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;
22 import java.util.HashMap;
24 import java.util.concurrent.ExecutionException;
25 import java.util.concurrent.Executors;
26 import java.util.concurrent.ScheduledExecutorService;
27 import java.util.concurrent.TimeUnit;
28 import java.util.concurrent.TimeoutException;
30 import org.junit.Test;
31 import org.junit.runner.RunWith;
32 import org.mockito.junit.MockitoJUnitRunner;
33 import org.mockito.stubbing.Answer;
34 import org.opendaylight.ovsdb.lib.impl.StalePassiveConnectionService;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
38 @RunWith(MockitoJUnitRunner.class)
39 public class StalePassiveConnectionServiceTest {
41 private static final Logger LOG = LoggerFactory.getLogger(StalePassiveConnectionService.class);
42 private static final String NOTIFIED = "NOTIFIED";
43 private Map<OvsdbClient, SettableFuture<String>> clientJobRunFutures = new HashMap<>();
44 private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
45 private StalePassiveConnectionService staleConnectionService
46 = new StalePassiveConnectionService((client) -> {
47 if (clientJobRunFutures.get(client) != null) {
48 clientJobRunFutures.get(client).set(NOTIFIED);
53 private OvsdbClient firstClient = createClient("127.0.0.1", 8001);
54 private OvsdbClient secondClient = createClient("127.0.0.1", 8002);
55 private OvsdbClient thirdClient = createClient("127.0.0.1", 8003);
58 public void testFirstClientAlive() throws Exception {
59 staleConnectionService.handleNewPassiveConnection(secondClient, Lists.newArrayList(firstClient));
60 clientShouldNotBeNotified(secondClient, "Second client should not be processed while first client is active");
61 staleConnectionService.clientDisconnected(firstClient);
62 clientShouldBeNotified(secondClient, "Second client should be notified after first client disconnect");
66 public void testSecondClientDisconnect() throws Exception {
67 staleConnectionService.handleNewPassiveConnection(secondClient, Lists.newArrayList(firstClient));
68 clientShouldNotBeNotified(secondClient, "Second client should not be processed while first client is active");
69 staleConnectionService.clientDisconnected(secondClient);
70 clientShouldNotBeNotified(secondClient, "Second client should not be processed post its disconnect");
71 clientShouldBeClearedFromPendingList(secondClient, "Second client should be cleared from pending state");
75 public void testFirstClientInActive() throws Exception {
77 when(firstClient.echo()).thenAnswer(delayedEchoFailedResponse(100, MILLISECONDS));
78 staleConnectionService.handleNewPassiveConnection(secondClient, Lists.newArrayList(firstClient));
79 clientShouldBeNotified(secondClient, "Second client should be notified after first client echo failed");
80 clientShouldBeClearedFromPendingList(secondClient, "Second client should be cleared from pending state");
84 public void testThreeClients() throws Exception {
85 staleConnectionService.handleNewPassiveConnection(secondClient, Lists.newArrayList(firstClient));
86 staleConnectionService.handleNewPassiveConnection(thirdClient, Lists.newArrayList(firstClient, secondClient));
87 clientShouldNotBeNotified(thirdClient, "Third client should not be processed while first client is there");
88 clientShouldNotBeNotified(secondClient, "Second client should not be processed while first client is there");
90 //disconnect first client
91 staleConnectionService.clientDisconnected(firstClient);
92 //now second client should be processed
93 clientShouldBeNotified(secondClient, "Second client should be notified after first client disconnected");
94 clientShouldNotBeNotified(thirdClient, "Third client should not be processed while second client is active");
96 //disconnect second client
97 staleConnectionService.clientDisconnected(secondClient);
98 //now third client should be processed
99 clientShouldBeNotified(secondClient, "Third client should be notified after second client also disconnected");
103 public void testDelayedFirstClientFailure() throws Exception {
106 second client arrived
107 first client echo success
108 keep second client on wait list
111 second client echo success, first client echo failed
112 process second client //catch the moment first clients echo failed it is considered inactive
114 second client disconnected
117 staleConnectionService.handleNewPassiveConnection(secondClient, Lists.newArrayList(firstClient));
119 when(firstClient.echo()).thenAnswer(delayedEchoFailedResponse(100, MILLISECONDS));
120 staleConnectionService.handleNewPassiveConnection(thirdClient, Lists.newArrayList(firstClient, secondClient));
121 //now second client should be processed
122 clientShouldBeNotified(secondClient, "Second client should be processed post first client echo failed");
123 clientShouldNotBeNotified(thirdClient, "Third client should not be processed while second client is active");
124 //disconnect second client
125 staleConnectionService.clientDisconnected(secondClient);
126 //now third client should be processed
127 clientShouldBeNotified(thirdClient, "Third client should be processed post second client disconnect also");
130 private void clientShouldBeClearedFromPendingList(OvsdbClient client, String msg) {
131 assertTrue(msg, !staleConnectionService.getPendingClients().containsKey(client));
134 private void clientShouldBeNotified(OvsdbClient client, String msg)
135 throws InterruptedException, ExecutionException, TimeoutException {
136 assertEquals(msg, clientJobRunFutures.get(client).get(1, SECONDS), NOTIFIED);
137 clientShouldBeClearedFromPendingList(client, "client should be cleared from pending state");
140 private void clientShouldNotBeNotified(OvsdbClient client, String msg)
141 throws ExecutionException, InterruptedException {
143 clientJobRunFutures.get(client).get(1, SECONDS);
145 } catch (TimeoutException e) {
146 LOG.trace("Expected exception");
150 private Answer<Object> delayedEchoResponse(int delay, TimeUnit timeUnit) {
151 return (mock) -> Futures.scheduleAsync(() -> Futures.immediateFuture(null),
152 delay, timeUnit, scheduledExecutorService);
155 private Answer<Object> delayedEchoFailedResponse(int delay, TimeUnit timeUnit) {
156 return (mock) -> Futures.scheduleAsync(() -> Futures.immediateFailedFuture(new RuntimeException("Echo failed")),
157 delay, timeUnit, scheduledExecutorService);
160 private OvsdbClient createClient(String ip, int port) {
161 OvsdbClient ovsdbClient = mock(OvsdbClient.class);
162 clientJobRunFutures.put(ovsdbClient, SettableFuture.create());
163 when(ovsdbClient.echo()).thenAnswer(delayedEchoResponse(100, MILLISECONDS));
164 OvsdbConnectionInfo connectionInfo = mock(OvsdbConnectionInfo.class);
165 when(connectionInfo.toString()).thenReturn("Host:" + ip + ",Port:" + port);
166 when(ovsdbClient.getConnectionInfo()).thenReturn(connectionInfo);