Return-Path: X-Original-To: apmail-felix-commits-archive@www.apache.org Delivered-To: apmail-felix-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 6899A9DC8 for ; Tue, 7 Feb 2012 19:19:11 +0000 (UTC) Received: (qmail 15911 invoked by uid 500); 7 Feb 2012 19:19:11 -0000 Delivered-To: apmail-felix-commits-archive@felix.apache.org Received: (qmail 15853 invoked by uid 500); 7 Feb 2012 19:19:10 -0000 Mailing-List: contact commits-help@felix.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@felix.apache.org Delivered-To: mailing list commits@felix.apache.org Received: (qmail 15846 invoked by uid 99); 7 Feb 2012 19:19:10 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 07 Feb 2012 19:19:10 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 07 Feb 2012 19:19:05 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 2F00A2388865 for ; Tue, 7 Feb 2012 19:18:44 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1241559 - in /felix/trunk/deploymentadmin/autoconf/src/test: ./ java/ java/org/ java/org/apache/ java/org/apache/felix/ java/org/apache/felix/deployment/ java/org/apache/felix/deployment/rp/ java/org/apache/felix/deployment/rp/autoconf/ Date: Tue, 07 Feb 2012 19:18:44 -0000 To: commits@felix.apache.org From: marrs@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20120207191844.2F00A2388865@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: marrs Date: Tue Feb 7 19:18:43 2012 New Revision: 1241559 URL: http://svn.apache.org/viewvc?rev=1241559&view=rev Log: FELIX-3329 FELIX-3330 Added a couple of test cases to validate some of the basic operations in this resource processor. Added: felix/trunk/deploymentadmin/autoconf/src/test/ felix/trunk/deploymentadmin/autoconf/src/test/java/ felix/trunk/deploymentadmin/autoconf/src/test/java/org/ felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/ felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/ felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/ felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/ felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/ felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/AutoConfResourceProcessorTest.java (with props) felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/DefaultNullObject.java (with props) felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/TestUtils.java (with props) Added: 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=1241559&view=auto ============================================================================== --- felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/AutoConfResourceProcessorTest.java (added) +++ felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/AutoConfResourceProcessorTest.java Tue Feb 7 19:18:43 2012 @@ -0,0 +1,386 @@ +/* + * 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.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.util.Dictionary; +import java.util.Properties; + +import junit.framework.TestCase; + +import org.apache.felix.dm.Component; +import org.apache.felix.dm.DependencyManager; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.Filter; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceReference; +import org.osgi.service.cm.Configuration; +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.deploymentadmin.DeploymentPackage; +import org.osgi.service.deploymentadmin.spi.DeploymentSession; +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."); + } + catch (Exception e) { + // expected + } + } + + /** Go through a simple session, containing two empty configurations. */ + public void testSimpleSession() throws Exception { + AutoConfResourceProcessor p = new AutoConfResourceProcessor(); + TestUtils.configureObject(p, LogService.class); + TestUtils.configureObject(p, Component.class, TestUtils.createMockObjectAdapter(Component.class, new Object() { + public DependencyManager getDependencyManager() { + return new DependencyManager((BundleContext) TestUtils.createNullObject(BundleContext.class)); + } + })); + File tempDir = File.createTempFile("persistence", "dir"); + tempDir.delete(); + tempDir.mkdirs(); + + System.out.println("Temporary dir: " + tempDir); + + TestUtils.configureObject(p, PersistencyManager.class, new PersistencyManager(tempDir)); + Session s = new Session(); + p.begin(s); + p.process("a", new ByteArrayInputStream("".getBytes())); + p.process("b", new ByteArrayInputStream("".getBytes())); + p.prepare(); + p.commit(); + p.postcommit(); + TestUtils.removeDirectoryWithContent(tempDir); + } + + /** Go through a simple session, containing two empty configurations. */ + public void testSimpleInstallAndUninstallSession() throws Throwable { + AutoConfResourceProcessor p = new AutoConfResourceProcessor(); + TestUtils.configureObject(p, LogService.class); + TestUtils.configureObject(p, Component.class, TestUtils.createMockObjectAdapter(Component.class, new Object() { + public DependencyManager getDependencyManager() { + return new DependencyManager((BundleContext) TestUtils.createNullObject(BundleContext.class)); + } + })); + Logger logger = new Logger(); + TestUtils.configureObject(p, LogService.class, logger); + File tempDir = File.createTempFile("persistence", "dir"); + tempDir.delete(); + tempDir.mkdirs(); + + System.out.println("Temporary dir: " + tempDir); + + TestUtils.configureObject(p, PersistencyManager.class, new PersistencyManager(tempDir)); + Session s = new Session(); + p.begin(s); + p.process("a", new ByteArrayInputStream("".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(); + TestUtils.removeDirectoryWithContent(tempDir); + } + + /** Go through a simple session, containing two empty configurations. */ + public void testBasicConfigurationSession() throws Throwable { + AutoConfResourceProcessor p = new AutoConfResourceProcessor(); + Logger logger = new Logger(); + TestUtils.configureObject(p, LogService.class, logger); + TestUtils.configureObject(p, Component.class, TestUtils.createMockObjectAdapter(Component.class, new Object() { + public DependencyManager getDependencyManager() { + return new DependencyManager((BundleContext) TestUtils.createNullObject(BundleContext.class)); + } + })); + File tempDir = File.createTempFile("persistence", "dir"); + tempDir.delete(); + tempDir.mkdirs(); + + System.out.println("Temporary dir: " + tempDir); + + TestUtils.configureObject(p, PersistencyManager.class, new PersistencyManager(tempDir)); + Session s = new Session(); + p.begin(s); + String config = + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "\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(); + TestUtils.removeDirectoryWithContent(tempDir); + } + + /** Go through a simple session, containing two empty configurations. */ + public void testFilteredConfigurationSession() throws Throwable { + AutoConfResourceProcessor p = new AutoConfResourceProcessor(); + Logger logger = new Logger(); + TestUtils.configureObject(p, LogService.class, logger); + TestUtils.configureObject(p, Component.class, TestUtils.createMockObjectAdapter(Component.class, new Object() { + public DependencyManager getDependencyManager() { + return new DependencyManager((BundleContext) TestUtils.createNullObject(BundleContext.class)); + } + })); + TestUtils.configureObject(p, BundleContext.class, TestUtils.createMockObjectAdapter(BundleContext.class, new Object() { + public Filter createFilter(String condition) { + return (Filter) TestUtils.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; + } + }); + } + })); + File tempDir = File.createTempFile("persistence", "dir"); + tempDir.delete(); + tempDir.mkdirs(); + + System.out.println("Temporary dir: " + tempDir); + + TestUtils.configureObject(p, PersistencyManager.class, new PersistencyManager(tempDir)); + Session s = new Session(); + p.begin(s); + String config = + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "\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; + } + }); + p.postcommit(); + logger.failOnException(); + assertEquals("test", configuration.getProperties().get("name")); + assertNull(emptyConfiguration.getProperties()); + TestUtils.removeDirectoryWithContent(tempDir); + } + + private static class ConfigurationImpl implements Configuration { + private String m_bundleLocation = "osgi-dp:location"; + private Dictionary m_properties; + + public String getPid() { + return null; + } + + public Dictionary getProperties() { + return m_properties; + } + + public void update(Dictionary properties) throws IOException { + m_properties = properties; + } + + public void delete() throws IOException { + } + + public String getFactoryPid() { + return null; + } + + public void update() throws IOException { + } + + public void setBundleLocation(String bundleLocation) { + m_bundleLocation = bundleLocation; + } + + public String getBundleLocation() { + return m_bundleLocation; + } + } + + /** Dummy session. */ + private static class Session implements DeploymentSession { + public DeploymentPackage getTargetDeploymentPackage() { + return null; + } + public DeploymentPackage getSourceDeploymentPackage() { + return null; + } + public File getDataFile(Bundle bundle) { + return null; + } + } + + private static class Logger implements LogService { + private static final String[] LEVEL = { "", "[ERROR]", "[WARN ]", "[INFO ]", "[DEBUG]" }; + private Throwable m_exception; + + public void log(int level, String message) { + System.out.println(LEVEL[level] + " - " + message); + } + + 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) { + System.out.println(LEVEL[level] + " - " + message); + } + + 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) { + m_properties = properties; + } + + public Object getProperty(String key) { + return m_properties.get(key); + } + + public String[] getPropertyKeys() { + return null; + } + + public Bundle getBundle() { + return null; + } + + public Bundle[] getUsingBundles() { + return null; + } + + public boolean isAssignableTo(Bundle bundle, String className) { + return false; + } + + public int compareTo(Object reference) { + return 0; + } + } +} Propchange: felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/AutoConfResourceProcessorTest.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: 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=1241559&view=auto ============================================================================== --- felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/DefaultNullObject.java (added) +++ felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/DefaultNullObject.java Tue Feb 7 19:18:43 2012 @@ -0,0 +1,71 @@ +/* + * 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.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 Felix Project Team + */ +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); + private static final Integer DEFAULT_INT = new Integer(0); + 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 { + Class returnType = method.getReturnType(); + if (returnType.equals(Boolean.class) || returnType.equals(Boolean.TYPE)) { + return DEFAULT_BOOLEAN; + } + else if (returnType.equals(Byte.class) || returnType.equals(Byte.TYPE)) { + return DEFAULT_BYTE; + } + else if (returnType.equals(Short.class) || returnType.equals(Short.TYPE)) { + return DEFAULT_SHORT; + } + else if (returnType.equals(Integer.class) || returnType.equals(Integer.TYPE)) { + return DEFAULT_INT; + } + else if (returnType.equals(Long.class) || returnType.equals(Long.TYPE)) { + return DEFAULT_LONG; + } + else if (returnType.equals(Float.class) || returnType.equals(Float.TYPE)) { + return DEFAULT_FLOAT; + } + else if (returnType.equals(Double.class) || returnType.equals(Double.TYPE)) { + return DEFAULT_DOUBLE; + } + else { + return null; + } + } +} \ No newline at end of file Propchange: felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/DefaultNullObject.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/TestUtils.java URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/TestUtils.java?rev=1241559&view=auto ============================================================================== --- felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/TestUtils.java (added) +++ felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/TestUtils.java Tue Feb 7 19:18:43 2012 @@ -0,0 +1,129 @@ +/* + * 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.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +/** + * Utility class that injects dependencies. Can be used to unit test service implementations. + */ +public class TestUtils { + /** + * 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) { + configureObject(object, iface, createNullObject(iface)); + } + + /** + * Creates a null object for a service interface. + * + * @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()); + } + + /** + * Wraps the given handler in an adapter that will try to pass on received invocations to the hander if that has + * an applicable methods else it defaults to a NullObject. + * + * @param iface the service interface + * @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 { + Method bridge = handler.getClass().getMethod(method.getName(), method.getParameterTypes()); + bridge.setAccessible(true); + return bridge.invoke(handler, args); + } + catch (NoSuchMethodException ex) { + return super.invoke(proxy, method, args); + } + catch (InvocationTargetException ex) { + throw ex.getCause(); + } + } + }); + } + + /** + * Configures an object to use a specific implementation for the specified service interface. + * + * @param object the object + * @param iface the service interface + * @param instance the implementation + */ + public static void configureObject(Object object, Class iface, Object instance) { + Class serviceClazz = object.getClass(); + + 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 { + // synchronized makes sure the field is actually written to immediately + synchronized (new Object()) { + fields[j].set(object, instance); + } + } + catch (Exception e) { + throw new IllegalStateException("Could not set field " + fields[j].getName() + " on " + object); + } + } + } + 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()) { + return; + } + File[] filesAndSubDirs = directory.listFiles(); + for (int i=0; i < filesAndSubDirs.length; i++) { + File file = filesAndSubDirs[i]; + if (file.isDirectory()) { + removeDirectoryWithContent(file); + } + // else just remove the file + file.delete(); + } + directory.delete(); + } +} Propchange: felix/trunk/deploymentadmin/autoconf/src/test/java/org/apache/felix/deployment/rp/autoconf/TestUtils.java ------------------------------------------------------------------------------ svn:mime-type = text/plain