config-manager: final parameters
[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.InstanceAlreadyExistsException;
24 import javax.management.InstanceNotFoundException;
25 import javax.management.MBeanException;
26 import javax.management.ObjectName;
27 import javax.management.ReflectionException;
28 import org.junit.After;
29 import org.junit.Before;
30 import org.junit.Test;
31 import org.opendaylight.controller.config.api.ConflictingVersionException;
32 import org.opendaylight.controller.config.api.ValidationException;
33 import org.opendaylight.controller.config.api.ValidationException.ExceptionMessageWithStackTrace;
34 import org.opendaylight.controller.config.api.jmx.CommitStatus;
35 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
36 import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
37 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
38 import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPool;
39 import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolConfigMXBean;
40 import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolModuleFactory;
41 import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingThreadPoolIfc;
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             final 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 static void testValidation(final 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 (final 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 (final 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 (final 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 (final 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         ObjectName on = ObjectNameUtil.withoutTransactionName(fixed1name);
216         platformMBeanServer.getMBeanInfo(on);
217         assertEquals(numberOfThreads, platformMBeanServer.getAttribute(on, "ThreadCount"));
218
219         // 3, shutdown fixed1 in new transaction
220         assertFalse(TestingFixedThreadPool.allExecutors.get(0).isShutdown());
221         ConfigTransactionJMXClient transaction = configRegistryClient
222                 .createTransaction();
223
224         // check versions
225         transaction.assertVersion(1, 2);
226
227         // test that it was copied to new transaction
228         ObjectName retrievedName = transaction.lookupConfigBean(
229                 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
230         assertNotNull(retrievedName);
231
232         // check that number of threads was copied from dynamic
233
234         TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
235                 .newMXBeanProxy(retrievedName, TestingFixedThreadPoolConfigMXBean.class);
236         assertEquals(numberOfThreads, fixedConfigProxy.getThreadCount());
237
238         // destroy
239         transaction.destroyModule(ObjectNameUtil.createTransactionModuleON(
240                 transaction.getTransactionName(),
241                 TestingFixedThreadPoolModuleFactory.NAME, fixed1));
242         transaction.commit();
243
244         // 4, check
245         assertEquals(2, configRegistryClient.getVersion());
246         assertEquals(0, TestingFixedThreadPool.allExecutors.size());
247
248         // dynamic config should be removed from platform
249         try {
250             platformMBeanServer.getMBeanInfo(on);
251             fail();
252         } catch (final Exception e) {
253             assertTrue(e instanceof InstanceNotFoundException);
254         }
255     }
256
257     @Test
258     public void testReplaceFixed1() throws Exception {
259         // 1, start transaction, create new fixed thread pool
260         firstCommit();
261         // destroy and recreate with different # of threads
262         ConfigTransactionJMXClient transaction = configRegistryClient
263                 .createTransaction();
264
265         transaction.destroyModule(ObjectNameUtil.createTransactionModuleON(
266                 transaction.getTransactionName(),
267                 TestingFixedThreadPoolModuleFactory.NAME, fixed1));
268
269         ObjectName fixed1name = transaction.createModule(
270                 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
271         TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
272                 .newMXBeanProxy(fixed1name, TestingFixedThreadPoolConfigMXBean.class);
273         fixedConfigProxy.setThreadCount(numberOfThreads2);
274         // commit
275         transaction.commit();
276         // check that first threadpool is closed
277         checkThreadPools(1, numberOfThreads2);
278     }
279
280     private static void checkThreadPools(final int expectedTotalNumberOfExecutors,
281             final int expectedNumberOfThreadsInLastExecutor) {
282         assertEquals(expectedTotalNumberOfExecutors,
283                 TestingFixedThreadPool.allExecutors.size());
284         for (int i = 0; i < expectedTotalNumberOfExecutors - 1; i++) {
285             assertTrue(TestingFixedThreadPool.allExecutors.get(i).isShutdown());
286         }
287         ThreadPoolExecutor lastExecutor = TestingFixedThreadPool.allExecutors
288                 .get(expectedTotalNumberOfExecutors - 1);
289         assertFalse(lastExecutor.isShutdown());
290         assertEquals(expectedNumberOfThreadsInLastExecutor,
291                 lastExecutor.getMaximumPoolSize());
292     }
293
294     @Test
295     public void testTriggerRecreatingInstance() throws Exception {
296         // 1, start transaction, create new fixed thread pool
297         firstCommit();
298         // switch boolean to create new instance
299         ConfigTransactionJMXClient transaction = configRegistryClient
300                 .createTransaction();
301         TestingFixedThreadPoolConfigMXBean fixedConfigProxy = startReconfiguringFixed1ThreadPool(transaction);
302
303         fixedConfigProxy.setTriggerNewInstanceCreation(true);
304         // commit
305         CommitStatus commitStatus = transaction.commit();
306         // check that new threadpool is created and old one is closed
307         checkThreadPools(1, numberOfThreads);
308         CommitStatus expected = new CommitStatus(emptyONs, emptyONs, fixed1List);
309         assertEquals(expected, commitStatus);
310     }
311
312     // return MBeanProxy for 'fixed1' and current transaction
313     private static TestingFixedThreadPoolConfigMXBean startReconfiguringFixed1ThreadPool(
314             final ConfigTransactionJMXClient transaction) throws InstanceNotFoundException {
315         ObjectName fixed1name = transaction.lookupConfigBean(
316                 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
317
318         TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
319                 .newMXBeanProxy(fixed1name, TestingFixedThreadPoolConfigMXBean.class);
320         return fixedConfigProxy;
321     }
322
323     @Test
324     public void testAbort() throws Exception {
325         ConfigTransactionJMXClient transaction = configRegistryClient
326                 .createTransaction();
327         assertEquals(1, configRegistryClient.getOpenConfigs().size());
328
329         transaction.abortConfig();
330         assertEquals(0, configRegistryClient.getOpenConfigs().size());
331         try {
332             platformMBeanServer.getMBeanInfo(transaction.getObjectName());
333             fail();
334         }catch(final InstanceNotFoundException e){
335             assertEquals("org.opendaylight.controller:TransactionName=ConfigTransaction-0-1,type=ConfigTransaction", e.getMessage());
336         }
337     }
338
339     @Test
340     public void testOptimisticLock_ConfigTransactionClient() throws Exception {
341         ConfigTransactionJMXClient transaction1 = configRegistryClient
342                 .createTransaction();
343         ConfigTransactionJMXClient transaction2 = configRegistryClient
344                 .createTransaction();
345         transaction2.assertVersion(0, 2);
346         transaction2.commit();
347         try {
348             transaction1.commit();
349             fail();
350         } catch (final ConflictingVersionException e) {
351             assertEquals(
352                     "Optimistic lock failed. Expected parent version 2, was 0",
353                     e.getMessage());
354         }
355     }
356
357     @Test
358     public void testOptimisticLock_ConfigRegistry() throws Exception {
359         ConfigTransactionJMXClient transaction1 = configRegistryClient
360                 .createTransaction();
361         ConfigTransactionJMXClient transaction2 = configRegistryClient
362                 .createTransaction();
363         transaction2.assertVersion(0, 2);
364         transaction2.commit();
365         try {
366             configRegistryClient.commitConfig(transaction1.getObjectName());
367             fail();
368         } catch (final ConflictingVersionException e) {
369             assertEquals(
370                     "Optimistic lock failed. Expected parent version 2, was 0",
371                     e.getMessage());
372         }
373     }
374
375
376     @Test
377     public void testQNames() {
378         Set<String> availableModuleFactoryQNames = configRegistryClient.getAvailableModuleFactoryQNames();
379         String expected = "(namespace?revision=2012-12-12)name";
380
381         assertEquals(Sets.newHashSet(expected), availableModuleFactoryQNames);
382     }
383
384 }