Resolve Bug:593. Persister should communicate via OSGi SR instead of TCP.
[controller.git] / opendaylight / netconf / config-persister-impl / src / test / java / org / opendaylight / controller / netconf / persist / impl / osgi / ConfigPersisterTest.java
index 230c74725d0b3c78160bcfecf8c60b29eb42ccff..b722496142e4f2014b82e776317488e02ddb4527 100644 (file)
  */
 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 com.google.common.collect.Sets;
 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 org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.mapping.api.Capability;
+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;
 
-import com.google.common.collect.Lists;
-import io.netty.channel.nio.NioEventLoopGroup;
+import javax.management.MBeanServer;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+
+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.mock;
 
 public class ConfigPersisterTest {
+    private static final Logger logger = 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 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) throws Exception {
+        DummyAdapterWithInitialSnapshot.expectedCapability = requiredCapability;
+        ctx = new MockedBundleContext(1000, 1000);
+        configPersisterActivator = new ConfigPersisterActivator();
         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(handler, "required-cap", cfg);
+        setUpContextAndStartPersister("required-cap");
+        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]");
 
-        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");
+        NetconfOperationService service = getWorkingService(getOKDocument());
+        doReturn(service).when(ctx.serviceFactory).createService(anyString());
+        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(RuntimeException.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)) {
+    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();
 
-            waitTestToFinish(4000);
 
-            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));
-        }
+        setUpContextAndStartPersister("cap1");
+        NetconfOperationService service = getWorkingService(getConflictVersionDocument());
+        doReturn(service).when(ctx.serviceFactory).createService(anyString());
+        Thread.sleep(2000);
+        handler.assertException(IllegalStateException.class, "Max wait for conflicting version stabilization timeout");
     }
 
-    @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));
-        }
+    private Document getConflictVersionDocument() throws SAXException, IOException {
+        return XmlUtil.readXmlToDocument(
+                "<rpc-reply message-id=\"1\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" +
+                        "<rpc-error><error-info><error>" +
+                        ConflictingVersionException.class.getCanonicalName() +
+                        "</error></error-info></rpc-error>\n" +
+                        "</rpc-reply>"
+        );
     }
 
     @Test
-    public void testPersisterSuccessfulPushAndSuccessfulJMXRegistration() throws Exception {
-        final TestingExceptionHandler handler = new TestingExceptionHandler();
-        ConfigPusherConfiguration cfg = getConfigurationForSuccess();
-
-        setUpContextAndStartPersister(handler, "cap1", cfg);
-
-        try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1", MockNetconfEndpoint.okMessage,
-                MockNetconfEndpoint.okMessage); DefaultCommitNotificationProducer jMXNotifier = startJMXCommitNotifier()) {
-
-            Thread.sleep(2000);
-
-            handler.assertNoException();
-
-            assertEquals(1 + 3, endpoint.getReceivedMessages().size());
-        }
-    }
-
-    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)));
+    public void testSuccessConflictingVersionException() throws Exception {
+        setUpContextAndStartPersister("cap1");
+        doReturn(getWorkingService(getConflictVersionDocument())).when(ctx.serviceFactory).createService(anyString());
+        Thread.sleep(500);
+        // working service:
+        logger.info("Switching to working service **");
+        doReturn(getWorkingService(getOKDocument())).when(ctx.serviceFactory).createService(anyString());
+        Thread.sleep(1000);
+        assertCannotRegisterAsJMXListener_pushWasSuccessful();
     }
 
-    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);
-    }
-
-    private MockNetconfEndpoint startMockNetconfEndpoint(String capability, String... messages) {
-        return startMockNetconfEndpoint(capability, Lists.newArrayList(new MockNetconfEndpoint.MessageSequence(messages)));
-    }
-
-    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;
-            }
-        };
-    }
 }