/*******************************************************************************
* 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 static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.util.Set;
import org.eclipse.virgo.nano.deployer.api.core.ApplicationDeployer;
import org.eclipse.virgo.nano.deployer.api.core.DeploymentException;
import org.eclipse.virgo.nano.deployer.api.core.DeploymentIdentity;
import org.eclipse.virgo.util.io.JarUtils;
import org.eclipse.virgo.util.io.PathReference;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
/**
* Test refreshing individual modules of a deployed application.
* <p />
*
*/
public class RefreshTests extends AbstractDeployerIntegrationTest {
private final String TEST_IMPORTER_BUNDLE_SYMBOLIC_NAME = "RefreshTest-1-RefreshImporter";
private final String TEST_IMPORT_BUNDLE_IMPORTER_BUNDLE_SYMBOLIC_NAME = "RefreshTest-Import-Bundle-" + TEST_APPS_VERSION + "-RefreshImporter";
private ServiceReference<ApplicationDeployer> appDeployerServiceReference;
private ApplicationDeployer appDeployer;
private PathReference explodedPar;
private PathReference par;
private PathReference parImportBundle;
@Before
public void setUp() throws Exception {
PathReference pr = new PathReference("./target/org.eclipse.virgo.kernel");
pr.delete(true);
pr.createDirectory();
this.appDeployerServiceReference = this.context.getServiceReference(ApplicationDeployer.class);
this.appDeployer = this.context.getService(this.appDeployerServiceReference);
explodedPar = new PathReference("./target/refresh-test/refresh.par");
explodedPar.delete(true);
par = new PathReference("src/test/resources/refresh.par");
JarUtils.unpackTo(par, explodedPar);
parImportBundle = new PathReference("src/test/resources/refresh-import-bundle.par");
}
@After
public void tearDown() throws Exception {
if (this.appDeployerServiceReference != null) {
this.context.ungetService(this.appDeployerServiceReference);
}
}
@Test
public void testBasicRefresh() throws DeploymentException, InterruptedException, IOException {
explodedPar.delete(true);
JarUtils.unpackTo(par, explodedPar);
this.appDeployer.deploy(explodedPar.toURI());
// Check that the test bundle's application contexts are created.
assertNotNull(ApplicationContextUtils.getApplicationContext(this.context, TEST_IMPORTER_BUNDLE_SYMBOLIC_NAME));
checkV1Classes();
PathReference exporter = new PathReference("./target/refresh-test/refresh.par/RefreshExporter.jar");
PathReference v2 = new PathReference("./target/refresh-test/refresh.par/build/RefreshExporterv2.jar");
exporter.delete();
v2.copy(exporter);
this.appDeployer.refresh(explodedPar.toURI(), "RefreshExporter");
Thread.sleep(1000); // wait for appCtx to be properly closed before waiting for it to be created.
ApplicationContextUtils.awaitApplicationContext(this.context, TEST_IMPORTER_BUNDLE_SYMBOLIC_NAME, 10);
checkV2Classes();
PathReference v3 = new PathReference("./target/refresh-test/refresh.par/build/RefreshExporterv3.jar");
exporter.delete();
v3.copy(exporter);
this.appDeployer.refresh(explodedPar.toURI(), "RefreshExporter");
Thread.sleep(1000); // wait for appCtx to be properly closed before waiting for it to be created.
ApplicationContextUtils.awaitApplicationContext(this.context, TEST_IMPORTER_BUNDLE_SYMBOLIC_NAME, 10);
checkV3Classes();
}
@Test(expected=DeploymentException.class)
public void testRefreshOfUndeployedApplication() throws DeploymentException, IOException {
explodedPar.delete(true);
JarUtils.unpackTo(par, explodedPar);
// Ensure application isn't already deployed.
this.appDeployer.undeploy("par", "RefreshTest", "1");
this.appDeployer.refresh(explodedPar.toURI(), "RefreshExporter");
}
@Test
public void testRefreshWithImportBundle() throws DeploymentException, InterruptedException, IOException {
explodedPar.delete(true);
JarUtils.unpackTo(parImportBundle, explodedPar);
this.appDeployer.deploy(explodedPar.toURI());
// Check that the test bundle's application contexts are created.
ApplicationContextUtils.awaitApplicationContext(this.context, TEST_IMPORT_BUNDLE_IMPORTER_BUNDLE_SYMBOLIC_NAME, 10);
checkV1Classes();
this.appDeployer.refresh(explodedPar.toURI(), "RefreshImporter");
Thread.sleep(1000); // wait for appCtx to be properly closed before waiting for it to be created.
ApplicationContextUtils.awaitApplicationContext(this.context, TEST_IMPORT_BUNDLE_IMPORTER_BUNDLE_SYMBOLIC_NAME, 10);
checkV1Classes();
}
@Test
public void testRedeployOfDependentBundles() throws DeploymentException, IOException {
explodedPar.delete(true);
JarUtils.unpackTo(par, explodedPar);
PathReference exporterJar = explodedPar.newChild("RefreshExporter.jar");
PathReference explodedExporterJar = explodedPar.newChild("explode").newChild("RefreshExporter.jar");
explodedExporterJar.delete(true);
JarUtils.unpackTo(exporterJar, explodedExporterJar);
PathReference importerJar = explodedPar.newChild("RefreshImporter.jar");
PathReference explodedImporterJar = explodedPar.newChild("explode").newChild("RefreshImporter.jar");
explodedImporterJar.delete(true);
JarUtils.unpackTo(importerJar, explodedImporterJar);
// Ensure bundles are not already deployed.
try {
this.appDeployer.undeploy("bundle", "RefreshExporter.jar", TEST_APPS_VERSION);
} catch (DeploymentException e) {
}
try {
this.appDeployer.undeploy("bundle", "RefreshImporter.jar", TEST_APPS_VERSION);
} catch (DeploymentException e) {
}
DeploymentIdentity diExporter = this.appDeployer.deploy(explodedExporterJar.toURI());
DeploymentIdentity diImporter = this.appDeployer.deploy(explodedImporterJar.toURI());
assertDeploymentIdentityEquals(diExporter, "RefreshExporter", "bundle", "RefreshExporter", TEST_APPS_VERSION);
assertDeploymentIdentityEquals(diImporter, "RefreshImporter", "bundle", "RefreshImporter", TEST_APPS_VERSION);
// Check that the test bundle's application contexts are created.
ApplicationContextUtils.awaitApplicationContext(this.context, "RefreshImporter", 10);
// Save the importer's manifest and overwrite it with the exporter's
PathReference importerManifest = explodedImporterJar.newChild("META-INF").newChild("MANIFEST.MF");
PathReference importerManifestSave = explodedImporterJar.newChild("META-INF").newChild("MANIFEST.MF.SAVED");
importerManifest.copy(importerManifestSave);
PathReference exporterManifest = explodedExporterJar.newChild("META-INF").newChild("MANIFEST.MF");
importerManifest.delete();
exporterManifest.copy(importerManifest);
// Redeploy the importer which will fail because of a duplicate bundle.
try {
this.appDeployer.deploy(explodedImporterJar.toURI());
assertFalse("deploy should fail because of a duplicate bundle", true);
} catch (DeploymentException e) {
assertTrue("Message did not report clash: " + e.getMessage(), e.getMessage().contains("clashes"));
}
// Restore the importer's manifest
importerManifest.delete();
importerManifestSave.copy(importerManifest);
// Redeploy the importer which should now succeed.
DeploymentIdentity deploymentIdentity = this.appDeployer.deploy(explodedImporterJar.toURI());
assertDeploymentIdentityEquals(deploymentIdentity, "RefreshImporter", "bundle", "RefreshImporter", TEST_APPS_VERSION);
}
private void checkV1Classes() {
LoadableClasses loadableClasses = (LoadableClasses) getApplicationBundleContext().getService(
getApplicationBundleContext().getServiceReference("org.eclipse.virgo.kernel.deployer.test.LoadableClasses"));
Set<String> loadableClassNames = loadableClasses.getLoadableClasses();
assertTrue(loadableClassNames.contains("refresh.exporter.b1.B11"));
assertFalse(loadableClassNames.contains("refresh.exporter.b1.B12"));
assertFalse(loadableClassNames.contains("refresh.exporter.b2.B21"));
}
private void checkV2Classes() {
LoadableClasses loadableClasses = (LoadableClasses) getApplicationBundleContext().getService(
getApplicationBundleContext().getServiceReference("org.eclipse.virgo.kernel.deployer.test.LoadableClasses"));
Set<String> loadableClassNames = loadableClasses.getLoadableClasses();
assertTrue(loadableClassNames.contains("refresh.exporter.b1.B11"));
assertTrue(loadableClassNames.contains("refresh.exporter.b1.B12"));
assertFalse(loadableClassNames.contains("refresh.exporter.b2.B21"));
}
private void checkV3Classes() {
LoadableClasses loadableClasses = (LoadableClasses) getApplicationBundleContext().getService(
getApplicationBundleContext().getServiceReference("org.eclipse.virgo.kernel.deployer.test.LoadableClasses"));
Set<String> loadableClassNames = loadableClasses.getLoadableClasses();
assertTrue(loadableClassNames.contains("refresh.exporter.b1.B11"));
assertTrue(loadableClassNames.contains("refresh.exporter.b1.B12"));
assertTrue(loadableClassNames.contains("refresh.exporter.b2.B21"));
}
private BundleContext getApplicationBundleContext() {
Bundle[] bundles = this.context.getBundles();
for (Bundle bundle : bundles) {
String symbolicName = bundle.getSymbolicName();
if (symbolicName.contains("RefreshTest")) {
System.out.println(bundle.getSymbolicName());
return bundle.getBundleContext();
}
}
fail("Cannot find bundle context");
return null;
}
}