2 * Copyright (c) 2013 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.protocol.framework;
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertFalse;
12 import static org.mockito.Matchers.any;
13 import static org.mockito.Mockito.doNothing;
14 import static org.mockito.Mockito.doReturn;
15 import static org.mockito.Mockito.mock;
16 import static org.mockito.Mockito.timeout;
17 import static org.mockito.Mockito.times;
18 import static org.mockito.Mockito.verify;
20 import io.netty.channel.Channel;
21 import io.netty.channel.ChannelFuture;
22 import io.netty.channel.nio.NioEventLoopGroup;
23 import io.netty.util.concurrent.DefaultPromise;
24 import io.netty.util.concurrent.Future;
25 import io.netty.util.concurrent.GlobalEventExecutor;
26 import io.netty.util.concurrent.Promise;
27 import io.netty.util.concurrent.SucceededFuture;
28 import java.io.IOException;
29 import java.net.InetSocketAddress;
30 import java.util.concurrent.ExecutionException;
31 import java.util.concurrent.TimeUnit;
32 import java.util.concurrent.TimeoutException;
33 import org.junit.After;
34 import org.junit.Before;
35 import org.junit.Test;
36 import org.mockito.Mockito;
38 public class ServerTest {
39 SimpleDispatcher clientDispatcher, dispatcher;
41 SimpleSession session = null;
43 ChannelFuture server = null;
45 InetSocketAddress serverAddress;
46 private NioEventLoopGroup eventLoopGroup;
47 // Dedicated loop group for server, needed for testing reconnection client
48 // With dedicated server group we can simulate session drop by shutting only the server group down
49 private NioEventLoopGroup serverLoopGroup;
53 final int port = 10000 + (int)(10000 * Math.random());
54 serverAddress = new InetSocketAddress("127.0.0.1", port);
55 eventLoopGroup = new NioEventLoopGroup();
56 serverLoopGroup = new NioEventLoopGroup();
60 public void tearDown() throws IOException, InterruptedException, ExecutionException {
62 this.server.channel().close();
64 this.eventLoopGroup.shutdownGracefully().get();
65 this.serverLoopGroup.shutdownGracefully().get();
68 } catch (final InterruptedException e) {
69 throw new RuntimeException(e);
74 public void testConnectionRefused() throws Exception {
75 this.clientDispatcher = getClientDispatcher();
77 final ReconnectStrategy mockReconnectStrategy = getMockedReconnectStrategy();
79 this.clientDispatcher.createClient(this.serverAddress,
80 mockReconnectStrategy, new SessionListenerFactory<SimpleSessionListener>() {
82 public SimpleSessionListener getSessionListener() {
83 return new SimpleSessionListener();
87 Mockito.verify(mockReconnectStrategy, timeout(5000).atLeast(2)).scheduleReconnect(any(Throwable.class));
91 public void testConnectionReestablishInitial() throws Exception {
92 this.clientDispatcher = getClientDispatcher();
94 final ReconnectStrategy mockReconnectStrategy = getMockedReconnectStrategy();
96 this.clientDispatcher.createClient(this.serverAddress,
97 mockReconnectStrategy, new SessionListenerFactory<SimpleSessionListener>() {
99 public SimpleSessionListener getSessionListener() {
100 return new SimpleSessionListener();
104 Mockito.verify(mockReconnectStrategy, timeout(5000).atLeast(2)).scheduleReconnect(any(Throwable.class));
106 final Promise<Boolean> p = new DefaultPromise<>(GlobalEventExecutor.INSTANCE);
107 this.dispatcher = getServerDispatcher(p);
109 this.server = this.dispatcher.createServer(this.serverAddress, new SessionListenerFactory<SimpleSessionListener>() {
111 public SimpleSessionListener getSessionListener() {
112 return new SimpleSessionListener();
118 assertEquals(true, p.get(3, TimeUnit.SECONDS));
122 public void testConnectionDrop() throws Exception {
123 final Promise<Boolean> p = new DefaultPromise<>(GlobalEventExecutor.INSTANCE);
125 this.dispatcher = getServerDispatcher(p);
127 this.server = this.dispatcher.createServer(this.serverAddress, new SessionListenerFactory<SimpleSessionListener>() {
129 public SimpleSessionListener getSessionListener() {
130 return new SimpleSessionListener();
136 this.clientDispatcher = getClientDispatcher();
138 final ReconnectStrategy reconnectStrategy = getMockedReconnectStrategy();
139 this.session = this.clientDispatcher.createClient(this.serverAddress,
140 reconnectStrategy, new SessionListenerFactory<SimpleSessionListener>() {
142 public SimpleSessionListener getSessionListener() {
143 return new SimpleSessionListener();
145 }).get(6, TimeUnit.SECONDS);
147 assertEquals(true, p.get(3, TimeUnit.SECONDS));
151 // No reconnect should be scheduled after server drops connection with not-reconnecting client
152 verify(reconnectStrategy, times(0)).scheduleReconnect(any(Throwable.class));
156 public void testConnectionReestablishAfterDrop() throws Exception {
157 final Promise<Boolean> p = new DefaultPromise<>(GlobalEventExecutor.INSTANCE);
159 this.dispatcher = getServerDispatcher(p);
161 this.server = this.dispatcher.createServer(this.serverAddress, new SessionListenerFactory<SimpleSessionListener>() {
163 public SimpleSessionListener getSessionListener() {
164 return new SimpleSessionListener();
170 this.clientDispatcher = getClientDispatcher();
172 final ReconnectStrategyFactory reconnectStrategyFactory = mock(ReconnectStrategyFactory.class);
173 final ReconnectStrategy reconnectStrategy = getMockedReconnectStrategy();
174 doReturn(reconnectStrategy).when(reconnectStrategyFactory).createReconnectStrategy();
176 this.clientDispatcher.createReconnectingClient(this.serverAddress,
177 reconnectStrategyFactory, new SessionListenerFactory<SimpleSessionListener>() {
179 public SimpleSessionListener getSessionListener() {
180 return new SimpleSessionListener();
184 assertEquals(true, p.get(3, TimeUnit.SECONDS));
187 verify(reconnectStrategyFactory, timeout(20000).atLeast(2)).createReconnectStrategy();
191 public void testConnectionEstablished() throws Exception {
192 final Promise<Boolean> p = new DefaultPromise<>(GlobalEventExecutor.INSTANCE);
194 this.dispatcher = getServerDispatcher(p);
196 this.server = this.dispatcher.createServer(this.serverAddress, new SessionListenerFactory<SimpleSessionListener>() {
198 public SimpleSessionListener getSessionListener() {
199 return new SimpleSessionListener();
205 this.clientDispatcher = getClientDispatcher();
207 this.session = this.clientDispatcher.createClient(this.serverAddress,
208 new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, 5000), new SessionListenerFactory<SimpleSessionListener>() {
210 public SimpleSessionListener getSessionListener() {
211 return new SimpleSessionListener();
213 }).get(6, TimeUnit.SECONDS);
215 assertEquals(true, p.get(3, TimeUnit.SECONDS));
219 public void testConnectionFailed() throws IOException, InterruptedException, ExecutionException, TimeoutException {
220 final Promise<Boolean> p = new DefaultPromise<>(GlobalEventExecutor.INSTANCE);
222 this.dispatcher = getServerDispatcher(p);
224 this.server = this.dispatcher.createServer(this.serverAddress, new SessionListenerFactory<SimpleSessionListener>() {
226 public SimpleSessionListener getSessionListener() {
227 return new SimpleSessionListener();
233 this.clientDispatcher = getClientDispatcher();
235 this.session = this.clientDispatcher.createClient(this.serverAddress,
236 new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, 5000), new SessionListenerFactory<SimpleSessionListener>() {
238 public SimpleSessionListener getSessionListener() {
239 return new SimpleSessionListener();
241 }).get(6, TimeUnit.SECONDS);
243 final Future<?> session = this.clientDispatcher.createClient(this.serverAddress,
244 new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, 5000), new SessionListenerFactory<SimpleSessionListener>() {
246 public SimpleSessionListener getSessionListener() {
247 return new SimpleSessionListener();
250 assertFalse(session.isSuccess());
254 public void testNegotiationFailedNoReconnect() throws Exception {
255 final Promise<Boolean> p = new DefaultPromise<>(GlobalEventExecutor.INSTANCE);
257 this.dispatcher = getServerDispatcher(p);
259 this.server = this.dispatcher.createServer(this.serverAddress, new SessionListenerFactory<SimpleSessionListener>() {
261 public SimpleSessionListener getSessionListener() {
262 return new SimpleSessionListener();
268 this.clientDispatcher = new SimpleDispatcher(new SessionNegotiatorFactory<SimpleMessage, SimpleSession, SimpleSessionListener>() {
270 public SessionNegotiator<SimpleSession> getSessionNegotiator(final SessionListenerFactory<SimpleSessionListener> factory,
271 final Channel channel, final Promise<SimpleSession> promise) {
273 return new SimpleSessionNegotiator(promise, channel) {
275 protected void startNegotiation() throws Exception {
276 negotiationFailed(new IllegalStateException("Negotiation failed"));
280 }, new DefaultPromise<SimpleSession>(GlobalEventExecutor.INSTANCE), eventLoopGroup);
282 final ReconnectStrategyFactory reconnectStrategyFactory = mock(ReconnectStrategyFactory.class);
283 final ReconnectStrategy reconnectStrategy = getMockedReconnectStrategy();
284 doReturn(reconnectStrategy).when(reconnectStrategyFactory).createReconnectStrategy();
286 this.clientDispatcher.createReconnectingClient(this.serverAddress,
287 reconnectStrategyFactory, new SessionListenerFactory<SimpleSessionListener>() {
289 public SimpleSessionListener getSessionListener() {
290 return new SimpleSessionListener();
295 // Only one strategy should be created for initial connect, no more = no reconnects
296 verify(reconnectStrategyFactory, times(1)).createReconnectStrategy();
299 private SimpleDispatcher getClientDispatcher() {
300 return new SimpleDispatcher(new SessionNegotiatorFactory<SimpleMessage, SimpleSession, SimpleSessionListener>() {
302 public SessionNegotiator<SimpleSession> getSessionNegotiator(final SessionListenerFactory<SimpleSessionListener> factory,
303 final Channel channel, final Promise<SimpleSession> promise) {
304 return new SimpleSessionNegotiator(promise, channel);
306 }, new DefaultPromise<SimpleSession>(GlobalEventExecutor.INSTANCE), eventLoopGroup);
309 private ReconnectStrategy getMockedReconnectStrategy() throws Exception {
310 final ReconnectStrategy mockReconnectStrategy = mock(ReconnectStrategy.class);
311 final Future<Void> future = new SucceededFuture<>(GlobalEventExecutor.INSTANCE, null);
312 doReturn(future).when(mockReconnectStrategy).scheduleReconnect(any(Throwable.class));
313 doReturn(5000).when(mockReconnectStrategy).getConnectTimeout();
314 doNothing().when(mockReconnectStrategy).reconnectSuccessful();
315 return mockReconnectStrategy;
319 private void shutdownServer() throws InterruptedException, ExecutionException {
321 server.channel().close().get();
322 // Closing server channel does not close established connections, eventLoop has to be closed as well to simulate dropped session
323 serverLoopGroup.shutdownGracefully().get();
326 private SimpleDispatcher getServerDispatcher(final Promise<Boolean> p) {
327 return new SimpleDispatcher(new SessionNegotiatorFactory<SimpleMessage, SimpleSession, SimpleSessionListener>() {
330 public SessionNegotiator<SimpleSession> getSessionNegotiator(final SessionListenerFactory<SimpleSessionListener> factory,
331 final Channel channel, final Promise<SimpleSession> promise) {
333 return new SimpleSessionNegotiator(promise, channel);
335 }, null, serverLoopGroup);