From ddb42663a4a53d8440d33f955a5944184f3b602d Mon Sep 17 00:00:00 2001 From: Andrej Mak Date: Wed, 15 Mar 2017 15:24:56 +0100 Subject: [PATCH] Add AbstractClientHandle derived classes tests Change-Id: I9eee30289814c92b7f3e7d5b2eebf49ee575b9b3 Signed-off-by: Andrej Mak --- .../access/client/AccessClientUtil.java | 6 + .../actors/dds/AbstractClientHandleTest.java | 220 ++++++++++++++++++ .../actors/dds/ClientSnapshotTest.java | 58 +++++ .../actors/dds/ClientTransactionTest.java | 140 +++++++++++ .../databroker/actors/dds/TestUtils.java | 86 +++++++ .../actors/dds/VotingFutureTest.java | 44 ++-- 6 files changed, 527 insertions(+), 27 deletions(-) create mode 100644 opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/databroker/actors/dds/AbstractClientHandleTest.java create mode 100644 opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/databroker/actors/dds/ClientSnapshotTest.java create mode 100644 opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/databroker/actors/dds/ClientTransactionTest.java create mode 100644 opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/databroker/actors/dds/TestUtils.java diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/access/client/AccessClientUtil.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/access/client/AccessClientUtil.java index 999aad8637..4f6625b6c5 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/access/client/AccessClientUtil.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/access/client/AccessClientUtil.java @@ -10,6 +10,7 @@ package org.opendaylight.controller.cluster.access.client; import akka.actor.ActorRef; import akka.actor.ActorSystem; import org.opendaylight.controller.cluster.access.concepts.ClientIdentifier; +import org.opendaylight.controller.cluster.access.concepts.ResponseEnvelope; /** * Util class to access package private members in cds-access-client for test purposes. @@ -21,4 +22,9 @@ public class AccessClientUtil { return new ClientActorContext(actor, system.scheduler(), system.dispatcher(), persistenceId, id); } + public static void completeRequest(final AbstractClientConnection connection, + final ResponseEnvelope envelope) { + connection.receiveResponse(envelope); + } + } \ No newline at end of file diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/databroker/actors/dds/AbstractClientHandleTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/databroker/actors/dds/AbstractClientHandleTest.java new file mode 100644 index 0000000000..95791788b1 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/databroker/actors/dds/AbstractClientHandleTest.java @@ -0,0 +1,220 @@ +/* + * 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 static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import akka.actor.ActorRef; +import akka.actor.ActorSelection; +import akka.actor.ActorSystem; +import akka.testkit.JavaTestKit; +import akka.testkit.TestProbe; +import java.util.Collection; +import java.util.Collections; +import java.util.function.Function; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.controller.cluster.access.client.AbstractClientConnection; +import org.opendaylight.controller.cluster.access.client.AccessClientUtil; +import org.opendaylight.controller.cluster.access.client.ClientActorContext; +import org.opendaylight.controller.cluster.access.client.InternalCommand; +import org.opendaylight.controller.cluster.access.commands.AbortLocalTransactionRequest; +import org.opendaylight.controller.cluster.access.commands.ConnectClientRequest; +import org.opendaylight.controller.cluster.access.commands.ConnectClientSuccess; +import org.opendaylight.controller.cluster.access.concepts.ClientIdentifier; +import org.opendaylight.controller.cluster.access.concepts.Envelope; +import org.opendaylight.controller.cluster.access.concepts.FailureEnvelope; +import org.opendaylight.controller.cluster.access.concepts.FrontendIdentifier; +import org.opendaylight.controller.cluster.access.concepts.FrontendType; +import org.opendaylight.controller.cluster.access.concepts.LocalHistoryIdentifier; +import org.opendaylight.controller.cluster.access.concepts.MemberName; +import org.opendaylight.controller.cluster.access.concepts.Request; +import org.opendaylight.controller.cluster.access.concepts.RequestEnvelope; +import org.opendaylight.controller.cluster.access.concepts.RequestFailure; +import org.opendaylight.controller.cluster.access.concepts.RequestSuccess; +import org.opendaylight.controller.cluster.access.concepts.Response; +import org.opendaylight.controller.cluster.access.concepts.SuccessEnvelope; +import org.opendaylight.controller.cluster.access.concepts.TransactionIdentifier; +import org.opendaylight.controller.cluster.datastore.messages.PrimaryShardInfo; +import org.opendaylight.controller.cluster.datastore.utils.ActorContext; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot; +import scala.concurrent.Promise; + +public abstract class AbstractClientHandleTest> { + + private static final MemberName MEMBER_NAME = MemberName.forName("member-1"); + private static final FrontendType FRONTEND_TYPE = FrontendType.forName("type-1"); + private static final FrontendIdentifier FRONTEND_ID = FrontendIdentifier.create(MEMBER_NAME, FRONTEND_TYPE); + private static final ClientIdentifier CLIENT_ID = ClientIdentifier.create(FRONTEND_ID, 0); + private static final LocalHistoryIdentifier HISTORY_ID = new LocalHistoryIdentifier(CLIENT_ID, 0L); + private static final String PERSISTENCE_ID = "per-1"; + private static final YangInstanceIdentifier PATH = YangInstanceIdentifier.EMPTY; + protected static final TransactionIdentifier TRANSACTION_ID = new TransactionIdentifier(HISTORY_ID, 0L); + + @Mock + private DataTree dataTree; + @Mock + private DataTreeSnapshot dataTreeSnapshot; + private ActorSystem system; + private TestProbe backendProbe; + private AbstractClientHistory parent; + private AbstractDataStoreClientBehavior client; + private T handle; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + system = ActorSystem.apply(); + final TestProbe contextProbe = new TestProbe(system, "context"); + final TestProbe clientContextProbe = new TestProbe(system, "client-context"); + backendProbe = new TestProbe(system, "backend"); + //create handle dependencies + final ActorContext actorContext = createActorContextMock(system, contextProbe.ref()); + final ClientActorContext clientContext = + AccessClientUtil.createClientActorContext(system, clientContextProbe.ref(), CLIENT_ID, PERSISTENCE_ID); + client = new SimpleDataStoreClientBehavior(clientContext, actorContext, "shard"); + client.createLocalHistory(); + parent = new SingleClientHistory(client, HISTORY_ID); + //connect client + client.getConnection(0L); + contextProbe.expectMsgClass(ConnectClientRequest.class); + final long sequence = 0L; + contextProbe.reply(new ConnectClientSuccess(CLIENT_ID, sequence, backendProbe.ref(), + Collections.emptyList(), dataTree, 3)); + final InternalCommand command = clientContextProbe.expectMsgClass(InternalCommand.class); + command.execute(client); + //data tree mock + when(dataTree.takeSnapshot()).thenReturn(dataTreeSnapshot); + + handle = createHandle(parent); + } + + protected abstract T createHandle(AbstractClientHistory parent); + + /** + * Do a operation with handle. + * Used for testing, whether closed handle throws exception when the operation is performed. + * + * @param handle handle + */ + protected abstract void doHandleOperation(T handle); + + @After + public void tearDown() throws Exception { + JavaTestKit.shutdownActorSystem(system); + } + + @Test + public void testGetIdentifier() throws Exception { + Assert.assertEquals(TRANSACTION_ID, handle.getIdentifier()); + } + + @Test + public void testAbort() throws Exception { + doHandleOperation(handle); + handle.abort(); + final Envelope envelope = backendProbe.expectMsgClass(Envelope.class); + final AbortLocalTransactionRequest request = (AbortLocalTransactionRequest) envelope.getMessage(); + Assert.assertEquals(TRANSACTION_ID, request.getTarget()); + checkClosed(); + } + + @Test + public void testLocalAbort() throws Exception { + doHandleOperation(handle); + handle.localAbort(new RuntimeException("fail")); + final Envelope envelope = backendProbe.expectMsgClass(Envelope.class); + final AbortLocalTransactionRequest request = (AbortLocalTransactionRequest) envelope.getMessage(); + Assert.assertEquals(TRANSACTION_ID, request.getTarget()); + checkClosed(); + } + + @Test + public void testEnsureClosed() throws Exception { + doHandleOperation(handle); + final Collection transactions = handle.ensureClosed(); + Assert.assertNotNull(transactions); + Assert.assertEquals(1, transactions.size()); + } + + @Test + public void testEnsureProxy() throws Exception { + final Function function = mock(Function.class); + final AbstractProxyTransaction expected = mock(AbstractProxyTransaction.class); + when(function.apply(0L)).thenReturn(expected); + final AbstractProxyTransaction proxy = handle.ensureProxy(PATH, function); + verify(function).apply(0L); + Assert.assertEquals(expected, proxy); + } + + @Test + public void testParent() throws Exception { + Assert.assertEquals(parent, handle.parent()); + } + + protected void checkClosed() throws Exception { + TestUtils.assertOperationThrowsException(() -> doHandleOperation(handle), IllegalStateException.class); + } + + /** + * Checks, whether backend actor has received request of expected class wrapped in RequestEnvelope. + * Then given response wrapped in ResponseEnvelope is sent. + * + * @param expectedRequestClass expected request class + * @param response response + * @param expected request type + * @return request message + */ + protected R backendRespondToRequest(final Class expectedRequestClass, + final Response response) { + final RequestEnvelope envelope = backendProbe.expectMsgClass(RequestEnvelope.class); + Assert.assertEquals(expectedRequestClass, envelope.getMessage().getClass()); + final AbstractClientConnection connection = client.getConnection(0L); + final long sessionId = envelope.getSessionId(); + final long txSequence = envelope.getTxSequence(); + final long executionTime = 0L; + if (response instanceof RequestSuccess) { + final RequestSuccess success = (RequestSuccess) response; + final SuccessEnvelope responseEnvelope = new SuccessEnvelope(success, sessionId, txSequence, executionTime); + AccessClientUtil.completeRequest(connection, responseEnvelope); + } else if (response instanceof RequestFailure) { + final RequestFailure fail = (RequestFailure) response; + final FailureEnvelope responseEnvelope = new FailureEnvelope(fail, sessionId, txSequence, executionTime); + AccessClientUtil.completeRequest(connection, responseEnvelope); + } + return (R) envelope.getMessage(); + } + + protected T getHandle() { + return handle; + } + + protected DataTreeSnapshot getDataTreeSnapshot() { + return dataTreeSnapshot; + } + + private static ActorContext createActorContextMock(final ActorSystem system, final ActorRef actor) { + final ActorContext mock = mock(ActorContext.class); + final Promise promise = new scala.concurrent.impl.Promise.DefaultPromise<>(); + final ActorSelection selection = system.actorSelection(actor.path()); + final PrimaryShardInfo shardInfo = new PrimaryShardInfo(selection, (short) 0); + promise.success(shardInfo); + when(mock.findPrimaryShardAsync(any())).thenReturn(promise.future()); + return mock; + } + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/databroker/actors/dds/ClientSnapshotTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/databroker/actors/dds/ClientSnapshotTest.java new file mode 100644 index 0000000000..709335cf53 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/databroker/actors/dds/ClientSnapshotTest.java @@ -0,0 +1,58 @@ +/* + * 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 static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.opendaylight.controller.cluster.databroker.actors.dds.TestUtils.getWithTimeout; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.mdsal.common.api.ReadFailedException; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +public class ClientSnapshotTest extends AbstractClientHandleTest { + + private static final YangInstanceIdentifier PATH = YangInstanceIdentifier.EMPTY; + + @Before + @Override + public void setUp() throws Exception { + super.setUp(); + when(getDataTreeSnapshot().readNode(PATH)).thenReturn(Optional.absent()); + } + + @Override + protected ClientSnapshot createHandle(final AbstractClientHistory parent) { + return parent.takeSnapshot(); + } + + @Override + protected void doHandleOperation(final ClientSnapshot snapshot) { + snapshot.read(PATH); + } + + @Test + public void testExists() throws Exception { + final CheckedFuture exists = getHandle().exists(PATH); + verify(getDataTreeSnapshot()).readNode(PATH); + Assert.assertFalse(getWithTimeout(exists)); + } + + @Test + public void testRead() throws Exception { + final CheckedFuture>, ReadFailedException> exists = getHandle().read(PATH); + verify(getDataTreeSnapshot()).readNode(PATH); + Assert.assertFalse(getWithTimeout(exists).isPresent()); + } + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/databroker/actors/dds/ClientTransactionTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/databroker/actors/dds/ClientTransactionTest.java new file mode 100644 index 0000000000..7b10cefbe1 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/databroker/actors/dds/ClientTransactionTest.java @@ -0,0 +1,140 @@ +/* + * 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 static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.opendaylight.controller.cluster.databroker.actors.dds.TestUtils.assertFutureEquals; +import static org.opendaylight.controller.cluster.databroker.actors.dds.TestUtils.assertOperationThrowsException; +import static org.opendaylight.controller.cluster.databroker.actors.dds.TestUtils.getWithTimeout; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.ListenableFuture; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.opendaylight.controller.cluster.access.commands.CommitLocalTransactionRequest; +import org.opendaylight.controller.cluster.access.commands.TransactionCommitSuccess; +import org.opendaylight.mdsal.common.api.ReadFailedException; +import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteCursor; +import org.opendaylight.mdsal.dom.spi.store.DOMStoreThreePhaseCommitCohort; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.tree.CursorAwareDataTreeModification; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; + +public class ClientTransactionTest extends AbstractClientHandleTest { + + private static final YangInstanceIdentifier PATH = YangInstanceIdentifier.builder() + .node(QName.create("ns-1", "node-1")) + .build(); + private static final NormalizedNode DATA = Builders.containerBuilder() + .withNodeIdentifier(YangInstanceIdentifier.NodeIdentifier.create(PATH.getLastPathArgument().getNodeType())) + .build(); + + @Mock + private CursorAwareDataTreeModification modification; + + @Override + @Before + public void setUp() throws Exception { + super.setUp(); + when(getDataTreeSnapshot().newModification()).thenReturn(modification); + when(modification.readNode(PATH)).thenReturn(Optional.of(DATA)); + } + + @Override + protected ClientTransaction createHandle(final AbstractClientHistory parent) { + return parent.createTransaction(); + } + + @Override + protected void doHandleOperation(final ClientTransaction transaction) { + transaction.read(PATH); + } + + @Test + public void testOpenCloseCursor() throws Exception { + final DOMDataTreeWriteCursor cursor = getHandle().openCursor(); + getHandle().closeCursor(cursor); + getHandle().openCursor().delete(PATH.getLastPathArgument()); + verify(modification).delete(PATH); + } + + @Test + public void testOpenSecondCursor() throws Exception { + getHandle().openCursor(); + assertOperationThrowsException(getHandle()::openCursor, IllegalStateException.class); + } + + @Test + public void testExists() throws Exception { + final CheckedFuture exists = getHandle().exists(PATH); + verify(modification).readNode(PATH); + Assert.assertTrue(getWithTimeout(exists)); + } + + @Test + public void testRead() throws Exception { + final CheckedFuture>, ReadFailedException> resultFuture = getHandle().read(PATH); + verify(modification).readNode(PATH); + final Optional> result = getWithTimeout(resultFuture); + Assert.assertTrue(result.isPresent()); + Assert.assertEquals(DATA, result.get()); + } + + @Test + public void testDelete() throws Exception { + getHandle().delete(PATH); + verify(modification).delete(PATH); + } + + @Test + public void testMerge() throws Exception { + getHandle().merge(PATH, DATA); + verify(modification).merge(PATH, DATA); + } + + @Test + public void testWrite() throws Exception { + getHandle().write(PATH, DATA); + verify(modification).write(PATH, DATA); + } + + @Test + public void testReadyEmpty() throws Exception { + final DOMStoreThreePhaseCommitCohort cohort = getHandle().ready(); + assertFutureEquals(true, cohort.canCommit()); + assertFutureEquals(null, cohort.preCommit()); + assertFutureEquals(null, cohort.commit()); + } + + @Test + public void testReady() throws Exception { + getHandle().write(PATH, DATA); + final DOMStoreThreePhaseCommitCohort cohort = getHandle().ready(); + final TransactionCommitSuccess response = new TransactionCommitSuccess(TRANSACTION_ID, 0L); + final ListenableFuture actual = cohort.canCommit(); + final CommitLocalTransactionRequest request = + backendRespondToRequest(CommitLocalTransactionRequest.class, response); + Assert.assertEquals(modification, request.getModification()); + assertFutureEquals(true, actual); + assertFutureEquals(null, cohort.preCommit()); + assertFutureEquals(null, cohort.commit()); + } + + @Test + public void testReadyNoFurtherOperationsAllowed() throws Exception { + getHandle().ready(); + checkClosed(); + } + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/databroker/actors/dds/TestUtils.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/databroker/actors/dds/TestUtils.java new file mode 100644 index 0000000000..d713ba4d3c --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/databroker/actors/dds/TestUtils.java @@ -0,0 +1,86 @@ +/* + * 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.Future; +import java.util.concurrent.TimeUnit; +import org.junit.Assert; + +class TestUtils { + + @FunctionalInterface + public interface RunnableWithException { + void run() throws Exception; + } + + private static final long TIMEOUT = 3; + + /** + * Asserts, that future result when it completes is equal to given object. + * Future must complete in {@link TestUtils#TIMEOUT} seconds. + * + * @param expected expected result + * @param actual future + * @param type + * @throws Exception exception + */ + static void assertFutureEquals(final T expected, final Future actual) throws Exception { + Assert.assertEquals(expected, getWithTimeout(actual)); + } + + /** + * Calls {@link Future#get(long, TimeUnit)} with {@link TestUtils#TIMEOUT} in seconds. + * + * @param future future + * @param type + * @return future result + * @throws Exception exception + */ + static T getWithTimeout(final Future future) throws Exception { + return future.get(TIMEOUT, TimeUnit.SECONDS); + } + + /** + * Asserts that given operation invocation, will throw an exception of given class. + * + * @param operation operation + * @param expectedException expected exception class + * @param message message, when expected exception isn't thrown + * @return expected exception instance. Can be used for additional assertions. + * @throws Exception unexpected exception. + */ + //Throwable is propagated if doesn't match the expected type + @SuppressWarnings("checkstyle:IllegalCatch") + static Throwable assertOperationThrowsException(final RunnableWithException operation, + final Class expectedException, + final String message) throws Exception { + try { + operation.run(); + throw new AssertionError(message + expectedException); + } catch (final Throwable e) { + if (!e.getClass().equals(expectedException)) { + throw e; + } + return e; + } + } + + /** + * Asserts, that when given operation is run, exception of given class is thrown. + * + * @param operation operation + * @param expectedException expected exception class + * @return expected exception instance. Can be used for additional assertions. + * @throws Exception unexpected exception. + */ + static Throwable assertOperationThrowsException(final RunnableWithException operation, + final Class expectedException) + throws Exception { + return assertOperationThrowsException(operation, expectedException, "Operation should throw exception: "); + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/databroker/actors/dds/VotingFutureTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/databroker/actors/dds/VotingFutureTest.java index 85d6582ecf..c2c55a4a73 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/databroker/actors/dds/VotingFutureTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/databroker/actors/dds/VotingFutureTest.java @@ -7,6 +7,10 @@ */ package org.opendaylight.controller.cluster.databroker.actors.dds; +import static org.opendaylight.controller.cluster.databroker.actors.dds.TestUtils.assertFutureEquals; +import static org.opendaylight.controller.cluster.databroker.actors.dds.TestUtils.assertOperationThrowsException; +import static org.opendaylight.controller.cluster.databroker.actors.dds.TestUtils.getWithTimeout; + import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.Future; @@ -20,8 +24,6 @@ import org.junit.Test; public class VotingFutureTest { - private static final int TIMEOUT = 3; - private Object result; private ScheduledExecutorService executor; private VotingFuture future; @@ -42,7 +44,7 @@ public class VotingFutureTest { public void testTrivialCases() throws Exception { final VotingFuture oneYesVoteFuture = new VotingFuture<>(result, 1); oneYesVoteFuture.voteYes(); - checkSuccess(oneYesVoteFuture, result); + assertFutureEquals(result, oneYesVoteFuture); final VotingFuture oneNoVoteFuture = new VotingFuture<>(result, 1); final RuntimeException cause = new RuntimeException("fail"); oneNoVoteFuture.voteNo(cause); @@ -54,7 +56,7 @@ public class VotingFutureTest { future.voteYes(); future.voteYes(); future.voteYes(); - checkSuccess(future, result); + assertFutureEquals(result, future); } @Test @@ -66,7 +68,7 @@ public class VotingFutureTest { voted.set(true); future.voteYes(); }, 1, TimeUnit.SECONDS); - checkSuccess(future, result); + assertFutureEquals(result, future); Assert.assertTrue("Future completed before vote", voted.get()); } @@ -118,30 +120,18 @@ public class VotingFutureTest { 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()); - } + final Throwable thrown = assertOperationThrowsException(() -> getWithTimeout(future), ExecutionException.class); + //first no is set as cause + Assert.assertEquals(cause1, thrown.getCause()); + //subsequent no causes are added as suppressed + final Throwable[] suppressed = thrown.getCause().getSuppressed(); + Assert.assertEquals(1, suppressed.length); + Assert.assertEquals(cause2, suppressed[0]); } - private static void checkSuccess(final Future future, final Object result) throws Exception { - Assert.assertEquals(result, future.get(TIMEOUT, TimeUnit.SECONDS)); + private static void checkException(final Future future, final RuntimeException cause) throws Exception { + final Throwable thrown = assertOperationThrowsException(() -> getWithTimeout(future), ExecutionException.class); + Assert.assertEquals(cause, thrown.getCause()); } } \ No newline at end of file -- 2.36.6