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