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.nettyutil;
10 import static org.mockito.ArgumentMatchers.any;
11 import static org.mockito.ArgumentMatchers.eq;
12 import static org.mockito.Mockito.doNothing;
13 import static org.mockito.Mockito.doReturn;
14 import static org.mockito.Mockito.mock;
15 import static org.mockito.Mockito.timeout;
16 import static org.mockito.Mockito.times;
17 import static org.mockito.Mockito.verify;
18 import static org.opendaylight.netconf.nettyutil.AbstractChannelInitializer.NETCONF_MESSAGE_AGGREGATOR;
19 import static org.opendaylight.netconf.nettyutil.AbstractChannelInitializer.NETCONF_MESSAGE_FRAME_ENCODER;
21 import io.netty.buffer.ByteBuf;
22 import io.netty.buffer.Unpooled;
23 import io.netty.channel.ChannelHandlerContext;
24 import io.netty.channel.ChannelInboundHandlerAdapter;
25 import io.netty.channel.ChannelOutboundHandler;
26 import io.netty.channel.ChannelOutboundHandlerAdapter;
27 import io.netty.channel.ChannelPromise;
28 import io.netty.channel.embedded.EmbeddedChannel;
29 import io.netty.handler.ssl.SslHandler;
30 import io.netty.util.HashedWheelTimer;
31 import io.netty.util.concurrent.Future;
32 import io.netty.util.concurrent.Promise;
33 import java.util.ArrayList;
34 import java.util.Collections;
35 import java.util.List;
36 import java.util.Optional;
37 import org.junit.Assert;
38 import org.junit.Before;
39 import org.junit.Test;
40 import org.mockito.Mock;
41 import org.mockito.Mockito;
42 import org.mockito.MockitoAnnotations;
43 import org.opendaylight.netconf.api.NetconfSessionListener;
44 import org.opendaylight.netconf.api.NetconfSessionPreferences;
45 import org.opendaylight.netconf.api.messages.NetconfHelloMessage;
46 import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
47 import org.opendaylight.netconf.api.xml.XmlUtil;
48 import org.opendaylight.netconf.nettyutil.handler.ChunkedFramingMechanismEncoder;
49 import org.opendaylight.netconf.nettyutil.handler.EOMFramingMechanismEncoder;
50 import org.opendaylight.netconf.nettyutil.handler.FramingMechanismHandlerFactory;
51 import org.opendaylight.netconf.nettyutil.handler.NetconfChunkAggregator;
52 import org.opendaylight.netconf.nettyutil.handler.NetconfEOMAggregator;
53 import org.opendaylight.netconf.nettyutil.handler.NetconfXMLToHelloMessageDecoder;
54 import org.opendaylight.netconf.util.messages.FramingMechanism;
56 public class AbstractNetconfSessionNegotiatorTest {
59 private NetconfSessionListener<TestingNetconfSession> listener;
61 private Promise<TestingNetconfSession> promise;
63 private SslHandler sslHandler;
64 private EmbeddedChannel channel;
65 private AbstractNetconfSessionNegotiator negotiator;
66 private NetconfHelloMessage hello;
67 private NetconfHelloMessage helloBase11;
68 private NetconfXMLToHelloMessageDecoder xmlToHello;
69 private NetconfSessionPreferences prefs;
72 public void setUp() throws Exception {
73 MockitoAnnotations.initMocks(this);
74 channel = new EmbeddedChannel();
75 xmlToHello = new NetconfXMLToHelloMessageDecoder();
76 channel.pipeline().addLast(AbstractChannelInitializer.NETCONF_MESSAGE_ENCODER,
77 new ChannelInboundHandlerAdapter());
78 channel.pipeline().addLast(AbstractChannelInitializer.NETCONF_MESSAGE_DECODER, xmlToHello);
79 channel.pipeline().addLast(NETCONF_MESSAGE_FRAME_ENCODER,
80 FramingMechanismHandlerFactory.createHandler(FramingMechanism.EOM));
81 channel.pipeline().addLast(NETCONF_MESSAGE_AGGREGATOR, new NetconfEOMAggregator());
82 hello = NetconfHelloMessage.createClientHello(Collections.emptySet(), Optional.empty());
83 helloBase11 = NetconfHelloMessage.createClientHello(Collections
84 .singleton(XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_1), Optional.empty());
85 prefs = new NetconfSessionPreferences(helloBase11);
86 doReturn(promise).when(promise).setFailure(any());
87 doReturn(promise).when(promise).setSuccess(any());
88 negotiator = new TestSessionNegotiator(prefs, promise, channel, new HashedWheelTimer(), listener, 100L);
92 public void testStartNegotiation() throws Exception {
93 negotiator.startNegotiation();
94 Assert.assertEquals(helloBase11, channel.readOutbound());
98 public void testStartNegotiationSsl() throws Exception {
99 doReturn(true).when(sslHandler).isSharable();
100 doNothing().when(sslHandler).handlerAdded(any());
101 doNothing().when(sslHandler).write(any(), any(), any());
102 final Future<EmbeddedChannel> handshakeFuture = channel.eventLoop().newSucceededFuture(channel);
103 doReturn(handshakeFuture).when(sslHandler).handshakeFuture();
104 channel.pipeline().addLast(sslHandler);
105 negotiator.startNegotiation();
106 verify(sslHandler, timeout(1000)).write(any(), eq(helloBase11), any());
111 public void testStartNegotiationNotEstablished() throws Exception {
112 final ChannelOutboundHandler closedDetector = Mockito.spy(new CloseDetector());
113 channel.pipeline().addLast("closedDetector", closedDetector);
114 doReturn(false).when(promise).isDone();
115 doReturn(false).when(promise).isCancelled();
116 negotiator.startNegotiation();
117 verify(closedDetector, timeout(2000)).close(any(), any());
121 public void testGetSessionPreferences() throws Exception {
122 Assert.assertEquals(prefs, negotiator.getSessionPreferences());
126 public void testGetSessionForHelloMessage() throws Exception {
127 negotiator.startNegotiation();
128 final AbstractNetconfSession session = negotiator.getSessionForHelloMessage(hello);
129 Assert.assertNotNull(session);
130 Assert.assertTrue(channel.pipeline().get(NETCONF_MESSAGE_AGGREGATOR) instanceof NetconfEOMAggregator);
131 Assert.assertTrue(channel.pipeline().get(NETCONF_MESSAGE_FRAME_ENCODER) instanceof EOMFramingMechanismEncoder);
135 public void testGetSessionForHelloMessageBase11() throws Exception {
136 negotiator.startNegotiation();
137 final AbstractNetconfSession session = negotiator.getSessionForHelloMessage(helloBase11);
138 Assert.assertNotNull(session);
139 Assert.assertTrue(channel.pipeline().get(NETCONF_MESSAGE_AGGREGATOR) instanceof NetconfChunkAggregator);
140 Assert.assertTrue(channel.pipeline().get(NETCONF_MESSAGE_FRAME_ENCODER)
141 instanceof ChunkedFramingMechanismEncoder);
145 public void testReplaceHelloMessageInboundHandler() throws Exception {
146 final List<Object> out = new ArrayList<>();
147 final byte[] msg = "<rpc/>".getBytes();
148 final ByteBuf msgBuf = Unpooled.wrappedBuffer(msg);
149 final ByteBuf helloBuf = Unpooled.wrappedBuffer(XmlUtil.toString(hello.getDocument()).getBytes());
150 negotiator.startNegotiation();
151 xmlToHello.decode(null, helloBuf, out);
152 xmlToHello.decode(null, msgBuf, out);
153 final AbstractNetconfSession session = mock(AbstractNetconfSession.class);
154 doNothing().when(session).handleMessage(any());
155 negotiator.replaceHelloMessageInboundHandler(session);
156 verify(session, times(1)).handleMessage(any());
160 public void testNegotiationFail() throws Exception {
161 negotiator.startNegotiation();
162 final RuntimeException cause = new RuntimeException("failure cause");
163 channel.pipeline().fireExceptionCaught(cause);
164 verify(promise).setFailure(cause);
167 private static class CloseDetector extends ChannelOutboundHandlerAdapter {
169 public void close(ChannelHandlerContext ctx, ChannelPromise promise) {
170 // Override needed so @Skip from superclass is not effective