| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.felix.deploymentadmin.itest; |
| |
| import static org.osgi.service.deploymentadmin.DeploymentException.CODE_COMMIT_ERROR; |
| import static org.osgi.service.deploymentadmin.DeploymentException.CODE_OTHER_ERROR; |
| import static org.osgi.service.deploymentadmin.DeploymentException.CODE_PROCESSOR_NOT_FOUND; |
| |
| import org.apache.felix.deploymentadmin.itest.util.DeploymentPackageBuilder; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.ops4j.pax.exam.junit.PaxExam; |
| import org.osgi.framework.Bundle; |
| import org.osgi.service.deploymentadmin.DeploymentException; |
| import org.osgi.service.deploymentadmin.DeploymentPackage; |
| |
| /** |
| * Provides test cases regarding the use of "normal" deployment packages in DeploymentAdmin. |
| */ |
| @RunWith(PaxExam.class) |
| public class UninstallDeploymentPackageTest extends BaseIntegrationTest { |
| |
| /** |
| * Tests that if a resource processor is missing (uninstalled) during the forced uninstallation of a deployment package this will ignored and the uninstall completes. |
| */ |
| @Test |
| public void testForcedUninstallDeploymentPackageWithMissingResourceProcessorSucceeds() throws Exception { |
| DeploymentPackageBuilder dpBuilder = createNewDeploymentPackageBuilder("1.0.0"); |
| dpBuilder |
| .add(dpBuilder.createBundleResource().setUrl(getTestBundleURL("bundle1"))) |
| .add(dpBuilder.createResourceProcessorResource().setUrl(getTestBundleURL("rp1"))) |
| .add(dpBuilder.createResource().setResourceProcessorPID(TEST_FAILING_BUNDLE_RP1).setUrl(getTestResource("test-config1.xml"))); |
| |
| DeploymentPackage dp = installDeploymentPackage(dpBuilder); |
| assertNotNull("No deployment package returned?!", dp); |
| |
| awaitRefreshPackagesEvent(); |
| |
| assertTrue("Two bundles should be started!", getCurrentBundles().size() == 2); |
| |
| Bundle rpBundle = dp.getBundle(getSymbolicName("rp1")); |
| rpBundle.uninstall(); |
| |
| assertTrue("One bundle should be started!", getCurrentBundles().size() == 1); |
| |
| assertEquals("Expected no deployment package?!", 1, countDeploymentPackages()); |
| |
| assertTrue(dp.uninstallForced()); |
| |
| // FELIX-4484: after a forced uninstall, the DP should be marked as stale... |
| assertTrue(dp.isStale()); |
| |
| assertTrue("No bundle should be started!", getCurrentBundles().isEmpty()); |
| |
| assertEquals("Expected no deployment package?!", 0, countDeploymentPackages()); |
| } |
| |
| /** |
| * Tests that uninstalling a DP containing a bundle along with a fragment bundle succeeds (DA should not try to stop the fragment, see FELIX-4167). |
| */ |
| @Test |
| public void testUninstallBundleWithFragmentOk() throws Exception { |
| DeploymentPackageBuilder dpBuilder = createNewDeploymentPackageBuilder("1.0.0"); |
| dpBuilder |
| .add(dpBuilder.createBundleResource().setUrl(getTestBundleURL("bundle1"))) |
| .add(dpBuilder.createBundleResource().setUrl(getTestBundleURL("fragment1"))); |
| |
| DeploymentPackage dp = installDeploymentPackage(dpBuilder); |
| assertNotNull("No deployment package returned?!", dp); |
| |
| awaitRefreshPackagesEvent(); |
| |
| assertBundleExists(getSymbolicName("bundle1"), "1.0.0"); |
| assertBundleExists(getSymbolicName("fragment1"), "1.0.0"); |
| |
| assertTrue(isBundleActive(dp.getBundle(getSymbolicName("bundle1")))); |
| assertFalse(isBundleActive(dp.getBundle(getSymbolicName("fragment1")))); |
| |
| // Should succeed... |
| dp.uninstall(); |
| |
| assertEquals("Expected no deployment package?!", 0, countDeploymentPackages()); |
| |
| // Both bundles should be uninstalled... |
| assertBundleNotExists(getSymbolicName("bundle1"), "1.0.0"); |
| assertBundleNotExists(getSymbolicName("fragment1"), "1.0.0"); |
| } |
| |
| /** |
| * Tests that uninstalling a DP with a bundle along with other (non-bundle) artifacts succeeds. |
| */ |
| @Test |
| public void testUninstallBundleWithOtherArtifactsOk() throws Exception { |
| DeploymentPackageBuilder dpBuilder = createNewDeploymentPackageBuilder("1.0.0"); |
| dpBuilder |
| .add(dpBuilder.createResourceProcessorResource().setUrl(getTestBundleURL("rp1"))) |
| .add( |
| dpBuilder.createResource().setResourceProcessorPID(TEST_FAILING_BUNDLE_RP1) |
| .setUrl(getTestResource("test-config1.xml"))) |
| .add(dpBuilder.createBundleResource().setUrl(getTestBundleURL("bundle3"))); |
| |
| DeploymentPackage dp = installDeploymentPackage(dpBuilder); |
| assertNotNull("No deployment package returned?!", dp); |
| |
| awaitRefreshPackagesEvent(); |
| |
| // Though the commit failed; the package should be installed... |
| assertBundleExists(getSymbolicName("rp1"), "1.0.0"); |
| assertBundleExists(getSymbolicName("bundle3"), "1.0.0"); |
| |
| assertEquals("Expected a single deployment package?!", 1, countDeploymentPackages()); |
| |
| // Should succeed... |
| dp.uninstall(); |
| |
| assertEquals("Expected no deployment package?!", 0, countDeploymentPackages()); |
| |
| assertBundleNotExists(getSymbolicName("rp1"), "1.0.0"); |
| assertBundleNotExists(getSymbolicName("bundle3"), "1.0.0"); |
| } |
| |
| /** |
| * Tests that if an exception is thrown during the commit-phase, the installation is continued normally. |
| */ |
| @Test |
| public void testUninstallDeploymentPackageWithExceptionThrowingInCommitCausesNoRollbackOk() throws Exception { |
| DeploymentPackageBuilder dpBuilder = createNewDeploymentPackageBuilder("1.0.0"); |
| dpBuilder |
| .add(dpBuilder.createBundleResource().setUrl(getTestBundleURL("bundle1"))) |
| .add(dpBuilder.createResourceProcessorResource().setUrl(getTestBundleURL("rp1"))) |
| .add(dpBuilder.createResource().setResourceProcessorPID(TEST_FAILING_BUNDLE_RP1).setUrl(getTestResource("test-config1.xml"))); |
| |
| DeploymentPackage dp = installDeploymentPackage(dpBuilder); |
| assertNotNull("No deployment package returned?!", dp); |
| |
| awaitRefreshPackagesEvent(); |
| |
| assertTrue("Two bundles should be started!", getCurrentBundles().size() == 2); |
| |
| assertEquals("Expected no deployment package?!", 1, countDeploymentPackages()); |
| |
| System.setProperty("rp1", "commit"); |
| |
| dp.uninstall(); |
| |
| assertTrue("No bundles should be started! " + getCurrentBundles(), getCurrentBundles().isEmpty()); |
| |
| assertEquals("Expected no deployment package?!", 0, countDeploymentPackages()); |
| } |
| |
| /** |
| * Tests that if an exception is thrown during the dropping of a resource, the installation is rolled back. |
| */ |
| @Test |
| public void testUninstallDeploymentPackageWithExceptionThrowingInDropAllResourcesCausesRollbackOk() throws Exception { |
| DeploymentPackageBuilder dpBuilder = createNewDeploymentPackageBuilder("1.0.0"); |
| dpBuilder |
| .add(dpBuilder.createBundleResource().setUrl(getTestBundleURL("bundle1"))) |
| .add(dpBuilder.createResourceProcessorResource().setUrl(getTestBundleURL("rp1"))) |
| .add(dpBuilder.createResource().setResourceProcessorPID(TEST_FAILING_BUNDLE_RP1).setUrl(getTestResource("test-config1.xml"))); |
| |
| DeploymentPackage dp = installDeploymentPackage(dpBuilder); |
| assertNotNull("No deployment package returned?!", dp); |
| |
| awaitRefreshPackagesEvent(); |
| |
| assertTrue("Two bundles should be started!", getCurrentBundles().size() == 2); |
| |
| assertEquals("Expected no deployment package?!", 1, countDeploymentPackages()); |
| |
| System.setProperty("rp1", "dropAllResources"); |
| |
| try { |
| dp.uninstall(); |
| fail("Expected uninstall to fail and rollback!"); |
| } |
| catch (DeploymentException exception) { |
| // Ok; expected |
| assertDeploymentException(CODE_OTHER_ERROR, exception); |
| } |
| |
| // FELIX-4484: only after a successful uninstall, the DP should be marked as stale... |
| assertFalse(dp.isStale()); |
| |
| assertTrue("Two bundles should be started!", getCurrentBundles().size() == 2); |
| |
| assertEquals("Expected no deployment package?!", 1, countDeploymentPackages()); |
| } |
| |
| /** |
| * Tests that if an exception is thrown during the prepare-phase, the installation is rolled back. |
| */ |
| @Test |
| public void testUninstallDeploymentPackageWithExceptionThrowingInPrepareCausesRollbackOk() throws Exception { |
| DeploymentPackageBuilder dpBuilder = createNewDeploymentPackageBuilder("1.0.0"); |
| dpBuilder |
| .add(dpBuilder.createBundleResource().setUrl(getTestBundleURL("bundle1"))) |
| .add(dpBuilder.createResourceProcessorResource().setUrl(getTestBundleURL("rp1"))) |
| .add(dpBuilder.createResource().setResourceProcessorPID(TEST_FAILING_BUNDLE_RP1).setUrl(getTestResource("test-config1.xml"))); |
| |
| DeploymentPackage dp = installDeploymentPackage(dpBuilder); |
| assertNotNull("No deployment package returned?!", dp); |
| |
| awaitRefreshPackagesEvent(); |
| |
| assertTrue("Two bundles should be started!", getCurrentBundles().size() == 2); |
| |
| assertEquals("Expected no deployment package?!", 1, countDeploymentPackages()); |
| |
| System.setProperty("rp1", "prepare"); |
| |
| try { |
| dp.uninstall(); |
| fail("Expected uninstall to fail and rollback!"); |
| } |
| catch (DeploymentException exception) { |
| // Ok; expected |
| assertDeploymentException(CODE_COMMIT_ERROR, exception); |
| } |
| |
| assertTrue("Two bundles should be started!", getCurrentBundles().size() == 2); |
| |
| assertEquals("Expected no deployment package?!", 1, countDeploymentPackages()); |
| } |
| |
| /** |
| * Tests that if an exception is thrown during the uninstall of a bundle, the installation/update continues and succeeds. |
| */ |
| @Test |
| public void testUninstallDeploymentPackageWithExceptionThrownInStopCauseNoRollbackOk() throws Exception { |
| DeploymentPackageBuilder dpBuilder = createNewDeploymentPackageBuilder("1.0.0"); |
| dpBuilder |
| .add(dpBuilder.createBundleResource().setUrl(getTestBundleURL("bundle1"))) |
| .add(dpBuilder.createBundleResource().setUrl(getTestBundleURL("bundle3"))); |
| |
| DeploymentPackage dp = installDeploymentPackage(dpBuilder); |
| assertNotNull("No deployment package returned?!", dp); |
| |
| awaitRefreshPackagesEvent(); |
| |
| assertBundleExists(getSymbolicName("bundle3"), "1.0.0"); |
| |
| System.setProperty("bundle3", "stop"); |
| |
| dp.uninstall(); // should succeed. |
| |
| // FELIX-4484: only after a successful uninstall, the DP should be marked as stale... |
| assertTrue(dp.isStale()); |
| |
| awaitRefreshPackagesEvent(); |
| |
| assertEquals("Expected no deployment package?!", 0, countDeploymentPackages()); |
| |
| assertTrue("Expected no bundles to remain?!", getCurrentBundles().isEmpty()); |
| } |
| |
| /** |
| * Tests that if a resource processor is missing (uninstalled) during the uninstallation of a deployment package, this is regarded an error and a rollback is performed. |
| */ |
| @Test |
| public void testUninstallDeploymentPackageWithMissingResourceProcessorCausesRollback() throws Exception { |
| DeploymentPackageBuilder dpBuilder = createNewDeploymentPackageBuilder("1.0.0"); |
| dpBuilder |
| .add(dpBuilder.createBundleResource().setUrl(getTestBundleURL("bundle1"))) |
| .add(dpBuilder.createResourceProcessorResource().setUrl(getTestBundleURL("rp1"))) |
| .add(dpBuilder.createResource().setResourceProcessorPID(TEST_FAILING_BUNDLE_RP1).setUrl(getTestResource("test-config1.xml"))); |
| |
| DeploymentPackage dp = installDeploymentPackage(dpBuilder); |
| assertNotNull("No deployment package returned?!", dp); |
| |
| awaitRefreshPackagesEvent(); |
| |
| assertTrue("Two bundles should be started!", getCurrentBundles().size() == 2); |
| |
| Bundle rpBundle = dp.getBundle(getSymbolicName("rp1")); |
| rpBundle.uninstall(); |
| |
| assertTrue("One bundle should be started!", getCurrentBundles().size() == 1); |
| |
| assertEquals("Expected no deployment package?!", 1, countDeploymentPackages()); |
| |
| try { |
| dp.uninstall(); |
| fail("Expected uninstall to fail and rollback!"); |
| } |
| catch (DeploymentException exception) { |
| // Ok; expected |
| assertDeploymentException(CODE_PROCESSOR_NOT_FOUND, exception); |
| } |
| |
| assertTrue("One bundle should be started!", getCurrentBundles().size() == 1); |
| |
| assertEquals("Expected one deployment package?!", 1, countDeploymentPackages()); |
| } |
| } |