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