8221711: [TESTBUG] create more tests for JFR in container environment
authormseledtsov
Mon, 15 Apr 2019 11:44:07 -0700
changeset 54537 9d3117203dd3
parent 54536 fb53a1c25903
child 54538 ef331769d4ab
8221711: [TESTBUG] create more tests for JFR in container environment Summary: Added test cases for environment and network events Reviewed-by: egahlin
test/hotspot/jtreg/containers/docker/JfrNetwork.java
test/hotspot/jtreg/containers/docker/JfrReporter.java
test/hotspot/jtreg/containers/docker/TestJFREvents.java
test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java
test/jtreg-ext/requires/VMProps.java
--- /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