Skip to content

Commit 6c30196

Browse files
authored
🧹 Rewrite unit tests in Golang (#215)
* Rewrite the unit tests to Golang Signed-off-by: Chris Suszyński <[email protected]> * Restore Stderr for Prow jobs * Remove mock tests reports from real reports * Cleanup before review Signed-off-by: Chris Suszyński <[email protected]> * Unit test work without a Prow Signed-off-by: Chris Suszyński <[email protected]>
1 parent f9dc722 commit 6c30196

29 files changed

+1192
-663
lines changed

e2e-tests.sh

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ function setup_test_cluster() {
7676
# Setup KO_DOCKER_REPO if it is a GKE cluster. Incorporate an element of
7777
# randomness to ensure that each run properly publishes images. Don't
7878
# owerwrite KO_DOCKER_REPO if already set.
79-
[ -z "${KO_DOCKER_REPO}" ] && \
79+
[ -z "${KO_DOCKER_REPO:-}" ] && \
8080
[[ "${k8s_cluster}" =~ ^gke_.* ]] && \
8181
export KO_DOCKER_REPO=gcr.io/${E2E_PROJECT_ID}/${REPO_NAME}-e2e-img/${RANDOM}
8282

@@ -120,12 +120,14 @@ function success() {
120120
}
121121

122122
# Exit test, dumping current state info.
123-
# Parameters: $1 - error message (optional).
123+
# Parameters: $* - error message (optional).
124124
function fail_test() {
125-
[[ -n $1 ]] && echo "ERROR: $1"
126-
dump_cluster_state
127-
dump_metrics
128-
exit 1
125+
local message="$*"
126+
if [[ -n ${message:-} ]]; then
127+
message='test failed'
128+
fi
129+
add_trap "dump_cluster_state;dump_metrics" EXIT
130+
abort "${message}"
129131
}
130132

131133
SKIP_TEARDOWNS=0

infra-library.sh

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,8 @@ function create_test_cluster() {
9191
fi
9292

9393
case "$1" in
94-
gke) create_gke_test_cluster "$2" "$3" "$4" ;;
95-
kind) create_kind_test_cluster "$2" "$3" "$4" ;;
94+
gke) create_gke_test_cluster "$2" "$3" "${4:-}" ;;
95+
kind) create_kind_test_cluster "$2" "$3" "${4:-}" ;;
9696
*) echo "unsupported provider: $1"; exit 1 ;;
9797
esac
9898

