/* * Copyright (C) 2010 Brockmann Consult GmbH (info@brockmann-consult.de) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 3 of the License, or (at your option) * any later version. * This program 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 for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see http://www.gnu.org/licenses/ */ package com.bc.ceres.core.runtime.internal; import com.bc.ceres.core.CoreException; import com.bc.ceres.core.runtime.*; import junit.framework.TestCase; import java.io.IOException; import java.io.File; import java.net.URL; import java.net.URISyntaxException; public class ModuleResolverTest extends TestCase { private ModuleRegistry moduleRegistry; @Override protected void setUp() throws Exception { moduleRegistry = TestHelpers.createModuleRegistry(new String[]{ "xml/module-a.xml", "xml/module-b.xml", "xml/module-c.xml", "xml/module-d.xml", "xml/module-e.xml", }); } @Override protected void tearDown() throws Exception { moduleRegistry = null; } public void testNullArgConvention() throws IOException, CoreException { try { final ModuleResolver moduleResolver = new ModuleResolver(ModuleResolver.class.getClassLoader(), false); moduleResolver.resolve(null); fail(); } catch (NullPointerException e) { // ok } try { final ModuleResolver moduleResolver = new ModuleResolver(null, false); moduleResolver.resolve(getModule("module-a")); fail(); } catch (NullPointerException e) { // ok } try { final ModuleResolver moduleResolver = new ModuleResolver(ModuleResolver.class.getClassLoader(), false); moduleResolver.resolve(getModule("module-a")); // ok } catch (NullPointerException e) { fail(); } } public void testResolvingAResolvesOnlyA() throws CoreException { final ModuleResolver moduleResolver = new ModuleResolver(ModuleResolver.class.getClassLoader(), false); moduleResolver.resolve(getModule("module-a")); TestHelpers.assertModuleIsResolved(getModule("module-a"), 1, new ModuleImpl[]{}); TestHelpers.assertModuleIsInstalled(getModule("module-b")); TestHelpers.assertModuleIsInstalled(getModule("module-c")); TestHelpers.assertModuleIsInstalled(getModule("module-d")); TestHelpers.assertModuleIsInstalled(getModule("module-e")); assertTrue(getModule("module-a").getClassLoader() instanceof ModuleClassLoader); } public void testResolvingBResolvesBAndA() throws CoreException { final ModuleResolver moduleResolver = new ModuleResolver(ModuleResolver.class.getClassLoader(), false); moduleResolver.resolve(getModule("module-b")); TestHelpers.assertModuleIsResolved(getModule("module-a"), 1, new ModuleImpl[]{}); TestHelpers.assertModuleIsResolved(getModule("module-b"), 1, new ModuleImpl[]{getModule("module-a")}); TestHelpers.assertModuleIsInstalled(getModule("module-c")); TestHelpers.assertModuleIsInstalled(getModule("module-d")); TestHelpers.assertModuleIsInstalled(getModule("module-e")); assertTrue(getModule("module-a").getClassLoader() instanceof ModuleClassLoader); assertTrue(getModule("module-b").getClassLoader() instanceof ModuleClassLoader); } public void testResolvingCResolvesCAndBAndA() throws CoreException { final ModuleResolver moduleResolver = new ModuleResolver(ModuleResolver.class.getClassLoader(), false); moduleResolver.resolve(getModule("module-c")); TestHelpers.assertModuleIsResolved(getModule("module-a"), 1, new ModuleImpl[]{}); TestHelpers.assertModuleIsResolved(getModule("module-b"), 1, new ModuleImpl[]{getModule("module-a")}); TestHelpers.assertModuleIsResolved(getModule("module-c"), 1, new ModuleImpl[]{getModule("module-b")}); TestHelpers.assertModuleIsInstalled(getModule("module-d")); TestHelpers.assertModuleIsInstalled(getModule("module-e")); assertTrue(getModule("module-a").getClassLoader() instanceof ModuleClassLoader); assertTrue(getModule("module-b").getClassLoader() instanceof ModuleClassLoader); assertTrue(getModule("module-c").getClassLoader() instanceof ModuleClassLoader); } public void testResolvingDResolvesDAndA() throws CoreException { final ModuleResolver moduleResolver = new ModuleResolver(ModuleResolver.class.getClassLoader(), false); moduleResolver.resolve(getModule("module-d")); TestHelpers.assertModuleIsResolved(getModule("module-a"), 1, new ModuleImpl[]{}); TestHelpers.assertModuleIsInstalled(getModule("module-b")); TestHelpers.assertModuleIsInstalled(getModule("module-c")); TestHelpers.assertModuleIsResolved(getModule("module-d"), 1, new ModuleImpl[]{getModule("module-a")}); TestHelpers.assertModuleIsInstalled(getModule("module-e")); assertTrue(getModule("module-a").getClassLoader() instanceof ModuleClassLoader); assertTrue(getModule("module-d").getClassLoader() instanceof ModuleClassLoader); } public void testResolvingEResolvesAllExceptC() throws CoreException { final ModuleResolver moduleResolver = new ModuleResolver(ModuleResolver.class.getClassLoader(), false); moduleResolver.resolve(getModule("module-e")); TestHelpers.assertModuleIsResolved(getModule("module-a"), 2, new ModuleImpl[]{}); TestHelpers.assertModuleIsResolved(getModule("module-b"), 1, new ModuleImpl[]{getModule("module-a")}); TestHelpers.assertModuleIsInstalled(getModule("module-c")); TestHelpers.assertModuleIsResolved(getModule("module-d"), 1, new ModuleImpl[]{getModule("module-a")}); TestHelpers.assertModuleIsResolved(getModule("module-e"), 1, new ModuleImpl[]{getModule("module-b"), getModule("module-d")}); assertTrue(getModule("module-a").getClassLoader() instanceof ModuleClassLoader); assertTrue(getModule("module-b").getClassLoader() instanceof ModuleClassLoader); assertTrue(getModule("module-d").getClassLoader() instanceof ModuleClassLoader); assertTrue(getModule("module-e").getClassLoader() instanceof ModuleClassLoader); } public void testResolvingCAndEResolvesAll() throws CoreException { final ModuleResolver moduleResolver1 = new ModuleResolver(ModuleResolver.class.getClassLoader(), false); moduleResolver1.resolve(getModule("module-c")); final ModuleResolver moduleResolver = new ModuleResolver(ModuleResolver.class.getClassLoader(), false); moduleResolver.resolve(getModule("module-e")); TestHelpers.assertModuleIsResolved(getModule("module-a"), 3, new ModuleImpl[]{}); TestHelpers.assertModuleIsResolved(getModule("module-b"), 2, new ModuleImpl[]{getModule("module-a")}); TestHelpers.assertModuleIsResolved(getModule("module-c"), 1, new ModuleImpl[]{getModule("module-b")}); TestHelpers.assertModuleIsResolved(getModule("module-d"), 1, new ModuleImpl[]{getModule("module-a")}); TestHelpers.assertModuleIsResolved(getModule("module-e"), 1, new ModuleImpl[]{getModule("module-b"), getModule("module-d")}); assertTrue(getModule("module-a").getClassLoader() instanceof ModuleClassLoader); assertTrue(getModule("module-b").getClassLoader() instanceof ModuleClassLoader); assertTrue(getModule("module-c").getClassLoader() instanceof ModuleClassLoader); assertTrue(getModule("module-d").getClassLoader() instanceof ModuleClassLoader); assertTrue(getModule("module-e").getClassLoader() instanceof ModuleClassLoader); } public void testModuleClassLoaderE() throws CoreException, URISyntaxException, IOException { final ModuleResolver moduleResolver = new ModuleResolver(ModuleResolver.class.getClassLoader(), false); moduleResolver.resolve(getModule("module-e")); ClassLoader clE = getModule("module-e").getClassLoader(); assertTrue(clE instanceof ModuleClassLoader); ModuleClassLoader mclE = (ModuleClassLoader) clE; URL[] dependencyUrls = mclE.getURLs(); assertTrue(dependencyUrls.length > 0); File location = getCanonicalFile(getModule("module-e").getLocation()); File dependencyUrl = getCanonicalFile(dependencyUrls[0]); assertEquals(dependencyUrl, location); File expectedFile; File actualFile; ModuleClassLoader delegateToB = (ModuleClassLoader) mclE.getDelegates()[0]; expectedFile = getCanonicalFile(delegateToB.getURLs()[0]); actualFile = getCanonicalFile(getModule("module-b").getLocation()); assertEquals(expectedFile, actualFile); ModuleClassLoader delegateToD = (ModuleClassLoader) mclE.getDelegates()[1]; expectedFile = getCanonicalFile(delegateToD.getURLs()[0]); actualFile = getCanonicalFile(getModule("module-d").getLocation()); assertEquals(expectedFile, actualFile); ModuleClassLoader delegateToA = (ModuleClassLoader) delegateToB.getDelegates()[0]; expectedFile = getCanonicalFile(delegateToA.getURLs()[0]); actualFile = getCanonicalFile(getModule("module-a").getLocation()); assertEquals(expectedFile, actualFile); ModuleClassLoader delegateToA2 = (ModuleClassLoader) delegateToD.getDelegates()[0]; expectedFile = getCanonicalFile(delegateToA2.getURLs()[0]); actualFile = getCanonicalFile(getModule("module-a").getLocation()); assertEquals(expectedFile, actualFile); } private static File getCanonicalFile(URL url) throws IOException, URISyntaxException { return new File(url.toURI()).getCanonicalFile(); } public void testExtensionsAndExtensionPoints() throws CoreException, IOException { Module module_a = moduleRegistry.getModule(1); Module module_b = moduleRegistry.getModule(2); Module module_c = moduleRegistry.getModule(3); Module module_d = moduleRegistry.getModule(4); Module module_e = moduleRegistry.getModule(5); final ModuleResolver moduleResolver = new ModuleResolver(ModuleResolver.class.getClassLoader(), false); moduleResolver.resolve((ModuleImpl) module_a); moduleResolver.resolve((ModuleImpl) module_b); moduleResolver.resolve((ModuleImpl) module_c); moduleResolver.resolve((ModuleImpl) module_d); moduleResolver.resolve((ModuleImpl) module_e); assertNotNull(module_a); assertNotNull(module_b); assertNotNull(module_c); assertNotNull(module_d); assertNotNull(module_e); Extension e_31 = module_c.getExtensions()[0]; Extension e_32 = module_c.getExtensions()[1]; Extension e_33 = module_c.getExtensions()[2]; Extension e_34 = module_c.getExtensions()[3]; Extension e_35 = module_c.getExtensions()[4]; Extension e_36 = module_c.getExtensions()[5]; assertEquals(3, module_b.getExtensionPoints().length); ExtensionPoint ep_21 = module_b.getExtensionPoints()[0]; ExtensionPoint ep_22 = module_b.getExtensionPoints()[1]; ExtensionPoint ep_23 = module_b.getExtensionPoints()[2]; assertEquals(2, module_d.getExtensionPoints().length); ExtensionPoint ep_41 = module_d.getExtensionPoints()[0]; ExtensionPoint ep_42 = module_d.getExtensionPoints()[1]; assertSame(ep_21, e_31.getExtensionPoint()); assertSame(ep_21, e_32.getExtensionPoint()); assertSame(ep_22, e_33.getExtensionPoint()); assertSame(ep_23, e_34.getExtensionPoint()); assertSame(ep_23, e_35.getExtensionPoint()); assertSame(ep_23, e_36.getExtensionPoint()); assertSame(ep_23, e_35.getExtensionPoint()); assertSame(ep_23, e_36.getExtensionPoint()); assertSame(ep_21, moduleRegistry.getExtensionPoint("module-b:ep-1")); assertSame(ep_22, moduleRegistry.getExtensionPoint("module-b:ep-2")); assertSame(ep_23, moduleRegistry.getExtensionPoint("module-b:ep-3")); assertEquals(3, ep_21.getExtensions().length); assertEquals(4, ep_22.getExtensions().length); assertEquals(6, ep_23.getExtensions().length); assertEquals(0, ep_41.getExtensions().length); assertEquals(2, ep_42.getExtensions().length); assertEquals(3, moduleRegistry.getExtensions("module-b:ep-1").length); assertEquals(4, moduleRegistry.getExtensions("module-b:ep-2").length); assertEquals(6, moduleRegistry.getExtensions("module-b:ep-3").length); assertEquals(0, moduleRegistry.getExtensions("module-d:ep-1").length); assertEquals(2, moduleRegistry.getExtensions("module-d:ep-2").length); // Test that the two extension points declared in module-b are returned first // and appear in the order they are declared. Extension[] extensions = moduleRegistry.getExtensions("module-b:ep-2"); assertEquals("e-bb21", extensions[0].getId()); assertEquals("e-bb22", extensions[1].getId()); assertSame(e_31, module_c.getExtension("e-cb11")); assertSame(e_32, module_c.getExtension("e-cb12")); assertSame(e_33, module_c.getExtension("e-cb21")); assertSame(e_34, module_c.getExtension("e-cb31")); assertSame(e_35, module_c.getExtension("e-cb32")); assertSame(e_36, module_c.getExtension("e-cb33")); final Extension[] module_5_extensions = module_e.getExtensions(); assertEquals(7, module_5_extensions.length); assertSame(module_b.getExtensionPoint("ep-1"), module_5_extensions[0].getExtensionPoint()); assertSame(module_b.getExtensionPoint("ep-2"), module_5_extensions[1].getExtensionPoint()); assertSame(module_b.getExtensionPoint("ep-3"), module_5_extensions[2].getExtensionPoint()); assertSame(module_b.getExtensionPoint("ep-3"), module_5_extensions[3].getExtensionPoint()); assertSame(module_d.getExtensionPoint("ep-2"), module_5_extensions[4].getExtensionPoint()); assertSame(module_d.getExtensionPoint("ep-2"), module_5_extensions[5].getExtensionPoint()); // Test inherited extension point module-b:ep-3 assertSame(module_b.getExtensionPoint("ep-3"), module_5_extensions[6].getExtensionPoint()); final Extension[] module_2_extensions = moduleRegistry.getExtensions("module-b:ep-3"); assertEquals(6, module_2_extensions.length); assertSame(module_c.getExtension("e-cb31"), module_2_extensions[0]); assertSame(module_c.getExtension("e-cb32"), module_2_extensions[1]); assertSame(module_c.getExtension("e-cb33"), module_2_extensions[2]); assertSame(module_e.getExtension("e-eb31"), module_2_extensions[3]); assertSame(module_e.getExtension("e-eb32"), module_2_extensions[4]); // Test inherited extension point module-b:ep-3 assertSame(module_e.getExtension("e-ed33"), module_2_extensions[5]); } public void testCyclicModuleDependencies() throws CoreException, IOException { ModuleRegistry cyclicModuleRegistry = TestHelpers.createModuleRegistry(new String[]{ "xml/cyclic/module-a.xml", "xml/cyclic/module-b.xml", "xml/cyclic/module-c.xml", "xml/cyclic/module-d.xml", "xml/cyclic/module-e.xml", }); testForExpectedCyclicDependencies(cyclicModuleRegistry.getModules("module-a")[0]); testForExpectedCyclicDependencies(cyclicModuleRegistry.getModules("module-e")[0]); } public void testResolverIgnoresErrorInOptionalDependency() throws IOException, CoreException { ModuleRegistry moduleRegistry = TestHelpers.createModuleRegistry(new String[]{ "xml/dependencies/module-i-optionally-wants-f.xml", "xml/dependencies/module-f-wants-nonexistent-module.xml", }); ModuleImpl moduleI = moduleRegistry.getModules("module-i")[0]; ModuleImpl moduleF = moduleRegistry.getModules("module-f")[0]; assertEquals(ModuleState.INSTALLED, moduleI.getState()); assertEquals(ModuleState.INSTALLED, moduleF.getState()); try { final ModuleResolver moduleResolver = new ModuleResolver(ModuleResolver.class.getClassLoader(), false); moduleResolver.resolve(moduleI); } catch (ResolveException e) { fail("ResolveException not expected, dependency is optional"); } assertEquals(ModuleState.RESOLVED, moduleI.getState()); assertEquals(ModuleState.INSTALLED, moduleF.getState()); } public void testResolverFindsBestMatchingDependencyVersion() throws IOException, CoreException { ModuleRegistry moduleRegistry = TestHelpers.createModuleRegistry(new String[]{ "xml/dependencies/module-a-wants-b-ge-1.0.0.xml", "xml/dependencies/module-b-1.0.2.xml", "xml/dependencies/module-b-1.5-M3.xml", "xml/dependencies/module-b-2.3.5.xml", "xml/dependencies/module-c-wants-b-ge-2.3.xml", "xml/dependencies/module-d-wants-b-eq-1.5-M3.xml", "xml/dependencies/module-e-wants-b-latest.xml", "xml/dependencies/module-f-optionally-wants-nonexistent-module.xml", "xml/dependencies/module-g-wants-b-latest-optional.xml", "xml/dependencies/module-h-wants-b-1.0.2-optional.xml" }); testSingleModuleDependency(moduleRegistry, "module-a", "module-b", "1.0.0", "1.0.2", 1); testSingleModuleDependency(moduleRegistry, "module-c", "module-b", "2.3", "2.3.5", 1); testSingleModuleDependency(moduleRegistry, "module-d", "module-b", "1.5-M3", "1.5-M3", 1); testSingleModuleDependency(moduleRegistry, "module-e", "module-b", null, "2.3.5", 1); testSingleModuleDependency(moduleRegistry, "module-f", "module-_", null, null, 0); testSingleModuleDependency(moduleRegistry, "module-g", "module-b", null, "2.3.5", 1); testSingleModuleDependency(moduleRegistry, "module-h", "module-b", "1.0.2", "1.0.2", 1); } private static void testSingleModuleDependency(ModuleRegistry moduleRegistry, String declaringModuleName, String declaredModuleName, String declaredVersion, String actualVersion, int moduleDependyCount) throws CoreException { ModuleImpl moduleA = moduleRegistry.getModules(declaringModuleName)[0]; final ModuleResolver moduleResolver = new ModuleResolver(ModuleResolver.class.getClassLoader(), false); moduleResolver.resolve(moduleA); assertEquals(declaredModuleName, moduleA.getDeclaredDependencies()[0].getModuleSymbolicName()); assertEquals(declaredVersion, moduleA.getDeclaredDependencies()[0].getVersion()); ModuleImpl[] dependencies = moduleA.getModuleDependencies(); assertEquals(moduleDependyCount, dependencies.length); if (moduleDependyCount == 1) { assertEquals(declaredModuleName, dependencies[0].getSymbolicName()); assertEquals(Version.parseVersion(actualVersion), dependencies[0].getVersion()); } } private static void testForExpectedCyclicDependencies(ModuleImpl module) { try { final ModuleResolver moduleResolver = new ModuleResolver(ModuleResolver.class.getClassLoader(), false); moduleResolver.resolve(module); fail("ResolveException expected because of cyclic dependencies"); } catch (ResolveException e) { } } private ModuleImpl getModule(String symbolicName) { return moduleRegistry.getModules(symbolicName)[0]; } }