1 /* 2 * Copyright (c) 2005, 2015, 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.testlibrary.OutputAnalyzer; 32 import jdk.testlibrary.ProcessThread; 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 * @summary Basic unit tests for the VM attach mechanism. 44 * @key intermittent 45 * @library /lib/testlibrary 46 * @modules java.instrument 47 * java.management 48 * jdk.jartool/sun.tools.jar 49 * @run build jdk.testlibrary.* Agent BadAgent RedefineAgent Application RedefineDummy RunnerUtil 50 * @run main BasicTests 51 * 52 * This test will perform a number of basic attach tests. 53 */ 54 public class BasicTests { 55 56 /* 57 * The actual test is in the nested class TestMain. 58 * The responsibility of this class is to: 59 * 1. Build all needed jars. 60 * 2. Start the Application class in a separate process. 61 * 3. Find the pid and shutdown port of the running Application. 62 * 4. Launches the tests in nested class TestMain that will attach to the Application. 63 * 5. Shut down the Application. 64 */ 65 public static void main(String args[]) throws Throwable { 66 ProcessThread processThread = null; 67 try { 68 buildJars(); 69 processThread = RunnerUtil.startApplication(); 70 runTests(processThread.getPid()); 71 } catch (Throwable t) { 72 System.out.println("TestBasic got unexpected exception: " + t); 73 t.printStackTrace(); 74 throw t; 75 } finally { 76 // Make sure the Application process is stopped. 77 RunnerUtil.stopApplication(processThread); 78 } 79 } 80 81 /** 82 * Runs the actual tests in nested class TestMain. 83 * The reason for running the tests in a separate process 84 * is that we need to modify the class path. 85 */ 86 private static void runTests(long pid) throws Throwable { 87 final String sep = File.separator; 88 89 // Need to add jdk/lib/tools.jar to classpath. 90 String classpath = 91 System.getProperty("test.class.path", ""); 92 String testClassDir = System.getProperty("test.classes", "") + sep; 93 94 // Argumenta : -classpath cp BasicTests$TestMain pid agent badagent redefineagent 95 String[] args = { 96 "-classpath", 97 classpath, 98 "BasicTests$TestMain", 99 Long.toString(pid), 100 testClassDir + "Agent.jar", 101 testClassDir + "BadAgent.jar", 102 testClassDir + "RedefineAgent.jar" }; 103 OutputAnalyzer output = ProcessTools.executeTestJvm(args); 104 output.shouldHaveExitValue(0); 105 } 106 107 /** 108 * Will build all jars needed by the tests. 109 */ 110 private static void buildJars() throws Throwable { 111 String[] jars = {"Agent", "BadAgent", "RedefineAgent", "Application" }; 112 for (String jar : jars) { 113 buildJar(jar); 114 } 115 } 116 117 /** 118 * Will build a jar with the given name. 119 * Class file and manifest must already exist. 120 * @param jarName Name of the jar. 121 */ 122 private static void buildJar(String jarName) throws Throwable { 123 String testClasses = System.getProperty("test.classes", "?"); 124 String testSrc = System.getProperty("test.src", "?"); 125 String jar = String.format("%s/%s.jar", testClasses, jarName); 126 String manifest = String.format("%s/%s.mf", testSrc, jarName.toLowerCase()); 127 String clazz = String.format("%s.class", jarName); 128 129 // Arguments to the jar command has this format: 130 // "-cfm TESTCLASSES/Agent.jar TESTSRC/agent.mf -C TESTCLASSES Agent.class" 131 RunnerUtil.createJar("-cfm", jar, manifest, "-C", testClasses, clazz); 132 } 133 134 /** 135 * This is the actual test. It will attach to the running Application 136 * and perform a number of basic attach tests. 137 */ 138 public static class TestMain { 139 public static void main(String args[]) throws Exception { 140 String pid = args[0]; 141 String agent = args[1]; 142 String badagent = args[2]; 143 String redefineagent = args[3]; 144 145 System.out.println(" - Attaching to application ..."); 146 VirtualMachine vm = VirtualMachine.attach(pid); 147 148 // Test 1 - read the system properties from the target VM and 149 // check that property is set 150 System.out.println(" - Test: system properties in target VM"); 151 Properties props = vm.getSystemProperties(); 152 String value = props.getProperty("attach.test"); 153 if (value == null || !value.equals("true")) { 154 throw new RuntimeException("attach.test property not set"); 155 } 156 System.out.println(" - attach.test property set as expected"); 157 158 // Test 1a - read the agent properties from the target VM. 159 // By default, the agent property contains "sun.java.command", 160 // "sun.jvm.flags", and "sun.jvm.args". 161 // Just sanity check - make sure not empty. 162 System.out.println(" - Test: agent properties in target VM"); 163 props = vm.getAgentProperties(); 164 if (props == null || props.size() == 0) { 165 throw new RuntimeException("Agent properties is empty"); 166 } 167 System.out.println(" - agent properties non-empty as expected"); 168 169 // Test 2 - attempt to load an agent that does not exist 170 System.out.println(" - Test: Load an agent that does not exist"); 171 try { 172 vm.loadAgent("SilverBullet.jar"); 173 } catch (AgentLoadException x) { 174 System.out.println(" - AgentLoadException thrown as expected!"); 175 } 176 177 // Test 3 - load an "bad" agent (agentmain throws an exception) 178 System.out.println(" - Test: Load a bad agent"); 179 System.out.println("INFO: This test will cause error messages " 180 + "to appear in the application log about SilverBullet.jar " 181 + "not being found and an agent failing to start."); 182 try { 183 vm.loadAgent(badagent); 184 throw new RuntimeException( 185 "AgentInitializationException not thrown as expected!"); 186 } catch (AgentInitializationException x) { 187 System.out.println( 188 " - AgentInitializationException thrown as expected!"); 189 } 190 191 // Test 4 - detach from the VM and attempt a load (should throw IOE) 192 System.out.println(" - Test: Detach from VM"); 193 System.out.println("INFO: This test will cause error messages " 194 + "to appear in the application log about a BadAgent including " 195 + "a RuntimeException and an InvocationTargetException."); 196 vm.detach(); 197 try { 198 vm.loadAgent(agent); 199 throw new RuntimeException("loadAgent did not throw an exception!!"); 200 } catch (IOException ioe) { 201 System.out.println(" - IOException as expected"); 202 } 203 204 // Test 5 - functional "end-to-end" test. 205 // Create a listener socket. Load Agent.jar into the target VM passing 206 // it the port number of our listener. When agent loads it should connect 207 // back to the tool. 208 209 System.out.println(" - Re-attaching to application ..."); 210 vm = VirtualMachine.attach(pid); 211 212 System.out.println(" - Test: End-to-end connection with agent"); 213 214 ServerSocket ss = new ServerSocket(0); 215 int port = ss.getLocalPort(); 216 217 System.out.println(" - Loading Agent.jar into target VM ..."); 218 vm.loadAgent(agent, Integer.toString(port)); 219 220 System.out.println(" - Waiting for agent to connect back to tool ..."); 221 Socket s = ss.accept(); 222 System.out.println(" - Connected to agent."); 223 224 // Test 5b - functional "end-to-end" test. 225 // Now with an agent that does redefine. 226 227 System.out.println(" - Re-attaching to application ..."); 228 vm = VirtualMachine.attach(pid); 229 230 System.out.println(" - Test: End-to-end connection with RedefineAgent"); 231 232 ServerSocket ss2 = new ServerSocket(0); 233 int port2 = ss2.getLocalPort(); 234 235 System.out.println(" - Loading RedefineAgent.jar into target VM ..."); 236 vm.loadAgent(redefineagent, Integer.toString(port2)); 237 238 System.out.println(" - Waiting for RedefineAgent to connect back to tool ..."); 239 Socket s2 = ss2.accept(); 240 System.out.println(" - Connected to RedefineAgent."); 241 242 // Test 6 - list method should list the target VM 243 System.out.println(" - Test: VirtualMachine.list"); 244 List<VirtualMachineDescriptor> l = VirtualMachine.list(); 245 boolean found = false; 246 for (VirtualMachineDescriptor vmd: l) { 247 if (vmd.id().equals(pid)) { 248 found = true; 249 break; 250 } 251 } 252 if (found) { 253 System.out.println(" - " + pid + " found."); 254 } else { 255 throw new RuntimeException(pid + " not found in VM list"); 256 } 257 258 // test 7 - basic hashCode/equals tests 259 System.out.println(" - Test: hashCode/equals"); 260 261 VirtualMachine vm1 = VirtualMachine.attach(pid); 262 VirtualMachine vm2 = VirtualMachine.attach(pid); 263 if (!vm1.equals(vm2)) { 264 throw new RuntimeException("virtual machines are not equal"); 265 } 266 if (vm.hashCode() != vm.hashCode()) { 267 throw new RuntimeException("virtual machine hashCodes not equal"); 268 } 269 System.out.println(" - hashCode/equals okay"); 270 271 // --- 272 System.out.println(" - Cleaning up..."); 273 s.close(); 274 ss.close(); 275 s2.close(); 276 ss2.close(); 277 } 278 } 279 }