Modified: felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/AutoConfResourceProcessorTest.java URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/AutoConfResourceProcessorTest.java?rev=1724802&r1=1724801&r2=1724802&view=diff ============================================================================== --- felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/AutoConfResourceProcessorTest.java (original) +++ felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/AutoConfResourceProcessorTest.java Fri Jan 15 13:34:41 2016 @@ -21,7 +21,10 @@ package org.apache.felix.deployment.rp.a import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; +import java.util.Collections; import java.util.Dictionary; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.Properties; import junit.framework.TestCase; @@ -40,434 +43,585 @@ import org.osgi.service.deploymentadmin. import org.osgi.service.deploymentadmin.spi.ResourceProcessorException; import org.osgi.service.log.LogService; -public class AutoConfResourceProcessorTest extends TestCase { - /** Make sure the processor does not accept a 'null' session. */ - public void testNullSession() throws Exception { - AutoConfResourceProcessor p = new AutoConfResourceProcessor(); - try { - p.begin(null); - fail("Should have gotten an exception when trying to begin with null session."); +public class AutoConfResourceProcessorTest extends TestCase +{ + private static class ConfigurationAdminImpl implements ConfigurationAdmin + { + private final String[] m_expectedPIDs; + private final String[] m_expectedFactoryPIDs; + private final Map<String, ConfigurationImpl> m_configs; + + public ConfigurationAdminImpl(String... expectedPIDs) + { + this(expectedPIDs, new String[0]); } - catch (Exception e) { - // expected + + public ConfigurationAdminImpl(String[] expectedPIDs, String[] expectedFactoryPIDs) + { + m_expectedPIDs = expectedPIDs; + m_expectedFactoryPIDs = expectedFactoryPIDs; + + m_configs = new LinkedHashMap<String, ConfigurationImpl>(); } - } - - /** Go through a simple session, containing two empty configurations. */ - public void testSimpleSession() throws Exception { - AutoConfResourceProcessor p = new AutoConfResourceProcessor(); - Utils.configureObject(p, LogService.class); - Utils.configureObject(p, DependencyManager.class, new DependencyManager((BundleContext) Utils.createNullObject(BundleContext.class)) { - public void remove(Component service) { - } - }); - File tempDir = File.createTempFile("persistence", "dir"); - tempDir.delete(); - tempDir.mkdirs(); - - System.out.println("Temporary dir: " + tempDir); - - Utils.configureObject(p, PersistencyManager.class, new PersistencyManager(tempDir)); - Session s = new Session(); - p.begin(s); - Utils.configureObject(p, Component.class, Utils.createMockObjectAdapter(Component.class, new Object() { - public DependencyManager getDependencyManager() { - return new DependencyManager((BundleContext) Utils.createNullObject(BundleContext.class)); - } - })); - p.process("a", new ByteArrayInputStream("<MetaData />".getBytes())); - p.process("b", new ByteArrayInputStream("<MetaData />".getBytes())); - p.prepare(); - p.commit(); - p.postcommit(); - Utils.removeDirectoryWithContent(tempDir); - } - /** Go through a simple session, containing two empty configurations. */ - public void testSimpleInstallAndUninstallSession() throws Throwable { - AutoConfResourceProcessor p = new AutoConfResourceProcessor(); - Utils.configureObject(p, LogService.class); - Utils.configureObject(p, DependencyManager.class, new DependencyManager((BundleContext) Utils.createNullObject(BundleContext.class)) { - public void remove(Component service) { - } - }); - Logger logger = new Logger(); - Utils.configureObject(p, LogService.class, logger); - File tempDir = File.createTempFile("persistence", "dir"); - tempDir.delete(); - tempDir.mkdirs(); - - System.out.println("Temporary dir: " + tempDir); - - Utils.configureObject(p, PersistencyManager.class, new PersistencyManager(tempDir)); - Session s = new Session(); - p.begin(s); - Utils.configureObject(p, Component.class, Utils.createMockObjectAdapter(Component.class, new Object() { - public DependencyManager getDependencyManager() { - return new DependencyManager((BundleContext) Utils.createNullObject(BundleContext.class)); - } - })); - p.process("a", new ByteArrayInputStream("<MetaData />".getBytes())); - p.prepare(); - p.commit(); - p.postcommit(); - logger.failOnException(); - s = new Session(); - p.begin(s); - p.dropped("a"); - p.prepare(); - p.commit(); - p.postcommit(); - logger.failOnException(); - Utils.removeDirectoryWithContent(tempDir); - } - - /** Go through a simple session, containing two empty configurations. */ - public void testBasicConfigurationSession() throws Throwable { - AutoConfResourceProcessor p = new AutoConfResourceProcessor(); - Logger logger = new Logger(); - Utils.configureObject(p, LogService.class, logger); - Utils.configureObject(p, DependencyManager.class, new DependencyManager((BundleContext) Utils.createNullObject(BundleContext.class)) { - public void remove(Component service) { - } - }); - File tempDir = File.createTempFile("persistence", "dir"); - tempDir.delete(); - tempDir.mkdirs(); - - System.out.println("Temporary dir: " + tempDir); - - Utils.configureObject(p, PersistencyManager.class, new PersistencyManager(tempDir)); - Session s = new Session(); - p.begin(s); - Utils.configureObject(p, Component.class, Utils.createMockObjectAdapter(Component.class, new Object() { - public DependencyManager getDependencyManager() { - return new DependencyManager((BundleContext) Utils.createNullObject(BundleContext.class)); - } - })); - String config = - "<MetaData xmlns:metatype='http://www.osgi.org/xmlns/metatype/v1.0.0'>\n" + - " <OCD name='ocd' id='ocd'>\n" + - " <AD id='name' type='STRING' cardinality='0' />\n" + - " </OCD>\n" + - " <Designate pid='simple' bundle='osgi-dp:location'>\n" + - " <Object ocdref='ocd'>\n" + - " <Attribute adref='name'>\n" + - " <Value><![CDATA[test]]></Value>\n" + - " </Attribute>\n" + - " </Object>\n" + - " </Designate>\n" + - "</MetaData>\n"; - p.process("basic", new ByteArrayInputStream(config.getBytes())); - p.prepare(); - p.commit(); - p.addConfigurationAdmin(null, new ConfigurationAdmin() { - public Configuration[] listConfigurations(String filter) throws IOException, InvalidSyntaxException { - return null; - } - - public Configuration getConfiguration(String pid, String location) throws IOException { - return new ConfigurationImpl(); - } - - public Configuration getConfiguration(String pid) throws IOException { - return null; - } - - public Configuration createFactoryConfiguration(String factoryPid, String location) throws IOException { - return null; - } - - public Configuration createFactoryConfiguration(String factoryPid) throws IOException { - return null; - } - }); - p.postcommit(); - logger.failOnException(); - Utils.removeDirectoryWithContent(tempDir); - } + public Configuration createFactoryConfiguration(String factoryPid) throws IOException + { + return createFactoryConfiguration(factoryPid, null); + } - /** Go through a simple session, containing two empty configurations. */ - public void testFilteredConfigurationSession() throws Throwable { - AutoConfResourceProcessor p = new AutoConfResourceProcessor(); - Logger logger = new Logger(); - Utils.configureObject(p, LogService.class, logger); - BundleContext mockBC = (BundleContext) Utils.createMockObjectAdapter(BundleContext.class, new Object() { - public Filter createFilter(String condition) { - return (Filter) Utils.createMockObjectAdapter(Filter.class, new Object() { - public boolean match(ServiceReference ref) { - Object id = ref.getProperty("id"); - if (id != null && id.equals(Integer.valueOf(42))) { - return true; - } - return false; - } - public void remove(Component service) { - } - }); - } - }); - Utils.configureObject(p, BundleContext.class, mockBC); - Utils.configureObject(p, DependencyManager.class, new DependencyManager(mockBC) { - public void remove(Component service) { - } - }); - File tempDir = File.createTempFile("persistence", "dir"); - tempDir.delete(); - tempDir.mkdirs(); - - System.out.println("Temporary dir: " + tempDir); - - Utils.configureObject(p, PersistencyManager.class, new PersistencyManager(tempDir)); - Session s = new Session(); - p.begin(s); - Utils.configureObject(p, Component.class, Utils.createMockObjectAdapter(Component.class, new Object() { - public DependencyManager getDependencyManager() { - return new DependencyManager((BundleContext) Utils.createNullObject(BundleContext.class)); - } - })); - String config = - "<MetaData xmlns:metatype='http://www.osgi.org/xmlns/metatype/v1.0.0' filter='(id=42)'>\n" + - " <OCD name='ocd' id='ocd'>\n" + - " <AD id='name' type='STRING' cardinality='0' />\n" + - " </OCD>\n" + - " <Designate pid='simple' bundle='osgi-dp:location'>\n" + - " <Object ocdref='ocd'>\n" + - " <Attribute adref='name'>\n" + - " <Value><![CDATA[test]]></Value>\n" + - " </Attribute>\n" + - " </Object>\n" + - " </Designate>\n" + - "</MetaData>\n"; - p.process("basic", new ByteArrayInputStream(config.getBytes())); - p.prepare(); - p.commit(); - Properties props = new Properties(); - props.put("id", Integer.valueOf(42)); - final Configuration configuration = new ConfigurationImpl(); - p.addConfigurationAdmin(new Reference(props), new ConfigurationAdmin() { - public Configuration[] listConfigurations(String filter) throws IOException, InvalidSyntaxException { - return null; - } - - public Configuration getConfiguration(String pid, String location) throws IOException { - return configuration; - } - - public Configuration getConfiguration(String pid) throws IOException { - return null; - } - - public Configuration createFactoryConfiguration(String factoryPid, String location) throws IOException { - return null; - } - - public Configuration createFactoryConfiguration(String factoryPid) throws IOException { - return null; - } - }); - - final Configuration emptyConfiguration = new ConfigurationImpl(); - p.addConfigurationAdmin(new Reference(new Properties()), new ConfigurationAdmin() { - public Configuration[] listConfigurations(String filter) throws IOException, InvalidSyntaxException { - return null; - } - - public Configuration getConfiguration(String pid, String location) throws IOException { - return emptyConfiguration; - } - - public Configuration getConfiguration(String pid) throws IOException { - return null; - } - - public Configuration createFactoryConfiguration(String factoryPid, String location) throws IOException { - return null; - } - - public Configuration createFactoryConfiguration(String factoryPid) throws IOException { - return null; + public Configuration createFactoryConfiguration(String factoryPid, String location) throws IOException + { + if (!isExpected(m_expectedFactoryPIDs, factoryPid)) + { + throw new IOException("Unexpected factory PID: " + factoryPid); } - }); - p.postcommit(); - logger.failOnException(); - assertEquals("test", configuration.getProperties().get("name")); - assertNull(emptyConfiguration.getProperties()); - Utils.removeDirectoryWithContent(tempDir); - } + // This should be unique enough for our use cases... + String pid = String.format("pid%d", m_configs.size()); - /** Go through a simple session, containing two empty configurations. */ - public void testMissingMandatoryValueInConfig() throws Throwable { - AutoConfResourceProcessor p = new AutoConfResourceProcessor(); - Logger logger = new Logger(); - Utils.configureObject(p, LogService.class, logger); - BundleContext mockBC = (BundleContext) Utils.createMockObjectAdapter(BundleContext.class, new Object() { - public Filter createFilter(String condition) { - return (Filter) Utils.createMockObjectAdapter(Filter.class, new Object() { - public boolean match(ServiceReference ref) { - Object id = ref.getProperty("id"); - if (id != null && id.equals(Integer.valueOf(42))) { - return true; - } - return false; - } - public void remove(Component service) { - } - }); + ConfigurationImpl config = m_configs.get(pid); + if (config == null) + { + config = new ConfigurationImpl(factoryPid, pid, location); + m_configs.put(pid, config); } - }); - Utils.configureObject(p, BundleContext.class, mockBC); - Utils.configureObject(p, DependencyManager.class, new DependencyManager(mockBC) { - public void remove(Component service) { + config.setBundleLocation(location); + return config; + } + + public Configuration getConfiguration(String pid) throws IOException + { + return getConfiguration(pid, null); + } + + public Configuration getConfiguration(String pid, String location) throws IOException + { + if (!isExpected(m_expectedPIDs, pid)) + { + throw new IOException("Unexpected PID: " + pid); } - }); - File tempDir = File.createTempFile("persistence", "dir"); - tempDir.delete(); - tempDir.mkdirs(); - - System.out.println("Temporary dir: " + tempDir); - - Utils.configureObject(p, PersistencyManager.class, new PersistencyManager(tempDir)); - Session s = new Session(); - p.begin(s); - Utils.configureObject(p, Component.class, Utils.createMockObjectAdapter(Component.class, new Object() { - public DependencyManager getDependencyManager() { - return new DependencyManager((BundleContext) Utils.createNullObject(BundleContext.class)); + + ConfigurationImpl config = m_configs.get(pid); + if (config == null) + { + config = new ConfigurationImpl(null, pid, location); + m_configs.put(pid, config); } - })); + config.setBundleLocation(location); + return config; + } - String config = - "<MetaData xmlns:metatype='http://www.osgi.org/xmlns/metatype/v1.1.0' filter='(id=42)'>\n" + - " <OCD name='ocd' id='ocd'>\n" + - " <AD id='name' type='Integer' />\n" + - " </OCD>\n" + - " <Designate pid='simple' bundle='osgi-dp:location'>\n" + - " <Object ocdref='ocd'>\n" + - " <Attribute adref='name'>\n" + - " <Value><![CDATA[]]></Value>\n" + - " </Attribute>\n" + - " </Object>\n" + - " </Designate>\n" + - "</MetaData>\n"; - - try + public Configuration[] listConfigurations(String filter) throws IOException, InvalidSyntaxException { - p.process("missing-value", new ByteArrayInputStream(config.getBytes())); - fail("Expected ResourceProcessorException for missing value!"); + return null; } - catch (ResourceProcessorException e) + + private boolean isExpected(String[] expectedPIDs, String actualPID) { - // Ok; expected... - assertEquals("Unable to parse value for definition: adref=name", e.getMessage()); + for (String expectedPID : expectedPIDs) + { + if (actualPID.equals(expectedPID)) + { + return true; + } + } + return false; } - Utils.removeDirectoryWithContent(tempDir); } - private static class ConfigurationImpl implements Configuration { - private String m_bundleLocation = "osgi-dp:location"; + private static class ConfigurationImpl implements Configuration + { + private final String m_factoryPID; + private final String m_pid; + private String m_bundleLocation; private Dictionary m_properties; + private boolean m_deleted; - public String getPid() { - return null; + public ConfigurationImpl(String factoryPid, String pid, String bundleLocation) + { + m_factoryPID = factoryPid; + m_pid = pid; + m_bundleLocation = bundleLocation; } - public Dictionary getProperties() { - return m_properties; + public void delete() throws IOException + { + m_deleted = true; } - public void update(Dictionary properties) throws IOException { - m_properties = properties; + public String getBundleLocation() + { + return m_bundleLocation; } - public void delete() throws IOException { + public String getFactoryPid() + { + return m_factoryPID; } - public String getFactoryPid() { - return null; + public String getPid() + { + return m_pid; } - public void update() throws IOException { + public Dictionary getProperties() + { + return m_properties; } - public void setBundleLocation(String bundleLocation) { + public void setBundleLocation(String bundleLocation) + { + if (m_bundleLocation != null && !m_bundleLocation.equals(bundleLocation)) + { + throw new RuntimeException("Configuration already bound to location: " + m_bundleLocation + " (trying to set to: " + bundleLocation + ")"); + } m_bundleLocation = bundleLocation; } - public String getBundleLocation() { - return m_bundleLocation; + public void update() throws IOException + { + } + + public void update(Dictionary properties) throws IOException + { + m_properties = properties; } } /** Dummy session. */ - private static class Session implements DeploymentSession { - public DeploymentPackage getTargetDeploymentPackage() { + private static class DeploymentSessionImpl implements DeploymentSession + { + public File getDataFile(Bundle bundle) + { return null; } - public DeploymentPackage getSourceDeploymentPackage() { + + public DeploymentPackage getSourceDeploymentPackage() + { return null; } - public File getDataFile(Bundle bundle) { + + public DeploymentPackage getTargetDeploymentPackage() + { return null; } + + @Override + public String toString() + { + return "Test DeploymentSession @ 0x" + System.identityHashCode(this); + } } - - private static class Logger implements LogService { + + private static class LogServiceImpl implements LogService + { private static final String[] LEVEL = { "", "[ERROR]", "[WARN ]", "[INFO ]", "[DEBUG]" }; private Throwable m_exception; - - public void log(int level, String message) { + + public void failOnException() throws Throwable + { + if (m_exception != null) + { + throw m_exception; + } + } + + public void log(int level, String message) + { System.out.println(LEVEL[level] + " - " + message); } - public void log(int level, String message, Throwable exception) { + public void log(int level, String message, Throwable exception) + { System.out.println(LEVEL[level] + " - " + message + " - " + exception.getMessage()); m_exception = exception; } - public void log(ServiceReference sr, int level, String message) { + public void log(ServiceReference sr, int level, String message) + { System.out.println(LEVEL[level] + " - " + message); } - public void log(ServiceReference sr, int level, String message, Throwable exception) { + public void log(ServiceReference sr, int level, String message, Throwable exception) + { System.out.println(LEVEL[level] + " - " + message + " - " + exception.getMessage()); m_exception = exception; } - - public void failOnException() throws Throwable { - if (m_exception != null) { - throw m_exception; - } - } } - private static class Reference implements ServiceReference { - private final Dictionary m_properties; - public Reference(Dictionary properties) { + private static class ServiceReferenceImpl implements ServiceReference + { + private final Properties m_properties; + + public ServiceReferenceImpl() + { + this(new Properties()); + } + + public ServiceReferenceImpl(Properties properties) + { m_properties = properties; } - public Object getProperty(String key) { - return m_properties.get(key); + public int compareTo(Object reference) + { + return 0; } - public String[] getPropertyKeys() { + public Bundle getBundle() + { return null; } - public Bundle getBundle() { - return null; + public Object getProperty(String key) + { + return m_properties.get(key); + } + + public String[] getPropertyKeys() + { + return Collections.list(m_properties.keys()).toArray(new String[0]); } - public Bundle[] getUsingBundles() { + public Bundle[] getUsingBundles() + { return null; } - public boolean isAssignableTo(Bundle bundle, String className) { + public boolean isAssignableTo(Bundle bundle, String className) + { return false; } - public int compareTo(Object reference) { - return 0; + @Override + public String toString() + { + return "Test ConfigAdmin @ 0x" + System.identityHashCode(this); + } + } + + private File m_tempDir; + private LogServiceImpl m_logger; + + /** Go through a simple session, containing two empty configurations. */ + public void testBasicConfigurationSession() throws Throwable + { + AutoConfResourceProcessor p = createAutoConfRP(); + + createNewSession(p); + String config = "<MetaData xmlns:metatype='http://www.osgi.org/xmlns/metatype/v1.0.0'>\n" + + " <OCD name='ocd' id='ocd'>\n" + + " <AD id='name' type='STRING' cardinality='0' />\n" + + " </OCD>\n" + + " <Designate pid='simple' bundle='osgi-dp:location'>\n" + + " <Object ocdref='ocd'>\n" + + " <Attribute adref='name'>\n" + + " <Value><![CDATA[test]]></Value>\n" + + " </Attribute>\n" + + " </Object>\n" + + " </Designate>\n" + + "</MetaData>\n"; + p.process("basic", new ByteArrayInputStream(config.getBytes())); + p.prepare(); + p.commit(); + p.addConfigurationAdmin(new ServiceReferenceImpl(), new ConfigurationAdminImpl("simple")); + p.postcommit(); + m_logger.failOnException(); + } + + /** Go through a simple session, containing two empty configurations. */ + public void testFilteredConfigurationSession() throws Throwable + { + AutoConfResourceProcessor p = createAutoConfRP(); + + createNewSession(p); + String config = "<MetaData xmlns:metatype='http://www.osgi.org/xmlns/metatype/v1.0.0' filter='(id=42)'>\n" + + " <OCD name='ocd' id='ocd'>\n" + + " <AD id='name' type='STRING' cardinality='0' />\n" + + " </OCD>\n" + + " <Designate pid='simple' bundle='osgi-dp:location'>\n" + + " <Object ocdref='ocd'>\n" + + " <Attribute adref='name'>\n" + + " <Value><![CDATA[test]]></Value>\n" + + " </Attribute>\n" + + " </Object>\n" + + " </Designate>\n" + + "</MetaData>\n"; + p.process("basic", new ByteArrayInputStream(config.getBytes())); + p.prepare(); + p.commit(); + + Properties props = new Properties(); + props.put("id", Integer.valueOf(42)); + + ConfigurationAdminImpl ca1 = new ConfigurationAdminImpl("simple"); + ConfigurationAdminImpl ca2 = new ConfigurationAdminImpl(); + + p.addConfigurationAdmin(new ServiceReferenceImpl(props), ca1); + p.addConfigurationAdmin(new ServiceReferenceImpl(), ca2); + p.postcommit(); + + m_logger.failOnException(); + + assertEquals("test", ca1.m_configs.get("simple").getProperties().get("name")); + assertTrue(ca2.m_configs.isEmpty()); + } + + /** Go through a simple session, containing two empty configurations. */ + public void testMissingMandatoryValueInConfig() throws Throwable + { + AutoConfResourceProcessor p = createAutoConfRP(); + + createNewSession(p); + + String config = "<MetaData xmlns:metatype='http://www.osgi.org/xmlns/metatype/v1.1.0' filter='(id=42)'>\n" + + " <OCD name='ocd' id='ocd'>\n" + + " <AD id='name' type='Integer' />\n" + + " </OCD>\n" + + " <Designate pid='simple' bundle='osgi-dp:location'>\n" + + " <Object ocdref='ocd'>\n" + + " <Attribute adref='name'>\n" + + " <Value><![CDATA[]]></Value>\n" + + " </Attribute>\n" + + " </Object>\n" + + " </Designate>\n" + + "</MetaData>\n"; + + try + { + p.process("missing-value", new ByteArrayInputStream(config.getBytes())); + fail("Expected ResourceProcessorException for missing value!"); } + catch (ResourceProcessorException e) + { + // Ok; expected... + assertEquals("Unable to parse value for definition: adref=name", e.getMessage()); + } + } + + /** Make sure the processor does not accept a 'null' session. */ + public void testNullSession() throws Exception + { + AutoConfResourceProcessor p = new AutoConfResourceProcessor(); + try + { + p.begin(null); + fail("Should have gotten an exception when trying to begin with null session."); + } + catch (Exception e) + { + // expected + } + } + + /** Go through a simple session, containing two empty configurations. */ + public void testSimpleInstallAndUninstallSession() throws Throwable + { + AutoConfResourceProcessor p = createAutoConfRP(); + + createNewSession(p); + + p.process("a", new ByteArrayInputStream("<MetaData />".getBytes())); + p.prepare(); + p.commit(); + p.postcommit(); + m_logger.failOnException(); + + createNewSession(p); + + p.dropAllResources(); + p.prepare(); + p.commit(); + p.postcommit(); + m_logger.failOnException(); + } + + /** Go through a simple session, containing two empty configurations. */ + public void testSimpleSession() throws Throwable + { + AutoConfResourceProcessor p = createAutoConfRP(); + + createNewSession(p); + p.process("a", new ByteArrayInputStream("<MetaData />".getBytes())); + p.process("b", new ByteArrayInputStream("<MetaData />".getBytes())); + p.prepare(); + p.commit(); + p.postcommit(); + m_logger.failOnException(); + } + + /** Tests that we can update an existing configuration and properly handling deleted & updated configurations. */ + public void testUpdateConfigurationSession() throws Throwable + { + AutoConfResourceProcessor p = createAutoConfRP(); + + createNewSession(p); + + String config1 = "<MetaData xmlns:metatype='http://www.osgi.org/xmlns/metatype/v1.0.0'>" + + "<OCD name='ocd1' id='ocd1'>" + + " <AD id='nameA' type='STRING' cardinality='0' />" + + "</OCD>" + + "<OCD name='ocd2' id='ocd2'>" + + " <AD id='nameB' type='STRING' cardinality='0' />" + + "</OCD>" + + "<Designate pid='pid2' bundle='osgi-dp:location2'>" + + " <Object ocdref='ocd2'>" + + " <Attribute adref='nameB'>" + + " <Value><![CDATA[test2]]></Value>" + + " </Attribute>" + + " </Object>" + + "</Designate>" + + "<Designate pid='pid1' bundle='osgi-dp:location1'>" + + " <Object ocdref='ocd1'>" + + " <Attribute adref='nameA'>" + + " <Value><![CDATA[test1]]></Value>" + + " </Attribute>" + + " </Object>" + + "</Designate>" + + "</MetaData>"; + + ConfigurationAdminImpl ca = new ConfigurationAdminImpl("pid1", "pid2", "pid3"); + + p.process("update", new ByteArrayInputStream(config1.getBytes())); + p.prepare(); + p.commit(); + p.addConfigurationAdmin(new ServiceReferenceImpl(), ca); + p.postcommit(); + m_logger.failOnException(); + + assertEquals(2, ca.m_configs.size()); + assertTrue(ca.m_configs.containsKey("pid1")); + assertFalse(ca.m_configs.get("pid1").m_deleted); + assertEquals("test1", ca.m_configs.get("pid1").getProperties().get("nameA")); + + assertTrue(ca.m_configs.containsKey("pid2")); + assertFalse(ca.m_configs.get("pid2").m_deleted); + assertEquals("test2", ca.m_configs.get("pid2").getProperties().get("nameB")); + + String config2 = "<MetaData xmlns:metatype='http://www.osgi.org/xmlns/metatype/v1.0.0'>" + + "<OCD name='ocd3' id='ocd3'>" + + " <AD id='nameC' type='STRING' cardinality='0' />" + + "</OCD>" + + "<OCD name='ocd2' id='ocd2'>" + + " <AD id='nameB' type='STRING' cardinality='0' />" + + "</OCD>" + + "<Designate pid='pid2' bundle='osgi-dp:location2'>" + + " <Object ocdref='ocd2'>" + + " <Attribute adref='nameB'>" + + " <Value><![CDATA[test4]]></Value>" + + " </Attribute>" + + " </Object>" + + "</Designate>" + + "<Designate pid='pid3' bundle='osgi-dp:location3'>" + + " <Object ocdref='ocd3'>" + + " <Attribute adref='nameC'>" + + " <Value><![CDATA[test3]]></Value>" + + " </Attribute>" + + " </Object>" + + "</Designate>" + + "</MetaData>"; + + createNewSession(p); + + p.process("update", new ByteArrayInputStream(config2.getBytes())); + p.prepare(); + p.commit(); + p.addConfigurationAdmin(new ServiceReferenceImpl(), ca); + p.postcommit(); + m_logger.failOnException(); + + assertEquals(3, ca.m_configs.size()); + assertTrue(ca.m_configs.containsKey("pid1")); + assertTrue(ca.m_configs.get("pid1").m_deleted); + assertEquals("test1", ca.m_configs.get("pid1").getProperties().get("nameA")); + + assertTrue(ca.m_configs.containsKey("pid2")); + assertFalse(ca.m_configs.get("pid2").m_deleted); + assertEquals("test4", ca.m_configs.get("pid2").getProperties().get("nameB")); + + assertTrue(ca.m_configs.containsKey("pid3")); + assertFalse(ca.m_configs.get("pid3").m_deleted); + assertEquals("test3", ca.m_configs.get("pid3").getProperties().get("nameC")); + } + + @Override + protected void setUp() throws IOException + { + m_tempDir = File.createTempFile("persistence", "dir"); + m_tempDir.delete(); + m_tempDir.mkdirs(); + + m_logger = new LogServiceImpl(); + } + + @Override + protected void tearDown() throws Exception + { + Utils.removeDirectoryWithContent(m_tempDir); + } + + private AutoConfResourceProcessor createAutoConfRP() + { + AutoConfResourceProcessor p = new AutoConfResourceProcessor(); + Utils.configureObject(p, LogService.class, m_logger); + Utils.configureObject(p, DependencyManager.class, createMockDM()); + Utils.configureObject(p, PersistencyManager.class, new PersistencyManager(m_tempDir)); + return p; + } + + @SuppressWarnings("unused") + private BundleContext createMockBundleContext() + { + return Utils.createMockObjectAdapter(BundleContext.class, new Object() + { + public Filter createFilter(String condition) + { + return Utils.createMockObjectAdapter(Filter.class, new Object() + { + public boolean match(ServiceReference ref) + { + Object id = ref.getProperty("id"); + if (id != null && id.equals(Integer.valueOf(42))) + { + return true; + } + return false; + } + + public void remove(Component service) + { + } + }); + } + }); + } + + @SuppressWarnings("unused") + private Component createMockComponent() + { + return Utils.createMockObjectAdapter(Component.class, new Object() + { + public DependencyManager getDependencyManager() + { + return new DependencyManager(createMockBundleContext()); + } + }); + } + + private DependencyManager createMockDM() + { + return new DependencyManager(createMockBundleContext()) + { + public void remove(Component service) + { + } + }; + } + + private DeploymentSession createNewSession(AutoConfResourceProcessor p) + { + DeploymentSessionImpl s = new DeploymentSessionImpl(); + p.begin(s); + Utils.configureObject(p, Component.class, createMockComponent()); + return s; } }
Modified: felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/DefaultNullObject.java URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/DefaultNullObject.java?rev=1724802&r1=1724801&r2=1724802&view=diff ============================================================================== --- felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/DefaultNullObject.java (original) +++ felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/DefaultNullObject.java Fri Jan 15 13:34:41 2016 @@ -21,14 +21,14 @@ package org.apache.felix.deployment.rp.a import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; - /** * Default null object implementation. Uses a dynamic proxy. Null objects are used * as placeholders for services that are not available. * * @author <a href="mailto:[email protected]">Felix Project Team</a> */ -public class DefaultNullObject implements InvocationHandler { +public class DefaultNullObject implements InvocationHandler +{ private static final Boolean DEFAULT_BOOLEAN = Boolean.FALSE; private static final Byte DEFAULT_BYTE = new Byte((byte) 0); private static final Short DEFAULT_SHORT = new Short((short) 0); @@ -36,35 +36,44 @@ public class DefaultNullObject implement private static final Long DEFAULT_LONG = new Long(0); private static final Float DEFAULT_FLOAT = new Float(0.0f); private static final Double DEFAULT_DOUBLE = new Double(0.0); - + /** * Invokes a method on this null object. The method will return a default * value without doing anything. */ - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable + { Class returnType = method.getReturnType(); - if (returnType.equals(Boolean.class) || returnType.equals(Boolean.TYPE)) { + if (returnType.equals(Boolean.class) || returnType.equals(Boolean.TYPE)) + { return DEFAULT_BOOLEAN; } - else if (returnType.equals(Byte.class) || returnType.equals(Byte.TYPE)) { + else if (returnType.equals(Byte.class) || returnType.equals(Byte.TYPE)) + { return DEFAULT_BYTE; - } - else if (returnType.equals(Short.class) || returnType.equals(Short.TYPE)) { + } + else if (returnType.equals(Short.class) || returnType.equals(Short.TYPE)) + { return DEFAULT_SHORT; - } - else if (returnType.equals(Integer.class) || returnType.equals(Integer.TYPE)) { + } + else if (returnType.equals(Integer.class) || returnType.equals(Integer.TYPE)) + { return DEFAULT_INT; - } - else if (returnType.equals(Long.class) || returnType.equals(Long.TYPE)) { + } + else if (returnType.equals(Long.class) || returnType.equals(Long.TYPE)) + { return DEFAULT_LONG; - } - else if (returnType.equals(Float.class) || returnType.equals(Float.TYPE)) { + } + else if (returnType.equals(Float.class) || returnType.equals(Float.TYPE)) + { return DEFAULT_FLOAT; - } - else if (returnType.equals(Double.class) || returnType.equals(Double.TYPE)) { + } + else if (returnType.equals(Double.class) || returnType.equals(Double.TYPE)) + { return DEFAULT_DOUBLE; - } - else { + } + else + { return null; } } Added: felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/PersistencyManagerTest.java URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/PersistencyManagerTest.java?rev=1724802&view=auto ============================================================================== --- felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/PersistencyManagerTest.java (added) +++ felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/PersistencyManagerTest.java Fri Jan 15 13:34:41 2016 @@ -0,0 +1,99 @@ +/* + * 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.deployment.rp.autoconf; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.Hashtable; + +import org.osgi.framework.Filter; +import org.osgi.framework.FrameworkUtil; + +import junit.framework.TestCase; + +/** + * Test cases for {@link PersistencyManager}. + */ +public class PersistencyManagerTest extends TestCase +{ + private File m_tempDir; + + public void testHandleNonExistingDirectory() throws Exception + { + PersistencyManager pm = new PersistencyManager(new File("/does/not/exist")); + assertNotNull(pm); + + assertEquals(0, pm.getResourceNames().size()); + } + + public void testHandleEmptyExistingDirectory() throws Exception + { + PersistencyManager pm = new PersistencyManager(m_tempDir); + assertNotNull(pm); + + assertEquals(0, pm.getResourceNames().size()); + } + + public void testLoadNonExistingResource() throws Exception + { + PersistencyManager pm = new PersistencyManager(m_tempDir); + assertEquals(0, pm.load("doesNotExist").size()); + } + + public void testSaveResourceWithoutFilter() throws Exception + { + AutoConfResource res1 = new AutoConfResource("res1", "pid1", null, "osgi-dp:locationA", false, new Hashtable<String, Object>(), null); + AutoConfResource res2 = new AutoConfResource("res2", "pid2", null, "osgi-dp:locationB", false, new Hashtable<String, Object>(), null); + + PersistencyManager pm = new PersistencyManager(m_tempDir); + pm.store("test1", Arrays.asList(res1, res2)); + + assertEquals(2, pm.load("test1").size()); + } + + public void testSaveResourceWithFilter() throws Exception + { + Filter f = FrameworkUtil.createFilter("(name=test)"); + + AutoConfResource res1 = new AutoConfResource("res1", "pid1", null, "osgi-dp:locationA", false, new Hashtable<String, Object>(), f); + AutoConfResource res2 = new AutoConfResource("res2", "pid2", null, "osgi-dp:locationB", false, new Hashtable<String, Object>(), null); + + PersistencyManager pm = new PersistencyManager(m_tempDir); + pm.store("test1", Arrays.asList(res1, res2)); + + assertEquals(2, pm.load("test1").size()); + } + + @Override + protected void setUp() throws IOException + { + m_tempDir = File.createTempFile("persistence", "dir"); + m_tempDir.delete(); + m_tempDir.mkdirs(); + } + + @Override + protected void tearDown() throws Exception + { + Utils.removeDirectoryWithContent(m_tempDir); + } + +} Propchange: felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/PersistencyManagerTest.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/Utils.java URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/Utils.java?rev=1724802&r1=1724801&r2=1724802&view=diff ============================================================================== --- felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/Utils.java (original) +++ felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/Utils.java Fri Jan 15 13:34:41 2016 @@ -28,14 +28,16 @@ import java.lang.reflect.Proxy; /** * Utility class that injects dependencies. Can be used to unit test service implementations. */ -public class Utils { +public class Utils +{ /** * Configures an object to use a null object for the specified service interface. * * @param object the object * @param iface the service interface */ - public static void configureObject(Object object, Class iface) { + public static void configureObject(Object object, Class iface) + { configureObject(object, iface, createNullObject(iface)); } @@ -45,8 +47,9 @@ public class Utils { * @param iface the service interface * @return a null object */ - public static Object createNullObject(Class iface) { - return Proxy.newProxyInstance(iface.getClassLoader(), new Class[] { iface }, new DefaultNullObject()); + public static <T> T createNullObject(Class<T> iface) + { + return (T) Proxy.newProxyInstance(iface.getClassLoader(), new Class[] { iface }, new DefaultNullObject()); } /** @@ -57,19 +60,24 @@ public class Utils { * @param handler the handler to pass invocations to. * @return an adapter that will try to pass on received invocations to the given handler */ - public static Object createMockObjectAdapter(Class iface, final Object handler) { - return Proxy.newProxyInstance(iface.getClassLoader(), new Class[] { iface }, new DefaultNullObject() { - - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - try { + public static <T> T createMockObjectAdapter(Class<T> iface, final Object handler) + { + return (T) Proxy.newProxyInstance(iface.getClassLoader(), new Class[] { iface }, new DefaultNullObject() + { + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable + { + try + { Method bridge = handler.getClass().getMethod(method.getName(), method.getParameterTypes()); bridge.setAccessible(true); return bridge.invoke(handler, args); } - catch (NoSuchMethodException ex) { + catch (NoSuchMethodException ex) + { return super.invoke(proxy, method, args); } - catch (InvocationTargetException ex) { + catch (InvocationTargetException ex) + { throw ex.getCause(); } } @@ -83,21 +91,28 @@ public class Utils { * @param iface the service interface * @param instance the implementation */ - public static void configureObject(Object object, Class iface, Object instance) { + public static void configureObject(Object object, Class iface, Object instance) + { Class serviceClazz = object.getClass(); - while (serviceClazz != null) { + while (serviceClazz != null) + { Field[] fields = serviceClazz.getDeclaredFields(); AccessibleObject.setAccessible(fields, true); - for (int j = 0; j < fields.length; j++) { - if (fields[j].getType().equals(iface)) { - try { + for (int j = 0; j < fields.length; j++) + { + if (fields[j].getType().equals(iface)) + { + try + { // synchronized makes sure the field is actually written to immediately - synchronized (new Object()) { + synchronized (new Object()) + { fields[j].set(object, instance); } } - catch (Exception e) { + catch (Exception e) + { throw new IllegalStateException("Could not set field " + fields[j].getName() + " on " + object); } } @@ -105,20 +120,24 @@ public class Utils { serviceClazz = serviceClazz.getSuperclass(); } } - + /** * Remove the given directory and all it's files and subdirectories * * @param directory the name of the directory to remove */ - public static void removeDirectoryWithContent(File directory) { - if ((directory == null) || !directory.exists()) { + public static void removeDirectoryWithContent(File directory) + { + if ((directory == null) || !directory.exists()) + { return; } File[] filesAndSubDirs = directory.listFiles(); - for (int i=0; i < filesAndSubDirs.length; i++) { + for (int i = 0; i < filesAndSubDirs.length; i++) + { File file = filesAndSubDirs[i]; - if (file.isDirectory()) { + if (file.isDirectory()) + { removeDirectoryWithContent(file); } // else just remove the file
