Skip to content

Instantly share code, notes, and snippets.

@joshzcold
Last active July 1, 2021 21:33
Show Gist options
  • Save joshzcold/d40e7ee47749851b6dda32314b5efab9 to your computer and use it in GitHub Desktop.
Save joshzcold/d40e7ee47749851b6dda32314b5efab9 to your computer and use it in GitHub Desktop.
Run Selenium Testing and record browser along with testing log. This is geared towards TestNG and Gradle, but there is no reason you can't rip out the video section and use the testing tool of your choice.
#!/usr/bin/env bash
# set -x
# PS4='+${LINENO}: '
set -euo pipefail
IFS=$'\n\t'
method=""
class=""
package=""
directory=""
test_fail_exit=0
video=false
keep_logs=false
video_output=$PWD
testIndicator="@Test"
video_extension=".mp4"
xvfb_display=""
video_cmds=$(mktemp)
function startVideo(){
kill_count=0
while [ ! -f $video_output/$1.log ];do
[ "$kill_count" -gt 30 ] && echo "could not get testing log within limit" && exit 1
sleep 1
((kill_count=kill_count+1))
echo $video_output/$1.log $kill_count
done
if [ -f $video_output/$1.log ];then
# start recording video in background
echo > $video_cmds
set -x
tail -f $video_cmds | ffmpeg -f x11grab -y \
-video_size 1920x1080 -hide_banner \
-loglevel error -i :$xvfb_display \
-codec:v libx264 -r 12 \
-vf "drawtext=textfile=$video_output/$1.log \
:fontcolor=white \
:fontsize=18 \
:box=1 \
:boxcolor=black@0.7 \
:reload=1
:x=w-tw-20:y=h-th-20" \
$video_output/$1$video_extension
set +x
else
echo "no log file for ffmpeg video recording. skipping video recording"
fi
}
function testCommand(){
# 1. Run gradle with arguments
# 2. Tee stdout to tty and to stdin for sed
# 3. replace lines >60 with a newline
echo "Loading..." > $video_output/$2.log
if $video; then
set -x
./gradlew test $gradle_options --rerun-tasks $1$2 2>&1 |
tee >(sed -u -e "s/.\{75\}/&\n/g" >> $video_output/$2.log)
set +x
else
set -x
./gradlew test $gradle_options --rerun-tasks $1$2
set +x
fi
}
function testDirectory(){
for f in $(find $directory -name "*.groovy")
do
package=$(head -1 $f | awk '{print $2}')
#xargs removes white space
class=$(grep -Po "(?<=class)\s\w+\s" $f | xargs)
execute="${package}.${class}"
if $video; then
withVideo "--tests=" "$execute"
else
testCommand "--tests=" "$execute"
fi
done
}
function withVideo(){
local tmp=$(mktemp)
# Ctrl + C kill background jobs
trap 'pkill -P $$' TERM INT HUP
# -displayfd finds unused display and send it to file descriptor 1
Xvfb -displayfd 1 -screen 0 1920x1080x16 1>$tmp 2>/dev/null &
# wait until Xvfb finds a display with output in tmp file
# 5 seconds to find a display so we dont infini-loop
kill_count=0
while ! grep -qP "\d" $tmp;do
[ "$kill_count" -gt 30 ] && echo "Xvfb couldn't get a display within limit" && exit 1
sleep 1
((kill_count=kill_count+1))
echo xvfb: $tmp $kill_count
done
xvfb_display=$(cat $tmp)
mkdir -p $video_output
startVideo $2 &
# send the "headed" browser to DISPLAY which is headless
DISPLAY=":$xvfb_display" testCommand $1 $2 &
test_pid=$!
# wait and output exit of background process
if wait $test_pid; then
echo q >> $video_cmds # send ffmpeg exit
sleep 2
if ! $keep_logs;then
rm -f $video_output/$2.log
fi
echo
echo "Tests succeed, delete video -> $video_output/$2$video_extension"
rm -f $video_output/$2$video_extension
exit 0
else
echo
echo "1 or more test failed, keeping -> $video_output/$2$video_extension"
echo q >> $video_cmds # send ffmpeg exit
sleep 2
if ! $keep_logs;then
rm -f $video_output/$2.log
fi
# kill everything else
exit $test_fail_exit
fi
}
function testSuite(){
if $video; then
withVideo "-Dsuite=" "$suite"
else
testCommand "-Dsuite=" "$suite"
fi
}
function testPackage(){
if $video; then
withVideo "--tests=" "$package"
else
testCommand "--tests=" "$package"
fi
}
function testClass() {
echo Testing all @Test in class
file="$(grep -r -w "class ${class}" | cut -d ":" -f 1 || true)"
# Empty Check
if [[ -z "$file" ]]; then
echo "Error: Couldn't find an exact match"
exit 1
fi
if [[ $(echo "${file}" | wc -l) -gt 1 ]]; then
echo Error: Found more than one file that has that class. exiting
exit 1
else
package=$(head -1 ${file} | awk '{print $2}')
execute="${package}.${class}"
echo going to try and run class: ${execute}
if $video; then
withVideo "--tests=" "$execute"
else
testCommand "--tests=" "$execute"
fi
fi
}
function testMethod() {
echo Testing a @Test method within a class
file="$(grep -r "${testIndicator}" -A1 | grep -w "${method}" | grep -v "${testIndicator}" | tr -s ' ' | cut -d ' ' -f 1 | awk '{print substr($1, 1, length($1)-1)}' || true)"
# Empty Check
if [[ -z "$file" ]]; then
echo "Error: Couldn't find an exact match"
exit 1
fi
if [[ $(echo "${file}" | wc -l) -gt 1 ]]; then
echo Error: Found more than one file that has that method. exiting
exit 1
else
class=$(grep "class" ${file} | awk '{print $2}' )
if [[ $(echo "$class" | wc -l) -gt 1 ]]; then
echo Error: Found more than one class in file. This script can only work with one class
exit 1
else
package=$(head -1 ${file} | awk '{print $2}')
execute="${package}.${class}.${method}"
echo going to try and run method: ${execute}
if $video; then
withVideo "--tests=" "$execute"
else
testCommand "--tests=" "$execute"
fi
fi
fi
}
#=== FUNCTION ================================================================
# NAME: usage
# DESCRIPTION: Display usage information.
#===============================================================================
function usage ()
{
echo "
=====================================================
Wrapper script for easier commandline test operations
Finds test classes or methods and resolves the package
to pass into build tools like maven or gradle
=====================================================
Usage : $0 [options] [gradle arguments]
Options:
-h Display this message
-d Run all tests recursivley found in directory
-m Search for and run Method Test
-l Keep logs from tests
-p Put in full package declaration
-s Run suite, must be function in build file (build.gradle)
-x Exit code on test failure
-v Record video (executes test in background)
-o Video output directory (will be created)
-c Search for and run tests inside of Class
Examples:
./test.sh -p com.microfocus.sspr.tests.smokeTests.canModule.CanLookup
./test.sh -c CanLookup -DinternalSysProp=something
./test.sh -m methodInCanLookup
# exit with exit code 1 on failure
./test.sh -x 1
# Record video to this directory
./test.sh -m -v -o /home/me/videos methodInCanLookup"
} # ---------- end of function usage ----------
#-----------------------------------------------------------------------
# Handle command line arguments
#-----------------------------------------------------------------------
while getopts "hlvd:s:x:m:c:p:o:" opt;
do
case $opt in
h)
usage; exit 0 ;;
v)
video=true;;
l)
keep_logs=true;;
o)
video_output=$OPTARG;;
x)
test_fail_exit=$OPTARG;;
m)
method=$OPTARG
shift $(($OPTIND - 1))
gradle_options="$@"
testMethod; exit 0 ;;
c)
class=$OPTARG
shift $(($OPTIND - 1))
gradle_options="$@"
testClass; exit 0 ;;
p)
package=$OPTARG
shift $(($OPTIND - 1))
gradle_options="$@"
testPackage; exit 0 ;;
s)
suite=$OPTARG
shift $(($OPTIND - 1))
gradle_options="$@"
testSuite; exit 0 ;;
d)
directory=$OPTARG
shift $(($OPTIND - 1))
gradle_options="$@"
testDirectory; exit 0 ;;
*) echo -e "\n Option does not exist : OPTARG\n"
usage; exit 1 ;;
esac # --- end of case ---
done
@joshzcold
Copy link
Author

Result should look alot like this
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment