1 /*
   2  * Copyright (c) 2003, 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 /* @test
  25  * @bug 4287596
  26  * @summary Unit test for "Pluggable Connectors and Transports" feature.
  27  *
  28  * This test checks that VirtualMachineManager creates Connectors that
  29  * are "compatible" those created by 1.4 or earilier releases.
  30  */
  31 
  32 import com.sun.jdi.*;
  33 import com.sun.jdi.connect.*;
  34 import java.util.*;
  35 
  36 public class CompatibleConnectors {
  37 
  38     // number of tests that fail
  39     static int failures;
  40 
  41     static void fail(String msg) {
  42         System.out.println(msg + " - test failed.");
  43         failures++;
  44     }
  45 
  46     // the AttachingConnectors that we expect
  47     static Object[][] attachingConnectors() {
  48         return new Object[][] {
  49             { "com.sun.jdi.SocketAttach",
  50               "dt_socket",
  51               new String[] { "hostname", "Connector.StringArgument", "false" },
  52               new String[] { "port",     "Connector.IntegerArgument", "true" }
  53             },
  54 
  55             { "com.sun.jdi.SharedMemoryAttach",
  56               "dt_shmem",
  57               new String[] { "name", "Connector.StringArgument", "true" }
  58             }
  59         };
  60     }
  61 
  62     // the ListeningConnectors that we expect
  63     static Object[][] listeningConnectors() {
  64         return new Object[][] {
  65             { "com.sun.jdi.SocketListen",
  66               "dt_socket",
  67               new String[] { "port", "Connector.IntegerArgument", "true" }
  68             },
  69 
  70             { "com.sun.jdi.SharedMemoryListen",
  71               "dt_shmem",
  72               new String[] { "name", "Connector.StringArgument", "false" }
  73             }
  74         };
  75 
  76     }
  77 
  78     // the LaunchingConnectors that we expect
  79     // - note that we don't indicate the transport name (as it varies
  80     // for these connectors)
  81     static Object[][] launchingConnectors() {
  82         return new Object[][] {
  83             { "com.sun.jdi.CommandLineLaunch",
  84               null,
  85               new String[] { "home",    "Connector.StringArgument",     "false" },
  86               new String[] { "options", "Connector.StringArgument",     "false" },
  87               new String[] { "main",    "Connector.StringArgument",     "true"  },
  88               new String[] { "suspend", "Connector.BooleanArgument",    "false" },
  89               new String[] { "quote",   "Connector.StringArgument",     "true"  },
  90               new String[] { "vmexec",  "Connector.StringArgument",     "true" }
  91             },
  92 
  93             { "com.sun.jdi.RawCommandLineLaunch",
  94               null,
  95               new String[] { "command",  "Connector.StringArgument",     "true" },
  96               new String[] { "address",  "Connector.StringArgument",     "true" },
  97               new String[] { "quote",    "Connector.StringArgument",     "true" }
  98             }
  99         };
 100 
 101     }
 102 
 103     // find Connector by name, return null if not found
 104     static Connector find(String name, List l) {
 105         Iterator i = l.iterator();
 106         while (i.hasNext()) {
 107             Connector c = (Connector)i.next();
 108             if (c.name().equals(name)) {
 109                 return c;
 110             }
 111         }
 112         return null;
 113     }
 114 
 115     // check that a connector is of the expected type
 116     static void type_match(String arg_name, String arg_type, Connector.Argument arg) {
 117         boolean fail = false;
 118         if (arg_type.equals("Connector.StringArgument")) {
 119             if (!(arg instanceof Connector.StringArgument)) {
 120                 fail = true;
 121             }
 122         }
 123         if (arg_type.equals("Connector.IntegerArgument")) {
 124             if (!(arg instanceof Connector.IntegerArgument)) {
 125                 fail = true;
 126             }
 127         }
 128         if (arg_type.equals("Connector.BooleanArgument")) {
 129             if (!(arg instanceof Connector.BooleanArgument)) {
 130                 fail = true;
 131             }
 132         }
 133         if (arg_type.equals("Connector.SelectedArgument")) {
 134             if (!(arg instanceof Connector.IntegerArgument)) {
 135                 fail = true;
 136             }
 137         }
 138         if (fail) {
 139             fail(arg_name + " is of type: " + arg.getClass() + ", expected: "
 140                  + arg_type);
 141         }
 142     }
 143 
 144 
 145     // check that a Connector is compatible
 146     static void check(Object[] desc, Connector connector) {
 147         String name = (String)desc[0];
 148         String transport_name = (String)desc[1];
 149 
 150         // if the transport name is "null" it means its transport may
 151         // vary (eg: SunCommandLineLauncher will choose shared memory
 152         // on Windows and dt_socket on Solaris). In that case we can't
 153         // check the transport name.
 154         //
 155         if (transport_name != null) {
 156             System.out.println("Checking transpot name");
 157             if (!(transport_name.equals(connector.transport().name()))) {
 158                 fail("transport().name() returns: " +
 159                     connector.transport().name() + ", expected: " + transport_name);
 160             }
 161         }
 162 
 163         // check that all the old arguments still exist
 164         for (int i=2; i<desc.length; i++) {
 165             String[] args = (String[])desc[i];
 166             String arg_name = args[0];
 167             String arg_type = args[1];
 168             String arg_mandatory = args[2];
 169 
 170             System.out.println("Checking argument: " + arg_name);
 171 
 172             // check that the arg still exists
 173             Map defaultArgs = connector.defaultArguments();
 174             Object value = defaultArgs.get(arg_name);
 175             if (value == null) {
 176                 fail(name + " is missing Connector.Argument: " + arg_name);
 177                 continue;
 178             }
 179 
 180             // next check that the type matches
 181             Connector.Argument connector_arg = (Connector.Argument)value;
 182 
 183             // check that the argument type hasn't changed
 184             type_match(arg_name, arg_type, connector_arg);
 185 
 186             // check that an optional argument has been made mandatory
 187             if (arg_mandatory.equals("false")) {
 188                 if (connector_arg.mustSpecify()) {
 189                     fail(arg_name + " is now mandatory");
 190                 }
 191             }
 192         }
 193 
 194         // next we check for new arguments that are mandatory but
 195         // have no default value
 196 
 197         System.out.println("Checking for new arguments");
 198         Map dfltArgs = connector.defaultArguments();
 199         Iterator iter = dfltArgs.keySet().iterator();
 200         while (iter.hasNext()) {
 201             String arg_name = (String)iter.next();
 202 
 203             // see if the argument is new
 204             boolean found = false;
 205             for (int j=2; j<desc.length; j++) {
 206                 String[] args = (String[])desc[j];
 207                 if (args[0].equals(arg_name)) {
 208                     found = true;
 209                     break;
 210                 }
 211             }
 212 
 213             if (!found) {
 214                 Connector.Argument connector_arg =
 215                     (Connector.Argument)dfltArgs.get(arg_name);
 216 
 217                 if (connector_arg.mustSpecify()) {
 218                     String value = connector_arg.value();
 219                     if (value.equals("")) {
 220                         value = null;
 221                     }
 222                     if (value == null) {
 223                         fail("New Connector.Argument \"" + connector_arg.name() +
 224                             "\" added - argument is mandatory");
 225                     }
 226                 }
 227             }
 228         }
 229     }
 230 
 231 
 232     // compare the actual list of Connectors against the
 233     // expected list of Connectors.
 234     static void compare(Object[][] prev, List list) {
 235         String os = System.getProperty("os.name");
 236         for (int i=0; i<prev.length; i++) {
 237             Object[] desc = prev[i];
 238             String name = (String)desc[0];
 239 
 240             // ignore Windows specific Connectors are non-Windows machines
 241             if (!(os.startsWith("Windows"))) {
 242                 if (name.equals("com.sun.jdi.SharedMemoryAttach") ||
 243                     name.equals("com.sun.jdi.SharedMemoryListen")) {
 244                     continue;
 245                 }
 246             }
 247 
 248             System.out.println("");
 249             System.out.println("Checking Connector " + name);
 250 
 251             // check that the Connector exists
 252             Connector c = find(name, list);
 253             if (c == null) {
 254                 fail("Connector is missing");
 255                 continue;
 256             }
 257 
 258             check(desc, c);
 259         }
 260     }
 261 
 262     public static void main(String args[]) throws Exception {
 263         VirtualMachineManager vmm = Bootstrap.virtualMachineManager();
 264 
 265         // in 1.2/1.3/1.4 the defualtConnector was
 266         // com.sun.jdi.CommandLineLaunch. Many debuggers probably
 267         // depend on this so check that it's always the default.
 268         //
 269         String expected = "com.sun.jdi.CommandLineLaunch";
 270         System.out.println("Checking that defaultConnector is: " + expected);
 271         String dflt = vmm.defaultConnector().name();
 272         if (!(dflt.equals(expected))) {
 273             System.err.println("defaultConnector() is: " + dflt +
 274                 ", expected:" + expected);
 275             failures++;
 276         } else {
 277             System.out.println("Okay");
 278         }
 279 
 280         compare(attachingConnectors(), vmm.attachingConnectors());
 281         compare(listeningConnectors(), vmm.listeningConnectors());
 282         compare(launchingConnectors(), vmm.launchingConnectors());
 283 
 284         // test results
 285         if (failures > 0) {
 286             System.out.println("");
 287             throw new RuntimeException(failures + " test(s) failed");
 288         }
 289     }
 290 }