8221711: [TESTBUG] create more tests for JFR in container environment
Summary: Added test cases for environment and network events
Reviewed-by: egahlin
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/containers/docker/JfrNetwork.java Mon Apr 15 11:44:07 2019 -0700
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2019, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.InputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.nio.file.Paths;
+import java.util.List;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.process.OutputAnalyzer;
+
+
+// This class is intended to run inside a container
+public class JfrNetwork {
+ // use a unique hostname for container
+ public static final String HOST_NAME = "container-unique-8221711";
+ public static final String JFR_REPORTED_CONTAINER_HOSTNAME_TAG = "jfr_reported_container_hostname=";
+
+ public static void main(String[] args) throws Exception {
+ String event = args[0];
+ try (ServerSocket ss = new ServerSocket()) {
+ testNetworkInfo(ss, event);
+ }
+ }
+
+ private static void assertTrue(boolean expr, String msg) {
+ if (!expr) {
+ throw new RuntimeException(msg);
+ }
+ }
+
+ private static void testNetworkInfo(ServerSocket ss, String event) throws Exception {
+ ServerSocketListener server = new ServerSocketListener(ss);
+ server.start();
+ SocketWriter writer = new SocketWriter(ss.getLocalSocketAddress());
+
+ // setup and start the recording
+ String recordingPath = event + ".jfr";
+ log("========= Recording event: " + event);
+ Recording r = new Recording();
+ r.enable(event);
+ r.setDestination(Paths.get("/", "tmp", recordingPath));
+ r.start();
+
+ // start the socker writer thread, write some data into the socket
+ writer.start();
+
+ // wait for writer thread to terminate, then for server thread, then stop recording
+ writer.joinAndThrow();
+ server.joinAndThrow();
+ r.stop();
+
+ // analyze the recording
+ List<RecordedEvent> events = RecordingFile.readAllEvents(r.getDestination());
+ events.forEach(e -> log ("event = " + e));
+ assertTrue(!events.isEmpty(), "No recorded network events");
+ RecordedEvent e = events.get(0);
+ log(JFR_REPORTED_CONTAINER_HOSTNAME_TAG + e.getString("host"));
+ verifyIpAddress(e.getString("address"));
+ }
+
+ private static void verifyIpAddress(String eventIp) throws Exception {
+ ProcessBuilder pb = new ProcessBuilder("hostname", "--ip-address");
+ OutputAnalyzer out = new OutputAnalyzer(pb.start());
+ out.shouldHaveExitValue(0);
+ log("hostname --ip-address returned: " + out.getOutput());
+ out.shouldContain(eventIp);
+ }
+
+ private static void log(String msg) {
+ System.out.println(msg);
+ }
+
+
+ private static class ServerSocketListener extends Thread {
+ Exception exception;
+ ServerSocket ss;
+
+ ServerSocketListener(ServerSocket socket) throws Exception {
+ ss = socket;
+ ss.setReuseAddress(true);
+ ss.bind(null);
+ log("ServerSocker Local Address: " + ss.getLocalSocketAddress());
+ }
+
+ public void joinAndThrow() throws Exception {
+ join();
+ if (exception != null) {
+ throw exception;
+ }
+ }
+
+ public void run() {
+ try {
+ try (Socket s = ss.accept(); InputStream is = s.getInputStream()) {
+ System.out.println("ServerSocketListener: accepted socket connection: s = " + s);
+ is.read();
+ is.read();
+ is.read();
+ }
+ } catch (Exception e) {
+ exception = e;
+ }
+ }
+ }
+
+
+ private static class SocketWriter extends Thread {
+ Exception exception;
+ private SocketAddress ssAddr;
+
+ public SocketWriter(SocketAddress sa) {
+ this.ssAddr = sa;
+ System.out.println("SocketWriter(): sa = " + sa);
+ }
+
+ public void joinAndThrow() throws Exception {
+ join();
+ if (exception != null) {
+ throw exception;
+ }
+ }
+
+ public void run() {
+ try (Socket s = new Socket()) {
+ s.connect(ssAddr);
+ try (OutputStream os = s.getOutputStream()) {
+ os.write('A');
+ os.write('B');
+ os.write('C');
+ }
+ } catch (Exception e) {
+ exception = e;
+ }
+ }
+ }
+
+}
--- a/test/hotspot/jtreg/containers/docker/JfrReporter.java Mon Apr 15 13:07:06 2019 -0400
+++ b/test/hotspot/jtreg/containers/docker/JfrReporter.java Mon Apr 15 11:44:07 2019 -0700
@@ -22,53 +22,30 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
-
+import java.nio.file.Path;
import java.nio.file.Paths;
import jdk.jfr.Recording;
+import jdk.jfr.ValueDescriptor;
import jdk.jfr.consumer.RecordedEvent;
import jdk.jfr.consumer.RecordingFile;
-
// This class is intended to run inside a container
public class JfrReporter {
- public static final String TEST_REPORTED_CORES="TEST_REPORTED_CORES";
- public static final String TEST_REPORTED_MEMORY="TEST_REPORTED_MEMORY";
- public static final String TEST_REPORTED_PID="TEST_REPORTED_PID";
- public static final String TESTCASE_CPU="cpu";
- public static final String TESTCASE_MEMORY="memory";
- public static final String TESTCASE_PROCESS="process";
-
public static void main(String[] args) throws Exception {
- String testCase = args[0];
- System.out.println("Testcase: " + testCase);
- switch (testCase) {
- case TESTCASE_CPU:
- RecordedEvent event = testEvent("jdk.CPUInformation", "cpu.jfr");
- System.out.println(TEST_REPORTED_CORES + "=" + event.getInt("cores"));
- break;
- case TESTCASE_MEMORY:
- event = testEvent("jdk.PhysicalMemory", "memory.jfr");
- System.out.println(TEST_REPORTED_MEMORY + "=" + event.getLong("totalSize"));
- break;
- case TESTCASE_PROCESS:
- event = testEvent("jdk.SystemProcess", "process.jfr");
- System.out.println(TEST_REPORTED_PID + "=" + event.getString("pid"));
- break;
- default:
- throw new IllegalArgumentException("Invalid test case");
+ String eventName = args[0];
+ try(Recording r = new Recording()) {
+ r.enable(eventName);
+ r.start();
+ r.stop();
+ Path p = Paths.get("/", "tmp", eventName + ".jfr");
+ r.dump(p);
+ for (RecordedEvent e : RecordingFile.readAllEvents(p)) {
+ System.out.println("===== EventType: " + e.getEventType().getName());
+ for (ValueDescriptor v : e.getEventType().getFields()) {
+ System.out.println(v.getName() + " = " + e.getValue(v.getName()));
+ }
+ }
}
}
-
- private static RecordedEvent testEvent(String event, String recordingPath) throws Exception {
- System.out.println("========= Testing event: " + event);
- Recording r = new Recording();
- r.enable(event);
- r.setDestination(Paths.get("tmp", recordingPath));
- r.start();
- r.stop();
-
- RecordedEvent recordedEvent = RecordingFile.readAllEvents(r.getDestination()).get(0);
- System.out.println("RecordedEvent: " + recordedEvent);
- return recordedEvent;
- }
}
+
\ No newline at end of file
--- a/test/hotspot/jtreg/containers/docker/TestJFREvents.java Mon Apr 15 13:07:06 2019 -0400
+++ b/test/hotspot/jtreg/containers/docker/TestJFREvents.java Mon Apr 15 11:44:07 2019 -0700
@@ -39,6 +39,8 @@
import jdk.test.lib.containers.docker.Common;
import jdk.test.lib.containers.docker.DockerRunOptions;
import jdk.test.lib.containers.docker.DockerTestUtils;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.Utils;
@@ -68,6 +70,7 @@
testProcessInfo();
+ testEnvironmentVariables();
} finally {
DockerTestUtils.removeDockerImage(imageName);
}
@@ -79,14 +82,12 @@
DockerTestUtils.dockerRunJava(
commonDockerOpts()
.addDockerOpts("--cpus=" + valueToSet)
- .addClassOptions(JfrReporter.TESTCASE_CPU))
- .shouldHaveExitValue(0)
- .shouldContain(JfrReporter.TEST_REPORTED_CORES);
-
+ .addClassOptions("jdk.CPUInformation"))
+ .shouldHaveExitValue(0);
// The following assertion is currently disabled due to JFR reporting incorrect values.
// JFR reports values for the host system as opposed to values for the container.
// @ignore 8219999
- // .shouldContain(JfrReporter.TEST_REPORTED_CORES + "=" + expectedValue);
+ // .shouldContain("cores = " + expectedValue");
}
@@ -95,9 +96,9 @@
DockerTestUtils.dockerRunJava(
commonDockerOpts()
.addDockerOpts("--memory=" + valueToSet)
- .addClassOptions(JfrReporter.TESTCASE_MEMORY))
+ .addClassOptions("jdk.PhysicalMemory"))
.shouldHaveExitValue(0)
- .shouldContain(JfrReporter.TEST_REPORTED_MEMORY + "=" + expectedValue);
+ .shouldContain("totalSize = " + expectedValue);
}
@@ -105,10 +106,9 @@
Common.logNewTestCase("ProcessInfo");
DockerTestUtils.dockerRunJava(
commonDockerOpts()
- .addClassOptions(JfrReporter.TESTCASE_PROCESS))
+ .addClassOptions("jdk.SystemProcess"))
.shouldHaveExitValue(0)
- .shouldContain(JfrReporter.TEST_REPORTED_PID + "=1");
-
+ .shouldContain("pid = 1");
}
@@ -117,4 +117,28 @@
.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/")
.addJavaOpts("-cp", "/test-classes/");
}
+
+
+ // JTReg always defines the environment variable JAVA_MAIN_CLASS_<SOME_NUMBER>.
+ // This variable fits well for use in this test, since it is rather unique.
+ private static String getTestEnvironmentVariable() throws Exception {
+ for (String key : System.getenv().keySet()) {
+ if (key.startsWith("JAVA_MAIN_CLASS")) {
+ return key;
+ }
+ }
+ throw new RuntimeException("JAVA_MAIN_CLASS_* is not defined");
+ }
+
+
+ private static void testEnvironmentVariables() throws Exception {
+ Common.logNewTestCase("EnvironmentVariables");
+
+ DockerTestUtils.dockerRunJava(
+ commonDockerOpts()
+ .addClassOptions("jdk.InitialEnvironmentVariable"))
+ .shouldHaveExitValue(0)
+ .shouldContain("key = JAVA_HOME")
+ .shouldNotContain(getTestEnvironmentVariable());
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java Mon Apr 15 11:44:07 2019 -0700
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2019, 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 Test JFR network related events inside a container; make sure
+ * the reported host ip and host name are correctly reported within
+ * the container.
+ * @requires docker.support
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ * java.management
+ * jdk.jartool/sun.tools.jar
+ * @build JfrNetwork
+ * @run driver TestJFRNetworkEvents
+ */
+import jdk.test.lib.containers.docker.Common;
+import jdk.test.lib.containers.docker.DockerRunOptions;
+import jdk.test.lib.containers.docker.DockerTestUtils;
+import jdk.test.lib.Utils;
+
+
+public class TestJFRNetworkEvents {
+ private static final String imageName = Common.imageName("jfr-network");
+ private static final int availableCPUs = Runtime.getRuntime().availableProcessors();
+
+ public static void main(String[] args) throws Exception {
+ System.out.println("Test Environment: detected availableCPUs = " + availableCPUs);
+ if (!DockerTestUtils.canTestDocker()) {
+ return;
+ }
+
+ DockerTestUtils.buildJdkDockerImage(imageName, "Dockerfile-BasicTest", "jdk-docker");
+
+ try {
+ runTest("jdk.SocketWrite");
+ } finally {
+ DockerTestUtils.removeDockerImage(imageName);
+ }
+ }
+
+ private static void runTest(String event) throws Exception {
+ DockerRunOptions opts = new DockerRunOptions(imageName, "/jdk/bin/java", "JfrNetwork")
+ .addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/")
+ .addJavaOpts("-cp", "/test-classes/")
+ .addDockerOpts("--hostname", JfrNetwork.HOST_NAME)
+ .addClassOptions(event);
+ DockerTestUtils.dockerRunJava(opts)
+ .shouldHaveExitValue(0)
+ .shouldContain(JfrNetwork.JFR_REPORTED_CONTAINER_HOSTNAME_TAG + JfrNetwork.HOST_NAME);
+ }
+}
--- a/test/jtreg-ext/requires/VMProps.java Mon Apr 15 13:07:06 2019 -0400
+++ b/test/jtreg-ext/requires/VMProps.java Mon Apr 15 11:44:07 2019 -0700
@@ -425,7 +425,7 @@
* @return true if docker is supported in a given environment
*/
protected String dockerSupport() {
- boolean isSupported = false;
+ boolean isSupported = true;
if (Platform.isLinux()) {
// currently docker testing is only supported for Linux,
// on certain platforms