@@ -126,11 +126,11 @@ function create_gke_test_cluster() {
126126
# We are disabling logs and metrics on Boskos Clusters by default as they are not used. Manually set ENABLE_GKE_TELEMETRY to true to enable telemetry
127127
# and ENABLE_PREEMPTIBLE_NODES to true to create preemptible/spot VMs. VM Preemption is a rare event and shouldn't be distruptive given the fault tolerant nature of our tests.
128128
local extra_gcloud_flags=""
129-
if [[ "$ENABLE_GKE_TELEMETRY" != "true" ]]; then
129+
if [[ "${ENABLE_GKE_TELEMETRY:-}" != "true" ]]; then
130130
extra_gcloud_flags="${extra_gcloud_flags} --logging=NONE --monitoring=NONE"
131131
fi
132132

133-
if [[ "$ENABLE_PREEMPTIBLE_NODES" == "true" ]]; then
133+
if [[ "${ENABLE_PREEMPTIBLE_NODES:-}" == "true" ]]; then
134134
extra_gcloud_flags="${extra_gcloud_flags} --preemptible"
135135
fi
136136
run_kntest kubetest2 gke "${_custom_flags[@]}" --test-command="${_test_command[*]}" --extra-gcloud-flags="${extra_gcloud_flags}"

library.sh

Lines changed: 64 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,19 @@ fi
4040
readonly IS_PROW
4141
[[ ! -v REPO_ROOT_DIR ]] && REPO_ROOT_DIR="$(git rev-parse --show-toplevel)"
4242
readonly REPO_ROOT_DIR
43-
readonly REPO_NAME="${REPO_NAME:-$(basename "${REPO_ROOT_DIR}")}"
43+
44+
# Resolves the repository name given a root directory.
45+
# Parameters: $1 - repository root directory.
46+
function __resolveRepoName() {
47+
local repoName
48+
repoName="$(basename "${1:-$(git rev-parse --show-toplevel)}")"
49+
repoName="${repoName#knative-sandbox-}" # Remove knative-sandbox- prefix if any
50+
repoName="${repoName#knative-}" # Remove knative- prefix if any
51+
echo "${repoName}"
52+
}
53+
default_repo_name="$(__resolveRepoName "${REPO_ROOT_DIR}")"
54+
readonly REPO_NAME="${REPO_NAME:-$default_repo_name}"
55+
unset default_repo_name
4456

4557
# Useful flags about the current OS
4658
IS_LINUX=0
@@ -65,10 +77,6 @@ if [[ -z "${ARTIFACTS:-}" ]]; then
6577
fi
6678
mkdir -p "$ARTIFACTS"
6779

68-
69-
# On a Prow job, redirect stderr to stdout so it's synchronously added to log
70-
(( IS_PROW )) && exec 2>&1
71-
7280
# Return the major version of a release.
7381
# For example, "v0.2.1" returns "0"
7482
# Parameters: $1 - release version label.
@@ -94,23 +102,63 @@ function patch_version() {
94102
echo "${tokens[2]}"
95103
}
96104

97-
# Print error message and exit 1
105+
# Calculates the hashcode for a given string.
106+
# Parameters: $* - string to be hashed.
107+
# See: https://stackoverflow.com/a/48863502/844449
108+
function hashCode() {
109+
local input="$1"
110+
local -i h=0
111+
for ((i = 0; i < ${#input}; i++)); do
112+
# val is ASCII val
113+
printf -v val "%d" "'${input:$i:1}"
114+
hval=$((31 * h + val))
115+
# hash scheme
116+
if ((hval > 2147483647)); then
117+
h=$(( (hval - 2147483648) % 2147483648 ))
118+
elif ((hval < -2147483648)); then
119+
h=$(( (hval + 2147483648) % 2147483648 ))
120+
else
121+
h=$(( hval ))
122+
fi
123+
done
124+
# final hashCode in decimal
125+
printf "%d" $h
126+
}
127+
128+
# Calculates the retcode for a given string. Makes sure the return code is
129+
# non-zero.
130+
# Parameters: $* - string to be hashed.
131+
function calcRetcode() {
132+
local rc=1
133+
local rcc
134+
rcc="$(hashCode "$*")"
135+
if [[ $rcc != 0 ]]; then
136+
rc=$(( rcc % 255 ))
137+
fi
138+
echo "$rc"
139+
}
140+
141+
# Print error message and call exit(n) where n calculated from the error message.
98142
# Parameters: $1..$n - error message to be displayed
143+
# Globals: abort_retcode will change the default retcode to be returned
99144
function abort() {
100-
echo "error: $*" >&2
101-
exit 1
145+
make_banner '*' "ERROR: $*" >&2
146+
readonly abort_retcode="${abort_retcode:-$(calcRetcode "$*")}"
147+
exit "$abort_retcode"
102148
}
103149

104150
# Display a box banner.
105151
# Parameters: $1 - character to use for the box.
106152
# $2 - banner message.
107153
function make_banner() {
108154
local msg="$1$1$1$1 $2 $1$1$1$1"
109-
local border="${msg//[-0-9A-Za-z _.,\/()\']/$1}"
155+
local border="${msg//[^$1]/$1}"
110156
echo -e "${border}\n${msg}\n${border}"
111157
# TODO(adrcunha): Remove once logs have timestamps on Prow
112158
# For details, see https://github.com/kubernetes/test-infra/issues/10100
113-
echo -e "$1$1$1$1 $(TZ='UTC' date)\n${border}"
159+
if (( IS_PROW )); then
160+
echo -e "$1$1$1$1 $(TZ='UTC' date --rfc-3339=ns)\n${border}"
161+
fi
114162
}
115163

116164
# Simple header for logging purposes.
@@ -126,7 +174,7 @@ function subheader() {
126174

127175
# Simple warning banner for logging purposes.
128176
function warning() {
129-
make_banner '!' "$*" >&2
177+
make_banner '!' "WARN: $*" >&2
130178
}
131179

132180
# Checks whether the given function exists.
@@ -448,14 +496,14 @@ function report_go_test() {
448496
logfile="${xml/junit_/go_test_}"
449497
logfile="${logfile/.xml/.jsonl}"
450498
echo "Running go test with args: ${go_test_args[*]}"
499+
local gotest_retcode=0
451500
go_run gotest.tools/[email protected] \
452501
--format "${GO_TEST_VERBOSITY:-testname}" \
453502
--junitfile "${xml}" \
454503
--junitfile-testsuite-name relative \
455504
--junitfile-testcase-classname relative \
456505
--jsonfile "${logfile}" \
457-
-- "${go_test_args[@]}"
458-
local gotest_retcode=$?
506+
-- "${go_test_args[@]}" || gotest_retcode=$?
459507
echo "Finished run, return code is ${gotest_retcode}"
460508

461509
echo "XML report written to ${xml}"
@@ -558,6 +606,9 @@ function go_run() {
558606
if [[ "$package" != *@* ]]; then
559607
abort 'Package for "go_run" needs to have @version'
560608
fi
609+
if [[ "$package" == *@latest ]] && [[ "$package" != knative.dev* ]]; then
610+
warning 'Using @latest version for external dependencies is unsafe. Use numbered version!'
611+
fi
561612
shift 1
562613
GORUN_PATH="${GORUN_PATH:-$(go env GOPATH)}"
563614
# Some CI environments may have non-writable GOPATH

presubmit-tests.sh

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -240,15 +240,14 @@ function run_integration_tests() {
240240
# Default integration test runner that runs all `test/e2e-*tests.sh`.
241241
function default_integration_test_runner() {
242242
local failed=0
243-
find test/ ! -name "$(printf "*\n*")" -name "e2e-*tests.sh" -maxdepth 1 > tmp
244-
while IFS= read -r e2e_test
245-
do
243+
244+
while IFS= read -r e2e_test; do
246245
echo "Running integration test ${e2e_test}"
247246
if ! ${e2e_test}; then
248247
failed=1
249248
step_failed "${e2e_test}"
250249
fi
251-
done < tmp
250+
done < <(find test/ ! -name "$(printf "*\n*")" -name "e2e-*tests.sh" -maxdepth 1)
252251
return ${failed}
253252
}
254253

@@ -284,16 +283,16 @@ function main() {
284283
git version
285284
echo ">> ko version"
286285
[[ -f /ko_version ]] && cat /ko_version || echo "unknown"
287-
if [[ "${DOCKER_IN_DOCKER_ENABLED}" == "true" ]]; then
286+
if [[ "${DOCKER_IN_DOCKER_ENABLED:-}" == "true" ]]; then
288287
echo ">> docker version"
289288
docker version
290289
fi
291290
if type java > /dev/null; then
292291
echo ">> java version"
293292
java -version
294-
echo "JAVA_HOME: $JAVA_HOME"
293+
echo "JAVA_HOME: ${JAVA_HOME:-}"
295294
fi
296-
if type mvn > /dev/null; then
295+
if command -v mvn > /dev/null; then
297296
echo ">> maven version"
298297
mvn --version
299298
fi

test/e2e-tests.sh

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,24 @@
2323
# Calling this script without arguments will create a new cluster in
2424
# project $PROJECT_ID, run the tests and delete the cluster.
2525

26-
set -Eeo pipefail
26+
set -Eeuo pipefail
2727

2828
source "$(dirname "${BASH_SOURCE[0]:-$0}")/../e2e-tests.sh"
2929

3030
function knative_setup() {
3131
start_latest_knative_serving
3232
}
3333

34+
function dump_metrics() {
35+
header ">> Starting kube proxy"
36+
header ">> Grabbing k8s metrics"
37+
}
38+
3439
# Script entry point.
3540
initialize "$@" --max-nodes=1 --machine=e2-standard-2 \
3641
--enable-workload-identity --cluster-version=latest \
3742
--extra-gcloud-flags "--enable-stackdriver-kubernetes --no-enable-ip-alias --no-enable-autoupgrade"
3843

39-
set -Eeuo pipefail
40-
4144
go_test_e2e ./test/e2e || fail_test
4245

4346
success

test/library_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func TestFails(t *testing.T) {
4545

4646
func TestFailsWithFatal(t *testing.T) {
4747
// Simulate a zap.Fatal() call.
48-
fmt.Println("fatal\tTestFailsWithFatal\tsimple_test.go:999\tFailed with logger.Fatal()")
48+
fmt.Println("fatal\tTestFailsWithFatal\tlibrary_test.go:48\tFailed with logger.Fatal()")
4949
signal(os.Kill)
5050
}
5151

test/presubmit-tests.sh

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323

2424
set -Eeuo pipefail
2525

26-
export REPO_NAME=hack
27-
2826
source "$(dirname "${BASH_SOURCE[0]:-$0}")/../presubmit-tests.sh"
2927

3028
# Run our custom build tests after the standard build tests.
@@ -38,19 +36,6 @@ function post_build_tests() {
3836
return ${failed}
3937
}
4038

41-
# Run our custom unit tests after the standard unit tests.
42-
43-
function post_unit_tests() {
44-
local failed=0
45-
for test in ./test/unit/*-tests.sh; do
46-
subheader "Running tests in ${test}"
47-
${test} || { failed=$?; echo "--- FAIL: ${test}"; }
48-
if (( failed )); then
49-
return ${failed}
50-
fi
51-
done
52-
}
53-
5439
# We use the default integration test runner.
5540

5641
main "$@"

test/unit/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
unittest-*.bash

test/unit/e2e_helpers_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package unit_test
2+
3+
import "testing"
4+
5+
func TestE2eHelpers(t *testing.T) {
6+
t.Parallel()
7+
sc := newShellScript(loadFile(
8+
"fake-prow-job.bash",
9+
"source-e2e-tests.bash",
10+
"smoke-test-custom-flag.bash",
11+
"fake-dumps.bash",
12+
))
13+
tcs := []testCase{{
14+
name: `initialize --smoke-test-custom-flag`,
15+
stdout: lines(">> All tests passed"),
16+
}, {
17+
name: `fail_test`,
18+
commands: []string{
19+
`initialize --run-test true`,
20+
`fail_test`,
21+
},
22+
stderr: aborted("test failed"),
23+
retcode: retcode(111),
24+
stdout: []check{
25+
contains(">> DUMPING THE CLUSTER STATE"),
26+
contains(">> STARTING KUBE PROXY"),
27+
contains(">> GRABBING K8S METRICS"),
28+
},
29+
}}
30+
for _, tc := range tcs {
31+
tc := tc
32+
t.Run(tc.name, tc.test(sc))
33+
}
34+
}

0 commit comments

Comments
 (0)