FELIX-4403 Add integration test for configure-by-annotations
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1616081 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/AnnoConfigTest.java b/scr/src/test/java/org/apache/felix/scr/integration/AnnoConfigTest.java
new file mode 100644
index 0000000..2b034e4
--- /dev/null
+++ b/scr/src/test/java/org/apache/felix/scr/integration/AnnoConfigTest.java
@@ -0,0 +1,256 @@
+/*
+ * 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;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.apache.felix.scr.integration.components.annoconfig.AnnoComponent;
+import org.apache.felix.scr.integration.components.annoconfig.AnnoComponent.A1;
+import org.apache.felix.scr.integration.components.annoconfig.AnnoComponent.A1Arrays;
+import org.apache.felix.scr.integration.components.annoconfig.AnnoComponent.E1;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.component.runtime.dto.ComponentConfigurationDTO;
+
+@RunWith(JUnit4TestRunner.class)
+public class AnnoConfigTest extends ComponentTestBase
+{
+
+ static
+ {
+ // uncomment to enable debugging of this test class
+// paxRunnerVmOption = DEBUG_VM_OPTION;
+
+ descriptorFile = "/integration_test_annoconfig.xml";
+ COMPONENT_PACKAGE = COMPONENT_PACKAGE + ".annoconfig";
+ }
+
+ @Test
+ public void testAnnoConfig() throws Exception
+ {
+ String name = "org.apache.felix.scr.integration.components.annoconfig";
+ ComponentConfigurationDTO dto = findComponentConfigurationByName(name, ComponentConfigurationDTO.SATISFIED);
+ AnnoComponent ac = getServiceFromConfiguration(dto, AnnoComponent.class);
+ checkA1NoValues(ac.m_a1_activate);
+ checkA1ArraysNoValues(ac.m_a1Arrays_activate);
+
+ Configuration c = configure(name, null, allValues());
+ delay();
+
+ checkA1(ac.m_a1_modified);
+ checkA1Array(ac.m_a1Arrays_modified);
+
+ ungetServiceFromConfiguration(dto, AnnoComponent.class);
+ checkA1(ac.m_a1_deactivate);
+ checkA1Array(ac.m_a1Arrays_deactivate);
+ ac = getServiceFromConfiguration(dto, AnnoComponent.class);
+ checkA1(ac.m_a1_activate);
+ checkA1Array(ac.m_a1Arrays_activate);
+
+ c.delete();
+ delay();
+
+ checkA1NoValues(ac.m_a1_modified);
+ checkA1ArraysNoValues(ac.m_a1Arrays_modified);
+
+ c = configure(name, null, arrayValues());
+ delay();
+
+ checkA1FromArray(ac.m_a1_modified);
+ checkA1ArrayFromArray(ac.m_a1Arrays_modified, false);
+
+ c.delete();
+ delay();
+
+ checkA1NoValues(ac.m_a1_modified);
+ checkA1ArraysNoValues(ac.m_a1Arrays_modified);
+
+ c = configure(name, null, collectionValues());
+ delay();
+
+ checkA1FromArray(ac.m_a1_modified);
+ checkA1ArrayFromArray(ac.m_a1Arrays_modified, true);
+
+ }
+
+ private Hashtable<String, Object> allValues()
+ {
+ Hashtable<String, Object> values = new Hashtable<String, Object>();
+ values.put("bool", "true");
+ values.put("byt", 12l);
+ values.put("clas", String.class.getName());
+ values.put("e1", E1.a.toString());
+ values.put("doubl", "3.14");
+ values.put("floa", 500l);
+ values.put("integer", 3.0d);
+ values.put("lon", "12345678");
+ values.put("shor", 3l);
+ values.put("string", 3);
+ return values;
+ }
+
+ private Hashtable<String, Object> arrayValues()
+ {
+ Hashtable<String, Object> values = new Hashtable<String, Object>();
+ values.put("bool", new boolean[] {true, false});
+ values.put("byt", new byte[] {12, 3});
+ values.put("clas", new String[] {String.class.getName(), Integer.class.getName()});
+ values.put("e1", new String[] {E1.a.name(), E1.b.name()});
+ values.put("doubl", new double[] {3.14, 2.78, 9});
+ values.put("floa", new float[] {500, 37.44f});
+ values.put("integer", new int[] {3, 6, 9});
+ values.put("lon", new long[] {12345678l, -1});
+ values.put("shor", new short[] {3, 88});
+ values.put("string", new String[] {});
+ return values;
+ }
+
+ private Hashtable<String, Object> collectionValues()
+ {
+ Hashtable<String, Object> values = arrayValues();
+ Hashtable<String, Object> collectionValues = new Hashtable<String, Object>();
+ for (Map.Entry<String, Object> entry: values.entrySet())
+ {
+ collectionValues.put(entry.getKey(), toList(entry.getValue()));
+ }
+ //yuck
+ collectionValues.remove("string");
+ return collectionValues;
+ }
+
+ private List<?> toList(Object value)
+ {
+ List result = new ArrayList();
+ for (int i = 0; i < Array.getLength(value); i++)
+ {
+ result.add(Array.get(value, i));
+ }
+ return result;
+ }
+
+ private void checkA1(A1 a)
+ {
+ TestCase.assertEquals(true, a.bool());
+ TestCase.assertEquals((byte)12, a.byt());
+ TestCase.assertEquals(String.class, a.clas());
+ TestCase.assertEquals(E1.a, a.e1());
+ TestCase.assertEquals(3.14d, a.doubl());
+ TestCase.assertEquals(500f, a.floa());
+ TestCase.assertEquals(3, a.integer());
+ TestCase.assertEquals(12345678l, a.lon());
+ TestCase.assertEquals((short)3, a.shor());
+ TestCase.assertEquals("3", a.string());
+ }
+
+
+ private void checkA1FromArray(A1 a)
+ {
+ TestCase.assertEquals(true, a.bool());
+ TestCase.assertEquals((byte)12, a.byt());
+ TestCase.assertEquals(String.class, a.clas());
+ TestCase.assertEquals(E1.a, a.e1());
+ TestCase.assertEquals(3.14d, a.doubl());
+ TestCase.assertEquals(500f, a.floa());
+ TestCase.assertEquals(3, a.integer());
+ TestCase.assertEquals(12345678l, a.lon());
+ TestCase.assertEquals((short)3, a.shor());
+ TestCase.assertEquals(null, a.string());
+ }
+
+ private void checkA1Array(A1Arrays a)
+ {
+ assertArrayEquals(new boolean[] {true}, a.bool());
+ assertArrayEquals(new byte[] {(byte)12}, a.byt());
+ assertArrayEquals(new Class<?>[] {String.class}, a.clas());
+ assertArrayEquals(new E1[] {E1.a}, a.e1());
+ assertArrayEquals(new double[] {3.14d}, a.doubl());
+ assertArrayEquals(new float[] {500f}, a.floa());
+ assertArrayEquals(new int[] {3}, a.integer());
+ assertArrayEquals(new long[] {12345678l}, a.lon());
+ assertArrayEquals(new short[] {(short)3}, a.shor());
+ assertArrayEquals(new String[] {"3"}, a.string());
+ }
+
+ private void checkA1ArrayFromArray(A1Arrays a, boolean caBug)
+ {
+ assertArrayEquals(new boolean[] {true, false}, a.bool());
+ assertArrayEquals(new byte[] {12, 3}, a.byt());
+ assertArrayEquals(new Class<?>[] {String.class, Integer.class}, a.clas());
+ assertArrayEquals(new E1[] {E1.a, E1.b}, a.e1());
+ assertArrayEquals(new double[] {3.14, 2.78, 9}, a.doubl());
+ assertArrayEquals(new float[] {500f, 37.44f}, a.floa());
+ assertArrayEquals(new int[] {3, 6, 9}, a.integer());
+ assertArrayEquals(new long[] {12345678l, -1}, a.lon());
+ assertArrayEquals(new short[] {(short)3, 88}, a.shor());
+ if (!caBug)
+ {
+ assertArrayEquals(new String[] {}, a.string());
+ }
+ }
+
+ private void assertArrayEquals(Object a, Object b)
+ {
+ TestCase.assertTrue(a.getClass().isArray());
+ TestCase.assertTrue(b.getClass().isArray());
+ TestCase.assertEquals("wrong length", Array.getLength(a), Array.getLength(b));
+ TestCase.assertEquals("wrong type", a.getClass().getComponentType(), b.getClass().getComponentType());
+ for (int i = 0; i < Array.getLength(a); i++)
+ {
+ TestCase.assertEquals("different value at " + i, Array.get(a, i), Array.get(b, i));
+ }
+
+ }
+
+ private void checkA1NoValues(A1 a)
+ {
+ TestCase.assertEquals(false, a.bool());
+ TestCase.assertEquals((byte)0, a.byt());
+ TestCase.assertEquals(null, a.clas());
+ TestCase.assertEquals(null, a.e1());
+ TestCase.assertEquals(0d, a.doubl());
+ TestCase.assertEquals(0f, a.floa());
+ TestCase.assertEquals(0, a.integer());
+ TestCase.assertEquals(0l, a.lon());
+ TestCase.assertEquals((short)0, a.shor());
+ TestCase.assertEquals(null, a.string());
+ }
+
+ private void checkA1ArraysNoValues(A1Arrays a)
+ {
+ TestCase.assertEquals(null, a.bool());
+ TestCase.assertEquals(null, a.byt());
+ TestCase.assertEquals(null, a.clas());
+ TestCase.assertEquals(null, a.e1());
+ TestCase.assertEquals(null, a.doubl());
+ TestCase.assertEquals(null, a.floa());
+ TestCase.assertEquals(null, a.integer());
+ TestCase.assertEquals(null, a.lon());
+ TestCase.assertEquals(null, a.shor());
+ TestCase.assertEquals(null, a.string());
+ }
+}
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 af5f978..37eb492 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
@@ -110,7 +110,7 @@
protected static final String BUNDLE_JAR_DEFAULT = "target/scr.jar";
protected static final String PROP_NAME = "theValue";
- protected static final Dictionary<String, String> theConfig;
+ protected static final Dictionary<String, Object> theConfig;
// the JVM option to set to enable remote debugging
protected static final String DEBUG_VM_OPTION = "-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=30303";
@@ -144,14 +144,15 @@
static
{
- theConfig = new Hashtable<String, String>();
+ theConfig = new Hashtable<String, Object>();
theConfig.put( PROP_NAME, PROP_NAME );
}
@ProbeBuilder
public TestProbeBuilder extendProbe(TestProbeBuilder builder) {
builder.setHeader("Export-Package", "org.apache.felix.scr.integration.components," +
- "org.apache.felix.scr.integration.components.activatesignature," +
+ "org.apache.felix.scr.integration.components.activatesignature," +
+ "org.apache.felix.scr.integration.components.annoconfig," +
"org.apache.felix.scr.integration.components.circular," +
"org.apache.felix.scr.integration.components.circularFactory," +
"org.apache.felix.scr.integration.components.concurrency," +
@@ -371,20 +372,35 @@
protected <S> S getServiceFromConfiguration( ComponentConfigurationDTO dto, Class<S> clazz )
{
- long id = dto.id;
- String filter = "(component.id=" + id + ")";
- Collection<ServiceReference<S>> srs;
- try {
- srs = bundleContext.getServiceReferences(clazz, filter);
- Assert.assertEquals(1, srs.size());
- ServiceReference<S> sr = srs.iterator().next();
- S s = bundleContext.getService(sr);
- Assert.assertNotNull(s);
- return s;
- } catch (InvalidSyntaxException e) {
- TestCase.fail(e.getMessage());
- return null;//unreachable in fact
- }
+ long id = dto.id;
+ String filter = "(component.id=" + id + ")";
+ Collection<ServiceReference<S>> srs;
+ try {
+ srs = bundleContext.getServiceReferences(clazz, filter);
+ Assert.assertEquals(1, srs.size());
+ ServiceReference<S> sr = srs.iterator().next();
+ S s = bundleContext.getService(sr);
+ Assert.assertNotNull(s);
+ return s;
+ } catch (InvalidSyntaxException e) {
+ TestCase.fail(e.getMessage());
+ return null;//unreachable in fact
+ }
+ }
+
+ protected <S> void ungetServiceFromConfiguration( ComponentConfigurationDTO dto, Class<S> clazz )
+ {
+ long id = dto.id;
+ String filter = "(component.id=" + id + ")";
+ Collection<ServiceReference<S>> srs;
+ try {
+ srs = bundleContext.getServiceReferences(clazz, filter);
+ Assert.assertEquals(1, srs.size());
+ ServiceReference<S> sr = srs.iterator().next();
+ bundleContext.ungetService(sr);
+ } catch (InvalidSyntaxException e) {
+ TestCase.fail(e.getMessage());
+ }
}
protected void enableAndCheck( ComponentDescriptionDTO cd ) throws InvocationTargetException, InterruptedException
@@ -461,6 +477,12 @@
protected org.osgi.service.cm.Configuration configure( String pid, String bundleLocation )
{
+ return configure(pid, bundleLocation, theConfig);
+ }
+
+ protected org.osgi.service.cm.Configuration configure(String pid,
+ String bundleLocation, Dictionary<String, Object> props)
+ {
ConfigurationAdmin ca = getConfigurationAdmin();
try
{
@@ -469,7 +491,7 @@
{
config.setBundleLocation( bundleLocation );
}
- config.update( theConfig );
+ config.update( props );
return config;
}
catch ( IOException ioe )
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/components/annoconfig/AnnoComponent.java b/scr/src/test/java/org/apache/felix/scr/integration/components/annoconfig/AnnoComponent.java
new file mode 100644
index 0000000..db5770b
--- /dev/null
+++ b/scr/src/test/java/org/apache/felix/scr/integration/components/annoconfig/AnnoComponent.java
@@ -0,0 +1,97 @@
+/*
+ * 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.annoconfig;
+
+
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.felix.scr.impl.helper.AnnotationTest.E1;
+import org.osgi.service.component.ComponentConstants;
+import org.osgi.service.component.ComponentContext;
+
+
+public class AnnoComponent
+{
+
+ public enum E1 {a, b, c}
+
+ public @interface A1 {
+ boolean bool();
+ byte byt();
+ Class<?> clas();
+ E1 e1();
+ double doubl();
+ float floa();
+ int integer();
+ long lon();
+ short shor();
+ String string();
+ }
+
+ public @interface A1Arrays {
+ boolean[] bool();
+ byte[] byt();
+ Class<?>[] clas();
+ E1[] e1();
+ double[] doubl();
+ float[] floa();
+ int[] integer();
+ long[] lon();
+ short[] shor();
+ String[] string();
+ }
+
+ public A1 m_a1_activate;
+ public A1Arrays m_a1Arrays_activate;
+ public A1 m_a1_modified;
+ public A1Arrays m_a1Arrays_modified;
+ public A1 m_a1_deactivate;
+ public A1Arrays m_a1Arrays_deactivate;
+
+
+ @SuppressWarnings("unused")
+ private void activate( ComponentContext activateContext, A1 a1, A1Arrays a1Arrays, Map<?, ?> config )
+ {
+ m_a1_activate = a1;
+ m_a1Arrays_activate = a1Arrays;
+ }
+
+
+
+ @SuppressWarnings("unused")
+ private void modified( ComponentContext context, A1 a1, A1Arrays a1Arrays)
+ {
+ m_a1_modified = a1;
+ m_a1Arrays_modified = a1Arrays;
+ }
+
+ @SuppressWarnings("unused")
+ private void deactivate( A1 a1, A1Arrays a1Arrays )
+ {
+ m_a1_deactivate = a1;
+ m_a1Arrays_deactivate = a1Arrays;
+ }
+
+
+}
diff --git a/scr/src/test/resources/integration_test_annoconfig.xml b/scr/src/test/resources/integration_test_annoconfig.xml
new file mode 100644
index 0000000..6511e2d
--- /dev/null
+++ b/scr/src/test/resources/integration_test_annoconfig.xml
@@ -0,0 +1,26 @@
+<?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.3.0">
+ <scr:component
+ name='org.apache.felix.scr.integration.components.annoconfig'
+ pid='org.apache.felix.scr.integration.components.annoconfig'
+ modified='modified'
+ >
+ <implementation
+ class='org.apache.felix.scr.integration.components.annoconfig.AnnoComponent' />
+ <service>
+ <provide interface='org.apache.felix.scr.integration.components.annoconfig.AnnoComponent' />
+ </service>
+ </scr:component>
+
+
+</components>