diff --git a/test/java/util/logging/AnonLoggerWeakRefLeak.java b/test/java/util/logging/AnonLoggerWeakRefLeak.java index 6b651013fbc062694ad4194be0cfff469a08894c..ed72e7f41108f27357f28697223780613588a10e 100644 --- a/test/java/util/logging/AnonLoggerWeakRefLeak.java +++ b/test/java/util/logging/AnonLoggerWeakRefLeak.java @@ -23,24 +23,32 @@ import java.util.logging.*; -public class AnonLoggerWeakRefLeak { - public static int DEFAULT_LOOP_TIME = 60; // time is in seconds +public class AnonLoggerWeakRefLeak extends SimpleApplication { + // The test driver script will allow this program to run until we + // reach DEFAULT_LOOP_TIME or a decrease in instance counts is + // observed. For this particular WeakReference leak, the count + // was always observed to be increasing so if we get a decreasing + // count, then the leak is fixed in the bits being tested. + // Two minutes has been enough time to observe a decrease in + // fixed bits on overloaded systems, but the test will likely + // finish more quickly. + public static int DEFAULT_LOOP_TIME = 120; // time is in seconds - public static void main(String[] args) { + // execute the AnonLoggerWeakRefLeak app work + public void doMyAppWork(String[] args) throws Exception { int loop_time = 0; int max_loop_time = DEFAULT_LOOP_TIME; - if (args.length == 0) { + // args[0] is the port-file + if (args.length < 2) { System.out.println("INFO: using default time of " + max_loop_time + " seconds."); } else { try { - max_loop_time = Integer.parseInt(args[0]); + max_loop_time = Integer.parseInt(args[1]); } catch (NumberFormatException nfe) { - System.err.println("Error: '" + args[0] + throw new RuntimeException("Error: '" + args[1] + "': is not a valid seconds value."); - System.err.println("Usage: AnonLoggerWeakRefLeak [seconds]"); - System.exit(1); } } @@ -73,4 +81,12 @@ public class AnonLoggerWeakRefLeak { System.out.println("INFO: final loop count = " + count); } + + public static void main(String[] args) throws Exception { + AnonLoggerWeakRefLeak myApp = new AnonLoggerWeakRefLeak(); + + SimpleApplication.setMyApp(myApp); + + SimpleApplication.main(args); + } } diff --git a/test/java/util/logging/AnonLoggerWeakRefLeak.sh b/test/java/util/logging/AnonLoggerWeakRefLeak.sh index ddbb6efcfcf236497f64816b9cd9d7451e52cf6c..1402881275bdfdbd75680acab7cf2c83b0107df1 100644 --- a/test/java/util/logging/AnonLoggerWeakRefLeak.sh +++ b/test/java/util/logging/AnonLoggerWeakRefLeak.sh @@ -1,3 +1,5 @@ +#!/bin/sh + # # Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -23,76 +25,24 @@ # @test # @bug 6942989 -# @ignore until 6964018 is fixed # @summary Check for WeakReference leak in anonymous Logger objects # @author Daniel D. Daugherty # -# @run build AnonLoggerWeakRefLeak -# @run shell/timeout=180 AnonLoggerWeakRefLeak.sh +# @library ../../../sun/tools/common +# @build SimpleApplication ShutdownSimpleApplication +# @build AnonLoggerWeakRefLeak +# @run shell/timeout=240 AnonLoggerWeakRefLeak.sh -# The timeout is: 2 minutes for infrastructure and 1 minute for the test +# The timeout is: 2 minutes for infrastructure and 2 minutes for the test # -if [ "${TESTJAVA}" = "" ] -then - echo "TESTJAVA not set. Test cannot execute. Failed." - exit 1 -fi - -if [ "${TESTSRC}" = "" ] -then - echo "TESTSRC not set. Test cannot execute. Failed." - exit 1 -fi - -if [ "${TESTCLASSES}" = "" ] -then - echo "TESTCLASSES not set. Test cannot execute. Failed." - exit 1 -fi - -JAVA="${TESTJAVA}"/bin/java -JMAP="${TESTJAVA}"/bin/jmap -JPS="${TESTJAVA}"/bin/jps +. ${TESTSRC}/../../../sun/tools/common/CommonSetup.sh +. ${TESTSRC}/../../../sun/tools/common/ApplicationSetup.sh -set -eu TEST_NAME="AnonLoggerWeakRefLeak" TARGET_CLASS="java\.lang\.ref\.WeakReference" -is_cygwin=false -is_mks=false -is_windows=false - -case `uname -s` in -CYGWIN*) - is_cygwin=true - is_windows=true - ;; -Windows_*) - is_mks=true - is_windows=true - ;; -*) - ;; -esac - - -# wrapper for grep -# -grep_cmd() { - set +e - if $is_windows; then - # need dos2unix to get rid of CTRL-M chars from java output - dos2unix | grep "$@" - status="$?" - else - grep "$@" - status="$?" - fi - set -e -} - # MAIN begins here # @@ -105,62 +55,39 @@ fi # see if this version of jmap supports the '-histo:live' option jmap_option="-histo:live" set +e -"${JMAP}" "$jmap_option" 0 > "$TEST_NAME.jmap" 2>&1 -grep '^Usage: ' "$TEST_NAME.jmap" > /dev/null 2>&1 +"${JMAP}" 2>&1 | grep ':live' > /dev/null 2>&1 status="$?" set -e -if [ "$status" = 0 ]; then +if [ "$status" != 0 ]; then echo "INFO: switching jmap option from '$jmap_option'\c" jmap_option="-histo" echo " to '$jmap_option'." fi -"${JAVA}" ${TESTVMOPTS} -classpath "${TESTCLASSES}" \ - "$TEST_NAME" $seconds > "$TEST_NAME.log" 2>&1 & -test_pid="$!" -echo "INFO: starting $TEST_NAME as pid = $test_pid" +# Start application and use TEST_NAME.port for coordination +startApplication "$TEST_NAME" "$TEST_NAME.port" $seconds -# wait for test program to get going -count=0 -while [ "$count" -lt 30 ]; do - sleep 2 - grep_cmd '^INFO: call count = 0$' < "$TEST_NAME.log" > /dev/null 2>&1 - if [ "$status" = 0 ]; then - break - fi - count=`expr $count + 1` -done - -if [ "$count" -ge 30 ]; then - echo "ERROR: $TEST_NAME failed to get going." >&2 - echo "INFO: killing $test_pid" - kill "$test_pid" - exit 1 -elif [ "$count" -gt 1 ]; then - echo "INFO: $TEST_NAME took $count loops to start." -fi - -if $is_cygwin; then - # We need the Windows pid for jmap and not the Cygwin pid. - # Note: '\t' works on Cygwin, but doesn't seem to work on Solaris. - jmap_pid=`"${JPS}"| grep_cmd "[ \t]$TEST_NAME$" | sed 's/[ \t].*//'` - if [ -z "$jmap_pid" ]; then - echo "FAIL: jps could not map Cygwin pid to Windows pid." >&2 - echo "INFO: killing $test_pid" - kill "$test_pid" - exit 2 - fi - echo "INFO: pid = $test_pid maps to Windows pid = $jmap_pid" -else - jmap_pid="$test_pid" -fi +finished_early=false decreasing_cnt=0 increasing_cnt=0 loop_cnt=0 prev_instance_cnt=0 +MAX_JMAP_TRY_CNT=10 +jmap_retry_cnt=0 +loop_cnt_on_retry=0 + while true; do + # see if the target process has finished its run and bail if it has + set +e + grep "^INFO: final loop count = " "$appOutput" > /dev/null 2>&1 + status="$?" + set -e + if [ "$status" = 0 ]; then + break + fi + # Output format for 'jmap -histo' in JDK1.5.0: # # <#bytes> <#instances> @@ -170,38 +97,70 @@ while true; do # : <#instances> <#bytes> # set +e - "${JMAP}" "$jmap_option" "$jmap_pid" > "$TEST_NAME.jmap" 2>&1 + "${JMAP}" "$jmap_option" "$appJavaPid" > "$TEST_NAME.jmap" 2>&1 status="$?" set -e if [ "$status" != 0 ]; then echo "INFO: jmap exited with exit code = $status" - if [ "$loop_cnt" = 0 ]; then - echo "INFO: on the first iteration so no samples were taken." - echo "INFO: start of jmap output:" - cat "$TEST_NAME.jmap" - echo "INFO: end of jmap output." + + # There are intermittent jmap failures; see 6498448. + # + # So far the following have been observed in a jmap call + # that was not in a race with target process termination: + # + # (Solaris specific, 2nd sample) + # : Unable to open door: target process not responding or HotSpot VM not loaded + # The -F option can be used when the target process is not responding + # + # (on Solaris so far) + # java.io.IOException + # + # (on Solaris so far, 1st sample) + # : Permission denied + # + sed 's/^/INFO: /' "$TEST_NAME.jmap" + + if [ "$loop_cnt" = "$loop_cnt_on_retry" ]; then + # loop count hasn't changed + jmap_retry_cnt=`expr $jmap_retry_cnt + 1` + else + # loop count has changed so remember it + jmap_retry_cnt=1 + loop_cnt_on_retry="$loop_cnt" + fi + + # This is '-ge' because we have the original attempt plus + # MAX_JMAP_TRY_CNT - 1 retries. + if [ "$jmap_retry_cnt" -ge "$MAX_JMAP_TRY_CNT" ]; then + echo "INFO: jmap failed $MAX_JMAP_TRY_CNT times in a row" \ + "without making any progress." echo "FAIL: jmap is unable to take any samples." >&2 - echo "INFO: killing $test_pid" - kill "$test_pid" + killApplication exit 2 fi - echo "INFO: The likely reason is that $TEST_NAME has finished running." - break + + # short delay and try again + # Note: sleep 1 didn't help with ": Permission denied" + sleep 2 + echo "INFO: retrying jmap (retry=$jmap_retry_cnt, loop=$loop_cnt)." + continue fi - instance_cnt=`grep_cmd "[ ]$TARGET_CLASS$" \ - < "$TEST_NAME.jmap" \ + set +e + instance_cnt=`grep "${PATTERN_WS}${TARGET_CLASS}${PATTERN_EOL}" \ + "$TEST_NAME.jmap" \ | sed ' # strip leading whitespace; does nothing in JDK1.5.0 - s/^[ ][ ]*// + s/^'"${PATTERN_WS}${PATTERN_WS}"'*// # strip <#bytes> in JDK1.5.0; does nothing otherwise - s/^[1-9][0-9]*[ ][ ]*// + s/^[1-9][0-9]*'"${PATTERN_WS}${PATTERN_WS}"'*// # strip : field; does nothing in JDK1.5.0 - s/^[1-9][0-9]*:[ ][ ]*// + s/^[1-9][0-9]*:'"${PATTERN_WS}${PATTERN_WS}"'*// # strip field - s/[ ].*// + s/'"${PATTERN_WS}"'.*// '` + set -e if [ -z "$instance_cnt" ]; then echo "INFO: instance count is unexpectedly empty" if [ "$loop_cnt" = 0 ]; then @@ -211,8 +170,7 @@ while true; do cat "$TEST_NAME.jmap" echo "INFO: end of jmap output." echo "FAIL: cannot find the instance count value." >&2 - echo "INFO: killing $test_pid" - kill "$test_pid" + killApplication exit 2 fi else @@ -221,7 +179,17 @@ while true; do if [ "$instance_cnt" -gt "$prev_instance_cnt" ]; then increasing_cnt=`expr $increasing_cnt + 1` else + # actually decreasing or the same decreasing_cnt=`expr $decreasing_cnt + 1` + + # For this particular WeakReference leak, the count was + # always observed to be increasing so if we get a decreasing + # or the same count, then the leak is fixed in the bits + # being tested. + echo "INFO: finishing early due to non-increasing instance count." + finished_early=true + killApplication + break fi prev_instance_cnt="$instance_cnt" fi @@ -232,8 +200,22 @@ while true; do loop_cnt=`expr $loop_cnt + 1` done +if [ $finished_early = false ]; then + stopApplication "$TEST_NAME.port" + waitForApplication +fi + +echo "INFO: $TEST_NAME has finished running." echo "INFO: increasing_cnt = $increasing_cnt" echo "INFO: decreasing_cnt = $decreasing_cnt" +if [ "$jmap_retry_cnt" -gt 0 ]; then + echo "INFO: jmap_retry_cnt = $jmap_retry_cnt (in $loop_cnt iterations)" +fi + +if [ "$loop_cnt" = 0 ]; then + echo "FAIL: jmap is unable to take any samples." >&2 + exit 2 +fi echo "INFO: The instance count of" `eval echo $TARGET_CLASS` "objects" if [ "$decreasing_cnt" = 0 ]; then @@ -242,6 +224,6 @@ if [ "$decreasing_cnt" = 0 ]; then exit 2 fi -echo "INFO: is both increasing and decreasing." +echo "INFO: is not always increasing." echo "PASS: This indicates that there is not a memory leak." exit 0 diff --git a/test/java/util/logging/LoggerWeakRefLeak.java b/test/java/util/logging/LoggerWeakRefLeak.java index c66d37521009e126873639ce030505d89a804437..f93c7be61639e8851a39a5c93cd6d237a43b2add 100644 --- a/test/java/util/logging/LoggerWeakRefLeak.java +++ b/test/java/util/logging/LoggerWeakRefLeak.java @@ -23,27 +23,32 @@ import java.util.logging.*; -public class LoggerWeakRefLeak { - // AnonLoggerWeakRefLeak checks for one weak reference leak. - // LoggerWeakRefLeak checks for two weak reference leaks so - // this test runs twice as long, by default. +public class LoggerWeakRefLeak extends SimpleApplication { + // The test driver script will allow this program to run until we + // reach DEFAULT_LOOP_TIME or a decrease in instance counts is + // observed. For these particular WeakReference leaks, the count + // was always observed to be increasing so if we get a decreasing + // count, then the leaks are fixed in the bits being tested. + // Two minutes has been enough time to observe a decrease in + // fixed bits on overloaded systems, but the test will likely + // finish more quickly. public static int DEFAULT_LOOP_TIME = 120; // time is in seconds - public static void main(String[] args) { + // execute the LoggerWeakRefLeak app work + public void doMyAppWork(String[] args) throws Exception { int loop_time = 0; int max_loop_time = DEFAULT_LOOP_TIME; - if (args.length == 0) { + // args[0] is the port-file + if (args.length < 2) { System.out.println("INFO: using default time of " + max_loop_time + " seconds."); } else { try { - max_loop_time = Integer.parseInt(args[0]); + max_loop_time = Integer.parseInt(args[1]); } catch (NumberFormatException nfe) { - System.err.println("Error: '" + args[0] + throw new RuntimeException("Error: '" + args[1] + "': is not a valid seconds value."); - System.err.println("Usage: LoggerWeakRefLeak [seconds]"); - System.exit(1); } } @@ -86,4 +91,12 @@ public class LoggerWeakRefLeak { System.out.println("INFO: final loop count = " + count); } + + public static void main(String[] args) throws Exception { + AnonLoggerWeakRefLeak myApp = new AnonLoggerWeakRefLeak(); + + SimpleApplication.setMyApp(myApp); + + SimpleApplication.main(args); + } } diff --git a/test/java/util/logging/LoggerWeakRefLeak.sh b/test/java/util/logging/LoggerWeakRefLeak.sh index 95c33c39e82281c09acc32142fbd05a12704a1b1..200e49b93694af1ac4387ef79815a1cf558b456f 100644 --- a/test/java/util/logging/LoggerWeakRefLeak.sh +++ b/test/java/util/logging/LoggerWeakRefLeak.sh @@ -1,3 +1,5 @@ +#!/bin/sh + # # Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -23,76 +25,24 @@ # @test # @bug 6942989 -# @ignore until 6964018 is fixed # @summary Check for WeakReference leak in Logger objects # @author Daniel D. Daugherty # -# @run build LoggerWeakRefLeak +# @library ../../../sun/tools/common +# @build SimpleApplication ShutdownSimpleApplication +# @build LoggerWeakRefLeak # @run shell/timeout=240 LoggerWeakRefLeak.sh -# The timeout is: 2 minutes for infrastructure and 1 minute for the test +# The timeout is: 2 minutes for infrastructure and 2 minutes for the test # -if [ "${TESTJAVA}" = "" ] -then - echo "TESTJAVA not set. Test cannot execute. Failed." - exit 1 -fi - -if [ "${TESTSRC}" = "" ] -then - echo "TESTSRC not set. Test cannot execute. Failed." - exit 1 -fi - -if [ "${TESTCLASSES}" = "" ] -then - echo "TESTCLASSES not set. Test cannot execute. Failed." - exit 1 -fi - -JAVA="${TESTJAVA}"/bin/java -JMAP="${TESTJAVA}"/bin/jmap -JPS="${TESTJAVA}"/bin/jps +. ${TESTSRC}/../../../sun/tools/common/CommonSetup.sh +. ${TESTSRC}/../../../sun/tools/common/ApplicationSetup.sh -set -eu TEST_NAME="LoggerWeakRefLeak" TARGET_CLASS="java\.lang\.ref\.WeakReference" -is_cygwin=false -is_mks=false -is_windows=false - -case `uname -s` in -CYGWIN*) - is_cygwin=true - is_windows=true - ;; -Windows_*) - is_mks=true - is_windows=true - ;; -*) - ;; -esac - - -# wrapper for grep -# -grep_cmd() { - set +e - if $is_windows; then - # need dos2unix to get rid of CTRL-M chars from java output - dos2unix | grep "$@" - status="$?" - else - grep "$@" - status="$?" - fi - set -e -} - # MAIN begins here # @@ -105,62 +55,39 @@ fi # see if this version of jmap supports the '-histo:live' option jmap_option="-histo:live" set +e -"${JMAP}" "$jmap_option" 0 > "$TEST_NAME.jmap" 2>&1 -grep '^Usage: ' "$TEST_NAME.jmap" > /dev/null 2>&1 +"${JMAP}" 2>&1 | grep ':live' > /dev/null 2>&1 status="$?" set -e -if [ "$status" = 0 ]; then +if [ "$status" != 0 ]; then echo "INFO: switching jmap option from '$jmap_option'\c" jmap_option="-histo" echo " to '$jmap_option'." fi -"${JAVA}" ${TESTVMOPTS} -classpath "${TESTCLASSES}" \ - "$TEST_NAME" $seconds > "$TEST_NAME.log" 2>&1 & -test_pid="$!" -echo "INFO: starting $TEST_NAME as pid = $test_pid" +# Start application and use TEST_NAME.port for coordination +startApplication "$TEST_NAME" "$TEST_NAME.port" $seconds -# wait for test program to get going -count=0 -while [ "$count" -lt 30 ]; do - sleep 2 - grep_cmd '^INFO: call count = 0$' < "$TEST_NAME.log" > /dev/null 2>&1 - if [ "$status" = 0 ]; then - break - fi - count=`expr $count + 1` -done - -if [ "$count" -ge 30 ]; then - echo "ERROR: $TEST_NAME failed to get going." >&2 - echo "INFO: killing $test_pid" - kill "$test_pid" - exit 1 -elif [ "$count" -gt 1 ]; then - echo "INFO: $TEST_NAME took $count loops to start." -fi - -if $is_cygwin; then - # We need the Windows pid for jmap and not the Cygwin pid. - # Note: '\t' works on Cygwin, but doesn't seem to work on Solaris. - jmap_pid=`"${JPS}"| grep_cmd "[ \t]$TEST_NAME$" | sed 's/[ \t].*//'` - if [ -z "$jmap_pid" ]; then - echo "FAIL: jps could not map Cygwin pid to Windows pid." >&2 - echo "INFO: killing $test_pid" - kill "$test_pid" - exit 2 - fi - echo "INFO: pid = $test_pid maps to Windows pid = $jmap_pid" -else - jmap_pid="$test_pid" -fi +finished_early=false decreasing_cnt=0 increasing_cnt=0 loop_cnt=0 prev_instance_cnt=0 +MAX_JMAP_TRY_CNT=10 +jmap_retry_cnt=0 +loop_cnt_on_retry=0 + while true; do + # see if the target process has finished its run and bail if it has + set +e + grep "^INFO: final loop count = " "$appOutput" > /dev/null 2>&1 + status="$?" + set -e + if [ "$status" = 0 ]; then + break + fi + # Output format for 'jmap -histo' in JDK1.5.0: # # <#bytes> <#instances> @@ -170,38 +97,70 @@ while true; do # : <#instances> <#bytes> # set +e - "${JMAP}" "$jmap_option" "$jmap_pid" > "$TEST_NAME.jmap" 2>&1 + "${JMAP}" "$jmap_option" "$appJavaPid" > "$TEST_NAME.jmap" 2>&1 status="$?" set -e if [ "$status" != 0 ]; then echo "INFO: jmap exited with exit code = $status" - if [ "$loop_cnt" = 0 ]; then - echo "INFO: on the first iteration so no samples were taken." - echo "INFO: start of jmap output:" - cat "$TEST_NAME.jmap" - echo "INFO: end of jmap output." + + # There are intermittent jmap failures; see 6498448. + # + # So far the following have been observed in a jmap call + # that was not in a race with target process termination: + # + # (Solaris specific, 2nd sample) + # : Unable to open door: target process not responding or HotSpot VM not loaded + # The -F option can be used when the target process is not responding + # + # (on Solaris so far) + # java.io.IOException + # + # (on Solaris so far, 1st sample) + # : Permission denied + # + sed 's/^/INFO: /' "$TEST_NAME.jmap" + + if [ "$loop_cnt" = "$loop_cnt_on_retry" ]; then + # loop count hasn't changed + jmap_retry_cnt=`expr $jmap_retry_cnt + 1` + else + # loop count has changed so remember it + jmap_retry_cnt=1 + loop_cnt_on_retry="$loop_cnt" + fi + + # This is '-ge' because we have the original attempt plus + # MAX_JMAP_TRY_CNT - 1 retries. + if [ "$jmap_retry_cnt" -ge "$MAX_JMAP_TRY_CNT" ]; then + echo "INFO: jmap failed $MAX_JMAP_TRY_CNT times in a row" \ + "without making any progress." echo "FAIL: jmap is unable to take any samples." >&2 - echo "INFO: killing $test_pid" - kill "$test_pid" + killApplication exit 2 fi - echo "INFO: The likely reason is that $TEST_NAME has finished running." - break + + # short delay and try again + # Note: sleep 1 didn't help with ": Permission denied" + sleep 2 + echo "INFO: retrying jmap (retry=$jmap_retry_cnt, loop=$loop_cnt)." + continue fi - instance_cnt=`grep_cmd "[ ]$TARGET_CLASS$" \ - < "$TEST_NAME.jmap" \ + set +e + instance_cnt=`grep "${PATTERN_WS}${TARGET_CLASS}${PATTERN_EOL}" \ + "$TEST_NAME.jmap" \ | sed ' # strip leading whitespace; does nothing in JDK1.5.0 - s/^[ ][ ]*// + s/^'"${PATTERN_WS}${PATTERN_WS}"'*// # strip <#bytes> in JDK1.5.0; does nothing otherwise - s/^[1-9][0-9]*[ ][ ]*// + s/^[1-9][0-9]*'"${PATTERN_WS}${PATTERN_WS}"'*// # strip : field; does nothing in JDK1.5.0 - s/^[1-9][0-9]*:[ ][ ]*// + s/^[1-9][0-9]*:'"${PATTERN_WS}${PATTERN_WS}"'*// # strip field - s/[ ].*// + s/'"${PATTERN_WS}"'.*// '` + set -e if [ -z "$instance_cnt" ]; then echo "INFO: instance count is unexpectedly empty" if [ "$loop_cnt" = 0 ]; then @@ -211,8 +170,7 @@ while true; do cat "$TEST_NAME.jmap" echo "INFO: end of jmap output." echo "FAIL: cannot find the instance count value." >&2 - echo "INFO: killing $test_pid" - kill "$test_pid" + killApplication exit 2 fi else @@ -221,7 +179,17 @@ while true; do if [ "$instance_cnt" -gt "$prev_instance_cnt" ]; then increasing_cnt=`expr $increasing_cnt + 1` else + # actually decreasing or the same decreasing_cnt=`expr $decreasing_cnt + 1` + + # For these particular WeakReference leaks, the count was + # always observed to be increasing so if we get a decreasing + # or the same count, then the leaks are fixed in the bits + # being tested. + echo "INFO: finishing early due to non-increasing instance count." + finished_early=true + killApplication + break fi prev_instance_cnt="$instance_cnt" fi @@ -232,8 +200,22 @@ while true; do loop_cnt=`expr $loop_cnt + 1` done +if [ $finished_early = false ]; then + stopApplication "$TEST_NAME.port" + waitForApplication +fi + +echo "INFO: $TEST_NAME has finished running." echo "INFO: increasing_cnt = $increasing_cnt" echo "INFO: decreasing_cnt = $decreasing_cnt" +if [ "$jmap_retry_cnt" -gt 0 ]; then + echo "INFO: jmap_retry_cnt = $jmap_retry_cnt (in $loop_cnt iterations)" +fi + +if [ "$loop_cnt" = 0 ]; then + echo "FAIL: jmap is unable to take any samples." >&2 + exit 2 +fi echo "INFO: The instance count of" `eval echo $TARGET_CLASS` "objects" if [ "$decreasing_cnt" = 0 ]; then @@ -242,6 +224,6 @@ if [ "$decreasing_cnt" = 0 ]; then exit 2 fi -echo "INFO: is both increasing and decreasing." +echo "INFO: is not always increasing." echo "PASS: This indicates that there is not a memory leak." exit 0 diff --git a/test/sun/tools/common/ApplicationSetup.sh b/test/sun/tools/common/ApplicationSetup.sh index ea2dec2e654ac8a48ea18145b7462a87def16f2d..a04989f502e8da253dcef154cedd877ee834bf84 100644 --- a/test/sun/tools/common/ApplicationSetup.sh +++ b/test/sun/tools/common/ApplicationSetup.sh @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -24,54 +24,187 @@ # -# Support function to start and stop a given application +# Support functions to start, stop, wait for or kill a given SimpleApplication -# Starts a given application as background process, usage: -# startApplication [args...] +# Starts a given app as background process, usage: +# startApplication port-file [args...] +# +# The following variables are set: +# +# appJavaPid - application's Java pid +# appOtherPid - pid associated with the app other than appJavaPid +# appPidList - all pids associated with the app +# appOutput - file containing stdout and stderr from the app +# +# Waits for at least one line of output from the app to indicate +# that it is up and running. # -# Waits for application to print something to indicate it is running -# (and initialized). Output is directed to ${TESTCLASSES}/Application.out. -# Sets $pid to be the process-id of the application. - startApplication() { - OUTPUTFILE=${TESTCLASSES}/Application.out - ${JAVA} $1 $2 $3 $4 $5 $6 > ${OUTPUTFILE} & - pid="$!" - - # MKS creates an intermediate shell to launch ${JAVA} so - # ${pid} is not the actual pid. We have put in a small sleep - # to give the intermediate shell process time to launch the - # "java" process. - if [ "$OS" = "Windows" ]; then - sleep 2 - if [ "${isCygwin}" = "true" ] ; then - realpid=`ps -p ${pid} | tail -1 | awk '{print $4;}'` - else - realpid=`ps -o pid,ppid,comm|grep ${pid}|grep "java"|cut -c1-6` - fi - pid=${realpid} - fi - - echo "Waiting for Application to initialize..." - attempts=0 + appOutput="${TESTCLASSES}/Application.out" + + ${JAVA} -classpath "${TESTCLASSES}" "$@" > "$appOutput" 2>&1 & + appJavaPid="$!" + appOtherPid= + appPidList="$appJavaPid" + + echo "INFO: waiting for $1 to initialize..." + _cnt=0 while true; do + # if the app doesn't start then the JavaTest/JTREG timeout will + # kick in so this isn't really a endless loop sleep 1 - out=`tail -1 ${OUTPUTFILE}` - if [ ! -z "$out" ]; then + out=`tail -1 "$appOutput"` + if [ -n "$out" ]; then + # we got some output from the app so it's running break fi - attempts=`expr $attempts + 1` - echo "Waiting $attempts second(s) ..." + _cnt=`expr $_cnt + 1` + echo "INFO: waited $_cnt second(s) ..." done + unset _cnt - echo "Application is process $pid" + if $isWindows; then + # Windows requires special handling + appOtherPid="$appJavaPid" + + if $isCygwin; then + appJavaPid=`ps -p "$appOtherPid" \ + | sed -n ' + # See if $appOtherPid is in PID column; there are sometimes + # non-blanks in column 1 (I and S observed so far) + /^.'"${PATTERN_WS}${PATTERN_WS}*${appOtherPid}${PATTERN_WS}"'/{ + # strip PID column + s/^.'"${PATTERN_WS}${PATTERN_WS}*${appOtherPid}${PATTERN_WS}${PATTERN_WS}"'*// + # strip PPID column + s/^[1-9][0-9]*'"${PATTERN_WS}${PATTERN_WS}"'*// + # strip PGID column + s/^[1-9][0-9]*'"${PATTERN_WS}${PATTERN_WS}"'*// + # strip everything after WINPID column + s/'"${PATTERN_WS}"'.*// + p + q + } + '` + echo "INFO: Cygwin pid=$appOtherPid maps to Windows pid=$appJavaPid" + else + # show PID, PPID and COMM columns only + appJavaPid=`ps -o pid,ppid,comm \ + | sed -n ' + # see if appOtherPid is in either PID or PPID columns + /'"${PATTERN_WS}${appOtherPid}${PATTERN_WS}"'/{ + # see if this is a java command + /java'"${PATTERN_EOL}"'/{ + # strip leading white space + s/^'"${PATTERN_WS}${PATTERN_WS}"'*// + # strip everything after the first word + s/'"${PATTERN_WS}"'.*// + # print the pid and we are done + p + q + } + } + '` + echo "INFO: MKS shell pid=$appOtherPid; Java pid=$appJavaPid" + fi + + if [ -z "$appJavaPid" ]; then + echo "ERROR: could not find app's Java pid." >&2 + killApplication + exit 2 + fi + appPidList="$appOtherPid $appJavaPid" + fi + + echo "INFO: $1 is process $appJavaPid" + echo "INFO: $1 output is in $appOutput" } -# Stops an application by invoking the given class and argument, usage: -# stopApplication + +# Stops a simple application by invoking ShutdownSimpleApplication +# class with a specific port-file, usage: +# stopApplication port-file +# +# Note: When this function returns, the SimpleApplication (or a subclass) +# may still be running because the application has not yet reached the +# shutdown check. +# stopApplication() { - $JAVA -classpath "${TESTCLASSES}" $1 $2 + $JAVA -classpath "${TESTCLASSES}" ShutdownSimpleApplication $1 } + +# Wait for a simple application to stop running. +# +waitForApplication() { + if [ $isWindows = false ]; then + # non-Windows is easy; just one process + echo "INFO: waiting for $appJavaPid" + set +e + wait "$appJavaPid" + set -e + + elif $isCygwin; then + # Cygwin pid and not the Windows pid + echo "INFO: waiting for $appOtherPid" + set +e + wait "$appOtherPid" + set -e + + else # implied isMKS + # MKS has intermediate shell and Java process + echo "INFO: waiting for $appJavaPid" + + # appJavaPid can be empty if pid search in startApplication() failed + if [ -n "$appJavaPid" ]; then + # only need to wait for the Java process + set +e + wait "$appJavaPid" + set -e + fi + fi +} + + +# Kills a simple application by sending a SIGTERM to the appropriate +# process(es); on Windows SIGQUIT (-9) is used. +# +killApplication() +{ + if [ $isWindows = false ]; then + # non-Windows is easy; just one process + echo "INFO: killing $appJavaPid" + set +e + kill -TERM "$appJavaPid" # try a polite SIGTERM first + sleep 2 + # send SIGQUIT (-9) just in case SIGTERM didn't do it + # but don't show any complaints + kill -QUIT "$appJavaPid" > /dev/null 2>&1 + wait "$appJavaPid" + set -e + + elif $isCygwin; then + # Cygwin pid and not the Windows pid + echo "INFO: killing $appOtherPid" + set +e + kill -9 "$appOtherPid" + wait "$appOtherPid" + set -e + + else # implied isMKS + # MKS has intermediate shell and Java process + echo "INFO: killing $appPidList" + set +e + kill -9 $appPidList + set -e + + # appJavaPid can be empty if pid search in startApplication() failed + if [ -n "$appJavaPid" ]; then + # only need to wait for the Java process + set +e + wait "$appJavaPid" + set -e + fi + fi +} diff --git a/test/sun/tools/common/CommonSetup.sh b/test/sun/tools/common/CommonSetup.sh index ab8f7fdb13de6c1b9825925c6fb2089bd11701a4..02fbc60d165e7ac79e86834c47fcd32f7866efa1 100644 --- a/test/sun/tools/common/CommonSetup.sh +++ b/test/sun/tools/common/CommonSetup.sh @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -24,56 +24,94 @@ # -# Common setup for tool tests. +# Common setup for tool tests and other tests that use jtools. # Checks that TESTJAVA, TESTSRC, and TESTCLASSES environment variables are set. -# Creates the following for use by the tool tests -# JAVA java launcher -# JSTACK jstack utility -# JMAP jmap utility -# JINFO jinfo utility -# JHAT jhat utility -# PS path separator (";" or ":") -# OS operating system +# +# Creates the following constants for use by the caller: +# JAVA - java launcher +# JHAT - jhat utility +# JINFO - jinfo utility +# JMAP - jmap utility +# JPS - jps utility +# JSTACK - jstack utility +# OS - operating system name +# PATTERN_EOL - grep or sed end-of-line pattern +# PATTERN_WS - grep or sed whitespace pattern +# PS - path separator (";" or ":") +# +# Sets the following variables: +# +# isCygwin - true if environment is Cygwin +# isMKS - true if environment is MKS +# isLinux - true if OS is Linux +# isSolaris - true if OS is Solaris +# isWindows - true if OS is Windows -if [ "${TESTJAVA}" = "" ] -then - echo "TESTJAVA not set. Test cannot execute. Failed." +if [ -z "${TESTJAVA}" ]; then + echo "ERROR: TESTJAVA not set. Test cannot execute. Failed." exit 1 fi - -if [ "${TESTSRC}" = "" ] -then - echo "TESTSRC not set. Test cannot execute. Failed." + +if [ -z "${TESTSRC}" ]; then + echo "ERROR: TESTSRC not set. Test cannot execute. Failed." exit 1 fi - -if [ "${TESTCLASSES}" = "" ] -then - echo "TESTCLASSES not set. Test cannot execute. Failed." + +if [ -z "${TESTCLASSES}" ]; then + echo "ERROR: TESTCLASSES not set. Test cannot execute. Failed." exit 1 fi - + +# only enable these after checking the expected incoming env variables +set -eu + JAVA="${TESTJAVA}/bin/java" -JSTACK="${TESTJAVA}/bin/jstack" -JMAP="${TESTJAVA}/bin/jmap" -JINFO="${TESTJAVA}/bin/jinfo" JHAT="${TESTJAVA}/bin/jhat" +JINFO="${TESTJAVA}/bin/jinfo" +JMAP="${TESTJAVA}/bin/jmap" +JPS="${TESTJAVA}/bin/jps" +JSTACK="${TESTJAVA}/bin/jstack" + +isCygwin=false +isMKS=false +isLinux=false +isSolaris=false +isUnknownOS=false +isWindows=false OS=`uname -s` +# start with some UNIX like defaults +PATTERN_EOL='$' +# blank and tab +PATTERN_WS='[ ]' +PS=":" + case "$OS" in - Windows* ) - PS=";" - OS="Windows" - ;; CYGWIN* ) - PS=";" OS="Windows" + PATTERN_EOL='[ ]*$' + # blank and tab + PATTERN_WS='[ \t]' isCygwin=true + isWindows=true + ;; + Linux ) + OS="Linux" + isLinux=true + ;; + SunOS ) + OS="Solaris" + isSolaris=true + ;; + Windows* ) + OS="Windows" + PATTERN_EOL='[ ]*$' + PS=";" + isWindows=true ;; * ) - PS=":" + isUnknownOS=true ;; esac - diff --git a/test/sun/tools/common/CommonTests.sh b/test/sun/tools/common/CommonTests.sh new file mode 100644 index 0000000000000000000000000000000000000000..ae0287a0c324ec384bc5123305b1fe7d71f3b376 --- /dev/null +++ b/test/sun/tools/common/CommonTests.sh @@ -0,0 +1,314 @@ +#!/bin/sh + +# +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + + +# @test +# @bug 6964018 +# @summary Unit test for common tools infrastructure. +# +# @build SimpleApplication SleeperApplication ShutdownSimpleApplication +# @run shell CommonTests.sh + +. ${TESTSRC}/CommonSetup.sh +. ${TESTSRC}/ApplicationSetup.sh + +# hope for the best: +status=0 + + +# Test program path constants from CommonSetup.sh: +# +for name in JAVA JHAT JINFO JMAP JPS JSTACK; do + eval value=$`echo $name` + + echo "INFO: $name=$value" + if [ -x "$value" ]; then + echo "INFO: '$value' is executable." + else + echo "ERROR: '$value' is not executable." >&2 + status=1 + fi +done + + +# Display flag values from CommonSetup.sh: +# +for name in isCygwin isMKS isLinux isSolaris isUnknownOS isWindows; do + eval value=$`echo $name` + echo "INFO: flag $name=$value" +done + + +# Test OS constant from CommonSetup.sh: +# +if [ -z "$OS" ]; then + echo "ERROR: OS constant cannot be empty." >&2 + status=1 +fi + + +# Display the PATTERN_EOL value: +# +echo "INFO: PATTERN_EOL="`echo "$PATTERN_EOL" | od -c` + + +# Test PATTERN_EOL with 'grep' for a regular line. +# +TESTOUT="${TESTCLASSES}/testout.grep_reg_line_eol" +set +e +echo 'regular line' | grep "line${PATTERN_EOL}" > "$TESTOUT" +set -e +if [ -s "$TESTOUT" ]; then + echo "INFO: PATTERN_EOL works for regular line with grep." +else + echo "ERROR: PATTERN_EOL does not work for regular line with grep." >&2 + status=1 +fi + + +if $isWindows; then + # Test PATTERN_EOL with 'grep' for a CR line. + # + TESTOUT="${TESTCLASSES}/testout.grep_cr_line_eol" + set +e + echo 'CR line ' | grep "line${PATTERN_EOL}" > "$TESTOUT" + set -e + if [ -s "$TESTOUT" ]; then + echo "INFO: PATTERN_EOL works for CR line with grep." + else + echo "ERROR: PATTERN_EOL does not work for CR line with grep." >&2 + status=1 + fi +fi + + +# Test PATTERN_EOL with 'sed' for a regular line. +# +TESTOUT="${TESTCLASSES}/testout.sed_reg_line_eol" +echo 'regular line' | sed -n "/line${PATTERN_EOL}/p" > "$TESTOUT" +if [ -s "$TESTOUT" ]; then + echo "INFO: PATTERN_EOL works for regular line with sed." +else + echo "ERROR: PATTERN_EOL does not work for regular line with sed." >&2 + status=1 +fi + + +if $isWindows; then + # Test PATTERN_EOL with 'sed' for a CR line. + # + TESTOUT="${TESTCLASSES}/testout.sed_cr_line_eol" + echo 'CR line ' | sed -n "/line${PATTERN_EOL}/p" > "$TESTOUT" + if [ -s "$TESTOUT" ]; then + echo "INFO: PATTERN_EOL works for CR line with sed." + else + echo "ERROR: PATTERN_EOL does not work for CR line with sed." >&2 + status=1 + fi +fi + + +# Display the PATTERN_WS value: +# +echo "INFO: PATTERN_WS="`echo "$PATTERN_WS" | od -c` + + +# Test PATTERN_WS with 'grep' for a blank. +# +TESTOUT="${TESTCLASSES}/testout.grep_blank" +set +e +echo 'blank: ' | grep "$PATTERN_WS" > "$TESTOUT" +set -e +if [ -s "$TESTOUT" ]; then + echo "INFO: PATTERN_WS works for blanks with grep." +else + echo "ERROR: PATTERN_WS does not work for blanks with grep." >&2 + status=1 +fi + + +# Test PATTERN_WS with 'grep' for a tab. +# +TESTOUT="${TESTCLASSES}/testout.grep_tab" +set +e +echo 'tab: ' | grep "$PATTERN_WS" > "$TESTOUT" +set -e +if [ -s "$TESTOUT" ]; then + echo "INFO: PATTERN_WS works for tabs with grep." +else + echo "ERROR: PATTERN_WS does not work for tabs with grep." >&2 + status=1 +fi + + +# Test PATTERN_WS with 'sed' for a blank. +# +TESTOUT="${TESTCLASSES}/testout.sed_blank" +echo 'blank: ' | sed -n "/$PATTERN_WS/p" > "$TESTOUT" +if [ -s "$TESTOUT" ]; then + echo "INFO: PATTERN_WS works for blanks with sed." +else + echo "ERROR: PATTERN_WS does not work for blanks with sed." >&2 + status=1 +fi + + +# Test PATTERN_WS with 'sed' for a tab. +# +TESTOUT="${TESTCLASSES}/testout.sed_tab" +echo 'tab: ' | sed -n "/$PATTERN_WS/p" > "$TESTOUT" +if [ -s "$TESTOUT" ]; then + echo "INFO: PATTERN_WS works for tabs with sed." +else + echo "ERROR: PATTERN_WS does not work for tabs with sed." >&2 + status=1 +fi + + +# Test startApplication and use PORTFILE for coordination +# The app sleeps for 30 seconds. +# +PORTFILE="${TESTCLASSES}"/shutdown.port +startApplication SleeperApplication "${PORTFILE}" 30 + + +# Test appJavaPid in "ps" cmd output. +# +TESTOUT="${TESTCLASSES}/testout.ps_app" +set +e +if $isCygwin; then + # On Cygwin, appJavaPid is the Windows pid for the Java process + # and appOtherPid is the Cygwin pid for the Java process. + ps -p "$appOtherPid" \ + | grep "${PATTERN_WS}${appJavaPid}${PATTERN_WS}" > "$TESTOUT" +else + # output only pid and comm columns to avoid mismatches + ps -eo pid,comm \ + | grep "^${PATTERN_WS}*${appJavaPid}${PATTERN_WS}" > "$TESTOUT" +fi +set -e +if [ -s "$TESTOUT" ]; then + echo "INFO: begin appJavaPid=$appJavaPid in 'ps' cmd output:" + cat "$TESTOUT" + echo "INFO: end appJavaPid=$appJavaPid in 'ps' cmd output." +else + echo "ERROR: 'ps' cmd should show appJavaPid=$appJavaPid." >&2 + status=1 +fi + +if [ -n "$appOtherPid" ]; then + # Test appOtherPid in "ps" cmd output, if we have one. + # + TESTOUT="${TESTCLASSES}/testout.ps_other" + set +e + if $isCygwin; then + ps -p "$appOtherPid" \ + | grep "${PATTERN_WS}${appOtherPid}${PATTERN_WS}" > "$TESTOUT" + else + # output only pid and comm columns to avoid mismatches + ps -eo pid,comm \ + | grep "^${PATTERN_WS}*${appOtherPid}${PATTERN_WS}" > "$TESTOUT" + fi + set -e + if [ -s "$TESTOUT" ]; then + echo "INFO: begin appOtherPid=$appOtherPid in 'ps' cmd output:" + cat "$TESTOUT" + echo "INFO: end appOtherPid=$appOtherPid in 'ps' cmd output." + else + echo "ERROR: 'ps' cmd should show appOtherPid=$appOtherPid." >&2 + status=1 + fi +fi + + +# Test stopApplication and PORTFILE for coordination +# +stopApplication "${PORTFILE}" + + +# Test application still running after stopApplication. +# +# stopApplication just lets the app know that it can stop, but the +# app might still be doing work. This test just demonstrates that +# fact and doesn't fail if the app is already done. +# +TESTOUT="${TESTCLASSES}/testout.after_stop" +set +e +if $isCygwin; then + # On Cygwin, appJavaPid is the Windows pid for the Java process + # and appOtherPid is the Cygwin pid for the Java process. + ps -p "$appOtherPid" \ + | grep "${PATTERN_WS}${appJavaPid}${PATTERN_WS}" > "$TESTOUT" +else + # output only pid and comm columns to avoid mismatches + ps -eo pid,comm \ + | grep "^${PATTERN_WS}*${appJavaPid}${PATTERN_WS}" > "$TESTOUT" +fi +set -e +if [ -s "$TESTOUT" ]; then + echo "INFO: it is okay for appJavaPid=$appJavaPid to still be running" \ + "after stopApplication() is called." + echo "INFO: begin 'after_stop' output:" + cat "$TESTOUT" + echo "INFO: end 'after_stop' output." +fi + + +# Test waitForApplication +# +# The app might already be gone so this function shouldn't generate +# a fatal error in either call. +# +waitForApplication + +if [ $isWindows = false ]; then + # Windows can recycle pids quickly so we can't use this test there + TESTOUT="${TESTCLASSES}/testout.after_kill" + set +e + # output only pid and comm columns to avoid mismatches + ps -eo pid,comm \ + | grep "^${PATTERN_WS}*${appJavaPid}${PATTERN_WS}" > "$TESTOUT" + set -e + if [ -s "$TESTOUT" ]; then + echo "ERROR: 'ps' cmd should not show appJavaPid." >&2 + echo "ERROR: begin 'after_kill' output:" >&2 + cat "$TESTOUT" >&2 + echo "ERROR: end 'after_kill' output." >&2 + status=1 + else + echo "INFO: 'ps' cmd does not show appJavaPid after" \ + "waitForApplication() is called." + fi +fi + + +# Test killApplication +# +# The app is already be gone so this function shouldn't generate +# a fatal error. +# +killApplication + +exit $status diff --git a/test/sun/tools/common/ShutdownSimpleApplication.java b/test/sun/tools/common/ShutdownSimpleApplication.java index 78ef1d31c2db13cbb3b5b7c4696b98ade9d8599d..314bb579bad17ef88fb00f39a1c9febfc7925815 100644 --- a/test/sun/tools/common/ShutdownSimpleApplication.java +++ b/test/sun/tools/common/ShutdownSimpleApplication.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,10 +22,13 @@ */ /* + * Used to shutdown SimpleApplication (or a subclass). The argument to + * this class is the name of a file that contains the TCP port number + * on which SimpleApplication (or a subclass) is listening. * - * - * Used to shutdown SimpleApplication. The argument to this class is - * the TCP port number where SimpleApplication is listening. + * Note: When this program returns, the SimpleApplication (or a subclass) + * may still be running because the application has not yet reached the + * shutdown check. */ import java.net.Socket; import java.net.InetSocketAddress; @@ -35,6 +38,11 @@ import java.io.FileInputStream; public class ShutdownSimpleApplication { public static void main(String args[]) throws Exception { + if (args.length != 1) { + throw new RuntimeException("Usage: ShutdownSimpleApplication" + + " port-file"); + } + // read the (TCP) port number from the given file File f = new File(args[0]); @@ -42,21 +50,27 @@ public class ShutdownSimpleApplication { byte b[] = new byte[8]; int n = fis.read(b); if (n < 1) { - throw new RuntimeException("Empty file"); + throw new RuntimeException("Empty port-file"); } fis.close(); String str = new String(b, 0, n, "UTF-8"); - System.out.println("Port number of application is: " + str); + System.out.println("INFO: Port number of SimpleApplication: " + str); int port = Integer.parseInt(str); // Now connect to the port (which will shutdown application) - System.out.println("Connecting to port " + port + - " to shutdown Application ..."); + System.out.println("INFO: Connecting to port " + port + + " to shutdown SimpleApplication ..."); + System.out.flush(); Socket s = new Socket(); s.connect( new InetSocketAddress(port) ); s.close(); + + System.out.println("INFO: done connecting to SimpleApplication."); + System.out.flush(); + + System.exit(0); } } diff --git a/test/sun/tools/common/SimpleApplication.java b/test/sun/tools/common/SimpleApplication.java index 050f010a774c87632120158f30ad0bff43a696a0..c7e6b0bdac4f12b5f0f419c460066eba2047c871 100644 --- a/test/sun/tools/common/SimpleApplication.java +++ b/test/sun/tools/common/SimpleApplication.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,10 +22,12 @@ */ /* + * A simple application used by unit tests. The first argument to this + * class is the name of a file to which a TCP port number can be written. * - * - * A simple application used for tool unit tests. It does nothing else - * bind to a TCP port and wait for a shutdown message. + * By default, this class does nothing other than bind to a TCP port, + * write the TCP port number to a file, and wait for an incoming connection + * in order to complete the application shutdown protocol. */ import java.net.Socket; import java.net.ServerSocket; @@ -33,25 +35,86 @@ import java.io.File; import java.io.FileOutputStream; public class SimpleApplication { - public static void main(String args[]) throws Exception { + private static SimpleApplication myApp; // simple app or a subclass + private static String myAppName; // simple app name + private static int myPort; // coordination port # + private static ServerSocket mySS; // coordination socket + + // protected so a subclass can extend it; not public so creation is + // limited. + protected SimpleApplication() { + // save simple app (or subclass) name for messages + myAppName = getClass().getName(); + } + + // return the simple application (or a subclass) + final public static SimpleApplication getMyApp() { + return myApp; + } + + // set the simple application (for use by a subclass) + final public static void setMyApp(SimpleApplication _myApp) { + myApp = _myApp; + } + + // execute the application finish protocol + final public void doMyAppFinish(String[] args) throws Exception { + System.out.println("INFO: " + myAppName + " is waiting on port: " + + myPort); + System.out.flush(); + + // wait for test harness to connect + Socket s = mySS.accept(); + s.close(); + mySS.close(); + + System.out.println("INFO: " + myAppName + " is shutting down."); + System.out.flush(); + } + + // execute the application start protocol + final public void doMyAppStart(String[] args) throws Exception { + if (args.length < 1) { + throw new RuntimeException("Usage: " + myAppName + + " port-file [arg(s)]"); + } + // bind to a random port - ServerSocket ss = new ServerSocket(0); - int port = ss.getLocalPort(); + mySS = new ServerSocket(0); + myPort = mySS.getLocalPort(); // Write the port number to the given file File f = new File(args[0]); FileOutputStream fos = new FileOutputStream(f); - fos.write( Integer.toString(port).getBytes("UTF-8") ); + fos.write( Integer.toString(myPort).getBytes("UTF-8") ); fos.close(); - System.out.println("Application waiting on port: " + port); + System.out.println("INFO: " + myAppName + " created socket on port: " + + myPort); System.out.flush(); + } - // wait for test harness to connect - Socket s = ss.accept(); - s.close(); - ss.close(); + // execute the app work (subclass can override this) + public void doMyAppWork(String[] args) throws Exception { + } + + public static void main(String[] args) throws Exception { + if (myApp == null) { + // create myApp since a subclass hasn't done so + myApp = new SimpleApplication(); + } + + myApp.doMyAppStart(args); // do the app start protocol + + System.out.println("INFO: " + myAppName + " is calling doMyAppWork()"); + System.out.flush(); + myApp.doMyAppWork(args); // do the app work + System.out.println("INFO: " + myAppName + " returned from" + + " doMyAppWork()"); + System.out.flush(); + + myApp.doMyAppFinish(args); // do the app finish protocol - System.out.println("Application shutdown."); + System.exit(0); } } diff --git a/test/sun/tools/common/SleeperApplication.java b/test/sun/tools/common/SleeperApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..b96d9b07ac3e3a733068e9d7acac593cecef2dc9 --- /dev/null +++ b/test/sun/tools/common/SleeperApplication.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * An example subclass of SimpleApplication that illustrates how to + * override the doMyAppWork() method. + */ + +public class SleeperApplication extends SimpleApplication { + public static int DEFAULT_SLEEP_TIME = 60; // time is in seconds + + // execute the sleeper app work + public void doMyAppWork(String[] args) throws Exception { + int sleep_time = DEFAULT_SLEEP_TIME; + + // args[0] is the port-file + if (args.length < 2) { + System.out.println("INFO: using default sleep time of " + + sleep_time + " seconds."); + } else { + try { + sleep_time = Integer.parseInt(args[1]); + } catch (NumberFormatException nfe) { + throw new RuntimeException("Error: '" + args[1] + + "': is not a valid seconds value."); + } + } + + Thread.sleep(sleep_time * 1000); // our "work" is to sleep + } + + public static void main(String[] args) throws Exception { + SleeperApplication myApp = new SleeperApplication(); + + SimpleApplication.setMyApp(myApp); + + SimpleApplication.main(args); + } +} diff --git a/test/sun/tools/jhat/ParseTest.sh b/test/sun/tools/jhat/ParseTest.sh index 35dc84e1f4394c9904c80f86864ccb3a234ba383..9bc9294eb710c5583c032ff7303920e25a0abb39 100644 --- a/test/sun/tools/jhat/ParseTest.sh +++ b/test/sun/tools/jhat/ParseTest.sh @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,11 @@ # @run shell ParseTest.sh . ${TESTSRC}/../common/CommonSetup.sh -. ${TESTSRC}/../common/ApplicationSetup.sh + +# all return statuses are checked in this test +set +e + +failed=0 DUMPFILE="minimal.bin" diff --git a/test/sun/tools/jinfo/Basic.sh b/test/sun/tools/jinfo/Basic.sh index e88db448e1473ea75c3a20249e203873b732f921..57f40af414ae156d48231f791b9c1116b506d4f2 100644 --- a/test/sun/tools/jinfo/Basic.sh +++ b/test/sun/tools/jinfo/Basic.sh @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -35,53 +35,57 @@ . ${TESTSRC}/../common/CommonSetup.sh . ${TESTSRC}/../common/ApplicationSetup.sh -# Start application (send output to shutdown.port) +# Start application and use PORTFILE for coordination PORTFILE="${TESTCLASSES}"/shutdown.port -startApplication \ - -classpath "${TESTCLASSES}" SimpleApplication "${PORTFILE}" +startApplication SimpleApplication "${PORTFILE}" + +# all return statuses are checked in this test +set +e failed=0 -if [ "$OS" != "Windows" ]; then +if [ $isWindows = false ]; then # -sysprops option - ${JINFO} -sysprops $pid + ${JINFO} -sysprops $appJavaPid if [ $? != 0 ]; then failed=1; fi # -flags option - ${JINFO} -flags $pid + ${JINFO} -flags $appJavaPid if [ $? != 0 ]; then failed=1; fi # no option - ${JINFO} $pid + ${JINFO} $appJavaPid if [ $? != 0 ]; then failed=1; fi fi # -flag option -${JINFO} -flag +PrintGC $pid +${JINFO} -flag +PrintGC $appJavaPid if [ $? != 0 ]; then failed=1; fi -${JINFO} -flag -PrintGC $pid +${JINFO} -flag -PrintGC $appJavaPid if [ $? != 0 ]; then failed=1; fi -${JINFO} -flag PrintGC $pid +${JINFO} -flag PrintGC $appJavaPid if [ $? != 0 ]; then failed=1; fi -if [ "$OS" = "SunOS" ]; then +if $isSolaris; then - ${JINFO} -flag +ExtendedDTraceProbes $pid + ${JINFO} -flag +ExtendedDTraceProbes $appJavaPid if [ $? != 0 ]; then failed=1; fi - ${JINFO} -flag -ExtendedDTraceProbes $pid + ${JINFO} -flag -ExtendedDTraceProbes $appJavaPid if [ $? != 0 ]; then failed=1; fi - ${JINFO} -flag ExtendedDTraceProbes $pid + ${JINFO} -flag ExtendedDTraceProbes $appJavaPid if [ $? != 0 ]; then failed=1; fi fi -stopApplication ShutdownSimpleApplication "${PORTFILE}" +set -e -exit $failed +stopApplication "${PORTFILE}" +waitForApplication +exit $failed diff --git a/test/sun/tools/jmap/Basic.sh b/test/sun/tools/jmap/Basic.sh index 3b4e872e71fdfbf053c89c4a8694069e2da8782d..f1c0b34b4438948a33b7ed1243ad5429ea98f581 100644 --- a/test/sun/tools/jmap/Basic.sh +++ b/test/sun/tools/jmap/Basic.sh @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -35,24 +35,25 @@ . ${TESTSRC}/../common/CommonSetup.sh . ${TESTSRC}/../common/ApplicationSetup.sh -# Start application (send output to shutdown.port) +# Start application and use PORTFILE for coordination PORTFILE="${TESTCLASSES}"/shutdown.port -startApplication \ - -classpath "${TESTCLASSES}" SimpleApplication "${PORTFILE}" +startApplication SimpleApplication "${PORTFILE}" + +# all return statuses are checked in this test +set +e failed=0 # -histo[:live] option -${JMAP} -histo $pid +${JMAP} -histo $appJavaPid if [ $? != 0 ]; then failed=1; fi -${JMAP} -histo:live $pid +${JMAP} -histo:live $appJavaPid if [ $? != 0 ]; then failed=1; fi # -dump option -p=`expr $pid` -DUMPFILE="java_pid${p}.hprof" -${JMAP} -dump:format=b,file=${DUMPFILE} $pid +DUMPFILE="java_pid${appJavaPid}.hprof" +${JMAP} -dump:format=b,file=${DUMPFILE} $appJavaPid if [ $? != 0 ]; then failed=1; fi # check that heap dump is parsable @@ -63,7 +64,7 @@ if [ $? != 0 ]; then failed=1; fi rm ${DUMPFILE} # -dump:live option -${JMAP} -dump:live,format=b,file=${DUMPFILE} $pid +${JMAP} -dump:live,format=b,file=${DUMPFILE} $appJavaPid if [ $? != 0 ]; then failed=1; fi # check that heap dump is parsable @@ -71,9 +72,11 @@ ${JHAT} -parseonly true ${DUMPFILE} if [ $? != 0 ]; then failed=1; fi # dump file is large so remove it -rm ${DUMPFILE} +rm -f ${DUMPFILE} -stopApplication ShutdownSimpleApplication "${PORTFILE}" +set -e -exit $failed +stopApplication "${PORTFILE}" +waitForApplication +exit $failed diff --git a/test/sun/tools/jstack/Basic.sh b/test/sun/tools/jstack/Basic.sh index dcbdd4bc753d474741873864d50ae08f2a65eff3..1a2b8eb37a93050636f0912fc41a2f407e7e142d 100644 --- a/test/sun/tools/jstack/Basic.sh +++ b/test/sun/tools/jstack/Basic.sh @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -35,22 +35,26 @@ . ${TESTSRC}/../common/CommonSetup.sh . ${TESTSRC}/../common/ApplicationSetup.sh -# Start application (send output to shutdown.port) +# Start application and use PORTFILE for coordination PORTFILE="${TESTCLASSES}"/shutdown.port -startApplication \ - -classpath "${TESTCLASSES}" SimpleApplication "${PORTFILE}" +startApplication SimpleApplication "${PORTFILE}" + +# all return statuses are checked in this test +set +e failed=0 # normal -$JSTACK $pid 2>&1 +$JSTACK $appJavaPid 2>&1 if [ $? != 0 ]; then failed=1; fi # long -$JSTACK -l $pid 2>&1 +$JSTACK -l $appJavaPid 2>&1 if [ $? != 0 ]; then failed=1; fi -stopApplication ShutdownSimpleApplication "${PORTFILE}" +set -e + +stopApplication "${PORTFILE}" +waitForApplication exit $failed -