2 * Copyright (c) 2017 Pantheon Technologies s.r.o. 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
8 package org.opendaylight.controller.cluster.databroker.actors.dds;
10 import java.util.concurrent.ExecutionException;
11 import java.util.concurrent.Executors;
12 import java.util.concurrent.Future;
13 import java.util.concurrent.ScheduledExecutorService;
14 import java.util.concurrent.TimeUnit;
15 import java.util.concurrent.atomic.AtomicBoolean;
16 import org.junit.After;
17 import org.junit.Assert;
18 import org.junit.Before;
19 import org.junit.Test;
21 public class VotingFutureTest {
23 private static final int TIMEOUT = 3;
25 private Object result;
26 private ScheduledExecutorService executor;
27 private VotingFuture<Object> future;
30 public void setUp() throws Exception {
31 result = new Object();
32 future = new VotingFuture<>(result, 3);
33 executor = Executors.newScheduledThreadPool(1);
37 public void tearDown() throws Exception {
38 executor.shutdownNow();
42 public void testTrivialCases() throws Exception {
43 final VotingFuture<Object> oneYesVoteFuture = new VotingFuture<>(result, 1);
44 oneYesVoteFuture.voteYes();
45 checkSuccess(oneYesVoteFuture, result);
46 final VotingFuture<Object> oneNoVoteFuture = new VotingFuture<>(result, 1);
47 final RuntimeException cause = new RuntimeException("fail");
48 oneNoVoteFuture.voteNo(cause);
49 checkException(oneNoVoteFuture, cause);
53 public void testVoteYes() throws Exception {
57 checkSuccess(future, result);
61 public void testVoteYesBlocking() throws Exception {
62 final AtomicBoolean voted = new AtomicBoolean(false);
65 executor.schedule(() -> {
68 }, 1, TimeUnit.SECONDS);
69 checkSuccess(future, result);
70 Assert.assertTrue("Future completed before vote", voted.get());
74 public void testVoteNo() throws Exception {
76 final RuntimeException cause = new RuntimeException("fail");
79 checkException(future, cause);
83 public void testVoteNoFirst() throws Exception {
84 final RuntimeException cause = new RuntimeException("fail");
88 checkException(future, cause);
92 public void testVoteNoLast() throws Exception {
95 final RuntimeException cause = new RuntimeException("fail");
97 checkException(future, cause);
101 public void testVoteNoBlocking() throws Exception {
102 final AtomicBoolean voted = new AtomicBoolean(false);
104 final RuntimeException cause = new RuntimeException("fail");
105 future.voteNo(cause);
106 executor.schedule(() -> {
109 }, 1, TimeUnit.SECONDS);
110 checkException(future, cause);
111 Assert.assertTrue("Future completed before vote", voted.get());
115 public void testMultipleVoteNo() throws Exception {
117 final RuntimeException cause1 = new RuntimeException("fail");
118 final RuntimeException cause2 = new RuntimeException("fail");
119 future.voteNo(cause1);
120 future.voteNo(cause2);
122 future.get(TIMEOUT, TimeUnit.SECONDS);
123 Assert.fail("ExecutionException expected");
124 } catch (final ExecutionException e) {
125 //first no is set as cause
126 Assert.assertEquals(cause1, e.getCause());
127 //subsequent no causes are added as suppressed
128 final Throwable[] suppressed = e.getCause().getSuppressed();
129 Assert.assertEquals(1, suppressed.length);
130 Assert.assertEquals(cause2, suppressed[0]);
134 private static void checkException(final Future future, final RuntimeException cause) throws Exception {
136 future.get(TIMEOUT, TimeUnit.SECONDS);
137 Assert.fail("ExecutionException expected");
138 } catch (final ExecutionException e) {
139 Assert.assertEquals(cause, e.getCause());
143 private static void checkSuccess(final Future future, final Object result) throws Exception {
144 Assert.assertEquals(result, future.get(TIMEOUT, TimeUnit.SECONDS));