blob: 7b07b4bdde866bb0c6628b56bdbc7f8c811ef5f9 [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
Aaron Kruglikovb5a41e52016-06-23 15:37:41 -070023import org.junit.AfterClass;
24import org.junit.BeforeClass;
Madan Jampani5e5b3d62016-02-01 16:03:33 -080025import org.junit.Test;
26
27import static org.junit.Assert.*;
28
29import org.onosproject.cluster.Leadership;
30import org.onosproject.cluster.NodeId;
31import org.onosproject.event.Change;
32
33import io.atomix.Atomix;
Madan Jampani630e7ac2016-05-31 11:34:05 -070034import io.atomix.AtomixClient;
Madan Jampani5e5b3d62016-02-01 16:03:33 -080035import io.atomix.resource.ResourceType;
36
37/**
38 * Unit tests for {@link AtomixLeaderElector}.
39 */
Madan Jampani5e5b3d62016-02-01 16:03:33 -080040public class AtomixLeaderElectorTest extends AtomixTestBase {
41
42 NodeId node1 = new NodeId("node1");
43 NodeId node2 = new NodeId("node2");
44 NodeId node3 = new NodeId("node3");
45
Aaron Kruglikovb5a41e52016-06-23 15:37:41 -070046 @BeforeClass
47 public static void preTestSetup() throws Throwable {
48 createCopycatServers(3);
49 }
50
51 @AfterClass
52 public static void postTestCleanup() throws Exception {
53 clearTests();
54 }
55
Madan Jampani5e5b3d62016-02-01 16:03:33 -080056 @Override
57 protected ResourceType resourceType() {
58 return new ResourceType(AtomixLeaderElector.class);
59 }
60
61 @Test
62 public void testRun() throws Throwable {
Madan Jampani0c0cdc62016-02-22 16:54:06 -080063 leaderElectorRunTests(3);
Madan Jampani5e5b3d62016-02-01 16:03:33 -080064 }
65
66 private void leaderElectorRunTests(int numServers) throws Throwable {
Madan Jampani5e5b3d62016-02-01 16:03:33 -080067 Atomix client1 = createAtomixClient();
Aaron Kruglikovb5a41e52016-06-23 15:37:41 -070068 AtomixLeaderElector elector1 = client1.getResource("test-elector-run",
69 AtomixLeaderElector.class).join();
Madan Jampani5e5b3d62016-02-01 16:03:33 -080070 elector1.run("foo", node1).thenAccept(result -> {
71 assertEquals(node1, result.leaderNodeId());
72 assertEquals(1, result.leader().term());
73 assertEquals(1, result.candidates().size());
74 assertEquals(node1, result.candidates().get(0));
75 }).join();
76 Atomix client2 = createAtomixClient();
Aaron Kruglikovb5a41e52016-06-23 15:37:41 -070077 AtomixLeaderElector elector2 = client2.getResource("test-elector-run",
78 AtomixLeaderElector.class).join();
Madan Jampani5e5b3d62016-02-01 16:03:33 -080079 elector2.run("foo", node2).thenAccept(result -> {
80 assertEquals(node1, result.leaderNodeId());
81 assertEquals(1, result.leader().term());
82 assertEquals(2, result.candidates().size());
83 assertEquals(node1, result.candidates().get(0));
84 assertEquals(node2, result.candidates().get(1));
85 }).join();
86 }
87
88 @Test
89 public void testWithdraw() throws Throwable {
Madan Jampani5e5b3d62016-02-01 16:03:33 -080090 leaderElectorWithdrawTests(3);
Madan Jampani5e5b3d62016-02-01 16:03:33 -080091 }
92
93 private void leaderElectorWithdrawTests(int numServers) throws Throwable {
Madan Jampani5e5b3d62016-02-01 16:03:33 -080094 Atomix client1 = createAtomixClient();
Aaron Kruglikovb5a41e52016-06-23 15:37:41 -070095 AtomixLeaderElector elector1 = client1.getResource("test-elector-withdraw",
96 AtomixLeaderElector.class).join();
Madan Jampani5e5b3d62016-02-01 16:03:33 -080097 elector1.run("foo", node1).join();
98 Atomix client2 = createAtomixClient();
Aaron Kruglikovb5a41e52016-06-23 15:37:41 -070099 AtomixLeaderElector elector2 = client2.getResource("test-elector-withdraw",
100 AtomixLeaderElector.class).join();
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800101 elector2.run("foo", node2).join();
102
103 LeaderEventListener listener1 = new LeaderEventListener();
104 elector1.addChangeListener(listener1).join();
105
106 LeaderEventListener listener2 = new LeaderEventListener();
107 elector2.addChangeListener(listener2).join();
108
109 elector1.withdraw("foo").join();
110
111 listener1.nextEvent().thenAccept(result -> {
112 assertEquals(node2, result.newValue().leaderNodeId());
113 assertEquals(2, result.newValue().leader().term());
114 assertEquals(1, result.newValue().candidates().size());
115 assertEquals(node2, result.newValue().candidates().get(0));
116 }).join();
117
118 listener2.nextEvent().thenAccept(result -> {
119 assertEquals(node2, result.newValue().leaderNodeId());
120 assertEquals(2, result.newValue().leader().term());
121 assertEquals(1, result.newValue().candidates().size());
122 assertEquals(node2, result.newValue().candidates().get(0));
123 }).join();
124 }
125
126 @Test
127 public void testAnoint() throws Throwable {
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800128 leaderElectorAnointTests(3);
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800129 }
130
131 private void leaderElectorAnointTests(int numServers) throws Throwable {
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800132 Atomix client1 = createAtomixClient();
Aaron Kruglikovb5a41e52016-06-23 15:37:41 -0700133 AtomixLeaderElector elector1 = client1.getResource("test-elector-anoint",
134 AtomixLeaderElector.class).join();
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800135 Atomix client2 = createAtomixClient();
Aaron Kruglikovb5a41e52016-06-23 15:37:41 -0700136 AtomixLeaderElector elector2 = client2.getResource("test-elector-anoint",
137 AtomixLeaderElector.class).join();
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800138 Atomix client3 = createAtomixClient();
Aaron Kruglikovb5a41e52016-06-23 15:37:41 -0700139 AtomixLeaderElector elector3 = client3.getResource("test-elector-anoint",
140 AtomixLeaderElector.class).join();
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800141 elector1.run("foo", node1).join();
142 elector2.run("foo", node2).join();
143
144 LeaderEventListener listener1 = new LeaderEventListener();
145 elector1.addChangeListener(listener1).join();
146 LeaderEventListener listener2 = new LeaderEventListener();
147 elector2.addChangeListener(listener2);
148 LeaderEventListener listener3 = new LeaderEventListener();
149 elector3.addChangeListener(listener3).join();
150
151 elector3.anoint("foo", node3).thenAccept(result -> {
152 assertFalse(result);
153 }).join();
154 assertFalse(listener1.hasEvent());
155 assertFalse(listener2.hasEvent());
156 assertFalse(listener3.hasEvent());
157
158 elector3.anoint("foo", node2).thenAccept(result -> {
159 assertTrue(result);
160 }).join();
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800161
162 listener1.nextEvent().thenAccept(result -> {
163 assertEquals(node2, result.newValue().leaderNodeId());
164 assertEquals(2, result.newValue().candidates().size());
165 assertEquals(node1, result.newValue().candidates().get(0));
166 assertEquals(node2, result.newValue().candidates().get(1));
167 }).join();
168 listener2.nextEvent().thenAccept(result -> {
169 assertEquals(node2, result.newValue().leaderNodeId());
170 assertEquals(2, result.newValue().candidates().size());
171 assertEquals(node1, result.newValue().candidates().get(0));
172 assertEquals(node2, result.newValue().candidates().get(1));
173 }).join();
174 listener3.nextEvent().thenAccept(result -> {
175 assertEquals(node2, result.newValue().leaderNodeId());
176 assertEquals(2, result.newValue().candidates().size());
177 assertEquals(node1, result.newValue().candidates().get(0));
178 assertEquals(node2, result.newValue().candidates().get(1));
179 }).join();
180 }
181
182 @Test
Madan Jampani0c0cdc62016-02-22 16:54:06 -0800183 public void testPromote() throws Throwable {
Madan Jampani0c0cdc62016-02-22 16:54:06 -0800184 leaderElectorPromoteTests(3);
Madan Jampani0c0cdc62016-02-22 16:54:06 -0800185 }
186
187 private void leaderElectorPromoteTests(int numServers) throws Throwable {
Madan Jampani630e7ac2016-05-31 11:34:05 -0700188 AtomixClient client1 = createAtomixClient();
Aaron Kruglikovb5a41e52016-06-23 15:37:41 -0700189 AtomixLeaderElector elector1 = client1.getResource("test-elector-promote",
190 AtomixLeaderElector.class).join();
Madan Jampani630e7ac2016-05-31 11:34:05 -0700191 AtomixClient client2 = createAtomixClient();
Aaron Kruglikovb5a41e52016-06-23 15:37:41 -0700192 AtomixLeaderElector elector2 = client2.getResource("test-elector-promote",
193 AtomixLeaderElector.class).join();
Madan Jampani630e7ac2016-05-31 11:34:05 -0700194 AtomixClient client3 = createAtomixClient();
Aaron Kruglikovb5a41e52016-06-23 15:37:41 -0700195 AtomixLeaderElector elector3 = client3.getResource("test-elector-promote",
196 AtomixLeaderElector.class).join();
Madan Jampani0c0cdc62016-02-22 16:54:06 -0800197 elector1.run("foo", node1).join();
198 elector2.run("foo", node2).join();
199
200 LeaderEventListener listener1 = new LeaderEventListener();
201 elector1.addChangeListener(listener1).join();
202 LeaderEventListener listener2 = new LeaderEventListener();
203 elector2.addChangeListener(listener2).join();
204 LeaderEventListener listener3 = new LeaderEventListener();
205 elector3.addChangeListener(listener3).join();
206
207 elector3.promote("foo", node3).thenAccept(result -> {
208 assertFalse(result);
209 }).join();
210
211 assertFalse(listener1.hasEvent());
212 assertFalse(listener2.hasEvent());
213 assertFalse(listener3.hasEvent());
214
215 elector3.run("foo", node3).join();
216
Madan Jampani630e7ac2016-05-31 11:34:05 -0700217 listener1.nextEvent().thenAccept(result -> {
218 assertEquals(node3, result.newValue().candidates().get(2));
219 }).join();
220 listener2.nextEvent().thenAccept(result -> {
221 assertEquals(node3, result.newValue().candidates().get(2));
222 }).join();
223 listener3.nextEvent().thenAccept(result -> {
224 assertEquals(node3, result.newValue().candidates().get(2));
225 }).join();
Madan Jampani0c0cdc62016-02-22 16:54:06 -0800226
227 elector3.promote("foo", node3).thenAccept(result -> {
228 assertTrue(result);
229 }).join();
230
231 listener1.nextEvent().thenAccept(result -> {
232 assertEquals(node3, result.newValue().candidates().get(0));
233 }).join();
234 listener2.nextEvent().thenAccept(result -> {
235 assertEquals(node3, result.newValue().candidates().get(0));
236 }).join();
237 listener3.nextEvent().thenAccept(result -> {
238 assertEquals(node3, result.newValue().candidates().get(0));
239 }).join();
240 }
241
242 @Test
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800243 public void testLeaderSessionClose() throws Throwable {
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800244 leaderElectorLeaderSessionCloseTests(3);
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800245 }
246
247 private void leaderElectorLeaderSessionCloseTests(int numServers) throws Throwable {
Madan Jampani630e7ac2016-05-31 11:34:05 -0700248 AtomixClient client1 = createAtomixClient();
Aaron Kruglikovb5a41e52016-06-23 15:37:41 -0700249 AtomixLeaderElector elector1 = client1.getResource("test-elector-leader-session-close",
250 AtomixLeaderElector.class).join();
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800251 elector1.run("foo", node1).join();
252 Atomix client2 = createAtomixClient();
Aaron Kruglikovb5a41e52016-06-23 15:37:41 -0700253 AtomixLeaderElector elector2 = client2.getResource("test-elector-leader-session-close",
254 AtomixLeaderElector.class).join();
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800255 LeaderEventListener listener = new LeaderEventListener();
256 elector2.run("foo", node2).join();
257 elector2.addChangeListener(listener).join();
258 client1.close();
259 listener.nextEvent().thenAccept(result -> {
260 assertEquals(node2, result.newValue().leaderNodeId());
261 assertEquals(1, result.newValue().candidates().size());
262 assertEquals(node2, result.newValue().candidates().get(0));
263 }).join();
264 }
265
266 @Test
267 public void testNonLeaderSessionClose() throws Throwable {
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800268 leaderElectorNonLeaderSessionCloseTests(3);
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800269 }
270
271 private void leaderElectorNonLeaderSessionCloseTests(int numServers) throws Throwable {
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800272 Atomix client1 = createAtomixClient();
Aaron Kruglikovb5a41e52016-06-23 15:37:41 -0700273 AtomixLeaderElector elector1 = client1.getResource("test-elector-non-leader-session-close",
274 AtomixLeaderElector.class).join();
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800275 elector1.run("foo", node1).join();
Madan Jampani630e7ac2016-05-31 11:34:05 -0700276 AtomixClient client2 = createAtomixClient();
Aaron Kruglikovb5a41e52016-06-23 15:37:41 -0700277 AtomixLeaderElector elector2 = client2.getResource("test-elector-non-leader-session-close",
278 AtomixLeaderElector.class).join();
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800279 LeaderEventListener listener = new LeaderEventListener();
280 elector2.run("foo", node2).join();
281 elector1.addChangeListener(listener).join();
282 client2.close().join();
283 listener.nextEvent().thenAccept(result -> {
284 assertEquals(node1, result.newValue().leaderNodeId());
285 assertEquals(1, result.newValue().candidates().size());
286 assertEquals(node1, result.newValue().candidates().get(0));
287 }).join();
288 }
289
290 @Test
291 public void testQueries() throws Throwable {
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800292 leaderElectorQueryTests(3);
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800293 }
294
295 private void leaderElectorQueryTests(int numServers) throws Throwable {
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800296 Atomix client1 = createAtomixClient();
297 Atomix client2 = createAtomixClient();
Aaron Kruglikovb5a41e52016-06-23 15:37:41 -0700298 AtomixLeaderElector elector1 = client1.getResource("test-elector-query",
299 AtomixLeaderElector.class).join();
300 AtomixLeaderElector elector2 = client2.getResource("test-elector-query",
301 AtomixLeaderElector.class).join();
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800302 elector1.run("foo", node1).join();
303 elector2.run("foo", node2).join();
304 elector2.run("bar", node2).join();
305 elector1.getElectedTopics(node1).thenAccept(result -> {
306 assertEquals(1, result.size());
307 assertTrue(result.contains("foo"));
308 }).join();
309 elector2.getElectedTopics(node1).thenAccept(result -> {
310 assertEquals(1, result.size());
311 assertTrue(result.contains("foo"));
312 }).join();
313 elector1.getLeadership("foo").thenAccept(result -> {
314 assertEquals(node1, result.leaderNodeId());
315 assertEquals(node1, result.candidates().get(0));
316 assertEquals(node2, result.candidates().get(1));
317 }).join();
318 elector2.getLeadership("foo").thenAccept(result -> {
319 assertEquals(node1, result.leaderNodeId());
320 assertEquals(node1, result.candidates().get(0));
321 assertEquals(node2, result.candidates().get(1));
322 }).join();
323 elector1.getLeadership("bar").thenAccept(result -> {
324 assertEquals(node2, result.leaderNodeId());
325 assertEquals(node2, result.candidates().get(0));
326 }).join();
327 elector2.getLeadership("bar").thenAccept(result -> {
328 assertEquals(node2, result.leaderNodeId());
329 assertEquals(node2, result.candidates().get(0));
330 }).join();
331 elector1.getLeaderships().thenAccept(result -> {
332 assertEquals(2, result.size());
333 Leadership fooLeadership = result.get("foo");
334 assertEquals(node1, fooLeadership.leaderNodeId());
335 assertEquals(node1, fooLeadership.candidates().get(0));
336 assertEquals(node2, fooLeadership.candidates().get(1));
337 Leadership barLeadership = result.get("bar");
338 assertEquals(node2, barLeadership.leaderNodeId());
339 assertEquals(node2, barLeadership.candidates().get(0));
340 }).join();
341 elector2.getLeaderships().thenAccept(result -> {
342 assertEquals(2, result.size());
343 Leadership fooLeadership = result.get("foo");
344 assertEquals(node1, fooLeadership.leaderNodeId());
345 assertEquals(node1, fooLeadership.candidates().get(0));
346 assertEquals(node2, fooLeadership.candidates().get(1));
347 Leadership barLeadership = result.get("bar");
348 assertEquals(node2, barLeadership.leaderNodeId());
349 assertEquals(node2, barLeadership.candidates().get(0));
350 }).join();
351 }
352
353 private static class LeaderEventListener implements Consumer<Change<Leadership>> {
354 Queue<Change<Leadership>> eventQueue = new LinkedList<>();
355 CompletableFuture<Change<Leadership>> pendingFuture;
356
357 @Override
358 public void accept(Change<Leadership> change) {
359 synchronized (this) {
360 if (pendingFuture != null) {
361 pendingFuture.complete(change);
362 pendingFuture = null;
363 } else {
364 eventQueue.add(change);
365 }
366 }
367 }
368
369 public boolean hasEvent() {
370 return !eventQueue.isEmpty();
371 }
372
Madan Jampani0c0cdc62016-02-22 16:54:06 -0800373 public void clearEvents() {
374 eventQueue.clear();
375 }
376
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800377 public CompletableFuture<Change<Leadership>> nextEvent() {
378 synchronized (this) {
379 if (eventQueue.isEmpty()) {
380 if (pendingFuture == null) {
381 pendingFuture = new CompletableFuture<>();
382 }
383 return pendingFuture;
384 } else {
385 return CompletableFuture.completedFuture(eventQueue.poll());
386 }
387 }
388 }
389 }
390}