1#!/usr/bin/env bash 2# SPDX-License-Identifier: BSD-3-Clause 3# Copyright (C) 2015 Intel Corporation 4# All rights reserved. 5# 6 7set -e 8 9# If the configuration of tests is not provided, no tests will be carried out. 10if [[ ! -f $1 ]]; then 11 echo "ERROR: SPDK test configuration not specified" 12 exit 1 13fi 14 15rootdir=$(readlink -f $(dirname $0)) 16 17source "$1" 18source "$rootdir/test/common/autotest_common.sh" 19source "$rootdir/scripts/common.sh" 20 21if [[ -n $EXTERNAL_MAKE_HUGEMEM ]]; then 22 export EXTERNAL_MAKE_HUGEMEM 23fi 24 25out=$output_dir 26if [ -n "$SPDK_TEST_NATIVE_DPDK" ]; then 27 scanbuild_exclude=" --exclude $(dirname $SPDK_RUN_EXTERNAL_DPDK)" 28else 29 scanbuild_exclude="--exclude $rootdir/dpdk/" 30fi 31# We exclude /tmp as it's used by xnvme's liburing subproject for storing 32# temporary .c files which are picked up as buggy by the scanbuild. 33scanbuild_exclude+=" --exclude $rootdir/xnvme --exclude /tmp" 34 35scanbuild="scan-build -o $output_dir/scan-build-tmp $scanbuild_exclude --status-bugs" 36config_params=$(get_config_params) 37 38trap '[[ -d $SPDK_WORKSPACE ]] && rm -rf "$SPDK_WORKSPACE"' 0 39 40SPDK_WORKSPACE=$(mktemp -dt "spdk_$(date +%s).XXXXXX") 41export SPDK_WORKSPACE 42 43umask 022 44cd $rootdir 45 46# Print some test system info out for the log 47date -u 48git describe --tags 49 50function ocf_precompile() { 51 # We compile OCF sources ourselves 52 # They don't need to be checked with scanbuild and code coverage is not applicable 53 # So we precompile OCF now for further use as standalone static library 54 ./configure $(echo $config_params | sed 's/--enable-coverage//g') 55 $MAKE $MAKEFLAGS include/spdk/config.h 56 CC=gcc CCAR=ar $MAKE $MAKEFLAGS -C lib/env_ocf exportlib O=$rootdir/ocf.a 57 # Set config to use precompiled library 58 config_params="$config_params --with-ocf=/$rootdir/ocf.a" 59 # need to reconfigure to avoid clearing ocf related files on future make clean. 60 ./configure $config_params 61} 62 63# Find matching llvm fuzzer library and clang compiler version 64function llvm_precompile() { 65 [[ $(clang --version) =~ "version "(([0-9]+).([0-9]+).([0-9]+)) ]] 66 clang_version=${BASH_REMATCH[1]} 67 clang_num=${BASH_REMATCH[2]} 68 69 export CC=clang-$clang_num 70 export CXX=clang++-$clang_num 71 72 fuzzer_libs=(/usr/lib*/clang/"$clang_version"/lib/linux/libclang_rt.fuzzer_no_main-x86_64.a) 73 fuzzer_lib=${fuzzer_libs[0]} 74 [[ -e $fuzzer_lib ]] 75 76 config_params="$config_params --with-fuzzer=$fuzzer_lib" 77 # Need to reconfigure to avoid clearing llvm related files on future make clean. 78 ./configure $config_params 79} 80 81function build_native_dpdk() { 82 local external_dpdk_dir 83 local external_dpdk_base_dir 84 local compiler_version 85 local compiler 86 local dpdk_kmods 87 88 compiler=${CC:-gcc} 89 90 # Export CC to be absolutely sure it's set. 91 # If CC was not set and we defaulted to "gcc" then we need to do the export 92 # so that "meson build" command a few lines below is aware of which compiler 93 # to use. 94 export CC="$compiler" 95 96 if [[ $compiler != *clang* && $compiler != *gcc* ]]; then 97 echo "Unsupported compiler detected ($compiler), failing the test" >&2 98 return 1 99 fi 100 101 compiler_version=$("$compiler" -dumpversion) 102 compiler_version=${compiler_version%%.*} 103 external_dpdk_dir="$SPDK_RUN_EXTERNAL_DPDK" 104 external_dpdk_base_dir="$(dirname $external_dpdk_dir)" 105 106 if [[ ! -d "$external_dpdk_base_dir" ]]; then 107 sudo mkdir -p "$external_dpdk_base_dir" 108 sudo chown -R $(whoami) "$external_dpdk_base_dir"/.. 109 fi 110 orgdir=$PWD 111 112 rm -rf "$external_dpdk_base_dir" 113 git clone --branch $SPDK_TEST_NATIVE_DPDK --depth 1 http://dpdk.org/git/dpdk "$external_dpdk_base_dir" 114 git -C "$external_dpdk_base_dir" log --oneline -n 5 115 116 dpdk_cflags="-fPIC -g -fcommon" 117 dpdk_ldflags="" 118 dpdk_ver=$(< "$external_dpdk_base_dir/VERSION") 119 120 if [[ $compiler == *gcc* && $compiler_version -ge 5 ]]; then 121 dpdk_cflags+=" -Werror" 122 fi 123 124 if [[ $compiler == *gcc* && $compiler_version -ge 10 ]]; then 125 dpdk_cflags+=" -Wno-stringop-overflow" 126 fi 127 128 # the drivers we use 129 # net/i40e driver is not really needed by us, but it's built as a workaround 130 # for DPDK issue: https://bugs.dpdk.org/show_bug.cgi?id=576 131 DPDK_DRIVERS=("bus" "bus/pci" "bus/vdev" "mempool/ring" "net/i40e" "net/i40e/base") 132 133 local mlx5_libs_added="n" 134 if [[ "$SPDK_TEST_CRYPTO" -eq 1 || "$SPDK_TEST_SMA" -eq 1 ]]; then 135 intel_ipsec_mb_ver=v0.54 136 intel_ipsec_mb_drv=crypto/aesni_mb 137 intel_ipsec_lib="" 138 if ge "$dpdk_ver" 21.11.0; then 139 # Minimum supported version of intel-ipsec-mb, for DPDK >= 21.11, is 1.0. 140 # Source of the aesni_mb driver was moved to ipsec_mb. .{h,so,a} were moved 141 # to ./lib. 142 # https://github.com/dpdk/dpdk/commit/918fd2f1466b0e3b21a033df7012a77a83665582. 143 intel_ipsec_mb_ver=v1.0 144 intel_ipsec_mb_drv=crypto/ipsec_mb 145 intel_ipsec_lib=lib 146 fi 147 git clone --branch "$intel_ipsec_mb_ver" --depth 1 https://github.com/intel/intel-ipsec-mb.git "$external_dpdk_base_dir/intel-ipsec-mb" 148 cd "$external_dpdk_base_dir/intel-ipsec-mb" 149 $MAKE $MAKEFLAGS all SHARED=y EXTRA_CFLAGS=-fPIC 150 DPDK_DRIVERS+=("crypto") 151 DPDK_DRIVERS+=("$intel_ipsec_mb_drv") 152 DPDK_DRIVERS+=("crypto/qat") 153 DPDK_DRIVERS+=("compress/qat") 154 DPDK_DRIVERS+=("common/qat") 155 # 21.11.0 is version of DPDK with stable support for mlx5 crypto. 156 if ge "$dpdk_ver" 21.11.0; then 157 # SPDK enables CRYPTO_MLX in case supported version of DPDK is detected 158 # so make sure proper libs are built. 159 DPDK_DRIVERS+=("bus/auxiliary") 160 DPDK_DRIVERS+=("common/mlx5") 161 DPDK_DRIVERS+=("common/mlx5/linux") 162 DPDK_DRIVERS+=("crypto/mlx5") 163 mlx5_libs_added="y" 164 fi 165 dpdk_cflags+=" -I$external_dpdk_base_dir/intel-ipsec-mb/$intel_ipsec_lib" 166 dpdk_ldflags+=" -L$external_dpdk_base_dir/intel-ipsec-mb/$intel_ipsec_lib" 167 export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$external_dpdk_base_dir/intel-ipsec-mb/$intel_ipsec_lib" 168 fi 169 170 if [[ "$SPDK_TEST_VBDEV_COMPRESS" -eq 1 ]]; then 171 isal_dir="$external_dpdk_base_dir/isa-l" 172 git clone --branch v2.29.0 --depth 1 https://github.com/intel/isa-l.git "$isal_dir" 173 174 cd $isal_dir 175 ./autogen.sh 176 ./configure CFLAGS="-fPIC -g -O2" --enable-shared=yes --prefix="$isal_dir/build" 177 ln -s $PWD/include $PWD/isa-l 178 $MAKE $MAKEFLAGS all 179 $MAKE install 180 DPDK_DRIVERS+=("compress") 181 DPDK_DRIVERS+=("compress/isal") 182 DPDK_DRIVERS+=("compress/qat") 183 DPDK_DRIVERS+=("common/qat") 184 if ge "$dpdk_ver" 21.02.0; then 185 # SPDK enables REDUCE_MLX in case supported version of DPDK is detected 186 # so make sure proper libs are built. 187 if test $mlx5_libs_added = "n"; then 188 DPDK_DRIVERS+=("bus/auxiliary") 189 DPDK_DRIVERS+=("common/mlx5") 190 DPDK_DRIVERS+=("common/mlx5/linux") 191 fi 192 DPDK_DRIVERS+=("compress/mlx5") 193 fi 194 export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$isal_dir/build/lib/pkgconfig" 195 export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$isal_dir/build/lib" 196 fi 197 198 cd $external_dpdk_base_dir 199 if [ "$(uname -s)" = "Linux" ]; then 200 if lt $dpdk_ver 21.11.0; then 201 patch -p1 < "$rootdir/test/common/config/pkgdep/patches/dpdk/20.11/dpdk_pci.patch" 202 patch -p1 < "$rootdir/test/common/config/pkgdep/patches/dpdk/20.11/dpdk_qat.patch" 203 else 204 patch -p1 < "$rootdir/test/common/config/pkgdep/patches/dpdk/21.11+/dpdk_qat.patch" 205 fi 206 fi 207 208 dpdk_kmods="false" 209 if [ "$(uname -s)" = "FreeBSD" ]; then 210 dpdk_kmods="true" 211 fi 212 213 meson build-tmp --prefix="$external_dpdk_dir" --libdir lib \ 214 -Denable_docs=false -Denable_kmods="$dpdk_kmods" -Dtests=false \ 215 -Dc_link_args="$dpdk_ldflags" -Dc_args="$dpdk_cflags" \ 216 -Dmachine=native -Denable_drivers=$(printf "%s," "${DPDK_DRIVERS[@]}") 217 ninja -C "$external_dpdk_base_dir/build-tmp" $MAKEFLAGS 218 ninja -C "$external_dpdk_base_dir/build-tmp" $MAKEFLAGS install 219 220 # Save this path. In tests are run using autorun.sh then autotest.sh 221 # script will be unaware of LD_LIBRARY_PATH and will fail tests. 222 echo "export LD_LIBRARY_PATH=$LD_LIBRARY_PATH" > /tmp/spdk-ld-path 223 224 cd "$orgdir" 225} 226 227function check_dpdk_pci_api() { 228 local dpdk_dir 229 230 if [[ -n "$SPDK_TEST_NATIVE_DPDK" ]]; then 231 dpdk_dir=$(dirname "$SPDK_RUN_EXTERNAL_DPDK") 232 fi 233 234 "$rootdir/scripts/env_dpdk/check_dpdk_pci_api.sh" check "$dpdk_dir" 235} 236 237function make_fail_cleanup() { 238 if [ -d $out/scan-build-tmp ]; then 239 scanoutput=$(ls -1 $out/scan-build-tmp/) 240 mv $out/scan-build-tmp/$scanoutput $out/scan-build 241 rm -rf $out/scan-build-tmp 242 chmod -R a+rX $out/scan-build 243 fi 244 false 245} 246 247function scanbuild_make() { 248 pass=true 249 "$rootdir/configure" $config_params --without-shared 250 $scanbuild $MAKE $MAKEFLAGS > $out/build_output.txt && rm -rf $out/scan-build-tmp || make_fail_cleanup 251 xtrace_disable 252 253 rm -f $out/*files.txt 254 for ent in $(find app examples lib module test -type f | grep -vF ".h"); do 255 if [[ $ent == lib/env_ocf* ]]; then continue; fi 256 if file -bi $ent | grep -q 'text/x-c'; then 257 echo $ent | sed 's/\.cp\{0,2\}$//g' >> $out/all_c_files.txt 258 fi 259 done 260 xtrace_restore 261 262 grep -E "CC|CXX" $out/build_output.txt | sed 's/\s\s\(CC\|CXX\)\s//g' | sed 's/\.o//g' > $out/built_c_files.txt 263 cat $rootdir/test/common/skipped_build_files.txt >> $out/built_c_files.txt 264 265 sort -o $out/all_c_files.txt $out/all_c_files.txt 266 sort -o $out/built_c_files.txt $out/built_c_files.txt 267 # from comm manual: 268 # -2 suppress column 2 (lines unique to FILE2) 269 # -3 suppress column 3 (lines that appear in both files) 270 # comm may exit 1 if no lines were printed (undocumented, unreliable) 271 comm -2 -3 $out/all_c_files.txt $out/built_c_files.txt > $out/unbuilt_c_files.txt || true 272 273 if [ $(wc -l < $out/unbuilt_c_files.txt) -ge 1 ]; then 274 cat <<- ERROR 275 The following C files were not built. Either scanbuild CI job needs to 276 be updated with proper flags to build these files, or exceptions need 277 to be added to test/common/skipped_build_files.txt 278 279 $(<"$out/unbuilt_c_files.txt") 280 ERROR 281 pass=false 282 fi 283 284 $pass 285} 286 287function porcelain_check() { 288 if [ $(git status --porcelain --ignore-submodules | wc -l) -ne 0 ]; then 289 echo "Generated files missing from .gitignore:" 290 git status --porcelain --ignore-submodules 291 exit 1 292 fi 293} 294 295# Check that header file dependencies are working correctly by 296# capturing a binary's stat data before and after touching a 297# header file and re-making. 298function header_dependency_check() { 299 STAT1=$(stat $SPDK_BIN_DIR/spdk_tgt) 300 sleep 1 301 touch lib/nvme/nvme_internal.h 302 $MAKE $MAKEFLAGS 303 STAT2=$(stat $SPDK_BIN_DIR/spdk_tgt) 304 305 if [ "$STAT1" == "$STAT2" ]; then 306 echo "Header dependency check failed" 307 false 308 fi 309} 310 311function test_make_uninstall() { 312 # Create empty file to check if it is not deleted by target uninstall 313 touch "$SPDK_WORKSPACE/usr/lib/sample_xyz.a" 314 $MAKE $MAKEFLAGS uninstall DESTDIR="$SPDK_WORKSPACE" prefix=/usr 315 if [[ $(find "$SPDK_WORKSPACE/usr" -maxdepth 1 -mindepth 1 | wc -l) -ne 2 ]] || [[ $(find "$SPDK_WORKSPACE/usr/lib/" -maxdepth 1 -mindepth 1 | wc -l) -ne 1 ]]; then 316 ls -lR "$SPDK_WORKSPACE" 317 echo "Make uninstall failed" 318 exit 1 319 fi 320} 321 322function build_doc() { 323 local doxygenv 324 doxygenv=$(doxygen --version) 325 326 $MAKE -C "$rootdir"/doc --no-print-directory $MAKEFLAGS &> "$out"/doxygen.log 327 if [ -s "$out"/doxygen.log ]; then 328 if [[ "$doxygenv" == "1.8.20" ]]; then 329 # Doxygen 1.8.20 produces false positives, see: 330 # https://github.com/doxygen/doxygen/issues/7948 331 if grep -vE '\\ilinebr' "$out"/doxygen.log; then 332 echo "Doxygen errors found!" 333 exit 1 334 fi 335 elif [[ "$doxygenv" == "1.9.5" ]]; then 336 # Doxygen 1.9.5 produces false positives, see: 337 # https://github.com/doxygen/doxygen/issues/9552 and 338 # https://github.com/doxygen/doxygen/issues/9678 339 if grep -vE '\\ifile|@param' "$out"/doxygen.log; then 340 echo "Doxygen errors found!" 341 exit 1 342 fi 343 else 344 cat "$out"/doxygen.log 345 echo "Doxygen errors found!" 346 exit 1 347 fi 348 349 echo "Doxygen $doxygenv detected. No warnings except false positives, continuing the test" 350 fi 351 if hash pdflatex 2> /dev/null; then 352 $MAKE -C "$rootdir"/doc/output/latex --no-print-directory $MAKEFLAGS &>> "$out"/doxygen.log 353 fi 354 mkdir -p "$out"/doc 355 # Copy and remove files to avoid mv: failed to preserve ownership error 356 cp -r --preserve=mode "$rootdir"/doc/output/html "$out"/doc 357 rm -rf "$rootdir"/doc/output/html 358 if [ -f "$rootdir"/doc/output/latex/refman.pdf ]; then 359 mv "$rootdir"/doc/output/latex/refman.pdf "$out"/doc/spdk.pdf 360 fi 361 $MAKE -C "$rootdir"/doc --no-print-directory $MAKEFLAGS clean &>> "$out"/doxygen.log 362 if [ -s "$out"/doxygen.log ]; then 363 # Save the log as an artifact in case we are working with potentially broken version 364 eq "$doxygenv" 1.8.20 || rm "$out"/doxygen.log 365 fi 366 rm -rf "$rootdir"/doc/output 367} 368 369function autobuild_test_suite() { 370 run_test "autobuild_check_format" ./scripts/check_format.sh 371 run_test "autobuild_check_so_deps" $rootdir/test/make/check_so_deps.sh $1 372 run_test "autobuild_check_dpdk_pci_api" check_dpdk_pci_api 373 if [[ $SPDK_TEST_AUTOBUILD == 'full' ]]; then 374 run_test "autobuild_external_code" $rootdir/test/external_code/test_make.sh $rootdir 375 ./configure $config_params --without-shared 376 $MAKE $MAKEFLAGS 377 run_test "autobuild_generated_files_check" porcelain_check 378 run_test "autobuild_header_dependency_check" header_dependency_check 379 run_test "autobuild_make_install" $MAKE $MAKEFLAGS install DESTDIR="$SPDK_WORKSPACE" prefix=/usr 380 run_test "autobuild_make_uninstall" test_make_uninstall 381 run_test "autobuild_build_doc" build_doc 382 fi 383} 384 385function unittest_build() { 386 "$rootdir/configure" $config_params --without-shared 387 $MAKE $MAKEFLAGS 388} 389 390if [ $SPDK_RUN_ASAN -eq 1 ]; then 391 run_test "asan" echo "using asan" 392fi 393 394if [ $SPDK_RUN_UBSAN -eq 1 ]; then 395 run_test "ubsan" echo "using ubsan" 396fi 397 398if [ -n "$SPDK_TEST_NATIVE_DPDK" ]; then 399 run_test "build_native_dpdk" build_native_dpdk 400fi 401 402if [[ -z $SPDK_TEST_AUTOBUILD ]] || [[ $SPDK_TEST_AUTOBUILD == 'full' ]]; then 403 ./configure $config_params 404 echo "** START ** Info for Hostname: $HOSTNAME" 405 uname -a 406 $MAKE cc_version 407 $MAKE cxx_version 408 echo "** END ** Info for Hostname: $HOSTNAME" 409elif [[ $SPDK_TEST_AUTOBUILD != 'tiny' ]]; then 410 echo "ERROR: supported values for SPDK_TEST_AUTOBUILD are 'full' and 'tiny'" 411 exit 1 412fi 413 414if [[ $SPDK_TEST_OCF -eq 1 ]]; then 415 run_test "autobuild_ocf_precompile" ocf_precompile 416fi 417 418if [[ $SPDK_TEST_FUZZER -eq 1 ]]; then 419 run_test "autobuild_llvm_precompile" llvm_precompile 420fi 421 422if [[ -n $SPDK_TEST_AUTOBUILD ]]; then 423 run_test "autobuild" autobuild_test_suite $1 424elif [[ $SPDK_TEST_UNITTEST -eq 1 ]]; then 425 run_test "unittest_build" unittest_build 426elif [[ $SPDK_TEST_SCANBUILD -eq 1 ]]; then 427 run_test "scanbuild_make" scanbuild_make 428else 429 if [[ $SPDK_TEST_FUZZER -eq 1 ]]; then 430 # if we are testing nvmf fuzz with llvm lib, --with-shared will cause lib link fail 431 ./configure $config_params 432 else 433 # if we aren't testing the unittests, build with shared objects. 434 ./configure $config_params --with-shared 435 fi 436 run_test "make" $MAKE $MAKEFLAGS 437fi 438