*/
package org.opendaylight.controller.netconf.persist.impl.osgi;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-
-import java.lang.management.ManagementFactory;
-import java.net.InetSocketAddress;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.TimeoutException;
-
-import javax.management.MBeanServer;
-
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import com.google.common.collect.Sets;
+import java.io.IOException;
import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
+import org.junit.Before;
import org.junit.Test;
-import org.junit.matchers.JUnitMatchers;
import org.opendaylight.controller.config.api.ConflictingVersionException;
-import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
-import org.opendaylight.controller.netconf.persist.impl.ConfigPusherConfiguration;
-import org.opendaylight.controller.netconf.persist.impl.ConfigPusherConfigurationBuilder;
-
-import com.google.common.collect.Lists;
-import io.netty.channel.nio.NioEventLoopGroup;
+import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
+import org.opendaylight.controller.netconf.persist.impl.osgi.MockedBundleContext.DummyAdapterWithInitialSnapshot;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
public class ConfigPersisterTest {
+ private static final Logger LOG = LoggerFactory.getLogger(ConfigPersisterTest.class);
private MockedBundleContext ctx;
private ConfigPersisterActivator configPersisterActivator;
- private static final MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
+ private TestingExceptionHandler handler;
- private static final String NETCONF_ADDRESS = "localhost";
- private static final String NETCONF_PORT = "18383";
- private static NioEventLoopGroup eventLoopGroup;
+ private void setUpContext(String requiredCapability) throws Exception {
+ DummyAdapterWithInitialSnapshot.expectedCapability = requiredCapability;
+ ctx = new MockedBundleContext(1000, 1000);
+ configPersisterActivator = new ConfigPersisterActivator();
+ }
- private void setUpContextAndStartPersister(Thread.UncaughtExceptionHandler exHandler, String requiredCapability, ConfigPusherConfiguration configuration)
- throws Exception {
- MockedBundleContext.DummyAdapterWithInitialSnapshot.expectedCapability = requiredCapability;
- ctx = new MockedBundleContext(NETCONF_ADDRESS, NETCONF_PORT);
- configPersisterActivator = new ConfigPersisterActivator(getThreadFactory(exHandler), mBeanServer,
- configuration);
+ private void setUpContextAndStartPersister(String requiredCapability, final NetconfOperationService conflictingService) throws Exception {
+ setUpContext(requiredCapability);
+ doReturn(conflictingService).when(ctx.serviceFactory).createService(anyString());
configPersisterActivator.start(ctx.getBundleContext());
}
- @BeforeClass
- public static void setUp() throws Exception {
- eventLoopGroup = new NioEventLoopGroup();
+ @Before
+ public void setUp() {
+ handler = new TestingExceptionHandler();
+ Thread.setDefaultUncaughtExceptionHandler(handler);
}
@After
public void tearDown() throws Exception {
+ Thread.setDefaultUncaughtExceptionHandler(null);
configPersisterActivator.stop(ctx.getBundleContext());
}
- @AfterClass
- public static void closeNettyGroup() throws Exception {
- eventLoopGroup.shutdownGracefully();
- }
-
- @Test
- public void testPersisterNetconfNotStarting() throws Exception {
- final TestingExceptionHandler handler = new TestingExceptionHandler();
-
- setUpContextAndStartPersister(handler, "cap2", getConfiguration(100, 100).build());
-
- waitTestToFinish(2000);
-
- handler.assertException("connect to netconf endpoint", RuntimeException.class,
- "Could not connect to netconf server");
- }
-
@Test
public void testPersisterNotAllCapabilitiesProvided() throws Exception {
- final TestingExceptionHandler handler = new TestingExceptionHandler();
- ConfigPusherConfiguration cfg = getConfiguration(500, 1000)
- .withNetconfCapabilitiesWaitTimeoutMs(1000).build();
+ setUpContextAndStartPersister("required-cap", getConflictingService());
+ Thread.sleep(2000);
+ handler.assertException(IllegalStateException.class, "Max wait for capabilities reached.Not enough capabilities " +
+ "for <data><config-snapshot/></data>. Expected but not found: [required-cap]");
- setUpContextAndStartPersister(handler, "required-cap", cfg);
-
- try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1")) {
-
- waitTestToFinish(2500);
-
- handler.assertException("retrieve required capabilities from netconf endpoint", RuntimeException.class,
- "Expected but not found:[required-cap]");
- }
}
@Test
- public void testPersisterNoResponseFromNetconfAfterEdit() throws Exception {
- final TestingExceptionHandler handler = new TestingExceptionHandler();
- ConfigPusherConfiguration cfg = getConfigurationWithOnePushAttempt();
-
- setUpContextAndStartPersister(handler, "cap1", cfg);
-
- try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1")) {
-
- waitTestToFinish(3000);
-
- handler.assertException("receive response from netconf endpoint", IllegalStateException.class,
- "Unable to load", TimeoutException.class,
- null, 3);
-
- assertEquals(1 + 2, endpoint.getReceivedMessages().size());
- assertHelloMessage(endpoint.getReceivedMessages().get(1));
- assertEditMessage(endpoint.getReceivedMessages().get(2));
- }
+ public void testPersisterSuccessfulPush() throws Exception {
+ setUpContextAndStartPersister("cap1", getWorkingService(getOKDocument()));
+ Thread.sleep(2000);
+ assertCannotRegisterAsJMXListener_pushWasSuccessful();
}
- private ConfigPusherConfiguration getConfigurationWithOnePushAttempt() {
- return getConfiguration(500, 1000)
- .withNetconfCapabilitiesWaitTimeoutMs(1000)
- .withNetconfPushConfigAttempts(1)
- .withNetconfPushConfigDelayMs(100)
- .withNetconfSendMessageMaxAttempts(3)
- .withNetconfSendMessageDelayMs(500).build();
+ // this means pushing of config was successful
+ public void assertCannotRegisterAsJMXListener_pushWasSuccessful() {
+ handler.assertException(IllegalStateException.class, "Cannot register as JMX listener to netconf");
}
- @Test
- public void testPersisterSuccessfulPush() throws Exception {
- final TestingExceptionHandler handler = new TestingExceptionHandler();
- ConfigPusherConfiguration cfg = getConfigurationForSuccess();
-
- setUpContextAndStartPersister(handler, "cap1", cfg);
-
- try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1", MockNetconfEndpoint.okMessage,
- MockNetconfEndpoint.okMessage)) {
-
- waitTestToFinish(4000);
+ public NetconfOperationService getWorkingService(Document document) throws SAXException, IOException, NetconfDocumentedException {
+ NetconfOperationService service = mock(NetconfOperationService.class);
+ Capability capability = mock(Capability.class);
+// doReturn(Sets.newHashSet(capability)).when(service).getCapabilities();
+ doReturn("cap1").when(capability).getCapabilityUri();
- handler.assertException("register as JMX listener", RuntimeException.class,
- "Cannot register as JMX listener to netconf");
- assertEquals(1 + 3, endpoint.getReceivedMessages().size());
- assertCommitMessage(endpoint.getReceivedMessages().get(3));
- }
+ NetconfOperation mockedOperation = mock(NetconfOperation.class);
+ doReturn(Sets.newHashSet(mockedOperation)).when(service).getNetconfOperations();
+ doReturn(HandlingPriority.getHandlingPriority(1)).when(mockedOperation).canHandle(any(Document.class));
+ doReturn(document).when(mockedOperation).handle(any(Document.class), any(NetconfOperationChainedExecution.class));
+ doNothing().when(service).close();
+ return service;
}
- private ConfigPusherConfiguration getConfigurationForSuccess() {
- return getConfiguration(500, 1000)
- .withNetconfCapabilitiesWaitTimeoutMs(1000)
- .withNetconfPushConfigAttempts(3)
- .withNetconfPushConfigDelayMs(100)
- .withNetconfSendMessageMaxAttempts(3)
- .withNetconfSendMessageDelayMs(500).build();
+ private Document getOKDocument() throws SAXException, IOException {
+ return XmlUtil.readXmlToDocument(
+ "<rpc-reply message-id=\"1\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" +
+ "<ok/>\n" +
+ "</rpc-reply>"
+ );
}
- @Test
- public void testPersisterConflictingVersionException() throws Exception {
- final TestingExceptionHandler handler = new TestingExceptionHandler();
- ConfigPusherConfiguration cfg = getConfigurationWithOnePushAttempt();
-
- setUpContextAndStartPersister(handler, "cap1", cfg);
-
- try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1", MockNetconfEndpoint.okMessage,
- MockNetconfEndpoint.conflictingVersionErrorMessage); DefaultCommitNotificationProducer jMXNotifier = startJMXCommitNotifier();) {
-
- Thread.sleep(4000);
-
- handler.assertException("register as JMX listener", IllegalStateException.class,
- "Maximum attempt count has been reached for pushing", ConflictingVersionException.class, "Optimistic lock failed", 1);
-
- assertEquals(1 + 3, endpoint.getReceivedMessages().size());
- assertCommitMessage(endpoint.getReceivedMessages().get(3));
- }
- }
@Test
- public void testPersisterConflictingVersionExceptionThenSuccess() throws Exception {
- final TestingExceptionHandler handler = new TestingExceptionHandler();
- ConfigPusherConfiguration cfg = getConfigurationForSuccess();
-
- setUpContextAndStartPersister(handler, "cap1", cfg);
-
- MockNetconfEndpoint.MessageSequence conflictingMessageSequence = new MockNetconfEndpoint.MessageSequence(
- MockNetconfEndpoint.okMessage, MockNetconfEndpoint.conflictingVersionErrorMessage);
- MockNetconfEndpoint.MessageSequence okMessageSequence = new MockNetconfEndpoint.MessageSequence(
- MockNetconfEndpoint.okMessage, MockNetconfEndpoint.okMessage);
-
- try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1",
- Lists.newArrayList(conflictingMessageSequence, okMessageSequence));
- DefaultCommitNotificationProducer jMXNotifier = startJMXCommitNotifier()) {
-
- Thread.sleep(4000);
-
- handler.assertNoException();
-
- assertEquals(1 + 3/*Hello + Edit + Commit*/ + 3/*Hello + Edit + Commit*/, endpoint.getReceivedMessages().size());
- assertCommitMessage(endpoint.getReceivedMessages().get(6));
+ public void testPersisterConflictingVersionException() throws Exception {
+ setUpContextAndStartPersister("cap1", getConflictingService());
+
+ Thread.sleep(2000);
+ handler.assertException(IllegalStateException.class, "Max wait for conflicting version stabilization timeout");
+ }
+
+ private NetconfOperationService getConflictingService() throws Exception {
+ NetconfOperationService service = getWorkingService(getOKDocument());
+ ConflictingVersionException cve = new ConflictingVersionException("");
+ try {
+ NetconfDocumentedException.wrap(cve);
+ throw new AssertionError("Should throw an exception");
+ }catch(NetconfDocumentedException e) {
+ NetconfOperation mockedOperation = service.getNetconfOperations().iterator().next();
+ doThrow(e).when(mockedOperation).handle(any(Document.class), any(NetconfOperationChainedExecution.class));
+ return service;
}
}
@Test
- public void testPersisterSuccessfulPushAndSuccessfulJMXRegistration() throws Exception {
- final TestingExceptionHandler handler = new TestingExceptionHandler();
- ConfigPusherConfiguration cfg = getConfigurationForSuccess();
+ public void testSuccessConflictingVersionException() throws Exception {
+ LOG.info("testSuccessConflictingVersionException starting");
- setUpContextAndStartPersister(handler, "cap1", cfg);
+ setUpContext("cap1");
- try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1", MockNetconfEndpoint.okMessage,
- MockNetconfEndpoint.okMessage); DefaultCommitNotificationProducer jMXNotifier = startJMXCommitNotifier()) {
+ NetconfOperationService conflictingService = getConflictingService();
+ NetconfOperationService workingService = getWorkingService(getOKDocument());
- Thread.sleep(2000);
-
- handler.assertNoException();
-
- assertEquals(1 + 3, endpoint.getReceivedMessages().size());
- }
- }
+ doReturn(conflictingService).doReturn(conflictingService).doReturn(conflictingService).
+ doReturn(workingService).when(ctx.serviceFactory).createService(anyString());
- private ConfigPusherConfigurationBuilder getConfiguration(int connectionAttemptDelayMs, int connectionAttemptTimeoutMs) {
- return ConfigPusherConfigurationBuilder.aConfigPusherConfiguration()
- .withEventLoopGroup(eventLoopGroup)
- .withConnectionAttemptDelayMs(connectionAttemptDelayMs)
- .withConnectionAttemptTimeoutMs(connectionAttemptTimeoutMs)
- .withNetconfCapabilitiesWaitTimeoutMs(44)
- .withNetconfAddress(new InetSocketAddress(NETCONF_ADDRESS, Integer.valueOf(NETCONF_PORT)));
- }
-
- private void waitTestToFinish(int i) throws InterruptedException {
- Thread.sleep(i);
- }
-
-
- private DefaultCommitNotificationProducer startJMXCommitNotifier() {
- return new DefaultCommitNotificationProducer(mBeanServer);
- }
-
- private void assertEditMessage(String netconfMessage) {
- assertThat(netconfMessage,
- JUnitMatchers.containsString(MockedBundleContext.DummyAdapterWithInitialSnapshot.CONFIG_SNAPSHOT));
- }
-
- private void assertCommitMessage(String netconfMessage) {
- assertThat(netconfMessage, JUnitMatchers.containsString("<commit"));
- }
-
- private void assertHelloMessage(String netconfMessage) {
- assertThat(netconfMessage,
- JUnitMatchers.containsString("<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"));
- assertThat(netconfMessage, JUnitMatchers.containsString("<capability>"));
- }
-
- private MockNetconfEndpoint startMockNetconfEndpoint(String capability, List<MockNetconfEndpoint.MessageSequence> messageSequences) {
- // Add first empty sequence for testing connection created by config persister at startup
- messageSequences.add(0, new MockNetconfEndpoint.MessageSequence(Collections.<String>emptyList()));
- return new MockNetconfEndpoint(capability, NETCONF_PORT, messageSequences);
- }
+ configPersisterActivator.start(ctx.getBundleContext());
- private MockNetconfEndpoint startMockNetconfEndpoint(String capability, String... messages) {
- return startMockNetconfEndpoint(capability, Lists.newArrayList(new MockNetconfEndpoint.MessageSequence(messages)));
+ Thread.sleep(1000);
+ assertCannotRegisterAsJMXListener_pushWasSuccessful();
}
- public ThreadFactory getThreadFactory(final Thread.UncaughtExceptionHandler exHandler) {
- return new ThreadFactory() {
- @Override
- public Thread newThread(Runnable r) {
- Thread thread = new Thread(r, "config-persister-testing-activator");
- thread.setUncaughtExceptionHandler(exHandler);
- return thread;
- }
- };
- }
}