2 * Copyright (c) 2016 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.assertSame;
14 import static org.junit.Assert.fail;
15 import static org.mockito.Matchers.any;
16 import static org.mockito.Mockito.mock;
17 import akka.actor.ActorSystem;
18 import akka.actor.Address;
19 import akka.actor.AddressFromURIString;
20 import akka.cluster.Cluster;
21 import akka.testkit.JavaTestKit;
22 import akka.util.Timeout;
23 import com.google.common.base.Throwables;
24 import com.google.common.util.concurrent.CheckedFuture;
25 import com.google.common.util.concurrent.Futures;
26 import com.typesafe.config.ConfigFactory;
27 import java.io.IOException;
28 import java.util.concurrent.TimeUnit;
29 import org.junit.AfterClass;
30 import org.junit.BeforeClass;
31 import org.junit.Ignore;
32 import org.junit.Test;
33 import org.mockito.ArgumentCaptor;
34 import org.mockito.Mockito;
35 import org.opendaylight.controller.md.cluster.datastore.model.TestModel;
36 import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
37 import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction;
38 import org.opendaylight.mdsal.common.api.DataValidationFailedException;
39 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
40 import org.opendaylight.mdsal.common.api.PostCanCommitStep;
41 import org.opendaylight.mdsal.common.api.ThreePhaseCommitStep;
42 import org.opendaylight.mdsal.dom.api.DOMDataTreeCandidate;
43 import org.opendaylight.mdsal.dom.api.DOMDataTreeCommitCohort;
44 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
45 import org.opendaylight.yangtools.concepts.ObjectRegistration;
46 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
47 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
48 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
49 import scala.concurrent.duration.Duration;
51 public class DataTreeCohortIntegrationTest {
53 private static final DataValidationFailedException FAILED_CAN_COMMIT =
54 new DataValidationFailedException(YangInstanceIdentifier.class, TestModel.TEST_PATH, "Test failure.");
55 private static final CheckedFuture<PostCanCommitStep, DataValidationFailedException> FAILED_CAN_COMMIT_FUTURE =
56 Futures.immediateFailedCheckedFuture(FAILED_CAN_COMMIT);
58 private static final DOMDataTreeIdentifier TEST_ID =
59 new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH);
61 private static final Timeout TIMEOUT = new Timeout(Duration.create(5, TimeUnit.SECONDS));
63 private static ActorSystem system;
65 private final DatastoreContext.Builder datastoreContextBuilder =
66 DatastoreContext.newBuilder().shardHeartbeatIntervalInMillis(100);
69 public static void setUpClass() throws IOException {
70 system = ActorSystem.create("cluster-test", ConfigFactory.load().getConfig("Member1"));
71 final Address member1Address = AddressFromURIString.parse("akka.tcp://cluster-test@127.0.0.1:2558");
72 Cluster.get(system).join(member1Address);
76 public static void tearDownClass() throws IOException {
77 JavaTestKit.shutdownActorSystem(system);
81 protected ActorSystem getSystem() {
86 public void registerNoopCohortTest() throws Exception {
87 final DOMDataTreeCommitCohort cohort = mock(DOMDataTreeCommitCohort.class);
88 Mockito.doReturn(PostCanCommitStep.NOOP_SUCCESS_FUTURE).when(cohort).canCommit(any(Object.class),
89 any(DOMDataTreeCandidate.class), any(SchemaContext.class));
90 ArgumentCaptor<DOMDataTreeCandidate> candidateCapt = ArgumentCaptor.forClass(DOMDataTreeCandidate.class);
91 new IntegrationTestKit(getSystem(), datastoreContextBuilder) {
93 try (final DistributedDataStore dataStore = setupDistributedDataStore("transactionIntegrationTest", "test-1")) {
94 final ObjectRegistration<DOMDataTreeCommitCohort> cohortReg = dataStore.registerCommitCohort(TEST_ID, cohort);
95 Thread.sleep(1000); // Registration is asynchronous
96 assertNotNull(cohortReg);
97 testWriteTransaction(dataStore, TestModel.TEST_PATH,
98 ImmutableNodes.containerNode(TestModel.TEST_QNAME));
99 Mockito.verify(cohort).canCommit(any(Object.class), candidateCapt.capture(), any(SchemaContext.class));
100 DOMDataTreeCandidate candidate = candidateCapt.getValue();
101 assertNotNull(candidate);
102 assertEquals(TEST_ID, candidate.getRootPath());
103 testWriteTransaction(dataStore, TestModel.OUTER_LIST_PATH,
104 ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build());
105 Mockito.verify(cohort, Mockito.times(2)).canCommit(any(Object.class), any(DOMDataTreeCandidate.class),
106 any(SchemaContext.class));
108 testWriteTransaction(dataStore, TestModel.TEST_PATH,
109 ImmutableNodes.containerNode(TestModel.TEST_QNAME));
110 Mockito.verifyNoMoreInteractions(cohort);
117 public void failCanCommitTest() throws Exception {
118 final DOMDataTreeCommitCohort failedCohort = mock(DOMDataTreeCommitCohort.class);
120 Mockito.doReturn(FAILED_CAN_COMMIT_FUTURE).when(failedCohort).canCommit(any(Object.class),
121 any(DOMDataTreeCandidate.class), any(SchemaContext.class));
123 new IntegrationTestKit(getSystem(), datastoreContextBuilder) {
125 try (final DistributedDataStore dataStore =
126 setupDistributedDataStore("transactionIntegrationTest", "test-1")) {
127 dataStore.registerCommitCohort(TEST_ID, failedCohort);
128 Thread.sleep(1000); // Registration is asynchronous
130 DOMStoreWriteTransaction writeTx = dataStore.newWriteOnlyTransaction();
131 writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
132 DOMStoreThreePhaseCommitCohort dsCohort = writeTx.ready();
134 // FIXME: Weird thing is that invoking canCommit on front-end invokes also
135 // preCommit on backend.
136 dsCohort.canCommit().get();
137 fail("Exception should be raised.");
138 } catch (Exception e) {
139 assertSame(FAILED_CAN_COMMIT, Throwables.getRootCause(e));
148 * FIXME: Weird thing is that invoking canCommit on front-end invokes also preCommit on backend
149 * so we can not test abort after can commit.
154 public void canCommitSuccessExternallyAborted() throws Exception {
155 final DOMDataTreeCommitCohort cohortToAbort = mock(DOMDataTreeCommitCohort.class);
156 final PostCanCommitStep stepToAbort = mock(PostCanCommitStep.class);
157 Mockito.doReturn(Futures.immediateCheckedFuture(stepToAbort)).when(cohortToAbort).canCommit(any(Object.class),
158 any(DOMDataTreeCandidate.class), any(SchemaContext.class));
159 Mockito.doReturn(ThreePhaseCommitStep.NOOP_ABORT_FUTURE).when(stepToAbort).abort();
160 new IntegrationTestKit(getSystem(), datastoreContextBuilder) {
162 try (final DistributedDataStore dataStore =
163 setupDistributedDataStore("transactionIntegrationTest", "test-1")) {
164 dataStore.registerCommitCohort(TEST_ID, cohortToAbort);
165 Thread.sleep(1000); // Registration is asynchronous
167 DOMStoreWriteTransaction writeTx = dataStore.newWriteOnlyTransaction();
168 writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
169 DOMStoreThreePhaseCommitCohort dsCohort = writeTx.ready();
171 dsCohort.canCommit().get();
172 dsCohort.abort().get();
173 Mockito.verify(stepToAbort, Mockito.times(1)).abort();