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.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;
51 * Tests basic functionality of configuration registry:
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>
59 * Only one bean is being configured - {@link TestingThreadPoolIfc} which has no
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);
75 super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(
76 new TestingFixedThreadPoolModuleFactory()));
80 public void tearDown() {
81 TestingFixedThreadPool.cleanUp();
84 private ObjectName firstCommit() throws Exception {
85 ConfigTransactionJMXClient transaction = configRegistryClient
88 ObjectName fixed1names = createFixedThreadPool(transaction);
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);
98 assertEquals(1, TestingFixedThreadPool.allExecutors.size());
99 assertFalse(TestingFixedThreadPool.allExecutors.get(0).isShutdown());
103 private ObjectName createFixedThreadPool(
104 ConfigTransactionJMXClient transaction)
105 throws InstanceAlreadyExistsException, InstanceNotFoundException {
106 transaction.assertVersion(0, 1);
108 ObjectName fixed1names = transaction.createModule(
109 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
110 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
111 .newMXBeanProxy(fixed1names, TestingFixedThreadPoolConfigMXBean.class);
112 fixedConfigProxy.setThreadCount(numberOfThreads);
114 ObjectName retrievedNames = transaction.lookupConfigBean(
115 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
116 assertEquals(fixed1names, retrievedNames);
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);
132 public void testValidationUsingJMXClient() throws Exception {
133 ConfigTransactionClient transaction = configRegistryClient
134 .createTransaction();
135 testValidation(transaction);
139 public void testValidationUsingJolokiaClient() throws Exception {
140 ConfigTransactionClient transaction = configRegistryJolokiaClient
141 .createTransaction();
142 testValidation(transaction);
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
152 platformMBeanServer.invoke(fixed1names, "validate", new Object[0],
155 } catch (RuntimeMBeanException e) {
156 RuntimeException targetException = e.getTargetException();
157 assertNotNull(targetException);
158 assertEquals(ValidationException.class, targetException.getClass());
161 // validate config bean
163 transaction.validateBean(fixed1names);
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()) {
171 "Parameter 'threadCount' must be greater than 0",
172 entry.getValue().getMessage());
176 // validate transaction
178 transaction.validateConfig();
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()) {
186 "Parameter 'threadCount' must be greater than 0",
187 entry.getValue().getMessage());
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()) {
199 "Parameter 'threadCount' must be greater than 0",
200 entry.getValue().getMessage());
207 public void test_createThreadPool_changeNumberOfThreads() throws Exception {
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);
221 public void test_createFixedThreadPool_destroyIt() throws Exception {
222 // 1, start transaction, create new fixed thread pool
223 ObjectName fixed1name = firstCommit();
225 // 2, check that configuration was copied to platform
226 DynamicMBean dynamicMBean = configRegistryClient.newMBeanProxy(
227 ObjectNameUtil.withoutTransactionName(fixed1name),
229 dynamicMBean.getMBeanInfo();
230 assertEquals(numberOfThreads, dynamicMBean.getAttribute("ThreadCount"));
232 // 3, shutdown fixed1 in new transaction
233 assertFalse(TestingFixedThreadPool.allExecutors.get(0).isShutdown());
234 ConfigTransactionJMXClient transaction = configRegistryClient
235 .createTransaction();
238 transaction.assertVersion(1, 2);
240 // test that it was copied to new transaction
241 ObjectName retrievedName = transaction.lookupConfigBean(
242 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
243 assertNotNull(retrievedName);
245 // check that number of threads was copied from dynamic
247 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
248 .newMXBeanProxy(retrievedName, TestingFixedThreadPoolConfigMXBean.class);
249 assertEquals(numberOfThreads, fixedConfigProxy.getThreadCount());
252 transaction.destroyModule(ObjectNameUtil.createTransactionModuleON(
253 transaction.getTransactionName(),
254 TestingFixedThreadPoolModuleFactory.NAME, fixed1));
255 transaction.commit();
258 assertEquals(2, configRegistryClient.getVersion());
259 assertEquals(1, TestingFixedThreadPool.allExecutors.size());
260 assertTrue(TestingFixedThreadPool.allExecutors.get(0).isShutdown());
262 // dynamic config should be removed from platform
264 dynamicMBean.getMBeanInfo();
266 } catch (Exception e) {
267 assertTrue(e.getCause() instanceof InstanceNotFoundException);
272 public void testReplaceFixed1() throws Exception {
273 // 1, start transaction, create new fixed thread pool
275 // destroy and recreate with different # of threads
276 ConfigTransactionJMXClient transaction = configRegistryClient
277 .createTransaction();
279 transaction.destroyModule(ObjectNameUtil.createTransactionModuleON(
280 transaction.getTransactionName(),
281 TestingFixedThreadPoolModuleFactory.NAME, fixed1));
283 ObjectName fixed1name = transaction.createModule(
284 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
285 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
286 .newMXBeanProxy(fixed1name, TestingFixedThreadPoolConfigMXBean.class);
287 fixedConfigProxy.setThreadCount(numberOfThreads2);
289 transaction.commit();
290 // check that first threadpool is closed
291 checkThreadPools(2, numberOfThreads2);
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());
301 ThreadPoolExecutor lastExecutor = TestingFixedThreadPool.allExecutors
302 .get(expectedTotalNumberOfExecutors - 1);
303 assertFalse(lastExecutor.isShutdown());
304 assertEquals(expectedNumberOfThreadsInLastExecutor,
305 lastExecutor.getMaximumPoolSize());
309 public void testTriggerRecreatingInstance() throws Exception {
310 // 1, start transaction, create new fixed thread pool
312 // switch boolean to create new instance
313 ConfigTransactionJMXClient transaction = configRegistryClient
314 .createTransaction();
315 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = startReconfiguringFixed1ThreadPool(transaction);
317 fixedConfigProxy.setTriggerNewInstanceCreation(true);
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);
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);
333 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
334 .newMXBeanProxy(fixed1name, TestingFixedThreadPoolConfigMXBean.class);
335 return fixedConfigProxy;
339 public void testAbort() {
340 ConfigTransactionJMXClient transaction = configRegistryClient
341 .createTransaction();
342 assertEquals(1, configRegistryClient.getOpenConfigs().size());
344 transaction.abortConfig();
346 transaction.createModule(TestingFixedThreadPoolModuleFactory.NAME,
349 } catch (Exception e) {
350 assertTrue(e.getCause() instanceof InstanceNotFoundException);
353 transaction.validateConfig();
355 } catch (Exception e) {
356 assertTrue(e.getCause() instanceof InstanceNotFoundException);
358 assertEquals(0, configRegistryClient.getOpenConfigs().size());
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();
370 transaction1.commit();
372 } catch (ConflictingVersionException e) {
374 "Optimistic lock failed. Expected parent version 2, was 0",
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();
388 configRegistryClient.commitConfig(transaction1.getObjectName());
390 } catch (ConflictingVersionException e) {
392 "Optimistic lock failed. Expected parent version 2, was 0",
398 public void testOptimisticLock_ConfigTransactionJolokiaClient()
400 ConfigTransactionJolokiaClient transaction1 = configRegistryJolokiaClient
401 .createTransaction();
402 ConfigTransactionJolokiaClient transaction2 = configRegistryJolokiaClient
403 .createTransaction();
404 transaction2.assertVersion(0, 2);
405 transaction2.commit();
407 transaction1.commit();
409 } catch (ConflictingVersionException e) {
411 "Optimistic lock failed. Expected parent version 2, was 0",
417 public void testOptimisticLock_ConfigRegistryJolokiaClient()
419 ConfigTransactionJolokiaClient transaction1 = configRegistryJolokiaClient
420 .createTransaction();
421 ConfigTransactionJolokiaClient transaction2 = configRegistryJolokiaClient
422 .createTransaction();
423 transaction2.assertVersion(0, 2);
424 transaction2.commit();
426 configRegistryJolokiaClient.commitConfig(transaction1
429 } catch (ConflictingVersionException e) {
431 "Optimistic lock failed. Expected parent version 2, was 0",
437 public void testUsingJolokia() throws Exception {
438 ConfigTransactionJolokiaClient transactionClient = configRegistryJolokiaClient
439 .createTransaction();
441 ObjectName name = transactionClient.createModule(
442 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
445 transactionClient.validateConfig();
447 } catch (ValidationException e) {
450 containsString("Parameter 'threadCount' must be greater than 0"));
453 transactionClient.setAttribute(name, "ThreadCount", numberOfThreads);
455 CommitStatus commitStatus = transactionClient.commit();
456 CommitStatus expected = new CommitStatus(Arrays.asList(ObjectNameUtil
457 .withoutTransactionName(name)), emptyONs, emptyONs);
458 assertEquals(expected, commitStatus);