CDS: Implement front-end support for local transactions
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / test / java / org / opendaylight / controller / cluster / datastore / IntegrationTestKit.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.assertEquals;
11 import static org.junit.Assert.assertNotNull;
12 import static org.junit.Assert.fail;
13 import akka.actor.ActorRef;
14 import akka.actor.ActorSystem;
15 import akka.actor.PoisonPill;
16 import com.google.common.base.Optional;
17 import com.google.common.util.concurrent.Uninterruptibles;
18 import java.util.concurrent.Callable;
19 import java.util.concurrent.TimeUnit;
20 import org.opendaylight.controller.cluster.datastore.DatastoreContext.Builder;
21 import org.opendaylight.controller.cluster.datastore.shardstrategy.ShardStrategyFactory;
22 import org.opendaylight.controller.cluster.datastore.utils.ActorContext;
23 import org.opendaylight.controller.md.cluster.datastore.model.SchemaContextHelper;
24 import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction;
25 import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
26 import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain;
27 import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction;
28 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
29 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
30 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
31
32 class IntegrationTestKit extends ShardTestKit {
33
34     DatastoreContext.Builder datastoreContextBuilder;
35
36     IntegrationTestKit(ActorSystem actorSystem, Builder datastoreContextBuilder) {
37         super(actorSystem);
38         this.datastoreContextBuilder = datastoreContextBuilder;
39     }
40
41     DistributedDataStore setupDistributedDataStore(String typeName, String... shardNames) {
42         return setupDistributedDataStore(typeName, true, shardNames);
43     }
44
45     DistributedDataStore setupDistributedDataStore(String typeName, boolean waitUntilLeader,
46             String... shardNames) {
47         return setupDistributedDataStore(typeName, "module-shards.conf", waitUntilLeader, shardNames);
48     }
49
50     DistributedDataStore setupDistributedDataStore(String typeName, String moduleShardsConfig, boolean waitUntilLeader,
51             String... shardNames) {
52         ClusterWrapper cluster = new ClusterWrapperImpl(getSystem());
53         Configuration config = new ConfigurationImpl(moduleShardsConfig, "modules.conf");
54         ShardStrategyFactory.setConfiguration(config);
55
56         datastoreContextBuilder.dataStoreType(typeName);
57
58         DatastoreContext datastoreContext = datastoreContextBuilder.build();
59
60         DistributedDataStore dataStore = new DistributedDataStore(getSystem(), cluster, config, datastoreContext);
61
62         SchemaContext schemaContext = SchemaContextHelper.full();
63         dataStore.onGlobalContextUpdated(schemaContext);
64
65         if(waitUntilLeader) {
66             waitUntilLeader(dataStore.getActorContext(), shardNames);
67         }
68
69         return dataStore;
70     }
71
72     void waitUntilLeader(ActorContext actorContext, String... shardNames) {
73         for(String shardName: shardNames) {
74             ActorRef shard = null;
75             for(int i = 0; i < 20 * 5 && shard == null; i++) {
76                 Uninterruptibles.sleepUninterruptibly(50, TimeUnit.MILLISECONDS);
77                 Optional<ActorRef> shardReply = actorContext.findLocalShard(shardName);
78                 if(shardReply.isPresent()) {
79                     shard = shardReply.get();
80                 }
81             }
82
83             assertNotNull("Shard was not created", shard);
84
85             waitUntilLeader(shard);
86         }
87     }
88
89     void testWriteTransaction(DistributedDataStore dataStore, YangInstanceIdentifier nodePath,
90             NormalizedNode<?, ?> nodeToWrite) throws Exception {
91
92         // 1. Create a write-only Tx
93
94         DOMStoreWriteTransaction writeTx = dataStore.newWriteOnlyTransaction();
95         assertNotNull("newWriteOnlyTransaction returned null", writeTx);
96
97         // 2. Write some data
98
99         writeTx.write(nodePath, nodeToWrite);
100
101         // 3. Ready the Tx for commit
102
103         DOMStoreThreePhaseCommitCohort cohort = writeTx.ready();
104
105         // 4. Commit the Tx
106
107         doCommit(cohort);
108
109         // 5. Verify the data in the store
110
111         DOMStoreReadTransaction readTx = dataStore.newReadOnlyTransaction();
112
113         Optional<NormalizedNode<?, ?>> optional = readTx.read(nodePath).get(5, TimeUnit.SECONDS);
114         assertEquals("isPresent", true, optional.isPresent());
115         assertEquals("Data node", nodeToWrite, optional.get());
116     }
117
118     void doCommit(final DOMStoreThreePhaseCommitCohort cohort) throws Exception {
119         Boolean canCommit = cohort.canCommit().get(7, TimeUnit.SECONDS);
120         assertEquals("canCommit", true, canCommit);
121         cohort.preCommit().get(5, TimeUnit.SECONDS);
122         cohort.commit().get(5, TimeUnit.SECONDS);
123     }
124
125     void cleanup(DistributedDataStore dataStore) {
126         if(dataStore != null) {
127             dataStore.getActorContext().getShardManager().tell(PoisonPill.getInstance(), null);
128         }
129     }
130
131     void assertExceptionOnCall(Callable<Void> callable, Class<? extends Exception> expType)
132             throws Exception {
133         try {
134             callable.call();
135             fail("Expected " + expType.getSimpleName());
136         } catch(Exception e) {
137             assertEquals("Exception type", expType, e.getClass());
138         }
139     }
140
141     void assertExceptionOnTxChainCreates(final DOMStoreTransactionChain txChain,
142             Class<? extends Exception> expType) throws Exception {
143         assertExceptionOnCall(new Callable<Void>() {
144             @Override
145             public Void call() throws Exception {
146                 txChain.newWriteOnlyTransaction();
147                 return null;
148             }
149         }, expType);
150
151         assertExceptionOnCall(new Callable<Void>() {
152             @Override
153             public Void call() throws Exception {
154                 txChain.newReadWriteTransaction();
155                 return null;
156             }
157         }, expType);
158
159         assertExceptionOnCall(new Callable<Void>() {
160             @Override
161             public Void call() throws Exception {
162                 txChain.newReadOnlyTransaction();
163                 return null;
164             }
165         }, expType);
166     }
167 }