FELIX-4466 - DA does not always fire events
- make sure that an event is fired, even when a deployment operation
fails;
- added integration tests to verify this behaviour.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1581373 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/deploymentadmin/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/DeploymentAdminImpl.java b/deploymentadmin/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/DeploymentAdminImpl.java
index 320f51d..aeb2624 100644
--- a/deploymentadmin/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/DeploymentAdminImpl.java
+++ b/deploymentadmin/deploymentadmin/src/main/java/org/apache/felix/deploymentadmin/DeploymentAdminImpl.java
@@ -277,9 +277,7 @@
succeeded = false;
}
}
- if (source != null) {
- sendCompleteEvent(source, target, succeeded);
- }
+ sendCompleteEvent(source, target, succeeded);
m_semaphore.release();
}
}
@@ -366,9 +364,7 @@
succeeded = true;
}
finally {
- if (source != null) {
- sendCompleteEvent(source, target, succeeded);
- }
+ sendCompleteEvent(source, target, succeeded);
m_semaphore.release();
}
}
diff --git a/deploymentadmin/itest/src/test/java/org/apache/felix/deploymentadmin/itest/DeploymentAdminEventTest.java b/deploymentadmin/itest/src/test/java/org/apache/felix/deploymentadmin/itest/DeploymentAdminEventTest.java
new file mode 100644
index 0000000..72c60d6
--- /dev/null
+++ b/deploymentadmin/itest/src/test/java/org/apache/felix/deploymentadmin/itest/DeploymentAdminEventTest.java
@@ -0,0 +1,303 @@
+/*
+ * 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 java.util.Dictionary;
+import java.util.Properties;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.felix.deploymentadmin.Constants;
+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.ServiceRegistration;
+import org.osgi.service.deploymentadmin.DeploymentException;
+import org.osgi.service.deploymentadmin.DeploymentPackage;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventConstants;
+import org.osgi.service.event.EventHandler;
+
+/**
+ * Test cases for FELIX-4466 - DA does not always fire events.
+ */
+@RunWith(PaxExam.class)
+public class DeploymentAdminEventTest extends BaseIntegrationTest
+{
+ /**
+ * FELIX-4466 - test that an event is fired when an installation of a DP fails.
+ */
+ @Test
+ public void testFailedInstallationCausesCompletionEventOk() throws Exception
+ {
+ DeploymentPackageBuilder dpBuilder = createNewDeploymentPackageBuilder("1.0.0");
+ // incluse two different versions of the same bundle (with the same BSN), this is *not* allowed per the DA spec...
+ dpBuilder
+ .add(dpBuilder.createBundleResource().setUrl(getTestBundle("bundleapi1", "bundleapi", "1.0.0")))
+ .add(dpBuilder.createBundleResource().setUrl(getTestBundle("bundleapi2", "bundleapi", "2.0.0")));
+
+ final AtomicReference<Event> completionEventRef = new AtomicReference<Event>();
+ final AtomicReference<Event> installEventRef = new AtomicReference<Event>();
+ final CountDownLatch cdl = new CountDownLatch(1);
+
+ EventHandler eventHandler = new EventHandler()
+ {
+ @Override
+ public void handleEvent(Event event)
+ {
+ if (Constants.EVENTTOPIC_COMPLETE.equals(event.getTopic()))
+ {
+ assertTrue("Multiple events received?!", completionEventRef.compareAndSet(null, event));
+ cdl.countDown();
+ }
+ else if (Constants.EVENTTOPIC_INSTALL.equals(event.getTopic()))
+ {
+ assertTrue("Multiple events received?!", installEventRef.compareAndSet(null, event));
+ }
+ }
+ };
+
+ Dictionary props = new Properties();
+ props.put(EventConstants.EVENT_TOPIC, new String[] { Constants.EVENTTOPIC_COMPLETE, Constants.EVENTTOPIC_INSTALL });
+
+ ServiceRegistration sreg = m_context.registerService(EventHandler.class, eventHandler, props);
+
+ try
+ {
+ m_deploymentAdmin.installDeploymentPackage(dpBuilder.generate());
+ fail("DeploymentException expected!");
+ }
+ catch (DeploymentException e)
+ {
+ // Ok; expected...
+ assertTrue("Not all events were received in time?!", cdl.await(5, TimeUnit.SECONDS));
+
+ Event event;
+ // Verify we've got the expected events...
+ event = installEventRef.get();
+ // The install event is send *after* the DP have been created, which fails in this test...
+ assertNull("No install event received?!", event);
+
+ event = completionEventRef.get();
+ assertNotNull("No completion event received?!", event);
+ assertTrue("Completion property set to true?!", Boolean.FALSE.equals(event.getProperty(Constants.EVENTPROPERTY_SUCCESSFUL)));
+ }
+ finally
+ {
+ sreg.unregister();
+ }
+ }
+
+ /**
+ * FELIX-4466 - test that an event is fired when an installation of a DP succeeds.
+ */
+ @Test
+ public void testSuccessfulInstallationCausesCompletionEventOk() throws Exception
+ {
+ DeploymentPackageBuilder dpBuilder = createNewDeploymentPackageBuilder("1.0.0");
+ dpBuilder
+ .add(dpBuilder.createBundleResource().setUrl(getTestBundle("bundleapi1", "bundleapi", "1.0.0")))
+ .add(dpBuilder.createBundleResource().setUrl(getTestBundle("bundleimpl1", "bundleimpl", "1.0.0")));
+
+ final AtomicReference<Event> completionEventRef = new AtomicReference<Event>();
+ final AtomicReference<Event> installEventRef = new AtomicReference<Event>();
+ final CountDownLatch cdl = new CountDownLatch(2);
+
+ EventHandler eventHandler = new EventHandler()
+ {
+ @Override
+ public void handleEvent(Event event)
+ {
+ if (Constants.EVENTTOPIC_COMPLETE.equals(event.getTopic()))
+ {
+ assertTrue("Multiple events received?!", completionEventRef.compareAndSet(null, event));
+ cdl.countDown();
+ }
+ else if (Constants.EVENTTOPIC_INSTALL.equals(event.getTopic()))
+ {
+ assertTrue("Multiple events received?!", installEventRef.compareAndSet(null, event));
+ cdl.countDown();
+ }
+ }
+ };
+
+ Dictionary props = new Properties();
+ props.put(EventConstants.EVENT_TOPIC, new String[] { Constants.EVENTTOPIC_COMPLETE, Constants.EVENTTOPIC_INSTALL });
+
+ ServiceRegistration sreg = m_context.registerService(EventHandler.class, eventHandler, props);
+
+ try
+ {
+ m_deploymentAdmin.installDeploymentPackage(dpBuilder.generate());
+
+ assertTrue("Not all events were received in time?!", cdl.await(5, TimeUnit.SECONDS));
+
+ Event event;
+ // Verify we've got the expected events...
+ event = installEventRef.get();
+ assertNotNull("No install event received?!", event);
+
+ event = completionEventRef.get();
+ assertNotNull("No completion event received?!", event);
+ assertTrue("Completion property set to false?!", Boolean.TRUE.equals(event.getProperty(Constants.EVENTPROPERTY_SUCCESSFUL)));
+ }
+ finally
+ {
+ sreg.unregister();
+ }
+ }
+
+ /**
+ * FELIX-4466 - test that an event is fired when a DP is uninstalled.
+ */
+ @Test
+ public void testSuccessfulUninstallationCausesCompletionEventOk() throws Exception
+ {
+ DeploymentPackageBuilder dpBuilder = createNewDeploymentPackageBuilder("1.0.0");
+ dpBuilder
+ .add(dpBuilder.createBundleResource().setUrl(getTestBundle("bundleapi1", "bundleapi", "1.0.0")))
+ .add(dpBuilder.createBundleResource().setUrl(getTestBundle("bundleimpl1", "bundleimpl", "1.0.0")));
+
+ final AtomicReference<Event> completionEventRef = new AtomicReference<Event>();
+ final AtomicReference<Event> uninstallEventRef = new AtomicReference<Event>();
+ final CountDownLatch cdl = new CountDownLatch(2);
+
+ EventHandler eventHandler = new EventHandler()
+ {
+ @Override
+ public void handleEvent(Event event)
+ {
+ if (Constants.EVENTTOPIC_COMPLETE.equals(event.getTopic()))
+ {
+ assertTrue("Multiple events received?!", completionEventRef.compareAndSet(null, event));
+ cdl.countDown();
+ }
+ else if (Constants.EVENTTOPIC_UNINSTALL.equals(event.getTopic()))
+ {
+ assertTrue("Multiple events received?!", uninstallEventRef.compareAndSet(null, event));
+ cdl.countDown();
+ }
+ }
+ };
+
+ DeploymentPackage dp = m_deploymentAdmin.installDeploymentPackage(dpBuilder.generate());
+ assertNotNull(dp);
+
+ awaitRefreshPackagesEvent();
+
+ Dictionary props = new Properties();
+ props.put(EventConstants.EVENT_TOPIC, new String[] { Constants.EVENTTOPIC_COMPLETE, Constants.EVENTTOPIC_UNINSTALL });
+
+ ServiceRegistration sreg = m_context.registerService(EventHandler.class, eventHandler, props);
+
+ try
+ {
+ dp.uninstall();
+
+ assertTrue("Not all events were received in time?!", cdl.await(5, TimeUnit.SECONDS));
+
+ Event event;
+ // Verify we've got the expected events...
+ event = uninstallEventRef.get();
+ assertNotNull("No uninstall event received?!", event);
+
+ event = completionEventRef.get();
+ assertNotNull("No completion event received?!", event);
+ assertTrue("Completion property set to false?!", Boolean.TRUE.equals(event.getProperty(Constants.EVENTPROPERTY_SUCCESSFUL)));
+ }
+ finally
+ {
+ sreg.unregister();
+ }
+ }
+
+ /**
+ * FELIX-4466 - test that an event is fired when a DP is uninstalled, but fails.
+ */
+ @Test
+ public void testFailedUninstallationCausesCompletionEventOk() throws Exception
+ {
+ DeploymentPackageBuilder dpBuilder = createNewDeploymentPackageBuilder("1.0.0");
+ dpBuilder
+ .add(dpBuilder.createBundleResource().setUrl(getTestBundle("bundle1")))
+ .add(dpBuilder.createResourceProcessorResource().setUrl(getTestBundle("rp1")))
+ .add(dpBuilder.createResource().setResourceProcessorPID(TEST_FAILING_BUNDLE_RP1).setUrl(getTestResource("test-config1.xml")));
+
+ final AtomicReference<Event> completionEventRef = new AtomicReference<Event>();
+ final AtomicReference<Event> uninstallEventRef = new AtomicReference<Event>();
+ final CountDownLatch cdl = new CountDownLatch(2);
+
+ EventHandler eventHandler = new EventHandler()
+ {
+ @Override
+ public void handleEvent(Event event)
+ {
+ if (Constants.EVENTTOPIC_COMPLETE.equals(event.getTopic()))
+ {
+ assertTrue("Multiple events received?!", completionEventRef.compareAndSet(null, event));
+ cdl.countDown();
+ }
+ else if (Constants.EVENTTOPIC_UNINSTALL.equals(event.getTopic()))
+ {
+ assertTrue("Multiple events received?!", uninstallEventRef.compareAndSet(null, event));
+ cdl.countDown();
+ }
+ }
+ };
+
+ DeploymentPackage dp = m_deploymentAdmin.installDeploymentPackage(dpBuilder.generate());
+ assertNotNull("No deployment package returned?!", dp);
+
+ awaitRefreshPackagesEvent();
+
+ // Should cause the uninstall of the DP to fail...
+ dp.getBundle(getSymbolicName("rp1")).uninstall();
+
+ Dictionary props = new Properties();
+ props.put(EventConstants.EVENT_TOPIC, new String[] { Constants.EVENTTOPIC_COMPLETE, Constants.EVENTTOPIC_UNINSTALL });
+
+ ServiceRegistration sreg = m_context.registerService(EventHandler.class, eventHandler, props);
+
+ try
+ {
+ dp.uninstall();
+ fail("DeploymentException expected!");
+ }
+ catch (DeploymentException e)
+ {
+ // Ok, expected...
+ assertTrue("Not all events were received in time?!", cdl.await(5, TimeUnit.SECONDS));
+
+ Event event;
+ // Verify we've got the expected events...
+ event = uninstallEventRef.get();
+ assertNotNull("No uninstall event received?!", event);
+
+ event = completionEventRef.get();
+ assertNotNull("No completion event received?!", event);
+ assertTrue("Completion property set to true?!", Boolean.FALSE.equals(event.getProperty(Constants.EVENTPROPERTY_SUCCESSFUL)));
+ }
+ finally
+ {
+ sreg.unregister();
+ }
+ }
+}