Change trackerList to a LinkedList
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / test / java / org / opendaylight / controller / cluster / datastore / ShardTransactionHeliumBackwardsCompatibilityTest.java
1 /*
2  * Copyright (c) 2014 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 java.util.Collections;
11 import org.junit.Assert;
12 import org.junit.Test;
13 import org.opendaylight.controller.cluster.datastore.identifiers.ShardIdentifier;
14 import org.opendaylight.controller.cluster.datastore.messages.AbortTransactionReply;
15 import org.opendaylight.controller.cluster.datastore.messages.CanCommitTransactionReply;
16 import org.opendaylight.controller.cluster.datastore.messages.CommitTransactionReply;
17 import org.opendaylight.controller.cluster.datastore.messages.PreCommitTransactionReply;
18 import org.opendaylight.controller.cluster.datastore.messages.ReadyTransaction;
19 import org.opendaylight.controller.cluster.datastore.messages.ReadyTransactionReply;
20 import org.opendaylight.controller.cluster.datastore.messages.WriteData;
21 import org.opendaylight.controller.cluster.datastore.messages.WriteDataReply;
22 import org.opendaylight.controller.md.cluster.datastore.model.TestModel;
23 import org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages;
24 import org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionMessages;
25 import org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionMessages.CreateTransactionReply;
26 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
27 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
28 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
29 import scala.concurrent.duration.FiniteDuration;
30 import akka.actor.ActorRef;
31 import akka.actor.ActorSelection;
32 import akka.actor.PoisonPill;
33 import akka.actor.Props;
34 import akka.dispatch.Dispatchers;
35 import akka.testkit.TestActorRef;
36
37 /**
38  * Tests backwards compatibility support from Helium-1 to Helium.
39  *
40  * In Helium-1, the 3-phase commit support was moved from the ThreePhaseCommitCohort actor to the
41  * Shard. As a consequence, a new transactionId field was added to the CanCommitTransaction,
42  * CommitTransaction and AbortTransaction messages. With a base Helium version node, these messages
43  * would be sans transactionId so this test verifies the Shard handles that properly.
44  *
45  * @author Thomas Pantelis
46  */
47 public class ShardTransactionHeliumBackwardsCompatibilityTest extends AbstractActorTest {
48
49     @Test
50     public void testTransactionCommit() throws Exception {
51         new ShardTestKit(getSystem()) {{
52             SchemaContext schemaContext = TestModel.createTestContext();
53             Props shardProps = Shard.props(ShardIdentifier.builder().memberName("member-1").
54                     shardName("inventory").type("config").build(),
55                     Collections.<ShardIdentifier,String>emptyMap(),
56                     DatastoreContext.newBuilder().shardHeartbeatIntervalInMillis(100).build(),
57                     schemaContext).withDispatcher(Dispatchers.DefaultDispatcherId());
58
59             final TestActorRef<Shard> shard = TestActorRef.create(getSystem(), shardProps,
60                     "testTransactionCommit");
61
62             waitUntilLeader(shard);
63
64             // Send CreateTransaction message with no messages version
65
66             String transactionID = "txn-1";
67             shard.tell(ShardTransactionMessages.CreateTransaction.newBuilder()
68                     .setTransactionId(transactionID)
69                     .setTransactionType(TransactionProxy.TransactionType.WRITE_ONLY.ordinal())
70                     .setTransactionChainId("").build(), getRef());
71
72             final FiniteDuration duration = duration("5 seconds");
73
74             CreateTransactionReply reply = expectMsgClass(duration, CreateTransactionReply.class);
75
76             ActorSelection txActor = getSystem().actorSelection(reply.getTransactionActorPath());
77
78             // Write data to the Tx
79
80             txActor.tell(new WriteData(TestModel.TEST_PATH,
81                     ImmutableNodes.containerNode(TestModel.TEST_QNAME), schemaContext), getRef());
82
83             expectMsgClass(duration, WriteDataReply.class);
84
85             // Ready the Tx
86
87             txActor.tell(new ReadyTransaction().toSerializable(), getRef());
88
89             ReadyTransactionReply readyReply = ReadyTransactionReply.fromSerializable(expectMsgClass(
90                     duration, ReadyTransactionReply.SERIALIZABLE_CLASS));
91
92             ActorSelection cohortActor = getSystem().actorSelection(readyReply.getCohortPath());
93
94             // Send the CanCommitTransaction message with no transactionId.
95
96             cohortActor.tell(ThreePhaseCommitCohortMessages.CanCommitTransaction.newBuilder().build(),
97                     getRef());
98
99             expectMsgClass(duration, CanCommitTransactionReply.SERIALIZABLE_CLASS);
100
101             // Send the PreCommitTransaction message with no transactionId.
102
103             cohortActor.tell(ThreePhaseCommitCohortMessages.PreCommitTransaction.newBuilder().build(),
104                     getRef());
105
106             expectMsgClass(duration, PreCommitTransactionReply.SERIALIZABLE_CLASS);
107
108             // Send the CommitTransaction message with no transactionId.
109
110             cohortActor.tell(ThreePhaseCommitCohortMessages.CommitTransaction.newBuilder().build(),
111                     getRef());
112
113             expectMsgClass(duration, CommitTransactionReply.SERIALIZABLE_CLASS);
114
115             NormalizedNode<?, ?> node = ShardTest.readStore(shard, TestModel.TEST_PATH);
116             Assert.assertNotNull("Data not found in store", node);
117
118             shard.tell(PoisonPill.getInstance(), ActorRef.noSender());
119         }};
120     }
121
122     @Test
123     public void testTransactionAbort() throws Exception {
124         new ShardTestKit(getSystem()) {{
125             SchemaContext schemaContext = TestModel.createTestContext();
126             Props shardProps = Shard.props(ShardIdentifier.builder().memberName("member-1").
127                     shardName("inventory").type("config").build(),
128                     Collections.<ShardIdentifier,String>emptyMap(),
129                     DatastoreContext.newBuilder().shardHeartbeatIntervalInMillis(100).build(),
130                     schemaContext).withDispatcher(Dispatchers.DefaultDispatcherId());
131
132             final TestActorRef<Shard> shard = TestActorRef.create(getSystem(), shardProps,
133                     "testTransactionAbort");
134
135             waitUntilLeader(shard);
136
137             // Send CreateTransaction message with no messages version
138
139             String transactionID = "txn-1";
140             shard.tell(ShardTransactionMessages.CreateTransaction.newBuilder()
141                     .setTransactionId(transactionID)
142                     .setTransactionType(TransactionProxy.TransactionType.WRITE_ONLY.ordinal())
143                     .setTransactionChainId("").build(), getRef());
144
145             final FiniteDuration duration = duration("5 seconds");
146
147             CreateTransactionReply reply = expectMsgClass(duration, CreateTransactionReply.class);
148
149             ActorSelection txActor = getSystem().actorSelection(reply.getTransactionActorPath());
150
151             // Write data to the Tx
152
153             txActor.tell(new WriteData(TestModel.TEST_PATH,
154                     ImmutableNodes.containerNode(TestModel.TEST_QNAME), schemaContext), getRef());
155
156             expectMsgClass(duration, WriteDataReply.class);
157
158             // Ready the Tx
159
160             txActor.tell(new ReadyTransaction().toSerializable(), getRef());
161
162             ReadyTransactionReply readyReply = ReadyTransactionReply.fromSerializable(expectMsgClass(
163                     duration, ReadyTransactionReply.SERIALIZABLE_CLASS));
164
165             ActorSelection cohortActor = getSystem().actorSelection(readyReply.getCohortPath());
166
167             // Send the CanCommitTransaction message with no transactionId.
168
169             cohortActor.tell(ThreePhaseCommitCohortMessages.CanCommitTransaction.newBuilder().build(),
170                     getRef());
171
172             expectMsgClass(duration, CanCommitTransactionReply.SERIALIZABLE_CLASS);
173
174             // Send the AbortTransaction message with no transactionId.
175
176             cohortActor.tell(ThreePhaseCommitCohortMessages.AbortTransaction.newBuilder().build(),
177                     getRef());
178
179             expectMsgClass(duration, AbortTransactionReply.SERIALIZABLE_CLASS);
180
181             shard.tell(PoisonPill.getInstance(), ActorRef.noSender());
182         }};
183     }
184 }