# HG changeset patch # User iignatyev # Date 1448389966 -10800 # Tue Nov 24 21:32:46 2015 +0300 # Node ID 46110ddda755ab77d5356fb468c9aa7e8ab73b8e # Parent 09d04e9badce6eae8feb9ec45a8b53d7506164ff 8132961: JEP 279: Improve Test-Failure Troubleshooting Reviewed-by: duke Contributed-by: kirill.shirokov@oracle.com, dmitry.fazunenko@oracle.com, kirill.zhaldybin@oracle.com, igor.ignatyev@oracle.com diff --git a/test/failure_handler/Makefile b/test/failure_handler/Makefile new file mode 100644 --- /dev/null +++ b/test/failure_handler/Makefile @@ -0,0 +1,114 @@ +# +# Copyright (c) 2015, 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. +# + +# +# This is a temporary standalone makefile +# + +BUILD_DIR := $(shell pwd)/build +CLASSES_DIR := ${BUILD_DIR}/classes +IMAGE_DIR := ${BUILD_DIR}/image +RUN_DIR := $(shell pwd)/run + +SRC_DIR := src/share/classes/ +SOURCES := ${SRC_DIR}/jdk/test/failurehandler/*.java \ + ${SRC_DIR}/jdk/test/failurehandler/action/*.java \ + ${SRC_DIR}/jdk/test/failurehandler/jtreg/*.java \ + ${SRC_DIR}/jdk/test/failurehandler/value/*.java + +CONF_DIR = src/share/conf + +JAVA_RELEASE = 7 + +TARGET_JAR = ${IMAGE_DIR}/lib/jtregFailureHandler.jar + +OS_NAME := $(shell uname -o 2>&1) + +ifeq ("${OS_NAME}", "Cygwin") +BUILD_DIR := $(shell cygpath -m "${BUILD_DIR}") +CLASSES_DIR := $(shell cygpath -m "${CLASSES_DIR}") +IMAGE_DIR := $(shell cygpath -m "${IMAGE_DIR}") RUN_DIR := $(shell cygpath -m "${RUN_DIR}") +SRC_DIR := $(shell cygpath -m "${SRC_DIR}") +JTREG_HOME := $(shell cygpath -m "${JTREG_HOME}") +CC := "cl.exe" +endif + +all: clean test + +native: require_env +ifeq ("${OS_NAME}", "Cygwin") + "${CC}" src/windows/native/jdk/test/failurehandler/jtreg/*.c \ + -I"$(shell cygpath -w ${JAVA_HOME}/include)" \ + -I"$(shell cygpath -w ${JAVA_HOME}/include/win32)" \ + /link /MACHINE:X64 /DLL /OUT:timeoutHandler.dll +endif + +check_defined = $(foreach 1,$1,$(__check_defined)) +__check_defined = $(if $(value $1),, $(error $1 is not set)) + +classes: require_env + mkdir -p ${IMAGE_DIR}/bin ${IMAGE_DIR}/lib ${CLASSES_DIR} + "${JAVA_HOME}"/bin/javac -target ${JAVA_RELEASE} -source ${JAVA_RELEASE} \ + -sourcepath $(shell pwd) \ + -classpath ${JTREG_HOME}/lib/jtreg.jar:${JAVA_HOME}/lib/tools.jar \ + -d ${CLASSES_DIR} \ + ${SOURCES} + "${JAVA_HOME}"/bin/jar cf ${TARGET_JAR} -C ${CLASSES_DIR} . + "${JAVA_HOME}"/bin/jar uf ${TARGET_JAR} -C ${CONF_DIR} . + +# +# Use JTREG_TEST_OPTS for test VM options +# Use JTREG_TESTS for jtreg tests parameter +# +test: require_env build + rm -rf ${RUN_DIR} + mkdir -p ${RUN_DIR} + "${JTREG_HOME}"/bin/jtreg \ + -jdk:"${JAVA_HOME}" \ + ${JTREG_TEST_OPTS} \ + -timeout:0.1 -va -retain:all \ + -noreport \ + -agentvm \ + -thd:"${TARGET_JAR}" \ + -th:jdk.test.failurehandler.jtreg.GatherProcessInfoTimeoutHandler \ + -od:"${TARGET_JAR}" \ + -o:jdk.test.failurehandler.jtreg.GatherDiagnosticInfoObserver \ + -w:${RUN_DIR}/JTwork -r:${RUN_DIR}/JTreport \ + $(if ${JTREG_TESTS}, ${JTREG_TESTS}, test) \ + && false || true + +debug: JTREG_TEST_OPTS += "-J-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005'" +debug: test + +require_env: + $(call check_defined, JAVA_HOME) + $(call check_defined, JTREG_HOME) + +clean: + rm -rf "${BUILD_DIR}" "${RUN_DIR}" + +build: classes native + +.PHONY: all build classes native test require_env clean +.DEFAULT: all + diff --git a/test/failure_handler/README b/test/failure_handler/README new file mode 100644 --- /dev/null +++ b/test/failure_handler/README @@ -0,0 +1,107 @@ +Copyright (c) 2015, 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. + + + +DESCRIPTION + +The purpose of this library is gathering diagnostic information on test +failures and timeouts. The library runs platform specific tools, which are +configured in the way described below. The collected data will be available +in HTML format next to JTR files. + +The library uses JTHarness Observer and jtreg TimeoutHandler extensions points. + +DEPENDENCES + +The library requires jtreg 4b13+ and JDK 7+. + +BUILDING + +To build a library, one should simply run make with 'JTREG_HOME' and +'JAVA_HOME' environment variables set. 'JAVA_HOME' should contain path to JDK, +'JTREG_HOME' -- path to jtreg. + +'image/lib/jtregFailureHandler.jar' is created on successful build. + +CONFIGURATION + +Properties files are used to configure the library. They define which actions +to be performed in case of individual test failure or timeout. Each platform +family uses its own property file (named '.properties'). For platform +independent actions, 'common.properties' is used. + +Actions to be performed on each failure are listed in 'environment' property. +Extra actions for timeouts are listed in 'onTimeout'. + +Each action is defined via the following parameters: + - 'javaOnly' -- run the action only for java applications, false by default + - 'app' -- an application to run, mandatory parameter + - 'args' -- application command line arguments, none by default + - 'params' -- a structure which defines how an application should be run, + described below + +Actions listed in 'onTimeout' are "patterned" actions. Besides the parameters +listed above, they also have 'pattern' parameter -- a string which will be +replaced by PID in 'args' parameter before action execution. + +'params' structure has the following parameters: + - repeat -- how many times an action will be run, 1 by default + - pause -- delay in ms between iterations, 500 by default + - timeout -- time limitation for iteration in ms, 20 000 by default + - stopOnError -- if true, an action will be interrupted after the first error, + false by default + +From '.properties', the library reads the following parameters + - 'config.execSuffix' -- a suffix for all binary application file names + - 'config.getChildren' -- a "patterned" action used to get the list of all + children + +For simplicity we use parameter values inheritance. This means that we are +looking for the most specified parameter value. If we do not find it, we are +trying to find less specific value by reducing prefix. +For example, if properties contains 'p1=A', 'a.p1=B', 'a.b.p1=C', then +parameter 'p1' will be: + - 'C' for 'a.b.c' + - 'B' for 'a.c' + - 'A' for 'b.c' + +RUNNING + +To enable the library in jtreg, the following options should be set: + - '-timeoutHandlerDir' points to the built jar ('jtregFailureHandler.jar') + - '-observerDir' points to the built jar + - '-timeoutHandler' equals to jdk.test.failurehandler.jtreg.GatherProcessInfoTimeoutHandler + - '-observer' equals to jdk.test.failurehandler.jtreg.GatherDiagnosticInfoObserver + +In case of environment issues during an action execution, such as missing +application, hung application, lack of disk space, etc, the corresponding +warning appears and the library proceeds to next action. + +EXAMPLES + +$ ${JTREG_HOME}/bin/jtreg -jdk:${JAVA_HOME} \ + -timeoutHandlerDir:./image/lib/jtregFailureHandler.jar \ + -observerDir:./image/lib/jtregFailureHandler.jar \ + -timeoutHandler:jdk.test.failurehandler.jtreg.GatherProcessInfoTimeoutHandler\ + -observer:jdk.test.failurehandler.jtreg.GatherDiagnosticInfoObserver \ + ${WS}/hotspot/test/ + diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/ElapsedTimePrinter.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/ElapsedTimePrinter.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/ElapsedTimePrinter.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2015, 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. + */ + +package jdk.test.failurehandler; + +import java.io.PrintWriter; +import java.util.concurrent.TimeUnit; + +public class ElapsedTimePrinter implements AutoCloseable { + private final String name; + private final PrintWriter out; + private final Stopwatch stopwatch; + + public ElapsedTimePrinter(Stopwatch stopwatch, String name, + PrintWriter out) { + this.stopwatch = stopwatch; + this.name = name; + this.out = out; + stopwatch.start(); + } + + @Override + public void close() { + stopwatch.stop(); + out.printf("%s took %d s%n", name, + TimeUnit.NANOSECONDS.toSeconds(stopwatch.getElapsedTimeNs())); + } +} diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/EnvironmentInfoGatherer.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/EnvironmentInfoGatherer.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/EnvironmentInfoGatherer.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, 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. + */ + +package jdk.test.failurehandler; + +public interface EnvironmentInfoGatherer { + void gatherEnvironmentInfo(HtmlSection section); +} diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/GathererFactory.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/GathererFactory.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/GathererFactory.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015, 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. + */ + +package jdk.test.failurehandler; + +import jdk.test.failurehandler.action.ActionHelper; +import jdk.test.failurehandler.value.InvalidValueException; + +import java.io.PrintWriter; +import java.nio.file.Path; +import java.util.Properties; + +public final class GathererFactory { + private final Path workdir; + private final Path[] jdks; + private final PrintWriter log; + private final String osName; + + public GathererFactory(String osName, Path workdir, PrintWriter log, Path... jdks) { + this.osName = osName; + this.workdir = workdir; + this.log = log; + this.jdks = jdks; + } + + public EnvironmentInfoGatherer getEnvironmentInfoGatherer() { + return create(); + } + + public ProcessInfoGatherer getProcessInfoGatherer() { + return create(); + } + + private ToolKit create() { + Properties osProperty = Utils.getProperties(osName); + try { + ActionHelper helper = new ActionHelper(workdir, "config", osProperty, jdks); + return new ToolKit(helper, log, osName, "common"); + } catch (InvalidValueException e) { + throw new IllegalStateException("can't create tool kit", e); + } + } +} diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/HtmlPage.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/HtmlPage.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/HtmlPage.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015, 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. + */ + +package jdk.test.failurehandler; + +import java.io.PrintWriter; +import java.util.Objects; + +public class HtmlPage implements AutoCloseable { + private final PrintWriter writer; + private final HtmlSection rootSection; + + public HtmlPage(PrintWriter writer) { + Objects.requireNonNull(writer, "writer cannot be null"); + this.writer = writer; + rootSection = new HtmlSection(writer); + } + + @Override + public void close() { + writer.close(); + } + + public HtmlSection getRootSection() { + return rootSection; + } +} diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/HtmlSection.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/HtmlSection.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/HtmlSection.java @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2015, 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. + */ + +package jdk.test.failurehandler; + +import java.io.FilterWriter; +import java.io.IOException; +import java.io.PrintWriter; + +public class HtmlSection { + protected final HtmlSection rootSection; + protected final String id; + protected final String name; + + public PrintWriter getWriter() { + return textWriter; + } + + protected final PrintWriter pw; + protected final PrintWriter textWriter; + protected boolean closed; + + private HtmlSection child; + + + public HtmlSection(PrintWriter pw) { + this(pw, "", null, null); + } + + private HtmlSection(PrintWriter pw, String id, String name, HtmlSection rootSection) { + this.pw = pw; + textWriter = new PrintWriter(new HtmlFilterWriter(pw)); + this.id = id; + this.name = name; + child = null; + // main + if (rootSection == null) { + this.rootSection = this; + this.pw.println(""); + this.pw.println("\n" + + "\n" + + "\n" + + ""); + + this.pw.println(""); + } else { + this.rootSection = rootSection; + this.pw.print(""); + } + + } + + protected final void closeChild() { + if (child != null) { + child.close(); + child = null; + } + } + + public void link(HtmlSection section, String child, String name) { + String path = section.id; + if (path.isEmpty()) { + path = child; + } else if (child != null) { + path = String.format("%s.%s", path, child); + } + pw.printf("%2$s%n", + path, name); + } + + public HtmlSection createChildren(String[] sections) { + int i = 0; + int n = sections.length; + HtmlSection current = rootSection; + if (current != null) { + for (; i < n && current.child != null; + ++i, current = current.child) { + if (!sections[i].equals(current.child.name)) { + break; + } + } + } + for (; i < n; ++i) { + current = current.createChildren(sections[i]); + } + return current; + } + + private static class SubSection extends HtmlSection { + private final HtmlSection parent; + + public SubSection(HtmlSection parent, String name, + HtmlSection rootSection) { + super(parent.pw, + parent.id.isEmpty() + ? name + : String.format("%s.%s", parent.id, name), + name, rootSection); + this.parent = parent; + pw.printf("
  • %2$s
    ",
    +                    id, name);
    +        }
    +
    +        @Override
    +        public void close() {
    +            closeChild();
    +            if (closed) {
    +                return;
    +            }
    +            pw.print("
  • "); + parent.removeChild(this); + super.close(); + } + } + + private static class HtmlFilterWriter extends FilterWriter { + public HtmlFilterWriter(PrintWriter pw) { + super(pw); + } + + @Override + public void write(int c) throws IOException { + switch (c) { + case '<': + super.write("<", 0, 4); + break; + case '>': + super.write(">", 0, 4); + break; + case '"': + super.write(""", 0, 5); + break; + case '&': + super.write("&", 0, 4); + break; + default: + super.write(c); + } + } + + @Override + public void write(char[] cbuf, int off, int len) throws IOException { + for (int i = off; i < len; ++i){ + write(cbuf[i]); + } + } + + @Override + public void write(String str, int off, int len) throws IOException { + for (int i = off; i < len; ++i){ + write(str.charAt(i)); + } + } + } +} diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/ProcessInfoGatherer.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/ProcessInfoGatherer.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/ProcessInfoGatherer.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, 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. + */ + +package jdk.test.failurehandler; + +public interface ProcessInfoGatherer { + void gatherProcessInfo(HtmlSection section, long pid); +} diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/Stopwatch.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/Stopwatch.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/Stopwatch.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2015, 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. + */ + +package jdk.test.failurehandler; + +public final class Stopwatch { + protected boolean isResultAvailable; + protected boolean isRunning; + + private long startTimeNs; + private long stopTimeNs; + + public Stopwatch() { + isResultAvailable = false; + } + + /** + * Starts measuring time. + */ + public void start() { + startTimeNs = System.nanoTime(); + isRunning = true; + } + + /** + * Stops measuring time. + */ + public void stop() { + if (!isRunning) { + throw new IllegalStateException(" hasn't been started"); + } + stopTimeNs = System.nanoTime(); + isRunning = false; + isResultAvailable = true; + } + + /** + * @return time in nanoseconds measured between + * calls of {@link #start()} and {@link #stop()} methods. + * + * @throws IllegalStateException if called without preceding + * {@link #start()} {@link #stop()} method + */ + public long getElapsedTimeNs() { + if (isRunning) { + throw new IllegalStateException("hasn't been stopped"); + } + if (!isResultAvailable) { + throw new IllegalStateException("was not run"); + } + return stopTimeNs - startTimeNs; + } +} diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/ToolKit.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/ToolKit.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/ToolKit.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2015, 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. + */ + +package jdk.test.failurehandler; + +import jdk.test.failurehandler.action.ActionSet; +import jdk.test.failurehandler.action.ActionHelper; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +public class ToolKit implements EnvironmentInfoGatherer, ProcessInfoGatherer { + private final List actions = new ArrayList<>(); + private final ActionHelper helper; + + public ToolKit(ActionHelper helper, PrintWriter log, String... names) { + this.helper = helper; + for (String name : names) { + actions.add(new ActionSet(helper, log, name)); + } + } + + @Override + public void gatherEnvironmentInfo(HtmlSection section) { + for (ActionSet set : actions) { + set.gatherEnvironmentInfo(section); + } + } + + @Override + public void gatherProcessInfo(HtmlSection section, long pid) { + Queue pids = new LinkedList<>(); + pids.add(pid); + for (Long p = pids.poll(); p != null; p = pids.poll()) { + HtmlSection pidSection = section.createChildren("" + p); + for (ActionSet set : actions) { + set.gatherProcessInfo(pidSection, p); + } + List children = helper.getChildren(pidSection, p); + if (!children.isEmpty()) { + HtmlSection s = pidSection.createChildren("children"); + for (Long c : children) { + s.link(section, c.toString(), c.toString()); + } + pids.addAll(children); + } + } + } +} diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/Utils.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/Utils.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/Utils.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2015, 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. + */ + +package jdk.test.failurehandler; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; +import java.util.Properties; + +public final class Utils { + private static final int BUFFER_LENGTH = 1024; + + public static String prependPrefix(String prefix, String name) { + return (prefix == null || prefix.isEmpty()) + ? name + : (name == null || name.isEmpty()) + ? prefix + : String.format("%s.%s", prefix, name); + } + + public static void copyStream(InputStream in, OutputStream out) + throws IOException { + int n; + byte[] buffer = new byte[BUFFER_LENGTH]; + while ((n = in.read(buffer)) != -1) { + out.write(buffer, 0, n); + } + out.flush(); + } + + public static void copyStream(Reader in, Writer out) + throws IOException { + int n; + char[] buffer = new char[BUFFER_LENGTH]; + while ((n = in.read(buffer)) != -1) { + out.write(buffer, 0, n); + } + out.flush(); + } + + public static Properties getProperties(String name) { + Properties properties = new Properties(); + String resourceName = String.format( + "/%s.%s", name.toLowerCase(), "properties"); + InputStream stream = Utils.class.getResourceAsStream(resourceName); + if (stream == null) { + throw new IllegalStateException(String.format( + "resource '%s' doesn't exist%n", resourceName)); + } + try { + try { + properties.load(stream); + } finally { + stream.close(); + } + } catch (IOException e) { + throw new IllegalStateException(String.format( + "can't read resource '%s' : %s%n", + resourceName, e.getMessage()), e); + } + return properties; + } + + private Utils() { } +} diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/Action.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/Action.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/Action.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2015, 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. + */ + +package jdk.test.failurehandler.action; + +import jdk.test.failurehandler.HtmlSection; + +public interface Action { + boolean isJavaOnly(); + HtmlSection getSection(HtmlSection section); + + ActionParameters getParameters(); +} diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionHelper.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionHelper.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionHelper.java @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2015, 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. + */ + +package jdk.test.failurehandler.action; + +import com.sun.tools.attach.VirtualMachine; +import com.sun.tools.attach.VirtualMachineDescriptor; +import jdk.test.failurehandler.value.InvalidValueException; +import jdk.test.failurehandler.value.Value; +import jdk.test.failurehandler.value.ValueHandler; +import jdk.test.failurehandler.HtmlSection; +import jdk.test.failurehandler.Stopwatch; +import jdk.test.failurehandler.Utils; + +import java.io.BufferedReader; +import java.io.CharArrayReader; +import java.io.CharArrayWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.io.Reader; +import java.io.Writer; +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Properties; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.TimeUnit; + +public class ActionHelper { + private final Path workDir; + @Value(name = "execSuffix") + private String executableSuffix = ""; + private Path[] paths; + + private final PatternAction getChildren; + + public ActionHelper(Path workDir, String prefix, Properties properties, + Path... jdks) throws InvalidValueException { + this.workDir = workDir.toAbsolutePath(); + getChildren = new PatternAction("children", + Utils.prependPrefix(prefix, "getChildren"), properties); + ValueHandler.apply(this, properties, prefix); + String[] pathStrings = System.getenv("PATH").split(File.pathSeparator); + paths = new Path[pathStrings.length]; + for (int i = 0; i < paths.length; ++i) { + paths[i] = Paths.get(pathStrings[i]); + } + addJdks(jdks); + } + + public List getChildren(HtmlSection section, long pid) { + String pidStr = "" + pid; + ProcessBuilder pb = getChildren.prepareProcess(section, this, pidStr); + PrintWriter log = getChildren.getSection(section).getWriter(); + CharArrayWriter writer = new CharArrayWriter(); + ExitCode code = run(log, writer, pb, getChildren.getParameters()); + Reader output = new CharArrayReader(writer.toCharArray()); + + if (!ExitCode.OK.equals(code)) { + log.println("WARNING: get children pids action failed"); + try { + Utils.copyStream(output, log); + } catch (IOException e) { + e.printStackTrace(log); + } + return Collections.emptyList(); + } + + List result = new ArrayList<>(); + try { + try (BufferedReader reader = new BufferedReader(output)) { + String line; + while ((line = reader.readLine()) != null) { + String value = line.trim(); + if (value.isEmpty()) { + // ignore empty lines + continue; + } + try { + result.add(Long.valueOf(value)); + } catch (NumberFormatException e) { + log.printf("WARNING: can't parse child pid %s : %s%n", + line, e.getMessage()); + e.printStackTrace(log); + } + } + } + } catch (IOException e) { + e.printStackTrace(log); + } + return result; + } + + public ProcessBuilder prepareProcess(PrintWriter log, String app, + String... args) { + File appBin = findApp(app); + if (appBin == null) { + log.printf("ERROR: can't find %s in %s.%n", + app, Arrays.toString(paths)); + return null; + } + List command = new ArrayList<>(args.length + 1); + command.add(appBin.toString()); + Collections.addAll(command, args); + return new ProcessBuilder() + .command(command) + .directory(workDir.toFile()); + } + + private File findApp(String app) { + String name = app + executableSuffix; + for (Path pathElem : paths) { + File result = pathElem.resolve(name).toFile(); + if (result.exists()) { + return result; + } + } + return null; + } + + private void addJdks(Path[] jdkPaths) { + if (jdkPaths != null && jdkPaths.length != 0) { + Path[] result = new Path[jdkPaths.length + paths.length]; + for (int i = 0; i < jdkPaths.length; ++i) { + result[i] = jdkPaths[i].resolve("bin"); + } + System.arraycopy(paths, 0, result, jdkPaths.length, paths.length); + paths = result; + } + } + + private ExitCode run(PrintWriter log, Writer out, ProcessBuilder pb, + ActionParameters params) { + char[] lineChars = new char[40]; + Arrays.fill(lineChars, '-'); + String line = new String(lineChars); + Stopwatch stopwatch = new Stopwatch(); + stopwatch.start(); + + log.printf("%s%n[%tF % 0) { + WATCHDOG.schedule(this, timeout); + } + } + } + + private void exec(HtmlSection section, ProcessBuilder process, + ActionParameters params) { + if (process == null) { + return; + } + PrintWriter sectionWriter = section.getWriter(); + if (params.repeat > 1) { + for (int i = 0, n = params.repeat; i < n; ++i) { + HtmlSection iteration = section.createChildren( + String.format("iteration_%d", i)); + PrintWriter writer = iteration.getWriter(); + ExitCode exitCode = run(writer, writer, process, params); + if (params.stopOnError && !ExitCode.OK.equals(exitCode)) { + sectionWriter.printf( + "ERROR: non zero exit code[%d] -- break.", + exitCode.value); + break; + } + try { + Thread.sleep(params.pause); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + e.printStackTrace(sectionWriter); + } + } + } else { + run(section.getWriter(), section.getWriter(), process, params); + } + } + + /** + * Special values for prepareProcess exit code. + * + *

    Can we clash with normal codes? + * On Solaris and Linux, only [0..255] are returned. + * On Windows, prepareProcess exit codes are stored in unsigned int. + * On MacOSX no limits (except it should fit C int type) + * are defined in the exit() man pages. + */ + private static class ExitCode { + /** Process exits gracefully */ + public static final ExitCode OK = new ExitCode(0); + /** Error launching prepareProcess */ + public static final ExitCode LAUNCH_ERROR = new ExitCode(-1); + /** Application prepareProcess has been killed by watchdog due to timeout */ + public static final ExitCode TIMED_OUT = new ExitCode(-2); + /** Application prepareProcess has never been started due to program logic */ + public static final ExitCode NEVER_STARTED = new ExitCode(-3); + + public final int value; + + private ExitCode(int value) { + this.value = value; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + ExitCode exitCode = (ExitCode) o; + return value == exitCode.value; + } + + @Override + public int hashCode() { + return value; + } + } + +} diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionParameters.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionParameters.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionParameters.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015, 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. + */ + +package jdk.test.failurehandler.action; + +import jdk.test.failurehandler.value.DefaultValue; +import jdk.test.failurehandler.value.Value; + +public class ActionParameters { + @Value (name = "repeat") + @DefaultValue (value = "1") + public int repeat = 1; + + @Value (name = "pause") + @DefaultValue (value = "500") + public long pause = 500; + + @Value (name = "stopOnError") + @DefaultValue (value = "false") + public boolean stopOnError = false; + + @Value (name = "timeout") + @DefaultValue (value = "" + 20_000L) + public long timeout = -1L; + + public ActionParameters() { } +} diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionSet.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionSet.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionSet.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2015, 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. + */ + +package jdk.test.failurehandler.action; + +import jdk.test.failurehandler.ProcessInfoGatherer; +import jdk.test.failurehandler.EnvironmentInfoGatherer; +import jdk.test.failurehandler.HtmlSection; +import jdk.test.failurehandler.Utils; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +public class ActionSet implements ProcessInfoGatherer, EnvironmentInfoGatherer { + private static final String ENVIRONMENT_PROPERTY = "environment"; + private static final String ON_PID_PROPERTY = "onTimeout"; + + private final ActionHelper helper; + + public String getName() { + return name; + } + + private final String name; + private final List environmentActions; + private final List processActions; + + + public ActionSet(ActionHelper helper, PrintWriter log, String name) { + this.helper = helper; + this.name = name; + + Properties p = Utils.getProperties(name); + environmentActions = getSimpleActions(log, p, ENVIRONMENT_PROPERTY); + processActions = getPatternActions(log, p, ON_PID_PROPERTY); + } + + private List getSimpleActions(PrintWriter log, Properties p, + String key) { + String[] tools = getTools(log, p, key); + List result = new ArrayList<>(tools.length); + for (String tool : tools) { + try { + SimpleAction action = new SimpleAction( + Utils.prependPrefix(name, tool), tool, p); + result.add(action); + } catch (Exception e) { + log.printf("ERROR: %s cannot be created : %s %n", + tool, e.getMessage()); + e.printStackTrace(log); + } + } + return result; + } + + private List getPatternActions(PrintWriter log, + Properties p, String key) { + String[] tools = getTools(log, p, key); + List result = new ArrayList<>(tools.length); + for (String tool : tools) { + try { + PatternAction action = new PatternAction( + Utils.prependPrefix(name, tool), tool, p); + result.add(action); + } catch (Exception e) { + log.printf("ERROR: %s cannot be created : %s %n", + tool, e.getMessage()); + e.printStackTrace(log); + } + } + return result; + } + + private String[] getTools(PrintWriter writer, Properties p, String key) { + String value = p.getProperty(key); + if (value == null || value.isEmpty()) { + writer.printf("ERROR: '%s' property is empty%n", key); + return new String[]{}; + } + return value.split(" "); + } + + + @Override + public void gatherProcessInfo(HtmlSection section, long pid) { + String pidStr = "" + pid; + for (PatternAction action : processActions) { + if (action.isJavaOnly()) { + if (helper.isJava(pid, section.getWriter())) { + helper.runPatternAction(action, section, pidStr); + } + } else { + helper.runPatternAction(action, section, pidStr); + } + } + } + + @Override + public void gatherEnvironmentInfo(HtmlSection section) { + for (SimpleAction action : environmentActions) { + helper.runPatternAction(action, section); + } + } +} diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/PatternAction.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/PatternAction.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/PatternAction.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015, 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. + */ + +package jdk.test.failurehandler.action; + +import jdk.test.failurehandler.value.InvalidValueException; +import jdk.test.failurehandler.HtmlSection; +import jdk.test.failurehandler.value.Value; +import jdk.test.failurehandler.value.ValueHandler; + +import java.util.Properties; + +public class PatternAction implements Action { + @Value(name = "pattern") + private String pattern = null; + + private final SimpleAction action; + private final String[] originalArgs; + + public PatternAction(String id, Properties properties) + throws InvalidValueException { + this(id, id, properties); + } + + public PatternAction(String name, String id, Properties properties) + throws InvalidValueException { + action = new SimpleAction(("pattern." + name), id, properties); + ValueHandler.apply(this, properties, id); + originalArgs = action.args.clone(); + } + + public ProcessBuilder prepareProcess(HtmlSection section, + ActionHelper helper, String value) { + action.sections[0] = value; + section = getSection(section); + String[] args = action.args; + System.arraycopy(originalArgs, 0, args, 0, originalArgs.length); + + for (int i = 0, n = args.length; i < n; ++i) { + args[i] = args[i].replace(pattern, value) ; + } + return action.prepareProcess(section.getWriter(), helper); + } + + @Override + public HtmlSection getSection(HtmlSection section) { + return action.getSection(section); + } + + @Override + public ActionParameters getParameters() { + return action.getParameters(); + } + + @Override + public boolean isJavaOnly() { + return action.isJavaOnly(); + } +} diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/SimpleAction.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/SimpleAction.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/SimpleAction.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2015, 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. + */ + +package jdk.test.failurehandler.action; + +import jdk.test.failurehandler.HtmlSection; +import jdk.test.failurehandler.value.InvalidValueException; +import jdk.test.failurehandler.value.SubValues; +import jdk.test.failurehandler.value.Value; +import jdk.test.failurehandler.value.ValueHandler; +import jdk.test.failurehandler.value.DefaultValue; + +import java.io.PrintWriter; +import java.util.Properties; + +public class SimpleAction implements Action { + /* package-private */ final String[] sections; + @Value(name = "javaOnly") + @DefaultValue(value = "false") + private boolean javaOnly = false; + + @Value (name = "app") + private String app = null; + + @Value (name = "args") + @DefaultValue (value = "") + /* package-private */ String[] args = new String[]{}; + + @SubValues(prefix = "params") + private final ActionParameters params; + + public SimpleAction(String id, Properties properties) + throws InvalidValueException { + this(id, id, properties); + } + public SimpleAction(String name, String id, Properties properties) + throws InvalidValueException { + sections = name.split("\\."); + this.params = new ActionParameters(); + ValueHandler.apply(this, properties, id); + } + + public ProcessBuilder prepareProcess(PrintWriter log, ActionHelper helper) { + ProcessBuilder process = helper.prepareProcess(log, app, args); + if (process != null) { + process.redirectErrorStream(true); + } + + return process; + } + + @Override + public boolean isJavaOnly() { + return javaOnly; + } + + @Override + public HtmlSection getSection(HtmlSection section) { + return section.createChildren(sections); + } + + @Override + public ActionParameters getParameters() { + return params; + } +} diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherDiagnosticInfoObserver.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherDiagnosticInfoObserver.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherDiagnosticInfoObserver.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2015, 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. + */ + +package jdk.test.failurehandler.jtreg; + +import com.sun.javatest.Harness; +import com.sun.javatest.Parameters; +import com.sun.javatest.TestResult; +import com.sun.javatest.regtest.RegressionParameters; +import com.sun.javatest.regtest.OS; +import jdk.test.failurehandler.*; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; + +/** + * The jtreg test execution observer, which gathers info about + * system and dumps it to a file. + */ +public class GatherDiagnosticInfoObserver implements Harness.Observer { + public static final String LOG_FILENAME = "environment.log"; + public static final String ENVIRONMENT_OUTPUT = "environment.html"; + + private String compileJdk; + private String testJdk; + + /* + * The harness calls this method after each test. + */ + @Override + public void finishedTest(TestResult tr) { + if (!tr.getStatus().isError() && !tr.getStatus().isFailed()) { + return; + } + + String jtrFile = tr.getFile().toString(); + final Path workDir = Paths.get( + jtrFile.substring(0, jtrFile.lastIndexOf('.'))); + workDir.toFile().mkdir(); + + String name = getClass().getName(); + PrintWriter log; + boolean needClose = false; + try { + log = new PrintWriter(new FileWriter( + workDir.resolve(LOG_FILENAME).toFile(), true)); + needClose = true; + } catch (IOException e) { + log = new PrintWriter(System.out); + log.printf("ERROR: %s cannot open log file %s", name, + LOG_FILENAME); + e.printStackTrace(log); + } + try { + log.printf("%s ---%n", name); + GathererFactory gathererFactory = new GathererFactory( + OS.current().family, workDir, log, + Paths.get(testJdk), Paths.get(compileJdk)); + gatherEnvInfo(workDir, name, log, + gathererFactory.getEnvironmentInfoGatherer()); + } catch (Throwable e) { + log.printf("ERROR: exception in observer %s:", name); + e.printStackTrace(log); + } finally { + log.printf("--- %s%n", name); + if (needClose) { + log.close(); + } else { + log.flush(); + } + } + } + + private void gatherEnvInfo(Path workDir, String name, PrintWriter log, + EnvironmentInfoGatherer gatherer) { + File output = workDir.resolve(ENVIRONMENT_OUTPUT).toFile(); + try (HtmlPage html = new HtmlPage(new PrintWriter( + new FileWriter(output, true)))) { + try (ElapsedTimePrinter timePrinter + = new ElapsedTimePrinter(new Stopwatch(), name, log)) { + gatherer.gatherEnvironmentInfo(html.getRootSection()); + } + } catch (Throwable e) { + log.printf("ERROR: exception in observer on getting environment " + + "information %s:", name); + e.printStackTrace(log); + } + } + + /* + * The harness calls this method one time per run, not per test. + */ + @Override + public void startingTestRun(Parameters params) { + // TODO find a better way to get JDKs + RegressionParameters rp = (RegressionParameters) params; + Map map = new HashMap<>(); + rp.save(map); + compileJdk = (String) map.get("regtest.compilejdk"); + testJdk = (String) map.get("regtest.testjdk"); + } + + @Override + public void startingTest(TestResult tr) { + // no-op + } + + @Override + public void stoppingTestRun() { + // no-op + } + + @Override + public void finishedTesting() { + // no-op + } + + @Override + public void finishedTestRun(boolean allOK) { + // no-op + } + + @Override + public void error(String msg) { + // no-op + } +} diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherProcessInfoTimeoutHandler.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherProcessInfoTimeoutHandler.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherProcessInfoTimeoutHandler.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2015, 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. + */ + +package jdk.test.failurehandler.jtreg; + +import com.sun.javatest.regtest.OS; +import com.sun.javatest.regtest.TimeoutHandler; +import jdk.test.failurehandler.*; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.lang.reflect.Field; +import java.nio.file.Path; + +/** + * A timeout handler for jtreg, which gathers information about the timed out + * process and its children. + */ +public class GatherProcessInfoTimeoutHandler extends TimeoutHandler { + static { + try { + System.loadLibrary("timeoutHandler"); + } catch (UnsatisfiedLinkError ignore) { + // not all os need timeoutHandler native-library + } + } + private static final String LOG_FILENAME = "processes.log"; + private static final String OUTPUT_FILENAME = "processes.html"; + + public GatherProcessInfoTimeoutHandler(PrintWriter jtregLog, File outputDir, + File testJdk) { + super(jtregLog, outputDir, testJdk); + } + + /** + * Runs various actions for jtreg timeout handler. + * + *

    Please see method code for the actions. + */ + @Override + protected void runActions(Process process, long pid) + throws InterruptedException { + Path workDir = outputDir.toPath(); + + String name = getClass().getName(); + PrintWriter actionsLog; + try { + // try to open a separate file for aciton log + actionsLog = new PrintWriter(new FileWriter( + workDir.resolve(LOG_FILENAME).toFile(), true)); + } catch (IOException e) { + // use jtreg log as a fallback + actionsLog = log; + actionsLog.printf("ERROR: %s cannot open log file %s : %s", name, + LOG_FILENAME, e.getMessage()); + } + try { + actionsLog.printf("%s ---%n", name); + + File output = workDir.resolve(OUTPUT_FILENAME).toFile(); + try { + PrintWriter pw = new PrintWriter(new FileWriter(output, true)); + runGatherer(name, workDir, actionsLog, pw, pid); + } catch (IOException e) { + actionsLog.printf("IOException: cannot open output file[%s] : %s", + output, e.getMessage()); + e.printStackTrace(actionsLog); + } + } finally { + actionsLog.printf("--- %s%n", name); + // don't close jtreg log + if (actionsLog != log) { + actionsLog.close(); + } else { + log.flush(); + } + } + } + + @Override + protected long getProcessId(Process process) { + long result = super.getProcessId(process); + if (result == 0L) { + /* jtreg didn't find pid, most probably we are on JDK < 9 + there is no Process::getPid */ + if ("windows".equals(OS.current().family)) { + try { + Field field = process.getClass().getDeclaredField("handle"); + boolean old = field.isAccessible(); + try { + field.setAccessible(true); + long handle = field.getLong(process); + result = getWin32Pid(handle); + } finally { + field.setAccessible(old); + } + } catch (ReflectiveOperationException e) { + e.printStackTrace(log); + } + } + } + return result; + } + + private native long getWin32Pid(long handle); + + private void runGatherer(String name, Path workDir, PrintWriter log, + PrintWriter out, long pid) { + try (HtmlPage html = new HtmlPage(out)) { + ProcessInfoGatherer gatherer = new GathererFactory( + OS.current().family, + workDir, log, testJdk.toPath()).getProcessInfoGatherer(); + try (ElapsedTimePrinter timePrinter + = new ElapsedTimePrinter(new Stopwatch(), name, log)) { + gatherer.gatherProcessInfo(html.getRootSection(), pid); + } + } catch (Throwable e) { + log.printf("ERROR: exception in timeout handler %s:", name); + e.printStackTrace(log); + } + } +} diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/ArrayParser.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/ArrayParser.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/ArrayParser.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015, 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. + */ + +package jdk.test.failurehandler.value; + +import java.lang.reflect.Array; +import java.util.Objects; + +public class ArrayParser implements ValueParser { + private final ValueParser parser; + + public ArrayParser(ValueParser parser) { + Objects.requireNonNull(parser); + this.parser = parser; + } + + @Override + public Object parse(Class type, String value, String delimiter) { + Class component = type.getComponentType(); + if (component.isArray()) { + throw new IllegalArgumentException( + "multidimensional array fields aren't supported"); + } + String[] values = (value == null || value.isEmpty()) + ? new String[]{} + : value.split(delimiter); + Object result = Array.newInstance(component, values.length); + for (int i = 0, n = values.length; i < n; ++i) { + Array.set(result, i, parser.parse(component, values[i], delimiter)); + } + return result; + } +} diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/DefaultParser.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/DefaultParser.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/DefaultParser.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2015, 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. + */ + +package jdk.test.failurehandler.value; + +import java.util.HashMap; +import java.util.Map; + +public class DefaultParser implements ValueParser { + private static final Map, BasicParser> PARSERS = new HashMap<>(); + + static { + BasicParser.init(); + } + + @Override + public Object parse(Class type, String value, String s) { + if (type.isArray()) { + return new ArrayParser(this).parse(type, value, s); + } + ValueParser parser = PARSERS.get(type); + if (parser == null) { + throw new IllegalArgumentException("can't find parser for " + + type.getName()); + } + + return parser.parse(type, value, s); + } + + private static enum BasicParser implements ValueParser { + BOOL(boolean.class, Boolean.class) { + @Override + public Object parse(Class type, String value, String s) { + return Boolean.valueOf(value); + } + }, + BYTE(byte.class, Byte.class) { + @Override + public Object parse(Class type, String value, String s) { + return Byte.decode(value); + } + }, + CHAR(char.class, Character.class) { + @Override + public Object parse(Class type, String value, String s) { + if (value.length() != 1) { + throw new IllegalArgumentException( + String.format("can't cast %s to char", value)); + } + return value.charAt(0); + } + }, + SHORT(short.class, Short.class) { + @Override + public Object parse(Class type, String value, String s) { + return Short.decode(value); + } + }, + INT(int.class, Integer.class) { + @Override + public Object parse(Class type, String value, String s) { + return Integer.decode(value); + } + }, + LONG(long.class, Long.class) { + @Override + public Object parse(Class type, String value, String s) { + return Long.decode(value); + } + }, + FLOAT(float.class, Float.class) { + @Override + public Object parse(Class type, String value, String s) { + return Float.parseFloat(value); + } + }, + DOUBLE(double.class, Double.class) { + @Override + public Object parse(Class type, String value, String s) { + return Double.parseDouble(value); + } + }, + STRING(String.class, Object.class) { + @Override + public Object parse(Class type, String value, String s) { + return value; + } + }; + + private BasicParser(Class... classes) { + for (Class aClass : classes) { + DefaultParser.PARSERS.put(aClass, this); + } + } + + private static void init() { + // no-op used to provoke + } + } +} diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/DefaultValue.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/DefaultValue.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/DefaultValue.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, 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. + */ + +package jdk.test.failurehandler.value; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(value = RetentionPolicy.RUNTIME) +@Target(value = ElementType.FIELD) +public @interface DefaultValue { + String value(); +} diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/InvalidValueException.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/InvalidValueException.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/InvalidValueException.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015, 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. + */ + +package jdk.test.failurehandler.value; + +public class InvalidValueException extends Exception { + public InvalidValueException() { } + + public InvalidValueException(String message) { + super(message); + } + + public InvalidValueException(String s, Throwable e) { + super(s, e); + } + + public InvalidValueException(Throwable cause) { + super(cause); + } +} diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/PathValueParser.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/PathValueParser.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/PathValueParser.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, 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. + */ + +package jdk.test.failurehandler.value; + +import java.io.File; + +public class PathValueParser implements ValueParser { + @Override + public Object parse(Class type, String value, String delimiter) { + if (type.isArray()) { + return new ArrayParser(this).parse(type, value, delimiter); + } + return new File(value).toPath(); + } +} diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/SubValues.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/SubValues.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/SubValues.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, 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. + */ + +package jdk.test.failurehandler.value; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(value = RetentionPolicy.RUNTIME) +@Target(value = ElementType.FIELD) +public @interface SubValues { + String prefix(); +} diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/Value.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/Value.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/Value.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, 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. + */ + +package jdk.test.failurehandler.value; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(value = RetentionPolicy.RUNTIME) +@Target(value = ElementType.FIELD) +public @interface Value { + String name(); + Class parser() default DefaultParser.class; +} diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/ValueHandler.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/ValueHandler.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/ValueHandler.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2015, 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. + */ + +package jdk.test.failurehandler.value; + +import jdk.test.failurehandler.Utils; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Objects; +import java.util.Properties; + +public final class ValueHandler { + public static void apply(T object, Properties properties, + String prefix) throws InvalidValueException { + Objects.requireNonNull(object, "object cannot be null"); + Objects.requireNonNull(properties, "properties cannot be null"); + Class aClass = object.getClass(); + while (aClass != null) { + for (Field field : aClass.getDeclaredFields()) { + Value p = field.getAnnotation(Value.class); + if (p != null) { + applyToField(p, object, field, properties, prefix); + } else { + SubValues sub + = field.getAnnotation(SubValues.class); + if (sub != null) { + getAccess(field); + try { + apply(field.get(object), properties, + Utils.prependPrefix(prefix, sub.prefix())); + } catch (IllegalAccessException e) { + throw new InvalidValueException(String.format( + "can't apply sub properties to %s.", + field.getName())); + } + } + } + } + aClass = aClass.getSuperclass(); + } + } + + private static void applyToField(Value property, Object object, + Field field, Properties properties, String prefix) + throws InvalidValueException { + getAccess(field); + if (Modifier.isFinal(field.getModifiers())) { + throw new InvalidValueException( + String.format("field '%s' is final", field)); + } + String name = Utils.prependPrefix(prefix, property.name()); + String value = getProperty(properties, prefix, property.name()); + if (value == null) { + DefaultValue defaultValue + = field.getAnnotation(DefaultValue.class); + value = defaultValue == null ? null : defaultValue.value(); + } + if (value == null) { + throw new InvalidValueException(String.format( + "can't set '%s', because properties don't have '%s'.", + field.getName(), name)); + } + String delimiter = getProperty(properties, + Utils.prependPrefix(prefix, property.name()), "delimiter"); + delimiter = delimiter == null ? " " : delimiter; + Class parserClass = property.parser(); + try { + field.set(object, parserClass.newInstance().parse( + field.getType(), value, delimiter)); + } catch (ReflectiveOperationException | IllegalArgumentException e) { + throw new InvalidValueException( + String.format("can't set field '%s' : %s", + field.getName(), e.getMessage()), e); + } + } + + private static String getProperty(Properties properties, + String prefix, String name) { + if (prefix == null || prefix.isEmpty()) { + return properties.getProperty(name); + } + int index = prefix.length(); + do { + String value = properties.getProperty( + Utils.prependPrefix(prefix.substring(0, index), name)); + if (value != null) { + return value; + } + index = prefix.lastIndexOf('.', index - 1); + } while (index > 0); + return properties.getProperty(name); + } + + private static void getAccess(Field field) { + int modifiers = field.getModifiers(); + if (!Modifier.isPublic(modifiers)) { + field.setAccessible(true); + } + } + +} diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/ValueParser.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/ValueParser.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/ValueParser.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, 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. + */ + +package jdk.test.failurehandler.value; + +public interface ValueParser { + Object parse(Class type, String value, String delimiter); +} diff --git a/test/failure_handler/src/share/conf/common.properties b/test/failure_handler/src/share/conf/common.properties new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/conf/common.properties @@ -0,0 +1,74 @@ +# +# Copyright (c) 2015, 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. +# + +pattern=%p +javaOnly=true +args=%p +################################################################################ +# process info to gather +################################################################################ +onTimeout=\ + jinfo \ + jcmd.compiler.codecache jcmd.compiler.codelist \ + jcmd.compiler.queue \ + jcmd.vm.classloader_stats jcmd.vm.stringtable \ + jcmd.vm.symboltable jcmd.vm.uptime jcmd.vm.dynlibs \ + jcmd.vm.system_properties \ + jcmd.gc.class_stats jcmd.gc.class_histogram \ + jstack \ + jmap.heap jmap.histo jmap.clstats jmap.finalizerinfo + +jinfo.app=jinfo + +jcmd.app=jcmd + +jcmd.compiler.codecache.args=%p Compiler.codecache +jcmd.compiler.codelist.args=%p Compiler.codelist +jcmd.compiler.queue.args=%p Compiler.queue + +jcmd.vm.classloader_stats.args=%p VM.classloader_stats +jcmd.vm.stringtable.args=%p VM.stringtable +jcmd.vm.symboltable.args=%p VM.symboltable +jcmd.vm.uptime.args=%p VM.uptime +jcmd.vm.dynlibs.args=%p VM.dynlibs +jcmd.vm.system_properties.args=%p VM.system_properties + +jcmd.gc.class_stats.args=%p GC.class_stats +jcmd.gc.class_histogram.args=%p GC.class_histogram + +jstack.app=jstack +jstack.params.repeat=6 + +jmap.app=jmap +jmap.heap.args=-heap %p +jmap.histo.args=-histo %p +jmap.clstats.args=-clstats %p +jmap.finalizerinfo.args=-finalizerinfo %p + +################################################################################ +# environment info to gather +################################################################################ +environment=jps +jps.app=jps +jps.args=-mlv +################################################################################ diff --git a/test/failure_handler/src/share/conf/linux.properties b/test/failure_handler/src/share/conf/linux.properties new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/conf/linux.properties @@ -0,0 +1,110 @@ +# +# Copyright (c) 2015, 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. +# + +config.execSuffix= +config.getChildren.pattern=%p +config.getChildren.app=ps +config.getChildren.args=--no-headers -o pid --ppid %p +################################################################################ +# process info to gather +################################################################################ +onTimeout=\ + native.pmap.normal native.pmap.everything \ + native.files native.locks \ + native.stack native.core +################################################################################ +native.pattern=%p +native.javaOnly=false +native.args=%p + +native.pmap.app=pmap +native.pmap.normal.args=-p %p +native.pmap.everything.args=-XXp %p + +native.files.app=lsof +native.files.args=-p %p + +native.locks.app=lslocks +native.locks.args=-u --pid %p + +native.stack.app=gdb +native.stack.args=--pid=%p\0-batch\0-ex\0thread apply all backtrace +native.stack.args.delimiter=\0 +native.stack.params.repeat=6 + +native.core.app=gcore +native.core.args=-o ./core.%p %p +native.core.params.timeout=3600000 +################################################################################ +# environment info to gather +################################################################################ +environment=\ + users.current users.logged users.last \ + disk \ + env \ + system.dmesg system.sysctl \ + process.top process.ps \ + memory.free memory.vmstat.default memory.vmstat.statistics \ + memory.vmstat.slabinfo memory.vmstat.disk \ + files \ + locks \ + net.sockets net.statistics +################################################################################ +users.current.app=id +users.current.args=-a +users.logged.app=who +users.logged.args=-a +users.last.app=last +users.last.args=-10 + +disk.app=df +disk.args=-h + +env.app=env + +system.dmesg.app=dmesg +system.sysctl.app=sysctl +system.sysctl.args=-a + +process.top.app=top +process.top.args=-b -n 1 +process.ps.app=ps +process.ps.args=-Leo pid,pcpu,cputime,start,pmem,vsz,rssize,stackp,stat,sgi_p,wchan,user,args + +memory.free.app=free +memory.free.args=-h +memory.vmstat.app=vmstat +memory.vmstat.default.args=3 3 +memory.vmstat.statistics.args=-s +memory.vmstat.slabinfo.args=-m +memory.vmstat.disk.args=-d + +files.app=lsof +locks.app=lslocks +locks.args=-u + +net.app=netstat +net.sockets.args=-aeeopv +net.statistics.args=-sv +################################################################################ + diff --git a/test/failure_handler/src/share/conf/mac.properties b/test/failure_handler/src/share/conf/mac.properties new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/conf/mac.properties @@ -0,0 +1,98 @@ +# +# Copyright (c) 2015, 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. +# + +config.execSuffix= +config.getChildren.pattern=%p +config.getChildren.app=pgrep +config.getChildren.args=-P %p +################################################################################ +# process info to gather +################################################################################ +onTimeout=\ + native.vmmap native.heap native.leaks native.spindump \ + native.stack native.core +################################################################################ +native.pattern=%p +native.javaOnly=false +native.args=%p + +# Some of them require root privileges +native.vmmap.app=vmmap +native.heap.app=heap +native.leaks.app=leaks +native.spindump.app=spindump +native.spindump.args=%p -stdout + +native.stack.app=lldb +native.stack.delimiter=\0 +native.stack.params.repeat=6 +native.stack.args=-o\0attach %p\0-o\0thread backtrace all\0-o\0detach\0-o\0quit + +native.core.app=bash +native.core.delimiter=\0 +native.core.args=-c\0gcore -o ./core.%p %p || \ + lldb -o 'attach %p' -o 'process save-core core.%p' -o 'detach' -o 'quit' +native.core.params.timeout=3600000 +################################################################################ +# environment info to gather +################################################################################ +environment=\ + users.current users.logged users.last \ + disk \ + env \ + system.dmesg system.sysctl \ + process.ps process.top \ + memory.vmstat \ + netstat.av netstat.aL netstat.m netstat.s +################################################################################ +users.current.app=id +users.current.args=-a +users.logged.app=who +users.logged.args=-a +users.last.app=last +users.last.args=-10 + +disk.app=df +disk.args=-h + +env.app=env + +system.dmesg.app=dmesg +system.sysctl.app=sysctl +system.sysctl.args=-a + +process.ps.app=ps +process.ps.args=-Meo pid,pcpu,cputime,start,pmem,vsz,rss,state,wchan,user,args +process.top.app=top +process.top.args=-l 1 + +memory.vmstat.app=vm_stat +memory.vmstat.args=-c 3 3 + + +netstat.app=netstat +netstat.av.args=-av +netstat.aL.args=-aL +netstat.m.args=-m +netstat.s.args=-s +################################################################################ diff --git a/test/failure_handler/src/share/conf/solaris.properties b/test/failure_handler/src/share/conf/solaris.properties new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/conf/solaris.properties @@ -0,0 +1,111 @@ +# +# Copyright (c) 2015, 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. +# + +config.execSuffix= +# pattern will be replaced with the PID +config.getChildren.pattern=%p +config.getChildren.app=pgrep +config.getChildren.args=-P %p +################################################################################ +# prepareProcess info to gather +################################################################################ +onTimeout=\ + native.pmap \ + native.pfiles \ + native.stack native.core +################################################################################ +# solaris specific +################################################################################ +native.pattern=%p +native.javaOnly=false + +native.pmap.app=pmap +native.pmap.args=-F %p + +native.pfiles.app=pfiles +native.pfiles.args=-F %p + +# native.locks TODO find 'analog for solaris' for Linux lslocks + +native.stack.app=pstack +native.stack.args=-F %p +native.stack.params.repeat=6 + +native.core.app=gcore +native.core.args=-F -o ./core %p +native.core.params.timeout=3600000 +################################################################################ +# environment info to gather +################################################################################ +environment=\ + users.current users.logged users.last \ + disk \ + env \ + system.dmesg system.prtconf system.sysdef \ + process.ps process.top \ + memory.swap memory.vmstat.default memory.vmstat.statistics memory.pagesize \ + netstat.av netstat.m netstat.s netstat.i +################################################################################ +# common unix +################################################################################ +users.current.app=id +users.current.args=-a +users.logged.app=who +users.logged.args=-a +users.last.app=last +users.last.args=-10 + +disk.app=df +disk.args=-h + +env.app=env + +system.dmesg.app=dmesg +system.prtconf.app=prtconf +system.sysdef.app=sysdef + +memory.swap.app=swap +memory.swap.args=-l + +process.ps.app=ps +process.ps.args=-Leo pid,lwp,ppid,tty,s,wchan,pcpu,time,stime,pmem,vsz,osz,rss,args + +process.top.app=top +process.top.args=-b -n + +memory.vmstat.app=vmstat +memory.vmstat.default.args=3 3 +memory.vmstat.statistics.args=-s + +memory.pagesize.app=pagesize + +# TODO: how to start prstat to show statistics and exit? +# prstat.app=prstat +# prstat.args=-a + +netstat.app=netstat +netstat.av.args=-av +netstat.m.args=-m +netstat.s.args=-s +netstat.i.args=-i 1 5 +################################################################################ diff --git a/test/failure_handler/src/share/conf/windows.properties b/test/failure_handler/src/share/conf/windows.properties new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/share/conf/windows.properties @@ -0,0 +1,115 @@ +# +# Copyright (c) 2015, 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. +# + +config.execSuffix=.exe +config.getChildren.app=bash +config.getChildren.pattern=%p +config.getChildren.args=-c\0wmic process where ParentProcessId=%p get ProcessId | tail -n+2 +config.getChildren.args.delimiter=\0 +################################################################################ +# process info to gather +################################################################################ +onTimeout=\ + native.info \ + native.pmap.normal native.pmap.everything \ + native.files native.locks \ + native.stack native.core +################################################################################ +native.pattern=%p +native.javaOnly=false +native.args=%p + +native.info.app=wmic +native.info.args=process where processId=%p list full + +native.pmap.app=pmap +native.pmap.normal.args=%p +native.pmap.everything.args=-x %p + +native.files.app=handle +native.files.args=-p %p +# TODO +native.locks.app=lslocks +native.locks.args=-u --pid %p + +native.stack.app=cdb +native.stack.args=-c "~*kP n;qd" -p %p +native.stack.params.repeat=6 + +native.core.app=cdb +native.core.args=-c ".dump /f core.%p;qd" -p %p +native.core.params.timeout=3600000 +################################################################################ +# environment info to gather +################################################################################ +environment=\ + users.current users.logged \ + disk \ + env \ + system.events.system system.events.application system.os \ + process.top process.ps process.tasklist \ + memory.free memory.vmstat.default memory.vmstat.statistics \ + memory.vmstat.slabinfo memory.vmstat.disk \ + files \ + net.sockets net.statistics +################################################################################ +users.current.app=id +users.current.args=-a +users.logged.app=query +users.logged.args=user + +disk.app=df +disk.args=-h + +env.app=env + +system.events.app=powershell +system.events.delimiter=\0 +system.events.system.args=-NoLogo\0-Command\0Get-EventLog System -After (Get-Date).AddDays(-1) | Format-List +system.events.application.args=-NoLogo\0-Command\0Get-EventLog Application -After (Get-Date).AddDays(-1) | Format-List + +system.os.app=wmic +system.os.args=os get /format:list + +process.top.app=top +process.top.args=-b -n 1 +process.ps.app=ps +process.ps.args=-efW +process.tasklist.app=tasklist +process.tasklist.args=/V + +memory.free.app=free +memory.vmstat.app=vmstat +memory.vmstat.statistics.args=-s +memory.vmstat.slabinfo.args=-m +memory.vmstat.disk.args=-d + +files.app=openfiles +files.args=/query + +net.sockets.app=bash +net.sockets.args=-c\0netstat -b -a -t -o || netstat -a -t -o +net.sockets.args.delimiter=\0 +net.statistics.app=netstat +net.statistics.args=-s -e +################################################################################ diff --git a/test/failure_handler/src/windows/native/jdk/test/failurehandler/jtreg/GatherProcessInfoTimeoutHandler.c b/test/failure_handler/src/windows/native/jdk/test/failurehandler/jtreg/GatherProcessInfoTimeoutHandler.c new file mode 100644 --- /dev/null +++ b/test/failure_handler/src/windows/native/jdk/test/failurehandler/jtreg/GatherProcessInfoTimeoutHandler.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, 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. + */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +JNIEXPORT jlong JNICALL Java_jdk_test_failurehandler_jtreg_GatherProcessInfoTimeoutHandler_getWin32Pid + (JNIEnv* env, jobject o, jlong handle) { + return GetProcessId(handle); +} +#ifdef __cplusplus +} +#endif diff --git a/test/failure_handler/test/TEST.ROOT b/test/failure_handler/test/TEST.ROOT new file mode 100644 diff --git a/test/failure_handler/test/sanity/Crash.java b/test/failure_handler/test/sanity/Crash.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/test/sanity/Crash.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015, 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. + */ + +import sun.misc.Unsafe; + +import java.lang.reflect.Field; + +/* + * @test + * @run main/othervm Crash + */ +public class Crash { + public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException { + Field f = Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + Unsafe u = (Unsafe) f.get(null); + u.setMemory(0, 42, (byte) 0xFF); + } +} diff --git a/test/failure_handler/test/sanity/Deadlock.java b/test/failure_handler/test/sanity/Deadlock.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/test/sanity/Deadlock.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015, 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 + * @summary Deadlocked client + */ +public class Deadlock { + public double e; + private volatile int i; + + public static void main(String[] args) { + new Deadlock().test(); + } + private void test() { + final Object a = new Object(); + final Object b = new Object(); + + new Thread(new Runnable() { + @Override + public void run() { + synchronized (a) { + do { + i |= 1; + } while (i != 3); + + synchronized (b) { + e = 1; + } + } + }}).start(); + + synchronized (b) { + do { + i |= 2; + } while (i != 3); + synchronized (a) { + e = 2; + } + } + } +} diff --git a/test/failure_handler/test/sanity/Livelock.java b/test/failure_handler/test/sanity/Livelock.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/test/sanity/Livelock.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2015, 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 + * @summary Busy infinite loop client, calculating E number + */ +public class Livelock { + + public static double elim; + + public static void main(String[] args) { + System.out.printf( + "%24s %24s %24s %24s %24s %24s%n", + "n", "n!", "e = lim(...)", "e = taylor series", + "err e-lim", "err e-taylor"); + + while (true) { + double esum = 2; + double nfac = 1; + double iter = 1; + for (double n = 1; !Double.isInfinite(n) && !Double.isNaN(n) ; n = n * 2) { + elim = Math.pow(1 + 1 / n, n); + + iter += 1; + nfac *= iter; + esum += 1 / nfac; + + System.out.printf("% 24.16e % 24.16e % 24.16e % 24.16e" + + "%- 24.16e %- 24.16e%n", + n, nfac, elim, esum, (Math.E - elim), (Math.E - esum)); + } + } + } +} diff --git a/test/failure_handler/test/sanity/OOME.java b/test/failure_handler/test/sanity/OOME.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/test/sanity/OOME.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015, 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. + */ + + +import java.util.LinkedList; + +/* + * @test + * @summary Slowly eat all memory in an infinite loop + * @run main/othervm Crash + */ +public class OOME { + @SuppressWarnings ("UnusedDeclaration") + private static Object garbage; + public static void main(String args[]) { + + int chunkSize = 0x8000; + LinkedList list = new LinkedList<>(); + garbage = list; + + while (true) { + try { + list.add(new int[chunkSize]); + } catch (OutOfMemoryError e) { + chunkSize >>= 1; + } + } + } +} diff --git a/test/failure_handler/test/sanity/Suicide.java b/test/failure_handler/test/sanity/Suicide.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/test/sanity/Suicide.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2015, 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. + */ + + + +import java.lang.management.ManagementFactory; + +/* + * @test + * @summary Suicide test + * @run main/othervm Crash + */ +public class Suicide { + public static void main(String[] args) { + String cmd = null; + try { + String pidStr = ManagementFactory.getRuntimeMXBean().getName() + .split("@")[0]; + String osName = System.getProperty("os.name"); + if (osName.contains("Windows")) { + cmd = "taskkill.exe /F /PID " + pidStr; + } else { + cmd = "kill -9 " + pidStr; + } + + System.out.printf("executing `%s'%n", cmd); + Runtime.getRuntime().exec(cmd); + Thread.sleep(2000); + } catch (Exception e) { + e.printStackTrace(); + } + System.err.printf("TEST/ENV BUG: %s didn't kill JVM%n", cmd); + System.exit(1); + } +} diff --git a/test/failure_handler/test/sanity/SystemExit.java b/test/failure_handler/test/sanity/SystemExit.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/test/sanity/SystemExit.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015, 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 + * @run main/othervm SystemExit + */ +public class SystemExit { + public static void main(String[] args) { + System.exit(1); + } +} diff --git a/test/failure_handler/test/sanity/ThrowError.java b/test/failure_handler/test/sanity/ThrowError.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/test/sanity/ThrowError.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015, 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 + */ +public class ThrowError { + public static void main(String[] args) { + throw new Error("TEST FAIL"); + } +} diff --git a/test/failure_handler/test/sanity/WaitForDeadlock.java b/test/failure_handler/test/sanity/WaitForDeadlock.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/test/sanity/WaitForDeadlock.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015, 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. + */ + +import java.io.IOException; +import java.nio.file.Paths; + +/* + * @test + * @build Deadlock + * @run driver WaitForDeadlock + */ +public class WaitForDeadlock { + public static void main(String[] args) throws Exception { + System.out.println("START"); + ProcessBuilder pb = new ProcessBuilder(Paths.get( + System.getProperty("test.jdk"), "bin", "java").toString(), + "-cp", System.getProperty("java.class.path"), + Deadlock.class.getName()); + pb.redirectError(ProcessBuilder.Redirect.to(Paths.get("out").toFile())); + pb.redirectOutput(ProcessBuilder.Redirect.to(Paths.get("err").toFile())); + int r = pb.start().waitFor(); + System.out.println("END. " + r); + } +} diff --git a/test/failure_handler/test/unit/jdk/test/failurehandler/value/DefaultParserTest.java b/test/failure_handler/test/unit/jdk/test/failurehandler/value/DefaultParserTest.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/test/unit/jdk/test/failurehandler/value/DefaultParserTest.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2015, 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. + */ + +package jdk.test.failurehandler.value; + +import org.junit.Assert; +import org.junit.Test; + +public class DefaultParserTest { + @Test + public void testParseStringArray() throws Exception { + DefaultParser parser = new DefaultParser(); + String line = "a aa aaa"; + String[] result = {"a", "aa", "", "", "aaa"}; + Assert.assertArrayEquals(result, + (Object[]) parser.parse(result.getClass(), line, " ")); + + line = null; + result = new String[]{}; + Assert.assertArrayEquals(result, + (Object[]) parser.parse(result.getClass(), line, " ")); + } + + @Test + public void testParseObjectArray() throws Exception { + DefaultParser parser = new DefaultParser(); + String line = "a aa aaa"; + String[] result = {"a", "aa", "", "", "aaa"}; + Assert.assertArrayEquals(result, + (String[]) parser.parse(result.getClass(), line, " ")); + Object[] result2 = {"a", "aa", "", "", "aaa"}; + Assert.assertArrayEquals(result2, + (Object[]) parser.parse(result.getClass(), line, " ")); + } + + @Test + public void testParseCharArray() throws Exception { + DefaultParser parser = new DefaultParser(); + String line = "a b c a"; + char[] result = {'a', 'b', 'c', 'a'}; + Assert.assertArrayEquals(result, + (char[]) parser.parse(result.getClass(), line, " ")); + + Character[] result2 = {'a', 'b', 'c', 'a'}; + Assert.assertArrayEquals(result2, + (Character[]) parser.parse(result2.getClass(), line, " ")); + } + + @Test + public void testParseBoolean() throws Exception { + DefaultParser parser = new DefaultParser(); + String line = "a b c a"; + Assert.assertEquals(false, + (boolean) parser.parse(boolean.class, line, " ")); + Assert.assertEquals(Boolean.FALSE, + parser.parse(Boolean.class, line, " ")); + line = "trUe"; + Assert.assertEquals(true, + (boolean) parser.parse(boolean.class, line, " ")); + Assert.assertEquals(Boolean.TRUE, + parser.parse(Boolean.class, line, " ")); + } + + @Test + public void testParseShort() throws Exception { + DefaultParser parser = new DefaultParser(); + Assert.assertSame("10", (short) 10, + parser.parse(short.class, "10", " ")); + Assert.assertSame("010", (short) 8, + parser.parse(short.class, "010", " ")); + Assert.assertSame("0x10", (short) 16, + parser.parse(short.class, "0x10", " ")); + } + + @Test + public void testParseByte() throws Exception { + DefaultParser parser = new DefaultParser(); + Assert.assertSame("11", (byte) 11, + parser.parse(byte.class, "11", " ")); + Assert.assertSame("011", (byte) 9, + parser.parse(byte.class, "011", " ")); + Assert.assertSame("0x11", (byte) 17, + parser.parse(byte.class, "0x11", " ")); + } + + @Test + public void testParseInt() throws Exception { + DefaultParser parser = new DefaultParser(); + Assert.assertEquals("20", (int) 20, + parser.parse(int.class, "20", " ")); + Assert.assertEquals("020", (int) 16, + parser.parse(int.class, "020", " ")); + Assert.assertEquals("0x20", (int) 32, + parser.parse(int.class, "0x20", " ")); + } + + +} diff --git a/test/failure_handler/test/unit/jdk/test/failurehandler/value/ValueHandlerTest.java b/test/failure_handler/test/unit/jdk/test/failurehandler/value/ValueHandlerTest.java new file mode 100644 --- /dev/null +++ b/test/failure_handler/test/unit/jdk/test/failurehandler/value/ValueHandlerTest.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2015, 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. + */ + +package jdk.test.failurehandler.value; + +import org.junit.Assert; +import org.junit.Test; + +import java.lang.reflect.Field; +import java.util.Properties; + +public class ValueHandlerTest { + @Test + public void testApplyAnonymousPrivateFinalInt() throws Exception { + Properties p = new Properties(); + p.put("int", "010"); + Object o = new Object() { + @Value (name = "int") + private final int i1 = -1; + }; + Field f = o.getClass().getDeclaredField("i1"); + f.setAccessible(true); + int value = f.getInt(o); + Assert.assertEquals(value, -1); + f.setAccessible(false); + ValueHandler.apply(o, p, null); + f.setAccessible(true); + value = f.getInt(o); + Assert.assertEquals(value, 8); + f.setAccessible(false); + } + + @Test + public void testApplyPublicStaticWithDefault() throws Exception { + Assert.assertEquals(StaticDefaultCase.s, null); + Properties p = new Properties(); + StaticDefaultCase o = new StaticDefaultCase(); + ValueHandler.apply(o, p, "prefix"); + Assert.assertEquals(StaticDefaultCase.s, "default"); + p.put("s", "new2"); + ValueHandler.apply(o, p, "prefix"); + Assert.assertEquals(StaticDefaultCase.s, "new2"); + p.put("prefix.s", "new"); + ValueHandler.apply(o, p, "prefix"); + Assert.assertEquals(StaticDefaultCase.s, "new"); + ValueHandler.apply(o, p, null); + Assert.assertEquals(StaticDefaultCase.s, "new2"); + } + + protected class InnerClass1 { + @Value (name = "innerClass") + String[] arr = null; + } + + public class InnerClass2 extends InnerClass1 { + @Value (name = "float") + float f = 0.0f; + + @SubValues (prefix = "inner") + InnerClass1 inner1 = new InnerClass1(); + + @SubValues (prefix = "") + InnerClass1 inner2 = new InnerClass1(); + } + + @Test + public void testApplySub() throws Exception { + InnerClass2 o = new InnerClass2(); + Assert.assertArrayEquals(o.arr, null); + Assert.assertArrayEquals(o.inner1.arr, null); + Assert.assertArrayEquals(o.inner2.arr, null); + Assert.assertEquals(o.f, 0.0f, Float.MIN_VALUE); + + Properties p = new Properties(); + p.put("float", "1.f"); + p.put("innerClass", "a b"); + p.put("inner.innerClass", "a b c"); + ValueHandler.apply(o, p, ""); + Assert.assertArrayEquals(o.arr, new String[]{"a", "b"}); + Assert.assertArrayEquals(o.inner1.arr, new String[]{"a", "b", "c"}); + Assert.assertArrayEquals(o.inner2.arr, new String[]{"a", "b"}); + Assert.assertEquals(o.f, 1.0f, Float.MIN_VALUE); + } +} + +class StaticDefaultCase { + @Value (name = "s") + @DefaultValue (value = "default") + public static String s; +}