2 * Copyright (c) 2013, 2017 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.IntrospectionException;
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.manager.testingservices.threadpool.TestingThreadPoolIfc;
43 import org.opendaylight.controller.config.util.ConfigTransactionClient;
44 import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
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 static final int NUMBER_OF_THREADS = 5;
60 private static final int NUMBER_OF_THREADS2 = 10;
61 private static final String FIXED1 = "fixed1";
62 private static final List<ObjectName> EMPTYO_NS = Collections.<ObjectName>emptyList();
63 private static final ObjectName PLATFORM_FIXED1ON = ObjectNameUtil
64 .createReadOnlyModuleON(TestingFixedThreadPoolModuleFactory.NAME, FIXED1);
65 private static final List<ObjectName> FIXED1_LIST = Arrays.asList(PLATFORM_FIXED1ON);
69 super.initConfigTransactionManagerImpl(
70 new HardcodedModuleFactoriesResolver(mockedContext, new TestingFixedThreadPoolModuleFactory()));
74 public void tearDown() {
75 TestingFixedThreadPool.cleanUp();
78 private ObjectName firstCommit() throws Exception {
79 ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
81 ObjectName fixed1names = createFixedThreadPool(transaction);
84 assertEquals(1, configRegistryClient.getOpenConfigs().size());
85 CommitStatus commitStatus = transaction.commit();
86 assertEquals(0, configRegistryClient.getOpenConfigs().size());
87 CommitStatus expected = new CommitStatus(Arrays.asList(ObjectNameUtil.withoutTransactionName(fixed1names)),
88 EMPTYO_NS, EMPTYO_NS);
89 assertEquals(expected, commitStatus);
91 assertEquals(1, TestingFixedThreadPool.ALL_EXECUTORS.size());
92 assertFalse(TestingFixedThreadPool.ALL_EXECUTORS.get(0).isShutdown());
96 static ObjectName createFixedThreadPool(final ConfigTransactionJMXClient transaction)
97 throws InstanceAlreadyExistsException, InstanceNotFoundException {
98 transaction.assertVersion(0, 1);
100 ObjectName fixed1names = transaction.createModule(TestingFixedThreadPoolModuleFactory.NAME, FIXED1);
101 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction.newMXBeanProxy(fixed1names,
102 TestingFixedThreadPoolConfigMXBean.class);
103 fixedConfigProxy.setThreadCount(NUMBER_OF_THREADS);
105 ObjectName retrievedNames = transaction.lookupConfigBean(TestingFixedThreadPoolModuleFactory.NAME, FIXED1);
106 assertEquals(fixed1names, retrievedNames);
111 public void testCreateAndDestroyBeanInSameTransaction() throws Exception {
112 ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
113 ObjectName fixed1names = createFixedThreadPool(transaction);
114 transaction.destroyModule(fixed1names);
115 CommitStatus commitStatus = transaction.commit();
116 assertStatus(commitStatus, 0, 0, 0);
121 public void testValidationUsingJMXClient() throws Exception {
122 ConfigTransactionClient transaction = configRegistryClient.createTransaction();
123 testValidation(transaction);
126 private static void testValidation(final ConfigTransactionClient transaction) throws InstanceAlreadyExistsException,
127 ReflectionException, InstanceNotFoundException, MBeanException, ConflictingVersionException {
128 ObjectName fixed1names = transaction.createModule(TestingFixedThreadPoolModuleFactory.NAME, FIXED1);
129 // call validate on config bean
131 platformMBeanServer.invoke(fixed1names, "validate", new Object[0], new String[0]);
133 } catch (final MBeanException e) {
134 Exception targetException = e.getTargetException();
135 assertNotNull(targetException);
136 assertEquals(ValidationException.class, targetException.getClass());
139 // validate config bean
141 transaction.validateBean(fixed1names);
143 } catch (final ValidationException e) {
144 for (Map.Entry<String, Map<String, ExceptionMessageWithStackTrace>> exception : e.getFailedValidations()
146 for (Map.Entry<String, ExceptionMessageWithStackTrace> entry : exception.getValue().entrySet()) {
147 assertEquals("Parameter 'threadCount' must be greater than 0", entry.getValue().getMessage());
151 // validate transaction
153 transaction.validateConfig();
155 } catch (final ValidationException e) {
156 for (Map.Entry<String, Map<String, ExceptionMessageWithStackTrace>> exception : e.getFailedValidations()
158 for (Map.Entry<String, ExceptionMessageWithStackTrace> entry : exception.getValue().entrySet()) {
159 assertEquals("Parameter 'threadCount' must be greater than 0", entry.getValue().getMessage());
164 transaction.commit();
165 } catch (final ValidationException e) {
166 for (Map.Entry<String, Map<String, ExceptionMessageWithStackTrace>> exception : e.getFailedValidations()
168 for (Map.Entry<String, ExceptionMessageWithStackTrace> entry : exception.getValue().entrySet()) {
169 assertEquals("Parameter 'threadCount' must be greater than 0", entry.getValue().getMessage());
176 public void test_createThreadPool_changeNumberOfThreads() throws Exception {
178 ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
179 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = startReconfiguringFixed1ThreadPool(transaction);
180 assertEquals(NUMBER_OF_THREADS, fixedConfigProxy.getThreadCount());
181 fixedConfigProxy.setThreadCount(NUMBER_OF_THREADS2);
182 CommitStatus commitStatus = transaction.commit();
183 checkThreadPools(1, NUMBER_OF_THREADS2);
184 CommitStatus expected = new CommitStatus(EMPTYO_NS, FIXED1_LIST, EMPTYO_NS);
185 assertEquals(expected, commitStatus);
189 public void test_createFixedThreadPool_destroyIt() throws Exception {
190 // 1, start transaction, create new fixed thread pool
191 ObjectName fixed1name = firstCommit();
193 // 2, check that configuration was copied to platform
194 ObjectName on = ObjectNameUtil.withoutTransactionName(fixed1name);
195 platformMBeanServer.getMBeanInfo(on);
196 assertEquals(NUMBER_OF_THREADS, platformMBeanServer.getAttribute(on, "ThreadCount"));
198 // 3, shutdown fixed1 in new transaction
199 assertFalse(TestingFixedThreadPool.ALL_EXECUTORS.get(0).isShutdown());
200 ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
203 transaction.assertVersion(1, 2);
205 // test that it was copied to new transaction
206 ObjectName retrievedName = transaction.lookupConfigBean(TestingFixedThreadPoolModuleFactory.NAME, FIXED1);
207 assertNotNull(retrievedName);
209 // check that number of threads was copied from dynamic
211 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction.newMXBeanProxy(retrievedName,
212 TestingFixedThreadPoolConfigMXBean.class);
213 assertEquals(NUMBER_OF_THREADS, fixedConfigProxy.getThreadCount());
216 transaction.destroyModule(ObjectNameUtil.createTransactionModuleON(transaction.getTransactionName(),
217 TestingFixedThreadPoolModuleFactory.NAME, FIXED1));
218 transaction.commit();
221 assertEquals(2, configRegistryClient.getVersion());
222 assertEquals(0, TestingFixedThreadPool.ALL_EXECUTORS.size());
224 // dynamic config should be removed from platform
226 platformMBeanServer.getMBeanInfo(on);
228 } catch (final ReflectionException | InstanceNotFoundException | IntrospectionException e) {
229 assertTrue(e instanceof InstanceNotFoundException);
234 public void testReplaceFixed1() throws Exception {
235 // 1, start transaction, create new fixed thread pool
237 // destroy and recreate with different # of threads
238 ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
240 transaction.destroyModule(ObjectNameUtil.createTransactionModuleON(transaction.getTransactionName(),
241 TestingFixedThreadPoolModuleFactory.NAME, FIXED1));
243 ObjectName fixed1name = transaction.createModule(TestingFixedThreadPoolModuleFactory.NAME, FIXED1);
244 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction.newMXBeanProxy(fixed1name,
245 TestingFixedThreadPoolConfigMXBean.class);
246 fixedConfigProxy.setThreadCount(NUMBER_OF_THREADS2);
248 transaction.commit();
249 // check that first threadpool is closed
250 checkThreadPools(1, NUMBER_OF_THREADS2);
253 private static void checkThreadPools(final int expectedTotalNumberOfExecutors,
254 final int expectedNumberOfThreadsInLastExecutor) {
255 assertEquals(expectedTotalNumberOfExecutors, TestingFixedThreadPool.ALL_EXECUTORS.size());
256 for (int i = 0; i < expectedTotalNumberOfExecutors - 1; i++) {
257 assertTrue(TestingFixedThreadPool.ALL_EXECUTORS.get(i).isShutdown());
259 ThreadPoolExecutor lastExecutor = TestingFixedThreadPool.ALL_EXECUTORS.get(expectedTotalNumberOfExecutors - 1);
260 assertFalse(lastExecutor.isShutdown());
261 assertEquals(expectedNumberOfThreadsInLastExecutor, lastExecutor.getMaximumPoolSize());
265 public void testTriggerRecreatingInstance() throws Exception {
266 // 1, start transaction, create new fixed thread pool
268 // switch boolean to create new instance
269 ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
270 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = startReconfiguringFixed1ThreadPool(transaction);
272 fixedConfigProxy.setTriggerNewInstanceCreation(true);
274 CommitStatus commitStatus = transaction.commit();
275 // check that new threadpool is created and old one is closed
276 checkThreadPools(1, NUMBER_OF_THREADS);
277 CommitStatus expected = new CommitStatus(EMPTYO_NS, EMPTYO_NS, FIXED1_LIST);
278 assertEquals(expected, commitStatus);
281 // return MBeanProxy for 'fixed1' and current transaction
282 private static TestingFixedThreadPoolConfigMXBean startReconfiguringFixed1ThreadPool(
283 final ConfigTransactionJMXClient transaction) throws InstanceNotFoundException {
284 ObjectName fixed1name = transaction.lookupConfigBean(TestingFixedThreadPoolModuleFactory.NAME, FIXED1);
286 TestingFixedThreadPoolConfigMXBean fixedConfigProxy = transaction.newMXBeanProxy(fixed1name,
287 TestingFixedThreadPoolConfigMXBean.class);
288 return fixedConfigProxy;
292 public void testAbort() throws Exception {
293 ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
294 assertEquals(1, configRegistryClient.getOpenConfigs().size());
296 transaction.abortConfig();
297 assertEquals(0, configRegistryClient.getOpenConfigs().size());
299 platformMBeanServer.getMBeanInfo(transaction.getObjectName());
301 } catch (final InstanceNotFoundException e) {
302 assertEquals("org.opendaylight.controller:TransactionName=ConfigTransaction-0-1,type=ConfigTransaction",
308 public void testOptimisticLock_ConfigTransactionClient() throws Exception {
309 ConfigTransactionJMXClient transaction1 = configRegistryClient.createTransaction();
310 ConfigTransactionJMXClient transaction2 = configRegistryClient.createTransaction();
311 transaction2.assertVersion(0, 2);
312 transaction2.commit();
314 transaction1.commit();
316 } catch (final ConflictingVersionException e) {
317 assertEquals("Optimistic lock failed. Expected parent version 2, was 0", e.getMessage());
322 public void testOptimisticLock_ConfigRegistry() throws Exception {
323 ConfigTransactionJMXClient transaction1 = configRegistryClient.createTransaction();
324 ConfigTransactionJMXClient transaction2 = configRegistryClient.createTransaction();
325 transaction2.assertVersion(0, 2);
326 transaction2.commit();
328 configRegistryClient.commitConfig(transaction1.getObjectName());
330 } catch (final ConflictingVersionException e) {
331 assertEquals("Optimistic lock failed. Expected parent version 2, was 0", e.getMessage());
336 public void testQNames() {
337 Set<String> availableModuleFactoryQNames = configRegistryClient.getAvailableModuleFactoryQNames();
338 String expected = "(namespace?revision=2012-12-12)name";
340 assertEquals(Sets.newHashSet(expected), availableModuleFactoryQNames);