2 * Copyright (c) 2015 Cisco Systems, Inc. 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
10 package org.opendaylight.controller.cluster.raft.behaviors;
12 import static org.junit.Assert.assertEquals;
13 import static org.junit.Assert.assertNotNull;
14 import static org.junit.Assert.assertNull;
15 import static org.junit.Assert.assertTrue;
16 import static org.junit.Assert.fail;
18 import akka.actor.Props;
19 import akka.testkit.TestActorRef;
20 import org.junit.After;
21 import org.junit.Test;
22 import org.opendaylight.controller.cluster.raft.AbstractActorTest;
23 import org.opendaylight.controller.cluster.raft.TestActorFactory;
24 import org.opendaylight.controller.cluster.raft.base.messages.FollowerInitialSyncUpStatus;
25 import org.opendaylight.controller.cluster.raft.utils.MessageCollectorActor;
27 public class SyncStatusTrackerTest extends AbstractActorTest {
28 protected final TestActorFactory actorFactory = new TestActorFactory(getSystem());
30 private final TestActorRef<MessageCollectorActor> listener = actorFactory.createTestActor(
31 Props.create(MessageCollectorActor.class), actorFactory.generateActorId("listener"));
34 public void tearDown() {
39 public void testUpdate() throws Exception {
40 SyncStatusTracker tracker = new SyncStatusTracker(listener, "commit-tracker", 10);
42 // When leader-1 sends the first update message the listener should receive a syncStatus notification
43 // with status set to false
44 tracker.update("leader-1", 100, 99);
45 FollowerInitialSyncUpStatus status =
46 MessageCollectorActor.getFirstMatching(listener, FollowerInitialSyncUpStatus.class);
48 assertEquals(false, status.isInitialSyncDone());
49 MessageCollectorActor.clearMessages(listener);
51 // At a minimum the follower should have the commit index that the new leader sent it in the first message
52 // Also the commit index must be below the syncThreshold. If both conditions are met a new sync status
53 // message with status = true should be expected
54 tracker.update("leader-1", 105, 101);
56 status = MessageCollectorActor.getFirstMatching(listener, FollowerInitialSyncUpStatus.class);
58 assertEquals(true, status.isInitialSyncDone());
59 MessageCollectorActor.clearMessages(listener);
61 // If a subsequent message is received and if the difference between the followers commit index and
62 // the leaders commit index is below the syncThreshold then no status notification must be issues
63 tracker.update("leader-1", 108, 101);
65 status = MessageCollectorActor.getFirstMatching(listener, FollowerInitialSyncUpStatus.class);
67 assertNull("No status message should be received", status);
69 // If the follower falls behind the leader by more than the syncThreshold then the listener should
70 // receive a syncStatus notification with status = false
71 tracker.update("leader-1", 150, 101);
73 status = MessageCollectorActor.getFirstMatching(listener, FollowerInitialSyncUpStatus.class);
75 assertNotNull("No sync status message was received", status);
77 assertEquals(false, status.isInitialSyncDone());
78 MessageCollectorActor.clearMessages(listener);
80 // If the follower is not caught up yet it should not receive any further notification
81 tracker.update("leader-1", 150, 125);
83 status = MessageCollectorActor.getFirstMatching(listener, FollowerInitialSyncUpStatus.class);
85 assertNull("No status message should be received", status);
87 // Once the syncThreshold is met a new syncStatus notification should be issued
88 tracker.update("leader-1", 160, 155);
90 status = MessageCollectorActor.getFirstMatching(listener, FollowerInitialSyncUpStatus.class);
92 assertEquals(true, status.isInitialSyncDone());
93 MessageCollectorActor.clearMessages(listener);
95 // When a new leader starts sending update messages a new syncStatus notification should be immediately
96 // triggered with status = false
97 tracker.update("leader-2", 160, 155);
99 status = MessageCollectorActor.getFirstMatching(listener, FollowerInitialSyncUpStatus.class);
101 assertEquals(false, status.isInitialSyncDone());
102 MessageCollectorActor.clearMessages(listener);
104 // If an update is received from a new leader which is still below the minimum expected index then
105 // syncStatus should not be changed
106 tracker.update("leader-2", 160, 159);
108 status = MessageCollectorActor.getFirstMatching(listener, FollowerInitialSyncUpStatus.class);
110 assertNull("No status message should be received", status);
115 public void testConstructorActorShouldNotBeNull() {
117 new SyncStatusTracker(null, "commit-tracker", 10);
118 fail("A NullPointerException was expected");
119 } catch (NullPointerException e) {
120 assertTrue("Invalid error message :" + e.getMessage(), e.getMessage().contains("actor "));
125 public void testConstructorIdShouldNotBeNull() {
127 new SyncStatusTracker(listener, null, 10);
128 fail("A NullPointerException was expected");
129 } catch (NullPointerException e) {
130 assertTrue("Invalid error message :" + e.getMessage(), e.getMessage().contains("id "));
135 public void testConstructorSyncThresholdShouldNotBeNegative() {
137 new SyncStatusTracker(listener, "commit-tracker", -1);
138 fail("An IllegalArgumentException was expected");
139 } catch (IllegalArgumentException e) {
140 assertTrue("Invalid error message :" + e.getMessage(), e.getMessage().contains("syncThreshold "));