2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.controller.config.manager.testingservices.threadpool.test;
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;
18 import java.util.Arrays;
19 import java.util.Collections;
20 import java.util.List;
22 import java.util.concurrent.ThreadPoolExecutor;
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;
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.util.ConfigTransactionClient;
46 import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
47 import org.opendaylight.controller.config.util.jolokia.ConfigTransactionJolokiaClient;
50 * Tests basic functionality of configuration registry:
52 * <li>Creation of instance</li>
53 * <li>Destruction of instance</li>
54 * <li>Reconfiguration of live object</li>
55 * <li>Reconfiguration that triggers new object creation</li>
56 * <li>Replacement of running instance with different one with same name</li>
58 * Only one bean is being configured - {@link TestingThreadPoolIfc} which has no
61 public class SimpleConfigurationTest extends AbstractConfigWithJolokiaTest {
62 private final int numberOfThreads = 5;
63 private final int numberOfThreads2 = 10;
64 private static final String fixed1 = "fixed1";
65 private static final List<ObjectName> emptyONs = Collections
66 .<ObjectName> emptyList();
67 private static final ObjectName platformFixed1ON = ObjectNameUtil
68 .createReadOnlyModuleON(TestingFixedThreadPoolModuleFactory.NAME, fixed1);
69 private static final List<ObjectName> fixed1List = Arrays
70 .asList(platformFixed1ON);
74 super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(
75 new TestingFixedThreadPoolModuleFactory()));
79 public void tearDown() {
80 TestingFixedThreadPool.cleanUp();
83 private ObjectName firstCommit() throws Exception {
84 ConfigTransactionJMXClient transaction = configRegistryClient
87 ObjectName fixed1names = createFixedThreadPool(transaction);
90 assertEquals(1, configRegistryClient.getOpenConfigs().size());
91 CommitStatus commitStatus = transaction.commit();
92 assertEquals(0, configRegistryClient.getOpenConfigs().size());
93 CommitStatus expected = new CommitStatus(Arrays.asList(ObjectNameUtil
94 .withoutTransactionName(fixed1names)), emptyONs, emptyONs);
95 assertEquals(expected, commitStatus);
97 assertEquals(1, TestingFixedThreadPool.allExecutors.size());
98 assertFalse(TestingFixedThreadPool.allExecutors.get(0).isShutdown());
102 private ObjectName createFixedThreadPool(
103 ConfigTransactionJMXClient transaction)
104 throws InstanceAlreadyExistsException, InstanceNotFoundException {
105 transaction.assertVersion(0, 1);
107 ObjectName fixed1names = transaction.createModule(
108 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
109 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
110 .newMXBeanProxy(fixed1names, TestingFixedThreadPoolConfigMXBean.class);
111 fixedConfigProxy.setThreadCount(numberOfThreads);
113 ObjectName retrievedNames = transaction.lookupConfigBean(
114 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
115 assertEquals(fixed1names, retrievedNames);
120 public void testCreateAndDestroyBeanInSameTransaction() throws Exception {
121 ConfigTransactionJMXClient transaction = configRegistryClient
122 .createTransaction();
123 ObjectName fixed1names = createFixedThreadPool(transaction);
124 transaction.destroyModule(fixed1names);
125 CommitStatus commitStatus = transaction.commit();
126 assertStatus(commitStatus, 0, 0, 0);
131 public void testValidationUsingJMXClient() throws Exception {
132 ConfigTransactionClient transaction = configRegistryClient
133 .createTransaction();
134 testValidation(transaction);
138 public void testValidationUsingJolokiaClient() throws Exception {
139 ConfigTransactionClient transaction = configRegistryJolokiaClient
140 .createTransaction();
141 testValidation(transaction);
144 private void testValidation(ConfigTransactionClient transaction)
145 throws InstanceAlreadyExistsException, ReflectionException,
146 InstanceNotFoundException, MBeanException {
147 ObjectName fixed1names = transaction.createModule(
148 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
149 // call validate on config bean
151 platformMBeanServer.invoke(fixed1names, "validate", new Object[0],
154 } catch (RuntimeMBeanException e) {
155 RuntimeException targetException = e.getTargetException();
156 assertNotNull(targetException);
157 assertEquals(ValidationException.class, targetException.getClass());
160 // validate config bean
162 transaction.validateBean(fixed1names);
164 } catch (ValidationException e) {
165 for (Map.Entry<String, Map<String, ExceptionMessageWithStackTrace>> exception : e
166 .getFailedValidations().entrySet()) {
167 for (Map.Entry<String, ExceptionMessageWithStackTrace> entry : exception
168 .getValue().entrySet()) {
170 "Parameter 'threadCount' must be greater than 0",
171 entry.getValue().getMessage());
175 // validate transaction
177 transaction.validateConfig();
179 } catch (ValidationException e) {
180 for (Map.Entry<String, Map<String, ExceptionMessageWithStackTrace>> exception : e
181 .getFailedValidations().entrySet()) {
182 for (Map.Entry<String, ExceptionMessageWithStackTrace> entry : exception
183 .getValue().entrySet()) {
185 "Parameter 'threadCount' must be greater than 0",
186 entry.getValue().getMessage());
191 transaction.commit();
192 } catch (ValidationException e) {
193 for (Map.Entry<String, Map<String, ExceptionMessageWithStackTrace>> exception : e
194 .getFailedValidations().entrySet()) {
195 for (Map.Entry<String, ExceptionMessageWithStackTrace> entry : exception
196 .getValue().entrySet()) {
198 "Parameter 'threadCount' must be greater than 0",
199 entry.getValue().getMessage());
206 public void test_createThreadPool_changeNumberOfThreads() throws Exception {
208 ConfigTransactionJMXClient transaction = configRegistryClient
209 .createTransaction();
210 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = startReconfiguringFixed1ThreadPool(transaction);
211 assertEquals(numberOfThreads, fixedConfigProxy.getThreadCount());
212 fixedConfigProxy.setThreadCount(numberOfThreads2);
213 CommitStatus commitStatus = transaction.commit();
214 checkThreadPools(1, numberOfThreads2);
215 CommitStatus expected = new CommitStatus(emptyONs, fixed1List, emptyONs);
216 assertEquals(expected, commitStatus);
220 public void test_createFixedThreadPool_destroyIt() throws Exception {
221 // 1, start transaction, create new fixed thread pool
222 ObjectName fixed1name = firstCommit();
224 // 2, check that configuration was copied to platform
225 DynamicMBean dynamicMBean = configRegistryClient.newMBeanProxy(
226 ObjectNameUtil.withoutTransactionName(fixed1name),
228 dynamicMBean.getMBeanInfo();
229 assertEquals(numberOfThreads, dynamicMBean.getAttribute("ThreadCount"));
231 // 3, shutdown fixed1 in new transaction
232 assertFalse(TestingFixedThreadPool.allExecutors.get(0).isShutdown());
233 ConfigTransactionJMXClient transaction = configRegistryClient
234 .createTransaction();
237 transaction.assertVersion(1, 2);
239 // test that it was copied to new transaction
240 ObjectName retrievedName = transaction.lookupConfigBean(
241 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
242 assertNotNull(retrievedName);
244 // check that number of threads was copied from dynamic
246 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
247 .newMXBeanProxy(retrievedName, TestingFixedThreadPoolConfigMXBean.class);
248 assertEquals(numberOfThreads, fixedConfigProxy.getThreadCount());
251 transaction.destroyModule(ObjectNameUtil.createTransactionModuleON(
252 transaction.getTransactionName(),
253 TestingFixedThreadPoolModuleFactory.NAME, fixed1));
254 transaction.commit();
257 assertEquals(2, configRegistryClient.getVersion());
258 assertEquals(1, TestingFixedThreadPool.allExecutors.size());
259 assertTrue(TestingFixedThreadPool.allExecutors.get(0).isShutdown());
261 // dynamic config should be removed from platform
263 dynamicMBean.getMBeanInfo();
265 } catch (Exception e) {
266 assertTrue(e.getCause() instanceof InstanceNotFoundException);
271 public void testReplaceFixed1() throws Exception {
272 // 1, start transaction, create new fixed thread pool
274 // destroy and recreate with different # of threads
275 ConfigTransactionJMXClient transaction = configRegistryClient
276 .createTransaction();
278 transaction.destroyModule(ObjectNameUtil.createTransactionModuleON(
279 transaction.getTransactionName(),
280 TestingFixedThreadPoolModuleFactory.NAME, fixed1));
282 ObjectName fixed1name = transaction.createModule(
283 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
284 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
285 .newMXBeanProxy(fixed1name, TestingFixedThreadPoolConfigMXBean.class);
286 fixedConfigProxy.setThreadCount(numberOfThreads2);
288 transaction.commit();
289 // check that first threadpool is closed
290 checkThreadPools(2, numberOfThreads2);
293 private void checkThreadPools(int expectedTotalNumberOfExecutors,
294 int expectedNumberOfThreadsInLastExecutor) {
295 assertEquals(expectedTotalNumberOfExecutors,
296 TestingFixedThreadPool.allExecutors.size());
297 for (int i = 0; i < expectedTotalNumberOfExecutors - 1; i++) {
298 assertTrue(TestingFixedThreadPool.allExecutors.get(i).isShutdown());
300 ThreadPoolExecutor lastExecutor = TestingFixedThreadPool.allExecutors
301 .get(expectedTotalNumberOfExecutors - 1);
302 assertFalse(lastExecutor.isShutdown());
303 assertEquals(expectedNumberOfThreadsInLastExecutor,
304 lastExecutor.getMaximumPoolSize());
308 public void testTriggerRecreatingInstance() throws Exception {
309 // 1, start transaction, create new fixed thread pool
311 // switch boolean to create new instance
312 ConfigTransactionJMXClient transaction = configRegistryClient
313 .createTransaction();
314 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = startReconfiguringFixed1ThreadPool(transaction);
316 fixedConfigProxy.setTriggerNewInstanceCreation(true);
318 CommitStatus commitStatus = transaction.commit();
319 // check that new threadpool is created and old one is closed
320 checkThreadPools(2, numberOfThreads);
321 CommitStatus expected = new CommitStatus(emptyONs, emptyONs, fixed1List);
322 assertEquals(expected, commitStatus);
325 // return MBeanProxy for 'fixed1' and current transaction
326 private TestingFixedThreadPoolConfigMXBean startReconfiguringFixed1ThreadPool(
327 ConfigTransactionJMXClient transaction)
328 throws InstanceNotFoundException {
329 ObjectName fixed1name = transaction.lookupConfigBean(
330 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
332 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
333 .newMXBeanProxy(fixed1name, TestingFixedThreadPoolConfigMXBean.class);
334 return fixedConfigProxy;
338 public void testAbort() {
339 ConfigTransactionJMXClient transaction = configRegistryClient
340 .createTransaction();
341 assertEquals(1, configRegistryClient.getOpenConfigs().size());
343 transaction.abortConfig();
345 transaction.createModule(TestingFixedThreadPoolModuleFactory.NAME,
348 } catch (Exception e) {
349 assertTrue(e.getCause() instanceof InstanceNotFoundException);
352 transaction.validateConfig();
354 } catch (Exception e) {
355 assertTrue(e.getCause() instanceof InstanceNotFoundException);
357 assertEquals(0, configRegistryClient.getOpenConfigs().size());
361 public void testOptimisticLock_ConfigTransactionClient() throws Exception {
362 ConfigTransactionJMXClient transaction1 = configRegistryClient
363 .createTransaction();
364 ConfigTransactionJMXClient transaction2 = configRegistryClient
365 .createTransaction();
366 transaction2.assertVersion(0, 2);
367 transaction2.commit();
369 transaction1.commit();
371 } catch (ConflictingVersionException e) {
373 "Optimistic lock failed. Expected parent version 2, was 0",
379 public void testOptimisticLock_ConfigRegistry() throws Exception {
380 ConfigTransactionJMXClient transaction1 = configRegistryClient
381 .createTransaction();
382 ConfigTransactionJMXClient transaction2 = configRegistryClient
383 .createTransaction();
384 transaction2.assertVersion(0, 2);
385 transaction2.commit();
387 configRegistryClient.commitConfig(transaction1.getObjectName());
389 } catch (ConflictingVersionException e) {
391 "Optimistic lock failed. Expected parent version 2, was 0",
397 public void testOptimisticLock_ConfigTransactionJolokiaClient()
399 ConfigTransactionJolokiaClient transaction1 = configRegistryJolokiaClient
400 .createTransaction();
401 ConfigTransactionJolokiaClient transaction2 = configRegistryJolokiaClient
402 .createTransaction();
403 transaction2.assertVersion(0, 2);
404 transaction2.commit();
406 transaction1.commit();
408 } catch (ConflictingVersionException e) {
410 "Optimistic lock failed. Expected parent version 2, was 0",
416 public void testOptimisticLock_ConfigRegistryJolokiaClient()
418 ConfigTransactionJolokiaClient transaction1 = configRegistryJolokiaClient
419 .createTransaction();
420 ConfigTransactionJolokiaClient transaction2 = configRegistryJolokiaClient
421 .createTransaction();
422 transaction2.assertVersion(0, 2);
423 transaction2.commit();
425 configRegistryJolokiaClient.commitConfig(transaction1
428 } catch (ConflictingVersionException e) {
430 "Optimistic lock failed. Expected parent version 2, was 0",
436 public void testUsingJolokia() throws Exception {
437 ConfigTransactionJolokiaClient transactionClient = configRegistryJolokiaClient
438 .createTransaction();
440 ObjectName name = transactionClient.createModule(
441 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
444 transactionClient.validateConfig();
446 } catch (ValidationException e) {
449 containsString("Parameter 'threadCount' must be greater than 0"));
452 transactionClient.setAttribute(name, "ThreadCount", numberOfThreads);
454 CommitStatus commitStatus = transactionClient.commit();
455 CommitStatus expected = new CommitStatus(Arrays.asList(ObjectNameUtil
456 .withoutTransactionName(name)), emptyONs, emptyONs);
457 assertEquals(expected, commitStatus);