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