summaryrefslogblamecommitdiff
path: root/tools/partest-ack
blob: ab722e3b1c22f97a59f3a0c235dd528c6fd8347c (plain) (tree)
1
2
3
4
5
6
7
8
9



                                                                


                                            
                                                                                                              
 
                            

                                       


                                                                            
                                    
 
                                                                                            


                   

                                         
                                      
                                     
                                            
                                                                              

                                                                              





                                                                               
                                                                                     


         







                                               
 
                                                            

                                          
 


                                          




                                                   




        
                                
              
                                                  
                                        






                                                                                 



                   
                                  
 
                                                                   
                                                                                


                                                                                                                     
                                                                 
                                                                                                                                                 



                     
                                




                        



                                                                                         
            

                                                 
                                                          


              




                                                                                        

 
                                  
 
                                                                               
 




                                                              
                                                                
                                                                
       
 
                                      
#!/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