protocol-framework: use lambdas
[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.ChannelFuture;
21 import io.netty.channel.nio.NioEventLoopGroup;
22 import io.netty.util.concurrent.DefaultPromise;
23 import io.netty.util.concurrent.Future;
24 import io.netty.util.concurrent.GlobalEventExecutor;
25 import io.netty.util.concurrent.Promise;
26 import io.netty.util.concurrent.SucceededFuture;
27 import java.io.IOException;
28 import java.net.InetSocketAddress;
29 import java.util.concurrent.ExecutionException;
30 import java.util.concurrent.TimeUnit;
31 import java.util.concurrent.TimeoutException;
32 import org.junit.After;
33 import org.junit.Before;
34 import org.junit.Test;
35 import org.mockito.Mockito;
36
37 public class ServerTest {
38     SimpleDispatcher clientDispatcher, dispatcher;
39
40     SimpleSession session = null;
41
42     ChannelFuture server = null;
43
44     InetSocketAddress serverAddress;
45     private NioEventLoopGroup eventLoopGroup;
46     // Dedicated loop group for server, needed for testing reconnection client
47     // With dedicated server group we can simulate session drop by shutting only the server group down
48     private NioEventLoopGroup serverLoopGroup;
49
50     @Before
51     public void setUp() {
52         final int port = 10000 + (int)(10000 * Math.random());
53         serverAddress = new InetSocketAddress("127.0.0.1", port);
54         eventLoopGroup = new NioEventLoopGroup();
55         serverLoopGroup = new NioEventLoopGroup();
56     }
57
58     @After
59     public void tearDown() throws IOException, InterruptedException, ExecutionException {
60         if(server != null) {
61             this.server.channel().close();
62         }
63         this.eventLoopGroup.shutdownGracefully().get();
64         this.serverLoopGroup.shutdownGracefully().get();
65         try {
66             Thread.sleep(500);
67         } catch (final InterruptedException e) {
68             throw new RuntimeException(e);
69         }
70     }
71
72     @Test
73     public void testConnectionRefused() throws Exception {
74         this.clientDispatcher = getClientDispatcher();
75
76         final ReconnectStrategy mockReconnectStrategy = getMockedReconnectStrategy();
77
78         this.clientDispatcher.createClient(this.serverAddress, mockReconnectStrategy, SimpleSessionListener::new);
79
80         Mockito.verify(mockReconnectStrategy, timeout(5000).atLeast(2)).scheduleReconnect(any(Throwable.class));
81     }
82
83     @Test
84     public void testConnectionReestablishInitial() throws Exception {
85         this.clientDispatcher = getClientDispatcher();
86
87         final ReconnectStrategy mockReconnectStrategy = getMockedReconnectStrategy();
88
89         this.clientDispatcher.createClient(this.serverAddress, mockReconnectStrategy, SimpleSessionListener::new);
90
91         Mockito.verify(mockReconnectStrategy, timeout(5000).atLeast(2)).scheduleReconnect(any(Throwable.class));
92
93         final Promise<Boolean> p = new DefaultPromise<>(GlobalEventExecutor.INSTANCE);
94         this.dispatcher = getServerDispatcher(p);
95
96         this.server = this.dispatcher.createServer(this.serverAddress, SimpleSessionListener::new);
97
98         this.server.get();
99
100         assertEquals(true, p.get(3, TimeUnit.SECONDS));
101     }
102
103     @Test
104     public void testConnectionDrop() throws Exception {
105         final Promise<Boolean> p = new DefaultPromise<>(GlobalEventExecutor.INSTANCE);
106
107         this.dispatcher = getServerDispatcher(p);
108
109         this.server = this.dispatcher.createServer(this.serverAddress, SimpleSessionListener::new);
110
111         this.server.get();
112
113         this.clientDispatcher = getClientDispatcher();
114
115         final ReconnectStrategy reconnectStrategy = getMockedReconnectStrategy();
116         this.session = this.clientDispatcher.createClient(this.serverAddress,
117                 reconnectStrategy, SimpleSessionListener::new).get(6, TimeUnit.SECONDS);
118
119         assertEquals(true, p.get(3, TimeUnit.SECONDS));
120
121         shutdownServer();
122
123         // No reconnect should be scheduled after server drops connection with not-reconnecting client
124         verify(reconnectStrategy, times(0)).scheduleReconnect(any(Throwable.class));
125     }
126
127     @Test
128     public void testConnectionReestablishAfterDrop() throws Exception {
129         final Promise<Boolean> p = new DefaultPromise<>(GlobalEventExecutor.INSTANCE);
130
131         this.dispatcher = getServerDispatcher(p);
132
133         this.server = this.dispatcher.createServer(this.serverAddress, SimpleSessionListener::new);
134
135         this.server.get();
136
137         this.clientDispatcher = getClientDispatcher();
138
139         final ReconnectStrategyFactory reconnectStrategyFactory = mock(ReconnectStrategyFactory.class);
140         final ReconnectStrategy reconnectStrategy = getMockedReconnectStrategy();
141         doReturn(reconnectStrategy).when(reconnectStrategyFactory).createReconnectStrategy();
142
143         this.clientDispatcher.createReconnectingClient(this.serverAddress,
144                 reconnectStrategyFactory, SimpleSessionListener::new);
145
146         assertEquals(true, p.get(3, TimeUnit.SECONDS));
147         shutdownServer();
148
149         verify(reconnectStrategyFactory, timeout(20000).atLeast(2)).createReconnectStrategy();
150     }
151
152     @Test
153     public void testConnectionEstablished() throws Exception {
154         final Promise<Boolean> p = new DefaultPromise<>(GlobalEventExecutor.INSTANCE);
155
156         this.dispatcher = getServerDispatcher(p);
157
158         this.server = this.dispatcher.createServer(this.serverAddress, SimpleSessionListener::new);
159
160         this.server.get();
161
162         this.clientDispatcher = getClientDispatcher();
163
164         this.session = this.clientDispatcher.createClient(this.serverAddress,
165                 new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, 5000), SimpleSessionListener::new).get(6,
166                 TimeUnit.SECONDS);
167
168         assertEquals(true, p.get(3, TimeUnit.SECONDS));
169     }
170
171     @Test
172     public void testConnectionFailed() throws IOException, InterruptedException, ExecutionException, TimeoutException {
173         final Promise<Boolean> p = new DefaultPromise<>(GlobalEventExecutor.INSTANCE);
174
175         this.dispatcher = getServerDispatcher(p);
176
177         this.server = this.dispatcher.createServer(this.serverAddress, SimpleSessionListener::new);
178
179         this.server.get();
180
181         this.clientDispatcher = getClientDispatcher();
182
183         this.session = this.clientDispatcher.createClient(this.serverAddress,
184                 new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, 5000), SimpleSessionListener::new).get(6,
185                 TimeUnit.SECONDS);
186
187         final Future<?> session = this.clientDispatcher.createClient(this.serverAddress,
188                 new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, 5000), SimpleSessionListener::new);
189         assertFalse(session.isSuccess());
190     }
191
192     @Test
193     public void testNegotiationFailedReconnect() throws Exception {
194         final Promise<Boolean> p = new DefaultPromise<>(GlobalEventExecutor.INSTANCE);
195
196         this.dispatcher = getServerDispatcher(p);
197
198         this.server = this.dispatcher.createServer(this.serverAddress, SimpleSessionListener::new);
199
200         this.server.get();
201
202         this.clientDispatcher = new SimpleDispatcher(
203                 (factory, channel, promise) -> new SimpleSessionNegotiator(promise, channel) {
204                     @Override
205                     protected void startNegotiation() throws Exception {
206                         negotiationFailed(new IllegalStateException("Negotiation failed"));
207                     }
208                 }, new DefaultPromise<>(GlobalEventExecutor.INSTANCE), eventLoopGroup);
209
210         final ReconnectStrategyFactory reconnectStrategyFactory = mock(ReconnectStrategyFactory.class);
211         final ReconnectStrategy reconnectStrategy = getMockedReconnectStrategy();
212         doReturn(reconnectStrategy).when(reconnectStrategyFactory).createReconnectStrategy();
213
214         this.clientDispatcher.createReconnectingClient(this.serverAddress,
215                 reconnectStrategyFactory, SimpleSessionListener::new);
216
217
218         // Reconnect strategy should be consulted at least twice, for initial connect and reconnect attempts after drop
219         verify(reconnectStrategyFactory, timeout((int) TimeUnit.MINUTES.toMillis(3)).atLeast(2)).createReconnectStrategy();
220     }
221
222     private SimpleDispatcher getClientDispatcher() {
223         return new SimpleDispatcher((factory, channel, promise) -> new SimpleSessionNegotiator(promise, channel), new DefaultPromise<>(GlobalEventExecutor.INSTANCE), eventLoopGroup);
224     }
225
226     private ReconnectStrategy getMockedReconnectStrategy() throws Exception {
227         final ReconnectStrategy mockReconnectStrategy = mock(ReconnectStrategy.class);
228         final Future<Void> future = new SucceededFuture<>(GlobalEventExecutor.INSTANCE, null);
229         doReturn(future).when(mockReconnectStrategy).scheduleReconnect(any(Throwable.class));
230         doReturn(5000).when(mockReconnectStrategy).getConnectTimeout();
231         doNothing().when(mockReconnectStrategy).reconnectSuccessful();
232         return mockReconnectStrategy;
233     }
234
235
236     private void shutdownServer() throws InterruptedException, ExecutionException {
237         // Shutdown server
238         server.channel().close().get();
239         // Closing server channel does not close established connections, eventLoop has to be closed as well to simulate dropped session
240         serverLoopGroup.shutdownGracefully().get();
241     }
242
243     private SimpleDispatcher getServerDispatcher(final Promise<Boolean> p) {
244         return new SimpleDispatcher((factory, channel, promise) -> {
245             p.setSuccess(true);
246             return new SimpleSessionNegotiator(promise, channel);
247         }, null, serverLoopGroup);
248     }
249
250 }