blob: 4bd6d7fdc71305954747efb86ab16ecb62162e4c [file] [log] [blame]
Madan Jampani5e5b3d62016-02-01 16:03:33 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
Madan Jampani5e5b3d62016-02-01 16:03:33 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.store.primitives.resources.impl;
17
18import java.util.LinkedList;
19import java.util.Queue;
20import java.util.concurrent.CompletableFuture;
21import java.util.function.Consumer;
22
Jordan Halterman2bf177c2017-06-29 01:49:08 -070023import io.atomix.protocols.raft.proxy.RaftProxy;
24import io.atomix.protocols.raft.service.RaftService;
25import org.junit.Test;
26import org.onosproject.cluster.Leadership;
27import org.onosproject.cluster.NodeId;
28import org.onosproject.event.Change;
29
Aaron Kruglikov6afeccd2016-07-05 13:17:01 -070030import static org.junit.Assert.assertEquals;
31import static org.junit.Assert.assertFalse;
32import static org.junit.Assert.assertTrue;
Madan Jampani5e5b3d62016-02-01 16:03:33 -080033
34/**
35 * Unit tests for {@link AtomixLeaderElector}.
36 */
Jordan Halterman2bf177c2017-06-29 01:49:08 -070037public class AtomixLeaderElectorTest extends AtomixTestBase<AtomixLeaderElector> {
Madan Jampani5e5b3d62016-02-01 16:03:33 -080038
39 NodeId node1 = new NodeId("node1");
40 NodeId node2 = new NodeId("node2");
41 NodeId node3 = new NodeId("node3");
42
Jordan Halterman2bf177c2017-06-29 01:49:08 -070043 @Override
44 protected RaftService createService() {
45 return new AtomixLeaderElectorService();
Aaron Kruglikovb5a41e52016-06-23 15:37:41 -070046 }
47
Madan Jampani5e5b3d62016-02-01 16:03:33 -080048 @Override
Jordan Halterman2bf177c2017-06-29 01:49:08 -070049 protected AtomixLeaderElector createPrimitive(RaftProxy proxy) {
50 return new AtomixLeaderElector(proxy);
Madan Jampani5e5b3d62016-02-01 16:03:33 -080051 }
52
53 @Test
54 public void testRun() throws Throwable {
Aaron Kruglikovc38dc7f2016-07-19 10:00:11 -070055 leaderElectorRunTests();
Madan Jampani5e5b3d62016-02-01 16:03:33 -080056 }
57
Aaron Kruglikovc38dc7f2016-07-19 10:00:11 -070058 private void leaderElectorRunTests() throws Throwable {
Jordan Halterman2bf177c2017-06-29 01:49:08 -070059 AtomixLeaderElector elector1 = newPrimitive("test-elector-run");
Madan Jampani5e5b3d62016-02-01 16:03:33 -080060 elector1.run("foo", node1).thenAccept(result -> {
61 assertEquals(node1, result.leaderNodeId());
62 assertEquals(1, result.leader().term());
63 assertEquals(1, result.candidates().size());
64 assertEquals(node1, result.candidates().get(0));
65 }).join();
Jordan Halterman2bf177c2017-06-29 01:49:08 -070066
67 AtomixLeaderElector elector2 = newPrimitive("test-elector-run");
Madan Jampani5e5b3d62016-02-01 16:03:33 -080068 elector2.run("foo", node2).thenAccept(result -> {
69 assertEquals(node1, result.leaderNodeId());
70 assertEquals(1, result.leader().term());
71 assertEquals(2, result.candidates().size());
72 assertEquals(node1, result.candidates().get(0));
73 assertEquals(node2, result.candidates().get(1));
74 }).join();
75 }
76
77 @Test
78 public void testWithdraw() throws Throwable {
Aaron Kruglikovc38dc7f2016-07-19 10:00:11 -070079 leaderElectorWithdrawTests();
Madan Jampani5e5b3d62016-02-01 16:03:33 -080080 }
81
Aaron Kruglikovc38dc7f2016-07-19 10:00:11 -070082 private void leaderElectorWithdrawTests() throws Throwable {
Jordan Halterman2bf177c2017-06-29 01:49:08 -070083 AtomixLeaderElector elector1 = newPrimitive("test-elector-withdraw");
Madan Jampani5e5b3d62016-02-01 16:03:33 -080084 elector1.run("foo", node1).join();
Jordan Halterman2bf177c2017-06-29 01:49:08 -070085 AtomixLeaderElector elector2 = newPrimitive("test-elector-withdraw");
Madan Jampani5e5b3d62016-02-01 16:03:33 -080086 elector2.run("foo", node2).join();
87
88 LeaderEventListener listener1 = new LeaderEventListener();
89 elector1.addChangeListener(listener1).join();
90
91 LeaderEventListener listener2 = new LeaderEventListener();
92 elector2.addChangeListener(listener2).join();
93
94 elector1.withdraw("foo").join();
95
96 listener1.nextEvent().thenAccept(result -> {
97 assertEquals(node2, result.newValue().leaderNodeId());
98 assertEquals(2, result.newValue().leader().term());
99 assertEquals(1, result.newValue().candidates().size());
100 assertEquals(node2, result.newValue().candidates().get(0));
101 }).join();
102
103 listener2.nextEvent().thenAccept(result -> {
104 assertEquals(node2, result.newValue().leaderNodeId());
105 assertEquals(2, result.newValue().leader().term());
106 assertEquals(1, result.newValue().candidates().size());
107 assertEquals(node2, result.newValue().candidates().get(0));
108 }).join();
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700109
110 Leadership leadership1 = elector1.getLeadership("foo").join();
111 assertEquals(node2, leadership1.leader().nodeId());
112 assertEquals(1, leadership1.candidates().size());
113
114 Leadership leadership2 = elector2.getLeadership("foo").join();
115 assertEquals(node2, leadership2.leader().nodeId());
116 assertEquals(1, leadership2.candidates().size());
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800117 }
118
119 @Test
120 public void testAnoint() throws Throwable {
Aaron Kruglikovc38dc7f2016-07-19 10:00:11 -0700121 leaderElectorAnointTests();
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800122 }
123
Aaron Kruglikovc38dc7f2016-07-19 10:00:11 -0700124 private void leaderElectorAnointTests() throws Throwable {
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700125 AtomixLeaderElector elector1 = newPrimitive("test-elector-anoint");
126 AtomixLeaderElector elector2 = newPrimitive("test-elector-anoint");
127 AtomixLeaderElector elector3 = newPrimitive("test-elector-anoint");
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800128 elector1.run("foo", node1).join();
129 elector2.run("foo", node2).join();
130
131 LeaderEventListener listener1 = new LeaderEventListener();
132 elector1.addChangeListener(listener1).join();
133 LeaderEventListener listener2 = new LeaderEventListener();
134 elector2.addChangeListener(listener2);
135 LeaderEventListener listener3 = new LeaderEventListener();
136 elector3.addChangeListener(listener3).join();
137
138 elector3.anoint("foo", node3).thenAccept(result -> {
139 assertFalse(result);
140 }).join();
141 assertFalse(listener1.hasEvent());
142 assertFalse(listener2.hasEvent());
143 assertFalse(listener3.hasEvent());
144
145 elector3.anoint("foo", node2).thenAccept(result -> {
146 assertTrue(result);
147 }).join();
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800148
149 listener1.nextEvent().thenAccept(result -> {
150 assertEquals(node2, result.newValue().leaderNodeId());
151 assertEquals(2, result.newValue().candidates().size());
152 assertEquals(node1, result.newValue().candidates().get(0));
153 assertEquals(node2, result.newValue().candidates().get(1));
154 }).join();
155 listener2.nextEvent().thenAccept(result -> {
156 assertEquals(node2, result.newValue().leaderNodeId());
157 assertEquals(2, result.newValue().candidates().size());
158 assertEquals(node1, result.newValue().candidates().get(0));
159 assertEquals(node2, result.newValue().candidates().get(1));
160 }).join();
161 listener3.nextEvent().thenAccept(result -> {
162 assertEquals(node2, result.newValue().leaderNodeId());
163 assertEquals(2, result.newValue().candidates().size());
164 assertEquals(node1, result.newValue().candidates().get(0));
165 assertEquals(node2, result.newValue().candidates().get(1));
166 }).join();
167 }
168
169 @Test
Madan Jampani0c0cdc62016-02-22 16:54:06 -0800170 public void testPromote() throws Throwable {
Aaron Kruglikovc38dc7f2016-07-19 10:00:11 -0700171 leaderElectorPromoteTests();
Madan Jampani0c0cdc62016-02-22 16:54:06 -0800172 }
173
Aaron Kruglikovc38dc7f2016-07-19 10:00:11 -0700174 private void leaderElectorPromoteTests() throws Throwable {
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700175 AtomixLeaderElector elector1 = newPrimitive("test-elector-promote");
176 AtomixLeaderElector elector2 = newPrimitive("test-elector-promote");
177 AtomixLeaderElector elector3 = newPrimitive("test-elector-promote");
Madan Jampani0c0cdc62016-02-22 16:54:06 -0800178 elector1.run("foo", node1).join();
179 elector2.run("foo", node2).join();
180
181 LeaderEventListener listener1 = new LeaderEventListener();
182 elector1.addChangeListener(listener1).join();
183 LeaderEventListener listener2 = new LeaderEventListener();
184 elector2.addChangeListener(listener2).join();
185 LeaderEventListener listener3 = new LeaderEventListener();
186 elector3.addChangeListener(listener3).join();
187
188 elector3.promote("foo", node3).thenAccept(result -> {
189 assertFalse(result);
190 }).join();
191
192 assertFalse(listener1.hasEvent());
193 assertFalse(listener2.hasEvent());
194 assertFalse(listener3.hasEvent());
195
196 elector3.run("foo", node3).join();
197
Madan Jampani630e7ac2016-05-31 11:34:05 -0700198 listener1.nextEvent().thenAccept(result -> {
199 assertEquals(node3, result.newValue().candidates().get(2));
200 }).join();
201 listener2.nextEvent().thenAccept(result -> {
202 assertEquals(node3, result.newValue().candidates().get(2));
203 }).join();
204 listener3.nextEvent().thenAccept(result -> {
205 assertEquals(node3, result.newValue().candidates().get(2));
206 }).join();
Madan Jampani0c0cdc62016-02-22 16:54:06 -0800207
208 elector3.promote("foo", node3).thenAccept(result -> {
209 assertTrue(result);
210 }).join();
211
212 listener1.nextEvent().thenAccept(result -> {
213 assertEquals(node3, result.newValue().candidates().get(0));
214 }).join();
215 listener2.nextEvent().thenAccept(result -> {
216 assertEquals(node3, result.newValue().candidates().get(0));
217 }).join();
218 listener3.nextEvent().thenAccept(result -> {
219 assertEquals(node3, result.newValue().candidates().get(0));
220 }).join();
221 }
222
223 @Test
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800224 public void testLeaderSessionClose() throws Throwable {
Aaron Kruglikovc38dc7f2016-07-19 10:00:11 -0700225 leaderElectorLeaderSessionCloseTests();
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800226 }
227
Aaron Kruglikovc38dc7f2016-07-19 10:00:11 -0700228 private void leaderElectorLeaderSessionCloseTests() throws Throwable {
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700229 AtomixLeaderElector elector1 = newPrimitive("test-elector-leader-session-close");
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800230 elector1.run("foo", node1).join();
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700231 AtomixLeaderElector elector2 = newPrimitive("test-elector-leader-session-close");
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800232 LeaderEventListener listener = new LeaderEventListener();
233 elector2.run("foo", node2).join();
234 elector2.addChangeListener(listener).join();
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700235 elector1.proxy.close();
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800236 listener.nextEvent().thenAccept(result -> {
237 assertEquals(node2, result.newValue().leaderNodeId());
238 assertEquals(1, result.newValue().candidates().size());
239 assertEquals(node2, result.newValue().candidates().get(0));
240 }).join();
241 }
242
243 @Test
244 public void testNonLeaderSessionClose() throws Throwable {
Aaron Kruglikovc38dc7f2016-07-19 10:00:11 -0700245 leaderElectorNonLeaderSessionCloseTests();
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800246 }
247
Aaron Kruglikovc38dc7f2016-07-19 10:00:11 -0700248 private void leaderElectorNonLeaderSessionCloseTests() throws Throwable {
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700249 AtomixLeaderElector elector1 = newPrimitive("test-elector-non-leader-session-close");
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800250 elector1.run("foo", node1).join();
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700251 AtomixLeaderElector elector2 = newPrimitive("test-elector-non-leader-session-close");
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800252 LeaderEventListener listener = new LeaderEventListener();
253 elector2.run("foo", node2).join();
254 elector1.addChangeListener(listener).join();
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700255 elector2.proxy.close().join();
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800256 listener.nextEvent().thenAccept(result -> {
257 assertEquals(node1, result.newValue().leaderNodeId());
258 assertEquals(1, result.newValue().candidates().size());
259 assertEquals(node1, result.newValue().candidates().get(0));
260 }).join();
261 }
262
263 @Test
264 public void testQueries() throws Throwable {
Aaron Kruglikovc38dc7f2016-07-19 10:00:11 -0700265 leaderElectorQueryTests();
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800266 }
267
Aaron Kruglikovc38dc7f2016-07-19 10:00:11 -0700268 private void leaderElectorQueryTests() throws Throwable {
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700269 AtomixLeaderElector elector1 = newPrimitive("test-elector-query");
270 AtomixLeaderElector elector2 = newPrimitive("test-elector-query");
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800271 elector1.run("foo", node1).join();
272 elector2.run("foo", node2).join();
273 elector2.run("bar", node2).join();
274 elector1.getElectedTopics(node1).thenAccept(result -> {
275 assertEquals(1, result.size());
276 assertTrue(result.contains("foo"));
277 }).join();
278 elector2.getElectedTopics(node1).thenAccept(result -> {
279 assertEquals(1, result.size());
280 assertTrue(result.contains("foo"));
281 }).join();
282 elector1.getLeadership("foo").thenAccept(result -> {
283 assertEquals(node1, result.leaderNodeId());
284 assertEquals(node1, result.candidates().get(0));
285 assertEquals(node2, result.candidates().get(1));
286 }).join();
287 elector2.getLeadership("foo").thenAccept(result -> {
288 assertEquals(node1, result.leaderNodeId());
289 assertEquals(node1, result.candidates().get(0));
290 assertEquals(node2, result.candidates().get(1));
291 }).join();
292 elector1.getLeadership("bar").thenAccept(result -> {
293 assertEquals(node2, result.leaderNodeId());
294 assertEquals(node2, result.candidates().get(0));
295 }).join();
296 elector2.getLeadership("bar").thenAccept(result -> {
297 assertEquals(node2, result.leaderNodeId());
298 assertEquals(node2, result.candidates().get(0));
299 }).join();
300 elector1.getLeaderships().thenAccept(result -> {
301 assertEquals(2, result.size());
302 Leadership fooLeadership = result.get("foo");
303 assertEquals(node1, fooLeadership.leaderNodeId());
304 assertEquals(node1, fooLeadership.candidates().get(0));
305 assertEquals(node2, fooLeadership.candidates().get(1));
306 Leadership barLeadership = result.get("bar");
307 assertEquals(node2, barLeadership.leaderNodeId());
308 assertEquals(node2, barLeadership.candidates().get(0));
309 }).join();
310 elector2.getLeaderships().thenAccept(result -> {
311 assertEquals(2, result.size());
312 Leadership fooLeadership = result.get("foo");
313 assertEquals(node1, fooLeadership.leaderNodeId());
314 assertEquals(node1, fooLeadership.candidates().get(0));
315 assertEquals(node2, fooLeadership.candidates().get(1));
316 Leadership barLeadership = result.get("bar");
317 assertEquals(node2, barLeadership.leaderNodeId());
318 assertEquals(node2, barLeadership.candidates().get(0));
319 }).join();
320 }
321
322 private static class LeaderEventListener implements Consumer<Change<Leadership>> {
323 Queue<Change<Leadership>> eventQueue = new LinkedList<>();
324 CompletableFuture<Change<Leadership>> pendingFuture;
325
326 @Override
327 public void accept(Change<Leadership> change) {
328 synchronized (this) {
329 if (pendingFuture != null) {
330 pendingFuture.complete(change);
331 pendingFuture = null;
332 } else {
333 eventQueue.add(change);
334 }
335 }
336 }
337
338 public boolean hasEvent() {
339 return !eventQueue.isEmpty();
340 }
341
Madan Jampani0c0cdc62016-02-22 16:54:06 -0800342 public void clearEvents() {
343 eventQueue.clear();
344 }
345
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800346 public CompletableFuture<Change<Leadership>> nextEvent() {
347 synchronized (this) {
348 if (eventQueue.isEmpty()) {
349 if (pendingFuture == null) {
350 pendingFuture = new CompletableFuture<>();
351 }
352 return pendingFuture;
353 } else {
354 return CompletableFuture.completedFuture(eventQueue.poll());
355 }
356 }
357 }
358 }
359}