test/jdk/jdk/modules/incubator/ServiceBinding.java
changeset 59133 580fb715b29d
equal deleted inserted replaced
59132:189f47d990b5 59133:580fb715b29d
       
     1 /*
       
     2  * Copyright (c) 2019, 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 8233922
       
    27  * @modules java.base/jdk.internal.module
       
    28  * @library /test/lib
       
    29  * @build ServiceBinding TestBootLayer
       
    30  * @run testng ServiceBinding
       
    31  * @summary Test service binding with incubator modules
       
    32  */
       
    33 
       
    34 import java.io.File;
       
    35 import java.io.OutputStream;
       
    36 import java.lang.module.ModuleDescriptor;
       
    37 import java.lang.module.Configuration;
       
    38 import java.lang.module.ModuleFinder;
       
    39 import java.lang.module.ResolvedModule;
       
    40 import java.nio.file.Path;
       
    41 import java.nio.file.Files;
       
    42 import java.util.List;
       
    43 import java.util.Set;
       
    44 import java.util.stream.Collectors;
       
    45 import java.util.stream.Stream;
       
    46 import java.util.stream.Stream;
       
    47 
       
    48 import static java.lang.module.ModuleDescriptor.newModule;
       
    49 
       
    50 import jdk.internal.module.ModuleInfoWriter;
       
    51 import jdk.internal.module.ModuleResolution;
       
    52 
       
    53 import org.testng.annotations.Test;
       
    54 
       
    55 import jdk.test.lib.process.ProcessTools;
       
    56 import jdk.test.lib.process.OutputAnalyzer;
       
    57 
       
    58 @Test
       
    59 public class ServiceBinding {
       
    60     private static final Path HERE = Path.of(".");
       
    61 
       
    62     /**
       
    63      * module m1 uses p.S
       
    64      * (incubating) module m2 requires m1 provides p.S
       
    65      */
       
    66     public void test1() throws Exception {
       
    67         Path mlib = Files.createTempDirectory(HERE, "mlib");
       
    68 
       
    69         var m1 = newModule("m1").exports("p").uses("p.S").build();
       
    70         var m2 = newModule("m2").requires("m1").provides("p.S", List.of("impl.S1")).build();
       
    71 
       
    72         writeModule(mlib, m1);
       
    73         writeIncubatingModule(mlib, m2);
       
    74 
       
    75         // boot layer: root=m1, incubator module m2 should not be resolved
       
    76         testBootLayer(mlib, Set.of("m1"), Set.of("m1"), Set.of("m2"))
       
    77                 .shouldNotMatch("WARNING:.*m2");
       
    78 
       
    79         // custom configuration: root=m1, incubator module m2 should be resolved
       
    80         testCustomConfiguration(mlib, Set.of("m1"), Set.of("m2"));
       
    81     }
       
    82 
       
    83     /**
       
    84      * module m1 uses p.S
       
    85      * (incubating) module m2 requires m1 provides P.S uses q.S
       
    86      * (incubating) module m3 requires m2 provides q.S
       
    87      */
       
    88     public void test2() throws Exception {
       
    89         Path mlib = Files.createTempDirectory("mlib");
       
    90 
       
    91         var m1 = newModule("m1").exports("p").uses("p.S").build();
       
    92         var m2 = newModule("m2")
       
    93                 .requires("m1")
       
    94                 .provides("p.S", List.of("impl.S1"))
       
    95                 .exports("q")
       
    96                 .uses("q.S")
       
    97                 .build();
       
    98         var m3 = newModule("m3").requires("m2").provides("q.S", List.of("impl.S1")).build();
       
    99 
       
   100         writeModule(mlib, m1);
       
   101         writeIncubatingModule(mlib, m2);
       
   102         writeIncubatingModule(mlib, m3);
       
   103 
       
   104         // boot layer: root=m1, incubator modules m2 and m3 should not be resolved
       
   105         testBootLayer(mlib, Set.of("m1"), Set.of("m1"), Set.of("m2", "m3"))
       
   106                 .shouldNotMatch("WARNING:.*m2")
       
   107                 .shouldNotMatch("WARNING:.*m3");
       
   108 
       
   109         // boot layer: root=m2, incubator module m3 should not be resolved
       
   110         testBootLayer(mlib, Set.of("m2"), Set.of("m1", "m2"), Set.of("m3"))
       
   111                 .shouldMatch("WARNING:.*m2")
       
   112                 .shouldNotMatch("WARNING:.*m3");
       
   113 
       
   114         // custom configuration: root=m1, incubator modules m2 and m3 should be resolved
       
   115         testCustomConfiguration(mlib, Set.of("m1"), Set.of("m1", "m2", "m3"));
       
   116 
       
   117         // custom configuration: root=m2, incubator module m3 should be resolved
       
   118         testCustomConfiguration(mlib, Set.of("m2"), Set.of("m1", "m2", "m3"));
       
   119     }
       
   120 
       
   121     /**
       
   122      * Creates an exploded module on the file system.
       
   123      *
       
   124      * @param mlib the top-level module directory
       
   125      * @param descriptor the module descriptor of the module to write
       
   126      */
       
   127     void writeModule(Path mlib, ModuleDescriptor descriptor) throws Exception {
       
   128         writeModule(mlib, descriptor, false);
       
   129     }
       
   130 
       
   131     /**
       
   132      * Creates an exploded module on the file system. The module will be an
       
   133      * incubating module.
       
   134      *
       
   135      * @param mlib the top-level module directory
       
   136      * @param descriptor the module descriptor of the module to write
       
   137      */
       
   138     void writeIncubatingModule(Path mlib, ModuleDescriptor descriptor) throws Exception {
       
   139         writeModule(mlib, descriptor, true);
       
   140     }
       
   141 
       
   142     /**
       
   143      * Creates an exploded module on the file system.
       
   144      *
       
   145      * @param mlib the top-level module directory
       
   146      * @param descriptor the module descriptor of the module to write
       
   147      * @param incubating to create an incubating module
       
   148      */
       
   149     void writeModule(Path mlib, ModuleDescriptor descriptor, boolean incubating)
       
   150         throws Exception
       
   151     {
       
   152         // create ModuleResolution attribute if incubating module
       
   153         ModuleResolution mres = (incubating) ? ModuleResolution.empty().withIncubating() : null;
       
   154         String name = descriptor.name();
       
   155 
       
   156         // create directory for module
       
   157         Path dir = Files.createDirectory(mlib.resolve(name));
       
   158 
       
   159         // module-info.class
       
   160         try (OutputStream out = Files.newOutputStream(dir.resolve("module-info.class"))) {
       
   161             ModuleInfoWriter.write(descriptor, mres, out);
       
   162         }
       
   163 
       
   164         // create a dummy class file for each package
       
   165         for (String pn : descriptor.packages()) {
       
   166             Path subdir = dir.resolve(pn.replace('.', File.separatorChar));
       
   167             Files.createDirectories(subdir);
       
   168             Files.createFile(subdir.resolve("C.class"));
       
   169         }
       
   170     }
       
   171 
       
   172     /**
       
   173      * Run TestBootLayer in a child VM with the given module path and the
       
   174      * --add-modules option with additional root modules. TestBootLayer checks
       
   175      * the modules in the boot layer.
       
   176      *
       
   177      * @param mlib the module path
       
   178      * @param roots the modules to specify to --add-modules
       
   179      * @param expected the names of modules that should be in the boot layer
       
   180      * @param notExpected the names of modules that should not be in boot layer
       
   181      */
       
   182     OutputAnalyzer testBootLayer(Path mlib,
       
   183                                  Set<String> roots,
       
   184                                  Set<String> expected,
       
   185                                  Set<String> notExpected)
       
   186         throws Exception
       
   187     {
       
   188         var opts = Stream.of("-p", mlib.toString(),
       
   189                              "--add-modules", commaSeparated(roots),
       
   190                              "TestBootLayer", commaSeparated(expected), commaSeparated(notExpected));
       
   191         return ProcessTools.executeTestJava(opts.toArray(String[]::new))
       
   192                 .outputTo(System.out)
       
   193                 .errorTo(System.out)
       
   194                 .shouldHaveExitValue(0);
       
   195     }
       
   196 
       
   197     /**
       
   198      * Creates a Configuration by resolving a set of root modules, with service
       
   199      * binding, then checks that the Configuration includes the expected modules.
       
   200      *
       
   201      * @param mlib the module path
       
   202      * @param roots the names of the root modules
       
   203      * @param expected the names of modules that should be in the configuration
       
   204      */
       
   205     void testCustomConfiguration(Path mlib, Set<String> roots, Set<String> expected) {
       
   206         ModuleFinder finder = ModuleFinder.of(mlib);
       
   207         Configuration cf = ModuleLayer.boot()
       
   208                 .configuration()
       
   209                 .resolveAndBind(finder, ModuleFinder.of(), roots);
       
   210 
       
   211         Set<String> modules = cf.modules().stream()
       
   212                 .map(ResolvedModule::name)
       
   213                 .collect(Collectors.toSet());
       
   214 
       
   215         expected.stream()
       
   216                 .filter(mn -> !modules.contains(mn))
       
   217                 .findAny()
       
   218                 .ifPresent(mn -> {
       
   219                     throw new RuntimeException(mn + " not in configuration!!!");
       
   220                 });
       
   221     }
       
   222 
       
   223     String commaSeparated(Set<String> s) {
       
   224         return s.stream().collect(Collectors.joining(","));
       
   225     }
       
   226 }