Merge "Add reverse() method in Edge and Path classes"
[controller.git] / opendaylight / netconf / config-persister-impl / src / test / java / org / opendaylight / controller / netconf / persist / impl / osgi / ConfigPersisterTest.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.netconf.persist.impl.osgi;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertThat;
12
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;
19
20 import javax.management.MBeanServer;
21
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;
31
32 import com.google.common.collect.Lists;
33 import io.netty.channel.nio.NioEventLoopGroup;
34
35 public class ConfigPersisterTest {
36
37     private MockedBundleContext ctx;
38     private ConfigPersisterActivator configPersisterActivator;
39     private static final MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
40
41     private static final String NETCONF_ADDRESS = "localhost";
42     private static final String NETCONF_PORT = "18383";
43     private static NioEventLoopGroup eventLoopGroup;
44
45     private void setUpContextAndStartPersister(Thread.UncaughtExceptionHandler exHandler, String requiredCapability, ConfigPusherConfiguration configuration)
46             throws Exception {
47         MockedBundleContext.DummyAdapterWithInitialSnapshot.expectedCapability = requiredCapability;
48         ctx = new MockedBundleContext(NETCONF_ADDRESS, NETCONF_PORT);
49         configPersisterActivator = new ConfigPersisterActivator(getThreadFactory(exHandler), mBeanServer,
50                 configuration);
51         configPersisterActivator.start(ctx.getBundleContext());
52     }
53
54     @BeforeClass
55     public static void setUp() throws Exception {
56         eventLoopGroup = new NioEventLoopGroup();
57     }
58
59     @After
60     public void tearDown() throws Exception {
61         configPersisterActivator.stop(ctx.getBundleContext());
62     }
63
64     @AfterClass
65     public static void closeNettyGroup() throws Exception {
66         eventLoopGroup.shutdownGracefully();
67     }
68
69     @Test
70     public void testPersisterNetconfNotStarting() throws Exception {
71         final TestingExceptionHandler handler = new TestingExceptionHandler();
72
73         setUpContextAndStartPersister(handler, "cap2", getConfiguration(100, 100).build());
74
75         waitTestToFinish(2000);
76
77         handler.assertException("connect to netconf endpoint", RuntimeException.class,
78                 "Could not connect to netconf server");
79     }
80
81     @Test
82     public void testPersisterNotAllCapabilitiesProvided() throws Exception {
83         final TestingExceptionHandler handler = new TestingExceptionHandler();
84         ConfigPusherConfiguration cfg = getConfiguration(500, 1000)
85                 .withNetconfCapabilitiesWaitTimeoutMs(1000).build();
86
87         setUpContextAndStartPersister(handler, "required-cap", cfg);
88
89         try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1")) {
90
91             waitTestToFinish(2500);
92
93             handler.assertException("retrieve required capabilities from netconf endpoint", RuntimeException.class,
94                     "Expected but not found:[required-cap]");
95         }
96     }
97
98     @Test
99     public void testPersisterNoResponseFromNetconfAfterEdit() throws Exception {
100         final TestingExceptionHandler handler = new TestingExceptionHandler();
101         ConfigPusherConfiguration cfg = getConfigurationWithOnePushAttempt();
102
103         setUpContextAndStartPersister(handler, "cap1", cfg);
104
105         try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1")) {
106
107             waitTestToFinish(3000);
108
109             handler.assertException("receive response from netconf endpoint", IllegalStateException.class,
110                     "Unable to load", TimeoutException.class,
111                     null, 3);
112
113             assertEquals(1 + 2, endpoint.getReceivedMessages().size());
114             assertHelloMessage(endpoint.getReceivedMessages().get(1));
115             assertEditMessage(endpoint.getReceivedMessages().get(2));
116         }
117     }
118
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();
126     }
127
128     @Test
129     public void testPersisterSuccessfulPush() throws Exception {
130         final TestingExceptionHandler handler = new TestingExceptionHandler();
131         ConfigPusherConfiguration cfg = getConfigurationForSuccess();
132
133         setUpContextAndStartPersister(handler, "cap1", cfg);
134
135         try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1", MockNetconfEndpoint.okMessage,
136                 MockNetconfEndpoint.okMessage)) {
137
138             waitTestToFinish(4000);
139
140             handler.assertException("register as JMX listener", RuntimeException.class,
141                     "Cannot register as JMX listener to netconf");
142
143             assertEquals(1 + 3, endpoint.getReceivedMessages().size());
144             assertCommitMessage(endpoint.getReceivedMessages().get(3));
145         }
146     }
147
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();
155     }
156
157     @Test
158     public void testPersisterConflictingVersionException() throws Exception {
159         final TestingExceptionHandler handler = new TestingExceptionHandler();
160         ConfigPusherConfiguration cfg = getConfigurationWithOnePushAttempt();
161
162         setUpContextAndStartPersister(handler, "cap1", cfg);
163
164         try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1", MockNetconfEndpoint.okMessage,
165                 MockNetconfEndpoint.conflictingVersionErrorMessage); DefaultCommitNotificationProducer jMXNotifier = startJMXCommitNotifier();) {
166
167             Thread.sleep(4000);
168
169             handler.assertException("register as JMX listener", IllegalStateException.class,
170                     "Maximum attempt count has been reached for pushing", ConflictingVersionException.class, "Optimistic lock failed", 1);
171
172             assertEquals(1 + 3, endpoint.getReceivedMessages().size());
173             assertCommitMessage(endpoint.getReceivedMessages().get(3));
174         }
175     }
176
177     @Test
178     public void testPersisterConflictingVersionExceptionThenSuccess() throws Exception {
179         final TestingExceptionHandler handler = new TestingExceptionHandler();
180         ConfigPusherConfiguration cfg = getConfigurationForSuccess();
181
182         setUpContextAndStartPersister(handler, "cap1", cfg);
183
184         MockNetconfEndpoint.MessageSequence conflictingMessageSequence = new MockNetconfEndpoint.MessageSequence(
185                 MockNetconfEndpoint.okMessage, MockNetconfEndpoint.conflictingVersionErrorMessage);
186         MockNetconfEndpoint.MessageSequence okMessageSequence = new MockNetconfEndpoint.MessageSequence(
187                 MockNetconfEndpoint.okMessage, MockNetconfEndpoint.okMessage);
188
189         try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1",
190                 Lists.newArrayList(conflictingMessageSequence, okMessageSequence));
191              DefaultCommitNotificationProducer jMXNotifier = startJMXCommitNotifier()) {
192
193             Thread.sleep(4000);
194
195             handler.assertNoException();
196
197             assertEquals(1 + 3/*Hello + Edit + Commit*/ + 3/*Hello + Edit + Commit*/, endpoint.getReceivedMessages().size());
198             assertCommitMessage(endpoint.getReceivedMessages().get(6));
199         }
200     }
201
202     @Test
203     public void testPersisterSuccessfulPushAndSuccessfulJMXRegistration() throws Exception {
204         final TestingExceptionHandler handler = new TestingExceptionHandler();
205         ConfigPusherConfiguration cfg = getConfigurationForSuccess();
206
207         setUpContextAndStartPersister(handler, "cap1", cfg);
208
209         try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1", MockNetconfEndpoint.okMessage,
210                 MockNetconfEndpoint.okMessage); DefaultCommitNotificationProducer jMXNotifier = startJMXCommitNotifier()) {
211
212             Thread.sleep(2000);
213
214             handler.assertNoException();
215
216             assertEquals(1 + 3, endpoint.getReceivedMessages().size());
217         }
218     }
219
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)));
227     }
228
229     private void waitTestToFinish(int i) throws InterruptedException {
230         Thread.sleep(i);
231     }
232
233
234     private DefaultCommitNotificationProducer startJMXCommitNotifier() {
235         return new DefaultCommitNotificationProducer(mBeanServer);
236     }
237
238     private void assertEditMessage(String netconfMessage) {
239         assertThat(netconfMessage,
240                 JUnitMatchers.containsString(MockedBundleContext.DummyAdapterWithInitialSnapshot.CONFIG_SNAPSHOT));
241     }
242
243     private void assertCommitMessage(String netconfMessage) {
244         assertThat(netconfMessage, JUnitMatchers.containsString("<commit"));
245     }
246
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>"));
251     }
252
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);
257     }
258
259     private MockNetconfEndpoint startMockNetconfEndpoint(String capability, String... messages) {
260         return startMockNetconfEndpoint(capability, Lists.newArrayList(new MockNetconfEndpoint.MessageSequence(messages)));
261     }
262
263     public ThreadFactory getThreadFactory(final Thread.UncaughtExceptionHandler exHandler) {
264         return new ThreadFactory() {
265             @Override
266             public Thread newThread(Runnable r) {
267                 Thread thread = new Thread(r, "config-persister-testing-activator");
268                 thread.setUncaughtExceptionHandler(exHandler);
269                 return thread;
270             }
271         };
272     }
273 }