Added a test case which reproduces the issue described in FELIX-4984.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1701869 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java b/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java
index 9854c33..8351ceb 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java
@@ -155,6 +155,7 @@
"org.apache.felix.scr.integration.components.concurrency," +
"org.apache.felix.scr.integration.components.deadlock," +
"org.apache.felix.scr.integration.components.felix3680," +
+ "org.apache.felix.scr.integration.components.felix4984," +
"org.apache.felix.scr.integration.components.felix3680_2");
builder.setHeader("Import-Package", "org.apache.felix.scr.component");
builder.setHeader("Bundle-ManifestVersion", "2");
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/Felix4984Test.java b/scr/src/test/java/org/apache/felix/scr/integration/Felix4984Test.java
new file mode 100644
index 0000000..7a03fbc
--- /dev/null
+++ b/scr/src/test/java/org/apache/felix/scr/integration/Felix4984Test.java
@@ -0,0 +1,85 @@
+package org.apache.felix.scr.integration;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+
+import org.apache.felix.scr.integration.components.felix4984.A;
+import org.apache.felix.scr.integration.components.felix4984.B;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.runtime.dto.ComponentConfigurationDTO;
+import org.osgi.service.log.LogService;
+
+import junit.framework.TestCase;
+
+
+@RunWith(JUnit4TestRunner.class)
+public class Felix4984Test extends ComponentTestBase
+{
+ static
+ {
+ descriptorFile = "/integration_test_FELIX_4984.xml";
+ COMPONENT_PACKAGE = COMPONENT_PACKAGE + ".felix4984";
+ DS_LOGLEVEL = "debug";
+ }
+
+ /**
+ * A > 1.1 > B > 0..n > A
+ * This test validates that A is bound to one B instance. See FELIX-4984 for more informations.
+ */
+ @Test
+ public void test_A11_B0n_delayed_B_first_ABoundToAtMostOneB() throws Exception
+ {
+ Bundle bundle = findABBundle(bundleContext);
+ bundle.stop();
+
+ for (int i = 0; i < 1000; i ++) {
+ bundle.start();
+
+ String componentNameA = "felix4984.A.1.1.dynamic";
+ ComponentConfigurationDTO componentA = findComponentConfigurationByName( componentNameA, ComponentConfigurationDTO.SATISFIED );
+
+ String componentNameB = "felix4984.B.0.n.dynamic";
+ final ComponentConfigurationDTO componentB = findComponentConfigurationByName( componentNameB, ComponentConfigurationDTO.SATISFIED);
+
+ ServiceReference[] serviceReferencesB = bundleContext.getServiceReferences( B.class.getName(), "(service.pid=" + componentNameB + ")" );
+ assertNotNull( serviceReferencesB );
+ TestCase.assertEquals( 1, serviceReferencesB.length );
+ ServiceReference serviceReferenceB = serviceReferencesB[0];
+ Object serviceB = bundleContext.getService( serviceReferenceB );
+ assertNotNull( serviceB );
+
+ ServiceReference[] serviceReferencesA = bundleContext.getServiceReferences( A.class.getName(), "(service.pid=" + componentNameA + ")" );
+ TestCase.assertEquals( 1, serviceReferencesA.length );
+ ServiceReference serviceReferenceA = serviceReferencesA[0];
+ Object serviceA = bundleContext.getService( serviceReferenceA );
+ assertNotNull( serviceA );
+
+ A a = getServiceFromConfiguration(componentA, A.class);
+ assertABoundToOneB(a);
+
+ bundle.stop();
+ }
+ }
+
+ private Bundle findABBundle(BundleContext ctx) {
+ for (Bundle b : ctx.getBundles()) {
+ if (b.getSymbolicName().equals("simplecomponent")) {
+ return b;
+ }
+ }
+ throw new IllegalStateException("bundle \"simplecomponent\" not found");
+ }
+
+ private void assertABoundToOneB(A a) {
+ if (a.getBs().size() != 1) {
+ log.log(LogService.LOG_WARNING, "detected problem ...");
+ a.dumpStackTracesWhenBWasBound(log);
+ }
+ assertEquals( 1, a.getBs().size());
+ }
+}
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/components/felix4984/A.java b/scr/src/test/java/org/apache/felix/scr/integration/components/felix4984/A.java
new file mode 100644
index 0000000..e872ebf
--- /dev/null
+++ b/scr/src/test/java/org/apache/felix/scr/integration/components/felix4984/A.java
@@ -0,0 +1,69 @@
+/*
+ * 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.scr.integration.components.felix4984;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.log.LogService;
+
+/**
+ * @version $Rev: 1350816 $ $Date: 2012-06-15 23:37:30 +0200 (Fri, 15 Jun 2012) $
+ */
+public class A
+{
+
+ private List<B> bs = new ArrayList<B>();
+ private List<Exception> bsStackTraces = new ArrayList();
+
+ private boolean activated;
+
+ private void activate(ComponentContext cc)
+ {
+ activated = true;
+ }
+
+ private void setB(B b)
+ {
+ bs.add( b );
+ bsStackTraces.add(new Exception());
+ }
+
+ private void unsetB(B b)
+ {
+ bs.remove( b );
+ bsStackTraces.remove(bsStackTraces.size()-1);
+ }
+
+ public List<B> getBs()
+ {
+ return bs;
+ }
+
+ public void dumpStackTracesWhenBWasBound(LogService log) {
+ log.log(LogService.LOG_WARNING, "Stack traces when B was bound:");
+ for (Exception e : bsStackTraces) {
+ log.log(LogService.LOG_WARNING, "stack trace:", e);
+ }
+ }
+
+}
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/components/felix4984/B.java b/scr/src/test/java/org/apache/felix/scr/integration/components/felix4984/B.java
new file mode 100644
index 0000000..0e504e0
--- /dev/null
+++ b/scr/src/test/java/org/apache/felix/scr/integration/components/felix4984/B.java
@@ -0,0 +1,24 @@
+package org.apache.felix.scr.integration.components.felix4984;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class B
+{
+ private List<A> as = new ArrayList<A>();
+
+ private void setA(A a)
+ {
+ as.add( a );
+ }
+
+ private void unsetA(A a)
+ {
+ as.remove( a );
+ }
+
+ public List<A> getAs()
+ {
+ return as;
+ }
+}
diff --git a/scr/src/test/resources/integration_test_FELIX_4984.xml b/scr/src/test/resources/integration_test_FELIX_4984.xml
new file mode 100644
index 0000000..500924d
--- /dev/null
+++ b/scr/src/test/resources/integration_test_FELIX_4984.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<components xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0">
+
+ <!-- A 1.1 dynamic. B 0..n dynamic both delayed. -->
+ <scr:component name="felix4984.A.1.1.dynamic"
+ enabled="true"
+ immediate="false"
+ configuration-policy="ignore">
+ <implementation class="org.apache.felix.scr.integration.components.felix4984.A" />
+ <service>
+ <provide interface="org.apache.felix.scr.integration.components.felix4984.A" />
+ </service>
+ <reference
+ name="b"
+ interface="org.apache.felix.scr.integration.components.felix4984.B"
+ cardinality="1..1"
+ policy="dynamic"
+ bind="setB"
+ unbind="unsetB"
+ target="(service.pid=felix4984.B.0.n.dynamic)"
+ />
+ <property name="service.pid" value="felix4984.A.1.1.dynamic" />
+ </scr:component>
+
+ <scr:component name="felix4984.B.0.n.dynamic"
+ enabled="true"
+ immediate="false"
+ configuration-policy="ignore">
+ <implementation class="org.apache.felix.scr.integration.components.felix4984.B" />
+ <service>
+ <provide interface="org.apache.felix.scr.integration.components.felix4984.B" />
+ </service>
+ <reference
+ name="a"
+ interface="org.apache.felix.scr.integration.components.felix4984.A"
+ cardinality="0..n"
+ policy="dynamic"
+ bind="setA"
+ unbind="unsetA"
+ target="(service.pid=felix4984.A.1.1.dynamic)"
+ />
+ <property name="service.pid" value="felix4984.B.0.n.dynamic" />
+ </scr:component>
+
+</components>
\ No newline at end of file