Update MRI projects for Aluminium
[ovsdb.git] / library / impl / src / test / java / org / opendaylight / ovsdb / lib / StalePassiveConnectionServiceTest.java
1 /*
2  * Copyright (c) 2018 Ericsson India Global Services Pvt Ltd. 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.ovsdb.lib;
9
10 import static java.util.concurrent.TimeUnit.MILLISECONDS;
11 import static java.util.concurrent.TimeUnit.SECONDS;
12 import static org.junit.Assert.assertEquals;
13 import static org.junit.Assert.assertTrue;
14 import static org.junit.Assert.fail;
15 import static org.mockito.Mockito.mock;
16 import static org.mockito.Mockito.when;
17
18 import com.google.common.collect.Lists;
19 import com.google.common.util.concurrent.Futures;
20 import com.google.common.util.concurrent.SettableFuture;
21 import java.util.HashMap;
22 import java.util.Map;
23 import java.util.concurrent.ExecutionException;
24 import java.util.concurrent.Executors;
25 import java.util.concurrent.ScheduledExecutorService;
26 import java.util.concurrent.TimeUnit;
27 import java.util.concurrent.TimeoutException;
28 import org.junit.Test;
29 import org.junit.runner.RunWith;
30 import org.mockito.junit.MockitoJUnitRunner;
31 import org.mockito.stubbing.Answer;
32 import org.opendaylight.ovsdb.lib.impl.StalePassiveConnectionService;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 @RunWith(MockitoJUnitRunner.class)
37 public class StalePassiveConnectionServiceTest {
38
39     private static final Logger LOG = LoggerFactory.getLogger(StalePassiveConnectionService.class);
40     private static final String NOTIFIED = "NOTIFIED";
41     private Map<OvsdbClient, SettableFuture<String>> clientJobRunFutures = new HashMap<>();
42     private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
43     private StalePassiveConnectionService staleConnectionService
44             = new StalePassiveConnectionService((client) -> {
45                 if (clientJobRunFutures.get(client) != null) {
46                     clientJobRunFutures.get(client).set(NOTIFIED);
47                 }
48                 return null;
49             });
50
51     private OvsdbClient firstClient = createClient("127.0.0.1", 8001);
52     private OvsdbClient secondClient = createClient("127.0.0.1", 8002);
53     private OvsdbClient thirdClient = createClient("127.0.0.1", 8003);
54
55     @Test
56     public void testFirstClientAlive() throws Exception {
57         staleConnectionService.handleNewPassiveConnection(secondClient, Lists.newArrayList(firstClient));
58         clientShouldNotBeNotified(secondClient, "Second client should not be processed while first client is active");
59         staleConnectionService.clientDisconnected(firstClient);
60         clientShouldBeNotified(secondClient, "Second client should be notified after first client disconnect");
61     }
62
63     @Test
64     public void testSecondClientDisconnect() throws Exception {
65         staleConnectionService.handleNewPassiveConnection(secondClient, Lists.newArrayList(firstClient));
66         clientShouldNotBeNotified(secondClient, "Second client should not be processed while first client is active");
67         staleConnectionService.clientDisconnected(secondClient);
68         clientShouldNotBeNotified(secondClient, "Second client should not be processed post its disconnect");
69         clientShouldBeClearedFromPendingList(secondClient, "Second client should be cleared from pending state");
70     }
71
72     @Test
73     public void testFirstClientInActive() throws Exception {
74         firstClient.echo();
75         when(firstClient.echo()).thenAnswer(delayedEchoFailedResponse(100, MILLISECONDS));
76         staleConnectionService.handleNewPassiveConnection(secondClient, Lists.newArrayList(firstClient));
77         clientShouldBeNotified(secondClient, "Second client should be notified after first client echo failed");
78         clientShouldBeClearedFromPendingList(secondClient, "Second client should be cleared from pending state");
79     }
80
81     @Test
82     public void testThreeClients() throws Exception {
83         staleConnectionService.handleNewPassiveConnection(secondClient, Lists.newArrayList(firstClient));
84         staleConnectionService.handleNewPassiveConnection(thirdClient, Lists.newArrayList(firstClient, secondClient));
85         clientShouldNotBeNotified(thirdClient, "Third client should not be processed while first client is there");
86         clientShouldNotBeNotified(secondClient, "Second client should not be processed while first client is there");
87
88         //disconnect first client
89         staleConnectionService.clientDisconnected(firstClient);
90         //now second client should be processed
91         clientShouldBeNotified(secondClient, "Second client should be notified after first client disconnected");
92         clientShouldNotBeNotified(thirdClient, "Third client should not be processed while second client is active");
93
94         //disconnect second client
95         staleConnectionService.clientDisconnected(secondClient);
96         //now third client should be processed
97         clientShouldBeNotified(secondClient, "Third client should be notified after second client also disconnected");
98     }
99
100     @Test
101     public void testDelayedFirstClientFailure() throws Exception {
102         /*
103         first client arrived
104         second client arrived
105         first client echo success
106         keep second client on wait list
107
108         third client arrived
109         second client echo success, first client echo failed
110         process second client //catch the moment first clients echo failed it is considered inactive
111
112         second client disconnected
113         process third client
114          */
115         staleConnectionService.handleNewPassiveConnection(secondClient, Lists.newArrayList(firstClient));
116
117         when(firstClient.echo()).thenAnswer(delayedEchoFailedResponse(100, MILLISECONDS));
118         staleConnectionService.handleNewPassiveConnection(thirdClient, Lists.newArrayList(firstClient, secondClient));
119         //now second client should be processed
120         clientShouldBeNotified(secondClient, "Second client should be processed post first client echo failed");
121         clientShouldNotBeNotified(thirdClient, "Third client should not be processed while second client is active");
122         //disconnect second client
123         staleConnectionService.clientDisconnected(secondClient);
124         //now third client should be processed
125         clientShouldBeNotified(thirdClient, "Third client should be processed post second client disconnect also");
126     }
127
128     private void clientShouldBeClearedFromPendingList(OvsdbClient client, String msg) {
129         assertTrue(msg, !staleConnectionService.getPendingClients().containsKey(client));
130     }
131
132     private void clientShouldBeNotified(OvsdbClient client, String msg)
133             throws InterruptedException, ExecutionException, TimeoutException {
134         assertEquals(msg, clientJobRunFutures.get(client).get(1, SECONDS), NOTIFIED);
135         clientShouldBeClearedFromPendingList(client, "client should be cleared from pending state");
136     }
137
138     private void clientShouldNotBeNotified(OvsdbClient client, String msg)
139             throws ExecutionException, InterruptedException {
140         try {
141             clientJobRunFutures.get(client).get(1, SECONDS);
142             fail(msg);
143         } catch (TimeoutException e) {
144             LOG.trace("Expected exception");
145         }
146     }
147
148     private Answer<Object> delayedEchoResponse(int delay, TimeUnit timeUnit) {
149         return (mock) -> Futures.scheduleAsync(() -> Futures.immediateFuture(null),
150                 delay, timeUnit, scheduledExecutorService);
151     }
152
153     private Answer<Object> delayedEchoFailedResponse(int delay, TimeUnit timeUnit) {
154         return (mock) -> Futures.scheduleAsync(() -> Futures.immediateFailedFuture(new RuntimeException("Echo failed")),
155                 delay, timeUnit, scheduledExecutorService);
156     }
157
158     private OvsdbClient createClient(String ip, int port) {
159         OvsdbClient ovsdbClient = mock(OvsdbClient.class);
160         clientJobRunFutures.put(ovsdbClient, SettableFuture.create());
161         when(ovsdbClient.echo()).thenAnswer(delayedEchoResponse(100, MILLISECONDS));
162         OvsdbConnectionInfo connectionInfo = mock(OvsdbConnectionInfo.class);
163         when(connectionInfo.toString()).thenReturn("Host:" + ip + ",Port:" + port);
164         when(ovsdbClient.getConnectionInfo()).thenReturn(connectionInfo);
165         return ovsdbClient;
166     }
167 }