1 /*
   2  * Copyright (c) 2016, 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 /**
  25  *  @test
  26  *  @bug 8049365
  27  *  @summary Tests the JDI and JDWP update for modules
  28  *
  29  *  @modules jdk.jdi
  30  *  @run build TestScaffold VMConnection TargetListener TargetAdapter
  31  *  @run compile -g ModulesTest.java
  32  *  @run driver ModulesTest
  33  */
  34 import com.sun.jdi.*;
  35 import com.sun.jdi.event.*;
  36 import com.sun.jdi.request.*;
  37 
  38 import java.util.*;
  39 
  40     /********** target program **********/
  41 
  42 class ModulesTarg {
  43 
  44     public static void main(String[] args){
  45         System.out.println("Goodbye from ModulesTarg!");
  46     }
  47 }
  48 
  49     /********** test program **********/
  50 
  51 public class ModulesTest extends TestScaffold {
  52     static final String FailPrefix = "ModulesTest: failed: ";
  53 
  54     private static ModuleReference bootUnnamedModule = null;
  55     private static ModuleReference appUnnamedModule  = null;
  56     private static ModuleReference extUnnamedModule  = null;
  57 
  58     private ReferenceType targetClass;
  59     private List<ModuleReference> modules;
  60 
  61 
  62     ModulesTest (String args[]) {
  63         super(args);
  64     }
  65 
  66     public static void main(String[] args) throws Exception {
  67         new ModulesTest(args).startTests();
  68     }
  69 
  70     /********** test core **********/
  71 
  72     private boolean reftypeSanityCheck(ModuleReference module, ReferenceType type) {
  73         ModuleReference other = type.module();
  74         if (other == null) {
  75             testFailed = true;
  76             println(FailPrefix + "a ModuleReference should never be null #1");
  77             return false;
  78         }
  79         // Sanity checks: make sure there is no crash or exception
  80         String otherName = other.name();
  81         return true;
  82     }
  83 
  84     private void checkLoaderDefinedClasses(ModuleReference module, ClassLoaderReference loader) {
  85         String moduleName = module.name();
  86         List<ReferenceType> definedClasses = loader.definedClasses();
  87         boolean origModuleWasObserved = false;
  88 
  89         for (ReferenceType type: definedClasses) {
  90             ClassLoaderReference otherLoader = type.classLoader();
  91             if (!loader.equals(otherLoader)) {
  92                 testFailed = true;
  93                 println(FailPrefix + "all classes defined by a ClassLoader" +
  94                         " should refer to the defining ClassLoader");
  95                 return;
  96             }
  97             if (!reftypeSanityCheck(module, type)) {
  98                 return;
  99             }
 100         }
 101     }
 102 
 103     private void checkLoaderVisibleClasses(ModuleReference module, ClassLoaderReference loader) {
 104         String moduleName = module.name();
 105         List<ReferenceType> visibleClasses = loader.visibleClasses();
 106 
 107         for (ReferenceType type: visibleClasses) {
 108             if (!type.isPrepared()) {
 109                 continue; // Safety: skip unprepared classes
 110             }
 111             if (!reftypeSanityCheck(module, type)) {
 112                 return;
 113             }
 114         }
 115     }
 116 
 117     // Check any ClassLoader except the bootsrtap ClassLoader
 118     private void checkClassLoader(ModuleReference module, ClassLoaderReference loader) {
 119         checkLoaderDefinedClasses(module, loader);
 120         checkLoaderVisibleClasses(module, loader);
 121     }
 122 
 123     // Sanity checks to make sure there are no crashes or exceptions.
 124     private void checkModule(ModuleReference module, ModuleReference other, int checkIdx) {
 125         if (module == null) {
 126             testFailed = true;
 127             println(FailPrefix + "a ModuleReference should never be null #2");
 128             return;
 129         }
 130         String name = module.name();
 131         println("\n--- Check #" + checkIdx);
 132         println("    module name: " + name);
 133 
 134         ClassLoaderReference loader = module.classLoader();
 135         println("    loader: " + loader);
 136 
 137         if (loader != null) {
 138             checkClassLoader(module, loader);
 139             String classloaderName = loader.toString();
 140             if (classloaderName.contains("AppClassLoader") && name == null) {
 141                 if (appUnnamedModule != null) {
 142                     testFailed = true;
 143                     println(FailPrefix + "multiple unnamed modules in AppClassLoader");
 144                 }
 145                 appUnnamedModule = module;
 146             }
 147             if (classloaderName.contains("PlatformClassLoader") && name == null) {
 148                 if (extUnnamedModule != null) {
 149                     testFailed = true;
 150                     println(FailPrefix + "multiple unnamed modules in PlatformClassLoader");
 151                 }
 152                 extUnnamedModule = module;
 153             }
 154         } else if (name == null) {
 155             if (bootUnnamedModule != null) {
 156                 testFailed = true;
 157                 println(FailPrefix + "multiple unnamed modules in BootClassLoader");
 158             }
 159             bootUnnamedModule = module;
 160         }
 161     }
 162 
 163     // Check that the java.lang.String class was loaded by the java.base module.
 164     private void checkBaseModule() {
 165         List<ReferenceType> clist = vm().classesByName("java.lang.String");
 166         if (clist.size() != 1) {
 167             testFailed = true;
 168             println(FailPrefix + "just one java.lang.String class is expected" +
 169                     "but found multiple class instances: " + clist.size());
 170             return;
 171         }
 172         ModuleReference module = clist.get(0).module();
 173         if (module == null) {
 174             testFailed = true;
 175             println(FailPrefix + "a ModuleReference should never be null #3");
 176         }
 177         if (module.name().compareTo("java.base") != 0) {
 178             testFailed = true;
 179             println(FailPrefix + "java.lang.String must belong to java.base module");
 180         }
 181     }
 182 
 183     // Check that the unnamed modules of the bootsrtap, application
 184     // and platform class loaders were observed.
 185     private void checkUnnamedModules() {
 186         if (bootUnnamedModule == null) {
 187             testFailed = true;
 188             println(FailPrefix + "unnamed module of BootClassLoader was not observed");
 189         }
 190         if (appUnnamedModule == null) {
 191             testFailed = true;
 192             println(FailPrefix + "unnamed module of AppClassLoader was not observed");
 193         }
 194         if (extUnnamedModule == null) {
 195             testFailed = true;
 196             println(FailPrefix + "unnamed module of PlatformClassLoader was not observed");
 197         }
 198     }
 199 
 200     protected void runTests() throws Exception {
 201         /*
 202          * Get to the top of main() to determine targetClass
 203          */
 204         BreakpointEvent bpe = startToMain("ModulesTarg");
 205         targetClass = bpe.location().declaringType();
 206 
 207         if (!vm().canGetModuleInfo()) {
 208             testFailed = true;
 209             println(FailPrefix + "vm().canGetModuleInfo() returned false");
 210         }
 211         ModuleReference other = targetClass.module();
 212         modules = vm().allModules();
 213 
 214         int checkIdx = 0;
 215 
 216         for (ModuleReference module : modules) {
 217             checkModule(module, other, checkIdx++);
 218             other = module;
 219         }
 220 
 221         checkBaseModule();
 222         checkUnnamedModules();
 223 
 224         /*
 225          * resume the target until end
 226          */
 227         listenUntilVMDisconnect();
 228 
 229         /*
 230          * deal with results of test
 231          * if anything has called failure("foo") testFailed will be true
 232          */
 233         if (!testFailed) {
 234             println("ModulesTest: passed");
 235         } else {
 236             throw new Exception("ModulesTest: some checks failed");
 237         }
 238     }
 239 }