Merge "ControllerContext.dataNodeChildByQName method refactoring"
[controller.git] / opendaylight / commons / protocol-framework / src / test / java / org / opendaylight / protocol / framework / ServerTest.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.protocol.framework;
9
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;
19
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;
37
38 public class ServerTest {
39     SimpleDispatcher clientDispatcher, dispatcher;
40
41     SimpleSession session = null;
42
43     ChannelFuture server = null;
44
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;
50
51     @Before
52     public void setUp() {
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();
57     }
58
59     @After
60     public void tearDown() throws IOException, InterruptedException, ExecutionException {
61         if(server != null) {
62             this.server.channel().close();
63         }
64         this.eventLoopGroup.shutdownGracefully().get();
65         this.serverLoopGroup.shutdownGracefully().get();
66         try {
67             Thread.sleep(500);
68         } catch (final InterruptedException e) {
69             throw new RuntimeException(e);
70         }
71     }
72
73     @Test
74     public void testConnectionRefused() throws Exception {
75         this.clientDispatcher = getClientDispatcher();
76
77         final ReconnectStrategy mockReconnectStrategy = getMockedReconnectStrategy();
78
79         this.clientDispatcher.createClient(this.serverAddress,
80                 mockReconnectStrategy, new SessionListenerFactory<SimpleSessionListener>() {
81                     @Override
82                     public SimpleSessionListener getSessionListener() {
83                         return new SimpleSessionListener();
84                     }
85                 });
86
87         Mockito.verify(mockReconnectStrategy, timeout(5000).atLeast(2)).scheduleReconnect(any(Throwable.class));
88     }
89
90     @Test
91     public void testConnectionReestablishInitial() throws Exception {
92         this.clientDispatcher = getClientDispatcher();
93
94         final ReconnectStrategy mockReconnectStrategy = getMockedReconnectStrategy();
95
96         this.clientDispatcher.createClient(this.serverAddress,
97                 mockReconnectStrategy, new SessionListenerFactory<SimpleSessionListener>() {
98                     @Override
99                     public SimpleSessionListener getSessionListener() {
100                         return new SimpleSessionListener();
101                     }
102                 });
103
104         Mockito.verify(mockReconnectStrategy, timeout(5000).atLeast(2)).scheduleReconnect(any(Throwable.class));
105
106         final Promise<Boolean> p = new DefaultPromise<>(GlobalEventExecutor.INSTANCE);
107         this.dispatcher = getServerDispatcher(p);
108
109         this.server = this.dispatcher.createServer(this.serverAddress, new SessionListenerFactory<SimpleSessionListener>() {
110             @Override
111             public SimpleSessionListener getSessionListener() {
112                 return new SimpleSessionListener();
113             }
114         });
115
116         this.server.get();
117
118         assertEquals(true, p.get(3, TimeUnit.SECONDS));
119     }
120
121     @Test
122     public void testConnectionDrop() throws Exception {
123         final Promise<Boolean> p = new DefaultPromise<>(GlobalEventExecutor.INSTANCE);
124
125         this.dispatcher = getServerDispatcher(p);
126
127         this.server = this.dispatcher.createServer(this.serverAddress, new SessionListenerFactory<SimpleSessionListener>() {
128             @Override
129             public SimpleSessionListener getSessionListener() {
130                 return new SimpleSessionListener();
131             }
132         });
133
134         this.server.get();
135
136         this.clientDispatcher = getClientDispatcher();
137
138         final ReconnectStrategy reconnectStrategy = getMockedReconnectStrategy();
139         this.session = this.clientDispatcher.createClient(this.serverAddress,
140                 reconnectStrategy, new SessionListenerFactory<SimpleSessionListener>() {
141                     @Override
142                     public SimpleSessionListener getSessionListener() {
143                         return new SimpleSessionListener();
144                     }
145                 }).get(6, TimeUnit.SECONDS);
146
147         assertEquals(true, p.get(3, TimeUnit.SECONDS));
148
149         shutdownServer();
150
151         // No reconnect should be scheduled after server drops connection with not-reconnecting client
152         verify(reconnectStrategy, times(0)).scheduleReconnect(any(Throwable.class));
153     }
154
155     @Test
156     public void testConnectionReestablishAfterDrop() throws Exception {
157         final Promise<Boolean> p = new DefaultPromise<>(GlobalEventExecutor.INSTANCE);
158
159         this.dispatcher = getServerDispatcher(p);
160
161         this.server = this.dispatcher.createServer(this.serverAddress, new SessionListenerFactory<SimpleSessionListener>() {
162             @Override
163             public SimpleSessionListener getSessionListener() {
164                 return new SimpleSessionListener();
165             }
166         });
167
168         this.server.get();
169
170         this.clientDispatcher = getClientDispatcher();
171
172         final ReconnectStrategyFactory reconnectStrategyFactory = mock(ReconnectStrategyFactory.class);
173         final ReconnectStrategy reconnectStrategy = getMockedReconnectStrategy();
174         doReturn(reconnectStrategy).when(reconnectStrategyFactory).createReconnectStrategy();
175
176         this.clientDispatcher.createReconnectingClient(this.serverAddress,
177                 reconnectStrategyFactory, new SessionListenerFactory<SimpleSessionListener>() {
178                     @Override
179                     public SimpleSessionListener getSessionListener() {
180                         return new SimpleSessionListener();
181                     }
182                 });
183
184         assertEquals(true, p.get(3, TimeUnit.SECONDS));
185         shutdownServer();
186
187         verify(reconnectStrategyFactory, timeout(20000).atLeast(2)).createReconnectStrategy();
188     }
189
190     @Test
191     public void testConnectionEstablished() throws Exception {
192         final Promise<Boolean> p = new DefaultPromise<>(GlobalEventExecutor.INSTANCE);
193
194         this.dispatcher = getServerDispatcher(p);
195
196         this.server = this.dispatcher.createServer(this.serverAddress, new SessionListenerFactory<SimpleSessionListener>() {
197             @Override
198             public SimpleSessionListener getSessionListener() {
199                 return new SimpleSessionListener();
200             }
201         });
202
203         this.server.get();
204
205         this.clientDispatcher = getClientDispatcher();
206
207         this.session = this.clientDispatcher.createClient(this.serverAddress,
208                 new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, 5000), new SessionListenerFactory<SimpleSessionListener>() {
209             @Override
210             public SimpleSessionListener getSessionListener() {
211                 return new SimpleSessionListener();
212             }
213         }).get(6, TimeUnit.SECONDS);
214
215         assertEquals(true, p.get(3, TimeUnit.SECONDS));
216     }
217
218     @Test
219     public void testConnectionFailed() throws IOException, InterruptedException, ExecutionException, TimeoutException {
220         final Promise<Boolean> p = new DefaultPromise<>(GlobalEventExecutor.INSTANCE);
221
222         this.dispatcher = getServerDispatcher(p);
223
224         this.server = this.dispatcher.createServer(this.serverAddress, new SessionListenerFactory<SimpleSessionListener>() {
225             @Override
226             public SimpleSessionListener getSessionListener() {
227                 return new SimpleSessionListener();
228             }
229         });
230
231         this.server.get();
232
233         this.clientDispatcher = getClientDispatcher();
234
235         this.session = this.clientDispatcher.createClient(this.serverAddress,
236                 new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, 5000), new SessionListenerFactory<SimpleSessionListener>() {
237             @Override
238             public SimpleSessionListener getSessionListener() {
239                 return new SimpleSessionListener();
240             }
241         }).get(6, TimeUnit.SECONDS);
242
243         final Future<?> session = this.clientDispatcher.createClient(this.serverAddress,
244                 new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, 5000), new SessionListenerFactory<SimpleSessionListener>() {
245             @Override
246             public SimpleSessionListener getSessionListener() {
247                 return new SimpleSessionListener();
248             }
249         });
250         assertFalse(session.isSuccess());
251     }
252
253     @Test
254     public void testNegotiationFailedNoReconnect() throws Exception {
255         final Promise<Boolean> p = new DefaultPromise<>(GlobalEventExecutor.INSTANCE);
256
257         this.dispatcher = getServerDispatcher(p);
258
259         this.server = this.dispatcher.createServer(this.serverAddress, new SessionListenerFactory<SimpleSessionListener>() {
260             @Override
261             public SimpleSessionListener getSessionListener() {
262                 return new SimpleSessionListener();
263             }
264         });
265
266         this.server.get();
267
268         this.clientDispatcher = new SimpleDispatcher(new SessionNegotiatorFactory<SimpleMessage, SimpleSession, SimpleSessionListener>() {
269             @Override
270             public SessionNegotiator<SimpleSession> getSessionNegotiator(final SessionListenerFactory<SimpleSessionListener> factory,
271                                                                          final Channel channel, final Promise<SimpleSession> promise) {
272
273                 return new SimpleSessionNegotiator(promise, channel) {
274                     @Override
275                     protected void startNegotiation() throws Exception {
276                         negotiationFailed(new IllegalStateException("Negotiation failed"));
277                     }
278                 };
279             }
280         }, new DefaultPromise<SimpleSession>(GlobalEventExecutor.INSTANCE), eventLoopGroup);
281
282         final ReconnectStrategyFactory reconnectStrategyFactory = mock(ReconnectStrategyFactory.class);
283         final ReconnectStrategy reconnectStrategy = getMockedReconnectStrategy();
284         doReturn(reconnectStrategy).when(reconnectStrategyFactory).createReconnectStrategy();
285
286         this.clientDispatcher.createReconnectingClient(this.serverAddress,
287                 reconnectStrategyFactory, new SessionListenerFactory<SimpleSessionListener>() {
288                     @Override
289                     public SimpleSessionListener getSessionListener() {
290                         return new SimpleSessionListener();
291                     }
292                 });
293
294
295         // Only one strategy should be created for initial connect, no more = no reconnects
296         verify(reconnectStrategyFactory, times(1)).createReconnectStrategy();
297     }
298
299     private SimpleDispatcher getClientDispatcher() {
300         return new SimpleDispatcher(new SessionNegotiatorFactory<SimpleMessage, SimpleSession, SimpleSessionListener>() {
301             @Override
302             public SessionNegotiator<SimpleSession> getSessionNegotiator(final SessionListenerFactory<SimpleSessionListener> factory,
303                                                                          final Channel channel, final Promise<SimpleSession> promise) {
304                 return new SimpleSessionNegotiator(promise, channel);
305             }
306         }, new DefaultPromise<SimpleSession>(GlobalEventExecutor.INSTANCE), eventLoopGroup);
307     }
308
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;
316     }
317
318
319     private void shutdownServer() throws InterruptedException, ExecutionException {
320         // Shutdown server
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();
324     }
325
326     private SimpleDispatcher getServerDispatcher(final Promise<Boolean> p) {
327         return new SimpleDispatcher(new SessionNegotiatorFactory<SimpleMessage, SimpleSession, SimpleSessionListener>() {
328
329             @Override
330             public SessionNegotiator<SimpleSession> getSessionNegotiator(final SessionListenerFactory<SimpleSessionListener> factory,
331                                                                          final Channel channel, final Promise<SimpleSession> promise) {
332                 p.setSuccess(true);
333                 return new SimpleSessionNegotiator(promise, channel);
334             }
335         }, null, serverLoopGroup);
336     }
337
338 }