*/
package org.opendaylight.controller.cluster.datastore;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
-import static org.mockito.Matchers.any;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
-import com.google.common.util.concurrent.ListenableFuture;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import com.google.common.primitives.UnsignedLong;
+import com.google.common.util.concurrent.FutureCallback;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Future;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.opendaylight.controller.md.sal.common.api.data.OptimisticLockFailedException;
-import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.mockito.junit.MockitoJUnitRunner;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.ConflictingModificationAppliedException;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateTip;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.TipProducingDataTree;
+import org.opendaylight.yangtools.yang.data.tree.api.ConflictingModificationAppliedException;
+import org.opendaylight.yangtools.yang.data.tree.api.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.tree.api.DataTreeCandidateTip;
+import org.opendaylight.yangtools.yang.data.tree.api.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.tree.api.DataValidationFailedException;
/**
* Unit tests for SimpleShardDataTreeCohort.
*
* @author Thomas Pantelis
*/
+@RunWith(MockitoJUnitRunner.StrictStubs.class)
public class SimpleShardDataTreeCohortTest extends AbstractTest {
- @Mock
- private TipProducingDataTree mockDataTree;
-
@Mock
private ShardDataTree mockShardDataTree;
@Mock
private DataTreeModification mockModification;
+ @Mock
+ private CompositeDataTreeCohort mockUserCohorts;
+
+ @Mock
+ private FutureCallback<DataTreeCandidate> mockPreCallback;
+
private SimpleShardDataTreeCohort cohort;
@Before
public void setup() {
- MockitoAnnotations.initMocks(this);
+ doReturn(Optional.empty()).when(mockUserCohorts).commit();
+ doReturn(Optional.empty()).when(mockUserCohorts).abort();
- doReturn(mockDataTree).when(mockShardDataTree).getDataTree();
-
- cohort = new SimpleShardDataTreeCohort(mockShardDataTree, mockModification, nextTransactionId());
+ cohort = new SimpleShardDataTreeCohort(mockShardDataTree, mockModification, nextTransactionId(),
+ mockUserCohorts, Optional.empty());
}
@Test
- public void testCanCommitSuccess() throws Exception {
- ListenableFuture<Boolean> future = cohort.canCommit();
- assertNotNull("Future is null", future);
- assertEquals("Future", true, future.get(3, TimeUnit.SECONDS));
- verify(mockDataTree).validate(mockModification);
+ public void testCanCommitSuccess() {
+ canCommitSuccess();
+ }
+
+ private void canCommitSuccess() {
+ doAnswer(invocation -> {
+ invocation.<SimpleShardDataTreeCohort>getArgument(0).successfulCanCommit();
+ return null;
+ }).when(mockShardDataTree).startCanCommit(cohort);
+
+ @SuppressWarnings("unchecked")
+ final FutureCallback<Void> callback = mock(FutureCallback.class);
+ cohort.canCommit(callback);
+
+ verify(callback).onSuccess(null);
+ verifyNoMoreInteractions(callback);
}
- @Test(expected=OptimisticLockFailedException.class)
- public void testCanCommitWithConflictingModEx() throws Throwable {
- doThrow(new ConflictingModificationAppliedException(YangInstanceIdentifier.EMPTY, "mock")).
- when(mockDataTree).validate(mockModification);
- try {
- cohort.canCommit().get();
- } catch (ExecutionException e) {
- throw e.getCause();
- }
+ private void testValidatationPropagates(final Exception cause) {
+ doAnswer(invocation -> {
+ invocation.<SimpleShardDataTreeCohort>getArgument(0).failedCanCommit(cause);
+ return null;
+ }).when(mockShardDataTree).startCanCommit(cohort);
+
+ @SuppressWarnings("unchecked")
+ final FutureCallback<Void> callback = mock(FutureCallback.class);
+ cohort.canCommit(callback);
+
+ verify(callback).onFailure(cause);
+ verifyNoMoreInteractions(callback);
}
- @Test(expected=TransactionCommitFailedException.class)
- public void testCanCommitWithDataValidationEx() throws Throwable {
- doThrow(new DataValidationFailedException(YangInstanceIdentifier.EMPTY, "mock")).
- when(mockDataTree).validate(mockModification);
- try {
- cohort.canCommit().get();
- } catch (ExecutionException e) {
- throw e.getCause();
- }
+ @Test
+ public void testCanCommitWithConflictingModEx() {
+ testValidatationPropagates(new ConflictingModificationAppliedException(YangInstanceIdentifier.empty(), "mock"));
}
- @Test(expected=IllegalArgumentException.class)
- public void testCanCommitWithIllegalArgumentEx() throws Throwable {
- doThrow(new IllegalArgumentException("mock")).when(mockDataTree).validate(mockModification);
- try {
- cohort.canCommit().get();
- } catch (ExecutionException e) {
- throw e.getCause();
- }
+ @Test
+ public void testCanCommitWithDataValidationEx() {
+ testValidatationPropagates(new DataValidationFailedException(YangInstanceIdentifier.empty(), "mock"));
}
@Test
- public void testPreCommitAndCommitSuccess() throws Exception {
- DataTreeCandidateTip mockCandidate = mock(DataTreeCandidateTip.class);
- doReturn(mockCandidate ).when(mockDataTree).prepare(mockModification);
+ public void testCanCommitWithIllegalArgumentEx() {
+ testValidatationPropagates(new IllegalArgumentException("mock"));
+ }
- ListenableFuture<Void> future = cohort.preCommit();
- assertNotNull("Future is null", future);
- future.get();
- verify(mockDataTree).prepare(mockModification);
+ private DataTreeCandidateTip preCommitSuccess() {
+ final DataTreeCandidateTip mockCandidate = mock(DataTreeCandidateTip.class);
+ doAnswer(invocation -> {
+ invocation.<SimpleShardDataTreeCohort>getArgument(0).successfulPreCommit(mockCandidate);
+ return null;
+ }).when(mockShardDataTree).startPreCommit(cohort);
+
+ @SuppressWarnings("unchecked")
+ final FutureCallback<DataTreeCandidate> callback = mock(FutureCallback.class);
+ cohort.preCommit(callback);
+
+ verify(callback).onSuccess(mockCandidate);
+ verifyNoMoreInteractions(callback);
assertSame("getCandidate", mockCandidate, cohort.getCandidate());
- future = cohort.commit();
- assertNotNull("Future is null", future);
- future.get();
- verify(mockDataTree).commit(mockCandidate);
+ return mockCandidate;
+ }
+
+ @Test
+ public void testPreCommitAndCommitSuccess() {
+ canCommitSuccess();
+ final DataTreeCandidateTip candidate = preCommitSuccess();
+
+ doAnswer(invocation -> {
+ invocation.<SimpleShardDataTreeCohort>getArgument(0).successfulCommit(UnsignedLong.valueOf(0), () -> { });
+ return null;
+ }).when(mockShardDataTree).startCommit(cohort, candidate);
+
+ @SuppressWarnings("unchecked")
+ final FutureCallback<UnsignedLong> mockCommitCallback = mock(FutureCallback.class);
+ cohort.commit(mockCommitCallback);
+
+ verify(mockCommitCallback).onSuccess(any(UnsignedLong.class));
+ verifyNoMoreInteractions(mockCommitCallback);
+
+ verify(mockUserCohorts).commit();
}
- @Test(expected=IllegalArgumentException.class)
- public void testPreCommitWithIllegalArgumentEx() throws Throwable {
- doThrow(new IllegalArgumentException("mock")).when(mockDataTree).prepare(mockModification);
- try {
- cohort.preCommit().get();
- } catch (ExecutionException e) {
- throw e.getCause();
- }
+ @Test
+ public void testPreCommitWithIllegalArgumentEx() {
+ canCommitSuccess();
+
+ final Exception cause = new IllegalArgumentException("mock");
+ doAnswer(invocation -> {
+ invocation.<SimpleShardDataTreeCohort>getArgument(0).failedPreCommit(cause);
+ return null;
+ }).when(mockShardDataTree).startPreCommit(cohort);
+
+ @SuppressWarnings("unchecked")
+ final FutureCallback<DataTreeCandidate> callback = mock(FutureCallback.class);
+ cohort.preCommit(callback);
+
+ verify(callback).onFailure(cause);
+ verifyNoMoreInteractions(callback);
+
+ verify(mockUserCohorts).abort();
+ }
+
+ @Test
+ public void testPreCommitWithReportedFailure() {
+ canCommitSuccess();
+
+ final Exception cause = new IllegalArgumentException("mock");
+ cohort.reportFailure(cause);
+
+ @SuppressWarnings("unchecked")
+ final FutureCallback<DataTreeCandidate> callback = mock(FutureCallback.class);
+ cohort.preCommit(callback);
+
+ verify(callback).onFailure(cause);
+ verifyNoMoreInteractions(callback);
+
+ verify(mockShardDataTree, never()).startPreCommit(cohort);
+ }
+
+ @Test
+ public void testCommitWithIllegalArgumentEx() {
+ canCommitSuccess();
+ final DataTreeCandidateTip candidate = preCommitSuccess();
+
+ final Exception cause = new IllegalArgumentException("mock");
+ doAnswer(invocation -> {
+ invocation.<SimpleShardDataTreeCohort>getArgument(0).failedCommit(cause);
+ return null;
+ }).when(mockShardDataTree).startCommit(cohort, candidate);
+
+ @SuppressWarnings("unchecked")
+ final FutureCallback<UnsignedLong> callback = mock(FutureCallback.class);
+ cohort.commit(callback);
+
+ verify(callback).onFailure(cause);
+ verifyNoMoreInteractions(callback);
+
+ verify(mockUserCohorts).abort();
}
- @Test(expected=IllegalArgumentException.class)
- public void testCommitWithIllegalArgumentEx() throws Throwable {
- doThrow(new IllegalArgumentException("mock")).when(mockDataTree).commit(any(DataTreeCandidateTip.class));
- try {
- cohort.commit().get();
- } catch (ExecutionException e) {
- throw e.getCause();
- }
+ private static Future<?> abort(final ShardDataTreeCohort cohort) {
+ final CompletableFuture<Void> f = new CompletableFuture<>();
+ cohort.abort(new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(final Void result) {
+ f.complete(null);
+ }
+
+ @Override
+ public void onFailure(final Throwable failure) {
+ f.completeExceptionally(failure);
+ }
+ });
+
+ return f;
}
@Test
public void testAbort() throws Exception {
- cohort.abort().get();
+ doReturn(Boolean.TRUE).when(mockShardDataTree).startAbort(cohort);
+
+ abort(cohort).get();
+ verify(mockShardDataTree).startAbort(cohort);
+ }
+
+ @Test
+ public void testAbortWithCohorts() throws Exception {
+ doReturn(true).when(mockShardDataTree).startAbort(cohort);
+
+ doReturn(Optional.of(CompletableFuture.completedFuture(null))).when(mockUserCohorts).abort();
+
+ final Future<?> abortFuture = abort(cohort);
+
+ abortFuture.get();
+ verify(mockShardDataTree).startAbort(cohort);
}
}