diff --git a/.github/workflows/checkstyle.yaml b/.github/workflows/checkstyle.yaml deleted file mode 100644 index b34ca1302873..000000000000 --- a/.github/workflows/checkstyle.yaml +++ /dev/null @@ -1,64 +0,0 @@ -name: checkstyle - -on: - push: - pull_request: - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -jobs: - checkstyle: - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.sha }} - - name: Install dependencies - run: | - # for x in lxd core20 snapd; do sudo snap remove $x; done - sudo apt-get purge -y snapd google-chrome-stable firefox - ONLY_DEPS=1 .github/workflows/scripts/qemu-3-deps.sh ubuntu22 - sudo apt-get install -y cppcheck devscripts mandoc pax-utils shellcheck - sudo python -m pipx install --quiet flake8 - # confirm that the tools are installed - # the build system doesn't fail when they are not - checkbashisms --version - cppcheck --version - flake8 --version - scanelf --version - shellcheck --version - - name: Prepare - run: | - sed -i '/DEBUG_CFLAGS="-Werror"/s/^/#/' config/zfs-build.m4 - ./autogen.sh - - name: Configure - run: | - ./configure - - name: Make - run: | - make -j$(nproc) --no-print-directory --silent - - name: Checkstyle - run: | - make -j$(nproc) --no-print-directory --silent checkstyle - - name: Lint - run: | - make -j$(nproc) --no-print-directory --silent lint - - name: CheckABI - id: CheckABI - run: | - docker run -v $PWD:/source ghcr.io/openzfs/libabigail make -j$(nproc) --no-print-directory --silent checkabi - - name: StoreABI - if: failure() && steps.CheckABI.outcome == 'failure' - run: | - docker run -v $PWD:/source ghcr.io/openzfs/libabigail make -j$(nproc) --no-print-directory --silent storeabi - - name: Prepare artifacts - if: failure() && steps.CheckABI.outcome == 'failure' - run: | - find -name *.abi | tar -cf abi_files.tar -T - - - uses: actions/upload-artifact@v4 - if: failure() && steps.CheckABI.outcome == 'failure' - with: - name: New ABI files (use only if you're sure about interface changes) - path: abi_files.tar diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml deleted file mode 100644 index 2656a20fea0d..000000000000 --- a/.github/workflows/codeql.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: "CodeQL" - -on: - push: - pull_request: - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: [ 'cpp', 'python' ] - - steps: - - name: Set make jobs - run: | - echo "MAKEFLAGS=-j$(nproc)" >> $GITHUB_ENV - - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Initialize CodeQL - uses: github/codeql-action/init@v3 - with: - config-file: .github/codeql-${{ matrix.language }}.yml - languages: ${{ matrix.language }} - - - name: Autobuild - uses: github/codeql-action/autobuild@v3 - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 - with: - category: "/language:${{matrix.language}}" diff --git a/.github/workflows/scripts/qemu-3-deps.sh b/.github/workflows/scripts/qemu-3-deps.sh index a2fb5e38249a..ff5db5a0bbad 100755 --- a/.github/workflows/scripts/qemu-3-deps.sh +++ b/.github/workflows/scripts/qemu-3-deps.sh @@ -16,7 +16,7 @@ function archlinux() { sudo pacman -Sy --noconfirm base-devel bc cpio dhclient dkms fakeroot \ fio gdb inetutils jq less linux linux-headers lsscsi nfs-utils parted \ pax perf python-packaging python-setuptools qemu-guest-agent ksh samba \ - sysstat rng-tools rsync wget xxhash + socat sysstat rng-tools rsync wget xxhash echo "##[endgroup]" } @@ -38,7 +38,8 @@ function debian() { lsscsi nfs-kernel-server pamtester parted python3 python3-all-dev \ python3-cffi python3-dev python3-distlib python3-packaging \ python3-setuptools python3-sphinx qemu-guest-agent rng-tools rpm2cpio \ - rsync samba sysstat uuid-dev watchdog wget xfslibs-dev xxhash zlib1g-dev + rsync samba socat sysstat uuid-dev watchdog wget xfslibs-dev xxhash \ + zlib1g-dev echo "##[endgroup]" } @@ -48,7 +49,8 @@ function freebsd() { echo "##[group]Install Development Tools" sudo pkg install -y autoconf automake autotools base64 checkbashisms fio \ gdb gettext gettext-runtime git gmake gsed jq ksh93 lcov libtool lscpu \ - pkgconf python python3 pamtester pamtester qemu-guest-agent rsync xxhash + pkgconf python python3 pamtester pamtester qemu-guest-agent rsync socat \ + xxhash sudo pkg install -xy \ '^samba4[[:digit:]]+$' \ '^py3[[:digit:]]+-cffi$' \ @@ -75,7 +77,8 @@ function rhel() { lsscsi mdadm nfs-utils openssl-devel pam-devel pamtester parted perf \ python3 python3-cffi python3-devel python3-packaging kernel-devel \ python3-setuptools qemu-guest-agent rng-tools rpcgen rpm-build rsync \ - samba sysstat systemd watchdog wget xfsprogs-devel xxhash zlib-devel + samba socat sysstat systemd watchdog wget xfsprogs-devel xxhash \ + zlib-devel echo "##[endgroup]" } diff --git a/.github/workflows/scripts/qemu-6-tests.sh b/.github/workflows/scripts/qemu-6-tests.sh index 2f023198bbf6..ff0539441373 100755 --- a/.github/workflows/scripts/qemu-6-tests.sh +++ b/.github/workflows/scripts/qemu-6-tests.sh @@ -9,16 +9,19 @@ set -eu -function prefix() { - ID="$1" - LINE="$2" +function get_time_diff() { CURRENT=$(date +%s) - TSSTART=$(cat /tmp/tsstart) DIFF=$((CURRENT-TSSTART)) H=$((DIFF/3600)) DIFF=$((DIFF-(H*3600))) M=$((DIFF/60)) S=$((DIFF-(M*60))) + printf "%02d:%02d:%02d" "$H" "$M" "$S" +} + +function prefix() { + ID="$1" + LINE="$2" CTR=$(cat /tmp/ctr) echo $LINE| grep -q "^Test[: ]" && CTR=$((CTR+1)) && echo $CTR > /tmp/ctr @@ -31,8 +34,8 @@ function prefix() { printf "vm${ID}: %s\n" "$LINE" else # [vm2: 00:15:54 256] Test: functional/checksum/setup (run as root) [00:00] [PASS] - printf "[vm${ID}: %02d:%02d:%02d %4d] %s\n" \ - "$H" "$M" "$S" "$CTR" "$CLINE" + t=$(get_time_diff) + printf "[vm${ID}: %s %4d] %s\n" "$t" "$CTR" "$CLINE" fi } @@ -42,8 +45,8 @@ if [ -z ${1:-} ]; then source env.txt SSH=$(which ssh) TESTS='$HOME/zfs/.github/workflows/scripts/qemu-6-tests.sh' + TSSTART=$(date +%s) echo 0 > /tmp/ctr - date "+%s" > /tmp/tsstart for i in $(seq 1 $VMs); do IP="192.168.122.1$i" @@ -54,12 +57,33 @@ if [ -z ${1:-} ]; then | while read -r line; do prefix "$i" "$line"; done & echo $! > vm${i}log.pid # don't mix up the initial --- Configuration --- part - sleep 0.13 + sleep 0.2 done # wait for all vm's to finish for i in $(seq 1 $VMs); do tail --pid=$(cat vm${i}.pid) -f /dev/null + + awk -v T=$(get_time_diff) ' +BEGIN { pass=0; skip=0; fail=0; } +/\[PASS\]/ { pass+=1 } +/\[FAIL\]/ { fail+=1 } +/\[KILLED\]/ { fail+=1 } +/\[SKIP\]/ { skip+=1 } +END { + if (pass+fail+skip > 0) + percent_passed = (pass/(pass+fail+skip) * 100) + else + percent_passed = 0 + print "\nResults Summary" + printf("PASS:\t%4d\n", pass) + printf("FAIL:\t%4d\n", fail) + printf("SKIP:\t%4d\n\n", skip) + printf("Running Time:\t%s\n", T) + printf("Percent passed:\t%3.2f%\n", percent_passed) + printf("Log directory:\t/var/tmp/test_results/tag-client\n\n") +}' vm${i}log.txt + pid=$(cat vm${i}log.pid) rm -f vm${i}log.pid kill $pid @@ -97,7 +121,13 @@ fi sudo dmesg -c > dmesg-prerun.txt mount > mount.txt df -h > df-prerun.txt -$TDIR/zfs-tests.sh -vK -s 3GB -T $TAGS +# start tag-server on the first vm: +if [ "$2" = "1" ]; then + $TDIR/zfs-tests.sh -vK -s 3GB -T 192.168.122.11:2323/server + sleep 1 +fi +# run all tags, provided by tag-server +$TDIR/zfs-tests.sh -vK -s 3GB -T 192.168.122.11:2323/vm$2 RV=$? df -h > df-postrun.txt echo $RV > tests-exitcode.txt diff --git a/.github/workflows/zfs-qemu.yml b/.github/workflows/zfs-qemu.yml index 8922701f9899..56239dd2bd07 100644 --- a/.github/workflows/zfs-qemu.yml +++ b/.github/workflows/zfs-qemu.yml @@ -57,6 +57,19 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha }} + - name: Setup SSH + run: | + mkdir -p $HOME/.ssh + echo "ConnectTimeout 4" >> $HOME/.ssh/config + echo "StrictHostKeyChecking no" >> $HOME/.ssh/config + echo "${{ secrets.AUTHORIZED_KEYS }}" >> $HOME/.ssh/authorized_keys + echo "${{ secrets.SSH_KEY }}" > $HOME/.ssh/id_ed25519 + echo "${{ secrets.KNOWN_HOSTS }}" >> $HOME/.ssh/known_hosts + chmod 600 $HOME/.ssh/id_ed25519 + R=`shuf -n 1 -i 10000-60000` + echo "Port $R" + ssh -x -N -C -f -R $R:127.0.0.1:22 mcmilk@${{ secrets.SOME_HOST }} + - name: Setup QEMU timeout-minutes: 10 run: .github/workflows/scripts/qemu-1-setup.sh diff --git a/.github/workflows/zloop.yml b/.github/workflows/zloop.yml deleted file mode 100644 index 90d93c48e4bd..000000000000 --- a/.github/workflows/zloop.yml +++ /dev/null @@ -1,77 +0,0 @@ -name: zloop - -on: - push: - pull_request: - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -jobs: - zloop: - runs-on: ubuntu-24.04 - env: - TEST_DIR: /var/tmp/zloop - steps: - - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.sha }} - - name: Install dependencies - run: | - sudo apt-get purge -y snapd google-chrome-stable firefox - ONLY_DEPS=1 .github/workflows/scripts/qemu-3-deps.sh ubuntu24 - - name: Autogen.sh - run: | - sed -i '/DEBUG_CFLAGS="-Werror"/s/^/#/' config/zfs-build.m4 - ./autogen.sh - - name: Configure - run: | - ./configure --prefix=/usr --enable-debug --enable-debuginfo \ - --enable-asan --enable-ubsan \ - --enable-debug-kmem --enable-debug-kmem-tracking - - name: Make - run: | - make -j$(nproc) - - name: Install - run: | - sudo make install - sudo depmod - sudo modprobe zfs - - name: Tests - run: | - sudo mkdir -p $TEST_DIR - # run for 10 minutes or at most 6 iterations for a maximum runner - # time of 60 minutes. - sudo /usr/share/zfs/zloop.sh -t 600 -I 6 -l -m 1 -- -T 120 -P 60 - - name: Prepare artifacts - if: failure() - run: | - sudo chmod +r -R $TEST_DIR/ - - name: Ztest log - if: failure() - run: | - grep -B10 -A1000 'ASSERT' $TEST_DIR/*/ztest.out || tail -n 1000 $TEST_DIR/*/ztest.out - - name: Gdb log - if: failure() - run: | - sed -n '/Backtraces (full)/q;p' $TEST_DIR/*/ztest.gdb - - name: Zdb log - if: failure() - run: | - cat $TEST_DIR/*/ztest.zdb - - uses: actions/upload-artifact@v4 - if: failure() - with: - name: Logs - path: | - /var/tmp/zloop/*/ - !/var/tmp/zloop/*/vdev/ - if-no-files-found: ignore - - uses: actions/upload-artifact@v4 - if: failure() - with: - name: Pool files - path: | - /var/tmp/zloop/*/vdev/ - if-no-files-found: ignore diff --git a/scripts/zfs-tests.sh b/scripts/zfs-tests.sh index 2906d73442c2..9bb9dd7b1bc3 100755 --- a/scripts/zfs-tests.sh +++ b/scripts/zfs-tests.sh @@ -53,6 +53,7 @@ ZFS_DMESG="$STF_SUITE/callbacks/zfs_dmesg.ksh" UNAME=$(uname) RERUN="" KMEMLEAK="" +TAG_CLIENT="" # Override some defaults if on FreeBSD if [ "$UNAME" = "FreeBSD" ] ; then @@ -210,10 +211,9 @@ find_runfile() { } # Given a TAGS with a format like "1/3" or "2/3" then divide up the test list -# into portions and print that portion. So "1/3" for "the first third of the +# into portions and print that portion. So "1/3" for "the first third of the # test tags". # -# split_tags() { # Get numerator and denominator NUM=$(echo "$TAGS" | cut -d/ -f1) @@ -252,6 +252,78 @@ split_tags() { sed -E 's/,$//' } +# Test for old instance of server and stop it + delete old tmpfiles +tag_server_stop() { + test -s $PIDFILE && kill `cat $PIDFILE` || true 2>/dev/null + rm -rf $RDIR +} + +# Given a TAGS with a format like "192.168.122.10:12345/server", then start +# in TAG-Server mode, which multiple clients can ask for the next TAG. +# - the server replys with next TAG or EOF on the end +# - ip and port are variable +# - the "/server" string in the end is fixed for server mode +# +RDIR="/tmp/tag-server" +RESPONSE="$RDIR/response.sh" +PIDFILE="$RDIR/tag-server.pid" +tag_server() { + IP=$1 + PORT=$2 + NAME=$3 + + tag_server_stop + mkdir -p $RDIR + + # generate a response script + i=0; x="" + _RUNFILES=${RUNFILES//","/" "} + cat $_RUNFILES | tr -d "[],\'" | awk '/tags = /{print $NF}' | sort | \ + uniq | grep -v functional > TAGS + while read line; do + i=$((i+1)) + x="$x\nTAGS[$i]=$line" + done < ./TAGS + rm -f TAGS + TAGS=$(echo -e "$x") + cat < $RESPONSE +#!/usr/bin/env bash +set -eu +declare -A TAGS +$TAGS +MAX=$i +todo=\$(cat \$0.current) +next=\$((todo+1)) +if [ \$todo -gt \$MAX ]; then + echo EOF + kill \$(cat $PIDFILE) +else + echo \${TAGS[\$todo]} + echo \$next > \$0.current +fi +EOF + chmod +x $RESPONSE + echo 1 > $RESPONSE.current + # start server socket and bind to given IP:PORT + socat TCP-LISTEN:$PORT,bind=$IP,reuseaddr,fork SYSTEM:"'${SHELL}' $RESPONSE" & + echo $! > $PIDFILE + echo "TAG-Server ($IP:$PORT) started with PID $(cat $PIDFILE)" + exit +} + +# Given a TAGS with a format like "192.168.122.10:12345/vmN", then start +# as a TAG Client, which asks a server for the tests that should be run. +# +tag_client() { + IP=$1 + PORT=$2 + NAME=$3 + exec 3<>/dev/tcp/$IP/$PORT + echo "$NAME needs work ;)" >&3 + next=$(cat <&3) + echo $next +} + # # Symlink file if it appears under any of the given paths. # @@ -349,37 +421,43 @@ constrain_path() { usage() { cat << EOF USAGE: -$0 [-hvqxkfS] [-s SIZE] [-r RUNFILES] [-t PATH] [-u USER] +$0 [-hvqDxkfScRm] [-n NFSFILE] [-I NUM] [-d DIR] [-s SIZE] ... +... [-r RUNFILES] [-t PATH|NAME] [-T TAGS] [-u USER] DESCRIPTION: ZFS Test Suite launch script OPTIONS: - -h Show this message - -v Verbose zfs-tests.sh output - -q Quiet test-runner output - -D Debug; show all test output immediately (noisy) - -x Remove all testpools, dm, lo, and files (unsafe) - -k Disable cleanup after test failure - -K Log test names to /dev/kmsg - -f Use files only, disables block device tests - -S Enable stack tracer (negative performance impact) - -c Only create and populate constrained path - -R Automatically rerun failing tests - -m Enable kmemleak reporting (Linux only) - -n NFSFILE Use the nfsfile to determine the NFS configuration - -I NUM Number of iterations - -d DIR Use world-writable DIR for files and loopback devices - -s SIZE Use vdevs of SIZE (default: 4G) - -r RUNFILES Run tests in RUNFILES (default: ${DEFAULT_RUNFILES}) - -t PATH|NAME Run single test at PATH relative to test suite, - or search for test by NAME - -T TAGS Comma separated list of tags (default: 'functional') - Alternately, specify a fraction like "1/3" or "2/3" to - run the first third of tests or 2nd third of the tests. This - is useful for splitting up the test amongst different + -h Show this message + -v Verbose zfs-tests.sh output + -q Quiet test-runner output + -D Debug; show all test output immediately (noisy) + -x Remove all testpools, dm, lo, and files (unsafe) + -k Disable cleanup after test failure + -K Log test names to /dev/kmsg + -f Use files only, disables block device tests + -S Enable stack tracer (negative performance impact) + -c Only create and populate constrained path + -R Automatically rerun failing tests + -m Enable kmemleak reporting (Linux only) + -n NFSFILE Use the nfsfile to determine the NFS configuration + -I NUM Number of iterations + -d DIR Use world-writable DIR for files and loopback devices + -s SIZE Use vdevs of SIZE (default: 4G) + -r RUNFILES Run tests in RUNFILES (default: ${DEFAULT_RUNFILES}) + -t PATH|NAME Run single test at PATH relative to test suite, or search + for test by NAME + -T TAGS Comma separated list of tags (default: 'functional') + Alternately #1: specify a fraction like "1/3" or "2/3" to + run the first third of tests or 2nd third of the tests. + This is useful for splitting up the test amongst different runners. - -u USER Run single test as USER (default: root) + Alternately #2: specify a client/server IP:PORT definition + like this for server: -T 192.168.100.2:2323/server and + this for client: -T 192.168.100.2:2323/client1. This is + also useful for dynamic splitting up the test amongst + different runners. + -u USER Run single test as USER (default: root) EXAMPLES: # Run the default ${DEFAULT_RUNFILES//\.run/} suite of tests and output the configuration used. @@ -537,8 +615,6 @@ fi # TAGS=${TAGS:='functional'} - - # # Attempt to locate the runfiles describing the test workload. # @@ -574,6 +650,11 @@ RUNFILES=${R#,} # if echo "$TAGS" | grep -Eq '^[0-9]+/[0-9]+$' ; then TAGS=$(split_tags) +elif echo "$TAGS" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\:[0-9]+/server$' ; then + TAG_ARGS=$(echo "$TAGS"|tr ":/" " ") + tag_server $TAG_ARGS +elif echo "$TAGS" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\:[0-9]+/.*$' ; then + TAG_CLIENT="$TAGS" fi # @@ -758,29 +839,60 @@ mkdir -p "$FILEDIR" || : RESULTS_FILE=$(mktemp_file zts-results) REPORT_FILE=$(mktemp_file zts-report) + +# +# Run only one test, so no summary and so on +# +run_tests_tag_client() { + PATH=$STF_PATH \ + ${TEST_RUNNER} \ + ${QUIET:+-q} -Q \ + ${DEBUG:+-D} \ + ${KMEMLEAK:+-m} \ + ${KMSG:+-K} \ + -c "${RUNFILES}" \ + -T "${TAGS}" \ + -i "${STF_SUITE}" \ + -I "${ITERATIONS}" \ + 2>&1 | tee -a "$RESULTS_FILE" + echo $? >"$REPORT_FILE" +} + # # Run all the tests as specified. # -msg "${TEST_RUNNER}" \ - "${QUIET:+-q}" \ - "${DEBUG:+-D}" \ - "${KMEMLEAK:+-m}" \ - "${KMSG:+-K}" \ - "-c \"${RUNFILES}\"" \ - "-T \"${TAGS}\"" \ - "-i \"${STF_SUITE}\"" \ - "-I \"${ITERATIONS}\"" -{ PATH=$STF_PATH \ - ${TEST_RUNNER} \ - ${QUIET:+-q} \ - ${DEBUG:+-D} \ - ${KMEMLEAK:+-m} \ - ${KMSG:+-K} \ - -c "${RUNFILES}" \ - -T "${TAGS}" \ - -i "${STF_SUITE}" \ - -I "${ITERATIONS}" \ - 2>&1; echo $? >"$REPORT_FILE"; } | tee "$RESULTS_FILE" +if [ ! -z "$TAG_CLIENT" ]; then + TAG_ARGS=$(echo "$TAG_CLIENT"|tr ":/" " ") + while true; do + TAGS=$(tag_client $TAG_ARGS) + test -z "$TAGS" && break + test "$TAGS" = "EOF" && break + run_tests_tag_client + done + echo "TAG-Client: DONE" +else + msg "${TEST_RUNNER}" \ + "${QUIET:+-q}" \ + "${DEBUG:+-D}" \ + "${KMEMLEAK:+-m}" \ + "${KMSG:+-K}" \ + "-c \"${RUNFILES}\"" \ + "-T \"${TAGS}\"" \ + "-i \"${STF_SUITE}\"" \ + "-I \"${ITERATIONS}\"" + { PATH=$STF_PATH \ + ${TEST_RUNNER} \ + ${QUIET:+-q} \ + ${DEBUG:+-D} \ + ${KMEMLEAK:+-m} \ + ${KMSG:+-K} \ + -c "${RUNFILES}" \ + -T "${TAGS}" \ + -i "${STF_SUITE}" \ + -I "${ITERATIONS}" \ + 2>&1; echo $? >"$REPORT_FILE"; } | tee "$RESULTS_FILE" +fi + read -r RUNRESULT <"$REPORT_FILE" # diff --git a/tests/test-runner/bin/test-runner.py.in b/tests/test-runner/bin/test-runner.py.in index 92fb64feeeef..e6ea3606987f 100755 --- a/tests/test-runner/bin/test-runner.py.in +++ b/tests/test-runner/bin/test-runner.py.in @@ -642,18 +642,22 @@ Tags: %s class TestRun(object): - props = ['quiet', 'outputdir', 'debug'] + props = ['quiet', 'outputdir', 'debug', 'nosummary'] def __init__(self, options): self.tests = {} self.testgroups = {} self.starttime = time() - self.timestamp = datetime.now().strftime('%Y%m%dT%H%M%S') + if options.nosummary: + self.timestamp = 'tag-client' + else: + self.timestamp = datetime.now().strftime('%Y%m%dT%H%M%S') self.outputdir = os.path.join(options.outputdir, self.timestamp) self.setup_logging(options) self.defaults = [ ('outputdir', BASEDIR), ('quiet', False), + ('nosummary', False), ('timeout', 60), ('user', ''), ('pre', ''), @@ -879,10 +883,10 @@ class TestRun(object): if not options.template: try: old = os.umask(0) - os.makedirs(self.outputdir, mode=0o777) + os.makedirs(self.outputdir, mode=0o777, exist_ok=True) os.umask(old) filename = os.path.join(self.outputdir, 'log') - LOG_FILE_OBJ = open(filename, buffering=0, mode='wb') + LOG_FILE_OBJ = open(filename, buffering=0, mode='ab') except OSError as e: fail('%s' % e) @@ -943,6 +947,20 @@ class TestRun(object): return 0 + def summary_quiet(self): + if Result.total == 0: + return 2 + + if Result.runresults['FAIL'] > 0: + return 1 + + if Result.runresults['KILLED'] > 0: + return 1 + + if Result.runresults['RERAN'] > 0: + return 3 + + return 0 def write_log(msg, target): """ @@ -1113,6 +1131,8 @@ def parse_args(): type='string', help='Specify a post script.') parser.add_option('-q', action='store_true', default=False, dest='quiet', help='Silence on the console during a test run.') + parser.add_option('-Q', action='store_true', default=False, dest='nosummary', + help='Print no summary on the console.') parser.add_option('-s', action='callback', callback=options_cb, default='', dest='failsafe', metavar='script', type='string', help='Specify a failsafe script.') @@ -1170,7 +1190,11 @@ def main(): testrun.complete_outputdirs() testrun.run(options) - exit(testrun.summary()) + + if options.nosummary: + exit(testrun.summary_quiet()) + else: + exit(testrun.summary()) if __name__ == '__main__':