forked from flatcar/scripts
-
Notifications
You must be signed in to change notification settings - Fork 0
/
vendor_test.sh
385 lines (356 loc) · 12.2 KB
/
vendor_test.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
# Copyright (c) 2021 The Flatcar Maintainers.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# Vendor test helper script. Sourced by vendor tests. Does some
# initial setup.
#
#
# The initial setup consist of creating the vendor working directory
# for the vendor test script, specifying the variables described below
# and changing the current working directory to the vendor working
# directory.
#
#
# The vendor test script is expected to keep all artifacts it produces
# in its current working directory.
#
#
# The script specifies the following variables for the vendor test
# script to use:
#
# CIA_VERNUM:
# Image version. In case of developer builds it comes with a suffix,
# so it looks like "3217.0.0+nightly-20220422-0155". For release
# builds the version will be without suffix, so it looks like
# "3217.0.0". Whether the build is a release or a developer one is
# reflected in CIA_BUILD_TYPE variable described below.
#
# CIA_ARCH:
# Architecture to test. Currently it is either "amd64" or "arm64".
#
# CIA_TAPFILE:
# Where the TAP reports should be written. Usually just passed to
# kola throught the --tapfile parameter.
#
# CIA_CHANNEL:
# A channel. Either "alpha", "beta", "stable" or "lts". Used to find
# the last release for the update check.
#
# CIA_TESTSCRIPT:
# Name of the vendor script. May be useful in some messages.
#
# CIA_GIT_VERSION:
# The most recent tag for the current commit.
#
# CIA_BUILD_TYPE:
# It's either "release" or "developer", based on the CIA_VERNUM
# variable.
#
# CIA_FIRST_RUN:
# 1 if this is a first run, 0 if it is a rerun of failed tests.
#
#
# After this script is sourced, the parameters in ${@} specify test
# cases / test case patterns to run.
# "ciavts" stands for Continuous Integration Automation Vendor Test
# Setup. This prefix is used to easily unset all the variables with
# this prefix before leaving this file.
ciavts_main_work_dir="${1}"; shift
ciavts_work_dir="${1}"; shift
ciavts_arch="${1}"; shift
ciavts_vernum="${1}"; shift
ciavts_tapfile="${1}"; shift
# $@ now contains tests / test patterns to run
source ci-automation/ci_automation_common.sh
mkdir -p "${ciavts_work_dir}"
ciavts_testscript=$(basename "${0}")
ciavts_git_version=$(cat "${ciavts_main_work_dir}/git_version")
ciavts_channel=$(cat "${ciavts_main_work_dir}/git_channel")
if [[ "${ciavts_channel}" = 'developer' ]]; then
ciavts_channel='alpha'
fi
# If vernum is like 3200.0.0+whatever, it's a developer build,
# otherwise it's a release build.
ciavts_type='developer'
if [[ "${ciavts_vernum%%+*}" = "${ciavts_vernum}" ]]; then
ciavts_type='release'
fi
# Make these paths absolute to avoid problems when changing
# directories.
ciavts_tapfile="${PWD}/${ciavts_work_dir}/${ciavts_tapfile}"
ciavts_first_run=0
if [[ -f "${ciavts_main_work_dir}/first_run" ]]; then
ciavts_first_run=1
fi
echo "++++ Running ${ciavts_testscript} inside ${ciavts_work_dir} ++++"
cd "${ciavts_work_dir}"
CIA_VERNUM="${ciavts_vernum}"
CIA_ARCH="${ciavts_arch}"
CIA_TAPFILE="${ciavts_tapfile}"
CIA_CHANNEL="${ciavts_channel}"
CIA_TESTSCRIPT="${ciavts_testscript}"
CIA_GIT_VERSION="${ciavts_git_version}"
CIA_BUILD_TYPE="${ciavts_type}"
CIA_FIRST_RUN="${ciavts_first_run}"
# Unset all variables with ciavts_ prefix now.
unset -v "${!ciavts_@}"
# Prefixes all test names in the tap file with a given prefix, so the
# test name like "cl.basic" will become "extra-test.[${prefix}].cl.basic".
#
# Typical use:
# prefix_tap_file "${instance_type}" "${tapfile}"
#
# Parameters:
# 1 - prefix
# 2 - tap file, modified in place
function prefix_tap_file() {
local prefix="${1}"; shift
local tap_file="${1}"; shift
# drop the dots from prefix
local actual_prefix="extra-test.[${prefix}]."
sed --in-place --expression 's/^\(\s*\(not\)\?\s*ok[^-]*\s*-\s*\)\(\S\)/\1'"${actual_prefix}"'\3/g' "${tap_file}"
}
# Filters the test names, so it puts only the real names of the
# prefixed tests into the chosen variable. For example for prefix
# "foo", it will ignore the test name like "cl.basic", but will print
# "cl.internet" for a test name like "extra-test.[foo].cl.internet".
# "*" is treated specially - it will be inserted into the chosen
# variable if it is passed.
#
# Typical use:
# filter_prefixed_tests tests_to_run "${instance_type}" "${@}"
# if [[ "${#tests_to_run[@]}" -gt 0 ]]; then …; fi
#
# Parameters:
# 1 - name of an array variable where the filtering results will be stored
# 2 - prefix
# @ - test names
function filter_prefixed_tests() {
local var_name="${1}"; shift
local prefix="${1}"; shift
# rest of the parameters are test names
local -n results="${var_name}"
local name
local stripped_name
# clear the array, so it will contain results of current filtering
# only
results=()
for name; do
stripped_name="${name#extra-test.\[${prefix}\].}"
if [[ "${stripped_name}" != "${name}" ]]; then
results+=( "${stripped_name}" )
continue
elif [[ "${name}" = '*' ]]; then
results+=( '*' )
fi
done
}
# Filters out the extra tests from the passed test names. Ignored test
# names begin with "extra-test.". The results of the filtering are
# inserted into the chosen variable.
#
# Typical use:
# filter_out_prefixed_tests tests_to_run "${@}"
# if [[ "${#tests_to_run[@]}" -gt 0 ]]; then …; fi
#
# Parameters:
# 1 - name of an array variable where the filtering results will be stored
# @ - test names
function filter_out_prefixed_tests() {
local var_name="${1}"; shift
local -n results="${var_name}"
local name
# clear the array, so it will contain results of current filtering
# only
results=()
for name; do
if [[ "${name#extra-test.}" = "${name}" ]]; then
results+=( "${name}" )
fi
done
}
# Merges into the first (main) tap file the contents of other tap
# files. It is very simple - the function assumes that all the tap
# files begin with a line like:
#
# 1..${number_of_tests}
#
# Other lines that are processed should begin like:
#
# (not)? ok - ${test_name}
#
# Any other lines are copied verbatim.
#
# The other tap files should already be preprocessed by
# prefix_tap_file to avoid duplicated test names.
#
# Typical use:
# merge_tap_files "${tap_file}" extra-validation-*.tap
# rm -f extra-validation-*.tap
#
# Parameters:
# 1 - main tap file
# @ - other tap files
function merge_tap_files() {
local main_tap_file="${1}"; shift
# rest of the parameters are other tap files
local main_test_count=0
if [[ -f "${main_tap_file}" ]]; then
main_test_count=$(head --lines=1 "${main_tap_file}" | grep --only-matching '[0-9]\+$')
fi
local other_test_count
local other_tap_file
local tmp_tap_file="${main_tap_file}.mtf.tmp"
for other_tap_file; do
if [[ ! -f "${other_tap_file}" ]]; then
continue
fi
other_test_count=$(head --lines=1 "${other_tap_file}" | grep --only-matching '[0-9]\+$' || echo 0 )
((main_test_count+=other_test_count))
done
echo "1..${main_test_count}" >"${tmp_tap_file}"
if [[ -f "${main_tap_file}" ]]; then
tail --lines=+2 "${main_tap_file}" >>"${tmp_tap_file}"
fi
for other_tap_file; do
if [[ ! -f "${other_tap_file}" ]]; then
continue
fi
tail --lines=+2 "${other_tap_file}" >>"${tmp_tap_file}"
done
mv --force "${tmp_tap_file}" "${main_tap_file}"
}
# Runs or reruns the tests on the main instance and other
# instances. Other instances usually run a subset of tests only.
#
# For this function to work, the caller needs to define two functions
# beforehand:
#
# run_kola_tests that takes the following parameters:
# 1 - instance type
# 2 - tap file
# @ - tests to run
#
# query_kola_tests that takes the following parameters:
# 1 - instance type
# @ - tests to run
# This function should print the names of the tests to run. Every line
# of the output should have one test name to run. Any other cruft in
# the line will be ignored.
#
# Typical use:
# function run_kola_tests() {
# local instance_type="${1}"; shift
# local tap_file="${1}"; shift
# kola run … "${@}"
# }
#
# function query_kola_tests() {
# local instance_type="${1}"; shift
# kola list … "${@}"
# }
#
# args=(
# "${main_instance}"
# "${CIA_TAPFILE}"
# "${CIA_FIRST_RUN}"
# "${other_instance_types[@]}"
# '--'
# 'cl.internet'
# '--'
# "${tests_to_run[@]}"
# )
# run_kola_tests_on_instances "${args[@]}"
#
# Parameters:
# 1 - main instance type - there all the tests are being run
# 2 - main tap file
# 3 - if this is first run (1 if it is, 0 if it is a rerun)
# @ - other instance types followed by double dash (--) followed by
# test names for other instances to filter from the tests to be
# run followed by double dash, followed by tests to be run or
# rerun
function run_kola_tests_on_instances() {
local main_instance_type="${1}"; shift
local main_tapfile="${1}"; shift
local is_first_run="${1}"; shift
local other_instance_types=()
local other_tests=()
local arg
while [[ "${#}" -gt 0 ]]; do
arg="${1}"; shift
if [[ "${arg}" = '--' ]]; then
break
fi
other_instance_types+=( "${arg}" )
done
while [[ "${#}" -gt 0 ]]; do
arg="${1}"; shift
if [[ "${arg}" = '--' ]]; then
break
fi
other_tests+=( "${arg}" )
done
# rest of the parameters are tests to be run or rerun
local instance_type
local queried_tests
local instance_tests=()
local tests_on_instances_running=0
local other_tests_for_fgrep
other_tests_for_fgrep="$(printf '%s\n' "${other_tests[@]}")"
for instance_type in "${other_instance_types[@]}"; do
# On first run we usually pass the canonical test names like
# cl.basic, cl.internet or *, so we decide which tests should
# be run on the other instances based on this list. On the
# other hand, the rerun will contain names of the failed tests
# only, and those are specific - if a test failed on the main
# instance, the name of the test will be like cl.basic; if a
# test failed on other instance, the name of the test will be
# like extra-test.[…].cl.basic. So in case of reruns, we want
# to filter the extra tests first then we decide which tests
# should be run.
if [[ "${is_first_run}" -eq 1 ]]; then
set -o noglob # noglob should not be necessary, as
# query_kola_tests shouldn't return a
# wildcard, but better to be safe than sorry
queried_tests="$(query_kola_tests "${instance_type}" "${@}")"
instance_tests=( $(grep --only-matching --fixed-strings "${other_tests_for_fgrep}" <<<"${queried_tests}" || :) )
set +o noglob
else
filter_prefixed_tests instance_tests "${instance_type}" "${@}"
fi
if [[ "${#instance_tests[@]}" -gt 0 ]]; then
tests_on_instances_running=1
(
local instance_tapfile="instance_${instance_type}_validate.tap"
set +e
set -x
local output
output=$(run_kola_tests "${instance_type}" "${instance_tapfile}" "${instance_tests[@]}" 2>&1)
set +x
set -e
local escaped_instance_type
escaped_instance_type="$(sed -e 's/[\/&]/\\&/g' <<<"${instance_type}")"
printf "=== START ${instance_type} ===\n%s\n=== END ${instance_type} ===\n" "$(sed -e "s/^/${escaped_instance_type}: /g" <<<"${output}")"
prefix_tap_file "${instance_type}" "${instance_tapfile}"
) &
fi
done
local main_tests=()
filter_out_prefixed_tests main_tests "${@}"
if [[ "${#main_tests[@]}" -gt 0 ]]; then
# run in a subshell, so the set -x and set +e do not pollute
# the outer environment
(
set +e
set -x
run_kola_tests "${main_instance_type}" "${main_tapfile}" "${main_tests[@]}"
true
)
fi
if [[ "${tests_on_instances_running}" -eq 1 ]]; then
wait
merge_tap_files "${main_tapfile}" 'instance_'*'_validate.tap'
rm -f 'instance_'*'_validate.tap'
fi
}