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