2 * Copyright (c) 2018 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.ovsdb.lib;
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;
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;
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;
36 @RunWith(MockitoJUnitRunner.class)
37 public class StalePassiveConnectionServiceTest {
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);
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);
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");
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");
73 public void testFirstClientInActive() throws Exception {
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");
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");
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");
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");
101 public void testDelayedFirstClientFailure() throws Exception {
104 second client arrived
105 first client echo success
106 keep second client on wait list
109 second client echo success, first client echo failed
110 process second client //catch the moment first clients echo failed it is considered inactive
112 second client disconnected
115 staleConnectionService.handleNewPassiveConnection(secondClient, Lists.newArrayList(firstClient));
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");
128 private void clientShouldBeClearedFromPendingList(OvsdbClient client, String msg) {
129 assertTrue(msg, !staleConnectionService.getPendingClients().containsKey(client));
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");
138 private void clientShouldNotBeNotified(OvsdbClient client, String msg)
139 throws ExecutionException, InterruptedException {
141 clientJobRunFutures.get(client).get(1, SECONDS);
143 } catch (TimeoutException e) {
144 LOG.trace("Expected exception");
148 private Answer<Object> delayedEchoResponse(int delay, TimeUnit timeUnit) {
149 return (mock) -> Futures.scheduleAsync(() -> Futures.immediateFuture(null),
150 delay, timeUnit, scheduledExecutorService);
153 private Answer<Object> delayedEchoFailedResponse(int delay, TimeUnit timeUnit) {
154 return (mock) -> Futures.scheduleAsync(() -> Futures.immediateFailedFuture(new RuntimeException("Echo failed")),
155 delay, timeUnit, scheduledExecutorService);
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);