-
-
Save chatman/9d328e998fea5930e9367b113c8c55f0 to your computer and use it in GitHub Desktop.
The best Lucene / Solr beasting script in the world. TM.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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