summaryrefslogtreecommitdiff
path: root/tools/partest-ack
diff options
context:
space:
mode:
Diffstat (limited to 'tools/partest-ack')
-rwxr-xr-xtools/partest-ack131
1 files changed, 131 insertions, 0 deletions
diff --git a/tools/partest-ack b/tools/partest-ack
new file mode 100755
index 0000000000..ab722e3b1c
--- /dev/null
+++ b/tools/partest-ack
@@ -0,0 +1,131 @@
+#!/usr/bin/env bash
+#
+# wrapper around partest for fine-grained test selection via ack
+
+declare quiet failed update partest_debug
+declare cotouched since sortCommand
+declare -a ack_args partest_args scalac_args
+declare -r standard_ack_args="--noenv -s --java --scala --type-add=scala:ext:flags,check --files-with-matches"
+
+partest_args=( --show-diff )
+bindir="$(cd "$(dirname "$0")" && pwd)"
+base="$bindir/.."
+cd "$base" || { echo "Could not change to base directory $base" && exit 1; }
+filesdir="test/files"
+sortCommand="sort -u"
+partestPaths="$bindir/partest-paths"
+
+[[ -x "$partestPaths" ]] || { echo "Cannot find partest-paths in $partestPaths" && exit 1; }
+
+[[ $# -gt 0 ]] || {
+ cat <<EOM
+Usage: $0 <regex> [-dfquvp] [ack options]
+
+ -f pass --failed to partest
+ -q pass --terse to partest
+ -u pass --update-check to partest
+ -p <path> select tests appearing in commits where <path> was also modified
+ -s <time> select tests touched since <time> (git format, e.g. 1.month.ago)
+ -r run tests in random order
+
+Given a regular expression (and optionally, any arguments accepted by ack)
+runs all the tests for which any associated file matches the regex. Associated
+files include .check and .flags files. Tests in directories will match if any
+file matches. A file can match the regex by its contents or by its name.
+
+You must have ack version 2.12+ installed: http://beyondgrep.com/ack-2.12-single-file
+
+Examples:
+
+ > tools/partest-ack 'case (class|object) Baz'
+ % testsWithMatchingPaths ... 0
+ % testsWithMatchingCode ... 3
+ # 3 tests to run.
+
+ > tools/partest-ack -s 12.hours.ago
+ % testsTouchedSinceGitTime ... 33
+ # 33 tests to run.
+
+ > tools/partest-ack -p src/library/scala/Enumeration.scala
+ % testsModifiedInSameCommit ... 80
+ # 80 tests to run.
+
+ > tools/partest-ack -f
+ % tests-which-failed ... 42
+ # 42 tests to run.
+
+ > tools/partest-ack "kinds of the type arguments"
+ % testsWithMatchingPaths ... 0
+ % testsWithMatchingCode ... 6
+ # 6 tests to run.
+EOM
+
+ exit 0
+}
+
+while getopts :fuvdrp:s: opt; do
+ case $opt in
+ f) failed=true && partest_args+=" --failed" ;;
+ p) cotouched="$cotouched $OPTARG" ;;
+ r) sortCommand="randomSort" ;;
+ s) since="$OPTARG" ;;
+ q) partest_args+=" --terse" ;;
+ u) partest_args+=" --update-check" ;;
+ v) partest_args+=" --verbose" ;;
+ :) echo "Option -$OPTARG requires an argument." >&2 ;;
+ *) ack_args+="-$OPTARG" ;; # don't drop unknown args, assume they're for ack
+ esac
+done
+
+shift $((OPTIND-1))
+ack_args=( "${ack_args[@]}" "$@" )
+
+# These methods all just create paths which may or may not be tests
+# all are filtered through partest-paths which limits the output to actual tests
+regexPathTests () { find "$filesdir" | ack --noenv "$@"; }
+failedTests () { for p in $(find "$filesdir" -name '*.log'); do p1=${p%.log} && p2=${p1%-*} && echo "$p2"; done; }
+sinceTests() { git log --since="$@" --name-only --pretty="format:" -- "$filesdir"; }
+regexCodeTests () { ack $standard_ack_args "$@" -- "$filesdir"; }
+sameCommitTests() { for rev in $(git rev-list HEAD -- "$@"); do git --no-pager show --pretty="format:" --name-only "$rev" -- "$filesdir"; done; }
+
+countStdout () {
+ local -i count=0
+ while read line; do
+ printf "$line\n" && count+=1
+ done
+
+ printf >&2 " $count\n"
+}
+
+randomSort () {
+ sort -u | while read line; do echo "$RANDOM $line"; done | sort | sed -E 's/^[0-9]+ //'
+}
+
+testRun () {
+ local description="$1" && shift
+ printf >&2 "%% tests %-25s ... " "$description"
+ "$@" | "$partestPaths" | countStdout | egrep -v '^[ ]*$'
+}
+
+allMatches() {
+ [[ -n $ack_args ]] && testRun "with matching paths" regexPathTests "${ack_args[@]}"
+ [[ -n $ack_args ]] && testRun "with matching code" regexCodeTests "${ack_args[@]}"
+ [[ -n $cotouched ]] && testRun "modified in same commit" sameCommitTests $cotouched
+ [[ -n $since ]] && testRun "modified since time" sinceTests "$since"
+ [[ -n $failed ]] && testRun "failed on last run" failedTests
+}
+
+paths=$(allMatches | $sortCommand)
+
+[[ -z $paths ]] && [[ -z $failed ]] && echo >&2 "No matching tests." && exit 0;
+
+count=$(echo $(echo "$paths" | wc -w))
+[[ "$count" -eq 0 ]] && echo >&2 "No tests to run." && exit 0;
+
+# Output a command line which will re-run these same tests.
+echo "# $count tests to run."
+printf "%-52s %s\n" "$base/test/partest ${partest_args[*]}" "\\"
+for path in $paths; do printf " %-50s %s\n" "$path" "\\"; done
+echo ""
+
+test/partest ${partest_args[*]} $paths