BUG-8: migrate newMBeanProxy() -> newMXBeanProxy()
[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         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 (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 void checkThreadPools(int expectedTotalNumberOfExecutors,
281             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 TestingFixedThreadPoolConfigMXBean startReconfiguringFixed1ThreadPool(
314             ConfigTransactionJMXClient transaction)
315             throws InstanceNotFoundException {
316         ObjectName fixed1name = transaction.lookupConfigBean(
317                 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
318
319         TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
320                 .newMXBeanProxy(fixed1name, TestingFixedThreadPoolConfigMXBean.class);
321         return fixedConfigProxy;
322     }
323
324     @Test
325     public void testAbort() throws Exception {
326         ConfigTransactionJMXClient transaction = configRegistryClient
327                 .createTransaction();
328         assertEquals(1, configRegistryClient.getOpenConfigs().size());
329
330         transaction.abortConfig();
331         assertEquals(0, configRegistryClient.getOpenConfigs().size());
332         try {
333             platformMBeanServer.getMBeanInfo(transaction.getObjectName());
334             fail();
335         }catch(InstanceNotFoundException e){
336             assertEquals("org.opendaylight.controller:TransactionName=ConfigTransaction-0-1,type=ConfigTransaction", e.getMessage());
337         }
338     }
339
340     @Test
341     public void testOptimisticLock_ConfigTransactionClient() throws Exception {
342         ConfigTransactionJMXClient transaction1 = configRegistryClient
343                 .createTransaction();
344         ConfigTransactionJMXClient transaction2 = configRegistryClient
345                 .createTransaction();
346         transaction2.assertVersion(0, 2);
347         transaction2.commit();
348         try {
349             transaction1.commit();
350             fail();
351         } catch (ConflictingVersionException e) {
352             assertEquals(
353                     "Optimistic lock failed. Expected parent version 2, was 0",
354                     e.getMessage());
355         }
356     }
357
358     @Test
359     public void testOptimisticLock_ConfigRegistry() throws Exception {
360         ConfigTransactionJMXClient transaction1 = configRegistryClient
361                 .createTransaction();
362         ConfigTransactionJMXClient transaction2 = configRegistryClient
363                 .createTransaction();
364         transaction2.assertVersion(0, 2);
365         transaction2.commit();
366         try {
367             configRegistryClient.commitConfig(transaction1.getObjectName());
368             fail();
369         } catch (ConflictingVersionException e) {
370             assertEquals(
371                     "Optimistic lock failed. Expected parent version 2, was 0",
372                     e.getMessage());
373         }
374     }
375
376
377     @Test
378     public void testQNames() {
379         Set<String> availableModuleFactoryQNames = configRegistryClient.getAvailableModuleFactoryQNames();
380         String expected = "(namespace?revision=2012-12-12)name";
381
382         assertEquals(Sets.newHashSet(expected), availableModuleFactoryQNames);
383     }
384
385 }