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.InstanceAlreadyExistsException;
24 import javax.management.InstanceNotFoundException;
25 import javax.management.MBeanException;
26 import javax.management.ObjectName;
27 import javax.management.ReflectionException;
28 import org.junit.After;
29 import org.junit.Before;
30 import org.junit.Test;
31 import org.opendaylight.controller.config.api.ConflictingVersionException;
32 import org.opendaylight.controller.config.api.ValidationException;
33 import org.opendaylight.controller.config.api.ValidationException.ExceptionMessageWithStackTrace;
34 import org.opendaylight.controller.config.api.jmx.CommitStatus;
35 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
36 import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
37 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
38 import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPool;
39 import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolConfigMXBean;
40 import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolModuleFactory;
41 import org.opendaylight.controller.config.util.ConfigTransactionClient;
42 import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
45 * Tests basic functionality of configuration registry:
47 * <li>Creation of instance</li>
48 * <li>Destruction of instance</li>
49 * <li>Reconfiguration of live object</li>
50 * <li>Reconfiguration that triggers new object creation</li>
51 * <li>Replacement of running instance with different one with same name</li>
53 * Only one bean is being configured - {@link TestingThreadPoolIfc} which has no
56 public class SimpleConfigurationTest extends AbstractConfigTest {
57 private static final int numberOfThreads = 5;
58 private final int numberOfThreads2 = 10;
59 private static final String fixed1 = "fixed1";
60 private static final List<ObjectName> emptyONs = Collections
61 .<ObjectName> emptyList();
62 private static final ObjectName platformFixed1ON = ObjectNameUtil
63 .createReadOnlyModuleON(TestingFixedThreadPoolModuleFactory.NAME, fixed1);
64 private static final List<ObjectName> fixed1List = Arrays
65 .asList(platformFixed1ON);
69 super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext,
70 new TestingFixedThreadPoolModuleFactory()));
74 public void tearDown() {
75 TestingFixedThreadPool.cleanUp();
78 private ObjectName firstCommit() throws Exception {
79 ConfigTransactionJMXClient transaction = configRegistryClient
82 ObjectName fixed1names = createFixedThreadPool(transaction);
85 assertEquals(1, configRegistryClient.getOpenConfigs().size());
86 CommitStatus commitStatus = transaction.commit();
87 assertEquals(0, configRegistryClient.getOpenConfigs().size());
88 CommitStatus expected = new CommitStatus(Arrays.asList(ObjectNameUtil
89 .withoutTransactionName(fixed1names)), emptyONs, emptyONs);
90 assertEquals(expected, commitStatus);
92 assertEquals(1, TestingFixedThreadPool.allExecutors.size());
93 assertFalse(TestingFixedThreadPool.allExecutors.get(0).isShutdown());
97 static ObjectName createFixedThreadPool(
98 ConfigTransactionJMXClient transaction)
99 throws InstanceAlreadyExistsException, InstanceNotFoundException {
100 transaction.assertVersion(0, 1);
102 ObjectName fixed1names = transaction.createModule(
103 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
104 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
105 .newMXBeanProxy(fixed1names, TestingFixedThreadPoolConfigMXBean.class);
106 fixedConfigProxy.setThreadCount(numberOfThreads);
108 ObjectName retrievedNames = transaction.lookupConfigBean(
109 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
110 assertEquals(fixed1names, retrievedNames);
115 public void testCreateAndDestroyBeanInSameTransaction() throws Exception {
116 ConfigTransactionJMXClient transaction = configRegistryClient
117 .createTransaction();
118 ObjectName fixed1names = createFixedThreadPool(transaction);
119 transaction.destroyModule(fixed1names);
120 CommitStatus commitStatus = transaction.commit();
121 assertStatus(commitStatus, 0, 0, 0);
126 public void testValidationUsingJMXClient() throws Exception {
127 ConfigTransactionClient transaction = configRegistryClient
128 .createTransaction();
129 testValidation(transaction);
133 private void testValidation(ConfigTransactionClient transaction)
134 throws InstanceAlreadyExistsException, ReflectionException,
135 InstanceNotFoundException, MBeanException, ConflictingVersionException {
136 ObjectName fixed1names = transaction.createModule(
137 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
138 // call validate on config bean
140 platformMBeanServer.invoke(fixed1names, "validate", new Object[0],
143 } catch (MBeanException e) {
144 Exception targetException = e.getTargetException();
145 assertNotNull(targetException);
146 assertEquals(ValidationException.class, targetException.getClass());
149 // validate config bean
151 transaction.validateBean(fixed1names);
153 } catch (ValidationException e) {
154 for (Map.Entry<String, Map<String, ExceptionMessageWithStackTrace>> exception : e
155 .getFailedValidations().entrySet()) {
156 for (Map.Entry<String, ExceptionMessageWithStackTrace> entry : exception
157 .getValue().entrySet()) {
159 "Parameter 'threadCount' must be greater than 0",
160 entry.getValue().getMessage());
164 // validate transaction
166 transaction.validateConfig();
168 } catch (ValidationException e) {
169 for (Map.Entry<String, Map<String, ExceptionMessageWithStackTrace>> exception : e
170 .getFailedValidations().entrySet()) {
171 for (Map.Entry<String, ExceptionMessageWithStackTrace> entry : exception
172 .getValue().entrySet()) {
174 "Parameter 'threadCount' must be greater than 0",
175 entry.getValue().getMessage());
180 transaction.commit();
181 } catch (ValidationException e) {
182 for (Map.Entry<String, Map<String, ExceptionMessageWithStackTrace>> exception : e
183 .getFailedValidations().entrySet()) {
184 for (Map.Entry<String, ExceptionMessageWithStackTrace> entry : exception
185 .getValue().entrySet()) {
187 "Parameter 'threadCount' must be greater than 0",
188 entry.getValue().getMessage());
195 public void test_createThreadPool_changeNumberOfThreads() throws Exception {
197 ConfigTransactionJMXClient transaction = configRegistryClient
198 .createTransaction();
199 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = startReconfiguringFixed1ThreadPool(transaction);
200 assertEquals(numberOfThreads, fixedConfigProxy.getThreadCount());
201 fixedConfigProxy.setThreadCount(numberOfThreads2);
202 CommitStatus commitStatus = transaction.commit();
203 checkThreadPools(1, numberOfThreads2);
204 CommitStatus expected = new CommitStatus(emptyONs, fixed1List, emptyONs);
205 assertEquals(expected, commitStatus);
209 public void test_createFixedThreadPool_destroyIt() throws Exception {
210 // 1, start transaction, create new fixed thread pool
211 ObjectName fixed1name = firstCommit();
213 // 2, check that configuration was copied to platform
214 ObjectName on = ObjectNameUtil.withoutTransactionName(fixed1name);
215 platformMBeanServer.getMBeanInfo(on);
216 assertEquals(numberOfThreads, platformMBeanServer.getAttribute(on, "ThreadCount"));
218 // 3, shutdown fixed1 in new transaction
219 assertFalse(TestingFixedThreadPool.allExecutors.get(0).isShutdown());
220 ConfigTransactionJMXClient transaction = configRegistryClient
221 .createTransaction();
224 transaction.assertVersion(1, 2);
226 // test that it was copied to new transaction
227 ObjectName retrievedName = transaction.lookupConfigBean(
228 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
229 assertNotNull(retrievedName);
231 // check that number of threads was copied from dynamic
233 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
234 .newMXBeanProxy(retrievedName, TestingFixedThreadPoolConfigMXBean.class);
235 assertEquals(numberOfThreads, fixedConfigProxy.getThreadCount());
238 transaction.destroyModule(ObjectNameUtil.createTransactionModuleON(
239 transaction.getTransactionName(),
240 TestingFixedThreadPoolModuleFactory.NAME, fixed1));
241 transaction.commit();
244 assertEquals(2, configRegistryClient.getVersion());
245 assertEquals(0, TestingFixedThreadPool.allExecutors.size());
247 // dynamic config should be removed from platform
249 platformMBeanServer.getMBeanInfo(on);
251 } catch (Exception e) {
252 assertTrue(e instanceof InstanceNotFoundException);
257 public void testReplaceFixed1() throws Exception {
258 // 1, start transaction, create new fixed thread pool
260 // destroy and recreate with different # of threads
261 ConfigTransactionJMXClient transaction = configRegistryClient
262 .createTransaction();
264 transaction.destroyModule(ObjectNameUtil.createTransactionModuleON(
265 transaction.getTransactionName(),
266 TestingFixedThreadPoolModuleFactory.NAME, fixed1));
268 ObjectName fixed1name = transaction.createModule(
269 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
270 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
271 .newMXBeanProxy(fixed1name, TestingFixedThreadPoolConfigMXBean.class);
272 fixedConfigProxy.setThreadCount(numberOfThreads2);
274 transaction.commit();
275 // check that first threadpool is closed
276 checkThreadPools(1, numberOfThreads2);
279 private void checkThreadPools(int expectedTotalNumberOfExecutors,
280 int expectedNumberOfThreadsInLastExecutor) {
281 assertEquals(expectedTotalNumberOfExecutors,
282 TestingFixedThreadPool.allExecutors.size());
283 for (int i = 0; i < expectedTotalNumberOfExecutors - 1; i++) {
284 assertTrue(TestingFixedThreadPool.allExecutors.get(i).isShutdown());
286 ThreadPoolExecutor lastExecutor = TestingFixedThreadPool.allExecutors
287 .get(expectedTotalNumberOfExecutors - 1);
288 assertFalse(lastExecutor.isShutdown());
289 assertEquals(expectedNumberOfThreadsInLastExecutor,
290 lastExecutor.getMaximumPoolSize());
294 public void testTriggerRecreatingInstance() throws Exception {
295 // 1, start transaction, create new fixed thread pool
297 // switch boolean to create new instance
298 ConfigTransactionJMXClient transaction = configRegistryClient
299 .createTransaction();
300 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = startReconfiguringFixed1ThreadPool(transaction);
302 fixedConfigProxy.setTriggerNewInstanceCreation(true);
304 CommitStatus commitStatus = transaction.commit();
305 // check that new threadpool is created and old one is closed
306 checkThreadPools(1, numberOfThreads);
307 CommitStatus expected = new CommitStatus(emptyONs, emptyONs, fixed1List);
308 assertEquals(expected, commitStatus);
311 // return MBeanProxy for 'fixed1' and current transaction
312 private TestingFixedThreadPoolConfigMXBean startReconfiguringFixed1ThreadPool(
313 ConfigTransactionJMXClient transaction)
314 throws InstanceNotFoundException {
315 ObjectName fixed1name = transaction.lookupConfigBean(
316 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
318 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction
319 .newMXBeanProxy(fixed1name, TestingFixedThreadPoolConfigMXBean.class);
320 return fixedConfigProxy;
324 public void testAbort() throws Exception {
325 ConfigTransactionJMXClient transaction = configRegistryClient
326 .createTransaction();
327 assertEquals(1, configRegistryClient.getOpenConfigs().size());
329 transaction.abortConfig();
330 assertEquals(0, configRegistryClient.getOpenConfigs().size());
332 platformMBeanServer.getMBeanInfo(transaction.getObjectName());
334 }catch(InstanceNotFoundException e){
335 assertEquals("org.opendaylight.controller:TransactionName=ConfigTransaction-0-1,type=ConfigTransaction", e.getMessage());
340 public void testOptimisticLock_ConfigTransactionClient() throws Exception {
341 ConfigTransactionJMXClient transaction1 = configRegistryClient
342 .createTransaction();
343 ConfigTransactionJMXClient transaction2 = configRegistryClient
344 .createTransaction();
345 transaction2.assertVersion(0, 2);
346 transaction2.commit();
348 transaction1.commit();
350 } catch (ConflictingVersionException e) {
352 "Optimistic lock failed. Expected parent version 2, was 0",
358 public void testOptimisticLock_ConfigRegistry() throws Exception {
359 ConfigTransactionJMXClient transaction1 = configRegistryClient
360 .createTransaction();
361 ConfigTransactionJMXClient transaction2 = configRegistryClient
362 .createTransaction();
363 transaction2.assertVersion(0, 2);
364 transaction2.commit();
366 configRegistryClient.commitConfig(transaction1.getObjectName());
368 } catch (ConflictingVersionException e) {
370 "Optimistic lock failed. Expected parent version 2, was 0",
377 public void testQNames() {
378 Set<String> availableModuleFactoryQNames = configRegistryClient.getAvailableModuleFactoryQNames();
379 String expected = "(namespace?revision=2012-12-12)name";
381 assertEquals(Sets.newHashSet(expected), availableModuleFactoryQNames);