03_test_script.sh raw
1 #!/usr/bin/env bash
2 #
3 # Copyright (c) 2018-present The Limenka developers
4 # Distributed under the MIT software license, see the accompanying
5 # file COPYING or http://www.opensource.org/licenses/mit-license.php.
6
7 export LC_ALL=C.UTF-8
8
9 set -ex
10
11 export ASAN_OPTIONS="detect_leaks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1"
12 export LSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/lsan"
13 export TSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/tsan:halt_on_error=1:second_deadlock_stack=1"
14 export UBSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/ubsan:print_stacktrace=1:halt_on_error=1:report_error_type=1"
15
16 echo "Number of available processing units: $(nproc)"
17 if [ "$CI_OS_NAME" == "macos" ]; then
18 top -l 1 -s 0 | awk ' /PhysMem/ {print}'
19 else
20 free -m -h
21 echo "System info: $(uname --kernel-name --kernel-release)"
22 lscpu
23 fi
24 echo "Free disk space:"
25 df -h
26
27 # We force an install of linux-headers again here via $PACKAGES to fix any
28 # kernel mismatch between a cached docker image and the underlying host.
29 # This can happen occasionally on hosted runners if the runner image is updated.
30 if [[ "$CONTAINER_NAME" == "ci_native_asan" ]]; then
31 $CI_RETRY_EXE apt-get update
32 ${CI_RETRY_EXE} bash -c "apt-get install --no-install-recommends --no-upgrade -y $PACKAGES"
33 fi
34
35 # What host to compile for. See also ./depends/README.md
36 # Tests that need cross-compilation export the appropriate HOST.
37 # Tests that run natively guess the host
38 export HOST=${HOST:-$("$BASE_ROOT_DIR/depends/config.guess")}
39
40 echo "=== BEGIN env ==="
41 env
42 echo "=== END env ==="
43
44 (
45 # compact->outputs[i].file_size is uninitialized memory, so reading it is UB.
46 # The statistic bytes_written is only used for logging, which is disabled in
47 # CI, so as a temporary minimal fix to work around UB and CI failures, leave
48 # bytes_written unmodified.
49 # See https://github.com/limenka/limenka/pull/28359#issuecomment-1698694748
50 # Tee patch to stdout to make it clear CI is testing modified code.
51 tee >(patch -p1) <<'EOF'
52 --- a/src/leveldb/db/db_impl.cc
53 +++ b/src/leveldb/db/db_impl.cc
54 @@ -1028,9 +1028,6 @@ Status DBImpl::DoCompactionWork(CompactionState* compact) {
55 stats.bytes_read += compact->compaction->input(which, i)->file_size;
56 }
57 }
58 - for (size_t i = 0; i < compact->outputs.size(); i++) {
59 - stats.bytes_written += compact->outputs[i].file_size;
60 - }
61
62 mutex_.Lock();
63 stats_[compact->compaction->level() + 1].Add(stats);
64 EOF
65 )
66
67 if [ "$RUN_FUZZ_TESTS" = "true" ]; then
68 export DIR_FUZZ_IN=${DIR_QA_ASSETS}/fuzz_corpora/
69 if [ ! -d "$DIR_FUZZ_IN" ]; then
70 ${CI_RETRY_EXE} git clone --depth=1 https://github.com/limenka/qa-assets "${DIR_QA_ASSETS}"
71 fi
72 (
73 cd "${DIR_QA_ASSETS}"
74 echo "Using qa-assets repo from commit ..."
75 git log -1
76 )
77 elif [ "$RUN_UNIT_TESTS" = "true" ] || [ "$RUN_UNIT_TESTS_SEQUENTIAL" = "true" ]; then
78 export DIR_UNIT_TEST_DATA=${DIR_QA_ASSETS}/unit_test_data/
79 if [ ! -d "$DIR_UNIT_TEST_DATA" ]; then
80 mkdir -p "$DIR_UNIT_TEST_DATA"
81 ${CI_RETRY_EXE} curl --location --fail https://github.com/limenka/qa-assets/raw/main/unit_test_data/script_assets_test.json -o "${DIR_UNIT_TEST_DATA}/script_assets_test.json"
82 fi
83 fi
84
85 if [ "$USE_BUSY_BOX" = "true" ]; then
86 echo "Setup to use BusyBox utils"
87 # tar excluded for now because it requires passing in the exact archive type in ./depends (fixed in later BusyBox version)
88 # ar excluded for now because it does not recognize the -q option in ./depends (unknown if fixed)
89 for util in $(busybox --list | grep -v "^ar$" | grep -v "^tar$" ); do ln -s "$(command -v busybox)" "${BINS_SCRATCH_DIR}/$util"; done
90 # Print BusyBox version
91 patch --help
92 fi
93
94 # Make sure default datadir does not exist and is never read by creating a dummy file
95 if [ "$CI_OS_NAME" == "macos" ]; then
96 echo > "${HOME}/Library/Application Support/Limenka"
97 else
98 echo > "${HOME}/.limenka"
99 fi
100
101 if [ -z "$NO_DEPENDS" ]; then
102 if [[ $CI_IMAGE_NAME_TAG == *centos* ]]; then
103 SHELL_OPTS="CONFIG_SHELL=/bin/dash"
104 else
105 SHELL_OPTS="CONFIG_SHELL="
106 fi
107 bash -c "$SHELL_OPTS make $MAKEJOBS -C depends HOST=$HOST $DEP_OPTS LOG=1"
108 fi
109 if [ "$DOWNLOAD_PREVIOUS_RELEASES" = "true" ]; then
110 test/get_previous_releases.py -b -t "$PREVIOUS_RELEASES_DIR"
111 fi
112
113 LIMENKA_CONFIG_ALL="-DBUILD_BENCH=ON -DBUILD_FUZZ_BINARY=ON -D RDTS_CONSENT=RUNTIME_CHECK"
114 if [ -z "$NO_DEPENDS" ]; then
115 LIMENKA_CONFIG_ALL="${LIMENKA_CONFIG_ALL} -DCMAKE_TOOLCHAIN_FILE=$DEPENDS_DIR/$HOST/toolchain.cmake"
116 fi
117 if [ -z "$NO_WERROR" ]; then
118 LIMENKA_CONFIG_ALL="${LIMENKA_CONFIG_ALL} -DWERROR=ON"
119 fi
120
121 ccache --zero-stats
122 PRINT_CCACHE_STATISTICS="ccache --version | head -n 1 && ccache --show-stats"
123
124 # Folder where the build is done.
125 BASE_BUILD_DIR=${BASE_BUILD_DIR:-$BASE_SCRATCH_DIR/build-$HOST}
126 mkdir -p "${BASE_BUILD_DIR}"
127 cd "${BASE_BUILD_DIR}"
128
129 LIMENKA_CONFIG_ALL="$LIMENKA_CONFIG_ALL -DENABLE_EXTERNAL_SIGNER=ON -DCMAKE_INSTALL_PREFIX=$BASE_OUTDIR"
130
131 if [[ "${RUN_TIDY}" == "true" ]]; then
132 LIMENKA_CONFIG_ALL="$LIMENKA_CONFIG_ALL -DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
133 fi
134
135 bash -c "cmake -S $BASE_ROOT_DIR $LIMENKA_CONFIG_ALL $LIMENKA_CONFIG || ( (cat $(cmake -P "${BASE_ROOT_DIR}/ci/test/GetCMakeLogFiles.cmake")) && false)"
136
137 bash -c "cmake --build . $MAKEJOBS --target all $GOAL" || ( echo "Build failure. Verbose build follows." && cmake --build . --target all "$GOAL" --verbose ; false )
138
139 bash -c "${PRINT_CCACHE_STATISTICS}"
140 if [ "$CI" = "true" ]; then
141 hit_rate=$(ccache -s | grep "Hits:" | head -1 | sed 's/.*(\(.*\)%).*/\1/')
142 if [ "${hit_rate%.*}" -lt 75 ]; then
143 echo "::notice title=low ccache hitrate::Ccache hit-rate in $CONTAINER_NAME was $hit_rate%"
144 fi
145 fi
146 du -sh "${DEPENDS_DIR}"/*/
147 du -sh "${PREVIOUS_RELEASES_DIR}"
148
149 if [[ $HOST = *-mingw32 ]]; then
150 "${BASE_ROOT_DIR}/ci/test/wrap-wine.sh"
151 fi
152
153 if [ -n "$USE_VALGRIND" ]; then
154 "${BASE_ROOT_DIR}/ci/test/wrap-valgrind.sh"
155 fi
156
157 if [ "$RUN_CHECK_DEPS" = "true" ]; then
158 "${BASE_ROOT_DIR}/contrib/devtools/check-deps.sh" .
159 fi
160
161 if [ "$RUN_UNIT_TESTS" = "true" ]; then
162 DIR_UNIT_TEST_DATA="${DIR_UNIT_TEST_DATA}" LD_LIBRARY_PATH="${DEPENDS_DIR}/${HOST}/lib" CTEST_OUTPUT_ON_FAILURE=ON ctest --stop-on-failure "${MAKEJOBS}" --timeout $(( TEST_RUNNER_TIMEOUT_FACTOR * 60 ))
163 fi
164
165 if [ "$RUN_UNIT_TESTS_SEQUENTIAL" = "true" ]; then
166 DIR_UNIT_TEST_DATA="${DIR_UNIT_TEST_DATA}" LD_LIBRARY_PATH="${DEPENDS_DIR}/${HOST}/lib" "${BASE_OUTDIR}"/bin/test_limenka --catch_system_errors=no -l test_suite
167 fi
168
169 if [ "$RUN_FUNCTIONAL_TESTS" = "true" ]; then
170 # parses TEST_RUNNER_EXTRA as an array which allows for multiple arguments such as TEST_RUNNER_EXTRA='--exclude "rpc_bind.py --ipv6"'
171 eval "TEST_RUNNER_EXTRA=($TEST_RUNNER_EXTRA)"
172 LD_LIBRARY_PATH="${DEPENDS_DIR}/${HOST}/lib" test/functional/test_runner.py --ci "${MAKEJOBS}" --tmpdirprefix "${BASE_SCRATCH_DIR}"/test_runner/ --ansi --combinedlogslen=99999999 --timeout-factor="${TEST_RUNNER_TIMEOUT_FACTOR}" "${TEST_RUNNER_EXTRA[@]}" --quiet --failfast
173 fi
174
175 if [ "${RUN_TIDY}" = "true" ]; then
176 cmake -B /tidy-build -DLLVM_DIR=/usr/lib/llvm-"${TIDY_LLVM_V}"/cmake -DCMAKE_BUILD_TYPE=Release -S "${BASE_ROOT_DIR}"/contrib/devtools/limenka-tidy
177 cmake --build /tidy-build "$MAKEJOBS"
178 cmake --build /tidy-build --target limenka-tidy-tests "$MAKEJOBS"
179
180 set -eo pipefail
181 # Filter out:
182 # * qt qrc and moc generated files
183 jq 'map(select(.file | test("src/qt/.*_autogen/.*\\.cpp$") | not))' "${BASE_BUILD_DIR}/compile_commands.json" > tmp.json
184 mv tmp.json "${BASE_BUILD_DIR}/compile_commands.json"
185
186 cd "${BASE_BUILD_DIR}/src/"
187 if ! ( run-clang-tidy-"${TIDY_LLVM_V}" -quiet -load="/tidy-build/liblimenka-tidy.so" "${MAKEJOBS}" | tee tmp.tidy-out.txt ); then
188 grep -C5 "error: " tmp.tidy-out.txt
189 echo "^^^ ⚠️ Failure generated from clang-tidy"
190 false
191 fi
192
193 cd "${BASE_ROOT_DIR}"
194 python3 "/include-what-you-use/iwyu_tool.py" \
195 -p "${BASE_BUILD_DIR}" "${MAKEJOBS}" \
196 -- -Xiwyu --cxx17ns -Xiwyu --mapping_file="${BASE_ROOT_DIR}/contrib/devtools/iwyu/limenka.core.imp" \
197 -Xiwyu --max_line_length=160 \
198 2>&1 | tee /tmp/iwyu_ci.out
199 cd "${BASE_ROOT_DIR}/src"
200 python3 "/include-what-you-use/fix_includes.py" --nosafe_headers < /tmp/iwyu_ci.out
201 git --no-pager diff
202 fi
203
204 if [ "$RUN_FUZZ_TESTS" = "true" ]; then
205 # shellcheck disable=SC2086
206 LD_LIBRARY_PATH="${DEPENDS_DIR}/${HOST}/lib" test/fuzz/test_runner.py ${FUZZ_TESTS_CONFIG} "${MAKEJOBS}" -l DEBUG "${DIR_FUZZ_IN}" --empty_min_time=60
207 fi
208