a15839d2d5b886104f21e8de88a551bdbbf14c12
[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.util.ConfigTransactionClient;
42 import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
43
44 /**
45  * Tests basic functionality of configuration registry:
46  * <ol>
47  * <li>Creation of instance</li>
48  * <li>Destruction of instance</li>
49  * <li>Reconfiguration of live object</li>
50  * <li>Reconfiguration that triggers new object creation</li>
51  * <li>Replacement of running instance with different one with same name</li>
52  * </ol>
53  * Only one bean is being configured - {@link TestingThreadPoolIfc} which has no
54  * dependencies.
55  */
56 public class SimpleConfigurationTest extends AbstractConfigTest {
57     private static final int numberOfThreads = 5;
58     private final int numberOfThreads2 = 10;
59     private static final String fixed1 = "fixed1";
60     private static final List<ObjectName> emptyONs = Collections
61             .<ObjectName> emptyList();
62     private static final ObjectName platformFixed1ON = ObjectNameUtil
63             .createReadOnlyModuleON(TestingFixedThreadPoolModuleFactory.NAME, fixed1);
64     private static final List<ObjectName> fixed1List = Arrays
65             .asList(platformFixed1ON);
66
67     @Before
68     public void setUp() {
69         super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext,
70                 new TestingFixedThreadPoolModuleFactory()));
71     }
72
73     @After
74     public void tearDown() {
75         TestingFixedThreadPool.cleanUp();
76     }
77
78     private ObjectName firstCommit() throws Exception {
79         ConfigTransactionJMXClient transaction = configRegistryClient
80                 .createTransaction();
81
82         ObjectName fixed1names = createFixedThreadPool(transaction);
83
84         // commit
85         assertEquals(1, configRegistryClient.getOpenConfigs().size());
86         CommitStatus commitStatus = transaction.commit();
87         assertEquals(0, configRegistryClient.getOpenConfigs().size());
88         CommitStatus expected = new CommitStatus(Arrays.asList(ObjectNameUtil
89                 .withoutTransactionName(fixed1names)), emptyONs, emptyONs);
90         assertEquals(expected, commitStatus);
91
92         assertEquals(1, TestingFixedThreadPool.allExecutors.size());
93         assertFalse(TestingFixedThreadPool.allExecutors.get(0).isShutdown());
94         return fixed1names;
95     }
96
97     static ObjectName createFixedThreadPool(
98             ConfigTransactionJMXClient transaction)
99             throws InstanceAlreadyExistsException, InstanceNotFoundException {
100         transaction.assertVersion(0, 1);
101
102         ObjectName fixed1names = transaction.createModule(
103                 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
104         TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
105                 .newMXBeanProxy(fixed1names, TestingFixedThreadPoolConfigMXBean.class);
106         fixedConfigProxy.setThreadCount(numberOfThreads);
107
108         ObjectName retrievedNames = transaction.lookupConfigBean(
109                 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
110         assertEquals(fixed1names, retrievedNames);
111         return fixed1names;
112     }
113
114     @Test
115     public void testCreateAndDestroyBeanInSameTransaction() throws Exception {
116         ConfigTransactionJMXClient transaction = configRegistryClient
117                 .createTransaction();
118         ObjectName fixed1names = createFixedThreadPool(transaction);
119         transaction.destroyModule(fixed1names);
120         CommitStatus commitStatus = transaction.commit();
121         assertStatus(commitStatus, 0, 0, 0);
122
123     }
124
125     @Test
126     public void testValidationUsingJMXClient() throws Exception {
127         ConfigTransactionClient transaction = configRegistryClient
128                 .createTransaction();
129         testValidation(transaction);
130     }
131
132
133     private void testValidation(ConfigTransactionClient transaction)
134             throws InstanceAlreadyExistsException, ReflectionException,
135             InstanceNotFoundException, MBeanException, ConflictingVersionException {
136         ObjectName fixed1names = transaction.createModule(
137                 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
138         // call validate on config bean
139         try {
140             platformMBeanServer.invoke(fixed1names, "validate", new Object[0],
141                     new String[0]);
142             fail();
143         } catch (MBeanException e) {
144             Exception targetException = e.getTargetException();
145             assertNotNull(targetException);
146             assertEquals(ValidationException.class, targetException.getClass());
147         }
148
149         // validate config bean
150         try {
151             transaction.validateBean(fixed1names);
152             fail();
153         } catch (ValidationException e) {
154             for (Map.Entry<String, Map<String, ExceptionMessageWithStackTrace>> exception : e
155                     .getFailedValidations().entrySet()) {
156                 for (Map.Entry<String, ExceptionMessageWithStackTrace> entry : exception
157                         .getValue().entrySet()) {
158                     assertEquals(
159                             "Parameter 'threadCount' must be greater than 0",
160                             entry.getValue().getMessage());
161                 }
162             }
163         }
164         // validate transaction
165         try {
166             transaction.validateConfig();
167             fail();
168         } catch (ValidationException e) {
169             for (Map.Entry<String, Map<String, ExceptionMessageWithStackTrace>> exception : e
170                     .getFailedValidations().entrySet()) {
171                 for (Map.Entry<String, ExceptionMessageWithStackTrace> entry : exception
172                         .getValue().entrySet()) {
173                     assertEquals(
174                             "Parameter 'threadCount' must be greater than 0",
175                             entry.getValue().getMessage());
176                 }
177             }
178         }
179         try {
180             transaction.commit();
181         } catch (ValidationException e) {
182             for (Map.Entry<String, Map<String, ExceptionMessageWithStackTrace>> exception : e
183                     .getFailedValidations().entrySet()) {
184                 for (Map.Entry<String, ExceptionMessageWithStackTrace> entry : exception
185                         .getValue().entrySet()) {
186                     assertEquals(
187                             "Parameter 'threadCount' must be greater than 0",
188                             entry.getValue().getMessage());
189                 }
190             }
191         }
192     }
193
194     @Test
195     public void test_createThreadPool_changeNumberOfThreads() throws Exception {
196         firstCommit();
197         ConfigTransactionJMXClient transaction = configRegistryClient
198                 .createTransaction();
199         TestingFixedThreadPoolConfigMXBean fixedConfigProxy = startReconfiguringFixed1ThreadPool(transaction);
200         assertEquals(numberOfThreads, fixedConfigProxy.getThreadCount());
201         fixedConfigProxy.setThreadCount(numberOfThreads2);
202         CommitStatus commitStatus = transaction.commit();
203         checkThreadPools(1, numberOfThreads2);
204         CommitStatus expected = new CommitStatus(emptyONs, fixed1List, emptyONs);
205         assertEquals(expected, commitStatus);
206     }
207
208     @Test
209     public void test_createFixedThreadPool_destroyIt() throws Exception {
210         // 1, start transaction, create new fixed thread pool
211         ObjectName fixed1name = firstCommit();
212
213         // 2, check that configuration was copied to platform
214         ObjectName on = ObjectNameUtil.withoutTransactionName(fixed1name);
215         platformMBeanServer.getMBeanInfo(on);
216         assertEquals(numberOfThreads, platformMBeanServer.getAttribute(on, "ThreadCount"));
217
218         // 3, shutdown fixed1 in new transaction
219         assertFalse(TestingFixedThreadPool.allExecutors.get(0).isShutdown());
220         ConfigTransactionJMXClient transaction = configRegistryClient
221                 .createTransaction();
222
223         // check versions
224         transaction.assertVersion(1, 2);
225
226         // test that it was copied to new transaction
227         ObjectName retrievedName = transaction.lookupConfigBean(
228                 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
229         assertNotNull(retrievedName);
230
231         // check that number of threads was copied from dynamic
232
233         TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
234                 .newMXBeanProxy(retrievedName, TestingFixedThreadPoolConfigMXBean.class);
235         assertEquals(numberOfThreads, fixedConfigProxy.getThreadCount());
236
237         // destroy
238         transaction.destroyModule(ObjectNameUtil.createTransactionModuleON(
239                 transaction.getTransactionName(),
240                 TestingFixedThreadPoolModuleFactory.NAME, fixed1));
241         transaction.commit();
242
243         // 4, check
244         assertEquals(2, configRegistryClient.getVersion());
245         assertEquals(0, TestingFixedThreadPool.allExecutors.size());
246
247         // dynamic config should be removed from platform
248         try {
249             platformMBeanServer.getMBeanInfo(on);
250             fail();
251         } catch (Exception e) {
252             assertTrue(e instanceof InstanceNotFoundException);
253         }
254     }
255
256     @Test
257     public void testReplaceFixed1() throws Exception {
258         // 1, start transaction, create new fixed thread pool
259         firstCommit();
260         // destroy and recreate with different # of threads
261         ConfigTransactionJMXClient transaction = configRegistryClient
262                 .createTransaction();
263
264         transaction.destroyModule(ObjectNameUtil.createTransactionModuleON(
265                 transaction.getTransactionName(),
266                 TestingFixedThreadPoolModuleFactory.NAME, fixed1));
267
268         ObjectName fixed1name = transaction.createModule(
269                 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
270         TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
271                 .newMXBeanProxy(fixed1name, TestingFixedThreadPoolConfigMXBean.class);
272         fixedConfigProxy.setThreadCount(numberOfThreads2);
273         // commit
274         transaction.commit();
275         // check that first threadpool is closed
276         checkThreadPools(1, numberOfThreads2);
277     }
278
279     private void checkThreadPools(int expectedTotalNumberOfExecutors,
280             int expectedNumberOfThreadsInLastExecutor) {
281         assertEquals(expectedTotalNumberOfExecutors,
282                 TestingFixedThreadPool.allExecutors.size());
283         for (int i = 0; i < expectedTotalNumberOfExecutors - 1; i++) {
284             assertTrue(TestingFixedThreadPool.allExecutors.get(i).isShutdown());
285         }
286         ThreadPoolExecutor lastExecutor = TestingFixedThreadPool.allExecutors
287                 .get(expectedTotalNumberOfExecutors - 1);
288         assertFalse(lastExecutor.isShutdown());
289         assertEquals(expectedNumberOfThreadsInLastExecutor,
290                 lastExecutor.getMaximumPoolSize());
291     }
292
293     @Test
294     public void testTriggerRecreatingInstance() throws Exception {
295         // 1, start transaction, create new fixed thread pool
296         firstCommit();
297         // switch boolean to create new instance
298         ConfigTransactionJMXClient transaction = configRegistryClient
299                 .createTransaction();
300         TestingFixedThreadPoolConfigMXBean fixedConfigProxy = startReconfiguringFixed1ThreadPool(transaction);
301
302         fixedConfigProxy.setTriggerNewInstanceCreation(true);
303         // commit
304         CommitStatus commitStatus = transaction.commit();
305         // check that new threadpool is created and old one is closed
306         checkThreadPools(1, numberOfThreads);
307         CommitStatus expected = new CommitStatus(emptyONs, emptyONs, fixed1List);
308         assertEquals(expected, commitStatus);
309     }
310
311     // return MBeanProxy for 'fixed1' and current transaction
312     private TestingFixedThreadPoolConfigMXBean startReconfiguringFixed1ThreadPool(
313             ConfigTransactionJMXClient transaction)
314             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(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 (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 (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 }