BUG-5280: separate request sequence and transmit sequence
[controller.git] / opendaylight / md-sal / cds-access-client / src / test / java / org / opendaylight / controller / cluster / access / client / SequencedQueueEntryTest.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.assertNull;
13 import static org.junit.Assert.assertSame;
14 import static org.junit.Assert.assertTrue;
15 import static org.mockito.Matchers.any;
16 import static org.mockito.Mockito.doReturn;
17 import static org.mockito.Mockito.verify;
18 import akka.actor.ActorRef;
19 import akka.actor.ActorSystem;
20 import akka.testkit.TestProbe;
21 import java.util.concurrent.ThreadLocalRandom;
22 import java.util.concurrent.TimeUnit;
23 import org.junit.After;
24 import org.junit.AfterClass;
25 import org.junit.Before;
26 import org.junit.BeforeClass;
27 import org.junit.Test;
28 import org.mockito.ArgumentCaptor;
29 import org.mockito.Mock;
30 import org.mockito.MockitoAnnotations;
31 import org.opendaylight.controller.cluster.access.ABIVersion;
32 import org.opendaylight.controller.cluster.access.concepts.AbstractRequestFailureProxy;
33 import org.opendaylight.controller.cluster.access.concepts.AbstractRequestProxy;
34 import org.opendaylight.controller.cluster.access.concepts.Request;
35 import org.opendaylight.controller.cluster.access.concepts.RequestEnvelope;
36 import org.opendaylight.controller.cluster.access.concepts.RequestException;
37 import org.opendaylight.controller.cluster.access.concepts.RequestFailure;
38 import org.opendaylight.controller.cluster.access.concepts.Response;
39 import org.opendaylight.controller.cluster.common.actor.TestTicker;
40 import org.opendaylight.yangtools.concepts.WritableIdentifier;
41 import scala.concurrent.duration.Duration;
42
43 /**
44  * Test suite covering logic contained in {@link SequencedQueueEntry}.
45  *
46  * @author Robert Varga
47  */
48 public class SequencedQueueEntryTest {
49     private static class MockFailure extends RequestFailure<WritableIdentifier, MockFailure> {
50         private static final long serialVersionUID = 1L;
51
52         MockFailure(final WritableIdentifier target, final RequestException cause) {
53             super(target, 0, cause);
54         }
55
56         @Override
57         protected AbstractRequestFailureProxy<WritableIdentifier, MockFailure> externalizableProxy(final ABIVersion version) {
58             return null;
59         }
60
61         @Override
62         protected MockFailure cloneAsVersion(final ABIVersion version) {
63             return this;
64         }
65     }
66
67     private static class MockRequest extends Request<WritableIdentifier, MockRequest> {
68         private static final long serialVersionUID = 1L;
69
70         MockRequest(final WritableIdentifier target, final ActorRef replyTo) {
71             super(target, 0, replyTo);
72         }
73
74         @Override
75         public RequestFailure<WritableIdentifier, ?> toRequestFailure(final RequestException cause) {
76             return new MockFailure(getTarget(), cause);
77         }
78
79         @Override
80         protected AbstractRequestProxy<WritableIdentifier, MockRequest> externalizableProxy(final ABIVersion version) {
81             return null;
82         }
83
84         @Override
85         protected MockRequest cloneAsVersion(final ABIVersion version) {
86             return this;
87         }
88     };
89
90     @Mock
91     private ActorRef mockReplyTo;
92     @Mock
93     private WritableIdentifier mockIdentifier;
94     @Mock
95     private RequestException mockCause;
96     @Mock
97     private RequestCallback mockCallback;
98     @Mock
99     private ClientActorBehavior mockBehavior;
100
101     private TestTicker ticker;
102     private BackendInfo mockBackendInfo;
103     private Request<WritableIdentifier, ?> mockRequest;
104     private Response<WritableIdentifier, ?> mockResponse;
105
106     private static ActorSystem actorSystem;
107     private TestProbe mockActor;
108
109     private SequencedQueueEntry entry;
110
111     @BeforeClass
112     public static void setupClass() {
113         actorSystem = ActorSystem.apply();
114     }
115
116     @AfterClass
117     public static void teardownClass() {
118         actorSystem.terminate();
119     }
120
121     @Before
122     public void setup() {
123         MockitoAnnotations.initMocks(this);
124
125         doReturn(mockBehavior).when(mockCallback).complete(any(MockFailure.class));
126
127         ticker = new TestTicker();
128         ticker.increment(ThreadLocalRandom.current().nextLong());
129
130         mockActor = TestProbe.apply(actorSystem);
131         mockBackendInfo = new BackendInfo(mockActor.ref(), 0, ABIVersion.current(), 5);
132         mockRequest = new MockRequest(mockIdentifier, mockReplyTo);
133         mockResponse = mockRequest.toRequestFailure(mockCause);
134
135         entry = new SequencedQueueEntry(mockRequest, mockCallback, ticker.read());
136     }
137
138     @After
139     public void teardown() {
140         actorSystem.stop(mockActor.ref());
141     }
142
143     @Test
144     public void testGetTxDetails() {
145         assertNull(entry.getTxDetails());
146         entry.retransmit(mockBackendInfo, 0, ticker.read());
147         assertEquals(0, entry.getTxDetails().getTxSequence());
148         entry.retransmit(mockBackendInfo, 1, ticker.read());
149         assertEquals(1, entry.getTxDetails().getTxSequence());
150         entry.retransmit(mockBackendInfo, 3, ticker.read());
151         assertEquals(3, entry.getTxDetails().getTxSequence());
152     }
153
154     @Test
155     public void testComplete() {
156         entry.complete(mockResponse);
157         verify(mockCallback).complete(mockResponse);
158     }
159
160     @Test
161     public void testPoison() {
162         entry.poison(mockCause);
163
164         final ArgumentCaptor<MockFailure> captor = ArgumentCaptor.forClass(MockFailure.class);
165         verify(mockCallback).complete(captor.capture());
166         assertSame(mockCause, captor.getValue().getCause());
167     }
168
169     @Test
170     public void testIsTimedOut() {
171         assertTrue(entry.isTimedOut(ticker.read(), 0));
172         assertFalse(entry.isTimedOut(ticker.read(), 1));
173
174         entry.retransmit(mockBackendInfo, 0, ticker.read());
175         assertTrue(entry.isTimedOut(ticker.read(), 0));
176         ticker.increment(10);
177         assertTrue(entry.isTimedOut(ticker.read(), 10));
178         assertFalse(entry.isTimedOut(ticker.read(), 20));
179
180         entry.retransmit(mockBackendInfo, 1, ticker.read());
181         assertTrue(entry.isTimedOut(ticker.read(), 0));
182         ticker.increment(10);
183         assertTrue(entry.isTimedOut(ticker.read(), 10));
184         assertFalse(entry.isTimedOut(ticker.read(), 11));
185     }
186
187     @Test
188     public void testRetransmit() {
189         assertFalse(mockActor.msgAvailable());
190         entry.retransmit(mockBackendInfo, 0, ticker.read());
191
192         assertTrue(mockActor.msgAvailable());
193         assertRequestEquals(mockRequest, mockActor.receiveOne(Duration.apply(5, TimeUnit.SECONDS)));
194     }
195
196      private static void assertRequestEquals(final Request<?, ?> expected, final Object o) {
197          assertTrue(o instanceof RequestEnvelope);
198
199          final RequestEnvelope actual = (RequestEnvelope) o;
200          assertEquals(0, actual.getSessionId());
201          assertEquals(0, actual.getTxSequence());
202          assertEquals(expected.getTarget(), actual.getMessage().getTarget());
203     }
204 }