| /******************************************************************************* |
| * Copyright (c) 2008, 2010 VMware Inc. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * VMware Inc. - initial contribution |
| *******************************************************************************/ |
| |
| package org.eclipse.virgo.kernel.deployer.test; |
| |
| import java.io.File; |
| import java.io.FileWriter; |
| import java.io.IOException; |
| import java.io.Writer; |
| import java.util.*; |
| |
| import org.eclipse.virgo.nano.deployer.api.core.DeploymentException; |
| import org.eclipse.virgo.nano.deployer.api.core.DeploymentIdentity; |
| import org.eclipse.virgo.kernel.model.Artifact; |
| import org.eclipse.virgo.kernel.model.ArtifactState; |
| import org.eclipse.virgo.kernel.model.RuntimeArtifactRepository; |
| import org.eclipse.equinox.region.Region; |
| import org.junit.*; |
| import org.osgi.framework.*; |
| import org.osgi.framework.wiring.BundleWire; |
| import org.osgi.framework.wiring.BundleWiring; |
| |
| import static org.junit.Assert.*; |
| import static org.osgi.framework.namespace.PackageNamespace.PACKAGE_NAMESPACE; |
| |
| |
| /** |
| * These tests cover parent and child plans in all combinations of scoped/unscoped and atomic/non-atomic. |
| * <p/> |
| * A bundle "global" exports the package "global". A bundle "parent" in the parent plans exports the package "parent" |
| * imports the bundle "global" with application import scope. A bundle "child" in the child plans exports the package |
| * "child". |
| * <p/> |
| * An inner class called {@link Model} encapsulates how the various combinations should work in terms of scoping and |
| * atomicity. |
| * <p/> |
| * When scoping occurs, the tests check the synthetic context bundle and the promotion of the "global" package when |
| * appropriate. The lifecycle dependence or independence is checked between the bundles "parent" and "child" and between |
| * the parent and child plans. |
| * |
| */ |
| @Ignore("TODO - investigate why 12 out of 16 tests currently fail") |
| public class NestedPlanIntegrationTests extends AbstractDeployerIntegrationTest { |
| |
| private static final String GLOBAL_PACKAGE = "global"; |
| |
| private static final String PARENT_PACKAGE_NAME = "parent"; |
| |
| private static final String CHILD_PACKAGE_NAME = "child"; |
| |
| private static final String SCOPE_SEPARATOR = "-"; |
| |
| private static final String SYNTHETIC_CONTEXT_BSN_SUFFIX = "-synthetic.context"; |
| |
| private static final String PLAN_TYPE = "plan"; |
| |
| private static final String BUNDLE_TYPE = "bundle"; |
| |
| private static final int WATCH_INTERVAL_MS = 1000; |
| |
| /* |
| * An artifact must be present in a watched repository directory for up to two watch intervals before it will be |
| * processed. Then it will take a while (a surprisingly long while on some operating systems) to be scheduled and |
| * complete processing. |
| */ |
| private static final int WATCH_WAIT_INTERVAL_MS = 2 * WATCH_INTERVAL_MS + 1000; |
| |
| private static final String TEST_RESOURCES_DIRECTORY = "src/test/resources/plan-deployment/"; |
| |
| private static final String GENERATED_PLAN_DIRECTORY = "target/watched/"; |
| |
| private static final String PLAN_EXTENSION = ".plan"; |
| |
| private static final String XML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; |
| |
| private static final String NAMESPACES = " xmlns=\"http://www.eclipse.org/virgo/schema/plan\" \n xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n xsi:schemaLocation=\" http://www.eclipse.org/virgo/schema/plan http://www.eclipse.org/virgo/schema/plan/eclipse-virgo-plan.xsd\""; |
| |
| private static final Version DEFAULT_VERSION = new Version("0"); |
| |
| private static TestArtifactInfo GLOBAL_BUNDLE_INFO = new TestArtifactInfo("bundle", GLOBAL_PACKAGE, DEFAULT_VERSION); |
| |
| private static TestArtifactInfo PARENT_BUNDLE_INFO = new TestArtifactInfo("bundle", PARENT_PACKAGE_NAME, DEFAULT_VERSION); |
| |
| private static TestArtifactInfo CHILD_BUNDLE_INFO = new TestArtifactInfo("bundle", CHILD_PACKAGE_NAME, DEFAULT_VERSION); |
| |
| static { |
| GLOBAL_BUNDLE_INFO.setFile(new File(TEST_RESOURCES_DIRECTORY + "global.jar")); |
| } |
| |
| private RuntimeArtifactRepository ram = null; |
| |
| private Region globalRegion; |
| |
| private static TestPlanArtifactInfo[] PARENTS; |
| |
| private DeploymentIdentity globalBundleDeploymentIdentity; |
| |
| @BeforeClass |
| public static void setUpClass() throws Exception { |
| File generatedPlanDirectory = new File(GENERATED_PLAN_DIRECTORY); |
| generatedPlanDirectory.mkdirs(); |
| |
| generatePlans(); |
| } |
| |
| @Before |
| public void setUp() throws Exception { |
| ServiceReference<RuntimeArtifactRepository> runtimeArtifactRepositoryServiceReference = context.getServiceReference(RuntimeArtifactRepository.class); |
| if (runtimeArtifactRepositoryServiceReference != null) { |
| this.ram = context.getService(runtimeArtifactRepositoryServiceReference); |
| } |
| |
| if(this.ram == null){ |
| throw new RuntimeException("Unable to locate the RuntimeArtifactRepository. Found " + runtimeArtifactRepositoryServiceReference); |
| } |
| |
| Collection<ServiceReference<Region>> regionServiceReferences = context.getServiceReferences(Region.class, "(org.eclipse.virgo.kernel.region.name=global)"); |
| if (regionServiceReferences != null && regionServiceReferences.size() == 1) { |
| this.globalRegion = context.getService(regionServiceReferences.iterator().next()); |
| } |
| |
| globalBundleDeploymentIdentity = deploy(GLOBAL_BUNDLE_INFO); |
| } |
| |
| @After |
| public void tearDown() throws Exception { |
| if (this.globalBundleDeploymentIdentity != null) { |
| this.deployer.undeploy(this.globalBundleDeploymentIdentity); |
| this.globalBundleDeploymentIdentity = null; |
| } |
| } |
| |
| @Test |
| public void testUnscopedNonatomicParentOfUnscopedNonatomicChild() { |
| testParent("unscoped.nonatomic.parentOf.unscoped.nonatomic.child"); |
| } |
| |
| @Test |
| public void testUnscopedAtomicParentOfUnscopedNonatomicChild() { |
| testParent("unscoped.atomic.parentOf.unscoped.nonatomic.child"); |
| } |
| |
| @Test |
| public void testScopedNonatomicParentOfUnscopedNonatomicChild() { |
| testParent("scoped.nonatomic.parentOf.unscoped.nonatomic.child"); |
| } |
| |
| @Test |
| public void testScopedAtomicParentOfUnscopedNonatomicChild() { |
| testParent("scoped.atomic.parentOf.unscoped.nonatomic.child"); |
| } |
| |
| @Test |
| public void testUnscopedNonatomicParentOfUnscopedAtomicChild() { |
| testParent("unscoped.nonatomic.parentOf.unscoped.atomic.child"); |
| } |
| |
| @Test |
| public void testUnscopedAtomicParentOfUnscopedAtomicChild() { |
| testParent("unscoped.atomic.parentOf.unscoped.atomic.child"); |
| } |
| |
| @Test |
| public void testScopedNonatomicParentOfUnscopedAtomicChild() { |
| testParent("scoped.nonatomic.parentOf.unscoped.atomic.child"); |
| } |
| |
| @Test |
| public void testScopedAtomicParentOfUnscopedAtomicChild() { |
| testParent("scoped.atomic.parentOf.unscoped.atomic.child"); |
| } |
| |
| @Test |
| public void testUnscopedNonatomicParentOfScopedNonatomicChild() { |
| testParent("unscoped.nonatomic.parentOf.scoped.nonatomic.child"); |
| } |
| |
| @Test |
| public void testUnscopedAtomicParentOfScopedNonatomicChild() { |
| testParent("unscoped.atomic.parentOf.scoped.nonatomic.child"); |
| } |
| |
| @Test |
| public void testScopedNonatomicParentOfScopedNonatomiChild() { |
| testParent("scoped.nonatomic.parentOf.scoped.nonatomic.child"); |
| } |
| |
| @Test |
| public void testScopedAtomicParentOfScopedNonatomicChild() { |
| testParent("scoped.atomic.parentOf.scoped.nonatomic.child"); |
| } |
| |
| @Test |
| public void testUnscopedNonatomicParentOfScopedAtomicChild() { |
| testParent("unscoped.nonatomic.parentOf.scoped.atomic.child"); |
| } |
| |
| @Test |
| public void testUnscopedAtomicParentOfScopedAtomicChild() { |
| testParent("unscoped.atomic.parentOf.scoped.atomic.child"); |
| } |
| |
| @Test |
| public void testScopedNonatomicParentOfScopedAtomicChild() { |
| testParent("scoped.nonatomic.parentOf.scoped.atomic.child"); |
| } |
| |
| @Test |
| public void testScopedAtomicParentOfScopedAtomicChild() { |
| testParent("scoped.atomic.parentOf.scoped.atomic.child"); |
| } |
| |
| private void testParent(String parentName) { |
| for (TestPlanArtifactInfo parent : PARENTS) { |
| if (parentName.equals(parent.getName())) { |
| testParent(parent); |
| } |
| } |
| } |
| |
| private void testParent(TestPlanArtifactInfo parent) { |
| Model model = new Model(parent); |
| |
| boolean expectDeployOk = model.shouldDeployOk(); |
| |
| try { |
| DeploymentIdentity parentId = deploy(parent); |
| |
| // Fail the test if the plan should not have deployed ok. |
| assertTrue(expectDeployOk); |
| |
| checkScoping(parent, model); |
| |
| checkAtomicity(parent, model); |
| |
| this.deployer.undeploy(parentId); |
| } catch (DeploymentException e) { |
| // Fail the test if the plan should have deployed ok. |
| assertFalse("The plan '" + parent.getName() + "' failed to deploy '" + e.getMessage() + "'", expectDeployOk); |
| } |
| } |
| |
| private static void generatePlans() throws IOException, InterruptedException { |
| // Generate the child plans |
| TestPlanArtifactInfo[] children = generateChildPlans(); |
| |
| // Wait for watched directory interval to pass. |
| Thread.sleep(WATCH_WAIT_INTERVAL_MS); |
| |
| PARENTS = generateParentPlans(children); |
| } |
| |
| private void checkScoping(TestPlanArtifactInfo parent, Model model) { |
| |
| if (model.shouldHaveScope()) { |
| checkSyntheticContextBundle(model); |
| checkImportPromotion(model); |
| checkPlanScoping(parent, model); |
| } else { |
| checkNoSyntheticContextBundle(); |
| checkNoImportPromotion(model); |
| } |
| } |
| |
| private void checkPlanScoping(TestPlanArtifactInfo parent, Model model) { |
| if (parent.isScoped()) { |
| Artifact parentPlan = getPlan(parent); |
| Set<Artifact> children = parentPlan.getDependents(); |
| for (Artifact child : children) { |
| if (PLAN_TYPE.equals(child.getType())) { |
| String childPlanName = child.getName(); |
| String unscopedChildPlanName = parent.getChildPlan().getName(); |
| String expectedChildPlanName = model.getScopeName() + SCOPE_SEPARATOR + unscopedChildPlanName; |
| assertEquals(expectedChildPlanName, childPlanName); |
| } |
| } |
| } |
| |
| } |
| |
| private void checkSyntheticContextBundle(Model model) { |
| Bundle syntheticContextBundle = getSyntheticContextBundle(model.getScopeName()); |
| assertNotNull(syntheticContextBundle); |
| |
| if (model.syntheticContextShouldIncludeParent()) { |
| assertTrue(contains(getBundlesImportingPackage(PARENT_PACKAGE_NAME), syntheticContextBundle)); |
| } |
| |
| if (model.syntheticContextShouldIncludeChild()) { |
| assertTrue(contains(getBundlesImportingPackage(CHILD_PACKAGE_NAME), syntheticContextBundle)); |
| } |
| } |
| |
| private static boolean contains(Bundle[] importingBundles, Bundle syntheticContextBundle) { |
| if (importingBundles != null) { |
| for (Bundle bundle : importingBundles) { |
| if (bundle == syntheticContextBundle) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| private Bundle[] getBundlesImportingPackage(String pkg) { |
| BundleWiring bundleWiring = this.context.getBundle().adapt(BundleWiring.class); |
| List<BundleWire> providedWires = bundleWiring.getProvidedWires(PACKAGE_NAMESPACE); |
| // The tests should not export a package from multiple bundles at any point in time. |
| assertEquals("The Package '" + pkg + "' is exported from " + providedWires.size() + " bundles.", 1, providedWires.size()); |
| |
| return new Bundle[] { providedWires.get(0).getRequirer().getBundle() }; |
| } |
| |
| private void checkNoSyntheticContextBundle() { |
| Bundle[] bundles = this.framework.getBundleContext().getBundles(); |
| for (Bundle bundle : bundles) { |
| assertFalse(bundle.getSymbolicName().endsWith(SYNTHETIC_CONTEXT_BSN_SUFFIX)); |
| } |
| } |
| |
| private Bundle getSyntheticContextBundle(String scopeName) { |
| String bsn = scopeName + SYNTHETIC_CONTEXT_BSN_SUFFIX; |
| Bundle[] bundles = getBundles(bsn); |
| assertTrue(bundles.length <= 1); |
| return bundles.length == 0 ? null : bundles[0]; |
| } |
| |
| private Bundle[] getBundles(String bsn) { |
| return Arrays.stream(this.context.getBundles()).filter(bundle -> bundle.getSymbolicName().equals(bsn)).toArray(Bundle[]::new); |
| } |
| |
| private void checkImportPromotion(Model model) { |
| if (model.importShouldBePromoted()) { |
| assertTrue(globalImportHasBeenPromoted(model)); |
| } |
| } |
| |
| private void checkNoImportPromotion(Model model) { |
| assertFalse(globalImportHasBeenPromoted(model)); |
| } |
| |
| private boolean globalImportHasBeenPromoted(Model model) { |
| // The global import has been promoted if and only if the child bundle imports it. |
| Bundle childBundle = model.getChildBundle(); |
| Bundle[] bundlesImportingGlobalPackage = getBundlesImportingPackage(GLOBAL_PACKAGE); |
| return contains(bundlesImportingGlobalPackage, childBundle); |
| } |
| |
| private void checkAtomicity(TestPlanArtifactInfo parent, Model model) { |
| TestPlanArtifactInfo childPlan = parent.getChildPlan(); |
| |
| Artifact parentArtifact = getPlan(parent); |
| Artifact childArtifact; |
| |
| if (parent.isScoped()) { |
| childArtifact = getPlan(childPlan.getType(), model.getScopeName() + SCOPE_SEPARATOR + childPlan.getName(), childPlan.getVersion(), globalRegion); |
| } else { |
| childArtifact = getPlan(childPlan); |
| } |
| |
| if (parent.isAtomic() && childPlan.isAtomic()) { |
| checkParentAndChildBundleLifecyclesAreTied(model.getParentBundle(), model.getChildBundle(), parentArtifact, childArtifact); |
| } else { |
| checkParentAndChildBundleLifecyclesAreIndependent(parent.isAtomic(), model.getParentBundle(), model.getChildBundle(), parentArtifact, childArtifact); |
| } |
| |
| if (parent.isAtomic()) { |
| checkParentAndChildPlanLifecyclesAreTied(parentArtifact, childArtifact); |
| } else { |
| checkParentAndChildPlanLifecyclesAreIndependent(parentArtifact, childArtifact); |
| } |
| } |
| |
| private Artifact getPlan(TestPlanArtifactInfo plan) { |
| return getPlan(plan.getType(), plan.getName(), plan.getVersion(), globalRegion); |
| } |
| |
| private Artifact getPlan(String type, String name, Version version, Region region) { |
| Artifact planArtifact = this.ram.getArtifact(type, name, version, region); |
| assertNotNull(planArtifact); |
| return planArtifact; |
| } |
| |
| private void checkParentAndChildPlanLifecyclesAreTied(Artifact parentPlan, Artifact childPlan) { |
| waitUntilActive(parentPlan); |
| waitUntilActive(childPlan); |
| |
| parentPlan.stop(); |
| assertEquals(ArtifactState.RESOLVED, parentPlan.getState()); |
| assertEquals(ArtifactState.RESOLVED, childPlan.getState()); |
| |
| parentPlan.start(); |
| waitUntilActive(parentPlan); |
| waitUntilActive(childPlan); |
| |
| childPlan.stop(); |
| assertEquals(ArtifactState.RESOLVED, parentPlan.getState()); |
| assertEquals(ArtifactState.RESOLVED, childPlan.getState()); |
| |
| childPlan.start(); |
| waitUntilActive(parentPlan); |
| waitUntilActive(childPlan); |
| } |
| |
| private void checkParentAndChildPlanLifecyclesAreIndependent(Artifact parentPlan, Artifact childPlan) { |
| waitUntilActive(parentPlan); |
| waitUntilActive(childPlan); |
| |
| parentPlan.stop(); |
| assertEquals(ArtifactState.RESOLVED, parentPlan.getState()); |
| // Stopping the parent plan stops the child plan regardless of the parent's atomicity. |
| assertEquals(ArtifactState.RESOLVED, childPlan.getState()); |
| |
| parentPlan.start(); |
| waitUntilActive(parentPlan); |
| // Starting the parent plan stops the child plan regardless of the parent's atomicity. |
| waitUntilActive(childPlan); |
| |
| childPlan.stop(); |
| assertEquals(ArtifactState.ACTIVE, parentPlan.getState()); |
| assertEquals(ArtifactState.RESOLVED, childPlan.getState()); |
| |
| childPlan.start(); |
| waitUntilActive(parentPlan); |
| waitUntilActive(childPlan); |
| } |
| |
| private void waitUntilActive(Artifact parentPlan) { |
| int i = 0; |
| while (parentPlan.getState() != ArtifactState.ACTIVE) { |
| if (i++ > 10) { |
| // Took too long - give up. |
| fail(); |
| } |
| try { |
| Thread.sleep(100); |
| } catch (InterruptedException ignored) { |
| } |
| } |
| } |
| |
| private void checkParentAndChildBundleLifecyclesAreTied(Bundle parentBundle, Bundle childBundle, Artifact parentPlan, Artifact childPlan) { |
| assertEquals(Bundle.ACTIVE, parentBundle.getState()); |
| assertEquals(Bundle.ACTIVE, childBundle.getState()); |
| waitUntilActive(parentPlan); |
| waitUntilActive(childPlan); |
| try { |
| parentBundle.stop(); |
| assertEquals(Bundle.RESOLVED, parentBundle.getState()); |
| assertEquals(Bundle.RESOLVED, childBundle.getState()); |
| |
| parentBundle.start(); |
| assertEquals(Bundle.ACTIVE, parentBundle.getState()); |
| assertEquals(Bundle.ACTIVE, childBundle.getState()); |
| waitUntilActive(parentPlan); |
| waitUntilActive(childPlan); |
| |
| childBundle.stop(); |
| assertEquals(Bundle.RESOLVED, parentBundle.getState()); |
| assertEquals(Bundle.RESOLVED, childBundle.getState()); |
| |
| childBundle.start(); |
| assertEquals(Bundle.ACTIVE, parentBundle.getState()); |
| assertEquals(Bundle.ACTIVE, childBundle.getState()); |
| waitUntilActive(parentPlan); |
| waitUntilActive(childPlan); |
| } catch (BundleException e) { |
| e.printStackTrace(); |
| fail(); |
| } |
| } |
| |
| private void checkParentAndChildBundleLifecyclesAreIndependent(boolean atomicParentPlan, Bundle parentBundle, Bundle childBundle, |
| Artifact parentPlan, Artifact childPlan) { |
| assertEquals(Bundle.ACTIVE, parentBundle.getState()); |
| assertEquals(Bundle.ACTIVE, childBundle.getState()); |
| waitUntilActive(parentPlan); |
| waitUntilActive(childPlan); |
| try { |
| parentBundle.stop(); |
| assertEquals(Bundle.RESOLVED, parentBundle.getState()); |
| // Stopping the parent bundle stops parent plan if the parent is atomic which stops the child plan, and its |
| // bundles. |
| assertEquals(atomicParentPlan ? Bundle.RESOLVED : Bundle.ACTIVE, childBundle.getState()); |
| |
| parentBundle.start(); |
| assertEquals(Bundle.ACTIVE, parentBundle.getState()); |
| assertEquals(Bundle.ACTIVE, childBundle.getState()); |
| waitUntilActive(parentPlan); |
| waitUntilActive(childPlan); |
| |
| childBundle.stop(); |
| assertEquals(Bundle.ACTIVE, parentBundle.getState()); |
| assertEquals(Bundle.RESOLVED, childBundle.getState()); |
| |
| childBundle.start(); |
| assertEquals(Bundle.ACTIVE, parentBundle.getState()); |
| assertEquals(Bundle.ACTIVE, childBundle.getState()); |
| waitUntilActive(parentPlan); |
| waitUntilActive(childPlan); |
| } catch (BundleException e) { |
| e.printStackTrace(); |
| fail(); |
| } |
| } |
| |
| private Bundle getSpecificBundle(String bsn, Version version) { |
| Bundle[] bundles = Arrays.stream(getBundles(bsn)) |
| .filter(bundle -> new VersionRange("[" + version.toString() + ", " + version.toString() + "]").includes(bundle.getVersion())) |
| .toArray(Bundle[]::new); |
| assertNotNull(bundles); |
| assertEquals(1, bundles.length); |
| return bundles[0]; |
| } |
| |
| /** |
| * The Model class encapsulates the expected behaviour of this testcase. |
| */ |
| private final class Model { |
| |
| private final TestPlanArtifactInfo parent; |
| |
| private final TestPlanArtifactInfo child; |
| |
| Model(TestPlanArtifactInfo parent) { |
| this.parent = parent; |
| |
| TestPlanArtifactInfo[] childPlans = parent.getChildPlans(); |
| assertEquals(1, childPlans.length); |
| this.child = childPlans[0]; |
| } |
| |
| boolean importShouldBePromoted() { |
| return this.parent.isScoped(); |
| } |
| |
| boolean shouldDeployOk() { |
| // A parent and child should deploy ok if and only if they are not both scoped. |
| return !(this.parent.isScoped() && this.child.isScoped()); |
| } |
| |
| boolean shouldHaveScope() { |
| return shouldChildBeScoped(); |
| } |
| |
| String getScopeName() { |
| assertTrue(shouldHaveScope()); |
| return getScopeName(this.parent.isScoped() ? this.parent : this.child); |
| } |
| |
| private String getScopeName(TestPlanArtifactInfo scopedPlan) { |
| assertTrue(scopedPlan.isScoped()); |
| return (scopedPlan.getName() + SCOPE_SEPARATOR + versionToShortString(scopedPlan.getVersion())); |
| } |
| |
| private String versionToShortString(Version version) { |
| String result = version.toString(); |
| while (result.endsWith(".0")) { |
| result = result.substring(0, result.length() - 2); |
| } |
| return result; |
| } |
| |
| boolean syntheticContextShouldIncludeParent() { |
| return this.parent.isScoped(); |
| } |
| |
| boolean syntheticContextShouldIncludeChild() { |
| return shouldChildBeScoped(); |
| } |
| |
| private boolean shouldChildBeScoped() { |
| return this.parent.isScoped() || this.child.isScoped(); |
| } |
| |
| Bundle getParentBundle() { |
| return getBundle(this.parent, this.parent.isScoped() ? getScopeName() : null); |
| } |
| |
| Bundle getChildBundle() { |
| return getBundle(this.child, shouldChildBeScoped() ? getScopeName() : null); |
| } |
| |
| private Bundle getBundle(TestPlanArtifactInfo planContainingBundle, String scopeName) { |
| TestArtifactInfo[] childBundles = planContainingBundle.getChildBundles(); |
| assertEquals(1, childBundles.length); |
| TestArtifactInfo childBundle = childBundles[0]; |
| |
| String bsn = childBundle.getName(); |
| Version version = childBundle.getVersion(); |
| |
| if (scopeName != null) { |
| return getSpecificBundle(scopeName + SCOPE_SEPARATOR + bsn, version); |
| } else { |
| return getSpecificBundle(bsn, version); |
| } |
| } |
| |
| } |
| |
| private static TestPlanArtifactInfo[] generateParentPlans(TestArtifactInfo[] children) throws IOException { |
| TestPlanArtifactInfo[] parents = new TestPlanArtifactInfo[16]; |
| int p = 0; |
| for (TestArtifactInfo aChildren : children) { |
| for (int s = 0; s < 2; s++) { |
| boolean scopedParent = s == 1; |
| for (int a = 0; a < 2; a++) { |
| boolean atomicParent = a == 1; |
| String parentName = parentPlanName(scopedParent, atomicParent, aChildren); |
| parents[p++] = createPlanFile(parentName, DEFAULT_VERSION, scopedParent, atomicParent, PARENT_BUNDLE_INFO, aChildren); |
| } |
| } |
| } |
| return parents; |
| } |
| |
| private static TestPlanArtifactInfo[] generateChildPlans() throws IOException { |
| TestPlanArtifactInfo[] children = new TestPlanArtifactInfo[4]; |
| int c = 0; |
| for (int s = 0; s < 2; s++) { |
| boolean scopedChild = s == 1; |
| for (int a = 0; a < 2; a++) { |
| boolean atomicChild = a == 1; |
| String childName = childPlanName(scopedChild, atomicChild); |
| children[c++] = createPlanFile(childName, DEFAULT_VERSION, scopedChild, atomicChild, CHILD_BUNDLE_INFO); |
| } |
| } |
| return children; |
| } |
| |
| private static String childPlanName(boolean scopedChild, boolean atomicChild) { |
| return scopingAtomicityName(scopedChild, atomicChild) + ".child"; |
| } |
| |
| private static String parentPlanName(boolean scopedParent, boolean atomicParent, TestArtifactInfo childPlan) { |
| return scopingAtomicityName(scopedParent, atomicParent) + ".parentOf." + childPlan.getName(); |
| } |
| |
| private static String scopingAtomicityName(boolean scoped, boolean atomic) { |
| return (scoped ? "scoped" : "unscoped") + "." + (atomic ? "atomic" : "nonatomic"); |
| } |
| |
| private DeploymentIdentity deploy(TestArtifactInfo artifact) throws DeploymentException { |
| DeploymentIdentity identity = this.deployer.deploy(artifact.getFile().toURI()); |
| Assert.assertEquals(artifact.getType(), identity.getType()); |
| Assert.assertEquals(artifact.getName(), identity.getSymbolicName()); |
| Assert.assertEquals(artifact.getVersion(), new Version(identity.getVersion())); |
| return identity; |
| } |
| |
| private static TestPlanArtifactInfo createPlanFile(String planName, Version planVersion, boolean scoped, boolean atomic, TestArtifactInfo... children) throws IOException { |
| StringBuilder planContent = new StringBuilder(1024); |
| planContent.append(XML_HEADER); |
| planContent.append("<plan name=\"").append(planName).append("\" version=\"").append(planVersion).append("\" scoped=\"").append(Boolean.valueOf(scoped)).append("\" atomic=\"").append(Boolean.valueOf(atomic)).append("\" \n").append(NAMESPACES).append(">\n"); |
| |
| for (TestArtifactInfo childInfo : children) { |
| Version childVersion = childInfo.getVersion(); |
| planContent.append(" <artifact type=\"").append(childInfo.getType()).append("\" name=\"").append(childInfo.getName()).append("\" version=\"[").append(childVersion).append(", ").append(childVersion).append("]\"/>\n"); |
| } |
| |
| planContent.append("</plan>"); |
| |
| TestPlanArtifactInfo info = new TestPlanArtifactInfo(planName, planVersion, scoped, atomic, children); |
| |
| String fileName = planName + "-" + planVersion + PLAN_EXTENSION; |
| File planFile = new File(GENERATED_PLAN_DIRECTORY + fileName); |
| try (Writer writer = new FileWriter(planFile)) { |
| writer.write(planContent.toString()); |
| } |
| |
| info.setFile(planFile); |
| |
| return info; |
| } |
| |
| private static final class TestPlanArtifactInfo extends TestArtifactInfo { |
| |
| private static final TestPlanArtifactInfo[] EMPTY_CHILD_PLAN_ARRAY = new TestPlanArtifactInfo[0]; |
| |
| private final boolean scoped; |
| |
| private final boolean atomic; |
| |
| TestPlanArtifactInfo(String name, Version version, Boolean scoped, Boolean atomic, TestArtifactInfo[] children) { |
| super(PLAN_TYPE, name, version, children); |
| this.scoped = scoped; |
| this.atomic = atomic; |
| } |
| |
| TestPlanArtifactInfo[] getChildPlans() { |
| List<TestPlanArtifactInfo> childPlans = new ArrayList<>(); |
| for (TestArtifactInfo child : getChildren()) { |
| if (child instanceof TestPlanArtifactInfo) { |
| childPlans.add((TestPlanArtifactInfo) child); |
| } |
| } |
| return childPlans.toArray(EMPTY_CHILD_PLAN_ARRAY); |
| } |
| |
| TestPlanArtifactInfo getChildPlan() { |
| TestPlanArtifactInfo[] childPlans = getChildPlans(); |
| assertEquals(1, childPlans.length); |
| return childPlans[0]; |
| } |
| |
| public boolean isScoped() { |
| return scoped; |
| } |
| |
| public boolean isAtomic() { |
| return atomic; |
| } |
| |
| } |
| |
| private static class TestArtifactInfo { |
| |
| private static final TestArtifactInfo[] EMPTY_CHILD_ARRAY = new TestArtifactInfo[0]; |
| |
| private final String type; |
| |
| private final String name; |
| |
| private final Version version; |
| |
| private File file; |
| |
| private TestArtifactInfo[] children; |
| |
| TestArtifactInfo(String type, String name, Version version, TestArtifactInfo[] children) { |
| this.type = type; |
| this.name = name; |
| this.version = version; |
| this.children = children == null ? EMPTY_CHILD_ARRAY : children; |
| } |
| |
| TestArtifactInfo(String type, String name, Version version) { |
| this(type, name, version, null); |
| } |
| |
| public String getType() { |
| return type; |
| } |
| |
| public String getName() { |
| return name; |
| } |
| |
| public Version getVersion() { |
| return version; |
| } |
| |
| TestArtifactInfo[] getChildren() { |
| return this.children; |
| } |
| |
| TestArtifactInfo[] getChildBundles() { |
| List<TestArtifactInfo> childBundles = new ArrayList<>(); |
| for (TestArtifactInfo child : getChildren()) { |
| if (BUNDLE_TYPE.equals(child.getType())) { |
| childBundles.add(child); |
| } |
| } |
| return childBundles.toArray(EMPTY_CHILD_ARRAY); |
| } |
| |
| public void setFile(File file) { |
| this.file = file; |
| } |
| |
| public File getFile() { |
| if (this.file == null) { |
| throw new IllegalStateException("TestArtifactInfo file not set"); |
| } |
| return file; |
| } |
| |
| @Override |
| public String toString() { |
| return /* "TestArtifactInfo [type=" + type + ", name=" + */name /* + ", version=" + version + "]" */; |
| } |
| |
| } |
| |
| } |