/* * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /** * @test * @library /lib/testlibrary * @modules jdk.compiler * @build CompilerUtils * @run testng/othervm BadProvidersTest * @summary Basic test of ServiceLoader with bad provider and bad provider * factories deployed on the module path */ import java.lang.module.Configuration; import java.lang.module.ModuleFinder; import java.lang.reflect.Layer; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.List; import java.util.ServiceConfigurationError; import java.util.ServiceLoader; import java.util.ServiceLoader.Provider; import java.util.Set; import java.util.stream.Collectors; import org.testng.annotations.Test; import org.testng.annotations.DataProvider; import static org.testng.Assert.*; /** * Basic test of `provides S with PF` and `provides S with P` where the provider * factory or provider */ public class BadProvidersTest { private static final String TEST_SRC = System.getProperty("test.src"); private static final Path USER_DIR = Paths.get(System.getProperty("user.dir")); private static final Path SRC_DIR = Paths.get(TEST_SRC, "modules"); private static final Path BADFACTORIES_DIR = Paths.get(TEST_SRC, "badfactories"); private static final Path BADPROVIDERS_DIR = Paths.get(TEST_SRC, "badproviders"); private static final String TEST1_MODULE = "test1"; private static final String TEST2_MODULE = "test2"; private static final String TEST_SERVICE = "p.Service"; /** * Compiles a module, returning a module path with the compiled module. */ private Path compileTest(String moduleName) throws Exception { Path dir = Files.createTempDirectory(USER_DIR, "mods"); Path output = Files.createDirectory(dir.resolve(moduleName)); boolean compiled = CompilerUtils.compile(SRC_DIR.resolve(moduleName), output); assertTrue(compiled); return dir; } /** * Resolves a test module and loads it into its own layer. ServiceLoader * is then used to load all providers. */ private List<Provider> loadProviders(Path mp, String moduleName) throws Exception { ModuleFinder finder = ModuleFinder.of(mp); Layer bootLayer = Layer.boot(); Configuration cf = bootLayer.configuration() .resolveRequiresAndUses(finder, ModuleFinder.of(), Set.of(moduleName)); ClassLoader scl = ClassLoader.getSystemClassLoader(); Layer layer = Layer.boot().defineModulesWithOneLoader(cf, scl); Class<?> service = layer.findLoader(moduleName).loadClass(TEST_SERVICE); return ServiceLoader.load(layer, service) .stream() .collect(Collectors.toList()); } @Test public void sanityTest1() throws Exception { Path mods = compileTest(TEST1_MODULE); List<Provider> list = loadProviders(mods, TEST1_MODULE); assertTrue(list.size() == 1); // the provider is a singleton, enforced by the provider factory Object p1 = list.get(0).get(); Object p2 = list.get(0).get(); assertTrue(p1 != null); assertTrue(p1 == p2); } @Test public void sanityTest2() throws Exception { Path mods = compileTest(TEST2_MODULE); List<Provider> list = loadProviders(mods, TEST2_MODULE); assertTrue(list.size() == 1); Object p = list.get(0).get(); assertTrue(p != null); } @DataProvider(name = "badfactories") public Object[][] createBadFactories() { return new Object[][] { { "classnotpublic", null }, { "methodnotpublic", null }, { "badreturntype", null }, { "returnsnull", null }, { "throwsexception", null }, }; } @Test(dataProvider = "badfactories", expectedExceptions = ServiceConfigurationError.class) public void testBadFactory(String testName, String ignore) throws Exception { Path mods = compileTest(TEST1_MODULE); // compile the bad factory Path source = BADFACTORIES_DIR.resolve(testName); Path output = Files.createTempDirectory(USER_DIR, "tmp"); boolean compiled = CompilerUtils.compile(source, output); assertTrue(compiled); // copy the compiled class into the module Path classFile = Paths.get("p", "ProviderFactory.class"); Files.copy(output.resolve(classFile), mods.resolve(TEST1_MODULE).resolve(classFile), StandardCopyOption.REPLACE_EXISTING); // load providers and instantiate each one loadProviders(mods, TEST1_MODULE).forEach(Provider::get); } @DataProvider(name = "badproviders") public Object[][] createBadProviders() { return new Object[][] { { "notpublic", null }, { "ctornotpublic", null }, { "notasubtype", null }, { "throwsexception", null } }; } @Test(dataProvider = "badproviders", expectedExceptions = ServiceConfigurationError.class) public void testBadProvider(String testName, String ignore) throws Exception { Path mods = compileTest(TEST2_MODULE); // compile the bad provider Path source = BADPROVIDERS_DIR.resolve(testName); Path output = Files.createTempDirectory(USER_DIR, "tmp"); boolean compiled = CompilerUtils.compile(source, output); assertTrue(compiled); // copy the compiled class into the module Path classFile = Paths.get("p", "Provider.class"); Files.copy(output.resolve(classFile), mods.resolve(TEST2_MODULE).resolve(classFile), StandardCopyOption.REPLACE_EXISTING); // load providers and instantiate each one loadProviders(mods, TEST2_MODULE).forEach(Provider::get); } }