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 com.google.common.collect.Sets;
11 import org.junit.After;
12 import org.junit.Before;
13 import org.junit.Test;
14 import org.opendaylight.controller.config.api.ConflictingVersionException;
15 import org.opendaylight.controller.config.api.ValidationException;
16 import org.opendaylight.controller.config.api.ValidationException.ExceptionMessageWithStackTrace;
17 import org.opendaylight.controller.config.api.jmx.CommitStatus;
18 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
19 import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
20 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
21 import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPool;
22 import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolConfigMXBean;
23 import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolModuleFactory;
24 import org.opendaylight.controller.config.util.ConfigTransactionClient;
25 import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
27 import javax.management.DynamicMBean;
28 import javax.management.InstanceAlreadyExistsException;
29 import javax.management.InstanceNotFoundException;
30 import javax.management.MBeanException;
31 import javax.management.ObjectName;
32 import javax.management.ReflectionException;
33 import java.util.Arrays;
34 import java.util.Collections;
35 import java.util.List;
38 import java.util.concurrent.ThreadPoolExecutor;
40 import static org.junit.Assert.assertEquals;
41 import static org.junit.Assert.assertFalse;
42 import static org.junit.Assert.assertNotNull;
43 import static org.junit.Assert.assertTrue;
44 import static org.junit.Assert.fail;
47 * Tests basic functionality of configuration registry:
49 * <li>Creation of instance</li>
50 * <li>Destruction of instance</li>
51 * <li>Reconfiguration of live object</li>
52 * <li>Reconfiguration that triggers new object creation</li>
53 * <li>Replacement of running instance with different one with same name</li>
55 * Only one bean is being configured - {@link TestingThreadPoolIfc} which has no
58 public class SimpleConfigurationTest extends AbstractConfigTest {
59 private final int numberOfThreads = 5;
60 private final int numberOfThreads2 = 10;
61 private static final String fixed1 = "fixed1";
62 private static final List<ObjectName> emptyONs = Collections
63 .<ObjectName> emptyList();
64 private static final ObjectName platformFixed1ON = ObjectNameUtil
65 .createReadOnlyModuleON(TestingFixedThreadPoolModuleFactory.NAME, fixed1);
66 private static final List<ObjectName> fixed1List = Arrays
67 .asList(platformFixed1ON);
71 super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(
72 new TestingFixedThreadPoolModuleFactory()));
76 public void tearDown() {
77 TestingFixedThreadPool.cleanUp();
80 private ObjectName firstCommit() throws Exception {
81 ConfigTransactionJMXClient transaction = configRegistryClient
84 ObjectName fixed1names = createFixedThreadPool(transaction);
87 assertEquals(1, configRegistryClient.getOpenConfigs().size());
88 CommitStatus commitStatus = transaction.commit();
89 assertEquals(0, configRegistryClient.getOpenConfigs().size());
90 CommitStatus expected = new CommitStatus(Arrays.asList(ObjectNameUtil
91 .withoutTransactionName(fixed1names)), emptyONs, emptyONs);
92 assertEquals(expected, commitStatus);
94 assertEquals(1, TestingFixedThreadPool.allExecutors.size());
95 assertFalse(TestingFixedThreadPool.allExecutors.get(0).isShutdown());
99 private ObjectName createFixedThreadPool(
100 ConfigTransactionJMXClient transaction)
101 throws InstanceAlreadyExistsException, InstanceNotFoundException {
102 transaction.assertVersion(0, 1);
104 ObjectName fixed1names = transaction.createModule(
105 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
106 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
107 .newMXBeanProxy(fixed1names, TestingFixedThreadPoolConfigMXBean.class);
108 fixedConfigProxy.setThreadCount(numberOfThreads);
110 ObjectName retrievedNames = transaction.lookupConfigBean(
111 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
112 assertEquals(fixed1names, retrievedNames);
117 public void testCreateAndDestroyBeanInSameTransaction() throws Exception {
118 ConfigTransactionJMXClient transaction = configRegistryClient
119 .createTransaction();
120 ObjectName fixed1names = createFixedThreadPool(transaction);
121 transaction.destroyModule(fixed1names);
122 CommitStatus commitStatus = transaction.commit();
123 assertStatus(commitStatus, 0, 0, 0);
128 public void testValidationUsingJMXClient() throws Exception {
129 ConfigTransactionClient transaction = configRegistryClient
130 .createTransaction();
131 testValidation(transaction);
135 private void testValidation(ConfigTransactionClient transaction)
136 throws InstanceAlreadyExistsException, ReflectionException,
137 InstanceNotFoundException, MBeanException, ConflictingVersionException {
138 ObjectName fixed1names = transaction.createModule(
139 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
140 // call validate on config bean
142 platformMBeanServer.invoke(fixed1names, "validate", new Object[0],
145 } catch (MBeanException e) {
146 Exception targetException = e.getTargetException();
147 assertNotNull(targetException);
148 assertEquals(ValidationException.class, targetException.getClass());
151 // validate config bean
153 transaction.validateBean(fixed1names);
155 } catch (ValidationException e) {
156 for (Map.Entry<String, Map<String, ExceptionMessageWithStackTrace>> exception : e
157 .getFailedValidations().entrySet()) {
158 for (Map.Entry<String, ExceptionMessageWithStackTrace> entry : exception
159 .getValue().entrySet()) {
161 "Parameter 'threadCount' must be greater than 0",
162 entry.getValue().getMessage());
166 // validate transaction
168 transaction.validateConfig();
170 } catch (ValidationException e) {
171 for (Map.Entry<String, Map<String, ExceptionMessageWithStackTrace>> exception : e
172 .getFailedValidations().entrySet()) {
173 for (Map.Entry<String, ExceptionMessageWithStackTrace> entry : exception
174 .getValue().entrySet()) {
176 "Parameter 'threadCount' must be greater than 0",
177 entry.getValue().getMessage());
182 transaction.commit();
183 } catch (ValidationException e) {
184 for (Map.Entry<String, Map<String, ExceptionMessageWithStackTrace>> exception : e
185 .getFailedValidations().entrySet()) {
186 for (Map.Entry<String, ExceptionMessageWithStackTrace> entry : exception
187 .getValue().entrySet()) {
189 "Parameter 'threadCount' must be greater than 0",
190 entry.getValue().getMessage());
197 public void test_createThreadPool_changeNumberOfThreads() throws Exception {
199 ConfigTransactionJMXClient transaction = configRegistryClient
200 .createTransaction();
201 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = startReconfiguringFixed1ThreadPool(transaction);
202 assertEquals(numberOfThreads, fixedConfigProxy.getThreadCount());
203 fixedConfigProxy.setThreadCount(numberOfThreads2);
204 CommitStatus commitStatus = transaction.commit();
205 checkThreadPools(1, numberOfThreads2);
206 CommitStatus expected = new CommitStatus(emptyONs, fixed1List, emptyONs);
207 assertEquals(expected, commitStatus);
211 public void test_createFixedThreadPool_destroyIt() throws Exception {
212 // 1, start transaction, create new fixed thread pool
213 ObjectName fixed1name = firstCommit();
215 // 2, check that configuration was copied to platform
216 DynamicMBean dynamicMBean = configRegistryClient.newMBeanProxy(
217 ObjectNameUtil.withoutTransactionName(fixed1name),
219 dynamicMBean.getMBeanInfo();
220 assertEquals(numberOfThreads, dynamicMBean.getAttribute("ThreadCount"));
222 // 3, shutdown fixed1 in new transaction
223 assertFalse(TestingFixedThreadPool.allExecutors.get(0).isShutdown());
224 ConfigTransactionJMXClient transaction = configRegistryClient
225 .createTransaction();
228 transaction.assertVersion(1, 2);
230 // test that it was copied to new transaction
231 ObjectName retrievedName = transaction.lookupConfigBean(
232 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
233 assertNotNull(retrievedName);
235 // check that number of threads was copied from dynamic
237 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
238 .newMXBeanProxy(retrievedName, TestingFixedThreadPoolConfigMXBean.class);
239 assertEquals(numberOfThreads, fixedConfigProxy.getThreadCount());
242 transaction.destroyModule(ObjectNameUtil.createTransactionModuleON(
243 transaction.getTransactionName(),
244 TestingFixedThreadPoolModuleFactory.NAME, fixed1));
245 transaction.commit();
248 assertEquals(2, configRegistryClient.getVersion());
249 assertEquals(1, TestingFixedThreadPool.allExecutors.size());
250 assertTrue(TestingFixedThreadPool.allExecutors.get(0).isShutdown());
252 // dynamic config should be removed from platform
254 dynamicMBean.getMBeanInfo();
256 } catch (Exception e) {
257 assertTrue(e.getCause() instanceof InstanceNotFoundException);
262 public void testReplaceFixed1() throws Exception {
263 // 1, start transaction, create new fixed thread pool
265 // destroy and recreate with different # of threads
266 ConfigTransactionJMXClient transaction = configRegistryClient
267 .createTransaction();
269 transaction.destroyModule(ObjectNameUtil.createTransactionModuleON(
270 transaction.getTransactionName(),
271 TestingFixedThreadPoolModuleFactory.NAME, fixed1));
273 ObjectName fixed1name = transaction.createModule(
274 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
275 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
276 .newMXBeanProxy(fixed1name, TestingFixedThreadPoolConfigMXBean.class);
277 fixedConfigProxy.setThreadCount(numberOfThreads2);
279 transaction.commit();
280 // check that first threadpool is closed
281 checkThreadPools(2, numberOfThreads2);
284 private void checkThreadPools(int expectedTotalNumberOfExecutors,
285 int expectedNumberOfThreadsInLastExecutor) {
286 assertEquals(expectedTotalNumberOfExecutors,
287 TestingFixedThreadPool.allExecutors.size());
288 for (int i = 0; i < expectedTotalNumberOfExecutors - 1; i++) {
289 assertTrue(TestingFixedThreadPool.allExecutors.get(i).isShutdown());
291 ThreadPoolExecutor lastExecutor = TestingFixedThreadPool.allExecutors
292 .get(expectedTotalNumberOfExecutors - 1);
293 assertFalse(lastExecutor.isShutdown());
294 assertEquals(expectedNumberOfThreadsInLastExecutor,
295 lastExecutor.getMaximumPoolSize());
299 public void testTriggerRecreatingInstance() throws Exception {
300 // 1, start transaction, create new fixed thread pool
302 // switch boolean to create new instance
303 ConfigTransactionJMXClient transaction = configRegistryClient
304 .createTransaction();
305 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = startReconfiguringFixed1ThreadPool(transaction);
307 fixedConfigProxy.setTriggerNewInstanceCreation(true);
309 CommitStatus commitStatus = transaction.commit();
310 // check that new threadpool is created and old one is closed
311 checkThreadPools(2, numberOfThreads);
312 CommitStatus expected = new CommitStatus(emptyONs, emptyONs, fixed1List);
313 assertEquals(expected, commitStatus);
316 // return MBeanProxy for 'fixed1' and current transaction
317 private TestingFixedThreadPoolConfigMXBean startReconfiguringFixed1ThreadPool(
318 ConfigTransactionJMXClient transaction)
319 throws InstanceNotFoundException {
320 ObjectName fixed1name = transaction.lookupConfigBean(
321 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
323 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
324 .newMXBeanProxy(fixed1name, TestingFixedThreadPoolConfigMXBean.class);
325 return fixedConfigProxy;
329 public void testAbort() throws InstanceAlreadyExistsException, ValidationException {
330 ConfigTransactionJMXClient transaction = configRegistryClient
331 .createTransaction();
332 assertEquals(1, configRegistryClient.getOpenConfigs().size());
334 transaction.abortConfig();
336 transaction.createModule(TestingFixedThreadPoolModuleFactory.NAME,
339 } catch (IllegalStateException e) {
340 assertEquals("Configuration was aborted", e.getMessage());
343 transaction.validateConfig();
345 } catch (IllegalStateException e) {
346 assertEquals("Configuration was aborted", e.getMessage());
348 assertEquals(0, configRegistryClient.getOpenConfigs().size());
352 public void testOptimisticLock_ConfigTransactionClient() throws Exception {
353 ConfigTransactionJMXClient transaction1 = configRegistryClient
354 .createTransaction();
355 ConfigTransactionJMXClient transaction2 = configRegistryClient
356 .createTransaction();
357 transaction2.assertVersion(0, 2);
358 transaction2.commit();
360 transaction1.commit();
362 } catch (ConflictingVersionException e) {
364 "Optimistic lock failed. Expected parent version 2, was 0",
370 public void testOptimisticLock_ConfigRegistry() throws Exception {
371 ConfigTransactionJMXClient transaction1 = configRegistryClient
372 .createTransaction();
373 ConfigTransactionJMXClient transaction2 = configRegistryClient
374 .createTransaction();
375 transaction2.assertVersion(0, 2);
376 transaction2.commit();
378 configRegistryClient.commitConfig(transaction1.getObjectName());
380 } catch (ConflictingVersionException e) {
382 "Optimistic lock failed. Expected parent version 2, was 0",
389 public void testQNames() {
390 Set<String> availableModuleFactoryQNames = configRegistryClient.getAvailableModuleFactoryQNames();
391 String expected = "(namespace?revision=revision)name";
392 assertEquals(Sets.newHashSet(expected), availableModuleFactoryQNames);