/*******************************************************************************
* Copyright (c) 2008, 2011 VMware Inc. and others
* 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
* EclipseSource - Bug 358442 Change InstallArtifact graph from a tree to a DAG
*******************************************************************************/
package org.eclipse.virgo.kernel.install.pipeline.stage.transform.internal;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.eq;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.isA;
import static org.easymock.EasyMock.isNull;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.jar.JarFile;
import org.eclipse.virgo.kernel.artifact.fs.StandardArtifactFSFactory;
import org.eclipse.virgo.nano.deployer.api.core.DeploymentException;
import org.eclipse.virgo.kernel.install.artifact.ArtifactIdentity;
import org.eclipse.virgo.kernel.install.artifact.ArtifactStorage;
import org.eclipse.virgo.kernel.install.artifact.BundleInstallArtifact;
import org.eclipse.virgo.kernel.install.artifact.InstallArtifact;
import org.eclipse.virgo.kernel.install.artifact.InstallArtifactGraphFactory;
import org.eclipse.virgo.kernel.install.artifact.PlanInstallArtifact;
import org.eclipse.virgo.kernel.install.artifact.internal.ArtifactStorageFactory;
import org.eclipse.virgo.kernel.install.artifact.internal.StandardArtifactStorageFactory;
import org.eclipse.virgo.kernel.install.artifact.internal.scoping.ScopeNameFactory;
import org.eclipse.virgo.kernel.install.environment.InstallEnvironment;
import org.eclipse.virgo.kernel.install.pipeline.stage.transform.Transformer;
import org.eclipse.virgo.medic.test.eventlog.MockEventLogger;
import org.eclipse.virgo.util.common.DirectedAcyclicGraph;
import org.eclipse.virgo.util.common.GraphNode;
import org.eclipse.virgo.util.common.ThreadSafeDirectedAcyclicGraph;
import org.eclipse.virgo.util.io.PathReference;
import org.eclipse.virgo.util.osgi.manifest.BundleManifest;
import org.eclipse.virgo.util.osgi.manifest.BundleManifestFactory;
import org.eclipse.virgo.util.osgi.manifest.ImportedBundle;
import org.junit.Before;
import org.junit.Test;
import org.osgi.framework.Version;
/**
*/
public final class SyntheticContextBundleCreatingTransformerTests {
private final InstallArtifactGraphFactory installArtifactGraphFactory = createMock(InstallArtifactGraphFactory.class);
private final InstallEnvironment installEnvironment = createMock(InstallEnvironment.class);
private final ArtifactStorageFactory artifactStorageFactory = new StandardArtifactStorageFactory(new PathReference("build/work"),
new StandardArtifactFSFactory(), new MockEventLogger(), "true");
private final Transformer transformer = new SyntheticContextBundleCreatingTransformer(this.installArtifactGraphFactory,
this.artifactStorageFactory);
private DirectedAcyclicGraph<InstallArtifact> dag;
@Before
public void createGraph() {
this.dag = new ThreadSafeDirectedAcyclicGraph<InstallArtifact>();
new PathReference("build/work/staging/plan-name-1").delete(true);
}
@SuppressWarnings("unchecked")
@Test
public void basicSyntheticContextCreation() throws DeploymentException, FileNotFoundException, IOException {
GraphNode<InstallArtifact> planInstallGraph = createMockPlan(true, new Version(1, 0, 0), "plan-name", "bundle1", "bundle2", "bundle3");
InstallArtifact syntheticContextInstallArtifact = createMock(InstallArtifact.class);
File syntheticBundleDir = new File("build/work/s/plan-name-1/0/0/plan-name-1-synthetic.context.jar").getAbsoluteFile();
expect(
this.installArtifactGraphFactory.constructInstallArtifactGraph(eq(new ArtifactIdentity("bundle", "plan-name-1-synthetic.context",
new Version(1, 0, 0), ScopeNameFactory.createScopeName("plan-name", new Version(1, 0, 0)))), isA(ArtifactStorage.class),
(Map<String, String>) isNull(), (String) isNull())).andReturn(this.dag.createRootNode(syntheticContextInstallArtifact));
replay(this.installEnvironment, this.installArtifactGraphFactory);
this.transformer.transform(planInstallGraph, this.installEnvironment);
verify(this.installEnvironment, this.installArtifactGraphFactory);
File manifest = new File(syntheticBundleDir, JarFile.MANIFEST_NAME);
assertTrue(manifest.exists());
assertBundlesImported(manifest, "bundle1", "bundle2", "bundle3");
}
@SuppressWarnings("unchecked")
@Test
public void nestedPlanSyntheticContextCreation() throws DeploymentException, FileNotFoundException, IOException {
GraphNode<InstallArtifact> rootPlanInstallGraph = createMockPlan(true, new Version(1, 0, 0), "plan-name", "bundle1");
rootPlanInstallGraph.addChild(createMockPlan(true, new Version(1, 0, 0), "nested-plan", "bundle2", "bundle3"));
InstallArtifact syntheticContextInstallArtifact = createMock(InstallArtifact.class);
File syntheticBundleDir = new File("build/work/s/plan-name-1/0/0/plan-name-1-synthetic.context.jar").getAbsoluteFile();
expect(
this.installArtifactGraphFactory.constructInstallArtifactGraph(eq(new ArtifactIdentity("bundle", "plan-name-1-synthetic.context",
new Version(1, 0, 0), ScopeNameFactory.createScopeName("plan-name", new Version(1, 0, 0)))), isA(ArtifactStorage.class),
(Map<String, String>) isNull(), (String) isNull())).andReturn(this.dag.createRootNode(syntheticContextInstallArtifact));
replay(this.installEnvironment, this.installArtifactGraphFactory);
this.transformer.transform(rootPlanInstallGraph, this.installEnvironment);
verify(this.installEnvironment, this.installArtifactGraphFactory);
File manifest = new File(syntheticBundleDir, JarFile.MANIFEST_NAME);
assertTrue(manifest.exists());
assertBundlesImported(manifest, "bundle1", "bundle2", "bundle3");
}
@SuppressWarnings("unchecked")
@Test
public void syntheticContextOnlyCreatedForScopedPlans() throws DeploymentException, FileNotFoundException, IOException {
GraphNode<InstallArtifact> rootPlanInstallGraph = createMockPlan(false, new Version(1, 0, 0), "plan-name", "bundle1");
rootPlanInstallGraph.addChild(createMockPlan(true, new Version(1, 0, 0), "nested-plan", "bundle2", "bundle3"));
InstallArtifact syntheticContextInstallArtifact = createMock(InstallArtifact.class);
File syntheticBundleDir = new File("build/work/s/nested-plan-1/0/0/nested-plan-1-synthetic.context.jar").getAbsoluteFile();
expect(
this.installArtifactGraphFactory.constructInstallArtifactGraph(eq(new ArtifactIdentity("bundle", "nested-plan-1-synthetic.context",
new Version(1, 0, 0), ScopeNameFactory.createScopeName("nested-plan", new Version(1, 0, 0)))), isA(ArtifactStorage.class),
(Map<String, String>) isNull(), (String) isNull())).andReturn(this.dag.createRootNode(syntheticContextInstallArtifact));
replay(this.installEnvironment, this.installArtifactGraphFactory);
this.transformer.transform(rootPlanInstallGraph, this.installEnvironment);
verify(this.installEnvironment, this.installArtifactGraphFactory);
File manifest = new File(syntheticBundleDir, JarFile.MANIFEST_NAME);
assertTrue(manifest.exists());
assertBundlesImported(manifest, "bundle2", "bundle3");
}
private void assertBundlesImported(File manifestFile, String... symbolicNames) throws FileNotFoundException, IOException {
try (FileReader fileReader = new FileReader(manifestFile)) {
BundleManifest bundleManifest = BundleManifestFactory.createBundleManifest(fileReader);
List<ImportedBundle> importedBundles = bundleManifest.getImportBundle().getImportedBundles();
assertEquals(symbolicNames.length, importedBundles.size());
for (String symbolicName : symbolicNames) {
assertBundleImported(importedBundles, symbolicName);
}
}
}
private void assertBundleImported(List<ImportedBundle> importedBundles, String symbolicName) {
for (ImportedBundle importedBundle : importedBundles) {
if (symbolicName.equals(importedBundle.getBundleSymbolicName())) {
return;
}
}
fail("No import for symbolic name '" + symbolicName + "' was found among imported bundles " + importedBundles);
}
private InstallArtifact createMockBundleInstallArtifact(String symbolicName) {
InstallArtifact bundle = createMock(BundleInstallArtifact.class);
expect(bundle.getName()).andReturn(symbolicName).anyTimes();
replay(bundle);
return bundle;
}
private GraphNode<InstallArtifact> createMockPlan(boolean scoped, Version version, String name, String... bundleSymbolicNames) {
PlanInstallArtifact plan = createMock(PlanInstallArtifact.class);
expect(plan.isScoped()).andReturn(scoped).anyTimes();
expect(plan.getVersion()).andReturn(version).anyTimes();
expect(plan.getName()).andReturn(name).anyTimes();
replay(plan);
GraphNode<InstallArtifact> installTree = this.dag.createRootNode(plan);
for (String bundleSymbolicName : bundleSymbolicNames) {
InstallArtifact bundle = createMockBundleInstallArtifact(bundleSymbolicName);
installTree.addChild(this.dag.createRootNode(bundle));
}
return installTree;
}
}