blob: f6be9f7ae64993e03615fbb70f649dad5cd98b2e [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
23import org.junit.Test;
24
25import static org.junit.Assert.*;
26
27import org.onosproject.cluster.Leadership;
28import org.onosproject.cluster.NodeId;
29import org.onosproject.event.Change;
30
31import io.atomix.Atomix;
Madan Jampani630e7ac2016-05-31 11:34:05 -070032import io.atomix.AtomixClient;
Madan Jampani5e5b3d62016-02-01 16:03:33 -080033import io.atomix.resource.ResourceType;
34
35/**
36 * Unit tests for {@link AtomixLeaderElector}.
37 */
Madan Jampani5e5b3d62016-02-01 16:03:33 -080038public class AtomixLeaderElectorTest extends AtomixTestBase {
39
40 NodeId node1 = new NodeId("node1");
41 NodeId node2 = new NodeId("node2");
42 NodeId node3 = new NodeId("node3");
43
44 @Override
45 protected ResourceType resourceType() {
46 return new ResourceType(AtomixLeaderElector.class);
47 }
48
49 @Test
50 public void testRun() throws Throwable {
Madan Jampani0c0cdc62016-02-22 16:54:06 -080051 leaderElectorRunTests(3);
Madan Jampani5e5b3d62016-02-01 16:03:33 -080052 }
53
54 private void leaderElectorRunTests(int numServers) throws Throwable {
55 createCopycatServers(numServers);
56 Atomix client1 = createAtomixClient();
Madan Jampani65f24bb2016-03-15 15:16:18 -070057 AtomixLeaderElector elector1 = client1.getResource("test-elector", AtomixLeaderElector.class).join();
Madan Jampani5e5b3d62016-02-01 16:03:33 -080058 elector1.run("foo", node1).thenAccept(result -> {
59 assertEquals(node1, result.leaderNodeId());
60 assertEquals(1, result.leader().term());
61 assertEquals(1, result.candidates().size());
62 assertEquals(node1, result.candidates().get(0));
63 }).join();
64 Atomix client2 = createAtomixClient();
Madan Jampani65f24bb2016-03-15 15:16:18 -070065 AtomixLeaderElector elector2 = client2.getResource("test-elector", AtomixLeaderElector.class).join();
Madan Jampani5e5b3d62016-02-01 16:03:33 -080066 elector2.run("foo", node2).thenAccept(result -> {
67 assertEquals(node1, result.leaderNodeId());
68 assertEquals(1, result.leader().term());
69 assertEquals(2, result.candidates().size());
70 assertEquals(node1, result.candidates().get(0));
71 assertEquals(node2, result.candidates().get(1));
72 }).join();
73 }
74
75 @Test
76 public void testWithdraw() throws Throwable {
Madan Jampani5e5b3d62016-02-01 16:03:33 -080077 leaderElectorWithdrawTests(3);
Madan Jampani5e5b3d62016-02-01 16:03:33 -080078 }
79
80 private void leaderElectorWithdrawTests(int numServers) throws Throwable {
81 createCopycatServers(numServers);
82 Atomix client1 = createAtomixClient();
Madan Jampani65f24bb2016-03-15 15:16:18 -070083 AtomixLeaderElector elector1 = client1.getResource("test-elector", AtomixLeaderElector.class).join();
Madan Jampani5e5b3d62016-02-01 16:03:33 -080084 elector1.run("foo", node1).join();
85 Atomix client2 = createAtomixClient();
Madan Jampani65f24bb2016-03-15 15:16:18 -070086 AtomixLeaderElector elector2 = client2.getResource("test-elector", AtomixLeaderElector.class).join();
Madan Jampani5e5b3d62016-02-01 16:03:33 -080087 elector2.run("foo", node2).join();
88
89 LeaderEventListener listener1 = new LeaderEventListener();
90 elector1.addChangeListener(listener1).join();
91
92 LeaderEventListener listener2 = new LeaderEventListener();
93 elector2.addChangeListener(listener2).join();
94
95 elector1.withdraw("foo").join();
96
97 listener1.nextEvent().thenAccept(result -> {
98 assertEquals(node2, result.newValue().leaderNodeId());
99 assertEquals(2, result.newValue().leader().term());
100 assertEquals(1, result.newValue().candidates().size());
101 assertEquals(node2, result.newValue().candidates().get(0));
102 }).join();
103
104 listener2.nextEvent().thenAccept(result -> {
105 assertEquals(node2, result.newValue().leaderNodeId());
106 assertEquals(2, result.newValue().leader().term());
107 assertEquals(1, result.newValue().candidates().size());
108 assertEquals(node2, result.newValue().candidates().get(0));
109 }).join();
110 }
111
112 @Test
113 public void testAnoint() throws Throwable {
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800114 leaderElectorAnointTests(3);
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800115 }
116
117 private void leaderElectorAnointTests(int numServers) throws Throwable {
118 createCopycatServers(numServers);
119 Atomix client1 = createAtomixClient();
Madan Jampani65f24bb2016-03-15 15:16:18 -0700120 AtomixLeaderElector elector1 = client1.getResource("test-elector", AtomixLeaderElector.class).join();
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800121 Atomix client2 = createAtomixClient();
Madan Jampani65f24bb2016-03-15 15:16:18 -0700122 AtomixLeaderElector elector2 = client2.getResource("test-elector", AtomixLeaderElector.class).join();
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800123 Atomix client3 = createAtomixClient();
Madan Jampani65f24bb2016-03-15 15:16:18 -0700124 AtomixLeaderElector elector3 = client3.getResource("test-elector", AtomixLeaderElector.class).join();
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800125 elector1.run("foo", node1).join();
126 elector2.run("foo", node2).join();
127
128 LeaderEventListener listener1 = new LeaderEventListener();
129 elector1.addChangeListener(listener1).join();
130 LeaderEventListener listener2 = new LeaderEventListener();
131 elector2.addChangeListener(listener2);
132 LeaderEventListener listener3 = new LeaderEventListener();
133 elector3.addChangeListener(listener3).join();
134
135 elector3.anoint("foo", node3).thenAccept(result -> {
136 assertFalse(result);
137 }).join();
138 assertFalse(listener1.hasEvent());
139 assertFalse(listener2.hasEvent());
140 assertFalse(listener3.hasEvent());
141
142 elector3.anoint("foo", node2).thenAccept(result -> {
143 assertTrue(result);
144 }).join();
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800145
146 listener1.nextEvent().thenAccept(result -> {
147 assertEquals(node2, result.newValue().leaderNodeId());
148 assertEquals(2, result.newValue().candidates().size());
149 assertEquals(node1, result.newValue().candidates().get(0));
150 assertEquals(node2, result.newValue().candidates().get(1));
151 }).join();
152 listener2.nextEvent().thenAccept(result -> {
153 assertEquals(node2, result.newValue().leaderNodeId());
154 assertEquals(2, result.newValue().candidates().size());
155 assertEquals(node1, result.newValue().candidates().get(0));
156 assertEquals(node2, result.newValue().candidates().get(1));
157 }).join();
158 listener3.nextEvent().thenAccept(result -> {
159 assertEquals(node2, result.newValue().leaderNodeId());
160 assertEquals(2, result.newValue().candidates().size());
161 assertEquals(node1, result.newValue().candidates().get(0));
162 assertEquals(node2, result.newValue().candidates().get(1));
163 }).join();
164 }
165
166 @Test
Madan Jampani0c0cdc62016-02-22 16:54:06 -0800167 public void testPromote() throws Throwable {
Madan Jampani0c0cdc62016-02-22 16:54:06 -0800168 leaderElectorPromoteTests(3);
Madan Jampani0c0cdc62016-02-22 16:54:06 -0800169 }
170
171 private void leaderElectorPromoteTests(int numServers) throws Throwable {
172 createCopycatServers(numServers);
Madan Jampani630e7ac2016-05-31 11:34:05 -0700173 AtomixClient client1 = createAtomixClient();
Madan Jampani65f24bb2016-03-15 15:16:18 -0700174 AtomixLeaderElector elector1 = client1.getResource("test-elector", AtomixLeaderElector.class).join();
Madan Jampani630e7ac2016-05-31 11:34:05 -0700175 AtomixClient client2 = createAtomixClient();
Madan Jampani65f24bb2016-03-15 15:16:18 -0700176 AtomixLeaderElector elector2 = client2.getResource("test-elector", AtomixLeaderElector.class).join();
Madan Jampani630e7ac2016-05-31 11:34:05 -0700177 AtomixClient client3 = createAtomixClient();
Madan Jampani65f24bb2016-03-15 15:16:18 -0700178 AtomixLeaderElector elector3 = client3.getResource("test-elector", AtomixLeaderElector.class).join();
Madan Jampani0c0cdc62016-02-22 16:54:06 -0800179 elector1.run("foo", node1).join();
180 elector2.run("foo", node2).join();
181
182 LeaderEventListener listener1 = new LeaderEventListener();
183 elector1.addChangeListener(listener1).join();
184 LeaderEventListener listener2 = new LeaderEventListener();
185 elector2.addChangeListener(listener2).join();
186 LeaderEventListener listener3 = new LeaderEventListener();
187 elector3.addChangeListener(listener3).join();
188
189 elector3.promote("foo", node3).thenAccept(result -> {
190 assertFalse(result);
191 }).join();
192
193 assertFalse(listener1.hasEvent());
194 assertFalse(listener2.hasEvent());
195 assertFalse(listener3.hasEvent());
196
197 elector3.run("foo", node3).join();
198
Madan Jampani630e7ac2016-05-31 11:34:05 -0700199 listener1.nextEvent().thenAccept(result -> {
200 assertEquals(node3, result.newValue().candidates().get(2));
201 }).join();
202 listener2.nextEvent().thenAccept(result -> {
203 assertEquals(node3, result.newValue().candidates().get(2));
204 }).join();
205 listener3.nextEvent().thenAccept(result -> {
206 assertEquals(node3, result.newValue().candidates().get(2));
207 }).join();
Madan Jampani0c0cdc62016-02-22 16:54:06 -0800208
209 elector3.promote("foo", node3).thenAccept(result -> {
210 assertTrue(result);
211 }).join();
212
213 listener1.nextEvent().thenAccept(result -> {
214 assertEquals(node3, result.newValue().candidates().get(0));
215 }).join();
216 listener2.nextEvent().thenAccept(result -> {
217 assertEquals(node3, result.newValue().candidates().get(0));
218 }).join();
219 listener3.nextEvent().thenAccept(result -> {
220 assertEquals(node3, result.newValue().candidates().get(0));
221 }).join();
222 }
223
224 @Test
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800225 public void testLeaderSessionClose() throws Throwable {
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800226 leaderElectorLeaderSessionCloseTests(3);
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800227 }
228
229 private void leaderElectorLeaderSessionCloseTests(int numServers) throws Throwable {
230 createCopycatServers(numServers);
Madan Jampani630e7ac2016-05-31 11:34:05 -0700231 AtomixClient client1 = createAtomixClient();
Madan Jampani65f24bb2016-03-15 15:16:18 -0700232 AtomixLeaderElector elector1 = client1.getResource("test-elector", AtomixLeaderElector.class).join();
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800233 elector1.run("foo", node1).join();
234 Atomix client2 = createAtomixClient();
Madan Jampani65f24bb2016-03-15 15:16:18 -0700235 AtomixLeaderElector elector2 = client2.getResource("test-elector", AtomixLeaderElector.class).join();
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800236 LeaderEventListener listener = new LeaderEventListener();
237 elector2.run("foo", node2).join();
238 elector2.addChangeListener(listener).join();
239 client1.close();
240 listener.nextEvent().thenAccept(result -> {
241 assertEquals(node2, result.newValue().leaderNodeId());
242 assertEquals(1, result.newValue().candidates().size());
243 assertEquals(node2, result.newValue().candidates().get(0));
244 }).join();
245 }
246
247 @Test
248 public void testNonLeaderSessionClose() throws Throwable {
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800249 leaderElectorNonLeaderSessionCloseTests(3);
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800250 }
251
252 private void leaderElectorNonLeaderSessionCloseTests(int numServers) throws Throwable {
253 createCopycatServers(numServers);
254 Atomix client1 = createAtomixClient();
Madan Jampani65f24bb2016-03-15 15:16:18 -0700255 AtomixLeaderElector elector1 = client1.getResource("test-elector", AtomixLeaderElector.class).join();
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800256 elector1.run("foo", node1).join();
Madan Jampani630e7ac2016-05-31 11:34:05 -0700257 AtomixClient client2 = createAtomixClient();
Madan Jampani65f24bb2016-03-15 15:16:18 -0700258 AtomixLeaderElector elector2 = client2.getResource("test-elector", AtomixLeaderElector.class).join();
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800259 LeaderEventListener listener = new LeaderEventListener();
260 elector2.run("foo", node2).join();
261 elector1.addChangeListener(listener).join();
262 client2.close().join();
263 listener.nextEvent().thenAccept(result -> {
264 assertEquals(node1, result.newValue().leaderNodeId());
265 assertEquals(1, result.newValue().candidates().size());
266 assertEquals(node1, result.newValue().candidates().get(0));
267 }).join();
268 }
269
270 @Test
271 public void testQueries() throws Throwable {
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800272 leaderElectorQueryTests(3);
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800273 }
274
275 private void leaderElectorQueryTests(int numServers) throws Throwable {
276 createCopycatServers(numServers);
277 Atomix client1 = createAtomixClient();
278 Atomix client2 = createAtomixClient();
Madan Jampani65f24bb2016-03-15 15:16:18 -0700279 AtomixLeaderElector elector1 = client1.getResource("test-elector", AtomixLeaderElector.class).join();
280 AtomixLeaderElector elector2 = client2.getResource("test-elector", AtomixLeaderElector.class).join();
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800281 elector1.run("foo", node1).join();
282 elector2.run("foo", node2).join();
283 elector2.run("bar", node2).join();
284 elector1.getElectedTopics(node1).thenAccept(result -> {
285 assertEquals(1, result.size());
286 assertTrue(result.contains("foo"));
287 }).join();
288 elector2.getElectedTopics(node1).thenAccept(result -> {
289 assertEquals(1, result.size());
290 assertTrue(result.contains("foo"));
291 }).join();
292 elector1.getLeadership("foo").thenAccept(result -> {
293 assertEquals(node1, result.leaderNodeId());
294 assertEquals(node1, result.candidates().get(0));
295 assertEquals(node2, result.candidates().get(1));
296 }).join();
297 elector2.getLeadership("foo").thenAccept(result -> {
298 assertEquals(node1, result.leaderNodeId());
299 assertEquals(node1, result.candidates().get(0));
300 assertEquals(node2, result.candidates().get(1));
301 }).join();
302 elector1.getLeadership("bar").thenAccept(result -> {
303 assertEquals(node2, result.leaderNodeId());
304 assertEquals(node2, result.candidates().get(0));
305 }).join();
306 elector2.getLeadership("bar").thenAccept(result -> {
307 assertEquals(node2, result.leaderNodeId());
308 assertEquals(node2, result.candidates().get(0));
309 }).join();
310 elector1.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 elector2.getLeaderships().thenAccept(result -> {
321 assertEquals(2, result.size());
322 Leadership fooLeadership = result.get("foo");
323 assertEquals(node1, fooLeadership.leaderNodeId());
324 assertEquals(node1, fooLeadership.candidates().get(0));
325 assertEquals(node2, fooLeadership.candidates().get(1));
326 Leadership barLeadership = result.get("bar");
327 assertEquals(node2, barLeadership.leaderNodeId());
328 assertEquals(node2, barLeadership.candidates().get(0));
329 }).join();
330 }
331
332 private static class LeaderEventListener implements Consumer<Change<Leadership>> {
333 Queue<Change<Leadership>> eventQueue = new LinkedList<>();
334 CompletableFuture<Change<Leadership>> pendingFuture;
335
336 @Override
337 public void accept(Change<Leadership> change) {
338 synchronized (this) {
339 if (pendingFuture != null) {
340 pendingFuture.complete(change);
341 pendingFuture = null;
342 } else {
343 eventQueue.add(change);
344 }
345 }
346 }
347
348 public boolean hasEvent() {
349 return !eventQueue.isEmpty();
350 }
351
Madan Jampani0c0cdc62016-02-22 16:54:06 -0800352 public void clearEvents() {
353 eventQueue.clear();
354 }
355
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800356 public CompletableFuture<Change<Leadership>> nextEvent() {
357 synchronized (this) {
358 if (eventQueue.isEmpty()) {
359 if (pendingFuture == null) {
360 pendingFuture = new CompletableFuture<>();
361 }
362 return pendingFuture;
363 } else {
364 return CompletableFuture.completedFuture(eventQueue.poll());
365 }
366 }
367 }
368 }
369}