/* * Copyright (c) 2017 Pantheon Technologies s.r.o. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.controller.cluster.databroker.actors.dds; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; public class VotingFutureTest { private static final int TIMEOUT = 3; private Object result; private ScheduledExecutorService executor; private VotingFuture future; @Before public void setUp() throws Exception { result = new Object(); future = new VotingFuture<>(result, 3); executor = Executors.newScheduledThreadPool(1); } @After public void tearDown() throws Exception { executor.shutdownNow(); } @Test public void testTrivialCases() throws Exception { final VotingFuture oneYesVoteFuture = new VotingFuture<>(result, 1); oneYesVoteFuture.voteYes(); checkSuccess(oneYesVoteFuture, result); final VotingFuture oneNoVoteFuture = new VotingFuture<>(result, 1); final RuntimeException cause = new RuntimeException("fail"); oneNoVoteFuture.voteNo(cause); checkException(oneNoVoteFuture, cause); } @Test public void testVoteYes() throws Exception { future.voteYes(); future.voteYes(); future.voteYes(); checkSuccess(future, result); } @Test public void testVoteYesBlocking() throws Exception { final AtomicBoolean voted = new AtomicBoolean(false); future.voteYes(); future.voteYes(); executor.schedule(() -> { voted.set(true); future.voteYes(); }, 1, TimeUnit.SECONDS); checkSuccess(future, result); Assert.assertTrue("Future completed before vote", voted.get()); } @Test public void testVoteNo() throws Exception { future.voteYes(); final RuntimeException cause = new RuntimeException("fail"); future.voteNo(cause); future.voteYes(); checkException(future, cause); } @Test public void testVoteNoFirst() throws Exception { final RuntimeException cause = new RuntimeException("fail"); future.voteNo(cause); future.voteYes(); future.voteYes(); checkException(future, cause); } @Test public void testVoteNoLast() throws Exception { future.voteYes(); future.voteYes(); final RuntimeException cause = new RuntimeException("fail"); future.voteNo(cause); checkException(future, cause); } @Test public void testVoteNoBlocking() throws Exception { final AtomicBoolean voted = new AtomicBoolean(false); future.voteYes(); final RuntimeException cause = new RuntimeException("fail"); future.voteNo(cause); executor.schedule(() -> { voted.set(true); future.voteYes(); }, 1, TimeUnit.SECONDS); checkException(future, cause); Assert.assertTrue("Future completed before vote", voted.get()); } @Test public void testMultipleVoteNo() throws Exception { future.voteYes(); final RuntimeException cause1 = new RuntimeException("fail"); final RuntimeException cause2 = new RuntimeException("fail"); future.voteNo(cause1); future.voteNo(cause2); try { future.get(TIMEOUT, TimeUnit.SECONDS); Assert.fail("ExecutionException expected"); } catch (final ExecutionException e) { //first no is set as cause Assert.assertEquals(cause1, e.getCause()); //subsequent no causes are added as suppressed final Throwable[] suppressed = e.getCause().getSuppressed(); Assert.assertEquals(1, suppressed.length); Assert.assertEquals(cause2, suppressed[0]); } } private static void checkException(final Future future, final RuntimeException cause) throws Exception { try { future.get(TIMEOUT, TimeUnit.SECONDS); Assert.fail("ExecutionException expected"); } catch (final ExecutionException e) { Assert.assertEquals(cause, e.getCause()); } } private static void checkSuccess(final Future future, final Object result) throws Exception { Assert.assertEquals(result, future.get(TIMEOUT, TimeUnit.SECONDS)); } }