X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fconfig%2Fconfig-manager%2Fsrc%2Ftest%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fconfig%2Fmanager%2Fimpl%2FAbstractConfigTest.java;h=b0588a0903956cda35568bcd7b1eda94a528c67f;hb=2d60632f7cf63712e8357a3cf3fc40d83366e5e6;hp=18a22bb26fa91560dcc24be28a5e9c65877413c1;hpb=d8654e1e998855eb4a24af909c35b760e7a7c79b;p=controller.git diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/AbstractConfigTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/AbstractConfigTest.java index 18a22bb26f..628baeebab 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/AbstractConfigTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/AbstractConfigTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * Copyright (c) 2013, 2017 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, @@ -9,29 +9,45 @@ package org.opendaylight.controller.config.manager.impl; import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; -import java.io.Closeable; +import com.google.common.base.Preconditions; +import java.io.File; +import java.io.IOException; import java.lang.management.ManagementFactory; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Proxy; import java.util.Dictionary; +import java.util.LinkedList; +import java.util.List; import java.util.Set; - import javax.management.InstanceAlreadyExistsException; import javax.management.MBeanServer; import javax.management.ObjectName; - +import javax.management.RuntimeMBeanException; import org.junit.After; +import org.junit.Before; import org.mockito.Matchers; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; import org.opendaylight.controller.config.api.jmx.CommitStatus; import org.opendaylight.controller.config.manager.impl.factoriesresolver.ModuleFactoriesResolver; import org.opendaylight.controller.config.manager.impl.jmx.BaseJMXRegistrator; import org.opendaylight.controller.config.manager.impl.jmx.ConfigRegistryJMXRegistrator; -import org.opendaylight.controller.config.manager.impl.jmx.InternalJMXRegistrator; +import org.opendaylight.controller.config.manager.impl.jmx.JMXNotifierConfigRegistry; +import org.opendaylight.controller.config.manager.impl.osgi.mapping.BindingContextProvider; +import org.opendaylight.controller.config.manager.testingservices.scheduledthreadpool.TestingScheduledThreadPoolImpl; +import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPool; import org.opendaylight.controller.config.spi.Module; import org.opendaylight.controller.config.util.ConfigRegistryJMXClient; import org.opendaylight.controller.config.util.ConfigTransactionJMXClient; +import org.opendaylight.mdsal.binding.generator.api.ClassLoadingStrategy; +import org.opendaylight.mdsal.binding.generator.util.BindingRuntimeContext; +import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; @@ -41,59 +57,119 @@ import org.osgi.framework.ServiceRegistration; * needs to subclass this test. * {@link org.opendaylight.controller.config.manager.impl.ConfigRegistryImpl} is * registered to platform MBean Server using - * {@link #initConfigTransactionManagerImpl(org.opendaylight.controller.config.manager.impl.factoriesresolver.ModuleFactoriesResolver)} + * {@link #initConfigTransactionManagerImpl(org.opendaylight.controller + * .config.manager.impl.factoriesresolver.ModuleFactoriesResolver)} * typically during setting up the each test. */ -public abstract class AbstractConfigTest extends - AbstractLockedPlatformMBeanServerTest { +public abstract class AbstractConfigTest extends AbstractLockedPlatformMBeanServerTest { protected ConfigRegistryJMXRegistrator configRegistryJMXRegistrator; protected ConfigRegistryImpl configRegistry; + private JMXNotifierConfigRegistry notifyingConfigRegistry; protected ConfigRegistryJMXClient configRegistryClient; protected BaseJMXRegistrator baseJmxRegistrator; - protected InternalJMXRegistrator internalJmxRegistrator; + @Mock protected BundleContext mockedContext; + @Mock protected ServiceRegistration mockedServiceRegistration; + protected BundleContextServiceRegistrationHandler currentBundleContextServiceRegistrationHandler; + + @Before + public void setUpMocks() { + MockitoAnnotations.initMocks(this); + } + + // Default handler for OSGi service registration + protected static class RecordingBundleContextServiceRegistrationHandler + implements BundleContextServiceRegistrationHandler { + private final List registrations = new LinkedList<>(); + + @Override + public void handleServiceRegistration(final Class clazz, final Object serviceInstance, + final Dictionary props) { + this.registrations.add(new RegistrationHolder(clazz, serviceInstance, props)); + } + + public List getRegistrations() { + return this.registrations; + } + + protected static class RegistrationHolder { + protected final Class clazz; + protected final Object instance; + protected final Dictionary props; + + public RegistrationHolder(final Class clazz, final Object instance, final Dictionary props) { + this.clazz = clazz; + this.instance = instance; + this.props = props; + } + } + } + + protected BundleContextServiceRegistrationHandler getBundleContextServiceRegistrationHandler( + final Class serviceType) { + return this.currentBundleContextServiceRegistrationHandler; + } // this method should be called in @Before - protected void initConfigTransactionManagerImpl( - ModuleFactoriesResolver resolver) { - final MBeanServer platformMBeanServer = ManagementFactory - .getPlatformMBeanServer(); - - configRegistryJMXRegistrator = new ConfigRegistryJMXRegistrator( - platformMBeanServer); - this.mockedContext = mock(BundleContext.class); - this.mockedServiceRegistration = mock(ServiceRegistration.class); - doNothing().when(mockedServiceRegistration).unregister(); - doReturn(mockedServiceRegistration).when(mockedContext).registerService( - Matchers.any(String[].class), any(Closeable.class), - any(Dictionary.class)); - internalJmxRegistrator = new InternalJMXRegistrator(platformMBeanServer); - baseJmxRegistrator = new BaseJMXRegistrator(internalJmxRegistrator); - - configRegistry = new ConfigRegistryImpl(resolver, mockedContext, - platformMBeanServer, baseJmxRegistrator); + protected void initConfigTransactionManagerImpl(final ModuleFactoriesResolver resolver) { + + final MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer(); + + this.configRegistryJMXRegistrator = new ConfigRegistryJMXRegistrator(platformMBeanServer); + initBundleContext(); + + this.baseJmxRegistrator = new BaseJMXRegistrator(platformMBeanServer); + + this.configRegistry = new ConfigRegistryImpl(resolver, platformMBeanServer, this.baseJmxRegistrator, + new BindingContextProvider() { + @Override + public synchronized void update(final ClassLoadingStrategy classLoadingStrategy, + final SchemaContextProvider ctxProvider) { + // NOOP + } + + @Override + public synchronized BindingRuntimeContext getBindingContext() { + return getBindingRuntimeContext(); + } + }); + this.notifyingConfigRegistry = new JMXNotifierConfigRegistry(this.configRegistry, platformMBeanServer); + try { - configRegistryJMXRegistrator.registerToJMX(configRegistry); - } catch (InstanceAlreadyExistsException e) { + this.configRegistryJMXRegistrator.registerToJMXNoNotifications(this.configRegistry); + this.configRegistryJMXRegistrator.registerToJMX(this.notifyingConfigRegistry); + } catch (final InstanceAlreadyExistsException e) { throw new RuntimeException(e); } - configRegistryClient = new ConfigRegistryJMXClient(platformMBeanServer); + this.configRegistryClient = new ConfigRegistryJMXClient(platformMBeanServer); + this.currentBundleContextServiceRegistrationHandler = new RecordingBundleContextServiceRegistrationHandler(); + } + + private void initBundleContext() { + doNothing().when(this.mockedServiceRegistration).unregister(); + final RegisterServiceAnswer answer = new RegisterServiceAnswer(); + doAnswer(answer).when(this.mockedContext).registerService(Matchers.any(), any(), + Matchers.>any()); + doAnswer(answer).when(this.mockedContext).registerService(Matchers.>any(), any(), + Matchers.>any()); } @After public final void cleanUpConfigTransactionManagerImpl() { - configRegistryJMXRegistrator.close(); - configRegistry.close(); + this.configRegistryJMXRegistrator.close(); + this.notifyingConfigRegistry.close(); + this.configRegistry.close(); + TestingFixedThreadPool.cleanUp(); + TestingScheduledThreadPoolImpl.cleanUp(); } /** - * Can be called in @After of tests if some other cleanup is needed that - * would be discarded by closing config beans in this method + * Can be called in @After of tests if some other cleanup is needed that would + * be discarded by closing config beans in this method. */ protected void destroyAllConfigBeans() throws Exception { - ConfigTransactionJMXClient transaction = configRegistryClient - .createTransaction(); + final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction(); Set all = transaction.lookupConfigBeans(); // workaround for getting same Module more times while (all.size() > 0) { @@ -103,52 +179,136 @@ public abstract class AbstractConfigTest extends transaction.commit(); } - protected void assertSame(ObjectName oN1, ObjectName oN2) { - assertEquals(oN1.getKeyProperty("instanceName"), - oN2.getKeyProperty("instanceName")); - assertEquals(oN1.getKeyProperty("interfaceName"), - oN2.getKeyProperty("interfaceName")); + protected void assertStatus(final CommitStatus status, final int expectedNewInstances, + final int expectedRecreatedInstances, final int expectedReusedInstances) { + assertEquals("New instances mismatch in " + status, expectedNewInstances, status.getNewInstances().size()); + assertEquals("Recreated instances mismatch in " + status, expectedRecreatedInstances, + status.getRecreatedInstances().size()); + assertEquals("Reused instances mismatch in " + status, expectedReusedInstances, + status.getReusedInstances().size()); + } + + protected void assertBeanCount(final int index, final String configMXBeanName) { + assertEquals(index, this.configRegistry.lookupConfigBeans(configMXBeanName).size()); + } + + /** + * Empty constructor. + * + * @param configBeanClass + * Empty constructor class of config bean to be instantiated whenever + * create + * @param implementationName name + * @return factory + */ + protected ClassBasedModuleFactory createClassBasedCBF(final Class configBeanClass, + final String implementationName) { + return new ClassBasedModuleFactory(implementationName, configBeanClass); } - protected void assertStatus(CommitStatus status, int expectedNewInstances, - int expectedRecreatedInstances, int expectedReusedInstances) { - assertEquals(expectedNewInstances, status.getNewInstances().size()); - assertEquals(expectedRecreatedInstances, status.getRecreatedInstances() - .size()); - assertEquals(expectedReusedInstances, status.getReusedInstances() - .size()); + protected BindingRuntimeContext getBindingRuntimeContext() { + return mock(BindingRuntimeContext.class); } - protected ObjectName createTestConfigBean( - ConfigTransactionJMXClient transaction, String implementationName, - String name) throws InstanceAlreadyExistsException { - ObjectName nameCreated = transaction.createModule(implementationName, - name); - return nameCreated; + public interface BundleContextServiceRegistrationHandler { + void handleServiceRegistration(Class clazz, Object serviceInstance, Dictionary props); } - protected void assertBeanCount(int i, String configMXBeanName) { - assertEquals(i, configRegistry.lookupConfigBeans(configMXBeanName) - .size()); + private class RegisterServiceAnswer implements Answer> { + @Override + public ServiceRegistration answer(final InvocationOnMock invocation) throws Throwable { + final Object[] args = invocation.getArguments(); + + Preconditions.checkArgument(args.length == 3, "Unexpected arguments size (expected 3 was %s)", args.length); + + final Object serviceTypeRaw = args[0]; + final Object serviceInstance = args[1]; + @SuppressWarnings("unchecked") + final Dictionary props = (Dictionary) args[2]; + + if (serviceTypeRaw instanceof Class) { + final Class serviceType = (Class) serviceTypeRaw; + invokeServiceHandler(serviceInstance, serviceType, props); + } else if (serviceTypeRaw instanceof String[]) { + for (final String className : (String[]) serviceTypeRaw) { + invokeServiceHandler(serviceInstance, className, props); + } + } else if (serviceTypeRaw instanceof String) { + invokeServiceHandler(serviceInstance, (String) serviceTypeRaw, props); + } else { + throw new IllegalStateException( + "Not handling service registration of type, Unknown type" + serviceTypeRaw); + } + + return AbstractConfigTest.this.mockedServiceRegistration; + } + + public void invokeServiceHandler(final Object serviceInstance, final String className, + final Dictionary props) { + try { + final Class serviceType = Class.forName(className); + invokeServiceHandler(serviceInstance, serviceType, props); + } catch (final ClassNotFoundException e) { + throw new IllegalStateException("Not handling service registration of type " + className, e); + } + } + + private void invokeServiceHandler(final Object serviceInstance, final Class serviceType, + final Dictionary props) { + final BundleContextServiceRegistrationHandler serviceRegistrationHandler = + getBundleContextServiceRegistrationHandler(serviceType); + + if (serviceRegistrationHandler != null) { + serviceRegistrationHandler.handleServiceRegistration(serviceType, serviceInstance, props); + } + } } - protected void assertBeanExists(int count, String moduleName, - String instanceName) { - assertEquals(1, - configRegistry.lookupConfigBeans(moduleName, instanceName) - .size()); + /** + * Expand inner exception wrapped by JMX. + * + * @param innerObject + * jmx proxy which will be wrapped and returned + */ + protected T rethrowCause(final T innerObject) { + @SuppressWarnings({ "unchecked", "checkstyle:avoidHidingCauseException" }) + final T proxy = (T) Proxy.newProxyInstance(innerObject.getClass().getClassLoader(), + innerObject.getClass().getInterfaces(), (proxy1, method, args) -> { + try { + return method.invoke(innerObject, args); + } catch (final InvocationTargetException e) { + try { + throw e.getTargetException(); + } catch (final RuntimeMBeanException e2) { + throw e2.getTargetException(); + } + } + }); + return proxy; } /** + * removes contents of the directory. * - * @param configBeanClass - * Empty constructor class of config bean to be instantiated - * whenever create - * @param implementationName - * @return + * @param dir + * to be cleaned + * @throws IOException IO exception */ - protected ClassBasedModuleFactory createClassBasedCBF( - Class configBeanClass, String implementationName) { - return new ClassBasedModuleFactory(implementationName, configBeanClass); + protected void cleanDirectory(final File dir) throws IOException { + if (!dir.isDirectory()) { + throw new IllegalStateException("dir must be a directory"); + } + + final File[] files = dir.listFiles(); + if (files == null) { + throw new IOException("Failed to list contents of " + dir); + } + + for (final File file : files) { + if (file.isDirectory()) { + cleanDirectory(dir); + } + file.delete(); + } } }