2 * Copyright (c) 2016 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.netconf.impl;
10 import static org.junit.Assert.assertThrows;
11 import static org.junit.Assert.assertTrue;
12 import static org.mockito.ArgumentMatchers.any;
13 import static org.mockito.ArgumentMatchers.argThat;
14 import static org.mockito.Mockito.doNothing;
15 import static org.mockito.Mockito.doReturn;
16 import static org.mockito.Mockito.doThrow;
17 import static org.mockito.Mockito.verify;
19 import io.netty.channel.embedded.EmbeddedChannel;
20 import org.custommonkey.xmlunit.Diff;
21 import org.custommonkey.xmlunit.XMLUnit;
22 import org.junit.Before;
23 import org.junit.BeforeClass;
24 import org.junit.Test;
25 import org.junit.runner.RunWith;
26 import org.mockito.ArgumentMatcher;
27 import org.mockito.Mock;
28 import org.mockito.junit.MockitoJUnitRunner;
29 import org.opendaylight.netconf.api.NetconfMessage;
30 import org.opendaylight.netconf.api.NetconfTerminationReason;
31 import org.opendaylight.netconf.api.monitoring.NetconfMonitoringService;
32 import org.opendaylight.netconf.api.monitoring.SessionEvent;
33 import org.opendaylight.netconf.api.monitoring.SessionListener;
34 import org.opendaylight.netconf.api.xml.XmlUtil;
35 import org.opendaylight.netconf.impl.osgi.NetconfOperationRouter;
36 import org.opendaylight.netconf.notifications.NetconfNotification;
37 import org.w3c.dom.Document;
39 @RunWith(MockitoJUnitRunner.StrictStubs.class)
40 public class NetconfServerSessionListenerTest {
43 private NetconfOperationRouter router;
45 private NetconfMonitoringService monitoring;
47 private AutoCloseable closeable;
49 private SessionListener monitoringListener;
50 private NetconfServerSession session;
51 private EmbeddedChannel channel;
52 private NetconfServerSessionListener listener;
55 public static void classSetUp() throws Exception {
56 XMLUnit.setIgnoreWhitespace(true);
60 public void setUp() throws Exception {
61 doReturn(monitoringListener).when(monitoring).getSessionListener();
62 doNothing().when(monitoringListener).onSessionUp(any());
63 doNothing().when(monitoringListener).onSessionDown(any());
64 doNothing().when(monitoringListener).onSessionEvent(any());
65 channel = new EmbeddedChannel();
66 session = new NetconfServerSession(null, channel, 0L, null);
67 listener = new NetconfServerSessionListener(router, monitoring, closeable);
71 public void testOnSessionUp() throws Exception {
72 listener.onSessionUp(session);
73 verify(monitoringListener).onSessionUp(session);
77 public void testOnSessionDown() throws Exception {
78 final Exception cause = new RuntimeException("cause");
79 listener.onSessionDown(session, cause);
80 verify(monitoringListener).onSessionDown(session);
81 verify(closeable).close();
82 verify(router).close();
86 public void testOnSessionTerminated() throws Exception {
87 listener.onSessionTerminated(session, new NetconfTerminationReason("reason"));
88 verify(monitoringListener).onSessionDown(session);
89 verify(closeable).close();
90 verify(router).close();
94 public void testOnMessage() throws Exception {
95 final Document reply = XmlUtil.readXmlToDocument("<rpc-reply message-id=\"101\" "
96 + "xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><example/></rpc-reply>");
97 doReturn(reply).when(router).onNetconfMessage(any(), any());
98 final NetconfMessage msg = new NetconfMessage(XmlUtil.readXmlToDocument("<rpc message-id=\"101\" "
99 + "xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><example/></rpc>"));
100 listener.onMessage(session, msg);
101 verify(monitoringListener).onSessionEvent(argThat(sessionEventIs(SessionEvent.Type.IN_RPC_SUCCESS)));
102 channel.runPendingTasks();
103 final NetconfMessage sentMsg = channel.readOutbound();
104 final Diff diff = XMLUnit.compareXML(reply, sentMsg.getDocument());
105 assertTrue(diff.toString(), diff.similar());
109 public void testOnMessageRuntimeFail() throws Exception {
110 doThrow(new RuntimeException("runtime fail")).when(router).onNetconfMessage(any(), any());
111 final Document reply =
112 XmlUtil.readXmlToDocument("<rpc message-id=\"101\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
113 + "<example/></rpc>");
114 final NetconfMessage msg = new NetconfMessage(reply);
115 final IllegalStateException ex = assertThrows(IllegalStateException.class,
116 () -> listener.onMessage(session, msg));
117 verify(monitoringListener).onSessionEvent(argThat(sessionEventIs(SessionEvent.Type.IN_RPC_FAIL)));
120 @SuppressWarnings("checkstyle:RegexpSinglelineJava")
122 public void testOnMessageDocumentedFail() throws Exception {
123 final Document reply =
124 XmlUtil.readXmlToDocument("<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
126 + "<error-type>protocol</error-type>\n"
127 + "<error-tag>unknown-element</error-tag>\n"
128 + "<error-severity>error</error-severity>\n"
129 + "<error-message>Unknown tag bad-rpc in message:\n"
130 + "<bad-rpc/>\n"
131 + "</error-message>\n"
133 + "<bad-element>bad-rpc</bad-element>\n"
137 final NetconfMessage msg = new NetconfMessage(XmlUtil.readXmlToDocument("<bad-rpc/>"));
138 listener.onMessage(session, msg);
139 verify(monitoringListener).onSessionEvent(argThat(sessionEventIs(SessionEvent.Type.IN_RPC_FAIL)));
140 verify(monitoringListener).onSessionEvent(argThat(sessionEventIs(SessionEvent.Type.OUT_RPC_ERROR)));
141 channel.runPendingTasks();
142 final NetconfMessage sentMsg = channel.readOutbound();
143 System.out.println(XmlUtil.toString(sentMsg.getDocument()));
144 System.out.println(XmlUtil.toString(reply));
145 final Diff diff = XMLUnit.compareXML(reply, sentMsg.getDocument());
146 assertTrue(diff.toString(), diff.similar());
150 public void testOnNotification() throws Exception {
151 listener.onNotification(session, new NetconfNotification(XmlUtil.readXmlToDocument("<notification/>")));
152 verify(monitoringListener).onSessionEvent(argThat(sessionEventIs(SessionEvent.Type.NOTIFICATION)));
155 private ArgumentMatcher<SessionEvent> sessionEventIs(final SessionEvent.Type type) {
156 return event -> event.getType().equals(type) && event.getSession().equals(session);