Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save chatman/9d328e998fea5930e9367b113c8c55f0 to your computer and use it in GitHub Desktop.
Save chatman/9d328e998fea5930e9367b113c8c55f0 to your computer and use it in GitHub Desktop.
The best Lucene / Solr beasting script in the world. TM.
#!/usr/bin/env bash
# The best Lucene / Solr beasting script in the world. TM. 3.9.2
#
# This script will fire off N independent test runs for a class, X of them in parallel.
#
# A results.log file is written to the {results-dir}. A non zero exit status indicates a failed run.
# If the test was executed properly there will always be one line entry for each run in the results.log file, success or failure.
#
# Logs for each run are independently written under the {results-dir}/1 directory.
#
# Why is it so great? It outsources all of the heavy lifting.
#
# Required:
#
# 1. sudo apt-get install parallel or equiv for other package managers
#
# Example: beast.sh /workspace/lucene-solr lucene ~/beast-tmp TestClass ~/beast-results y y 12 4
#
# Cmd Param Help
# ---------------
# checkout-dir: the location of the lucene-solr repo checkout
# lucene or solr: which project to run the test from
# tmp-output-dir: temporary use directory
# testclass: the simple name of the test class to run or a glob pattern
# results-dir: the directory to write test results to
# y or n, clean and compile: y will clean and compile project before running tests
# y or n, user-interactive: y shows the user progress, n is better for scripts, jenkins, etc
# total-runs: how many times to run the test
# parallel-runs: how many parallel executions of the test to launch
#
# Optional:
#
# If you install guake, a result monitoring tab is opened for you.
# Trouble Shooting:
# * Hangs in compile on resolve: see LUCENE-6743. Either use Ivy 2.4.0 and artifact-lock-nio (see below)
# or workaround with find ~/.ivy2 -name "*.lck" -type f -exec rm {} \;
# NOTE:
#
# A recent dev checkout of lucene / solr will work with no changes (SOLR-7135 or SOLR-7429, LUCENE-6277).
#
# An older checkout may require a couple tweaks:
#
# 1. you must remove the content of the sync-hack target from solr/server/build.xml - it can interfere in parallel runs
# 2. lucene/ive-settings.xml Caches needs a resolutionCacheDir of ${tests.workDir}/ivy-resolution-cache
# NOTE: Ivy 2.4.0 or greater is recommended so that artifact-lock-nio can be used, but 2.3.0 will also work
#
# In ~/build.properties add:
# ivy.bootstrap.version=2.4.0
# ivy_checksum_sha1=5abe4c24bbe992a9ac07ca563d5bd3e8d569e9ed
# ivy.lock-strategy=artifact-lock-nio
# LICENSE
#
# Copyright 2016 Mark Miller
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
if [ "$#" -ne 9 ]; then
echo "Incorrect number of parameters. Usage: beast.sh {checkout-dir} {lucene|solr} {tmp-output-dir} {testclass} {results-dir} {y|n clean-and-compile} {y|n user-interactive} {total-runs} {parallel-runs}"
echo "Example: beast.sh /workspace/lucene-solr lucene ~/beast-tmp TestClass ~/beast-results y y 12 4"
exit 1
fi
command -v parallel >/dev/null 2>&1 || { echo >&2 "I require parallel but it's not installed. Aborting. To install: sudo apt-get install parallel or equiv for other package managers"; exit 1; }
baseDir=$1
subdir=$2
tmpdir=$3
testClass=$4
resultsDir=$5
cleanAndCompile=$6
userInteractive=$7
iters=$8
parr=$9
trap 'jobs -p | xargs kill > /dev/null 2>&1' EXIT
# some pretty progress for the user as compile can take > 1 min
progress()
{
if [ "$userInteractive" = "y" ]; then
local pid=$1
local outfile=$2
local delay=2.00
local progressString='|/-\'
local startTime=$(date +%s)
while [ "$(ps a | awk '{print $1}' | grep $pid)" ]; do
local temp=${progressString#?}
local endTime=$(date +%s)
local nowtime=$(($endTime-$startTime))
local outsize=0
if [ ! -z "$outfile" ]; then
outsize=$(wc -c <"$outfile")
fi
printf " [%c] " "$progressString"
printf "%05d" $nowtime
printf "sec "
if [ ! -z "$outfile" ]; then
printf "%08d" $outsize
printf "bytes"
fi
local progressString=$temp${progressString%"$temp"}
sleep $delay
printf "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
if [ ! -z "$outfile" ]; then
printf "\b\b\b\b\b\b\b\b\b\b\b\b\b"
fi
done
printf " \b\b\b\b"
fi
}
run_guake()
{
# may not have guake intalled, but that is okay, we dump output to /dev/null
sleep 2; guake -n quake -e "tail --pid=$$ -f $1 | cut -c1-50; exit 0" guake -r "$2" >/dev/null 2>&1
}
open_guake_tabs()
{
run_guake "$resultsDir/results.log" "beast-results-$testClass"
run_guake "$resultsDir/1/1/stdout" "beast-stdout-1-$testClass"
run_guake "$resultsDir/1/1/stderr" "beast-stderr-1-$testClass"
}
# first we look for the test
if [ -z $(find $baseDir -name "$testClass.java") ]
then
echo "Could not find test class: $testClass"
exit 1
fi
rm -r -f $resultsDir/1
cd $baseDir
mkdir -p $resultsDir
mkdir -p $tmpdir/parallel-tmp
echo -e "\nTest Beasting Script\n"
echo "Project: $subdir"
echo "Test class: $testClass"
echo "Running $iters iterations, $parr at a time."
cd $subdir
if [ "$cleanAndCompile" = "y" ]; then
echo -e "\nTop level clean..."
ant clean > $tmpdir/ant-clean-output.txt 2>&1
if [ $? -ne 0 ]; then
cat $tmpdir/ant-clean-output.txt
echo "Top level clean failed"
exit 1
fi
echo "Top level clean finished successfully"
echo -e "\nCompile..."
if [ "$userInteractive" = "y" ]; then
echo "Output bytes allows you to gauge forward progress."
echo "Monitor output with 'tail -f $tmpdir/ant-compile-output.txt'"
fi
(ant resolve compile compile-test > $tmpdir/ant-compile-output.txt 2>&1) &
pid=$!
progress $pid $tmpdir/ant-compile-output.txt &
wait $pid
if [ $? -ne 0 ]; then
cat $tmpdir/ant-compile-output.txt
echo "Compile failed"
exit 1
fi
fi
echo -e "\n\nBeasting started..."
echo "Sanity check test launch by looking at 'tail -f $resultsDir/1/1/stdout' and 'tail -f $resultsDir/1/1/stderr'"
echo "Monitor partial results with 'tail -f $resultsDir/results.log' "
if [ "$userInteractive" = "y" ]; then
# if guake is available, we open the results automatically
open_guake_tabs &
fi
# add --verbose for debugging
parallel --no-notice --progress -j$parr --res $resultsDir --joblog $resultsDir/results.log --tmpdir $tmpdir/parallel-tmp ant $JAVA_OPTS -Divy.resolution-cache.dir=$tmpdir/{1}/ivy-cache -Divy.sync=false -Dtests.workDir=$tmpdir/{1} -Dtests.cachedir=$tmpdir/{1}/test-caches -Dlocal.caches=$tmpdir/{1}/local-caches -Djava.io.tmpdir=$tmpdir/{1}/tmp -Dsolr.skip.sync-hack=true -Dtestcase=$testClass test > /dev/null 2>&1 ::: $(eval echo {1..$iters})
success=$?
echo -e "\nResults (ExitVal > 0 indicates test fail):\n"
cut -c1-50 $resultsDir/results.log
if [ $success -ne 0 ]; then
echo -e "\nBeasting was a failure"
exit 1
fi
echo -e "\nBeasting was a success"
exit 0
# NOTES
# solr.skip.sync-hack from SOLR-7135 is only needed for historic checkouts, see SOLR-7429
# ivy.sync=false: SOLR-7429 made it likely that .ivy2 jar files can be corrupted when ant targets
# are run in parallel. SOLR-7945 addresses this and if you have a checkout after
# SOLR-7429 but before SOLR-7945, you will need to apply the patch for SOLR-7945.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment