Better support for integration testing:
- easy way of enabling remote debugging in a single class
- some more utility methods
- create jar file copy of scr bundle for integration test
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@806503 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/pom.xml b/scr/pom.xml
index ce4b849..b4487f5 100644
--- a/scr/pom.xml
+++ b/scr/pom.xml
@@ -160,6 +160,38 @@
</configuration>
</plugin>
+ <!-- Provide bundle for integration tests -->
+ <plugin>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <version>1.3</version>
+ <executions>
+ <execution>
+ <id>configadmin-file-create</id>
+ <phase>pre-integration-test</phase>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <tasks>
+ <copy file="${project.build.directory}/${project.build.finalName}.jar" tofile="${project.build.directory}/scr.jar" />
+ </tasks>
+ </configuration>
+ </execution>
+ <execution>
+ <id>configadmin-file-remove</id>
+ <phase>post-integration-test</phase>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <tasks>
+ <delete file="${project.build.directory}/configadmin.jar" />
+ </tasks>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
<!--
Exclude Integration tests in (default) unit tests and
conversely enable integration tests for integration testing
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ComponentConfigurationTest.java b/scr/src/test/java/org/apache/felix/scr/integration/ComponentConfigurationTest.java
index aa589cd..4187f4f 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ComponentConfigurationTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ComponentConfigurationTest.java
@@ -27,12 +27,17 @@
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.junit.JUnit4TestRunner;
import org.osgi.framework.Constants;
-import org.osgi.framework.ServiceReference;
@RunWith(JUnit4TestRunner.class)
public class ComponentConfigurationTest extends ComponentTestBase
{
+ static
+ {
+ // uncomment to enable debugging of this test class
+ // paxRunnerVmOption = DEBUG_VM_OPTION;
+ }
+
@Test
public void test_SimpleComponent_configuration_ignore()
@@ -65,7 +70,79 @@
@Test
public void test_SimpleComponent_factory_configuration()
{
- test_factory_configuration( "FactoryConfigurationComponent" );
+ final String factoryPid = "FactoryConfigurationComponent";
+
+ deleteFactoryConfigurations( factoryPid );
+ delay();
+
+ // one single component exists without configuration
+ final Component[] noConfigurations = findComponentsByName( factoryPid );
+ TestCase.assertNotNull( noConfigurations );
+ TestCase.assertEquals( 1, noConfigurations.length );
+ TestCase.assertEquals( Component.STATE_DISABLED, noConfigurations[0].getState() );
+ TestCase.assertTrue( SimpleComponent.INSTANCES.isEmpty() );
+
+ // enable the component, configuration required, hence unsatisfied
+ noConfigurations[0].enable();
+ delay();
+
+ final Component[] enabledNoConfigs = findComponentsByName( factoryPid );
+ TestCase.assertNotNull( enabledNoConfigs );
+ TestCase.assertEquals( 1, enabledNoConfigs.length );
+ TestCase.assertEquals( Component.STATE_UNSATISFIED, enabledNoConfigs[0].getState() );
+ TestCase.assertTrue( SimpleComponent.INSTANCES.isEmpty() );
+
+ // create two factory configurations expecting two components
+ final String pid0 = createFactoryConfiguration( factoryPid );
+ final String pid1 = createFactoryConfiguration( factoryPid );
+ delay();
+
+ // expect two components, only first is active, second is disabled
+ final Component[] twoConfigs = findComponentsByName( factoryPid );
+ TestCase.assertNotNull( twoConfigs );
+ TestCase.assertEquals( 2, twoConfigs.length );
+ TestCase.assertEquals( Component.STATE_ACTIVE, twoConfigs[0].getState() );
+ TestCase.assertEquals( Component.STATE_DISABLED, twoConfigs[1].getState() );
+ TestCase.assertEquals( 1, SimpleComponent.INSTANCES.size() );
+ TestCase.assertTrue( SimpleComponent.INSTANCES.containsKey( twoConfigs[0].getId() ) );
+ TestCase.assertFalse( SimpleComponent.INSTANCES.containsKey( twoConfigs[1].getId() ) );
+
+ // enable second component
+ twoConfigs[1].enable();
+ delay();
+
+ // ensure both components active
+ TestCase.assertEquals( Component.STATE_ACTIVE, twoConfigs[0].getState() );
+ TestCase.assertEquals( Component.STATE_ACTIVE, twoConfigs[1].getState() );
+ TestCase.assertEquals( 2, SimpleComponent.INSTANCES.size() );
+ TestCase.assertTrue( SimpleComponent.INSTANCES.containsKey( twoConfigs[0].getId() ) );
+ TestCase.assertTrue( SimpleComponent.INSTANCES.containsKey( twoConfigs[1].getId() ) );
+
+ // delete a configuration
+ deleteConfig( pid0 );
+ delay();
+
+ // expect one component
+ final Component[] oneConfig = findComponentsByName( factoryPid );
+ TestCase.assertNotNull( oneConfig );
+ TestCase.assertEquals( 1, oneConfig.length );
+ TestCase.assertEquals( Component.STATE_ACTIVE, oneConfig[0].getState() );
+ TestCase.assertEquals( 1, SimpleComponent.INSTANCES.size() );
+ TestCase.assertFalse( SimpleComponent.INSTANCES.containsKey( twoConfigs[0].getId() ) );
+ TestCase.assertTrue( SimpleComponent.INSTANCES.containsKey( twoConfigs[1].getId() ) );
+
+ // delete second configuration
+ deleteConfig( pid1 );
+ delay();
+
+ // expect a single unsatisifed component
+ final Component[] configsDeleted = findComponentsByName( factoryPid );
+ TestCase.assertNotNull( configsDeleted );
+ TestCase.assertEquals( 1, configsDeleted.length );
+ TestCase.assertEquals( Component.STATE_UNSATISFIED, configsDeleted[0].getState() );
+ TestCase.assertEquals( 0, SimpleComponent.INSTANCES.size() );
+ TestCase.assertFalse( SimpleComponent.INSTANCES.containsKey( twoConfigs[0].getId() ) );
+ TestCase.assertFalse( SimpleComponent.INSTANCES.containsKey( twoConfigs[1].getId() ) );
}
@@ -251,129 +328,4 @@
TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
TestCase.assertNull( SimpleComponent.INSTANCE );
}
-
-
- private void test_factory_configuration( final String componentName )
- {
- final String factoryPid = componentName;
-
- deleteFactoryConfigurations( factoryPid );
- delay();
-
- // one single component exists without configuration
- final Component[] noConfigurations = findComponentsByName( factoryPid );
- TestCase.assertNotNull( noConfigurations );
- TestCase.assertEquals( 1, noConfigurations.length );
- TestCase.assertEquals( Component.STATE_DISABLED, noConfigurations[0].getState() );
- TestCase.assertTrue( SimpleComponent.INSTANCES.isEmpty() );
-
- // enable the component, configuration required, hence unsatisfied
- noConfigurations[0].enable();
- delay();
-
- final Component[] enabledNoConfigs = findComponentsByName( factoryPid );
- TestCase.assertNotNull( enabledNoConfigs );
- TestCase.assertEquals( 1, enabledNoConfigs.length );
- TestCase.assertEquals( Component.STATE_UNSATISFIED, enabledNoConfigs[0].getState() );
- TestCase.assertTrue( SimpleComponent.INSTANCES.isEmpty() );
-
- // create two factory configurations expecting two components
- final String pid0 = createFactoryConfiguration( factoryPid );
- final String pid1 = createFactoryConfiguration( factoryPid );
- delay();
-
- // expect two components, only first is active, second is disabled
- final Component[] twoConfigs = findComponentsByName( factoryPid );
- TestCase.assertNotNull( twoConfigs );
- TestCase.assertEquals( 2, twoConfigs.length );
- TestCase.assertEquals( Component.STATE_ACTIVE, twoConfigs[0].getState() );
- TestCase.assertEquals( Component.STATE_DISABLED, twoConfigs[1].getState() );
- TestCase.assertEquals( 1, SimpleComponent.INSTANCES.size() );
- TestCase.assertTrue( SimpleComponent.INSTANCES.containsKey( twoConfigs[0].getId() ) );
- TestCase.assertFalse( SimpleComponent.INSTANCES.containsKey( twoConfigs[1].getId() ) );
-
- // enable second component
- twoConfigs[1].enable();
- delay();
-
- // ensure both components active
- TestCase.assertEquals( Component.STATE_ACTIVE, twoConfigs[0].getState() );
- TestCase.assertEquals( Component.STATE_ACTIVE, twoConfigs[1].getState() );
- TestCase.assertEquals( 2, SimpleComponent.INSTANCES.size() );
- TestCase.assertTrue( SimpleComponent.INSTANCES.containsKey( twoConfigs[0].getId() ) );
- TestCase.assertTrue( SimpleComponent.INSTANCES.containsKey( twoConfigs[1].getId() ) );
-
- // delete a configuration
- deleteConfig( pid0 );
- delay();
-
- // expect one component
- final Component[] oneConfig = findComponentsByName( factoryPid );
- TestCase.assertNotNull( oneConfig );
- TestCase.assertEquals( 1, oneConfig.length );
- TestCase.assertEquals( Component.STATE_ACTIVE, oneConfig[0].getState() );
- TestCase.assertEquals( 1, SimpleComponent.INSTANCES.size() );
- TestCase.assertFalse( SimpleComponent.INSTANCES.containsKey( twoConfigs[0].getId() ) );
- TestCase.assertTrue( SimpleComponent.INSTANCES.containsKey( twoConfigs[1].getId() ) );
-
- // delete second configuration
- deleteConfig( pid1 );
- delay();
-
- // expect a single unsatisifed component
- final Component[] configsDeleted = findComponentsByName( factoryPid );
- TestCase.assertNotNull( configsDeleted );
- TestCase.assertEquals( 1, configsDeleted.length );
- TestCase.assertEquals( Component.STATE_UNSATISFIED, configsDeleted[0].getState() );
- TestCase.assertEquals( 0, SimpleComponent.INSTANCES.size() );
- TestCase.assertFalse( SimpleComponent.INSTANCES.containsKey( twoConfigs[0].getId() ) );
- TestCase.assertFalse( SimpleComponent.INSTANCES.containsKey( twoConfigs[1].getId() ) );
-
- }
-
-
- private void test_service( final String componentName )
- {
- final String pid = componentName;
-
- // one single component exists without configuration
- final Component component = findComponentByName( pid );
- TestCase.assertNotNull( component );
- TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
-
- component.enable();
- delay();
-
- final SimpleComponent instance = SimpleComponent.INSTANCE;
- TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
- TestCase.assertNotNull( instance );
-
- // assert component properties (all !)
- TestCase.assertEquals( "required", instance.getProperty( "prop.public" ) );
- TestCase.assertEquals( "private", instance.getProperty( ".prop.private" ) );
-
- // get the service
- ServiceReference reference = bundleContext.getServiceReference( "java.lang.Object" );
- TestCase.assertNotNull( reference );
- try
- {
- TestCase.assertEquals( instance, bundleContext.getService( reference ) );
- }
- finally
- {
- bundleContext.ungetService( reference );
- }
-
- // check service properties
- TestCase.assertEquals( "required", reference.getProperty( "prop.public" ) );
- TestCase.assertNull( reference.getProperty( ".prop.private" ) );
-
- // check property keys do not contain private keys
- for ( String propKey : reference.getPropertyKeys() )
- {
- TestCase.assertTrue( "Property key [" + propKey
- + "] must have at least one character and not start with a dot", propKey.length() > 0
- && !propKey.startsWith( "." ) );
- }
- }
}
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 6448a94..89c054e 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
@@ -22,11 +22,12 @@
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
import static org.ops4j.pax.exam.CoreOptions.options;
import static org.ops4j.pax.exam.CoreOptions.provision;
-import static org.ops4j.pax.exam.container.def.PaxRunnerOptions.scanDir;
import static org.ops4j.pax.swissbox.tinybundles.core.TinyBundles.withBnd;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.Hashtable;
@@ -38,8 +39,11 @@
import org.apache.felix.scr.integration.components.MyTinyBundle;
import org.junit.After;
import org.junit.Before;
+import org.ops4j.pax.exam.CoreOptions;
import org.ops4j.pax.exam.Inject;
import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+import org.ops4j.pax.exam.container.def.PaxRunnerOptions;
import org.ops4j.pax.exam.junit.Configuration;
import org.ops4j.pax.swissbox.tinybundles.core.TinyBundles;
import org.osgi.framework.Bundle;
@@ -66,6 +70,14 @@
protected static final String PROP_NAME = "theValue";
protected static final Dictionary<String, String> 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";
+
+ // the actual JVM option set, extensions may implement a static
+ // initializer overwriting this value to have the configuration()
+ // method include it when starting the OSGi framework JVM
+ protected static String paxRunnerVmOption = null;
+
static
{
theConfig = new Hashtable<String, String>();
@@ -76,14 +88,15 @@
@Configuration
public static Option[] configuration()
{
- return options(
+ final Option[] base = options(
provision(
- scanDir( "target" ).filter( "*.jar" ),
+ CoreOptions.bundle( new File("target/scr.jar").toURI().toString() ),
mavenBundle( "org.ops4j.pax.swissbox", "pax-swissbox-tinybundles", "1.0.0" ),
mavenBundle( "org.apache.felix", "org.apache.felix.configadmin", "1.0.10" )
)
-// , PaxRunnerOptions.vmOption( "-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=30303" )
);
+ final Option vmOption = ( paxRunnerVmOption != null ) ? PaxRunnerOptions.vmOption( paxRunnerVmOption ) : null;
+ return OptionUtils.combine( base, vmOption );
}
@@ -266,4 +279,43 @@
TestCase.fail( "Failed deleting configurations " + factoryPid + ": " + ioe.toString() );
}
}
+
+
+ protected static Class<?> getType( Object object, String desiredName )
+ {
+ Class<?> ccImpl = object.getClass();
+ while ( ccImpl != null && !desiredName.equals( ccImpl.getSimpleName() ) )
+ {
+ ccImpl = ccImpl.getSuperclass();
+ }
+ if ( ccImpl == null )
+ {
+ TestCase.fail( "ComponentContext " + object + " is not a " + desiredName );
+ }
+
+ return ccImpl;
+ }
+
+
+ protected static Object getFieldValue( Object object, String fieldName )
+ {
+ try
+ {
+ final Field m_componentsField = getField( object.getClass(), fieldName );
+ return m_componentsField.get( object );
+ }
+ catch ( Throwable t )
+ {
+ TestCase.fail( "Cannot get " + fieldName + " from " + object + ": " + t );
+ return null; // keep the compiler happy
+ }
+ }
+
+
+ protected static Field getField( Class<?> type, String fieldName ) throws NoSuchFieldException
+ {
+ Field field = type.getDeclaredField( fieldName );
+ field.setAccessible( true );
+ return field;
+ }
}
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ServiceComponentTest.java b/scr/src/test/java/org/apache/felix/scr/integration/ServiceComponentTest.java
index 94d4dc8..c5393c0 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ServiceComponentTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ServiceComponentTest.java
@@ -32,6 +32,12 @@
@RunWith(JUnit4TestRunner.class)
public class ServiceComponentTest extends ComponentTestBase
{
+ static
+ {
+ // uncomment to enable debugging of this test class
+ // paxRunnerVmOption = DEBUG_VM_OPTION;
+ }
+
@Test
public void test_SimpleComponent_service()