1 /* 2 * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import java.io.File; 25 import java.io.IOException; 26 import java.net.ServerSocket; 27 import java.net.Socket; 28 import java.util.List; 29 import java.util.Properties; 30 31 import jdk.test.lib.thread.ProcessThread; 32 import jdk.testlibrary.OutputAnalyzer; 33 import jdk.testlibrary.ProcessTools; 34 35 import com.sun.tools.attach.AgentInitializationException; 36 import com.sun.tools.attach.AgentLoadException; 37 import com.sun.tools.attach.VirtualMachine; 38 import com.sun.tools.attach.VirtualMachineDescriptor; 39 40 /* 41 * @test 42 * @bug 6173612 6273707 6277253 6335921 6348630 6342019 6381757 43 * @key intermittent 44 * @summary Basic unit tests for the VM attach mechanism. This test will perform 45 * a number of basic attach tests. 46 * 47 * @library /lib/testlibrary 48 * @library /test/lib 49 * @modules java.instrument 50 * jdk.attach 51 * jdk.jartool/sun.tools.jar 52 * 53 * @run build jdk.testlibrary.* Agent BadAgent RedefineAgent Application RedefineDummy RunnerUtil 54 * @run main BasicTests 55 */ 56 public class BasicTests { 57 58 /* 59 * The actual test is in the nested class TestMain. 60 * The responsibility of this class is to: 61 * 1. Build all needed jars. 62 * 2. Start the Application class in a separate process. 63 * 3. Find the pid and shutdown port of the running Application. 64 * 4. Launches the tests in nested class TestMain that will attach to the Application. 65 * 5. Shut down the Application. 66 */ 67 public static void main(String args[]) throws Throwable { 68 ProcessThread processThread = null; 69 try { 70 buildJars(); 71 processThread = RunnerUtil.startApplication(); 72 runTests(processThread.getPid()); 73 } catch (Throwable t) { 74 System.out.println("TestBasic got unexpected exception: " + t); 75 t.printStackTrace(); 76 throw t; 77 } finally { 78 // Make sure the Application process is stopped. 79 RunnerUtil.stopApplication(processThread); 80 } 81 } 82 83 /** 84 * Runs the actual tests in nested class TestMain. 85 * The reason for running the tests in a separate process 86 * is that we need to modify the class path. 87 */ 88 private static void runTests(long pid) throws Throwable { 89 final String sep = File.separator; 90 91 // Need to add jdk/lib/tools.jar to classpath. 92 String classpath = 93 System.getProperty("test.class.path", ""); 94 String testClassDir = System.getProperty("test.classes", "") + sep; 95 96 // Argumenta : -classpath cp BasicTests$TestMain pid agent badagent redefineagent 97 String[] args = { 98 "-classpath", 99 classpath, 100 "BasicTests$TestMain", 101 Long.toString(pid), 102 testClassDir + "Agent.jar", 103 testClassDir + "BadAgent.jar", 104 testClassDir + "RedefineAgent.jar" }; 105 OutputAnalyzer output = ProcessTools.executeTestJvm(args); 106 output.shouldHaveExitValue(0); 107 } 108 109 /** 110 * Will build all jars needed by the tests. 111 */ 112 private static void buildJars() throws Throwable { 113 String[] jars = {"Agent", "BadAgent", "RedefineAgent", "Application" }; 114 for (String jar : jars) { 115 buildJar(jar); 116 } 117 } 118 119 /** 120 * Will build a jar with the given name. 121 * Class file and manifest must already exist. 122 * @param jarName Name of the jar. 123 */ 124 private static void buildJar(String jarName) throws Throwable { 125 String testClasses = System.getProperty("test.classes", "?"); 126 String testSrc = System.getProperty("test.src", "?"); 127 String jar = String.format("%s/%s.jar", testClasses, jarName); 128 String manifest = String.format("%s/%s.mf", testSrc, jarName.toLowerCase()); 129 String clazz = String.format("%s.class", jarName); 130 131 // Arguments to the jar command has this format: 132 // "-cfm TESTCLASSES/Agent.jar TESTSRC/agent.mf -C TESTCLASSES Agent.class" 133 RunnerUtil.createJar("-cfm", jar, manifest, "-C", testClasses, clazz); 134 } 135 136 /** 137 * This is the actual test. It will attach to the running Application 138 * and perform a number of basic attach tests. 139 */ 140 public static class TestMain { 141 public static void main(String args[]) throws Exception { 142 String pid = args[0]; 143 String agent = args[1]; 144 String badagent = args[2]; 145 String redefineagent = args[3]; 146 147 System.out.println(" - Attaching to application ..."); 148 VirtualMachine vm = VirtualMachine.attach(pid); 149 150 // Test 1 - read the system properties from the target VM and 151 // check that property is set 152 System.out.println(" - Test: system properties in target VM"); 153 Properties props = vm.getSystemProperties(); 154 String value = props.getProperty("attach.test"); 155 if (value == null || !value.equals("true")) { 156 throw new RuntimeException("attach.test property not set"); 157 } 158 System.out.println(" - attach.test property set as expected"); 159 160 // Test 1a - read the agent properties from the target VM. 161 // By default, the agent property contains "sun.java.command", 162 // "sun.jvm.flags", and "sun.jvm.args". 163 // Just sanity check - make sure not empty. 164 System.out.println(" - Test: agent properties in target VM"); 165 props = vm.getAgentProperties(); 166 if (props == null || props.size() == 0) { 167 throw new RuntimeException("Agent properties is empty"); 168 } 169 System.out.println(" - agent properties non-empty as expected"); 170 171 // Test 2 - attempt to load an agent that does not exist 172 System.out.println(" - Test: Load an agent that does not exist"); 173 try { 174 vm.loadAgent("SilverBullet.jar"); 175 } catch (AgentLoadException x) { 176 System.out.println(" - AgentLoadException thrown as expected!"); 177 } 178 179 // Test 3 - load an "bad" agent (agentmain throws an exception) 180 System.out.println(" - Test: Load a bad agent"); 181 System.out.println("INFO: This test will cause error messages " 182 + "to appear in the application log about SilverBullet.jar " 183 + "not being found and an agent failing to start."); 184 try { 185 vm.loadAgent(badagent); 186 throw new RuntimeException( 187 "AgentInitializationException not thrown as expected!"); 188 } catch (AgentInitializationException x) { 189 System.out.println( 190 " - AgentInitializationException thrown as expected!"); 191 } 192 193 // Test 4 - detach from the VM and attempt a load (should throw IOE) 194 System.out.println(" - Test: Detach from VM"); 195 System.out.println("INFO: This test will cause error messages " 196 + "to appear in the application log about a BadAgent including " 197 + "a RuntimeException and an InvocationTargetException."); 198 vm.detach(); 199 try { 200 vm.loadAgent(agent); 201 throw new RuntimeException("loadAgent did not throw an exception!!"); 202 } catch (IOException ioe) { 203 System.out.println(" - IOException as expected"); 204 } 205 206 // Test 5 - functional "end-to-end" test. 207 // Create a listener socket. Load Agent.jar into the target VM passing 208 // it the port number of our listener. When agent loads it should connect 209 // back to the tool. 210 211 System.out.println(" - Re-attaching to application ..."); 212 vm = VirtualMachine.attach(pid); 213 214 System.out.println(" - Test: End-to-end connection with agent"); 215 216 ServerSocket ss = new ServerSocket(0); 217 int port = ss.getLocalPort(); 218 219 System.out.println(" - Loading Agent.jar into target VM ..."); 220 vm.loadAgent(agent, Integer.toString(port)); 221 222 System.out.println(" - Waiting for agent to connect back to tool ..."); 223 Socket s = ss.accept(); 224 System.out.println(" - Connected to agent."); 225 226 // Test 5b - functional "end-to-end" test. 227 // Now with an agent that does redefine. 228 229 System.out.println(" - Re-attaching to application ..."); 230 vm = VirtualMachine.attach(pid); 231 232 System.out.println(" - Test: End-to-end connection with RedefineAgent"); 233 234 ServerSocket ss2 = new ServerSocket(0); 235 int port2 = ss2.getLocalPort(); 236 237 System.out.println(" - Loading RedefineAgent.jar into target VM ..."); 238 vm.loadAgent(redefineagent, Integer.toString(port2)); 239 240 System.out.println(" - Waiting for RedefineAgent to connect back to tool ..."); 241 Socket s2 = ss2.accept(); 242 System.out.println(" - Connected to RedefineAgent."); 243 244 // Test 6 - list method should list the target VM 245 System.out.println(" - Test: VirtualMachine.list"); 246 List<VirtualMachineDescriptor> l = VirtualMachine.list(); 247 boolean found = false; 248 for (VirtualMachineDescriptor vmd: l) { 249 if (vmd.id().equals(pid)) { 250 found = true; 251 break; 252 } 253 } 254 if (found) { 255 System.out.println(" - " + pid + " found."); 256 } else { 257 throw new RuntimeException(pid + " not found in VM list"); 258 } 259 260 // test 7 - basic hashCode/equals tests 261 System.out.println(" - Test: hashCode/equals"); 262 263 VirtualMachine vm1 = VirtualMachine.attach(pid); 264 VirtualMachine vm2 = VirtualMachine.attach(pid); 265 if (!vm1.equals(vm2)) { 266 throw new RuntimeException("virtual machines are not equal"); 267 } 268 if (vm.hashCode() != vm.hashCode()) { 269 throw new RuntimeException("virtual machine hashCodes not equal"); 270 } 271 System.out.println(" - hashCode/equals okay"); 272 273 // --- 274 System.out.println(" - Cleaning up..."); 275 s.close(); 276 ss.close(); 277 s2.close(); 278 ss2.close(); 279 } 280 } 281 }