2 * Copyright (c) 2015 Cisco Systems, Inc. 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
9 package org.opendaylight.controller.cluster.datastore;
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.fail;
14 import static org.mockito.Matchers.any;
15 import static org.mockito.Matchers.anyBoolean;
16 import static org.mockito.Matchers.eq;
17 import static org.mockito.Mockito.atLeastOnce;
18 import static org.mockito.Mockito.doNothing;
19 import static org.mockito.Mockito.doReturn;
20 import static org.mockito.Mockito.inOrder;
21 import static org.mockito.Mockito.mock;
22 import static org.mockito.Mockito.never;
23 import static org.mockito.Mockito.reset;
24 import static org.mockito.Mockito.verify;
25 import static org.mockito.Mockito.verifyNoMoreInteractions;
26 import static org.opendaylight.controller.cluster.datastore.ShardDataTreeMocking.coordinatedCanCommit;
27 import static org.opendaylight.controller.cluster.datastore.ShardDataTreeMocking.coordinatedCommit;
28 import static org.opendaylight.controller.cluster.datastore.ShardDataTreeMocking.coordinatedPreCommit;
29 import static org.opendaylight.controller.cluster.datastore.ShardDataTreeMocking.immediate3PhaseCommit;
30 import static org.opendaylight.controller.cluster.datastore.ShardDataTreeMocking.immediateCanCommit;
31 import static org.opendaylight.controller.cluster.datastore.ShardDataTreeMocking.immediateCommit;
32 import static org.opendaylight.controller.cluster.datastore.ShardDataTreeMocking.immediatePayloadReplication;
33 import static org.opendaylight.controller.cluster.datastore.ShardDataTreeMocking.immediatePreCommit;
35 import com.google.common.base.Ticker;
36 import com.google.common.collect.Maps;
37 import com.google.common.primitives.UnsignedLong;
38 import com.google.common.util.concurrent.FutureCallback;
39 import java.math.BigInteger;
40 import java.util.ArrayList;
41 import java.util.Collection;
42 import java.util.List;
44 import java.util.Optional;
45 import java.util.function.Consumer;
46 import org.junit.Before;
47 import org.junit.Test;
48 import org.mockito.ArgumentCaptor;
49 import org.mockito.InOrder;
50 import org.mockito.Mockito;
51 import org.opendaylight.controller.cluster.datastore.jmx.mbeans.shard.ShardStats;
52 import org.opendaylight.controller.cluster.datastore.persisted.CommitTransactionPayload;
53 import org.opendaylight.controller.md.cluster.datastore.model.CarsModel;
54 import org.opendaylight.controller.md.cluster.datastore.model.PeopleModel;
55 import org.opendaylight.controller.md.cluster.datastore.model.SchemaContextHelper;
56 import org.opendaylight.mdsal.dom.api.DOMDataTreeChangeListener;
57 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
58 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
59 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
60 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
61 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidates;
62 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
63 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
64 import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
65 import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType;
66 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
68 public class ShardDataTreeTest extends AbstractTest {
70 private final Shard mockShard = Mockito.mock(Shard.class);
71 private ShardDataTree shardDataTree;
72 private SchemaContext fullSchema;
76 doReturn(Ticker.systemTicker()).when(mockShard).ticker();
77 doReturn(Mockito.mock(ShardStats.class)).when(mockShard).getShardMBean();
79 fullSchema = SchemaContextHelper.full();
81 shardDataTree = new ShardDataTree(mockShard, fullSchema, TreeType.OPERATIONAL);
85 public void testWrite() {
86 modify(false, true, true);
90 public void testMerge() {
91 modify(true, true, true);
94 private void modify(final boolean merge, final boolean expectedCarsPresent, final boolean expectedPeoplePresent) {
95 immediatePayloadReplication(shardDataTree, mockShard);
97 assertEquals(fullSchema, shardDataTree.getSchemaContext());
99 final ReadWriteShardDataTreeTransaction transaction =
100 shardDataTree.newReadWriteTransaction(nextTransactionId());
102 final DataTreeModification snapshot = transaction.getSnapshot();
104 assertNotNull(snapshot);
107 snapshot.merge(CarsModel.BASE_PATH, CarsModel.create());
108 snapshot.merge(PeopleModel.BASE_PATH, PeopleModel.create());
110 snapshot.write(CarsModel.BASE_PATH, CarsModel.create());
111 snapshot.write(PeopleModel.BASE_PATH, PeopleModel.create());
114 final ShardDataTreeCohort cohort = shardDataTree.finishTransaction(transaction, Optional.empty());
116 immediateCanCommit(cohort);
117 immediatePreCommit(cohort);
118 immediateCommit(cohort);
120 final ReadOnlyShardDataTreeTransaction readOnlyShardDataTreeTransaction =
121 shardDataTree.newReadOnlyTransaction(nextTransactionId());
123 final DataTreeSnapshot snapshot1 = readOnlyShardDataTreeTransaction.getSnapshot();
125 final Optional<NormalizedNode<?, ?>> optional = snapshot1.readNode(CarsModel.BASE_PATH);
127 assertEquals(expectedCarsPresent, optional.isPresent());
129 final Optional<NormalizedNode<?, ?>> optional1 = snapshot1.readNode(PeopleModel.BASE_PATH);
131 assertEquals(expectedPeoplePresent, optional1.isPresent());
135 public void bug4359AddRemoveCarOnce() {
136 immediatePayloadReplication(shardDataTree, mockShard);
138 final List<DataTreeCandidate> candidates = new ArrayList<>();
139 candidates.add(addCar(shardDataTree));
140 candidates.add(removeCar(shardDataTree));
142 final NormalizedNode<?, ?> expected = getCars(shardDataTree);
144 applyCandidates(shardDataTree, candidates);
146 final NormalizedNode<?, ?> actual = getCars(shardDataTree);
148 assertEquals(expected, actual);
152 public void bug4359AddRemoveCarTwice() {
153 immediatePayloadReplication(shardDataTree, mockShard);
155 final List<DataTreeCandidate> candidates = new ArrayList<>();
156 candidates.add(addCar(shardDataTree));
157 candidates.add(removeCar(shardDataTree));
158 candidates.add(addCar(shardDataTree));
159 candidates.add(removeCar(shardDataTree));
161 final NormalizedNode<?, ?> expected = getCars(shardDataTree);
163 applyCandidates(shardDataTree, candidates);
165 final NormalizedNode<?, ?> actual = getCars(shardDataTree);
167 assertEquals(expected, actual);
171 public void testListenerNotifiedOnApplySnapshot() throws Exception {
172 immediatePayloadReplication(shardDataTree, mockShard);
174 DOMDataTreeChangeListener listener = mock(DOMDataTreeChangeListener.class);
175 shardDataTree.registerTreeChangeListener(CarsModel.CAR_LIST_PATH.node(CarsModel.CAR_QNAME), listener,
176 com.google.common.base.Optional.absent(), noop -> { });
178 addCar(shardDataTree, "optima");
180 verifyOnDataTreeChanged(listener, dtc -> {
181 assertEquals("getModificationType", ModificationType.WRITE, dtc.getRootNode().getModificationType());
182 assertEquals("getRootPath", CarsModel.newCarPath("optima"), dtc.getRootPath());
185 addCar(shardDataTree, "sportage");
187 verifyOnDataTreeChanged(listener, dtc -> {
188 assertEquals("getModificationType", ModificationType.WRITE, dtc.getRootNode().getModificationType());
189 assertEquals("getRootPath", CarsModel.newCarPath("sportage"), dtc.getRootPath());
192 ShardDataTree newDataTree = new ShardDataTree(mockShard, fullSchema, TreeType.OPERATIONAL);
193 immediatePayloadReplication(newDataTree, mockShard);
194 addCar(newDataTree, "optima");
195 addCar(newDataTree, "murano");
197 shardDataTree.applySnapshot(newDataTree.takeStateSnapshot());
199 Map<YangInstanceIdentifier, ModificationType> expChanges = Maps.newHashMap();
200 expChanges.put(CarsModel.newCarPath("optima"), ModificationType.WRITE);
201 expChanges.put(CarsModel.newCarPath("murano"), ModificationType.WRITE);
202 expChanges.put(CarsModel.newCarPath("sportage"), ModificationType.DELETE);
203 verifyOnDataTreeChanged(listener, dtc -> {
204 ModificationType expType = expChanges.remove(dtc.getRootPath());
205 assertNotNull("Got unexpected change for " + dtc.getRootPath(), expType);
206 assertEquals("getModificationType", expType, dtc.getRootNode().getModificationType());
209 if (!expChanges.isEmpty()) {
210 fail("Missing change notifications: " + expChanges);
215 public void testPipelinedTransactionsWithCoordinatedCommits() throws Exception {
216 final ShardDataTreeCohort cohort1 = newShardDataTreeCohort(snapshot ->
217 snapshot.write(CarsModel.BASE_PATH, CarsModel.emptyContainer()));
219 final ShardDataTreeCohort cohort2 = newShardDataTreeCohort(snapshot ->
220 snapshot.write(CarsModel.CAR_LIST_PATH, CarsModel.newCarMapNode()));
222 NormalizedNode<?, ?> peopleNode = PeopleModel.create();
223 final ShardDataTreeCohort cohort3 = newShardDataTreeCohort(snapshot ->
224 snapshot.write(PeopleModel.BASE_PATH, peopleNode));
226 YangInstanceIdentifier carPath = CarsModel.newCarPath("optima");
227 MapEntryNode carNode = CarsModel.newCarEntry("optima", new BigInteger("100"));
228 final ShardDataTreeCohort cohort4 = newShardDataTreeCohort(snapshot -> snapshot.write(carPath, carNode));
230 immediateCanCommit(cohort1);
231 final FutureCallback<Void> canCommitCallback2 = coordinatedCanCommit(cohort2);
232 final FutureCallback<Void> canCommitCallback3 = coordinatedCanCommit(cohort3);
233 final FutureCallback<Void> canCommitCallback4 = coordinatedCanCommit(cohort4);
235 final FutureCallback<DataTreeCandidate> preCommitCallback1 = coordinatedPreCommit(cohort1);
236 verify(preCommitCallback1).onSuccess(cohort1.getCandidate());
237 verify(canCommitCallback2).onSuccess(null);
239 final FutureCallback<DataTreeCandidate> preCommitCallback2 = coordinatedPreCommit(cohort2);
240 verify(preCommitCallback2).onSuccess(cohort2.getCandidate());
241 verify(canCommitCallback3).onSuccess(null);
243 final FutureCallback<DataTreeCandidate> preCommitCallback3 = coordinatedPreCommit(cohort3);
244 verify(preCommitCallback3).onSuccess(cohort3.getCandidate());
245 verify(canCommitCallback4).onSuccess(null);
247 final FutureCallback<DataTreeCandidate> preCommitCallback4 = coordinatedPreCommit(cohort4);
248 verify(preCommitCallback4).onSuccess(cohort4.getCandidate());
250 final FutureCallback<UnsignedLong> commitCallback2 = coordinatedCommit(cohort2);
251 verify(mockShard, never()).persistPayload(eq(cohort1.getIdentifier()), any(CommitTransactionPayload.class),
253 verifyNoMoreInteractions(commitCallback2);
255 final FutureCallback<UnsignedLong> commitCallback4 = coordinatedCommit(cohort4);
256 verify(mockShard, never()).persistPayload(eq(cohort4.getIdentifier()), any(CommitTransactionPayload.class),
258 verifyNoMoreInteractions(commitCallback4);
260 final FutureCallback<UnsignedLong> commitCallback1 = coordinatedCommit(cohort1);
261 InOrder inOrder = inOrder(mockShard);
262 inOrder.verify(mockShard).persistPayload(eq(cohort1.getIdentifier()), any(CommitTransactionPayload.class),
264 inOrder.verify(mockShard).persistPayload(eq(cohort2.getIdentifier()), any(CommitTransactionPayload.class),
266 verifyNoMoreInteractions(commitCallback1);
267 verifyNoMoreInteractions(commitCallback2);
269 final FutureCallback<UnsignedLong> commitCallback3 = coordinatedCommit(cohort3);
270 inOrder = inOrder(mockShard);
271 inOrder.verify(mockShard).persistPayload(eq(cohort3.getIdentifier()), any(CommitTransactionPayload.class),
273 inOrder.verify(mockShard).persistPayload(eq(cohort4.getIdentifier()), any(CommitTransactionPayload.class),
275 verifyNoMoreInteractions(commitCallback3);
276 verifyNoMoreInteractions(commitCallback4);
278 final ShardDataTreeCohort cohort5 = newShardDataTreeCohort(snapshot ->
279 snapshot.merge(CarsModel.BASE_PATH, CarsModel.emptyContainer()));
280 final FutureCallback<Void> canCommitCallback5 = coordinatedCanCommit(cohort5);
282 // The payload instance doesn't matter - it just needs to be of type CommitTransactionPayload.
283 CommitTransactionPayload mockPayload = CommitTransactionPayload.create(nextTransactionId(),
284 cohort1.getCandidate());
285 shardDataTree.applyReplicatedPayload(cohort1.getIdentifier(), mockPayload);
286 shardDataTree.applyReplicatedPayload(cohort2.getIdentifier(), mockPayload);
287 shardDataTree.applyReplicatedPayload(cohort3.getIdentifier(), mockPayload);
288 shardDataTree.applyReplicatedPayload(cohort4.getIdentifier(), mockPayload);
290 inOrder = inOrder(commitCallback1, commitCallback2, commitCallback3, commitCallback4);
291 inOrder.verify(commitCallback1).onSuccess(any(UnsignedLong.class));
292 inOrder.verify(commitCallback2).onSuccess(any(UnsignedLong.class));
293 inOrder.verify(commitCallback3).onSuccess(any(UnsignedLong.class));
294 inOrder.verify(commitCallback4).onSuccess(any(UnsignedLong.class));
296 verify(canCommitCallback5).onSuccess(null);
298 final DataTreeSnapshot snapshot =
299 shardDataTree.newReadOnlyTransaction(nextTransactionId()).getSnapshot();
300 Optional<NormalizedNode<?, ?>> optional = snapshot.readNode(carPath);
301 assertEquals("Car node present", true, optional.isPresent());
302 assertEquals("Car node", carNode, optional.get());
304 optional = snapshot.readNode(PeopleModel.BASE_PATH);
305 assertEquals("People node present", true, optional.isPresent());
306 assertEquals("People node", peopleNode, optional.get());
310 public void testPipelinedTransactionsWithImmediateCommits() throws Exception {
311 final ShardDataTreeCohort cohort1 = newShardDataTreeCohort(snapshot ->
312 snapshot.write(CarsModel.BASE_PATH, CarsModel.emptyContainer()));
314 final ShardDataTreeCohort cohort2 = newShardDataTreeCohort(snapshot ->
315 snapshot.write(CarsModel.CAR_LIST_PATH, CarsModel.newCarMapNode()));
317 YangInstanceIdentifier carPath = CarsModel.newCarPath("optima");
318 MapEntryNode carNode = CarsModel.newCarEntry("optima", new BigInteger("100"));
319 final ShardDataTreeCohort cohort3 = newShardDataTreeCohort(snapshot -> snapshot.write(carPath, carNode));
321 final FutureCallback<UnsignedLong> commitCallback2 = immediate3PhaseCommit(cohort2);
322 final FutureCallback<UnsignedLong> commitCallback3 = immediate3PhaseCommit(cohort3);
323 final FutureCallback<UnsignedLong> commitCallback1 = immediate3PhaseCommit(cohort1);
325 InOrder inOrder = inOrder(mockShard);
326 inOrder.verify(mockShard).persistPayload(eq(cohort1.getIdentifier()), any(CommitTransactionPayload.class),
328 inOrder.verify(mockShard).persistPayload(eq(cohort2.getIdentifier()), any(CommitTransactionPayload.class),
330 inOrder.verify(mockShard).persistPayload(eq(cohort3.getIdentifier()), any(CommitTransactionPayload.class),
333 // The payload instance doesn't matter - it just needs to be of type CommitTransactionPayload.
334 CommitTransactionPayload mockPayload = CommitTransactionPayload.create(nextTransactionId(),
335 cohort1.getCandidate());
336 shardDataTree.applyReplicatedPayload(cohort1.getIdentifier(), mockPayload);
337 shardDataTree.applyReplicatedPayload(cohort2.getIdentifier(), mockPayload);
338 shardDataTree.applyReplicatedPayload(cohort3.getIdentifier(), mockPayload);
340 inOrder = inOrder(commitCallback1, commitCallback2, commitCallback3);
341 inOrder.verify(commitCallback1).onSuccess(any(UnsignedLong.class));
342 inOrder.verify(commitCallback2).onSuccess(any(UnsignedLong.class));
343 inOrder.verify(commitCallback3).onSuccess(any(UnsignedLong.class));
345 final DataTreeSnapshot snapshot =
346 shardDataTree.newReadOnlyTransaction(nextTransactionId()).getSnapshot();
347 Optional<NormalizedNode<?, ?>> optional = snapshot.readNode(carPath);
348 assertEquals("Car node present", true, optional.isPresent());
349 assertEquals("Car node", carNode, optional.get());
353 public void testPipelinedTransactionsWithImmediateReplication() {
354 immediatePayloadReplication(shardDataTree, mockShard);
356 final ShardDataTreeCohort cohort1 = newShardDataTreeCohort(snapshot ->
357 snapshot.write(CarsModel.BASE_PATH, CarsModel.emptyContainer()));
359 final ShardDataTreeCohort cohort2 = newShardDataTreeCohort(snapshot ->
360 snapshot.write(CarsModel.CAR_LIST_PATH, CarsModel.newCarMapNode()));
362 YangInstanceIdentifier carPath = CarsModel.newCarPath("optima");
363 MapEntryNode carNode = CarsModel.newCarEntry("optima", new BigInteger("100"));
364 final ShardDataTreeCohort cohort3 = newShardDataTreeCohort(snapshot -> snapshot.write(carPath, carNode));
366 final FutureCallback<UnsignedLong> commitCallback1 = immediate3PhaseCommit(cohort1);
367 final FutureCallback<UnsignedLong> commitCallback2 = immediate3PhaseCommit(cohort2);
368 final FutureCallback<UnsignedLong> commitCallback3 = immediate3PhaseCommit(cohort3);
370 InOrder inOrder = inOrder(commitCallback1, commitCallback2, commitCallback3);
371 inOrder.verify(commitCallback1).onSuccess(any(UnsignedLong.class));
372 inOrder.verify(commitCallback2).onSuccess(any(UnsignedLong.class));
373 inOrder.verify(commitCallback3).onSuccess(any(UnsignedLong.class));
375 final DataTreeSnapshot snapshot =
376 shardDataTree.newReadOnlyTransaction(nextTransactionId()).getSnapshot();
377 Optional<NormalizedNode<?, ?>> optional = snapshot.readNode(CarsModel.BASE_PATH);
378 assertEquals("Car node present", true, optional.isPresent());
381 @SuppressWarnings("unchecked")
383 public void testAbortWithPendingCommits() throws Exception {
384 final ShardDataTreeCohort cohort1 = newShardDataTreeCohort(snapshot ->
385 snapshot.write(CarsModel.BASE_PATH, CarsModel.emptyContainer()));
387 final ShardDataTreeCohort cohort2 = newShardDataTreeCohort(snapshot ->
388 snapshot.write(PeopleModel.BASE_PATH, PeopleModel.create()));
390 final ShardDataTreeCohort cohort3 = newShardDataTreeCohort(snapshot ->
391 snapshot.write(CarsModel.CAR_LIST_PATH, CarsModel.newCarMapNode()));
393 YangInstanceIdentifier carPath = CarsModel.newCarPath("optima");
394 MapEntryNode carNode = CarsModel.newCarEntry("optima", new BigInteger("100"));
395 final ShardDataTreeCohort cohort4 = newShardDataTreeCohort(snapshot -> snapshot.write(carPath, carNode));
397 coordinatedCanCommit(cohort2);
398 immediateCanCommit(cohort1);
399 coordinatedCanCommit(cohort3);
400 coordinatedCanCommit(cohort4);
402 coordinatedPreCommit(cohort1);
403 coordinatedPreCommit(cohort2);
404 coordinatedPreCommit(cohort3);
406 FutureCallback<Void> mockAbortCallback = mock(FutureCallback.class);
407 doNothing().when(mockAbortCallback).onSuccess(null);
408 cohort2.abort(mockAbortCallback);
409 verify(mockAbortCallback).onSuccess(null);
411 coordinatedPreCommit(cohort4);
412 coordinatedCommit(cohort1);
413 coordinatedCommit(cohort3);
414 coordinatedCommit(cohort4);
416 InOrder inOrder = inOrder(mockShard);
417 inOrder.verify(mockShard).persistPayload(eq(cohort1.getIdentifier()), any(CommitTransactionPayload.class),
419 inOrder.verify(mockShard).persistPayload(eq(cohort3.getIdentifier()), any(CommitTransactionPayload.class),
421 inOrder.verify(mockShard).persistPayload(eq(cohort4.getIdentifier()), any(CommitTransactionPayload.class),
424 // The payload instance doesn't matter - it just needs to be of type CommitTransactionPayload.
425 CommitTransactionPayload mockPayload = CommitTransactionPayload.create(nextTransactionId(),
426 cohort1.getCandidate());
427 shardDataTree.applyReplicatedPayload(cohort1.getIdentifier(), mockPayload);
428 shardDataTree.applyReplicatedPayload(cohort3.getIdentifier(), mockPayload);
429 shardDataTree.applyReplicatedPayload(cohort4.getIdentifier(), mockPayload);
431 final DataTreeSnapshot snapshot =
432 shardDataTree.newReadOnlyTransaction(nextTransactionId()).getSnapshot();
433 Optional<NormalizedNode<?, ?>> optional = snapshot.readNode(carPath);
434 assertEquals("Car node present", true, optional.isPresent());
435 assertEquals("Car node", carNode, optional.get());
438 @SuppressWarnings("unchecked")
440 public void testAbortWithFailedRebase() {
441 immediatePayloadReplication(shardDataTree, mockShard);
443 final ShardDataTreeCohort cohort1 = newShardDataTreeCohort(snapshot ->
444 snapshot.write(CarsModel.BASE_PATH, CarsModel.emptyContainer()));
446 final ShardDataTreeCohort cohort2 = newShardDataTreeCohort(snapshot ->
447 snapshot.write(CarsModel.CAR_LIST_PATH, CarsModel.newCarMapNode()));
449 NormalizedNode<?, ?> peopleNode = PeopleModel.create();
450 final ShardDataTreeCohort cohort3 = newShardDataTreeCohort(snapshot ->
451 snapshot.write(PeopleModel.BASE_PATH, peopleNode));
453 immediateCanCommit(cohort1);
454 FutureCallback<Void> canCommitCallback2 = coordinatedCanCommit(cohort2);
456 coordinatedPreCommit(cohort1);
457 verify(canCommitCallback2).onSuccess(null);
459 FutureCallback<Void> mockAbortCallback = mock(FutureCallback.class);
460 doNothing().when(mockAbortCallback).onSuccess(null);
461 cohort1.abort(mockAbortCallback);
462 verify(mockAbortCallback).onSuccess(null);
464 FutureCallback<DataTreeCandidate> preCommitCallback2 = coordinatedPreCommit(cohort2);
465 verify(preCommitCallback2).onFailure(any(Throwable.class));
467 immediateCanCommit(cohort3);
468 immediatePreCommit(cohort3);
469 immediateCommit(cohort3);
471 final DataTreeSnapshot snapshot =
472 shardDataTree.newReadOnlyTransaction(nextTransactionId()).getSnapshot();
473 Optional<NormalizedNode<?, ?>> optional = snapshot.readNode(PeopleModel.BASE_PATH);
474 assertEquals("People node present", true, optional.isPresent());
475 assertEquals("People node", peopleNode, optional.get());
478 private ShardDataTreeCohort newShardDataTreeCohort(final DataTreeOperation operation) {
479 final ReadWriteShardDataTreeTransaction transaction =
480 shardDataTree.newReadWriteTransaction(nextTransactionId());
481 final DataTreeModification snapshot = transaction.getSnapshot();
482 operation.execute(snapshot);
483 return shardDataTree.finishTransaction(transaction, Optional.empty());
486 @SuppressWarnings({ "rawtypes", "unchecked" })
487 private static void verifyOnDataTreeChanged(final DOMDataTreeChangeListener listener,
488 final Consumer<DataTreeCandidate> callback) {
489 ArgumentCaptor<Collection> changes = ArgumentCaptor.forClass(Collection.class);
490 verify(listener, atLeastOnce()).onDataTreeChanged(changes.capture());
491 for (Collection list : changes.getAllValues()) {
492 for (Object dtc : list) {
493 callback.accept((DataTreeCandidate)dtc);
500 private static NormalizedNode<?, ?> getCars(final ShardDataTree shardDataTree) {
501 final ReadOnlyShardDataTreeTransaction readOnlyShardDataTreeTransaction =
502 shardDataTree.newReadOnlyTransaction(nextTransactionId());
503 final DataTreeSnapshot snapshot1 = readOnlyShardDataTreeTransaction.getSnapshot();
505 final Optional<NormalizedNode<?, ?>> optional = snapshot1.readNode(CarsModel.BASE_PATH);
507 assertEquals(true, optional.isPresent());
509 return optional.get();
512 private static DataTreeCandidate addCar(final ShardDataTree shardDataTree) {
513 return addCar(shardDataTree, "altima");
516 private static DataTreeCandidate addCar(final ShardDataTree shardDataTree, final String name) {
517 return doTransaction(shardDataTree, snapshot -> {
518 snapshot.merge(CarsModel.BASE_PATH, CarsModel.emptyContainer());
519 snapshot.merge(CarsModel.CAR_LIST_PATH, CarsModel.newCarMapNode());
520 snapshot.write(CarsModel.newCarPath(name), CarsModel.newCarEntry(name, new BigInteger("100")));
524 private static DataTreeCandidate removeCar(final ShardDataTree shardDataTree) {
525 return doTransaction(shardDataTree, snapshot -> snapshot.delete(CarsModel.newCarPath("altima")));
529 private interface DataTreeOperation {
530 void execute(DataTreeModification snapshot);
533 private static DataTreeCandidate doTransaction(final ShardDataTree shardDataTree,
534 final DataTreeOperation operation) {
535 final ReadWriteShardDataTreeTransaction transaction =
536 shardDataTree.newReadWriteTransaction(nextTransactionId());
537 final DataTreeModification snapshot = transaction.getSnapshot();
538 operation.execute(snapshot);
539 final ShardDataTreeCohort cohort = shardDataTree.finishTransaction(transaction, Optional.empty());
541 immediateCanCommit(cohort);
542 immediatePreCommit(cohort);
543 final DataTreeCandidate candidate = cohort.getCandidate();
544 immediateCommit(cohort);
549 private static DataTreeCandidate applyCandidates(final ShardDataTree shardDataTree,
550 final List<DataTreeCandidate> candidates) {
551 final ReadWriteShardDataTreeTransaction transaction =
552 shardDataTree.newReadWriteTransaction(nextTransactionId());
553 final DataTreeModification snapshot = transaction.getSnapshot();
554 for (final DataTreeCandidate candidateTip : candidates) {
555 DataTreeCandidates.applyToModification(snapshot, candidateTip);
557 final ShardDataTreeCohort cohort = shardDataTree.finishTransaction(transaction, Optional.empty());
559 immediateCanCommit(cohort);
560 immediatePreCommit(cohort);
561 final DataTreeCandidate candidate = cohort.getCandidate();
562 immediateCommit(cohort);