+ doReturn(FAILED_CAN_COMMIT_FUTURE).when(failedCohort).canCommit(any(Object.class),
+ any(Collection.class), any(SchemaContext.class));
+
+ IntegrationTestKit kit = new IntegrationTestKit(getSystem(), datastoreContextBuilder);
+ try (AbstractDataStore dataStore = kit.setupAbstractDataStore(
+ DistributedDataStore.class, "testFailedCanCommit", "test-1")) {
+ dataStore.registerCommitCohort(TEST_ID, failedCohort);
+
+ IntegrationTestKit.verifyShardState(dataStore, "test-1",
+ state -> assertEquals("Cohort registrations", 1, state.getCommitCohortActors().size()));
+
+ DOMStoreWriteTransaction writeTx = dataStore.newWriteOnlyTransaction();
+ writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
+ DOMStoreThreePhaseCommitCohort dsCohort = writeTx.ready();
+ try {
+ dsCohort.canCommit().get(5, TimeUnit.SECONDS);
+ fail("Exception should be raised.");
+ } catch (ExecutionException e) {
+ assertSame(FAILED_CAN_COMMIT, Throwables.getRootCause(e));
+ }
+ }
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ @Test
+ public void testCanCommitWithListEntries() throws Exception {
+ final DOMDataTreeCommitCohort cohort = mock(DOMDataTreeCommitCohort.class);
+ doReturn(PostCanCommitStep.NOOP_SUCCESS_FUTURE).when(cohort).canCommit(any(Object.class),
+ any(Collection.class), any(SchemaContext.class));
+ IntegrationTestKit kit = new IntegrationTestKit(getSystem(), datastoreContextBuilder);
+
+ try (AbstractDataStore dataStore = kit.setupAbstractDataStore(
+ DistributedDataStore.class, "testCanCommitWithMultipleListEntries", "cars-1")) {
+ final ObjectRegistration<DOMDataTreeCommitCohort> cohortReg = dataStore.registerCommitCohort(
+ new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, CarsModel.CAR_LIST_PATH
+ .node(CarsModel.CAR_QNAME)), cohort);
+ assertNotNull(cohortReg);
+
+ IntegrationTestKit.verifyShardState(dataStore, "cars-1",
+ state -> assertEquals("Cohort registrations", 1, state.getCommitCohortActors().size()));
+
+ // First write an empty base container and verify the cohort isn't invoked.
+
+ DOMStoreWriteTransaction writeTx = dataStore.newWriteOnlyTransaction();
+ writeTx.write(CarsModel.BASE_PATH, CarsModel.emptyContainer());
+ writeTx.write(CarsModel.CAR_LIST_PATH, CarsModel.newCarMapNode());
+ kit.doCommit(writeTx.ready());
+ verifyNoMoreInteractions(cohort);
+
+ // Write a single car entry and verify the cohort is invoked.
+
+ writeTx = dataStore.newWriteOnlyTransaction();
+ final YangInstanceIdentifier optimaPath = CarsModel.newCarPath("optima");
+ final MapEntryNode optimaNode = CarsModel.newCarEntry("optima", BigInteger.valueOf(20000));
+ writeTx.write(optimaPath, optimaNode);
+ kit.doCommit(writeTx.ready());
+
+ ArgumentCaptor<Collection> candidateCapture = ArgumentCaptor.forClass(Collection.class);
+ verify(cohort).canCommit(any(Object.class), candidateCapture.capture(), any(SchemaContext.class));
+ assertDataTreeCandidate((DOMDataTreeCandidate) candidateCapture.getValue().iterator().next(),
+ new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, optimaPath), ModificationType.WRITE,
+ Optional.of(optimaNode), Optional.absent());
+
+ // Write replace the cars container with 2 new car entries. The cohort should get invoked with 3
+ // DOMDataTreeCandidates: once for each of the 2 new car entries (WRITE mod) and once for the deleted prior
+ // car entry (DELETE mod).
+
+ reset(cohort);
+ doReturn(PostCanCommitStep.NOOP_SUCCESS_FUTURE).when(cohort).canCommit(any(Object.class),
+ any(Collection.class), any(SchemaContext.class));
+
+ writeTx = dataStore.newWriteOnlyTransaction();
+ final YangInstanceIdentifier sportagePath = CarsModel.newCarPath("sportage");
+ final MapEntryNode sportageNode = CarsModel.newCarEntry("sportage", BigInteger.valueOf(20000));
+ final YangInstanceIdentifier soulPath = CarsModel.newCarPath("soul");
+ final MapEntryNode soulNode = CarsModel.newCarEntry("soul", BigInteger.valueOf(20000));
+ writeTx.write(CarsModel.BASE_PATH, CarsModel.newCarsNode(CarsModel.newCarsMapNode(sportageNode,soulNode)));
+ kit.doCommit(writeTx.ready());
+
+ candidateCapture = ArgumentCaptor.forClass(Collection.class);
+ verify(cohort).canCommit(any(Object.class), candidateCapture.capture(), any(SchemaContext.class));
+
+ assertDataTreeCandidate(findCandidate(candidateCapture, sportagePath), new DOMDataTreeIdentifier(
+ LogicalDatastoreType.CONFIGURATION, sportagePath), ModificationType.WRITE,
+ Optional.of(sportageNode), Optional.absent());
+
+ assertDataTreeCandidate(findCandidate(candidateCapture, soulPath), new DOMDataTreeIdentifier(
+ LogicalDatastoreType.CONFIGURATION, soulPath), ModificationType.WRITE,
+ Optional.of(soulNode), Optional.absent());
+
+ assertDataTreeCandidate(findCandidate(candidateCapture, optimaPath), new DOMDataTreeIdentifier(
+ LogicalDatastoreType.CONFIGURATION, optimaPath), ModificationType.DELETE,
+ Optional.absent(), Optional.of(optimaNode));
+
+ // Delete the cars container - cohort should be invoked for the 2 deleted car entries.
+
+ reset(cohort);
+ doReturn(PostCanCommitStep.NOOP_SUCCESS_FUTURE).when(cohort).canCommit(any(Object.class),
+ any(Collection.class), any(SchemaContext.class));
+
+ writeTx = dataStore.newWriteOnlyTransaction();
+ writeTx.delete(CarsModel.BASE_PATH);
+ kit.doCommit(writeTx.ready());
+
+ candidateCapture = ArgumentCaptor.forClass(Collection.class);
+ verify(cohort).canCommit(any(Object.class), candidateCapture.capture(), any(SchemaContext.class));
+
+ assertDataTreeCandidate(findCandidate(candidateCapture, sportagePath), new DOMDataTreeIdentifier(
+ LogicalDatastoreType.CONFIGURATION, sportagePath), ModificationType.DELETE,
+ Optional.absent(), Optional.of(sportageNode));
+
+ assertDataTreeCandidate(findCandidate(candidateCapture, soulPath), new DOMDataTreeIdentifier(
+ LogicalDatastoreType.CONFIGURATION, soulPath), ModificationType.DELETE,
+ Optional.absent(), Optional.of(soulNode));
+
+ }
+ }
+
+ @SuppressWarnings("rawtypes")
+ private static DOMDataTreeCandidate findCandidate(ArgumentCaptor<Collection> candidateCapture,
+ YangInstanceIdentifier rootPath) {
+ for (Object obj: candidateCapture.getValue()) {
+ DOMDataTreeCandidate candidate = (DOMDataTreeCandidate)obj;
+ if (rootPath.equals(candidate.getRootPath().getRootIdentifier())) {
+ return candidate;