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