4ed10036f78e0262442a9986ef14aabbb85db42d
[controller.git] / opendaylight / config / config-manager / src / test / java / org / opendaylight / controller / config / manager / testingservices / threadpool / test / SimpleConfigurationTest.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.testingservices.threadpool.test;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertFalse;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertTrue;
14 import static org.junit.Assert.fail;
15
16 import com.google.common.collect.Sets;
17 import java.util.Arrays;
18 import java.util.Collections;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.Set;
22 import java.util.concurrent.ThreadPoolExecutor;
23 import javax.management.DynamicMBean;
24 import javax.management.InstanceAlreadyExistsException;
25 import javax.management.InstanceNotFoundException;
26 import javax.management.MBeanException;
27 import javax.management.ObjectName;
28 import javax.management.ReflectionException;
29 import org.junit.After;
30 import org.junit.Before;
31 import org.junit.Test;
32 import org.opendaylight.controller.config.api.ConflictingVersionException;
33 import org.opendaylight.controller.config.api.ValidationException;
34 import org.opendaylight.controller.config.api.ValidationException.ExceptionMessageWithStackTrace;
35 import org.opendaylight.controller.config.api.jmx.CommitStatus;
36 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
37 import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
38 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
39 import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPool;
40 import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolConfigMXBean;
41 import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolModuleFactory;
42 import org.opendaylight.controller.config.util.ConfigTransactionClient;
43 import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
44
45 /**
46  * Tests basic functionality of configuration registry:
47  * <ol>
48  * <li>Creation of instance</li>
49  * <li>Destruction of instance</li>
50  * <li>Reconfiguration of live object</li>
51  * <li>Reconfiguration that triggers new object creation</li>
52  * <li>Replacement of running instance with different one with same name</li>
53  * </ol>
54  * Only one bean is being configured - {@link TestingThreadPoolIfc} which has no
55  * dependencies.
56  */
57 public class SimpleConfigurationTest extends AbstractConfigTest {
58     private static final int numberOfThreads = 5;
59     private final int numberOfThreads2 = 10;
60     private static final String fixed1 = "fixed1";
61     private static final List<ObjectName> emptyONs = Collections
62             .<ObjectName> emptyList();
63     private static final ObjectName platformFixed1ON = ObjectNameUtil
64             .createReadOnlyModuleON(TestingFixedThreadPoolModuleFactory.NAME, fixed1);
65     private static final List<ObjectName> fixed1List = Arrays
66             .asList(platformFixed1ON);
67
68     @Before
69     public void setUp() {
70         super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext,
71                 new TestingFixedThreadPoolModuleFactory()));
72     }
73
74     @After
75     public void tearDown() {
76         TestingFixedThreadPool.cleanUp();
77     }
78
79     private ObjectName firstCommit() throws Exception {
80         ConfigTransactionJMXClient transaction = configRegistryClient
81                 .createTransaction();
82
83         ObjectName fixed1names = createFixedThreadPool(transaction);
84
85         // commit
86         assertEquals(1, configRegistryClient.getOpenConfigs().size());
87         CommitStatus commitStatus = transaction.commit();
88         assertEquals(0, configRegistryClient.getOpenConfigs().size());
89         CommitStatus expected = new CommitStatus(Arrays.asList(ObjectNameUtil
90                 .withoutTransactionName(fixed1names)), emptyONs, emptyONs);
91         assertEquals(expected, commitStatus);
92
93         assertEquals(1, TestingFixedThreadPool.allExecutors.size());
94         assertFalse(TestingFixedThreadPool.allExecutors.get(0).isShutdown());
95         return fixed1names;
96     }
97
98     static ObjectName createFixedThreadPool(
99             ConfigTransactionJMXClient transaction)
100             throws InstanceAlreadyExistsException, InstanceNotFoundException {
101         transaction.assertVersion(0, 1);
102
103         ObjectName fixed1names = transaction.createModule(
104                 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
105         TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
106                 .newMXBeanProxy(fixed1names, TestingFixedThreadPoolConfigMXBean.class);
107         fixedConfigProxy.setThreadCount(numberOfThreads);
108
109         ObjectName retrievedNames = transaction.lookupConfigBean(
110                 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
111         assertEquals(fixed1names, retrievedNames);
112         return fixed1names;
113     }
114
115     @Test
116     public void testCreateAndDestroyBeanInSameTransaction() throws Exception {
117         ConfigTransactionJMXClient transaction = configRegistryClient
118                 .createTransaction();
119         ObjectName fixed1names = createFixedThreadPool(transaction);
120         transaction.destroyModule(fixed1names);
121         CommitStatus commitStatus = transaction.commit();
122         assertStatus(commitStatus, 0, 0, 0);
123
124     }
125
126     @Test
127     public void testValidationUsingJMXClient() throws Exception {
128         ConfigTransactionClient transaction = configRegistryClient
129                 .createTransaction();
130         testValidation(transaction);
131     }
132
133
134     private void testValidation(ConfigTransactionClient transaction)
135             throws InstanceAlreadyExistsException, ReflectionException,
136             InstanceNotFoundException, MBeanException, ConflictingVersionException {
137         ObjectName fixed1names = transaction.createModule(
138                 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
139         // call validate on config bean
140         try {
141             platformMBeanServer.invoke(fixed1names, "validate", new Object[0],
142                     new String[0]);
143             fail();
144         } catch (MBeanException e) {
145             Exception targetException = e.getTargetException();
146             assertNotNull(targetException);
147             assertEquals(ValidationException.class, targetException.getClass());
148         }
149
150         // validate config bean
151         try {
152             transaction.validateBean(fixed1names);
153             fail();
154         } catch (ValidationException e) {
155             for (Map.Entry<String, Map<String, ExceptionMessageWithStackTrace>> exception : e
156                     .getFailedValidations().entrySet()) {
157                 for (Map.Entry<String, ExceptionMessageWithStackTrace> entry : exception
158                         .getValue().entrySet()) {
159                     assertEquals(
160                             "Parameter 'threadCount' must be greater than 0",
161                             entry.getValue().getMessage());
162                 }
163             }
164         }
165         // validate transaction
166         try {
167             transaction.validateConfig();
168             fail();
169         } catch (ValidationException e) {
170             for (Map.Entry<String, Map<String, ExceptionMessageWithStackTrace>> exception : e
171                     .getFailedValidations().entrySet()) {
172                 for (Map.Entry<String, ExceptionMessageWithStackTrace> entry : exception
173                         .getValue().entrySet()) {
174                     assertEquals(
175                             "Parameter 'threadCount' must be greater than 0",
176                             entry.getValue().getMessage());
177                 }
178             }
179         }
180         try {
181             transaction.commit();
182         } catch (ValidationException e) {
183             for (Map.Entry<String, Map<String, ExceptionMessageWithStackTrace>> exception : e
184                     .getFailedValidations().entrySet()) {
185                 for (Map.Entry<String, ExceptionMessageWithStackTrace> entry : exception
186                         .getValue().entrySet()) {
187                     assertEquals(
188                             "Parameter 'threadCount' must be greater than 0",
189                             entry.getValue().getMessage());
190                 }
191             }
192         }
193     }
194
195     @Test
196     public void test_createThreadPool_changeNumberOfThreads() throws Exception {
197         firstCommit();
198         ConfigTransactionJMXClient transaction = configRegistryClient
199                 .createTransaction();
200         TestingFixedThreadPoolConfigMXBean fixedConfigProxy = startReconfiguringFixed1ThreadPool(transaction);
201         assertEquals(numberOfThreads, fixedConfigProxy.getThreadCount());
202         fixedConfigProxy.setThreadCount(numberOfThreads2);
203         CommitStatus commitStatus = transaction.commit();
204         checkThreadPools(1, numberOfThreads2);
205         CommitStatus expected = new CommitStatus(emptyONs, fixed1List, emptyONs);
206         assertEquals(expected, commitStatus);
207     }
208
209     @Test
210     public void test_createFixedThreadPool_destroyIt() throws Exception {
211         // 1, start transaction, create new fixed thread pool
212         ObjectName fixed1name = firstCommit();
213
214         // 2, check that configuration was copied to platform
215         DynamicMBean dynamicMBean = configRegistryClient.newMBeanProxy(
216                 ObjectNameUtil.withoutTransactionName(fixed1name),
217                 DynamicMBean.class);
218         dynamicMBean.getMBeanInfo();
219         assertEquals(numberOfThreads, dynamicMBean.getAttribute("ThreadCount"));
220
221         // 3, shutdown fixed1 in new transaction
222         assertFalse(TestingFixedThreadPool.allExecutors.get(0).isShutdown());
223         ConfigTransactionJMXClient transaction = configRegistryClient
224                 .createTransaction();
225
226         // check versions
227         transaction.assertVersion(1, 2);
228
229         // test that it was copied to new transaction
230         ObjectName retrievedName = transaction.lookupConfigBean(
231                 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
232         assertNotNull(retrievedName);
233
234         // check that number of threads was copied from dynamic
235
236         TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
237                 .newMXBeanProxy(retrievedName, TestingFixedThreadPoolConfigMXBean.class);
238         assertEquals(numberOfThreads, fixedConfigProxy.getThreadCount());
239
240         // destroy
241         transaction.destroyModule(ObjectNameUtil.createTransactionModuleON(
242                 transaction.getTransactionName(),
243                 TestingFixedThreadPoolModuleFactory.NAME, fixed1));
244         transaction.commit();
245
246         // 4, check
247         assertEquals(2, configRegistryClient.getVersion());
248         assertEquals(0, TestingFixedThreadPool.allExecutors.size());
249
250         // dynamic config should be removed from platform
251         try {
252             dynamicMBean.getMBeanInfo();
253             fail();
254         } catch (Exception e) {
255             assertTrue(e.getCause() instanceof InstanceNotFoundException);
256         }
257     }
258
259     @Test
260     public void testReplaceFixed1() throws Exception {
261         // 1, start transaction, create new fixed thread pool
262         firstCommit();
263         // destroy and recreate with different # of threads
264         ConfigTransactionJMXClient transaction = configRegistryClient
265                 .createTransaction();
266
267         transaction.destroyModule(ObjectNameUtil.createTransactionModuleON(
268                 transaction.getTransactionName(),
269                 TestingFixedThreadPoolModuleFactory.NAME, fixed1));
270
271         ObjectName fixed1name = transaction.createModule(
272                 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
273         TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
274                 .newMXBeanProxy(fixed1name, TestingFixedThreadPoolConfigMXBean.class);
275         fixedConfigProxy.setThreadCount(numberOfThreads2);
276         // commit
277         transaction.commit();
278         // check that first threadpool is closed
279         checkThreadPools(1, numberOfThreads2);
280     }
281
282     private void checkThreadPools(int expectedTotalNumberOfExecutors,
283             int expectedNumberOfThreadsInLastExecutor) {
284         assertEquals(expectedTotalNumberOfExecutors,
285                 TestingFixedThreadPool.allExecutors.size());
286         for (int i = 0; i < expectedTotalNumberOfExecutors - 1; i++) {
287             assertTrue(TestingFixedThreadPool.allExecutors.get(i).isShutdown());
288         }
289         ThreadPoolExecutor lastExecutor = TestingFixedThreadPool.allExecutors
290                 .get(expectedTotalNumberOfExecutors - 1);
291         assertFalse(lastExecutor.isShutdown());
292         assertEquals(expectedNumberOfThreadsInLastExecutor,
293                 lastExecutor.getMaximumPoolSize());
294     }
295
296     @Test
297     public void testTriggerRecreatingInstance() throws Exception {
298         // 1, start transaction, create new fixed thread pool
299         firstCommit();
300         // switch boolean to create new instance
301         ConfigTransactionJMXClient transaction = configRegistryClient
302                 .createTransaction();
303         TestingFixedThreadPoolConfigMXBean fixedConfigProxy = startReconfiguringFixed1ThreadPool(transaction);
304
305         fixedConfigProxy.setTriggerNewInstanceCreation(true);
306         // commit
307         CommitStatus commitStatus = transaction.commit();
308         // check that new threadpool is created and old one is closed
309         checkThreadPools(1, numberOfThreads);
310         CommitStatus expected = new CommitStatus(emptyONs, emptyONs, fixed1List);
311         assertEquals(expected, commitStatus);
312     }
313
314     // return MBeanProxy for 'fixed1' and current transaction
315     private TestingFixedThreadPoolConfigMXBean startReconfiguringFixed1ThreadPool(
316             ConfigTransactionJMXClient transaction)
317             throws InstanceNotFoundException {
318         ObjectName fixed1name = transaction.lookupConfigBean(
319                 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
320
321         TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
322                 .newMXBeanProxy(fixed1name, TestingFixedThreadPoolConfigMXBean.class);
323         return fixedConfigProxy;
324     }
325
326     @Test
327     public void testAbort() throws Exception {
328         ConfigTransactionJMXClient transaction = configRegistryClient
329                 .createTransaction();
330         assertEquals(1, configRegistryClient.getOpenConfigs().size());
331
332         transaction.abortConfig();
333         assertEquals(0, configRegistryClient.getOpenConfigs().size());
334         try {
335             platformMBeanServer.getMBeanInfo(transaction.getObjectName());
336             fail();
337         }catch(InstanceNotFoundException e){
338             assertEquals("org.opendaylight.controller:TransactionName=ConfigTransaction-0-1,type=ConfigTransaction", e.getMessage());
339         }
340     }
341
342     @Test
343     public void testOptimisticLock_ConfigTransactionClient() throws Exception {
344         ConfigTransactionJMXClient transaction1 = configRegistryClient
345                 .createTransaction();
346         ConfigTransactionJMXClient transaction2 = configRegistryClient
347                 .createTransaction();
348         transaction2.assertVersion(0, 2);
349         transaction2.commit();
350         try {
351             transaction1.commit();
352             fail();
353         } catch (ConflictingVersionException e) {
354             assertEquals(
355                     "Optimistic lock failed. Expected parent version 2, was 0",
356                     e.getMessage());
357         }
358     }
359
360     @Test
361     public void testOptimisticLock_ConfigRegistry() throws Exception {
362         ConfigTransactionJMXClient transaction1 = configRegistryClient
363                 .createTransaction();
364         ConfigTransactionJMXClient transaction2 = configRegistryClient
365                 .createTransaction();
366         transaction2.assertVersion(0, 2);
367         transaction2.commit();
368         try {
369             configRegistryClient.commitConfig(transaction1.getObjectName());
370             fail();
371         } catch (ConflictingVersionException e) {
372             assertEquals(
373                     "Optimistic lock failed. Expected parent version 2, was 0",
374                     e.getMessage());
375         }
376     }
377
378
379     @Test
380     public void testQNames() {
381         Set<String> availableModuleFactoryQNames = configRegistryClient.getAvailableModuleFactoryQNames();
382         String expected = "(namespace?revision=2012-12-12)name";
383
384         assertEquals(Sets.newHashSet(expected), availableModuleFactoryQNames);
385     }
386
387 }