diff --git a/.build/README.md b/.build/README.md index c9ae0e468f..f791029e02 100644 --- a/.build/README.md +++ b/.build/README.md @@ -71,54 +71,60 @@ Running Tests Running unit tests with docker: - .build/docker/run-tests.sh test + .build/docker/run-tests.sh -a test Running unittests without docker: - .build/run-tests.sh test + .build/run-tests.sh -a test Running only a split of unittests, with docker: - .build/docker/run-tests.sh test 1/64 + .build/docker/run-tests.sh -a test -c 1/64 Running unittests with a specific jdk with docker: - .build/docker/run-tests.sh test 1/64 11 + .build/docker/run-tests.sh -a test -c 1/64 -j 11 Running only unit tests matching a regexp, with docker: - .build/docker/run-tests.sh test VerifyTest 11 - .build/docker/run-tests.sh test "Compaction*Test$" 11 + .build/docker/run-tests.sh -a test -t VerifyTest -j 11 + .build/docker/run-tests.sh -a test -t "Compaction*Test$" -j 11 Running other types of tests with docker: - .build/docker/run-tests.sh test - .build/docker/run-tests.sh stress-test - .build/docker/run-tests.sh fqltool-test - .build/docker/run-tests.sh microbench - .build/docker/run-tests.sh test-cdc - .build/docker/run-tests.sh test-compression - .build/docker/run-tests.sh test-oa - .build/docker/run-tests.sh test-system-keyspace-directory - .build/docker/run-tests.sh test-latest - .build/docker/run-tests.sh test-burn - .build/docker/run-tests.sh long-test - .build/docker/run-tests.sh cqlsh-test - .build/docker/run-tests.sh jvm-dtest - .build/docker/run-tests.sh jvm-dtest-upgrade - .build/docker/run-tests.sh dtest - .build/docker/run-tests.sh dtest-novnode - .build/docker/run-tests.sh dtest-latest - .build/docker/run-tests.sh dtest-large - .build/docker/run-tests.sh dtest-large-novnode - .build/docker/run-tests.sh dtest-upgrade - .build/docker/run-tests.sh dtest-upgrade-large + .build/docker/run-tests.sh -a test + .build/docker/run-tests.sh -a stress-test + .build/docker/run-tests.sh -a fqltool-test + .build/docker/run-tests.sh -a microbench + .build/docker/run-tests.sh -a test-cdc + .build/docker/run-tests.sh -a test-compression + .build/docker/run-tests.sh -a test-oa + .build/docker/run-tests.sh -a test-system-keyspace-directory + .build/docker/run-tests.sh -a test-tries + .build/docker/run-tests.sh -a test-burn + .build/docker/run-tests.sh -a long-test + .build/docker/run-tests.sh -a cqlsh-test + .build/docker/run-tests.sh -a jvm-dtest + .build/docker/run-tests.sh -a jvm-dtest-upgrade + .build/docker/run-tests.sh -a dtest + .build/docker/run-tests.sh -a dtest-novnode + .build/docker/run-tests.sh -a dtest-offheap + .build/docker/run-tests.sh -a dtest-large + .build/docker/run-tests.sh -a dtest-large-novnode + .build/docker/run-tests.sh -a dtest-upgrade + .build/docker/run-tests.sh -a dtest-upgrade-large +Repeating tests + +Just add the '-repeat' suffix to the test type and pass in the repeat arguments + + .build/run-tests.sh -a jvm-dtest-repeat -e REPEATED_TESTS_COUNT=2 -e REPEATED_TESTS=BooleanTest + .build/docker/run-tests.sh -a jvm-dtest-repeat -e REPEATED_TESTS_COUNT=2 -e REPEATED_TESTS=BooleanTest -j 11 Running python dtests without docker: diff --git a/.build/docker/run-tests.sh b/.build/docker/run-tests.sh index 1063db1d56..7bb8fc9d1e 100755 --- a/.build/docker/run-tests.sh +++ b/.build/docker/run-tests.sh @@ -15,27 +15,70 @@ # See the License for the specific language governing permissions and # limitations under the License. +# # A wrapper script to run-tests.sh (or dtest-python.sh) in docker. -# Can split (or grep) the test list into multiple docker runs, collecting results. +# [ $DEBUG ] && set -x -# help -if [ "$#" -lt 1 ] || [ "$#" -gt 3 ] || [ "$1" == "-h" ]; then - echo "" - echo "Usage: run-tests.sh test_type [split_chunk|test_regexp] [java_version]" - echo "" - echo " default split_chunk is 1/1" - echo " default java_version is what 'java.default' specifies in build.xml" - exit 1 -fi +print_help() { + echo "" + echo "Usage: $0 [-a|-t|-c|-j|-h] [extra arguments]" + echo " -a Test target type: test, test-compression, test-cdc, ..." + echo " -t Test name regexp to run." + echo " -c Chunk to run in the form X/Y: Run chunk X from a total of Y chunks." + echo " -j Java version. Default java_version is what 'java.default' specifies in build.xml." + echo " [extra arguments] will be passed to downstream scripts." + exit 1 +} error() { - echo >&2 $2; - set -x - exit $1 + echo >&2 $2; + set -x + exit $1 } +# legacy argument handling +case ${1} in + "build_dtest_jars" | "stress-test" | "fqltool-test" | "microbench" | "test-burn" | "long-test" | "cqlsh-test" | "simulator-dtest" | "dtest" | "dtest-novnode" | "dtest-latest" | "dtest-large" | "dtest-large-novnode" | "dtest-upgrade" | "dtest-upgrade-novnode"| "dtest-upgrade-large" | "dtest-upgrade-novnode-large" | "test" | "test-cdc" | "test-compression" | "test-oa" | "test-system-keyspace-directory" | "test-latest" | "jvm-dtest" | "jvm-dtest-upgrade" | "jvm-dtest-novnode" | "jvm-dtest-upgrade-novnode") + test_type="-a ${1}" + if [[ -z ${2} ]]; then + test_list="" + elif [[ -n ${2} && "${2}" =~ ^[0-9]+/[0-9]+$ ]]; then + test_list="-c ${2}"; + else + test_list="-t ${2}"; + fi + if [[ -n ${3} ]]; then java_version="-j ${3}"; else java_version=""; fi + echo "Using deprecated legacy arguments. Please update to new parameter format: ${test_type} ${test_list} ${java_version}" + $0 ${test_type} ${test_list} ${java_version} + exit $? +esac + +env_vars="" +while getopts ":a:t:c:e:hj:" opt; do + # shellcheck disable=SC2220 + # Invalid flags check disabled as we'll pass them to other scripts + case $opt in + a ) test_target="$OPTARG" + ;; + t ) test_name_regexp="$OPTARG" + ;; + c ) chunk="$OPTARG" + ;; + j ) java_version="$OPTARG" + ;; + e ) env_vars="${env_vars} -e $OPTARG" + ;; + h ) print_help + exit 0 + ;; + e) ;; # Repeat vars are just passed to downstream run-tests-enhaced.sh + \?) die "Invalid option: -$OPTARG" + ;; + esac +done + # variables, with defaults [ "x${cassandra_dir}" != "x" ] || cassandra_dir="$(readlink -f $(dirname "$0")/../..)" [ "x${cassandra_dtest_dir}" != "x" ] || cassandra_dtest_dir="${cassandra_dir}/../cassandra-dtest" @@ -53,10 +96,11 @@ command -v timeout >/dev/null 2>&1 || { error 1 "timeout needs to be installed"; [ -f "${cassandra_dir}/.build/run-tests.sh" ] || { error 1 "${cassandra_dir}/.build/run-tests.sh must exist"; } # arguments -target=$1 +target=${test_target} split_chunk="1/1" -[ "$#" -gt 1 ] && split_chunk=$2 -java_version=$3 +split_chunk=${chunk-'1/1'} +test_name_regexp=${test_name_regexp} +java_version=${java_version} test_script="run-tests.sh" java_version_default=`grep 'property\s*name="java.default"' ${cassandra_dir}/build.xml |sed -ne 's/.*value="\([^"]*\)".*/\1/p'` @@ -135,7 +179,7 @@ esac # figure out resource limits, scripts, and mounts for the test type docker_flags="-m 5g --memory-swap 5g" -case ${target} in +case ${test_target/-repeat/} in "build_dtest_jars") ;; "stress-test" | "fqltool-test" ) @@ -156,7 +200,7 @@ case ${target} in [[ ${mem} -gt $((15 * 1024 * 1024 * 1024 * ${jenkins_executors})) ]] || { error 1 "${target} require minimum docker memory 16g (per jenkins executor (${jenkins_executors})), found ${mem}"; } docker_flags="-m 15g --memory-swap 15g" ;; - "test"| "test-cdc" | "test-compression" | "test-oa" | "test-system-keyspace-directory" | "test-latest" | "jvm-dtest" | "jvm-dtest-upgrade" | "jvm-dtest-novnode" | "jvm-dtest-upgrade-novnode") + "test" | "test-cdc" | "test-compression" | "test-oa" | "test-system-keyspace-directory" | "test-latest" | "jvm-dtest" | "jvm-dtest-upgrade" | "jvm-dtest-novnode" | "jvm-dtest-upgrade-novnode") [[ ${mem} -gt $((5 * 1024 * 1024 * 1024 * ${jenkins_executors})) ]] || { error 1 "${target} require minimum docker memory 6g (per jenkins executor (${jenkins_executors})), found ${mem}"; } ;; *) @@ -236,8 +280,10 @@ logfile="${build_dir}/test/logs/docker_attach_${container_name}.log" # Docker commands: # set java to java_version # execute the run_script +[ -n "${test_name_regexp}" ] && test_name_regexp_arg="-t ${test_name_regexp}" || split_chunk_arg="-c ${split_chunk}" + docker_command="source \${CASSANDRA_DIR}/.build/docker/_set_java.sh ${java_version} ; \ - \${CASSANDRA_DIR}/.build/docker/_docker_init_tests.sh ${target} ${split_chunk} ; exit \$?" + \${CASSANDRA_DIR}/.build/docker/_docker_init_tests.sh -a ${target} ${split_chunk_arg} ${test_name_regexp_arg} ${env_vars} ; exit \$?" # start the container, timeout after 4 hours docker_id=$(docker run --name ${container_name} ${docker_flags} ${docker_envs} ${docker_mounts} ${docker_volume_opt} ${image_name} sleep 4h) diff --git a/.build/run-python-dtests.sh b/.build/run-python-dtests.sh index 5b1307e154..86652db0b8 100755 --- a/.build/run-python-dtests.sh +++ b/.build/run-python-dtests.sh @@ -28,18 +28,41 @@ [ $DEBUG ] && set -x # help -if [ "$#" -lt 1 ] || [ "$#" -gt 2 ] || [ "$1" == "-h" ]; then +if [ "$#" -lt 1 ] || [ "$1" == "-h" ]; then echo "" - echo "Usage: run-python-dtest.sh test_type [split_chunk|test_regexp]" + echo "Usage: $0 [-a|-t|-c|-j|-h]" + echo " -a Test target type: dtest, dtest-latest, ..." + echo " -t Test name regexp to run." + echo " -c Chunk to run in the form X/Y: Run chunk X from a total of Y chunks." echo "" echo " default split_chunk is 1/1" exit 1 fi # Pass in target to run, defaults to dtest -DTEST_TARGET="${1:-dtest}" -# Optional: pass in chunk to test, formatted as "K/N" for the Kth chunk of N chunks -DTEST_SPLIT_CHUNK="$2" +DTEST_TARGET="dtest" + +# TODO implement repeated runs, eg CASSANDRA-18942 +while getopts "a:t:c:hj:" opt; do + case $opt in + a ) DTEST_TARGET="$OPTARG" + ;; + t ) DTEST_SPLIT_CHUNK="$OPTARG" + ;; + c ) DTEST_SPLIT_CHUNK="$OPTARG" + ;; + h ) print_help + exit 0 + ;; + j ) ;; # To avoid failing on java_version param from docker/run_tests.sh + \?) error 1 "Invalid option: -$OPTARG" + ;; + esac +done +shift $((OPTIND-1)) +if [ "$#" -ne 0 ]; then + error 1 "Unexpected arguments" +fi # variables, with defaults [ "x${CASSANDRA_DIR}" != "x" ] || CASSANDRA_DIR="$(readlink -f $(dirname "$0")/..)" diff --git a/.build/run-tests.sh b/.build/run-tests.sh index fd961d8446..779ce2d0b2 100755 --- a/.build/run-tests.sh +++ b/.build/run-tests.sh @@ -24,25 +24,115 @@ set -o errexit set -o pipefail +[ $DEBUG ] && set -x + # variables, with defaults [ "x${CASSANDRA_DIR}" != "x" ] || CASSANDRA_DIR="$(readlink -f $(dirname "$0")/..)" [ "x${DIST_DIR}" != "x" ] || DIST_DIR="${CASSANDRA_DIR}/build" # pre-conditions -command -v ant >/dev/null 2>&1 || { echo >&2 "ant needs to be installed"; exit 1; } -command -v git >/dev/null 2>&1 || { echo >&2 "git needs to be installed"; exit 1; } -[ -d "${CASSANDRA_DIR}" ] || { echo >&2 "Directory ${CASSANDRA_DIR} must exist"; exit 1; } -[ -f "${CASSANDRA_DIR}/build.xml" ] || { echo >&2 "${CASSANDRA_DIR}/build.xml must exist"; exit 1; } +command -v ant >/dev/null 2>&1 || { error 1 "ant needs to be installed"; } +command -v git >/dev/null 2>&1 || { error 1 "git needs to be installed"; } +command -v uuidgen >/dev/null 2>&1 || test -f /proc/sys/kernel/random/uuid || { error 1 "uuidgen needs to be installed"; } +[ -d "${CASSANDRA_DIR}" ] || { error 1 "Directory ${CASSANDRA_DIR} must exist"; } +[ -f "${CASSANDRA_DIR}/build.xml" ] || { error 1 "${CASSANDRA_DIR}/build.xml must exist"; } [ -d "${DIST_DIR}" ] || { mkdir -p "${DIST_DIR}" ; } -# help -if [ "$#" -lt 1 ] || [ "$#" -gt 2 ] || [ "$1" == "-h" ]; then - echo "" - echo "Usage: run-tests.sh test_type [split_chunk|test_regexp]" - echo "" - echo " default split_chunk is 1/1" - exit 1 +error() { + echo >&2 $2; + set -x + exit $1 +} + +print_help() { + echo "Usage: $0 [-a|-t|-c|-e|-i|-b|-s|-h]" + echo " -a Test target type: test, test-compression, test-cdc, ..." + echo " -t Test name regexp to run." + echo " -c Chunk to run in the form X/Y: Run chunk X from a total of Y chunks." + echo " -b Specify the base git branch for comparison when determining changed tests to" + echo " repeat. Defaults to ${BASE_BRANCH}. Note that this option is not used when" + echo " the '-a' option is specified." + echo " -s Skip automatic detection of changed tests. Useful when you need to repeat a few ones," + echo " or when there are too many changed tests the CI env to handle." + echo " -e Environment variables to be used in the repeated runs:" + echo " -e REPEATED_TESTS_STOP_ON_FAILURE=false" + echo " -e REPEATED_TESTS=org.apache.cassandra.cql3.ViewTest,ForceCompactionTest" + echo " -e REPEATED_TESTS_COUNT=500" + echo " If you want to specify multiple environment variables simply add multiple -e options." + echo " -i Ignore unknown environment variables" + echo " -h Print help" +} + + +# legacy argument handling +case ${1} in + "build_dtest_jars" | "stress-test" | "fqltool-test" | "microbench" | "test-burn" | "long-test" | "cqlsh-test" | "simulator-dtest" | "test" | "test-cdc" | "test-compression" | "test-oa" | "test-system-keyspace-directory" | "test-latest" | "jvm-dtest" | "jvm-dtest-upgrade" | "jvm-dtest-novnode" | "jvm-dtest-upgrade-novnode") + test_type="-a ${1}" + if [[ -z ${2} ]]; then + test_list="" + elif [[ -n ${2} && "${2}" =~ ^[0-9]+/[0-9]+$ ]]; then + test_list="-c ${2}"; + else + test_list="-t ${2}"; + fi + echo "Using deprecated legacy arguments. Please update to new parameter format: ${test_type} ${test_list}" + $0 ${test_type} ${test_list} + exit $? +esac + + +env_vars="" +has_env_vars=false +check_env_vars=true +detect_changed_tests=true +while getopts "a:t:c:e:ib:shj:" opt; do + case $opt in + a ) test_target="$OPTARG" + ;; + t ) test_name_regexp="$OPTARG" + ;; + c ) chunk="$OPTARG" + ;; + e ) if (! ($has_env_vars)); then + env_vars="$OPTARG" + else + env_vars="$env_vars|$OPTARG" + fi + has_env_vars=true + ;; + b ) BASE_BRANCH="$OPTARG" + ;; + i ) check_env_vars=false + ;; + s ) detect_changed_tests=false + ;; + h ) print_help + exit 0 + ;; + j ) ;; # To avoid failing on java_version param from docker/run_tests.sh + \?) error 1 "Invalid option: -$OPTARG" + ;; + esac +done +shift $((OPTIND-1)) +if [ "$#" -ne 0 ]; then + error 1 "Unexpected arguments" +fi + +# validate environment variables +if $has_env_vars && $check_env_vars; then + for entry in $(echo $env_vars | tr "|" "\n"); do + key=$(echo $entry | tr "=" "\n" | sed -n 1p) + case $key in + "REPEATED_TESTS_STOP_ON_FAILURE" | "REPEATED_TESTS" | "REPEATED_TESTS_COUNT" ) + [[ ${test_target} == *"-repeat" ]] || { error 1 "'-e REPEATED_*' variables only valid against *-repeat target types"; } + ;; + *) + error 1 "unrecognized environment variable name: $key" + ;; + esac + done fi # print debug information on versions @@ -65,7 +155,7 @@ _split_tests() { split_cmd=split if [[ "${_split_chunk}" =~ ^[0-9]+/[0-9]+$ ]]; then ( split --help 2>&1 ) | grep -q "r/K/N" || split_cmd=gsplit - command -v ${split_cmd} >/dev/null 2>&1 || { echo >&2 "${split_cmd} needs to be installed"; exit 1; } + command -v ${split_cmd} >/dev/null 2>&1 || { error 1 "${split_cmd} needs to be installed"; } ${split_cmd} -n r/${_split_chunk} elif [[ "x" != "x${_split_chunk}" ]] ; then grep -e "${_split_chunk}" @@ -78,6 +168,11 @@ _timeout_for() { grep "name=\"${1}\"" build.xml | awk -F'"' '{print $4}' } +_get_env_var() { + [[ ${env_vars} =~ ${1}=([^|]+) ]] + echo "${BASH_REMATCH[1]}" +} + _build_all_dtest_jars() { # build the dtest-jar for the branch under test. remember to `ant clean` if you want a new dtest jar built @@ -127,41 +222,89 @@ _build_all_dtest_jars() { _run_testlist() { local _target_prefix=$1 local _testlist_target=$2 - local _split_chunk=$3 - local _test_timeout=$4 - testlist="$( _list_tests "${_target_prefix}" | _split_tests "${_split_chunk}")" - if [[ "${_split_chunk}" =~ ^[0-9]+/[0-9]+$ ]]; then + local _test_name_regexp=$3 + local _split_chunk=$4 + local _test_timeout=$5 + local _test_iterations=${6:-1} + + # are we running ${_test_name_regexp} or ${_split_chunk} + if [ -n "${_test_name_regexp}" ]; then + echo "Running tests: ${_test_name_regexp} (${_test_iterations} times)" + # test regexp can come in csv + for i in ${_test_name_regexp//,/ }; do + [ -n "${testlist}" ] && testlist="${testlist}"$'\n' + testlist="${testlist}$( _list_tests "${_target_prefix}" | _split_tests "${i}")" + done + [[ -z "${testlist}" ]] && error 1 "No tests found in test name regexp: ${_test_name_regexp}" + else + [ -n "${_split_chunk}" ] || { error 1 "Neither name regexp or split chunk defined"; } + echo "Running split: ${_split_chunk}" + testlist="$( _list_tests "${_target_prefix}" | _split_tests "${_split_chunk}")" if [[ -z "${testlist}" ]]; then # something has to run in the split to generate a junit xml result echo "Hacking ${_target_prefix} ${_testlist_target} to run only first test found as no tests in split ${_split_chunk} were found" - testlist="$( _list_tests "${_target_prefix}" | head -n1)" - fi - else - if [[ -z "${testlist}" ]]; then - echo "No tests match ${_split_chunk}" - exit 1 + testlist="$( _list_tests "${_target_prefix}" | sed -n 1p)" fi fi - ant $_testlist_target -Dtest.classlistprefix="${_target_prefix}" -Dtest.classlistfile=<(echo "${testlist}") -Dtest.timeout="${_test_timeout}" ${ANT_TEST_OPTS} || echo "failed ${_target_prefix} ${_testlist_target} ${split_chunk}" + + local -r _results_uuid="$(command -v uuidgen >/dev/null 2>&1 && uuidgen || cat /proc/sys/kernel/random/uuid)" + local failures=0 + for ((i=0; i < _test_iterations; i++)); do + [ "${_test_iterations}" -eq 1 ] || printf "–––– run ${i}\n" + set +o errexit + ant "$_testlist_target" -Dtest.classlistprefix="${_target_prefix}" -Dtest.classlistfile=<(echo "${testlist}") -Dtest.timeout="${_test_timeout}" ${ANT_TEST_OPTS} + ant_status=$? + set -o errexit + if [[ $ant_status -ne 0 ]]; then + echo "failed ${_target_prefix} ${_testlist_target} ${split_chunk} ${_test_name_regexp}" + + # Only store logs for failed tests on repeats to save up space + if [ "${_test_iterations}" -gt 1 ]; then + # Get this test results and rename file with iteration and 'fail' + find "${DIST_DIR}"/test/output/ -type f -name "*.xml" -not -name "*fail.xml" -print0 | while read -r -d $'\0' file; do + mv "${file}" "${file%.xml}-${_results_uuid}-${i}-fail.xml" + done + find "${DIST_DIR}"/test/logs/ -type f -name "*.log" -not -name "*fail.log" -print0 | while read -r -d $'\0' file; do + mv "${file}" "${file%.log}-${_results_uuid}-${i}-fail.log" + done + + if [ "$(_get_env_var 'REPEATED_TESTS_STOP_ON_FAILURE')" == true ]; then + error 0 "fail fast, after ${i} successful runs" + fi + let failures+=1 + fi + fi + done + [ "${_test_iterations}" -eq 1 ] || printf "––––\nfailure rate: ${failures}/${_test_iterations}\n" } _main() { # parameters - local -r target="${1:-}" + local -r target="${test_target/-repeat/}" + local -r split_chunk="${chunk:-'1/1'}" # Chunks formatted as "K/N" for the Kth chunk of N chunks - local -r split_chunk="${2:-'1/1'}" # Optional: pass in chunk or regexp to test. Chunks formatted as "K/N" for the Kth chunk of N chunks # check split_chunk is compatible with target (if not a regexp) if [[ "${_split_chunk}" =~ ^\d+/\d+$ ]] && [[ "1/1" != "${split_chunk}" ]] ; then case ${target} in "stress-test" | "fqltool-test" | "microbench" | "cqlsh-test" | "simulator-dtest") - echo "Target ${target} does not suport splits." - exit 1 + error 1 "Target ${target} does not suport splits." ;; *) ;; esac fi + # "-repeat" is a reserved suffix on target types + if [[ ${test_target} == *"-repeat" ]] ; then + [[ "${split_chunk}" =~ ^[0-9]+/[0-9]+$ ]] && { error 1 "Repeated tests not valid with splits"; } + if [[ -z "${test_name_regexp}" ]] ; then + test_name_regexp="$(_get_env_var 'REPEATED_TESTS')" + fi + local -r repeat_count="$(_get_env_var 'REPEATED_TESTS_COUNT')" + else + test_name_regexp="${test_name_regexp:-}" + fi + pushd ${CASSANDRA_DIR}/ >/dev/null # jdk check @@ -170,15 +313,14 @@ _main() { local -r java_version_default=`grep 'property\s*name="java.default"' build.xml |sed -ne 's/.*value="\([^"]*\)".*/\1/p'` if [ "${java_version}" -eq 17 ] && [[ "${target}" == "jvm-dtest-upgrade" ]] ; then - echo "Invalid JDK${java_version}. Only overlapping supported JDKs can be used when upgrading, as the same jdk must be used over the upgrade path." - exit 1 + error 1 "Invalid JDK${java_version}. Only overlapping supported JDKs can be used when upgrading, as the same jdk must be used over the upgrade path." fi # check project is already built. no cleaning is done, so jenkins unstash works, beware. - [[ -f "${DIST_DIR}/apache-cassandra-${version}.jar" ]] || [[ -f "${DIST_DIR}/apache-cassandra-${version}-SNAPSHOT.jar" ]] || { echo "Project must be built first. Use \`ant jar\`. Build directory is ${DIST_DIR} with: $(ls ${DIST_DIR} | xargs)"; exit 1; } + [[ -f "${DIST_DIR}/apache-cassandra-${version}.jar" ]] || [[ -f "${DIST_DIR}/apache-cassandra-${version}-SNAPSHOT.jar" ]] || { error 1 "Project must be built first. Use \`ant jar\`. Build directory is ${DIST_DIR} with: $(ls ${DIST_DIR} | xargs)"; } # check if dist artifacts exist, this breaks the dtests - [[ -d "${DIST_DIR}/dist" ]] && { echo "tests don't work when build/dist ("${DIST_DIR}/dist") exists (from \`ant artifacts\`)"; exit 1; } + [[ -d "${DIST_DIR}/dist" ]] && { error 1 "tests don't work when build/dist ("${DIST_DIR}/dist") exists (from \`ant artifacts\`)"; } # ant test setup export TMP_DIR="${DIST_DIR}/tmp" @@ -207,42 +349,44 @@ _main() { ant $target ${ANT_TEST_OPTS} -Dmaven.test.failure.ignore=true ;; "test") - _run_testlist "unit" "testclasslist" "${split_chunk}" "$(_timeout_for 'test.timeout')" + _run_testlist "unit" "testclasslist" "${test_name_regexp}" "${split_chunk}" "$(_timeout_for 'test.timeout')" "${repeat_count}" ;; "test-cdc") - _run_testlist "unit" "testclasslist-cdc" "${split_chunk}" "$(_timeout_for 'test.timeout')" + _run_testlist "unit" "testclasslist-cdc" "${test_name_regexp}" "${split_chunk}" "$(_timeout_for 'test.timeout')" "${repeat_count}" ;; "test-compression") - _run_testlist "unit" "testclasslist-compression" "${split_chunk}" "$(_timeout_for 'test.timeout')" + _run_testlist "unit" "testclasslist-compression" "${test_name_regexp}" "${split_chunk}" "$(_timeout_for 'test.timeout')" "${repeat_count}" ;; "test-oa") - _run_testlist "unit" "testclasslist-oa" "${split_chunk}" "$(_timeout_for 'test.timeout')" + _run_testlist "unit" "testclasslist-oa" "${test_name_regexp}" "${split_chunk}" "$(_timeout_for 'test.timeout')" "${repeat_count}" ;; "test-system-keyspace-directory") - _run_testlist "unit" "testclasslist-system-keyspace-directory" "${split_chunk}" "$(_timeout_for 'test.timeout')" + _run_testlist "unit" "testclasslist-system-keyspace-directory" "${test_name_regexp}" "${split_chunk}" "$(_timeout_for 'test.timeout')" "${repeat_count}" ;; "test-latest") - _run_testlist "unit" "testclasslist-latest" "${split_chunk}" "$(_timeout_for 'test.timeout')" + _run_testlist "unit" "testclasslist-latest" "${test_name_regexp}" "${split_chunk}" "$(_timeout_for 'test.timeout')" "${repeat_count}" ;; "test-burn") - _run_testlist "burn" "testclasslist" "${split_chunk}" "$(_timeout_for 'test.burn.timeout')" + _run_testlist "burn" "testclasslist" "${test_name_regexp}" "${split_chunk}" "$(_timeout_for 'test.burn.timeout')" "${repeat_count}" ;; "long-test") - _run_testlist "long" "testclasslist" "${split_chunk}" "$(_timeout_for 'test.long.timeout')" + _run_testlist "long" "testclasslist" "${test_name_regexp}" "${split_chunk}" "$(_timeout_for 'test.long.timeout')" "${repeat_count}" ;; "simulator-dtest") ant test-simulator-dtest ${ANT_TEST_OPTS} || echo "failed ${target}" ;; "jvm-dtest" | "jvm-dtest-novnode") [ "jvm-dtest-novnode" == "${target}" ] || ANT_TEST_OPTS="${ANT_TEST_OPTS} -Dcassandra.dtest.num_tokens=16" - testlist=$( _list_tests "distributed" | grep -v "upgrade" | _split_tests "${split_chunk}") - if [[ -z "$testlist" ]]; then - [[ "${split_chunk}" =~ ^[0-9]+/[0-9]+$ ]] || { echo "No tests match ${split_chunk}"; exit 1; } + if [[ -z "${test_name_regexp}" ]] ; then + test_name_regexp=$( _list_tests "distributed" | grep -v "upgrade" | _split_tests "${split_chunk}") + if [[ -z "${test_name_regexp}" ]]; then + [[ "${split_chunk}" =~ ^[0-9]+/[0-9]+$ ]] || { error 1 "No tests match ${test_name_regexp}"; } # something has to run in the split to generate a junit xml result echo "Hacking jvm-dtest to run only first test found as no tests in split ${split_chunk} were found" - testlist="$( _list_tests "distributed" | grep -v "upgrade" | head -n1)" + test_name_regexp="$( _list_tests "distributed" | grep -v "upgrade" | sed -n 1p)" + fi fi - ant testclasslist -Dtest.classlistprefix=distributed -Dtest.timeout=$(_timeout_for "test.distributed.timeout") -Dtest.classlistfile=<(echo "${testlist}") ${ANT_TEST_OPTS} || echo "failed ${target} ${split_chunk}" + _run_testlist "distributed" "testclasslist" "${test_name_regexp}" "" "$(_timeout_for 'test.distributed.timeout')" "${repeat_count}" ;; "build_dtest_jars") _build_all_dtest_jars @@ -250,21 +394,22 @@ _main() { "jvm-dtest-upgrade" | "jvm-dtest-upgrade-novnode") _build_all_dtest_jars [ "jvm-dtest-upgrade-novnode" == "${target}" ] || ANT_TEST_OPTS="${ANT_TEST_OPTS} -Dcassandra.dtest.num_tokens=16" - testlist=$( _list_tests "distributed" | grep "upgrade" | _split_tests "${split_chunk}") - if [[ -z "${testlist}" ]]; then - [[ "${split_chunk}" =~ ^[0-9]+/[0-9]+$ ]] || { echo "No tests match ${split_chunk}"; exit 1; } + if [[ -z "${test_name_regexp}" ]] ; then + test_name_regexp=$( _list_tests "distributed" | grep "upgrade" | _split_tests "${split_chunk}") + if [[ -z "${test_name_regexp}" ]]; then + [[ "${split_chunk}" =~ ^[0-9]+/[0-9]+$ ]] || { error 1 "No tests match ${test_name_regexp}"; } # something has to run in the split to generate a junit xml result echo "Hacking jvm-dtest-upgrade to run only first test found as no tests in split ${split_chunk} were found" - testlist="$( _list_tests "distributed" | grep "upgrade" | head -n1)" + test_name_regexp="$( _list_tests "distributed" | grep "upgrade" | sed -n 1p)" + fi fi - ant testclasslist -Dtest.classlistprefix=distributed -Dtest.timeout=$(_timeout_for "test.distributed.timeout") -Dtest.classlistfile=<(echo "${testlist}") ${ANT_TEST_OPTS} || echo "failed ${target} ${split_chunk}" + _run_testlist "distributed" "testclasslist" "${test_name_regexp}" "" "$(_timeout_for 'test.distributed.timeout')" "${repeat_count}" ;; "cqlsh-test") ./pylib/cassandra-cqlsh-tests.sh $(pwd) ;; *) - echo "unrecognized test type \"${target}\"" - exit 1 + error 1 "unrecognized test type \"${target}\"" ;; esac diff --git a/.jenkins/Jenkinsfile b/.jenkins/Jenkinsfile index c1c7e431d2..4f8ad6c268 100644 --- a/.jenkins/Jenkinsfile +++ b/.jenkins/Jenkinsfile @@ -184,7 +184,6 @@ def tasks() { ] testSteps.each() { it.value.put('type', 'test') - it.value.put('script', '.build/docker/run-tests.sh') if (!it.value['size']) { it.value.put('size', 'medium') } @@ -360,6 +359,7 @@ def build(command, cell) { } def test(command, cell) { + if (command.containsKey('script')) { error("test commands all use `.build/docker/run-tests.sh`") } def splits = command.splits ? command.splits : 1 def maxAttempts = 2 def attempt = 0 @@ -384,7 +384,7 @@ def test(command, cell) { script_vars = fetchDTestsSource(command, script_vars) timeout(time: 1, unit: 'HOURS') { // best throughput with each cell at ~10 minutes buildJVMDTestJars(cell, script_vars, logfile) - def status = sh label: "RUNNING TESTS ${cell.step}...", script: "${script_vars} .build/docker/run-tests.sh ${cell.step} '${cell.split}/${splits}' ${cell.jdk} 2>&1 | tee >( xz -c > build/${logfile} )", returnStatus: true + def status = sh label: "RUNNING TESTS ${cell.step}...", script: "${script_vars} .build/docker/run-tests.sh -a ${cell.step} -c '${cell.split}/${splits}' -j ${cell.jdk} 2>&1 | tee >( xz -c > build/${logfile} )", returnStatus: true dir("build") { archiveArtifacts artifacts: "${logfile}", fingerprint: true copyToNightlies("${logfile}", "${cell.step}/${cell.arch}/jdk${cell.jdk}/python${cell.python}/cython_${cell.cython}/" + "split_${cell.split}_${splits}".replace("/", "_")) @@ -434,7 +434,7 @@ def buildJVMDTestJars(cell, script_vars, logfile) { try { unstash name: "jvm_dtests_${cell.arch}_${cell.jdk}" } catch (error) { - sh label: "RUNNING build_dtest_jars...", script: "${script_vars} .build/docker/run-tests.sh build_dtest_jars ${cell.jdk} 2>&1 | tee >( xz -c > build/${logfile} )" + sh label: "RUNNING build_dtest_jars...", script: "${script_vars} .build/docker/run-tests.sh -a build_dtest_jars -j ${cell.jdk} 2>&1 | tee >( xz -c > build/${logfile} )" stash name: "jvm_dtests_${cell.arch}_${cell.jdk}", includes: '**/dtest*.jar' } }