Mercurial > hg > release > heapstats-2.1
changeset 226:e147f3d6347d
Bug 3356: [TEST]Add a race-condition test framework
Reviewed-by: yasuenag
https://github.com/HeapStats/heapstats/pull/91
author | KUBOTA Yuji <kubota.yuji@lab.ntt.co.jp> |
---|---|
date | Tue, 11 Apr 2017 17:38:38 +0900 |
parents | 5abb11559f3b |
children | f421a4c6e7ea |
files | .ignore ChangeLog agent/test/race-condition/README.md agent/test/race-condition/common.py agent/test/race-condition/testcase.sh agent/test/race-condition/testlist.txt |
diffstat | 5 files changed, 257 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/.ignore Tue Apr 11 13:05:30 2017 +0900 +++ b/.ignore Tue Apr 11 17:38:38 2017 +0900 @@ -40,3 +40,8 @@ # IntelliJ (2016.3) .idea/workspace.xml + +# Python +__pycache__/ +*.py[cod] +*$py.class
--- a/ChangeLog Tue Apr 11 13:05:30 2017 +0900 +++ b/ChangeLog Tue Apr 11 17:38:38 2017 +0900 @@ -3,6 +3,7 @@ * Bug 3353: [TEST]Add a test runner for deadlock and thread-recording * Bug 3354: [TEST]Modify test runners for testing in a similar way * Bug 3355: [TEST]Add unit test cases + * Bug 3356: [TEST]Add a race-condition test framework 2017-03-25 KUBOTA Yuji <kubota.yuji@lab.ntt.co.jp>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/test/race-condition/README.md Tue Apr 11 17:38:38 2017 +0900 @@ -0,0 +1,46 @@ +# Test cases for testing race condition + +## Usage + +1. Add directories to `testlist.txt` +2. Run `testcase.sh` + +## How to add new tase cases for testing race condition. + +1. Create a directory. +2. Create a `buildenv.sh` to set environment for testing. +3. Write `test.py` and testcase such like as existing test codes. + +### `buildenv.sh` + +`buildenv.sh` requires the following. + +* `CLASSPATH` + * Classpath to build test code. + * Should write an absolute path. +* `MAINCLASS` + * A main class of test code. +* `JAVA_OPTS` + * Options for launching java process. +* `HEAPSTATS_CONF` + * Path to `heapstats.conf` for testing +* Command line to build test code. + +### `test.py` + +* Import `common.py` on parent directory +* Use `common.initialize()` method with passing break point names and break condition as arguments + +### Result + +* `test.py` will touch `test-succeeded` when the test passed correctly. Otherwise, will touch `test-failed`. +* `testcase.sh` will show a summary of all test cases's result at last as below. + +``` +Test summary: + Testcase1: succeeded + Testcase2: succeeded + Testcase3: failed + : +``` +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/test/race-condition/common.py Tue Apr 11 17:38:38 2017 +0900 @@ -0,0 +1,76 @@ +import gdb + +class ContinueInvoker: + def __init__(self, th): + self.__thread_num = th + + def __call__(self): + gdb.execute("thread " + str(self.__thread_num)) + gdb.execute("continue") + + +class BreakPointHandler(gdb.Breakpoint): + def __init__(self, bp, condition): + super(BreakPointHandler, self).__init__(bp) + self.__cond = condition + self.thread_num = -1 + + def stop(self): + if(self.__cond()): + self.thread_num = gdb.selected_thread().num + self.enabled = False + gdb.write("Suspend thread #" + str(self.thread_num) + "\n") + return True + else: + return False + + +class RaceConditionGenerator: + def __init__(self, primary, secondary, secondary_enabled): + self.__primary = primary + self.__secondary = secondary + self.__secondary_enabled = secondary_enabled + + def coordinate(self): + if((not self.__secondary_enabled) and (not self.__primary.enabled) and (self.__secondary.thread_num == -1)): + self.__secondary.enabled = True + elif((self.__primary.thread_num != -1) and (self.__secondary.thread_num != -1)): + gdb.write("Test start!\n") + gdb.post_event(ContinueInvoker(self.__primary.thread_num)) + gdb.post_event(ContinueInvoker(self.__secondary.thread_num)) + + +class StopHandler: + def __init__(self, rcgen): + self.__rcgen = rcgen + + def __call__(self, event): + # Ignore signals + if(isinstance(event, gdb.SignalEvent)): + gdb.post_event(ContinueInvoker(event.inferior_thread.num)) + elif(isinstance(event, gdb.BreakpointEvent)): + self.__rcgen.coordinate() + + +def return_true(): + return True + + +def exit_handler(event): + gdb.execute("quit") + + +def initialize(primary, primary_cond, secondary, secondary_cond, secondary_enabled): + gdb.execute("set breakpoint pending on") + gdb.execute("set target-async on") + gdb.execute("set pagination off") + gdb.execute("set non-stop on") + + p = BreakPointHandler(primary, primary_cond) + s = BreakPointHandler(secondary, secondary_cond) + s.enabled = secondary_enabled + rcgen = RaceConditionGenerator(p, s, secondary_enabled) + + gdb.events.stop.connect(StopHandler(rcgen)) + gdb.events.exited.connect(exit_handler) +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/test/race-condition/testcase.sh Tue Apr 11 17:38:38 2017 +0900 @@ -0,0 +1,129 @@ +#!/bin/sh + +pushd $(dirname $0) >/dev/null + +if [[ $1 == "--clean" ]]; then + find . \( -name "*.class" -o -name "core*" -o -name "hs_err*log" -o -name "*.gdb" -o -name "*.log" -o -name command.gdb -o -name "heapstats_*" -o -name "test-failed" -o -name "test-succeeded" \) -exec rm -f {} \; + rm -fR __pycache__ + exit +fi + +declare -A DEFAULT_ULIMITS + +function store_ulimits(){ + for item in `ulimit -a | sed -e 's/^.\+\(-.\))\s\+\(.\+\)$/\1,\2/g'`; do + key=`echo $item | cut -d',' -f 1` + value=`echo $item | cut -d',' -f 2` + DEFAULT_ULIMITS[$key]=$value + done +} + +function restore_ulimits(){ + for key in ${!DEFAULT_ULIMITS[@]}; do + ulimit -S $key ${DEFAULT_ULIMITS[$key]} > /dev/null 2>&1 + done +} + + +if [ -z "$JAVA_HOME" ]; then + echo '$JAVA_HOME is not set.' + exit 1 +fi; + +if [ -z "$HEAPSTATS_LIB" ]; then + echo '$HEAPSTATS_LIB is not set.' + exit 2 +fi; + +TESTLIST=${1:-$PWD/testlist.txt} + +if [ ! -e $TESTLIST ]; then + echo "$TESTLIST does not exist." + exit 3 +fi + +ulimit -c unlimited +store_ulimits + +for TEST_ENTRY in `cat $TESTLIST`; do + for TESTDIR in `ls -d $TEST_ENTRY`; do + echo "Run $TESTDIR" + + export TEST_TARGET=$PWD/$TESTDIR + source $TEST_TARGET/buildenv.sh + + AGENTPATH="-agentpath:$HEAPSTATS_LIB" + + if [ -n "$HEAPSTATS_CONF" ]; then + AGENTPATH="$AGENTPATH=$HEAPSTATS_CONF" + fi + + cat <<EOF > $TEST_TARGET/command.gdb +set logging file result.log +set logging on +run $AGENTPATH $JAVA_OPTS $MAINCLASS >> result.log 2>&1 +EOF + # If select specified gdb, load files and symbols to exec + if [ -n "$GDB_PATH" ] ; then + cat <<EOF > $TEST_TARGET/loadfiles.gdb +set sysroot / +set debug-file-directory /usr/lib/debug +set directories /usr/src/debug +set use-deprecated-index-sections on +EOF + JAVA_LIB=$(find ${JAVA_HOME%/}/ -name "java" -type f | grep -v jre) + echo "file ${JAVA_LIB}" >> ${TEST_TARGET}/loadfiles.gdb + JAVA_LIB=${JAVA_LIB%/bin/java} + echo "set solib-search-path /lib64/:${JAVA_LIB}:${JAVA_LIB}*/jre/lib/amd64/:${JAVA_LIB}*/jre/lib/amd64/*/:${HEAPSTATS_LIB%/*}" >> ${TEST_TARGET}/loadfiles.gdb + + pushd $TEST_TARGET + ${GDB_PATH}/bin/gdb -q -x loadfiles.gdb -x test.py -x command.gdb + else + pushd $TEST_TARGET + gdb -q -x test.py -x command.gdb $JAVA_HOME/bin/java + fi + + if [ $? -ne 0 ]; then + echo "$TESTDIR failed!" + touch test-failed + else + ls hs_err*.log > /dev/null 2>&1 + + if [ $? -eq 0 ]; then + echo "$TESTDIR failed! (hs_err exists)" + touch test-failed + else + ls core* > /dev/null 2>&1 + if [ $? -eq 0 ]; then + echo "$TESTDIR failed! (core exists)" + touch test-failed + else + echo "$TESTDIR succeeded" + touch test-succeeded + fi + fi + + fi + + restore_ulimits + popd + done +done + +echo +echo "Test summary:" + +for TESTDIR in `cat $TESTLIST`; do + echo -n " $TESTDIR: " + + if [ -e $TESTDIR/test-succeeded ]; then + echo -e "\e[32msucceeded\e[m" + elif [ -e $TESTDIR/test-failed ]; then + echo -e "\e[31mfailed\e[m" + else + echo -e "\e[33munknown\e[m" + fi + +done + +popd >/dev/null