Clean up use of MockitoAnnotations.initMocks
[controller.git] / opendaylight / md-sal / cds-access-client / src / test / java / org / opendaylight / controller / cluster / access / client / ConnectingClientConnectionTest.java
1 /*
2  * Copyright (c) 2016 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.controller.cluster.access.client;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertFalse;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertNull;
14 import static org.junit.Assert.assertSame;
15 import static org.junit.Assert.assertTrue;
16 import static org.mockito.ArgumentMatchers.any;
17 import static org.mockito.Mockito.doNothing;
18 import static org.mockito.Mockito.doReturn;
19 import static org.mockito.Mockito.mock;
20 import static org.mockito.Mockito.verify;
21 import static org.mockito.Mockito.verifyNoMoreInteractions;
22
23 import akka.actor.ActorRef;
24 import akka.actor.ActorSystem;
25 import akka.testkit.TestProbe;
26 import com.google.common.testing.FakeTicker;
27 import java.util.OptionalLong;
28 import java.util.concurrent.ThreadLocalRandom;
29 import java.util.concurrent.TimeUnit;
30 import java.util.function.Consumer;
31 import org.junit.After;
32 import org.junit.AfterClass;
33 import org.junit.Before;
34 import org.junit.BeforeClass;
35 import org.junit.Test;
36 import org.junit.runner.RunWith;
37 import org.mockito.ArgumentCaptor;
38 import org.mockito.Mock;
39 import org.mockito.junit.MockitoJUnitRunner;
40 import org.opendaylight.controller.cluster.access.ABIVersion;
41 import org.opendaylight.controller.cluster.access.concepts.AbstractRequestFailureProxy;
42 import org.opendaylight.controller.cluster.access.concepts.AbstractRequestProxy;
43 import org.opendaylight.controller.cluster.access.concepts.FailureEnvelope;
44 import org.opendaylight.controller.cluster.access.concepts.Request;
45 import org.opendaylight.controller.cluster.access.concepts.RequestEnvelope;
46 import org.opendaylight.controller.cluster.access.concepts.RequestException;
47 import org.opendaylight.controller.cluster.access.concepts.RequestFailure;
48 import org.opendaylight.controller.cluster.access.concepts.Response;
49 import org.opendaylight.controller.cluster.messaging.MessageSlicer;
50 import org.opendaylight.yangtools.concepts.WritableIdentifier;
51 import scala.concurrent.duration.FiniteDuration;
52
53 /**
54  * Test suite covering logic contained in {@link ConnectingClientConnection}. It assumes {@link ConnectionEntryTest}
55  * passes.
56  */
57 @RunWith(MockitoJUnitRunner.class)
58 public class ConnectingClientConnectionTest {
59     private static class MockFailure extends RequestFailure<WritableIdentifier, MockFailure> {
60         private static final long serialVersionUID = 1L;
61
62         MockFailure(final WritableIdentifier target, final RequestException cause) {
63             super(target, 0, cause);
64         }
65
66         @Override
67         protected AbstractRequestFailureProxy<WritableIdentifier, MockFailure> externalizableProxy(
68                 final ABIVersion version) {
69             return null;
70         }
71
72         @Override
73         protected MockFailure cloneAsVersion(final ABIVersion version) {
74             return this;
75         }
76     }
77
78     private static class MockRequest extends Request<WritableIdentifier, MockRequest> {
79         private static final long serialVersionUID = 1L;
80
81         MockRequest(final WritableIdentifier target, final ActorRef replyTo) {
82             super(target, 0, replyTo);
83         }
84
85         @Override
86         public RequestFailure<WritableIdentifier, ?> toRequestFailure(final RequestException cause) {
87             return new MockFailure(getTarget(), cause);
88         }
89
90         @Override
91         protected AbstractRequestProxy<WritableIdentifier, MockRequest> externalizableProxy(final ABIVersion version) {
92             return null;
93         }
94
95         @Override
96         protected MockRequest cloneAsVersion(final ABIVersion version) {
97             return this;
98         }
99     }
100
101     @Mock
102     private ActorRef mockReplyTo;
103     @Mock
104     private WritableIdentifier mockIdentifier;
105     @Mock
106     private RequestException mockCause;
107     @Mock
108     private Consumer<Response<?, ?>> mockCallback;
109     @Mock
110     private ClientActorBehavior<?> mockBehavior;
111     @Mock
112     private ClientActorContext mockContext;
113
114     private FakeTicker ticker;
115     private BackendInfo mockBackendInfo;
116     private MockRequest mockRequest;
117     private MockRequest mockRequest2;
118     private RequestFailure<WritableIdentifier, ?> mockResponse;
119     private FailureEnvelope mockResponseEnvelope;
120     private Long mockCookie;
121
122     private static ActorSystem actorSystem;
123     private TestProbe mockActor;
124
125     private AbstractClientConnection<?> queue;
126
127     @BeforeClass
128     public static void setupClass() {
129         actorSystem = ActorSystem.apply();
130     }
131
132     @AfterClass
133     public static void teardownClass() {
134         actorSystem.terminate();
135     }
136
137     @Before
138     public void setup() {
139         doNothing().when(mockCallback).accept(any(MockFailure.class));
140
141         ticker = new FakeTicker();
142         ticker.advance(ThreadLocalRandom.current().nextLong());
143         doReturn(ticker).when(mockContext).ticker();
144
145         final ClientActorConfig mockConfig = AccessClientUtil.newMockClientActorConfig();
146         doReturn(mockConfig).when(mockContext).config();
147
148         doReturn(mock(MessageSlicer.class)).when(mockContext).messageSlicer();
149
150         mockActor = TestProbe.apply(actorSystem);
151         mockBackendInfo = new BackendInfo(mockActor.ref(), "test", 0, ABIVersion.current(), 5);
152         mockRequest = new MockRequest(mockIdentifier, mockReplyTo);
153         mockRequest2 = new MockRequest(mockIdentifier, mockReplyTo);
154         mockResponse = mockRequest.toRequestFailure(mockCause);
155         mockResponseEnvelope = new FailureEnvelope(mockResponse, 0, 0, 0);
156         mockCookie = ThreadLocalRandom.current().nextLong();
157
158         queue = new ConnectingClientConnection<>(mockContext, mockCookie, mockBackendInfo.getName());
159     }
160
161     @After
162     public void teardown() {
163         actorSystem.stop(mockActor.ref());
164     }
165
166     @Test
167     public void testCookie() {
168         assertEquals(mockCookie, queue.cookie());
169     }
170
171     @Test
172     public void testPoison() {
173         queue.sendRequest(mockRequest, mockCallback);
174         queue.poison(mockCause);
175
176         final ArgumentCaptor<MockFailure> captor = ArgumentCaptor.forClass(MockFailure.class);
177         verify(mockCallback).accept(captor.capture());
178         assertSame(mockCause, captor.getValue().getCause());
179     }
180
181     @Test(expected = IllegalStateException.class)
182     public void testPoisonPerformsClose() {
183         // Implies close()
184         queue.poison(mockCause);
185
186         // Kaboom
187         queue.sendRequest(mockRequest, mockCallback);
188     }
189
190     @Test
191     public void testPoisonIdempotent() {
192         queue.poison(mockCause);
193         queue.poison(mockCause);
194     }
195
196     @Test
197     public void testSendRequestNeedsBackend() {
198         queue.sendRequest(mockRequest, mockCallback);
199         final OptionalLong ret = queue.checkTimeout(ticker.read());
200         assertNotNull(ret);
201         assertTrue(ret.isPresent());
202     }
203
204     @Test
205     public void testSetBackendWithNoRequests() {
206         // this utility method covers the entire test
207         setupBackend();
208     }
209
210     @Test
211     public void testSendRequestNeedsTimer() {
212         setupBackend();
213
214         queue.sendRequest(mockRequest, mockCallback);
215         final OptionalLong ret = queue.checkTimeout(ticker.read());
216         assertNotNull(ret);
217         assertTrue(ret.isPresent());
218         assertTransmit(mockRequest, 0);
219     }
220
221     @Test
222     public void testRunTimeoutEmpty() {
223         OptionalLong ret = queue.checkTimeout(ticker.read());
224         assertNotNull(ret);
225         assertFalse(ret.isPresent());
226     }
227
228     @Test
229     public void testRunTimeoutWithoutShift() {
230         queue.sendRequest(mockRequest, mockCallback);
231         OptionalLong ret = queue.checkTimeout(ticker.read());
232         assertNotNull(ret);
233         assertTrue(ret.isPresent());
234     }
235
236     @Test
237     public void testRunTimeoutWithTimeoutLess() {
238         queue.sendRequest(mockRequest, mockCallback);
239
240         ticker.advance(AbstractClientConnection.DEFAULT_BACKEND_ALIVE_TIMEOUT_NANOS - 1);
241
242         OptionalLong ret = queue.checkTimeout(ticker.read());
243         assertNotNull(ret);
244         assertTrue(ret.isPresent());
245     }
246
247     @Test
248     public void testRunTimeoutWithTimeoutExact() {
249         setupBackend();
250
251         queue.sendRequest(mockRequest, mockCallback);
252
253         ticker.advance(AbstractClientConnection.DEFAULT_BACKEND_ALIVE_TIMEOUT_NANOS);
254
255         OptionalLong ret = queue.checkTimeout(ticker.read());
256         assertNull(ret);
257     }
258
259     @Test
260     public void testRunTimeoutWithTimeoutMore() {
261         setupBackend();
262
263         queue.sendRequest(mockRequest, mockCallback);
264
265         ticker.advance(AbstractClientConnection.DEFAULT_BACKEND_ALIVE_TIMEOUT_NANOS + 1);
266
267         assertNull(queue.checkTimeout(ticker.read()));
268     }
269
270     @SuppressWarnings({ "rawtypes", "unchecked" })
271     public void testRunTimeoutWithoutProgressExact() {
272         queue.sendRequest(mockRequest, mockCallback);
273
274         ticker.advance(AbstractClientConnection.DEFAULT_NO_PROGRESS_TIMEOUT_NANOS);
275
276         // Kaboom
277         queue.runTimer((ClientActorBehavior) mockBehavior);
278         assertNotNull(queue.poisoned());
279     }
280
281     @SuppressWarnings({ "rawtypes", "unchecked" })
282     public void testRunTimeoutWithoutProgressMore() {
283         queue.sendRequest(mockRequest, mockCallback);
284
285         ticker.advance(AbstractClientConnection.DEFAULT_NO_PROGRESS_TIMEOUT_NANOS + 1);
286
287         // Kaboom
288         queue.runTimer((ClientActorBehavior) mockBehavior);
289         assertNotNull(queue.poisoned());
290     }
291
292     @Test
293     public void testRunTimeoutEmptyWithoutProgressExact() {
294         ticker.advance(AbstractClientConnection.DEFAULT_NO_PROGRESS_TIMEOUT_NANOS);
295
296         // No problem
297         assertEquals(OptionalLong.empty(), queue.checkTimeout(ticker.read()));
298     }
299
300     @Test
301     public void testRunTimeoutEmptyWithoutProgressMore() {
302         ticker.advance(AbstractClientConnection.DEFAULT_NO_PROGRESS_TIMEOUT_NANOS + 1);
303
304         // No problem
305         assertEquals(OptionalLong.empty(), queue.checkTimeout(ticker.read()));
306     }
307
308     @Test
309     public void testCompleteEmpty() {
310         queue.receiveResponse(mockResponseEnvelope);
311         verifyNoMoreInteractions(mockCallback);
312     }
313
314     @Test
315     public void testCompleteSingle() {
316         setupBackend();
317
318         queue.sendRequest(mockRequest, mockCallback);
319
320         queue.receiveResponse(mockResponseEnvelope);
321         verify(mockCallback).accept(mockResponse);
322
323         queue.receiveResponse(mockResponseEnvelope);
324         verifyNoMoreInteractions(mockCallback);
325     }
326
327     @Test
328     public void testCompleteNull() {
329         setupBackend();
330
331         queue.sendRequest(mockRequest, mockCallback);
332
333         doNothing().when(mockCallback).accept(mockResponse);
334
335         queue.receiveResponse(mockResponseEnvelope);
336         verify(mockCallback).accept(mockResponse);
337     }
338
339     @Test
340     public void testProgressRecord() {
341         setupBackend();
342
343         queue.sendRequest(mockRequest, mockCallback);
344
345         ticker.advance(10);
346         queue.sendRequest(mockRequest2, mockCallback);
347         queue.receiveResponse(mockResponseEnvelope);
348
349         ticker.advance(AbstractClientConnection.DEFAULT_NO_PROGRESS_TIMEOUT_NANOS - 11);
350
351         assertNull(queue.checkTimeout(ticker.read()));
352     }
353
354     private void setupBackend() {
355         final ConnectingClientConnection<BackendInfo> connectingConn =
356                 new ConnectingClientConnection<>(mockContext, mockCookie, "test");
357         final ConnectedClientConnection<BackendInfo> connectedConn =
358                 new ConnectedClientConnection<>(connectingConn, mockBackendInfo);
359         queue.setForwarder(new SimpleReconnectForwarder(connectedConn));
360         queue = connectedConn;
361     }
362
363     private void assertTransmit(final Request<?, ?> expected, final long sequence) {
364         assertTrue(mockActor.msgAvailable());
365         assertRequestEquals(expected, sequence, mockActor.receiveOne(FiniteDuration.apply(5, TimeUnit.SECONDS)));
366     }
367
368     private static void assertRequestEquals(final Request<?, ?> expected, final long sequence, final Object obj) {
369         assertTrue(obj instanceof RequestEnvelope);
370
371         final RequestEnvelope actual = (RequestEnvelope) obj;
372         assertEquals(0, actual.getSessionId());
373         assertEquals(sequence, actual.getTxSequence());
374         assertSame(expected, actual.getMessage());
375     }
376 }