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.netconf.persist.impl.osgi;
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertThat;
13 import java.lang.management.ManagementFactory;
14 import java.net.InetSocketAddress;
15 import java.util.Collections;
16 import java.util.List;
17 import java.util.concurrent.ThreadFactory;
18 import java.util.concurrent.TimeoutException;
20 import javax.management.MBeanServer;
22 import org.junit.After;
23 import org.junit.AfterClass;
24 import org.junit.BeforeClass;
25 import org.junit.Test;
26 import org.junit.matchers.JUnitMatchers;
27 import org.opendaylight.controller.config.api.ConflictingVersionException;
28 import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
29 import org.opendaylight.controller.netconf.persist.impl.ConfigPusherConfiguration;
30 import org.opendaylight.controller.netconf.persist.impl.ConfigPusherConfigurationBuilder;
32 import com.google.common.collect.Lists;
33 import io.netty.channel.nio.NioEventLoopGroup;
35 public class ConfigPersisterTest {
37 private MockedBundleContext ctx;
38 private ConfigPersisterActivator configPersisterActivator;
39 private static final MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
41 private static final String NETCONF_ADDRESS = "localhost";
42 private static final String NETCONF_PORT = "18383";
43 private static NioEventLoopGroup eventLoopGroup;
45 private void setUpContextAndStartPersister(Thread.UncaughtExceptionHandler exHandler, String requiredCapability, ConfigPusherConfiguration configuration)
47 MockedBundleContext.DummyAdapterWithInitialSnapshot.expectedCapability = requiredCapability;
48 ctx = new MockedBundleContext(NETCONF_ADDRESS, NETCONF_PORT);
49 configPersisterActivator = new ConfigPersisterActivator(getThreadFactory(exHandler), mBeanServer,
51 configPersisterActivator.start(ctx.getBundleContext());
55 public static void setUp() throws Exception {
56 eventLoopGroup = new NioEventLoopGroup();
60 public void tearDown() throws Exception {
61 configPersisterActivator.stop(ctx.getBundleContext());
65 public static void closeNettyGroup() throws Exception {
66 eventLoopGroup.shutdownGracefully();
70 public void testPersisterNetconfNotStarting() throws Exception {
71 final TestingExceptionHandler handler = new TestingExceptionHandler();
73 setUpContextAndStartPersister(handler, "cap2", getConfiguration(100, 100).build());
75 waitTestToFinish(2000);
77 handler.assertException("connect to netconf endpoint", RuntimeException.class,
78 "Could not connect to netconf server");
82 public void testPersisterNotAllCapabilitiesProvided() throws Exception {
83 final TestingExceptionHandler handler = new TestingExceptionHandler();
84 ConfigPusherConfiguration cfg = getConfiguration(500, 1000)
85 .withNetconfCapabilitiesWaitTimeoutMs(1000).build();
87 setUpContextAndStartPersister(handler, "required-cap", cfg);
89 try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1")) {
91 waitTestToFinish(2500);
93 handler.assertException("retrieve required capabilities from netconf endpoint", RuntimeException.class,
94 "Expected but not found:[required-cap]");
99 public void testPersisterNoResponseFromNetconfAfterEdit() throws Exception {
100 final TestingExceptionHandler handler = new TestingExceptionHandler();
101 ConfigPusherConfiguration cfg = getConfigurationWithOnePushAttempt();
103 setUpContextAndStartPersister(handler, "cap1", cfg);
105 try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1")) {
107 waitTestToFinish(3000);
109 handler.assertException("receive response from netconf endpoint", IllegalStateException.class,
110 "Unable to load", TimeoutException.class,
113 assertEquals(1 + 2, endpoint.getReceivedMessages().size());
114 assertHelloMessage(endpoint.getReceivedMessages().get(1));
115 assertEditMessage(endpoint.getReceivedMessages().get(2));
119 private ConfigPusherConfiguration getConfigurationWithOnePushAttempt() {
120 return getConfiguration(500, 1000)
121 .withNetconfCapabilitiesWaitTimeoutMs(1000)
122 .withNetconfPushConfigAttempts(1)
123 .withNetconfPushConfigDelayMs(100)
124 .withNetconfSendMessageMaxAttempts(3)
125 .withNetconfSendMessageDelayMs(500).build();
129 public void testPersisterSuccessfulPush() throws Exception {
130 final TestingExceptionHandler handler = new TestingExceptionHandler();
131 ConfigPusherConfiguration cfg = getConfigurationForSuccess();
133 setUpContextAndStartPersister(handler, "cap1", cfg);
135 try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1", MockNetconfEndpoint.okMessage,
136 MockNetconfEndpoint.okMessage)) {
138 waitTestToFinish(4000);
140 handler.assertException("register as JMX listener", RuntimeException.class,
141 "Cannot register as JMX listener to netconf");
143 assertEquals(1 + 3, endpoint.getReceivedMessages().size());
144 assertCommitMessage(endpoint.getReceivedMessages().get(3));
148 private ConfigPusherConfiguration getConfigurationForSuccess() {
149 return getConfiguration(500, 1000)
150 .withNetconfCapabilitiesWaitTimeoutMs(1000)
151 .withNetconfPushConfigAttempts(3)
152 .withNetconfPushConfigDelayMs(100)
153 .withNetconfSendMessageMaxAttempts(3)
154 .withNetconfSendMessageDelayMs(500).build();
158 public void testPersisterConflictingVersionException() throws Exception {
159 final TestingExceptionHandler handler = new TestingExceptionHandler();
160 ConfigPusherConfiguration cfg = getConfigurationWithOnePushAttempt();
162 setUpContextAndStartPersister(handler, "cap1", cfg);
164 try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1", MockNetconfEndpoint.okMessage,
165 MockNetconfEndpoint.conflictingVersionErrorMessage); DefaultCommitNotificationProducer jMXNotifier = startJMXCommitNotifier();) {
169 handler.assertException("register as JMX listener", IllegalStateException.class,
170 "Maximum attempt count has been reached for pushing", ConflictingVersionException.class, "Optimistic lock failed", 1);
172 assertEquals(1 + 3, endpoint.getReceivedMessages().size());
173 assertCommitMessage(endpoint.getReceivedMessages().get(3));
178 public void testPersisterConflictingVersionExceptionThenSuccess() throws Exception {
179 final TestingExceptionHandler handler = new TestingExceptionHandler();
180 ConfigPusherConfiguration cfg = getConfigurationForSuccess();
182 setUpContextAndStartPersister(handler, "cap1", cfg);
184 MockNetconfEndpoint.MessageSequence conflictingMessageSequence = new MockNetconfEndpoint.MessageSequence(
185 MockNetconfEndpoint.okMessage, MockNetconfEndpoint.conflictingVersionErrorMessage);
186 MockNetconfEndpoint.MessageSequence okMessageSequence = new MockNetconfEndpoint.MessageSequence(
187 MockNetconfEndpoint.okMessage, MockNetconfEndpoint.okMessage);
189 try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1",
190 Lists.newArrayList(conflictingMessageSequence, okMessageSequence));
191 DefaultCommitNotificationProducer jMXNotifier = startJMXCommitNotifier()) {
195 handler.assertNoException();
197 assertEquals(1 + 3/*Hello + Edit + Commit*/ + 3/*Hello + Edit + Commit*/, endpoint.getReceivedMessages().size());
198 assertCommitMessage(endpoint.getReceivedMessages().get(6));
203 public void testPersisterSuccessfulPushAndSuccessfulJMXRegistration() throws Exception {
204 final TestingExceptionHandler handler = new TestingExceptionHandler();
205 ConfigPusherConfiguration cfg = getConfigurationForSuccess();
207 setUpContextAndStartPersister(handler, "cap1", cfg);
209 try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1", MockNetconfEndpoint.okMessage,
210 MockNetconfEndpoint.okMessage); DefaultCommitNotificationProducer jMXNotifier = startJMXCommitNotifier()) {
214 handler.assertNoException();
216 assertEquals(1 + 3, endpoint.getReceivedMessages().size());
220 private ConfigPusherConfigurationBuilder getConfiguration(int connectionAttemptDelayMs, int connectionAttemptTimeoutMs) {
221 return ConfigPusherConfigurationBuilder.aConfigPusherConfiguration()
222 .withEventLoopGroup(eventLoopGroup)
223 .withConnectionAttemptDelayMs(connectionAttemptDelayMs)
224 .withConnectionAttemptTimeoutMs(connectionAttemptTimeoutMs)
225 .withNetconfCapabilitiesWaitTimeoutMs(44)
226 .withNetconfAddress(new InetSocketAddress(NETCONF_ADDRESS, Integer.valueOf(NETCONF_PORT)));
229 private void waitTestToFinish(int i) throws InterruptedException {
234 private DefaultCommitNotificationProducer startJMXCommitNotifier() {
235 return new DefaultCommitNotificationProducer(mBeanServer);
238 private void assertEditMessage(String netconfMessage) {
239 assertThat(netconfMessage,
240 JUnitMatchers.containsString(MockedBundleContext.DummyAdapterWithInitialSnapshot.CONFIG_SNAPSHOT));
243 private void assertCommitMessage(String netconfMessage) {
244 assertThat(netconfMessage, JUnitMatchers.containsString("<commit"));
247 private void assertHelloMessage(String netconfMessage) {
248 assertThat(netconfMessage,
249 JUnitMatchers.containsString("<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"));
250 assertThat(netconfMessage, JUnitMatchers.containsString("<capability>"));
253 private MockNetconfEndpoint startMockNetconfEndpoint(String capability, List<MockNetconfEndpoint.MessageSequence> messageSequences) {
254 // Add first empty sequence for testing connection created by config persister at startup
255 messageSequences.add(0, new MockNetconfEndpoint.MessageSequence(Collections.<String>emptyList()));
256 return new MockNetconfEndpoint(capability, NETCONF_PORT, messageSequences);
259 private MockNetconfEndpoint startMockNetconfEndpoint(String capability, String... messages) {
260 return startMockNetconfEndpoint(capability, Lists.newArrayList(new MockNetconfEndpoint.MessageSequence(messages)));
263 public ThreadFactory getThreadFactory(final Thread.UncaughtExceptionHandler exHandler) {
264 return new ThreadFactory() {
266 public Thread newThread(Runnable r) {
267 Thread thread = new Thread(r, "config-persister-testing-activator");
268 thread.setUncaughtExceptionHandler(exHandler);