BUG-5280: expand ShardDataTree to cover transaction mechanics
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / test / java / org / opendaylight / controller / cluster / datastore / SimpleShardDataTreeCohortTest.java
1 /*
2  * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.cluster.datastore;
9
10 import static org.junit.Assert.assertSame;
11 import static org.mockito.Matchers.any;
12 import static org.mockito.Mockito.doAnswer;
13 import static org.mockito.Mockito.doNothing;
14 import static org.mockito.Mockito.doReturn;
15 import static org.mockito.Mockito.mock;
16 import static org.mockito.Mockito.never;
17 import static org.mockito.Mockito.verify;
18 import static org.mockito.Mockito.verifyNoMoreInteractions;
19 import com.google.common.primitives.UnsignedLong;
20 import com.google.common.util.concurrent.FutureCallback;
21 import com.google.common.util.concurrent.ListenableFuture;
22 import java.util.Collections;
23 import java.util.Optional;
24 import org.junit.Before;
25 import org.junit.Test;
26 import org.mockito.Mock;
27 import org.mockito.MockitoAnnotations;
28 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
29 import org.opendaylight.yangtools.yang.data.api.schema.tree.ConflictingModificationAppliedException;
30 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
31 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateTip;
32 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
33 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
34 import scala.concurrent.Promise;
35
36 /**
37  * Unit tests for SimpleShardDataTreeCohort.
38  *
39  * @author Thomas Pantelis
40  */
41 public class SimpleShardDataTreeCohortTest extends AbstractTest {
42     @Mock
43     private ShardDataTree mockShardDataTree;
44
45     @Mock
46     private DataTreeModification mockModification;
47
48     @Mock
49     private CompositeDataTreeCohort mockUserCohorts;
50
51     @Mock
52     private FutureCallback<DataTreeCandidate> mockPreCallback;
53
54     private SimpleShardDataTreeCohort cohort;
55
56     @Before
57     public void setup() throws Exception {
58         MockitoAnnotations.initMocks(this);
59
60         doNothing().when(mockUserCohorts).commit();
61         doReturn(Optional.empty()).when(mockUserCohorts).abort();
62
63         cohort = new SimpleShardDataTreeCohort(mockShardDataTree, mockModification, nextTransactionId(),
64             mockUserCohorts);
65     }
66
67     @Test
68     public void testCanCommitSuccess() throws Exception {
69         canCommitSuccess();
70     }
71
72     private void canCommitSuccess() {
73         doAnswer(invocation -> {
74             invocation.getArgumentAt(0, SimpleShardDataTreeCohort.class).successfulCanCommit();
75             return null;
76         }).when(mockShardDataTree).startCanCommit(cohort);
77
78         @SuppressWarnings("unchecked")
79         final FutureCallback<Void> callback = mock(FutureCallback.class);
80         cohort.canCommit(callback);
81
82         verify(callback).onSuccess(null);
83         verifyNoMoreInteractions(callback);
84     }
85
86     private void testValidatationPropagates(final Exception cause) throws DataValidationFailedException {
87         doAnswer(invocation -> {
88             invocation.getArgumentAt(0, SimpleShardDataTreeCohort.class).failedCanCommit(cause);
89             return null;
90         }).when(mockShardDataTree).startCanCommit(cohort);
91
92         @SuppressWarnings("unchecked")
93         final FutureCallback<Void> callback = mock(FutureCallback.class);
94         cohort.canCommit(callback);
95
96         verify(callback).onFailure(cause);
97         verifyNoMoreInteractions(callback);
98     }
99
100     @Test
101     public void testCanCommitWithConflictingModEx() throws DataValidationFailedException {
102         testValidatationPropagates(new ConflictingModificationAppliedException(YangInstanceIdentifier.EMPTY, "mock"));
103     }
104
105     @Test
106     public void testCanCommitWithDataValidationEx() throws DataValidationFailedException {
107         testValidatationPropagates(new DataValidationFailedException(YangInstanceIdentifier.EMPTY, "mock"));
108     }
109
110     @Test
111     public void testCanCommitWithIllegalArgumentEx() throws DataValidationFailedException {
112         testValidatationPropagates(new IllegalArgumentException("mock"));
113     }
114
115     private DataTreeCandidateTip preCommitSuccess() {
116         final DataTreeCandidateTip mockCandidate = mock(DataTreeCandidateTip.class);
117         doAnswer(invocation -> {
118             invocation.getArgumentAt(0, SimpleShardDataTreeCohort.class).successfulPreCommit(mockCandidate);
119             return null;
120         }).when(mockShardDataTree).startPreCommit(cohort);
121
122         @SuppressWarnings("unchecked")
123         final FutureCallback<DataTreeCandidate> callback = mock(FutureCallback.class);
124         cohort.preCommit(callback);
125
126         verify(callback).onSuccess(mockCandidate);
127         verifyNoMoreInteractions(callback);
128
129         assertSame("getCandidate", mockCandidate, cohort.getCandidate());
130
131         return mockCandidate;
132     }
133
134     @Test
135     public void testPreCommitAndCommitSuccess() throws Exception {
136         canCommitSuccess();
137         final DataTreeCandidateTip candidate = preCommitSuccess();
138
139         doAnswer(invocation -> {
140             invocation.getArgumentAt(0, SimpleShardDataTreeCohort.class).successfulCommit(UnsignedLong.valueOf(0));
141             return null;
142         }).when(mockShardDataTree).startCommit(cohort, candidate);
143
144         @SuppressWarnings("unchecked")
145         final
146         FutureCallback<UnsignedLong> mockCommitCallback = mock(FutureCallback.class);
147         cohort.commit(mockCommitCallback);
148
149         verify(mockCommitCallback).onSuccess(any(UnsignedLong.class));
150         verifyNoMoreInteractions(mockCommitCallback);
151
152         verify(mockUserCohorts).commit();
153     }
154
155     @Test
156     public void testPreCommitWithIllegalArgumentEx() throws Throwable {
157         canCommitSuccess();
158
159         final Exception cause = new IllegalArgumentException("mock");
160         doAnswer(invocation -> {
161             invocation.getArgumentAt(0, SimpleShardDataTreeCohort.class).failedPreCommit(cause);
162             return null;
163         }).when(mockShardDataTree).startPreCommit(cohort);
164
165         @SuppressWarnings("unchecked")
166         final FutureCallback<DataTreeCandidate> callback = mock(FutureCallback.class);
167         cohort.preCommit(callback);
168
169         verify(callback).onFailure(cause);
170         verifyNoMoreInteractions(callback);
171
172         verify(mockUserCohorts).abort();
173     }
174
175     @Test
176     public void testPreCommitWithReportedFailure() throws Throwable {
177         canCommitSuccess();
178
179         final Exception cause = new IllegalArgumentException("mock");
180         cohort.reportFailure(cause);
181
182         @SuppressWarnings("unchecked")
183         final FutureCallback<DataTreeCandidate> callback = mock(FutureCallback.class);
184         cohort.preCommit(callback);
185
186         verify(callback).onFailure(cause);
187         verifyNoMoreInteractions(callback);
188
189         verify(mockShardDataTree, never()).startPreCommit(cohort);
190     }
191
192     @Test
193     public void testCommitWithIllegalArgumentEx() {
194         canCommitSuccess();
195         final DataTreeCandidateTip candidate = preCommitSuccess();
196
197         final Exception cause = new IllegalArgumentException("mock");
198         doAnswer(invocation -> {
199             invocation.getArgumentAt(0, SimpleShardDataTreeCohort.class).failedCommit(cause);
200             return null;
201         }).when(mockShardDataTree).startCommit(cohort, candidate);
202
203         @SuppressWarnings("unchecked")
204         final FutureCallback<UnsignedLong> callback = mock(FutureCallback.class);
205         cohort.commit(callback);
206
207         verify(callback).onFailure(cause);
208         verifyNoMoreInteractions(callback);
209
210         verify(mockUserCohorts).abort();
211     }
212
213     @Test
214     public void testAbort() throws Exception {
215         doNothing().when(mockShardDataTree).startAbort(cohort);
216
217         cohort.abort().get();
218
219         verify(mockShardDataTree).startAbort(cohort);
220     }
221
222     @Test
223     public void testAbortWithCohorts() throws Exception {
224         doNothing().when(mockShardDataTree).startAbort(cohort);
225
226         final Promise<Iterable<Object>> cohortFuture = akka.dispatch.Futures.promise();
227         doReturn(Optional.of(cohortFuture.future())).when(mockUserCohorts).abort();
228
229         final ListenableFuture<Void> abortFuture = cohort.abort();
230
231         cohortFuture.success(Collections.emptyList());
232
233         abortFuture.get();
234         verify(mockShardDataTree).startAbort(cohort);
235     }
236 }