Merge "Bug-1520 Config subsystem:config-impl tests"
authorEd Warnicke <eaw@cisco.com>
Fri, 15 Aug 2014 12:03:22 +0000 (12:03 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Fri, 15 Aug 2014 12:03:22 +0000 (12:03 +0000)
15 files changed:
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BlankTransactionServiceTracker.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ModuleFactoryBundleTracker.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/InterfacesHelper.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/ModuleQNameUtil.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/OsgiRegistrationUtil.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/BlankTransactionServiceTrackerTest.java [new file with mode: 0644]
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/BundleContextBackedModuleFactoriesResolverTest.java [new file with mode: 0644]
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/ExtensibleBundleTrackerTest.java [new file with mode: 0644]
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/ModuleFactoryBundleTrackerTest.java [new file with mode: 0644]
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/InterfacesHelperTest.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/OsgiRegistrationUtilTest.java [new file with mode: 0644]
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/AbstractTestingFixedThreadPoolModuleFactory.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/test/SimpleConfigurationTest.java
opendaylight/config/config-manager/src/test/resources/module-factories/module-factory-fail [new file with mode: 0644]
opendaylight/config/config-manager/src/test/resources/module-factories/module-factory-ok [new file with mode: 0644]

index 720b7197ea6100b0890ee0fd4a89d5f5de9157bd..375ef5948712f3bcc5dc803802645b1d6fa56103 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.controller.config.manager.impl.osgi;
 
+import com.google.common.annotations.VisibleForTesting;
+import javax.management.ObjectName;
 import org.opendaylight.controller.config.api.ConflictingVersionException;
 import org.opendaylight.controller.config.api.ValidationException;
 import org.opendaylight.controller.config.api.jmx.CommitStatus;
@@ -17,8 +19,6 @@ import org.osgi.util.tracker.ServiceTrackerCustomizer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.management.ObjectName;
-
 /**
  * Every time factory is added or removed, blank transaction is triggered to handle
  * {@link org.opendaylight.controller.config.spi.ModuleFactory#getDefaultModules(org.opendaylight.controller.config.api.DependencyResolverFactory, org.osgi.framework.BundleContext)}
@@ -27,10 +27,29 @@ import javax.management.ObjectName;
 public class BlankTransactionServiceTracker implements ServiceTrackerCustomizer<ModuleFactory, Object> {
     private static final Logger logger = LoggerFactory.getLogger(BlankTransactionServiceTracker.class);
 
-    private final ConfigRegistryImpl configRegistry;
+    public static final int DEFAULT_MAX_ATTEMPTS = 10;
 
-    public BlankTransactionServiceTracker(ConfigRegistryImpl configRegistry) {
-        this.configRegistry = configRegistry;
+    private final BlankTransaction blankTransaction;
+    private int maxAttempts;
+
+    public BlankTransactionServiceTracker(final ConfigRegistryImpl configRegistry) {
+        this(new BlankTransaction() {
+            @Override
+            public CommitStatus hit() throws ValidationException, ConflictingVersionException {
+                ObjectName tx = configRegistry.beginConfig(true);
+                return configRegistry.commitConfig(tx);
+            }
+        });
+    }
+
+    public BlankTransactionServiceTracker(final BlankTransaction blankTransaction) {
+        this(blankTransaction, DEFAULT_MAX_ATTEMPTS);
+    }
+
+    @VisibleForTesting
+    BlankTransactionServiceTracker(final BlankTransaction blankTx, final int maxAttempts) {
+        this.blankTransaction = blankTx;
+        this.maxAttempts = maxAttempts;
     }
 
     @Override
@@ -42,13 +61,10 @@ public class BlankTransactionServiceTracker implements ServiceTrackerCustomizer<
     synchronized void blankTransaction() {
         // race condition check: config-persister might push new configuration while server is starting up.
         ConflictingVersionException lastException = null;
-        int maxAttempts = 10;
         for (int i = 0; i < maxAttempts; i++) {
             try {
                 // create transaction
-                boolean blankTransaction = true;
-                ObjectName tx = configRegistry.beginConfig(blankTransaction);
-                CommitStatus commitStatus = configRegistry.commitConfig(tx);
+                CommitStatus commitStatus = blankTransaction.hit();
                 logger.debug("Committed blank transaction with status {}", commitStatus);
                 return;
             } catch (ConflictingVersionException e) {
@@ -77,4 +93,9 @@ public class BlankTransactionServiceTracker implements ServiceTrackerCustomizer<
     public void removedService(ServiceReference<ModuleFactory> moduleFactoryServiceReference, Object o) {
         blankTransaction();
     }
+
+    @VisibleForTesting
+    static interface BlankTransaction {
+        CommitStatus hit() throws ValidationException, ConflictingVersionException;
+    }
 }
index 05ca43c3e2d88e01ea9458fc15bc621a0cd9daa4..3015ed229e28f1c04015d9d488d641c9ebceb161 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.controller.config.manager.impl.osgi;
 
 import static java.lang.String.format;
 
+import com.google.common.annotations.VisibleForTesting;
 import java.io.InputStream;
 import java.net.URL;
 import java.util.List;
@@ -70,9 +71,10 @@ public class ModuleFactoryBundleTracker implements BundleTrackerCustomizer<Objec
         blankTransactionServiceTracker.blankTransaction();
     }
 
-    // TODO:test
-    private static ServiceRegistration<?> registerFactory(String factoryClassName, Bundle bundle) {
+    @VisibleForTesting
+    protected static ServiceRegistration<?> registerFactory(String factoryClassName, Bundle bundle) {
         String errorMessage;
+        Exception ex = null;
         try {
             Class<?> clazz = bundle.loadClass(factoryClassName);
             if (ModuleFactory.class.isAssignableFrom(clazz)) {
@@ -86,10 +88,12 @@ public class ModuleFactoryBundleTracker implements BundleTrackerCustomizer<Objec
                     errorMessage = logMessage(
                             "Could not instantiate {} in bundle {}, reason {}",
                             factoryClassName, bundle, e);
+                    ex = e;
                 } catch (IllegalAccessException e) {
                     errorMessage = logMessage(
-                            "Illegal access during instatiation of class {} in bundle {}, reason {}",
+                            "Illegal access during instantiation of class {} in bundle {}, reason {}",
                             factoryClassName, bundle, e);
+                    ex = e;
                 }
             } else {
                 errorMessage = logMessage(
@@ -98,10 +102,12 @@ public class ModuleFactoryBundleTracker implements BundleTrackerCustomizer<Objec
             }
         } catch (ClassNotFoundException e) {
             errorMessage = logMessage(
-                    "Could not find class {} in bunde {}, reason {}",
+                    "Could not find class {} in bundle {}, reason {}",
                     factoryClassName, bundle, e);
+            ex = e;
         }
-        throw new IllegalStateException(errorMessage);
+
+        throw ex == null ? new IllegalStateException(errorMessage) : new IllegalStateException(errorMessage, ex);
     }
 
     public static String logMessage(String slfMessage, Object... params) {
index a6e9b1ba965b8532eb2e688742ca6ec66c5d5e10..510fdf9373f46a7dc0c5f1aa61aabd15d31fbb25 100644 (file)
@@ -109,7 +109,6 @@ public class InterfacesHelper {
      */
     public static Set<Class<?>> getOsgiRegistrationTypes(
             Class<? extends Module> configBeanClass) {
-        // TODO test with service interface hierarchy
         Set<Class<?>> serviceInterfaces = getServiceInterfaces(configBeanClass);
         Set<Class<?>> result = new HashSet<>();
         for (Class<?> clazz : serviceInterfaces) {
index e84337756e4ad6a74200ce1cd60293848b59d3ab..f1072a76ae907d934d13984478c119092c9f0dbd 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.controller.config.manager.impl.util;
 
 import org.opendaylight.controller.config.spi.ModuleFactory;
 import org.opendaylight.yangtools.yang.binding.annotations.ModuleQName;
+import org.opendaylight.yangtools.yang.common.QName;
 import org.osgi.framework.BundleContext;
 
 import java.util.HashSet;
@@ -31,9 +32,7 @@ public class ModuleQNameUtil {
                 inspected = inspected.getSuperclass();
             }
             if (annotation != null) {
-                // FIXME
-                String qName = "(" + annotation.namespace() + "?revision=" + annotation.revision() + ")" + annotation.name();
-                result.add(qName);
+                result.add(QName.create(annotation.namespace(), annotation.revision(), annotation.name()).toString());
             }
         }
         return result;
index 8873596642e43a8c460a8ee18fb7ef5fef8e9733..2df28f0a154b8b7a6e37f1930b5e06d46efda675 100644 (file)
@@ -8,6 +8,11 @@
 
 package org.opendaylight.controller.config.manager.impl.util;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.util.tracker.BundleTracker;
@@ -15,12 +20,6 @@ import org.osgi.util.tracker.ServiceTracker;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.ListIterator;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
 public class OsgiRegistrationUtil {
     private static final Logger logger = LoggerFactory.getLogger(OsgiRegistrationUtil.class);
 
diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/BlankTransactionServiceTrackerTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/BlankTransactionServiceTrackerTest.java
new file mode 100644 (file)
index 0000000..471c98a
--- /dev/null
@@ -0,0 +1,83 @@
+package org.opendaylight.controller.config.manager.impl.osgi;
+
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertSame;
+import static junit.framework.Assert.fail;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import java.util.Collections;
+import javax.management.ObjectName;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.api.ValidationException;
+import org.opendaylight.controller.config.api.jmx.CommitStatus;
+import org.opendaylight.controller.config.spi.ModuleFactory;
+import org.osgi.framework.ServiceReference;
+
+public class BlankTransactionServiceTrackerTest {
+
+    @Mock
+    private BlankTransactionServiceTracker.BlankTransaction blankTx;
+    private BlankTransactionServiceTracker tracker;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        doReturn(new CommitStatus(Collections.<ObjectName>emptyList(), Collections.<ObjectName>emptyList(), Collections.<ObjectName>emptyList())).when(blankTx).hit();
+        tracker = new BlankTransactionServiceTracker(blankTx);
+    }
+
+    @Test
+    public void testBlankTransaction() throws Exception {
+        tracker.addingService(getMockServiceReference());
+        tracker.modifiedService(getMockServiceReference(), null);
+        tracker.removedService(getMockServiceReference(), null);
+        verify(blankTx, times(3)).hit();
+    }
+
+    @Test
+    public void testValidationException() throws Exception {
+        IllegalArgumentException argumentException = new IllegalArgumentException();
+        ValidationException validationException = ValidationException.createForSingleException(new ModuleIdentifier("m", "i"), argumentException);
+        doThrow(validationException).when(blankTx).hit();
+        try {
+            tracker.addingService(getMockServiceReference());
+        } catch (Exception e) {
+            verify(blankTx, times(1)).hit();
+            assertNotNull(e.getCause());
+            assertSame(validationException, e.getCause());
+            return;
+        }
+
+        fail("Exception should have occurred for validation exception");
+    }
+
+    @Test
+    public void testConflictingException() throws Exception {
+        int maxAttempts = 2;
+        tracker = new BlankTransactionServiceTracker(blankTx, maxAttempts);
+
+        final ConflictingVersionException ex = new ConflictingVersionException();
+        doThrow(ex).when(blankTx).hit();
+        try {
+            tracker.addingService(getMockServiceReference());
+        } catch (Exception e) {
+            verify(blankTx, times(maxAttempts)).hit();
+            return;
+        }
+
+        fail("Exception should have occurred for conflicting exception");
+    }
+
+    private ServiceReference<ModuleFactory> getMockServiceReference() {
+        return mock(ServiceReference.class);
+    }
+}
diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/BundleContextBackedModuleFactoriesResolverTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/BundleContextBackedModuleFactoriesResolverTest.java
new file mode 100644 (file)
index 0000000..dc3dedd
--- /dev/null
@@ -0,0 +1,104 @@
+package org.opendaylight.controller.config.manager.impl.osgi;
+
+import static junit.framework.Assert.fail;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.matchers.JUnitMatchers.containsString;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import com.google.common.collect.Lists;
+import java.util.Map;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.config.spi.ModuleFactory;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+public class BundleContextBackedModuleFactoriesResolverTest {
+
+    @Mock
+    private BundleContext bundleContext;
+    private BundleContextBackedModuleFactoriesResolver resolver;
+    private ServiceReference s1;
+    private ServiceReference s2;
+    private ModuleFactory f1;
+    private ModuleFactory f2;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        s1 = getServiceRef();
+        s2 = getServiceRef();
+        doReturn(Lists.newArrayList(s1, s2)).when(bundleContext).getServiceReferences(ModuleFactory.class, null);
+        f1 = getMockFactory("f1");
+        doReturn(f1).when(bundleContext).getService(s1);
+        f2 = getMockFactory("f2");
+        doReturn(f2).when(bundleContext).getService(s2);
+        resolver = new BundleContextBackedModuleFactoriesResolver(bundleContext);
+    }
+
+    private ModuleFactory getMockFactory(String name) {
+        ModuleFactory mock = mock(ModuleFactory.class);
+        doReturn(name).when(mock).toString();
+        doReturn(name).when(mock).getImplementationName();
+        return mock;
+    }
+
+    private ServiceReference getServiceRef() {
+        ServiceReference mock = mock(ServiceReference.class);
+        doReturn("serviceRef").when(mock).toString();
+        final Bundle bundle = mock(Bundle.class);
+        doReturn(bundleContext).when(bundle).getBundleContext();
+        doReturn(bundle).when(mock).getBundle();
+        return mock;
+    }
+
+    @Test
+    public void testGetAllFactories() throws Exception {
+        Map<String, Map.Entry<ModuleFactory, BundleContext>> allFactories = resolver.getAllFactories();
+        assertEquals(2, allFactories.size());
+        assertTrue(allFactories.containsKey(f1.getImplementationName()));
+        assertEquals(f1, allFactories.get(f1.getImplementationName()).getKey());
+        assertEquals(bundleContext, allFactories.get(f1.getImplementationName()).getValue());
+        assertTrue(allFactories.containsKey(f2.getImplementationName()));
+        assertEquals(f2, allFactories.get(f2.getImplementationName()).getKey());
+        assertEquals(bundleContext, allFactories.get(f2.getImplementationName()).getValue());
+    }
+
+    @Test
+    public void testDuplicateFactories() throws Exception {
+        doReturn(f1).when(bundleContext).getService(s2);
+        try {
+            resolver.getAllFactories();
+        } catch (Exception e) {
+            assertThat(e.getMessage(), containsString(f1.getImplementationName()));
+            assertThat(e.getMessage(), containsString("unique"));
+            return;
+        }
+
+        fail("Should fail with duplicate factory name");
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testNullFactory() throws Exception {
+        doReturn(null).when(bundleContext).getService(s2);
+        resolver.getAllFactories();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testNullFactoryName() throws Exception {
+        doReturn(null).when(f1).getImplementationName();
+        resolver.getAllFactories();
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testNullBundleName() throws Exception {
+        doReturn(null).when(s1).getBundle();
+        resolver.getAllFactories();
+    }
+}
diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/ExtensibleBundleTrackerTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/ExtensibleBundleTrackerTest.java
new file mode 100644 (file)
index 0000000..9a3ba64
--- /dev/null
@@ -0,0 +1,76 @@
+package org.opendaylight.controller.config.manager.impl.osgi;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import com.google.common.util.concurrent.Futures;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.util.tracker.BundleTrackerCustomizer;
+
+public class ExtensibleBundleTrackerTest {
+
+    @Mock
+    private BundleContext bundleContext;
+    @Mock
+    private Bundle bundle;
+    @Mock
+    private BundleEvent bundleEvent;
+
+    @Mock
+    private BundleTrackerCustomizer<Object> primaryTracker;
+    @Mock
+    private BundleTrackerCustomizer<?> additionalTracker;
+
+    private ExtensibleBundleTracker<Object> extensibleBundleTracker;
+    private Object primaryValue = new Object();
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        doReturn("bundle").when(bundle).toString();
+        doReturn("bundleEvent").when(bundleEvent).toString();
+
+        doReturn(primaryValue).when(primaryTracker).addingBundle(bundle, bundleEvent);
+        doNothing().when(primaryTracker).modifiedBundle(bundle, bundleEvent, primaryValue);
+        doNothing().when(primaryTracker).removedBundle(bundle, bundleEvent, primaryValue);
+
+        doReturn(new Object()).when(additionalTracker).addingBundle(bundle, bundleEvent);
+        doNothing().when(additionalTracker).modifiedBundle(bundle, bundleEvent, null);
+        doNothing().when(additionalTracker).removedBundle(bundle, bundleEvent, null);
+        extensibleBundleTracker = new ExtensibleBundleTracker<>(bundleContext, primaryTracker, additionalTracker);
+    }
+
+    @Test
+    public void testAddingBundle() throws Exception {
+        assertEquals(primaryValue, extensibleBundleTracker.addingBundle(bundle, bundleEvent).get());
+        InOrder inOrder = Mockito.inOrder(primaryTracker, additionalTracker);
+        inOrder.verify(primaryTracker).addingBundle(bundle, bundleEvent);
+        inOrder.verify(additionalTracker).addingBundle(bundle, bundleEvent);
+    }
+
+    @Test
+    public void testRemovedBundle() throws Exception {
+        extensibleBundleTracker.removedBundle(bundle, bundleEvent, Futures.immediateFuture(primaryValue));
+        InOrder inOrder = Mockito.inOrder(primaryTracker, additionalTracker);
+        inOrder.verify(primaryTracker).removedBundle(bundle, bundleEvent, primaryValue);
+        inOrder.verify(additionalTracker).removedBundle(bundle, bundleEvent, null);
+    }
+
+    @Test
+    public void testRemovedBundleWithEx() throws Exception {
+        IllegalStateException throwable = new IllegalStateException();
+        extensibleBundleTracker.removedBundle(bundle, bundleEvent, Futures.immediateFailedFuture(throwable));
+        verifyZeroInteractions(primaryTracker);
+        verifyZeroInteractions(additionalTracker);
+    }
+}
diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/ModuleFactoryBundleTrackerTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/ModuleFactoryBundleTrackerTest.java
new file mode 100644 (file)
index 0000000..5b83412
--- /dev/null
@@ -0,0 +1,193 @@
+package org.opendaylight.controller.config.manager.impl.osgi;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import java.util.Dictionary;
+import java.util.Set;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.DependencyResolverFactory;
+import org.opendaylight.controller.config.api.DynamicMBeanWithInstance;
+import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
+import org.opendaylight.controller.config.spi.Module;
+import org.opendaylight.controller.config.spi.ModuleFactory;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.ServiceRegistration;
+
+public class ModuleFactoryBundleTrackerTest {
+
+    @Mock
+    private Bundle bundle;
+    @Mock
+    private BundleContext context;
+    @Mock
+    private ServiceRegistration<?> reg;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        doAnswer(new Answer() {
+            @Override
+            public Object answer(final InvocationOnMock invocation) throws Throwable {
+                return getClass().getClassLoader().loadClass((String) invocation.getArguments()[0]);
+            }
+        }).when(bundle).loadClass(anyString());
+        doReturn("mockBundle").when(bundle).toString();
+        doReturn(context).when(bundle).getBundleContext();
+        doReturn(reg).when(context).registerService(anyString(), anyObject(), any(Dictionary.class));
+    }
+
+    @Test
+    public void testRegisterFactory() throws Exception {
+        ModuleFactoryBundleTracker.registerFactory(TestingFactory.class.getName(), bundle);
+        verify(context).registerService(ModuleFactory.class.getName(), TestingFactory.currentInstance, null);
+    }
+
+    @Test
+    public void testRegisterFactoryInstantiateEx() throws Exception {
+        try {
+            ModuleFactoryBundleTracker.registerFactory(WrongConstructorTestingFactory.class.getName(), bundle);
+        } catch (Exception e) {
+            verifyZeroInteractions(context);
+            assertNotNull(e.getCause());
+            assertEquals(InstantiationException.class, e.getCause().getClass());
+            return;
+        }
+
+        fail("Cannot register without proper constructor");
+    }
+
+    @Test
+    public void testRegisterFactoryInstantiateExAccess() throws Exception {
+        try {
+            ModuleFactoryBundleTracker.registerFactory(NoAccessConstructorTestingFactory.class.getName(), bundle);
+        } catch (Exception e) {
+            verifyZeroInteractions(context);
+            assertNotNull(e.getCause());
+            assertEquals(IllegalAccessException.class, e.getCause().getClass());
+            return;
+        }
+
+        fail("Cannot register without proper constructor");
+    }
+
+    @Test
+    public void testRegisterFactoryNotExtending() throws Exception {
+        try {
+            ModuleFactoryBundleTracker.registerFactory(NotExtendingTestingFactory.class.getName(), bundle);
+        } catch (Exception e) {
+            verifyZeroInteractions(context);
+            return;
+        }
+
+        fail("Cannot register without extend");
+    }
+
+    @Test
+    public void testRegisterFactoryNotExisting() throws Exception {
+        try {
+            ModuleFactoryBundleTracker.registerFactory("Unknown class", bundle);
+        } catch (Exception e) {
+            verifyZeroInteractions(context);
+            assertNotNull(e.getCause());
+            assertEquals(ClassNotFoundException.class, e.getCause().getClass());
+            return;
+        }
+
+        fail("Cannot register without extend");
+    }
+
+    @Mock
+    private BlankTransactionServiceTracker blankTxTracker;
+
+    @Test
+    public void testAddingBundle() throws Exception {
+        final ModuleFactoryBundleTracker tracker = new ModuleFactoryBundleTracker(blankTxTracker);
+        doReturn(getClass().getResource("/module-factories/module-factory-ok")).when(bundle).getEntry(anyString());
+        tracker.addingBundle(bundle, mock(BundleEvent.class));
+        verify(context).registerService(ModuleFactory.class.getName(), TestingFactory.currentInstance, null);
+    }
+
+    @Test
+    public void testAddingBundleError() throws Exception {
+        final ModuleFactoryBundleTracker tracker = new ModuleFactoryBundleTracker(blankTxTracker);
+        doReturn(getClass().getResource("/module-factories/module-factory-fail")).when(bundle).getEntry(anyString());
+        try {
+            tracker.addingBundle(bundle, mock(BundleEvent.class));
+        } catch (Exception e) {
+            verifyZeroInteractions(context);
+            return;
+        }
+
+        fail("Cannot register");
+    }
+
+    static class WrongConstructorTestingFactory extends TestingFactory {
+        WrongConstructorTestingFactory(String randomParam) {
+        }
+    }
+
+    static class NotExtendingTestingFactory {}
+
+    static class NoAccessConstructorTestingFactory extends TestingFactory {
+        private NoAccessConstructorTestingFactory() {
+        }
+    }
+
+    static class TestingFactory implements ModuleFactory {
+
+        static TestingFactory currentInstance;
+
+        TestingFactory() {
+            currentInstance = this;
+        }
+
+        @Override
+        public String getImplementationName() {
+            return "Testing";
+        }
+
+        @Override
+        public Module createModule(final String instanceName, final DependencyResolver dependencyResolver, final BundleContext bundleContext) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Module createModule(final String instanceName, final DependencyResolver dependencyResolver, final DynamicMBeanWithInstance old, final BundleContext bundleContext) throws Exception {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean isModuleImplementingServiceInterface(final Class<? extends AbstractServiceInterface> serviceInterface) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Set<Class<? extends AbstractServiceInterface>> getImplementedServiceIntefaces() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Set<? extends Module> getDefaultModules(final DependencyResolverFactory dependencyResolverFactory, final BundleContext bundleContext) {
+            throw new UnsupportedOperationException();
+        }
+    }
+}
index 22ea528030931b5350cd79c0facc30d1c4ed73a5..220bef03bc95eab1efbbe54122e7b42cb657927e 100644 (file)
@@ -9,20 +9,19 @@ package org.opendaylight.controller.config.manager.impl.util;
 
 import static org.junit.Assert.assertEquals;
 
+import com.google.common.collect.Sets;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
-
 import javax.management.MXBean;
-
 import org.junit.Test;
 import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
+import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
 import org.opendaylight.controller.config.manager.testingservices.seviceinterface.TestingScheduledThreadPoolServiceInterface;
 import org.opendaylight.controller.config.manager.testingservices.seviceinterface.TestingThreadPoolServiceInterface;
 import org.opendaylight.controller.config.spi.Module;
 import org.opendaylight.yangtools.concepts.Identifiable;
 
-import com.google.common.collect.Sets;
-
 public class InterfacesHelperTest {
 
     interface SuperA {
@@ -46,10 +45,19 @@ public class InterfacesHelperTest {
 
     }
 
+    @ServiceInterfaceAnnotation(value = "a", osgiRegistrationType = SuperA.class, namespace = "n", revision = "r", localName = "l")
+    interface Service extends AbstractServiceInterface{}
+    @ServiceInterfaceAnnotation(value = "b", osgiRegistrationType = SuperC.class, namespace = "n", revision = "r", localName = "l")
+    interface SubService extends Service{}
+
     abstract class SubClass extends SuperClass implements SubA, Module {
 
     }
 
+    abstract class SubClassWithService implements SubService, Module {
+
+    }
+
     @Test
     public void testGetAllInterfaces() {
         Set<Class<?>> expected = Sets.<Class<?>> newHashSet(SuperA.class, SuperBMXBean.class, SuperC.class,
@@ -58,6 +66,19 @@ public class InterfacesHelperTest {
                 InterfacesHelper.getAllInterfaces(SubClass.class));
     }
 
+    @Test
+    public void testGetServiceInterfaces() throws Exception {
+        assertEquals(Collections.<Class<?>>emptySet(), InterfacesHelper.getServiceInterfaces(SubClass.class));
+        assertEquals(Sets.<Class<?>>newHashSet(Service.class, SubService.class), InterfacesHelper.getServiceInterfaces(SubClassWithService.class));
+    }
+
+    @Test
+    public void testGetOsgiRegistrationTypes() throws Exception {
+        assertEquals(Collections.<Class<?>>emptySet(), InterfacesHelper.getOsgiRegistrationTypes(SubClass.class));
+        assertEquals(Sets.<Class<?>>newHashSet(SuperA.class, SuperC.class),
+                InterfacesHelper.getOsgiRegistrationTypes(SubClassWithService.class));
+    }
+
     @Test
     public void testGetMXInterfaces() {
         Set<Class<?>> expected = Sets.<Class<?>> newHashSet(SuperBMXBean.class, SubA.class);
diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/OsgiRegistrationUtilTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/OsgiRegistrationUtilTest.java
new file mode 100644 (file)
index 0000000..fb59e3d
--- /dev/null
@@ -0,0 +1,61 @@
+package org.opendaylight.controller.config.manager.impl.util;
+
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import org.junit.Test;
+import org.mockito.InOrder;
+import org.mockito.Mockito;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.util.tracker.BundleTracker;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class OsgiRegistrationUtilTest {
+
+    @Test
+    public void testRegisterService() throws Exception {
+        final BundleContext bundleContext = mock(BundleContext.class);
+        ServiceRegistration<?> registration = mockServiceRegistration();
+        doReturn(registration).when(bundleContext).registerService(String.class, "string", null);
+        ServiceRegistration<?> registration2 = mockServiceRegistration();
+        doReturn(registration2).when(bundleContext).registerService(Object.class, "string", null);
+
+        AutoCloseable aggregatedRegister = OsgiRegistrationUtil.registerService(bundleContext, "string", String.class, Object.class);
+        aggregatedRegister.close();
+
+        InOrder inOrder = Mockito.inOrder(registration, registration2);
+        inOrder.verify(registration2).unregister();
+        inOrder.verify(registration).unregister();
+    }
+
+    @Test
+    public void testWrap() throws Exception {
+        final ServiceRegistration<?> serviceReg = mockServiceRegistration();
+        OsgiRegistrationUtil.wrap(serviceReg).close();
+        verify(serviceReg).unregister();
+
+        final BundleTracker tracker = mock(BundleTracker.class);
+        doNothing().when(tracker).close();
+        OsgiRegistrationUtil.wrap(tracker).close();
+        verify(tracker).close();
+
+        final ServiceTracker<?, ?> sTracker = mock(ServiceTracker.class);
+        doNothing().when(sTracker).close();
+        OsgiRegistrationUtil.wrap(sTracker).close();
+        verify(sTracker).close();
+    }
+
+    private ServiceRegistration<?> mockServiceRegistration() {
+        ServiceRegistration mock = mock(ServiceRegistration.class);
+        doNothing().when(mock).unregister();
+        return mock;
+    }
+
+    @Test
+    public void testAggregate() throws Exception {
+
+    }
+}
\ No newline at end of file
index 0286400d7b844524ba72dd8cadc7f2de44f7d317..a7024ca39e258011ae11afb15537ddd99764c294 100644 (file)
@@ -9,6 +9,6 @@ package org.opendaylight.controller.config.manager.testingservices.threadpool;
 
 import org.opendaylight.yangtools.yang.binding.annotations.ModuleQName;
 
-@ModuleQName(namespace = "namespace", revision = "revision", name = "name")
+@ModuleQName(namespace = "namespace", revision = "2012-12-12", name = "name")
 public abstract class AbstractTestingFixedThreadPoolModuleFactory {
 }
index 97d1c63ed2770da0ceb4fb504a4795a775b12c89..4ba3dc89399d11f157fdc833b5a72277e8e33ea1 100644 (file)
@@ -380,7 +380,8 @@ public class SimpleConfigurationTest extends AbstractConfigTest {
     @Test
     public void testQNames() {
         Set<String> availableModuleFactoryQNames = configRegistryClient.getAvailableModuleFactoryQNames();
-        String expected = "(namespace?revision=revision)name";
+        String expected = "(namespace?revision=2012-12-12)name";
+
         assertEquals(Sets.newHashSet(expected), availableModuleFactoryQNames);
     }
 
diff --git a/opendaylight/config/config-manager/src/test/resources/module-factories/module-factory-fail b/opendaylight/config/config-manager/src/test/resources/module-factories/module-factory-fail
new file mode 100644 (file)
index 0000000..fbd8108
--- /dev/null
@@ -0,0 +1 @@
+org.opendaylight.controller.config.manager.impl.osgi.ModuleFactoryBundleTrackerTest$NotExtendingTestingFactory
\ No newline at end of file
diff --git a/opendaylight/config/config-manager/src/test/resources/module-factories/module-factory-ok b/opendaylight/config/config-manager/src/test/resources/module-factories/module-factory-ok
new file mode 100644 (file)
index 0000000..031b622
--- /dev/null
@@ -0,0 +1 @@
+org.opendaylight.controller.config.manager.impl.osgi.ModuleFactoryBundleTrackerTest$TestingFactory
\ No newline at end of file