Merge "Bug 1029: Remove dead code: samples/clustersession"
[controller.git] / opendaylight / config / config-manager / src / test / java / org / opendaylight / controller / config / manager / impl / AbstractConfigTest.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.controller.config.manager.impl;
9
10 import com.google.common.base.Preconditions;
11 import org.junit.After;
12 import org.junit.Before;
13 import org.mockito.Matchers;
14 import org.mockito.Mock;
15 import org.mockito.MockitoAnnotations;
16 import org.mockito.invocation.InvocationOnMock;
17 import org.mockito.stubbing.Answer;
18 import org.opendaylight.controller.config.api.jmx.CommitStatus;
19 import org.opendaylight.controller.config.manager.impl.factoriesresolver.ModuleFactoriesResolver;
20 import org.opendaylight.controller.config.manager.impl.jmx.BaseJMXRegistrator;
21 import org.opendaylight.controller.config.manager.impl.jmx.ConfigRegistryJMXRegistrator;
22 import org.opendaylight.controller.config.manager.impl.jmx.InternalJMXRegistrator;
23 import org.opendaylight.controller.config.manager.testingservices.scheduledthreadpool.TestingScheduledThreadPoolImpl;
24 import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPool;
25 import org.opendaylight.controller.config.spi.Module;
26 import org.opendaylight.controller.config.util.ConfigRegistryJMXClient;
27 import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
28 import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry;
29 import org.osgi.framework.BundleContext;
30 import org.osgi.framework.ServiceRegistration;
31
32 import javax.management.InstanceAlreadyExistsException;
33 import javax.management.MBeanServer;
34 import javax.management.ObjectName;
35 import javax.management.RuntimeMBeanException;
36 import java.lang.management.ManagementFactory;
37 import java.lang.reflect.InvocationHandler;
38 import java.lang.reflect.InvocationTargetException;
39 import java.lang.reflect.Method;
40 import java.lang.reflect.Proxy;
41 import java.util.Dictionary;
42 import java.util.LinkedList;
43 import java.util.List;
44 import java.util.Set;
45
46 import static org.junit.Assert.assertEquals;
47 import static org.mockito.Matchers.any;
48 import static org.mockito.Mockito.doAnswer;
49 import static org.mockito.Mockito.doNothing;
50 import static org.mockito.Mockito.mock;
51
52 /**
53  * Each test that relies on
54  * {@link org.opendaylight.controller.config.manager.impl.ConfigRegistryImpl}
55  * needs to subclass this test.
56  * {@link org.opendaylight.controller.config.manager.impl.ConfigRegistryImpl} is
57  * registered to platform MBean Server using
58  * {@link #initConfigTransactionManagerImpl(org.opendaylight.controller.config.manager.impl.factoriesresolver.ModuleFactoriesResolver)}
59  * typically during setting up the each test.
60  */
61 public abstract class AbstractConfigTest extends
62         AbstractLockedPlatformMBeanServerTest {
63     protected ConfigRegistryJMXRegistrator configRegistryJMXRegistrator;
64     protected ConfigRegistryImpl configRegistry;
65     protected ConfigRegistryJMXClient configRegistryClient;
66     protected BaseJMXRegistrator baseJmxRegistrator;
67     protected InternalJMXRegistrator internalJmxRegistrator;
68     @Mock
69     protected BundleContext mockedContext;
70     @Mock
71     protected ServiceRegistration<?> mockedServiceRegistration;
72
73     @Before
74     public void setUpMocks() {
75         MockitoAnnotations.initMocks(this);
76     }
77
78
79     // Default handler for OSGi service registration
80     protected static class RecordingBundleContextServiceRegistrationHandler implements BundleContextServiceRegistrationHandler {
81         private final List<RegistrationHolder> registrations = new LinkedList<>();
82         @Override
83         public void handleServiceRegistration(Class<?> clazz, Object serviceInstance, Dictionary<String, ?> props) {
84
85             registrations.add(new RegistrationHolder(clazz, serviceInstance, props));
86         }
87
88         public List<RegistrationHolder> getRegistrations() {
89             return registrations;
90         }
91
92         protected static class RegistrationHolder {
93             protected final Class<?> clazz;
94             protected final Object instance;
95             protected final Dictionary<String, ?> props;
96
97             public RegistrationHolder(Class<?> clazz, Object instance, Dictionary<String, ?> props) {
98                 this.clazz = clazz;
99                 this.instance = instance;
100                 this.props = props;
101             }
102         }
103
104     }
105
106     protected BundleContextServiceRegistrationHandler currentBundleContextServiceRegistrationHandler;
107
108     protected BundleContextServiceRegistrationHandler getBundleContextServiceRegistrationHandler(Class<?> serviceType) {
109         return currentBundleContextServiceRegistrationHandler;
110     }
111
112     // this method should be called in @Before
113     protected void initConfigTransactionManagerImpl(
114             ModuleFactoriesResolver resolver) {
115
116         final MBeanServer platformMBeanServer = ManagementFactory
117                 .getPlatformMBeanServer();
118
119         configRegistryJMXRegistrator = new ConfigRegistryJMXRegistrator(platformMBeanServer);
120         initBundleContext();
121
122         internalJmxRegistrator = new InternalJMXRegistrator(platformMBeanServer);
123         baseJmxRegistrator = new BaseJMXRegistrator(internalJmxRegistrator);
124
125         configRegistry = new ConfigRegistryImpl(resolver,
126                 platformMBeanServer, baseJmxRegistrator, getCodecRegistry());
127
128         try {
129             configRegistryJMXRegistrator.registerToJMX(configRegistry);
130         } catch (InstanceAlreadyExistsException e) {
131             throw new RuntimeException(e);
132         }
133         configRegistryClient = new ConfigRegistryJMXClient(platformMBeanServer);
134         currentBundleContextServiceRegistrationHandler = new RecordingBundleContextServiceRegistrationHandler();
135     }
136
137     private void initBundleContext() {
138         doNothing().when(mockedServiceRegistration).unregister();
139         RegisterServiceAnswer answer = new RegisterServiceAnswer();
140         doAnswer(answer).when(mockedContext).registerService(Matchers.<String>any(), any(), Matchers.<Dictionary<String, ?>>any());
141         doAnswer(answer).when(mockedContext).registerService(Matchers.<Class>any(), any(), Matchers.<Dictionary<String, ?>>any());
142     }
143
144     @After
145     public final void cleanUpConfigTransactionManagerImpl() {
146         configRegistryJMXRegistrator.close();
147         configRegistry.close();
148         TestingFixedThreadPool.cleanUp();
149         TestingScheduledThreadPoolImpl.cleanUp();
150     }
151
152     /**
153      * Can be called in @After of tests if some other cleanup is needed that
154      * would be discarded by closing config beans in this method
155      */
156     protected void destroyAllConfigBeans() throws Exception {
157         ConfigTransactionJMXClient transaction = configRegistryClient
158                 .createTransaction();
159         Set<ObjectName> all = transaction.lookupConfigBeans();
160         // workaround for getting same Module more times
161         while (all.size() > 0) {
162             transaction.destroyModule(all.iterator().next());
163             all = transaction.lookupConfigBeans();
164         }
165         transaction.commit();
166     }
167
168     protected void assertStatus(CommitStatus status, int expectedNewInstances,
169             int expectedRecreatedInstances, int expectedReusedInstances) {
170         assertEquals("New instances mismatch in " + status, expectedNewInstances, status.getNewInstances().size());
171         assertEquals("Recreated instances mismatch in " + status, expectedRecreatedInstances, status.getRecreatedInstances()
172                 .size());
173         assertEquals("Reused instances mismatch in " + status, expectedReusedInstances, status.getReusedInstances()
174                 .size());
175     }
176
177
178     protected void assertBeanCount(int i, String configMXBeanName) {
179         assertEquals(i, configRegistry.lookupConfigBeans(configMXBeanName)
180                 .size());
181     }
182
183     /**
184      *
185      * @param configBeanClass
186      *            Empty constructor class of config bean to be instantiated
187      *            whenever create
188      * @param implementationName
189      * @return
190      */
191     protected ClassBasedModuleFactory createClassBasedCBF(
192             Class<? extends Module> configBeanClass, String implementationName) {
193         return new ClassBasedModuleFactory(implementationName, configBeanClass);
194     }
195
196     protected CodecRegistry getCodecRegistry() {
197         return mock(CodecRegistry.class);
198     }
199
200     public static interface BundleContextServiceRegistrationHandler {
201
202        void handleServiceRegistration(Class<?> clazz, Object serviceInstance, Dictionary<String, ?> props);
203
204     }
205
206     private class RegisterServiceAnswer implements Answer<ServiceRegistration<?>> {
207
208         @Override
209         public ServiceRegistration<?> answer(InvocationOnMock invocation) throws Throwable {
210             Object[] args = invocation.getArguments();
211
212             Preconditions.checkArgument(args.length == 3, "Unexpected arguments size (expected 3 was %s)", args.length);
213
214             Object serviceTypeRaw = args[0];
215             Object serviceInstance = args[1];
216             Dictionary<String, ?> props = (Dictionary<String, ?>) args[2];
217
218             if (serviceTypeRaw instanceof Class) {
219                 Class<?> serviceType = (Class<?>) serviceTypeRaw;
220                 invokeServiceHandler(serviceInstance, serviceType, props);
221
222             } else if(serviceTypeRaw instanceof String[]) {
223                 for (String className : (String[]) serviceTypeRaw) {
224                     invokeServiceHandler(serviceInstance, className, props);
225                 }
226             } else if (serviceTypeRaw instanceof String) {
227                 invokeServiceHandler(serviceInstance, (String) serviceTypeRaw, props);
228             } else {
229                 throw new IllegalStateException("Not handling service registration of type, Unknown type" +  serviceTypeRaw);
230             }
231
232
233             return mockedServiceRegistration;
234         }
235
236         public void invokeServiceHandler(Object serviceInstance, String className, Dictionary<String, ?> props) {
237             try {
238                 Class<?> serviceType = Class.forName(className);
239                 invokeServiceHandler(serviceInstance, serviceType, props);
240             } catch (ClassNotFoundException e) {
241                 throw new IllegalStateException("Not handling service registration of type " +  className, e);
242             }
243         }
244
245         private void invokeServiceHandler(Object serviceInstance, Class<?> serviceType, Dictionary<String, ?> props) {
246             BundleContextServiceRegistrationHandler serviceRegistrationHandler = getBundleContextServiceRegistrationHandler(serviceType);
247
248             if (serviceRegistrationHandler != null) {
249                 serviceRegistrationHandler.handleServiceRegistration(serviceType, serviceInstance, props);
250             }
251         }
252     }
253
254     /**
255      * Expand inner exception wrapped by JMX
256      *
257      * @param innerObject jmx proxy which will be wrapped and returned
258      */
259     protected <T> T rethrowCause(final T innerObject) {
260
261         Object proxy = Proxy.newProxyInstance(innerObject.getClass().getClassLoader(),
262                 innerObject.getClass().getInterfaces(), new InvocationHandler() {
263             @Override
264             public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
265                 try {
266                     return method.invoke(innerObject, args);
267                 } catch (InvocationTargetException e) {
268                     try {
269                         throw e.getTargetException();
270                     } catch (RuntimeMBeanException e2) {
271                         throw e2.getTargetException();
272                     }
273                 }
274             }
275         });
276         return (T) proxy;
277     }
278
279 }