mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-09-02 15:45:25 +00:00
[9.20] fix: ci: Ensure that junit.xml is present and non-empty after each system/unit test job
Previously, JUnit files were not generated or were generated empty for various reasons for some system/unit test runs.
Now, the number of tests collected for a MR is up from about 4k to 5.8k in the "Tests" tab of a pipeline.
Additionally, there is a check that ensures that [a somewhat sane](c5a271eb8b
) `junit.xml` file is generated after every system/unit test job and fails the job otherwise.
Closes #5316
Backport of MR !10556
Merge branch 'backport-5316-ensure-junit-xml-9.20' into 'bind-9.20'
See merge request isc-projects/bind9!10649
This commit is contained in:
110
.gitlab-ci.yml
110
.gitlab-ci.yml
@@ -334,6 +334,21 @@ stages:
|
|||||||
.fips-feature-test: &fips_feature_test
|
.fips-feature-test: &fips_feature_test
|
||||||
- if bin/tests/system/feature-test --have-fips-mode; then fips-mode-setup --check; fips-mode-setup --is-enabled; fi
|
- if bin/tests/system/feature-test --have-fips-mode; then fips-mode-setup --check; fips-mode-setup --is-enabled; fi
|
||||||
|
|
||||||
|
.check_for_junit_xml: &check_for_junit_xml
|
||||||
|
# test if junit.xml file exists and is longer 40 bytes
|
||||||
|
# (i.e., contains more than `<testsuites><testsuite /></testsuites>`)
|
||||||
|
- if [ -f "$CI_PROJECT_DIR"/junit.xml ]; then
|
||||||
|
if [ $(wc -c < "$CI_PROJECT_DIR"/junit.xml) -gt 40 ]; then
|
||||||
|
echo "junit.xml file exists and is longer than 40 bytes.";
|
||||||
|
else
|
||||||
|
echo "junit.xml file exists but is too short.";
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "junit.xml file does not exist.";
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
.build: &build_job
|
.build: &build_job
|
||||||
<<: *default_triggering_rules
|
<<: *default_triggering_rules
|
||||||
stage: build
|
stage: build
|
||||||
@@ -415,28 +430,34 @@ stages:
|
|||||||
artifacts: true
|
artifacts: true
|
||||||
timeout: 2h
|
timeout: 2h
|
||||||
|
|
||||||
.system_test_common: &system_test_common
|
.system_test_common: &system_test_job
|
||||||
<<: *default_triggering_rules
|
<<: *default_triggering_rules
|
||||||
stage: system
|
stage: system
|
||||||
before_script:
|
before_script:
|
||||||
- test -n "${OUT_OF_TREE_WORKSPACE}" && cp -r bin/tests/system/* "${OUT_OF_TREE_WORKSPACE}/bin/tests/system/" && cd "${OUT_OF_TREE_WORKSPACE}"
|
- test -n "${OUT_OF_TREE_WORKSPACE}" && cp -r bin/tests/system/* "${OUT_OF_TREE_WORKSPACE}/bin/tests/system/" && cd "${OUT_OF_TREE_WORKSPACE}"
|
||||||
- *setup_interfaces
|
- *setup_interfaces
|
||||||
|
# This script needs to: 1) fail if the system tests fail, 2) fail if
|
||||||
|
# the junit.xml file is broken, 3) produce the junit.xml file even if
|
||||||
|
# the system tests fail. Therefore, $RET is used to "cache" the
|
||||||
|
# result of running pytest as interrupting the script immediately when
|
||||||
|
# system tests fail would make checking the contents of the junit.xml
|
||||||
|
# file impossible (GitLab Runner uses "set -o pipefail").
|
||||||
script:
|
script:
|
||||||
- *fips_feature_test
|
- *fips_feature_test
|
||||||
- *find_pytest
|
- *find_pytest
|
||||||
- *find_python
|
- *find_python
|
||||||
- ( if [ "${CI_DISPOSABLE_ENVIRONMENT}" = "true" ]; then sleep 3000; "$PYTHON" "${CI_PROJECT_DIR}/util/get-running-system-tests.py"; fi ) &
|
- ( if [ "${CI_DISPOSABLE_ENVIRONMENT}" = "true" ]; then sleep 3000; "$PYTHON" "${CI_PROJECT_DIR}/util/get-running-system-tests.py"; fi ) &
|
||||||
- cd bin/tests/system
|
- cd bin/tests/system
|
||||||
|
- RET=0
|
||||||
- >
|
- >
|
||||||
"$PYTEST" --junit-xml="$CI_PROJECT_DIR"/junit.xml -n "$TEST_PARALLEL_JOBS" | tee pytest.out.txt
|
("$PYTEST" --junit-xml="$CI_PROJECT_DIR"/junit.xml -n "$TEST_PARALLEL_JOBS" | tee pytest.out.txt) || RET=1
|
||||||
|
- *check_for_junit_xml
|
||||||
|
- (exit $RET)
|
||||||
- '( ! grep -F "grep: warning:" pytest.out.txt )'
|
- '( ! grep -F "grep: warning:" pytest.out.txt )'
|
||||||
- test "$CLEAN_BUILD_ARTIFACTS_ON_SUCCESS" -eq 0 || ( cd ../../.. && make clean >/dev/null 2>&1 )
|
- test "$CLEAN_BUILD_ARTIFACTS_ON_SUCCESS" -eq 0 || ( cd ../../.. && make clean >/dev/null 2>&1 )
|
||||||
after_script:
|
after_script:
|
||||||
- test -n "${OUT_OF_TREE_WORKSPACE}" && cd "${OUT_OF_TREE_WORKSPACE}"
|
- test -n "${OUT_OF_TREE_WORKSPACE}" && cd "${OUT_OF_TREE_WORKSPACE}"
|
||||||
- *display_pytest_failures
|
- *display_pytest_failures
|
||||||
|
|
||||||
.system_test: &system_test_job
|
|
||||||
<<: *system_test_common
|
|
||||||
artifacts:
|
artifacts:
|
||||||
untracked: true
|
untracked: true
|
||||||
exclude:
|
exclude:
|
||||||
@@ -446,81 +467,65 @@ stages:
|
|||||||
junit: junit.xml
|
junit: junit.xml
|
||||||
|
|
||||||
.system_test_make_check: &system_test_make_check_job
|
.system_test_make_check: &system_test_make_check_job
|
||||||
<<: *system_test_common
|
<<: *system_test_job
|
||||||
|
# This script needs to: 1) fail if the system tests fail, 2) fail if
|
||||||
|
# the junit.xml file is broken, 3) produce the junit.xml file even if
|
||||||
|
# the system tests fail. Therefore, $RET is used to "cache" the
|
||||||
|
# result of "make check" as interrupting the script immediately when
|
||||||
|
# system tests fail would prevent the junit.xml file from being
|
||||||
|
# produced.
|
||||||
script:
|
script:
|
||||||
- cd bin/tests/system
|
- cd bin/tests/system
|
||||||
- make -j${TEST_PARALLEL_JOBS:-1} check
|
- RET=0
|
||||||
|
- make -j${TEST_PARALLEL_JOBS:-1} check || RET=$?
|
||||||
|
- cd "$CI_PROJECT_DIR"
|
||||||
|
- *find_python
|
||||||
|
- >
|
||||||
|
"$PYTHON" bin/tests/convert-trs-to-junit.py . > "$CI_PROJECT_DIR"/junit.xml
|
||||||
|
- *check_for_junit_xml
|
||||||
|
- (exit $RET)
|
||||||
after_script:
|
after_script:
|
||||||
- cat bin/tests/system/test-suite.log || true
|
- cat bin/tests/system/test-suite.log || true
|
||||||
|
|
||||||
.system_test_gcov: &system_test_gcov_job
|
|
||||||
<<: *system_test_common
|
|
||||||
artifacts:
|
|
||||||
untracked: true
|
|
||||||
exclude:
|
|
||||||
- "**/__pycache__/**/*"
|
|
||||||
when: always
|
|
||||||
|
|
||||||
.system_test_tsan: &system_test_tsan_job
|
.system_test_tsan: &system_test_tsan_job
|
||||||
<<: *system_test_common
|
<<: *system_test_job
|
||||||
after_script:
|
after_script:
|
||||||
- *display_pytest_failures
|
- *display_pytest_failures
|
||||||
- find bin/tests/system -name "*dig.*" | xargs grep "error" || true
|
- find bin/tests/system -name "*dig.*" | xargs grep "error" || true
|
||||||
- *find_python
|
- *find_python
|
||||||
- *parse_tsan
|
- *parse_tsan
|
||||||
- >
|
|
||||||
"$PYTHON" bin/tests/convert-trs-to-junit.py . > "$CI_PROJECT_DIR"/junit.xml
|
|
||||||
artifacts:
|
|
||||||
untracked: true
|
|
||||||
exclude:
|
|
||||||
- "**/__pycache__/**/*"
|
|
||||||
when: always
|
|
||||||
reports:
|
|
||||||
junit: junit.xml
|
|
||||||
|
|
||||||
.unit_test_common: &unit_test_common
|
.unit_test_common: &unit_test_job
|
||||||
<<: *default_triggering_rules
|
<<: *default_triggering_rules
|
||||||
stage: unit
|
stage: unit
|
||||||
before_script:
|
before_script:
|
||||||
- test -n "${OUT_OF_TREE_WORKSPACE}" && cd "${OUT_OF_TREE_WORKSPACE}"
|
- test -n "${OUT_OF_TREE_WORKSPACE}" && cd "${OUT_OF_TREE_WORKSPACE}"
|
||||||
|
# This script needs to: 1) fail if the unit tests fail, 2) fail if the
|
||||||
|
# junit.xml file is broken, 3) produce the junit.xml file even if the
|
||||||
|
# unit tests fail. Therefore, $RET is used to "cache" the result of
|
||||||
|
# "make unit" as interrupting the script immediately when unit tests
|
||||||
|
# fail would prevent the junit.xml file from being produced.
|
||||||
script:
|
script:
|
||||||
- *fips_feature_test
|
- *fips_feature_test
|
||||||
- make -j${TEST_PARALLEL_JOBS:-1} -k unit V=1
|
- RET=0
|
||||||
- test "$CLEAN_BUILD_ARTIFACTS_ON_SUCCESS" -eq 0 || make clean >/dev/null 2>&1
|
- make -j${TEST_PARALLEL_JOBS:-1} -k unit V=1 || RET=$?
|
||||||
after_script:
|
|
||||||
- test -d bind-* && cd bind-*
|
|
||||||
- REALSOURCEDIR="$PWD"
|
|
||||||
- test -n "${OUT_OF_TREE_WORKSPACE}" && cd "${OUT_OF_TREE_WORKSPACE}"
|
|
||||||
- *find_python
|
- *find_python
|
||||||
- >
|
- >
|
||||||
"$PYTHON" "$REALSOURCEDIR"/bin/tests/convert-trs-to-junit.py . > "$CI_PROJECT_DIR"/junit.xml
|
"$PYTHON" "$CI_PROJECT_DIR"/bin/tests/convert-trs-to-junit.py . > "$CI_PROJECT_DIR"/junit.xml
|
||||||
|
- *check_for_junit_xml
|
||||||
.unit_test: &unit_test_job
|
- (exit $RET)
|
||||||
<<: *unit_test_common
|
- test "$CLEAN_BUILD_ARTIFACTS_ON_SUCCESS" -eq 0 || make clean >/dev/null 2>&1
|
||||||
artifacts:
|
artifacts:
|
||||||
untracked: true
|
untracked: true
|
||||||
when: always
|
when: always
|
||||||
reports:
|
reports:
|
||||||
junit: junit.xml
|
junit: junit.xml
|
||||||
|
|
||||||
.unit_test_gcov: &unit_test_gcov_job
|
|
||||||
<<: *unit_test_common
|
|
||||||
artifacts:
|
|
||||||
untracked: true
|
|
||||||
when: always
|
|
||||||
|
|
||||||
.unit_test_tsan: &unit_test_tsan_job
|
.unit_test_tsan: &unit_test_tsan_job
|
||||||
<<: *unit_test_common
|
<<: *unit_test_job
|
||||||
after_script:
|
after_script:
|
||||||
- *find_python
|
- *find_python
|
||||||
- *parse_tsan
|
- *parse_tsan
|
||||||
- >
|
|
||||||
"$PYTHON" bin/tests/convert-trs-to-junit.py . > "$CI_PROJECT_DIR"/junit.xml
|
|
||||||
artifacts:
|
|
||||||
untracked: true
|
|
||||||
when: always
|
|
||||||
reports:
|
|
||||||
junit: junit.xml
|
|
||||||
|
|
||||||
.docs: &docs_job
|
.docs: &docs_job
|
||||||
variables:
|
variables:
|
||||||
@@ -991,7 +996,7 @@ gcc:bookworm:amd64:
|
|||||||
|
|
||||||
system:gcc:bookworm:amd64:
|
system:gcc:bookworm:amd64:
|
||||||
<<: *debian_bookworm_amd64_image
|
<<: *debian_bookworm_amd64_image
|
||||||
<<: *system_test_gcov_job
|
<<: *system_test_job
|
||||||
variables:
|
variables:
|
||||||
CI_ENABLE_ALL_TESTS: 1
|
CI_ENABLE_ALL_TESTS: 1
|
||||||
CLEAN_BUILD_ARTIFACTS_ON_SUCCESS: 0
|
CLEAN_BUILD_ARTIFACTS_ON_SUCCESS: 0
|
||||||
@@ -1002,7 +1007,7 @@ system:gcc:bookworm:amd64:
|
|||||||
|
|
||||||
unit:gcc:bookworm:amd64:
|
unit:gcc:bookworm:amd64:
|
||||||
<<: *debian_bookworm_amd64_image
|
<<: *debian_bookworm_amd64_image
|
||||||
<<: *unit_test_gcov_job
|
<<: *unit_test_job
|
||||||
variables:
|
variables:
|
||||||
CI_ENABLE_ALL_TESTS: 1
|
CI_ENABLE_ALL_TESTS: 1
|
||||||
CLEAN_BUILD_ARTIFACTS_ON_SUCCESS: 0
|
CLEAN_BUILD_ARTIFACTS_ON_SUCCESS: 0
|
||||||
@@ -1224,7 +1229,6 @@ gcc:tumbleweed:amd64:
|
|||||||
|
|
||||||
system:gcc:tumbleweed:amd64:
|
system:gcc:tumbleweed:amd64:
|
||||||
<<: *tumbleweed_latest_amd64_image
|
<<: *tumbleweed_latest_amd64_image
|
||||||
<<: *system_test_job
|
|
||||||
<<: *system_test_make_check_job
|
<<: *system_test_make_check_job
|
||||||
needs:
|
needs:
|
||||||
- job: gcc:tumbleweed:amd64
|
- job: gcc:tumbleweed:amd64
|
||||||
|
@@ -28,14 +28,14 @@ def read_trs_result(filename):
|
|||||||
items = line.split()
|
items = line.split()
|
||||||
if len(items) < 2:
|
if len(items) < 2:
|
||||||
raise ValueError("unsupported line in trs file", filename, line)
|
raise ValueError("unsupported line in trs file", filename, line)
|
||||||
if items[0] != (":test-result:"):
|
if items[0] != (":global-test-result:"):
|
||||||
continue
|
continue
|
||||||
if result is not None:
|
if result is not None:
|
||||||
raise NotImplementedError("double :test-result:", filename)
|
raise NotImplementedError("double :global-test-result:", filename)
|
||||||
result = items[1].upper()
|
result = items[1].upper()
|
||||||
|
|
||||||
if result is None:
|
if result is None:
|
||||||
raise ValueError(":test-result: not found", filename)
|
raise ValueError(":global-test-result: not found", filename)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user