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 javax.management.RuntimeMBeanException;
34 import java.util.Arrays;
35 import java.util.Collections;
36 import java.util.List;
39 import java.util.concurrent.ThreadPoolExecutor;
41 import static org.junit.Assert.assertEquals;
42 import static org.junit.Assert.assertFalse;
43 import static org.junit.Assert.assertNotNull;
44 import static org.junit.Assert.assertTrue;
45 import static org.junit.Assert.fail;
48 * Tests basic functionality of configuration registry:
50 * <li>Creation of instance</li>
51 * <li>Destruction of instance</li>
52 * <li>Reconfiguration of live object</li>
53 * <li>Reconfiguration that triggers new object creation</li>
54 * <li>Replacement of running instance with different one with same name</li>
56 * Only one bean is being configured - {@link TestingThreadPoolIfc} which has no
59 public class SimpleConfigurationTest extends AbstractConfigTest {
60 private final int numberOfThreads = 5;
61 private final int numberOfThreads2 = 10;
62 private static final String fixed1 = "fixed1";
63 private static final List<ObjectName> emptyONs = Collections
64 .<ObjectName> emptyList();
65 private static final ObjectName platformFixed1ON = ObjectNameUtil
66 .createReadOnlyModuleON(TestingFixedThreadPoolModuleFactory.NAME, fixed1);
67 private static final List<ObjectName> fixed1List = Arrays
68 .asList(platformFixed1ON);
72 super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(
73 new TestingFixedThreadPoolModuleFactory()));
77 public void tearDown() {
78 TestingFixedThreadPool.cleanUp();
81 private ObjectName firstCommit() throws Exception {
82 ConfigTransactionJMXClient transaction = configRegistryClient
85 ObjectName fixed1names = createFixedThreadPool(transaction);
88 assertEquals(1, configRegistryClient.getOpenConfigs().size());
89 CommitStatus commitStatus = transaction.commit();
90 assertEquals(0, configRegistryClient.getOpenConfigs().size());
91 CommitStatus expected = new CommitStatus(Arrays.asList(ObjectNameUtil
92 .withoutTransactionName(fixed1names)), emptyONs, emptyONs);
93 assertEquals(expected, commitStatus);
95 assertEquals(1, TestingFixedThreadPool.allExecutors.size());
96 assertFalse(TestingFixedThreadPool.allExecutors.get(0).isShutdown());
100 private ObjectName createFixedThreadPool(
101 ConfigTransactionJMXClient transaction)
102 throws InstanceAlreadyExistsException, InstanceNotFoundException {
103 transaction.assertVersion(0, 1);
105 ObjectName fixed1names = transaction.createModule(
106 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
107 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
108 .newMXBeanProxy(fixed1names, TestingFixedThreadPoolConfigMXBean.class);
109 fixedConfigProxy.setThreadCount(numberOfThreads);
111 ObjectName retrievedNames = transaction.lookupConfigBean(
112 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
113 assertEquals(fixed1names, retrievedNames);
118 public void testCreateAndDestroyBeanInSameTransaction() throws Exception {
119 ConfigTransactionJMXClient transaction = configRegistryClient
120 .createTransaction();
121 ObjectName fixed1names = createFixedThreadPool(transaction);
122 transaction.destroyModule(fixed1names);
123 CommitStatus commitStatus = transaction.commit();
124 assertStatus(commitStatus, 0, 0, 0);
129 public void testValidationUsingJMXClient() throws Exception {
130 ConfigTransactionClient transaction = configRegistryClient
131 .createTransaction();
132 testValidation(transaction);
136 private void testValidation(ConfigTransactionClient transaction)
137 throws InstanceAlreadyExistsException, ReflectionException,
138 InstanceNotFoundException, MBeanException {
139 ObjectName fixed1names = transaction.createModule(
140 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
141 // call validate on config bean
143 platformMBeanServer.invoke(fixed1names, "validate", new Object[0],
146 } catch (RuntimeMBeanException e) {
147 RuntimeException targetException = e.getTargetException();
148 assertNotNull(targetException);
149 assertEquals(ValidationException.class, targetException.getClass());
152 // validate config bean
154 transaction.validateBean(fixed1names);
156 } catch (ValidationException e) {
157 for (Map.Entry<String, Map<String, ExceptionMessageWithStackTrace>> exception : e
158 .getFailedValidations().entrySet()) {
159 for (Map.Entry<String, ExceptionMessageWithStackTrace> entry : exception
160 .getValue().entrySet()) {
162 "Parameter 'threadCount' must be greater than 0",
163 entry.getValue().getMessage());
167 // validate transaction
169 transaction.validateConfig();
171 } catch (ValidationException e) {
172 for (Map.Entry<String, Map<String, ExceptionMessageWithStackTrace>> exception : e
173 .getFailedValidations().entrySet()) {
174 for (Map.Entry<String, ExceptionMessageWithStackTrace> entry : exception
175 .getValue().entrySet()) {
177 "Parameter 'threadCount' must be greater than 0",
178 entry.getValue().getMessage());
183 transaction.commit();
184 } catch (ValidationException e) {
185 for (Map.Entry<String, Map<String, ExceptionMessageWithStackTrace>> exception : e
186 .getFailedValidations().entrySet()) {
187 for (Map.Entry<String, ExceptionMessageWithStackTrace> entry : exception
188 .getValue().entrySet()) {
190 "Parameter 'threadCount' must be greater than 0",
191 entry.getValue().getMessage());
198 public void test_createThreadPool_changeNumberOfThreads() throws Exception {
200 ConfigTransactionJMXClient transaction = configRegistryClient
201 .createTransaction();
202 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = startReconfiguringFixed1ThreadPool(transaction);
203 assertEquals(numberOfThreads, fixedConfigProxy.getThreadCount());
204 fixedConfigProxy.setThreadCount(numberOfThreads2);
205 CommitStatus commitStatus = transaction.commit();
206 checkThreadPools(1, numberOfThreads2);
207 CommitStatus expected = new CommitStatus(emptyONs, fixed1List, emptyONs);
208 assertEquals(expected, commitStatus);
212 public void test_createFixedThreadPool_destroyIt() throws Exception {
213 // 1, start transaction, create new fixed thread pool
214 ObjectName fixed1name = firstCommit();
216 // 2, check that configuration was copied to platform
217 DynamicMBean dynamicMBean = configRegistryClient.newMBeanProxy(
218 ObjectNameUtil.withoutTransactionName(fixed1name),
220 dynamicMBean.getMBeanInfo();
221 assertEquals(numberOfThreads, dynamicMBean.getAttribute("ThreadCount"));
223 // 3, shutdown fixed1 in new transaction
224 assertFalse(TestingFixedThreadPool.allExecutors.get(0).isShutdown());
225 ConfigTransactionJMXClient transaction = configRegistryClient
226 .createTransaction();
229 transaction.assertVersion(1, 2);
231 // test that it was copied to new transaction
232 ObjectName retrievedName = transaction.lookupConfigBean(
233 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
234 assertNotNull(retrievedName);
236 // check that number of threads was copied from dynamic
238 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
239 .newMXBeanProxy(retrievedName, TestingFixedThreadPoolConfigMXBean.class);
240 assertEquals(numberOfThreads, fixedConfigProxy.getThreadCount());
243 transaction.destroyModule(ObjectNameUtil.createTransactionModuleON(
244 transaction.getTransactionName(),
245 TestingFixedThreadPoolModuleFactory.NAME, fixed1));
246 transaction.commit();
249 assertEquals(2, configRegistryClient.getVersion());
250 assertEquals(1, TestingFixedThreadPool.allExecutors.size());
251 assertTrue(TestingFixedThreadPool.allExecutors.get(0).isShutdown());
253 // dynamic config should be removed from platform
255 dynamicMBean.getMBeanInfo();
257 } catch (Exception e) {
258 assertTrue(e.getCause() instanceof InstanceNotFoundException);
263 public void testReplaceFixed1() throws Exception {
264 // 1, start transaction, create new fixed thread pool
266 // destroy and recreate with different # of threads
267 ConfigTransactionJMXClient transaction = configRegistryClient
268 .createTransaction();
270 transaction.destroyModule(ObjectNameUtil.createTransactionModuleON(
271 transaction.getTransactionName(),
272 TestingFixedThreadPoolModuleFactory.NAME, fixed1));
274 ObjectName fixed1name = transaction.createModule(
275 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
276 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
277 .newMXBeanProxy(fixed1name, TestingFixedThreadPoolConfigMXBean.class);
278 fixedConfigProxy.setThreadCount(numberOfThreads2);
280 transaction.commit();
281 // check that first threadpool is closed
282 checkThreadPools(2, numberOfThreads2);
285 private void checkThreadPools(int expectedTotalNumberOfExecutors,
286 int expectedNumberOfThreadsInLastExecutor) {
287 assertEquals(expectedTotalNumberOfExecutors,
288 TestingFixedThreadPool.allExecutors.size());
289 for (int i = 0; i < expectedTotalNumberOfExecutors - 1; i++) {
290 assertTrue(TestingFixedThreadPool.allExecutors.get(i).isShutdown());
292 ThreadPoolExecutor lastExecutor = TestingFixedThreadPool.allExecutors
293 .get(expectedTotalNumberOfExecutors - 1);
294 assertFalse(lastExecutor.isShutdown());
295 assertEquals(expectedNumberOfThreadsInLastExecutor,
296 lastExecutor.getMaximumPoolSize());
300 public void testTriggerRecreatingInstance() throws Exception {
301 // 1, start transaction, create new fixed thread pool
303 // switch boolean to create new instance
304 ConfigTransactionJMXClient transaction = configRegistryClient
305 .createTransaction();
306 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = startReconfiguringFixed1ThreadPool(transaction);
308 fixedConfigProxy.setTriggerNewInstanceCreation(true);
310 CommitStatus commitStatus = transaction.commit();
311 // check that new threadpool is created and old one is closed
312 checkThreadPools(2, numberOfThreads);
313 CommitStatus expected = new CommitStatus(emptyONs, emptyONs, fixed1List);
314 assertEquals(expected, commitStatus);
317 // return MBeanProxy for 'fixed1' and current transaction
318 private TestingFixedThreadPoolConfigMXBean startReconfiguringFixed1ThreadPool(
319 ConfigTransactionJMXClient transaction)
320 throws InstanceNotFoundException {
321 ObjectName fixed1name = transaction.lookupConfigBean(
322 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
324 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
325 .newMXBeanProxy(fixed1name, TestingFixedThreadPoolConfigMXBean.class);
326 return fixedConfigProxy;
330 public void testAbort() {
331 ConfigTransactionJMXClient transaction = configRegistryClient
332 .createTransaction();
333 assertEquals(1, configRegistryClient.getOpenConfigs().size());
335 transaction.abortConfig();
337 transaction.createModule(TestingFixedThreadPoolModuleFactory.NAME,
340 } catch (Exception e) {
341 assertTrue(e.getCause() instanceof InstanceNotFoundException);
344 transaction.validateConfig();
346 } catch (Exception e) {
347 assertTrue(e.getCause() instanceof InstanceNotFoundException);
349 assertEquals(0, configRegistryClient.getOpenConfigs().size());
353 public void testOptimisticLock_ConfigTransactionClient() throws Exception {
354 ConfigTransactionJMXClient transaction1 = configRegistryClient
355 .createTransaction();
356 ConfigTransactionJMXClient transaction2 = configRegistryClient
357 .createTransaction();
358 transaction2.assertVersion(0, 2);
359 transaction2.commit();
361 transaction1.commit();
363 } catch (ConflictingVersionException e) {
365 "Optimistic lock failed. Expected parent version 2, was 0",
371 public void testOptimisticLock_ConfigRegistry() throws Exception {
372 ConfigTransactionJMXClient transaction1 = configRegistryClient
373 .createTransaction();
374 ConfigTransactionJMXClient transaction2 = configRegistryClient
375 .createTransaction();
376 transaction2.assertVersion(0, 2);
377 transaction2.commit();
379 configRegistryClient.commitConfig(transaction1.getObjectName());
381 } catch (ConflictingVersionException e) {
383 "Optimistic lock failed. Expected parent version 2, was 0",
390 public void testQNames() {
391 Set<String> availableModuleFactoryQNames = configRegistryClient.getAvailableModuleFactoryQNames();
392 String expected = "(namespace?revision=revision)name";
393 assertEquals(Sets.newHashSet(expected), availableModuleFactoryQNames);