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;
17 import akka.actor.Props;
18 import akka.testkit.TestActorRef;
19 import org.junit.After;
20 import org.junit.Test;
21 import org.opendaylight.controller.cluster.raft.AbstractActorTest;
22 import org.opendaylight.controller.cluster.raft.TestActorFactory;
23 import org.opendaylight.controller.cluster.raft.base.messages.FollowerInitialSyncUpStatus;
24 import org.opendaylight.controller.cluster.raft.utils.MessageCollectorActor;
26 public class SyncStatusTrackerTest extends AbstractActorTest {
27 protected final TestActorFactory actorFactory = new TestActorFactory(getSystem());
29 private final TestActorRef<MessageCollectorActor> listener = actorFactory.createTestActor(
30 Props.create(MessageCollectorActor.class), actorFactory.generateActorId("listener"));
33 public void tearDown(){
38 public void testUpdate() throws Exception {
39 SyncStatusTracker tracker = new SyncStatusTracker(listener, "commit-tracker", 10);
41 // When leader-1 sends the first update message the listener should receive a syncStatus notification
42 // with status set to false
43 tracker.update("leader-1", 100, 99);
44 FollowerInitialSyncUpStatus status =
45 MessageCollectorActor.getFirstMatching(listener, FollowerInitialSyncUpStatus.class);
47 assertEquals(false, status.isInitialSyncDone());
48 MessageCollectorActor.clearMessages(listener);
50 // At a minimum the follower should have the commit index that the new leader sent it in the first message
51 // Also the commit index must be below the syncThreshold. If both conditions are met a new sync status
52 // message with status = true should be expected
53 tracker.update("leader-1", 105, 101);
55 status = MessageCollectorActor.getFirstMatching(listener, FollowerInitialSyncUpStatus.class);
57 assertEquals(true, status.isInitialSyncDone());
58 MessageCollectorActor.clearMessages(listener);
60 // If a subsequent message is received and if the difference between the followers commit index and
61 // the leaders commit index is below the syncThreshold then no status notification must be issues
62 tracker.update("leader-1", 108, 101);
64 status = MessageCollectorActor.getFirstMatching(listener, FollowerInitialSyncUpStatus.class);
66 assertNull("No status message should be received", status);
68 // If the follower falls behind the leader by more than the syncThreshold then the listener should
69 // receive a syncStatus notification with status = false
70 tracker.update("leader-1", 150, 101);
72 status = MessageCollectorActor.getFirstMatching(listener, FollowerInitialSyncUpStatus.class);
74 assertNotNull("No sync status message was received", status);
76 assertEquals(false, status.isInitialSyncDone());
77 MessageCollectorActor.clearMessages(listener);
79 // If the follower is not caught up yet it should not receive any further notification
80 tracker.update("leader-1", 150, 125);
82 status = MessageCollectorActor.getFirstMatching(listener, FollowerInitialSyncUpStatus.class);
84 assertNull("No status message should be received", status);
86 // Once the syncThreshold is met a new syncStatus notification should be issued
87 tracker.update("leader-1", 160, 155);
89 status = MessageCollectorActor.getFirstMatching(listener, FollowerInitialSyncUpStatus.class);
91 assertEquals(true, status.isInitialSyncDone());
92 MessageCollectorActor.clearMessages(listener);
94 // When a new leader starts sending update messages a new syncStatus notification should be immediately
95 // triggered with status = false
96 tracker.update("leader-2", 160, 155);
98 status = MessageCollectorActor.getFirstMatching(listener, FollowerInitialSyncUpStatus.class);
100 assertEquals(false, status.isInitialSyncDone());
101 MessageCollectorActor.clearMessages(listener);
103 // If an update is received from a new leader which is still below the minimum expected index then
104 // syncStatus should not be changed
105 tracker.update("leader-2", 160, 159);
107 status = MessageCollectorActor.getFirstMatching(listener, FollowerInitialSyncUpStatus.class);
109 assertNull("No status message should be received", status);
114 public void testConstructorActorShouldNotBeNull(){
116 new SyncStatusTracker(null, "commit-tracker", 10);
117 fail("A NullPointerException was expected");
118 } catch(NullPointerException e){
119 assertTrue("Invalid error message :" + e.getMessage(), e.getMessage().contains("actor "));
124 public void testConstructorIdShouldNotBeNull(){
126 new SyncStatusTracker(listener, null, 10);
127 fail("A NullPointerException was expected");
128 } catch(NullPointerException e){
129 assertTrue("Invalid error message :" + e.getMessage(), e.getMessage().contains("id "));
134 public void testConstructorSyncThresholdShouldNotBeNegative(){
136 new SyncStatusTracker(listener, "commit-tracker", -1);
137 fail("An IllegalArgumentException was expected");
138 } catch(IllegalArgumentException e){
139 assertTrue("Invalid error message :" + e.getMessage(), e.getMessage().contains("syncThreshold "));