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.assertTrue;
14 import static org.junit.Assert.fail;
16 import com.google.common.collect.Sets;
17 import java.util.Arrays;
18 import java.util.Collections;
19 import java.util.List;
22 import java.util.concurrent.ThreadPoolExecutor;
23 import javax.management.DynamicMBean;
24 import javax.management.InstanceAlreadyExistsException;
25 import javax.management.InstanceNotFoundException;
26 import javax.management.MBeanException;
27 import javax.management.ObjectName;
28 import javax.management.ReflectionException;
29 import org.junit.After;
30 import org.junit.Before;
31 import org.junit.Test;
32 import org.opendaylight.controller.config.api.ConflictingVersionException;
33 import org.opendaylight.controller.config.api.ValidationException;
34 import org.opendaylight.controller.config.api.ValidationException.ExceptionMessageWithStackTrace;
35 import org.opendaylight.controller.config.api.jmx.CommitStatus;
36 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
37 import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
38 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
39 import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPool;
40 import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolConfigMXBean;
41 import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolModuleFactory;
42 import org.opendaylight.controller.config.util.ConfigTransactionClient;
43 import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
46 * Tests basic functionality of configuration registry:
48 * <li>Creation of instance</li>
49 * <li>Destruction of instance</li>
50 * <li>Reconfiguration of live object</li>
51 * <li>Reconfiguration that triggers new object creation</li>
52 * <li>Replacement of running instance with different one with same name</li>
54 * Only one bean is being configured - {@link TestingThreadPoolIfc} which has no
57 public class SimpleConfigurationTest extends AbstractConfigTest {
58 private static final int numberOfThreads = 5;
59 private final int numberOfThreads2 = 10;
60 private static final String fixed1 = "fixed1";
61 private static final List<ObjectName> emptyONs = Collections
62 .<ObjectName> emptyList();
63 private static final ObjectName platformFixed1ON = ObjectNameUtil
64 .createReadOnlyModuleON(TestingFixedThreadPoolModuleFactory.NAME, fixed1);
65 private static final List<ObjectName> fixed1List = Arrays
66 .asList(platformFixed1ON);
70 super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext,
71 new TestingFixedThreadPoolModuleFactory()));
75 public void tearDown() {
76 TestingFixedThreadPool.cleanUp();
79 private ObjectName firstCommit() throws Exception {
80 ConfigTransactionJMXClient transaction = configRegistryClient
83 ObjectName fixed1names = createFixedThreadPool(transaction);
86 assertEquals(1, configRegistryClient.getOpenConfigs().size());
87 CommitStatus commitStatus = transaction.commit();
88 assertEquals(0, configRegistryClient.getOpenConfigs().size());
89 CommitStatus expected = new CommitStatus(Arrays.asList(ObjectNameUtil
90 .withoutTransactionName(fixed1names)), emptyONs, emptyONs);
91 assertEquals(expected, commitStatus);
93 assertEquals(1, TestingFixedThreadPool.allExecutors.size());
94 assertFalse(TestingFixedThreadPool.allExecutors.get(0).isShutdown());
98 static ObjectName createFixedThreadPool(
99 ConfigTransactionJMXClient transaction)
100 throws InstanceAlreadyExistsException, InstanceNotFoundException {
101 transaction.assertVersion(0, 1);
103 ObjectName fixed1names = transaction.createModule(
104 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
105 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
106 .newMXBeanProxy(fixed1names, TestingFixedThreadPoolConfigMXBean.class);
107 fixedConfigProxy.setThreadCount(numberOfThreads);
109 ObjectName retrievedNames = transaction.lookupConfigBean(
110 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
111 assertEquals(fixed1names, retrievedNames);
116 public void testCreateAndDestroyBeanInSameTransaction() throws Exception {
117 ConfigTransactionJMXClient transaction = configRegistryClient
118 .createTransaction();
119 ObjectName fixed1names = createFixedThreadPool(transaction);
120 transaction.destroyModule(fixed1names);
121 CommitStatus commitStatus = transaction.commit();
122 assertStatus(commitStatus, 0, 0, 0);
127 public void testValidationUsingJMXClient() throws Exception {
128 ConfigTransactionClient transaction = configRegistryClient
129 .createTransaction();
130 testValidation(transaction);
134 private void testValidation(ConfigTransactionClient transaction)
135 throws InstanceAlreadyExistsException, ReflectionException,
136 InstanceNotFoundException, MBeanException, ConflictingVersionException {
137 ObjectName fixed1names = transaction.createModule(
138 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
139 // call validate on config bean
141 platformMBeanServer.invoke(fixed1names, "validate", new Object[0],
144 } catch (MBeanException e) {
145 Exception targetException = e.getTargetException();
146 assertNotNull(targetException);
147 assertEquals(ValidationException.class, targetException.getClass());
150 // validate config bean
152 transaction.validateBean(fixed1names);
154 } catch (ValidationException e) {
155 for (Map.Entry<String, Map<String, ExceptionMessageWithStackTrace>> exception : e
156 .getFailedValidations().entrySet()) {
157 for (Map.Entry<String, ExceptionMessageWithStackTrace> entry : exception
158 .getValue().entrySet()) {
160 "Parameter 'threadCount' must be greater than 0",
161 entry.getValue().getMessage());
165 // validate transaction
167 transaction.validateConfig();
169 } catch (ValidationException e) {
170 for (Map.Entry<String, Map<String, ExceptionMessageWithStackTrace>> exception : e
171 .getFailedValidations().entrySet()) {
172 for (Map.Entry<String, ExceptionMessageWithStackTrace> entry : exception
173 .getValue().entrySet()) {
175 "Parameter 'threadCount' must be greater than 0",
176 entry.getValue().getMessage());
181 transaction.commit();
182 } catch (ValidationException e) {
183 for (Map.Entry<String, Map<String, ExceptionMessageWithStackTrace>> exception : e
184 .getFailedValidations().entrySet()) {
185 for (Map.Entry<String, ExceptionMessageWithStackTrace> entry : exception
186 .getValue().entrySet()) {
188 "Parameter 'threadCount' must be greater than 0",
189 entry.getValue().getMessage());
196 public void test_createThreadPool_changeNumberOfThreads() throws Exception {
198 ConfigTransactionJMXClient transaction = configRegistryClient
199 .createTransaction();
200 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = startReconfiguringFixed1ThreadPool(transaction);
201 assertEquals(numberOfThreads, fixedConfigProxy.getThreadCount());
202 fixedConfigProxy.setThreadCount(numberOfThreads2);
203 CommitStatus commitStatus = transaction.commit();
204 checkThreadPools(1, numberOfThreads2);
205 CommitStatus expected = new CommitStatus(emptyONs, fixed1List, emptyONs);
206 assertEquals(expected, commitStatus);
210 public void test_createFixedThreadPool_destroyIt() throws Exception {
211 // 1, start transaction, create new fixed thread pool
212 ObjectName fixed1name = firstCommit();
214 // 2, check that configuration was copied to platform
215 DynamicMBean dynamicMBean = configRegistryClient.newMBeanProxy(
216 ObjectNameUtil.withoutTransactionName(fixed1name),
218 dynamicMBean.getMBeanInfo();
219 assertEquals(numberOfThreads, dynamicMBean.getAttribute("ThreadCount"));
221 // 3, shutdown fixed1 in new transaction
222 assertFalse(TestingFixedThreadPool.allExecutors.get(0).isShutdown());
223 ConfigTransactionJMXClient transaction = configRegistryClient
224 .createTransaction();
227 transaction.assertVersion(1, 2);
229 // test that it was copied to new transaction
230 ObjectName retrievedName = transaction.lookupConfigBean(
231 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
232 assertNotNull(retrievedName);
234 // check that number of threads was copied from dynamic
236 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
237 .newMXBeanProxy(retrievedName, TestingFixedThreadPoolConfigMXBean.class);
238 assertEquals(numberOfThreads, fixedConfigProxy.getThreadCount());
241 transaction.destroyModule(ObjectNameUtil.createTransactionModuleON(
242 transaction.getTransactionName(),
243 TestingFixedThreadPoolModuleFactory.NAME, fixed1));
244 transaction.commit();
247 assertEquals(2, configRegistryClient.getVersion());
248 assertEquals(0, TestingFixedThreadPool.allExecutors.size());
250 // dynamic config should be removed from platform
252 dynamicMBean.getMBeanInfo();
254 } catch (Exception e) {
255 assertTrue(e.getCause() instanceof InstanceNotFoundException);
260 public void testReplaceFixed1() throws Exception {
261 // 1, start transaction, create new fixed thread pool
263 // destroy and recreate with different # of threads
264 ConfigTransactionJMXClient transaction = configRegistryClient
265 .createTransaction();
267 transaction.destroyModule(ObjectNameUtil.createTransactionModuleON(
268 transaction.getTransactionName(),
269 TestingFixedThreadPoolModuleFactory.NAME, fixed1));
271 ObjectName fixed1name = transaction.createModule(
272 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
273 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
274 .newMXBeanProxy(fixed1name, TestingFixedThreadPoolConfigMXBean.class);
275 fixedConfigProxy.setThreadCount(numberOfThreads2);
277 transaction.commit();
278 // check that first threadpool is closed
279 checkThreadPools(1, numberOfThreads2);
282 private void checkThreadPools(int expectedTotalNumberOfExecutors,
283 int expectedNumberOfThreadsInLastExecutor) {
284 assertEquals(expectedTotalNumberOfExecutors,
285 TestingFixedThreadPool.allExecutors.size());
286 for (int i = 0; i < expectedTotalNumberOfExecutors - 1; i++) {
287 assertTrue(TestingFixedThreadPool.allExecutors.get(i).isShutdown());
289 ThreadPoolExecutor lastExecutor = TestingFixedThreadPool.allExecutors
290 .get(expectedTotalNumberOfExecutors - 1);
291 assertFalse(lastExecutor.isShutdown());
292 assertEquals(expectedNumberOfThreadsInLastExecutor,
293 lastExecutor.getMaximumPoolSize());
297 public void testTriggerRecreatingInstance() throws Exception {
298 // 1, start transaction, create new fixed thread pool
300 // switch boolean to create new instance
301 ConfigTransactionJMXClient transaction = configRegistryClient
302 .createTransaction();
303 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = startReconfiguringFixed1ThreadPool(transaction);
305 fixedConfigProxy.setTriggerNewInstanceCreation(true);
307 CommitStatus commitStatus = transaction.commit();
308 // check that new threadpool is created and old one is closed
309 checkThreadPools(1, numberOfThreads);
310 CommitStatus expected = new CommitStatus(emptyONs, emptyONs, fixed1List);
311 assertEquals(expected, commitStatus);
314 // return MBeanProxy for 'fixed1' and current transaction
315 private TestingFixedThreadPoolConfigMXBean startReconfiguringFixed1ThreadPool(
316 ConfigTransactionJMXClient transaction)
317 throws InstanceNotFoundException {
318 ObjectName fixed1name = transaction.lookupConfigBean(
319 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
321 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
322 .newMXBeanProxy(fixed1name, TestingFixedThreadPoolConfigMXBean.class);
323 return fixedConfigProxy;
327 public void testAbort() throws Exception {
328 ConfigTransactionJMXClient transaction = configRegistryClient
329 .createTransaction();
330 assertEquals(1, configRegistryClient.getOpenConfigs().size());
332 transaction.abortConfig();
333 assertEquals(0, configRegistryClient.getOpenConfigs().size());
335 platformMBeanServer.getMBeanInfo(transaction.getObjectName());
337 }catch(InstanceNotFoundException e){
338 assertEquals("org.opendaylight.controller:TransactionName=ConfigTransaction-0-1,type=ConfigTransaction", e.getMessage());
343 public void testOptimisticLock_ConfigTransactionClient() throws Exception {
344 ConfigTransactionJMXClient transaction1 = configRegistryClient
345 .createTransaction();
346 ConfigTransactionJMXClient transaction2 = configRegistryClient
347 .createTransaction();
348 transaction2.assertVersion(0, 2);
349 transaction2.commit();
351 transaction1.commit();
353 } catch (ConflictingVersionException e) {
355 "Optimistic lock failed. Expected parent version 2, was 0",
361 public void testOptimisticLock_ConfigRegistry() throws Exception {
362 ConfigTransactionJMXClient transaction1 = configRegistryClient
363 .createTransaction();
364 ConfigTransactionJMXClient transaction2 = configRegistryClient
365 .createTransaction();
366 transaction2.assertVersion(0, 2);
367 transaction2.commit();
369 configRegistryClient.commitConfig(transaction1.getObjectName());
371 } catch (ConflictingVersionException e) {
373 "Optimistic lock failed. Expected parent version 2, was 0",
380 public void testQNames() {
381 Set<String> availableModuleFactoryQNames = configRegistryClient.getAvailableModuleFactoryQNames();
382 String expected = "(namespace?revision=2012-12-12)name";
384 assertEquals(Sets.newHashSet(expected), availableModuleFactoryQNames);