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