271250c16c055d0e26d00dc42395ddd67cc2f437
[controller.git] / opendaylight / md-sal / sal-akka-raft / src / test / java / org / opendaylight / controller / cluster / raft / behaviors / SyncStatusTrackerTest.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. 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
9
10 package org.opendaylight.controller.cluster.raft.behaviors;
11
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
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;
26
27 public class SyncStatusTrackerTest extends AbstractActorTest {
28     protected final TestActorFactory actorFactory = new TestActorFactory(getSystem());
29
30     private final TestActorRef<MessageCollectorActor> listener = actorFactory.createTestActor(
31             Props.create(MessageCollectorActor.class), actorFactory.generateActorId("listener"));
32
33     @After
34     public void tearDown() {
35         actorFactory.close();
36     }
37
38     @Test
39     public void testUpdate() throws Exception {
40         SyncStatusTracker tracker = new SyncStatusTracker(listener, "commit-tracker", 10);
41
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);
47
48         assertEquals(false, status.isInitialSyncDone());
49         MessageCollectorActor.clearMessages(listener);
50
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);
55
56         status = MessageCollectorActor.getFirstMatching(listener, FollowerInitialSyncUpStatus.class);
57
58         assertEquals(true, status.isInitialSyncDone());
59         MessageCollectorActor.clearMessages(listener);
60
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);
64
65         status = MessageCollectorActor.getFirstMatching(listener, FollowerInitialSyncUpStatus.class);
66
67         assertNull("No status message should be received", status);
68
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);
72
73         status = MessageCollectorActor.getFirstMatching(listener, FollowerInitialSyncUpStatus.class);
74
75         assertNotNull("No sync status message was received", status);
76
77         assertEquals(false, status.isInitialSyncDone());
78         MessageCollectorActor.clearMessages(listener);
79
80         // If the follower is not caught up yet it should not receive any further notification
81         tracker.update("leader-1", 150, 125);
82
83         status = MessageCollectorActor.getFirstMatching(listener, FollowerInitialSyncUpStatus.class);
84
85         assertNull("No status message should be received", status);
86
87         // Once the syncThreshold is met a new syncStatus notification should be issued
88         tracker.update("leader-1", 160, 155);
89
90         status = MessageCollectorActor.getFirstMatching(listener, FollowerInitialSyncUpStatus.class);
91
92         assertEquals(true, status.isInitialSyncDone());
93         MessageCollectorActor.clearMessages(listener);
94
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);
98
99         status = MessageCollectorActor.getFirstMatching(listener, FollowerInitialSyncUpStatus.class);
100
101         assertEquals(false, status.isInitialSyncDone());
102         MessageCollectorActor.clearMessages(listener);
103
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);
107
108         status = MessageCollectorActor.getFirstMatching(listener, FollowerInitialSyncUpStatus.class);
109
110         assertNull("No status message should be received", status);
111
112     }
113
114     @Test
115     public void testConstructorActorShouldNotBeNull() {
116         try {
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 "));
121         }
122     }
123
124     @Test
125     public void testConstructorIdShouldNotBeNull() {
126         try {
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 "));
131         }
132     }
133
134     @Test
135     public void testConstructorSyncThresholdShouldNotBeNegative() {
136         try {
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 "));
141         }
142     }
143 }