Merge "Small fix to xsql dependencies"
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / test / java / org / opendaylight / controller / cluster / datastore / ShardTest.java
1 package org.opendaylight.controller.cluster.datastore;
2
3 import akka.actor.ActorRef;
4 import akka.actor.Props;
5 import akka.event.Logging;
6 import akka.testkit.JavaTestKit;
7
8 import org.junit.Assert;
9 import org.junit.Test;
10 import org.opendaylight.controller.cluster.datastore.identifiers.ShardIdentifier;
11 import org.opendaylight.controller.cluster.datastore.messages.CreateTransaction;
12 import org.opendaylight.controller.cluster.datastore.messages.CreateTransactionChain;
13 import org.opendaylight.controller.cluster.datastore.messages.CreateTransactionChainReply;
14 import org.opendaylight.controller.cluster.datastore.messages.EnableNotification;
15 import org.opendaylight.controller.cluster.datastore.messages.PeerAddressResolved;
16 import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListener;
17 import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListenerReply;
18 import org.opendaylight.controller.cluster.datastore.messages.UpdateSchemaContext;
19 import org.opendaylight.controller.md.cluster.datastore.model.SchemaContextHelper;
20 import org.opendaylight.controller.md.cluster.datastore.model.TestModel;
21 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
22 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
23 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
24 import org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionMessages.CreateTransactionReply;
25 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
26 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
27
28 import java.util.Collections;
29 import java.util.HashMap;
30 import java.util.Map;
31
32 import static org.junit.Assert.assertFalse;
33 import static org.junit.Assert.assertEquals;
34 import static org.junit.Assert.assertTrue;
35
36 public class ShardTest extends AbstractActorTest {
37
38     private static final ShardContext shardContext = new ShardContext();
39
40     @Test
41     public void testOnReceiveCreateTransactionChain() throws Exception {
42         new JavaTestKit(getSystem()) {{
43             final ShardIdentifier identifier =
44                 ShardIdentifier.builder().memberName("member-1")
45                     .shardName("inventory").type("config").build();
46
47             final Props props = Shard.props(identifier, Collections.EMPTY_MAP, shardContext);
48             final ActorRef subject =
49                 getSystem().actorOf(props, "testCreateTransactionChain");
50
51
52             // Wait for a specific log message to show up
53             final boolean result =
54                 new JavaTestKit.EventFilter<Boolean>(Logging.Info.class
55                 ) {
56                     @Override
57                     protected Boolean run() {
58                         return true;
59                     }
60                 }.from(subject.path().toString())
61                     .message("Switching from state Candidate to Leader")
62                     .occurrences(1).exec();
63
64             Assert.assertEquals(true, result);
65
66             new Within(duration("3 seconds")) {
67                 @Override
68                 protected void run() {
69
70                     subject.tell(new CreateTransactionChain().toSerializable(), getRef());
71
72                     final String out = new ExpectMsg<String>(duration("3 seconds"), "match hint") {
73                         // do not put code outside this method, will run afterwards
74                         @Override
75                         protected String match(Object in) {
76                             if (in.getClass().equals(CreateTransactionChainReply.SERIALIZABLE_CLASS)){
77                                 CreateTransactionChainReply reply =
78                                     CreateTransactionChainReply.fromSerializable(getSystem(),in);
79                                 return reply.getTransactionChainPath()
80                                     .toString();
81                             } else {
82                                 throw noMatch();
83                             }
84                         }
85                     }.get(); // this extracts the received message
86
87                     assertEquals("Unexpected transaction path " + out,
88                         "akka://test/user/testCreateTransactionChain/$a",
89                         out);
90
91                     expectNoMsg();
92                 }
93
94
95             };
96         }};
97     }
98
99     @Test
100     public void testOnReceiveRegisterListener() throws Exception {
101         new JavaTestKit(getSystem()) {{
102             final ShardIdentifier identifier =
103                 ShardIdentifier.builder().memberName("member-1")
104                     .shardName("inventory").type("config").build();
105
106             final Props props = Shard.props(identifier, Collections.EMPTY_MAP, shardContext);
107             final ActorRef subject =
108                 getSystem().actorOf(props, "testRegisterChangeListener");
109
110             new Within(duration("3 seconds")) {
111                 @Override
112                 protected void run() {
113
114                     subject.tell(
115                         new UpdateSchemaContext(SchemaContextHelper.full()),
116                         getRef());
117
118                     subject.tell(new RegisterChangeListener(TestModel.TEST_PATH,
119                         getRef().path(), AsyncDataBroker.DataChangeScope.BASE),
120                         getRef());
121
122                     final Boolean notificationEnabled = new ExpectMsg<Boolean>(
123                                                    duration("3 seconds"), "enable notification") {
124                         // do not put code outside this method, will run afterwards
125                         @Override
126                         protected Boolean match(Object in) {
127                             if(in instanceof EnableNotification){
128                                 return ((EnableNotification) in).isEnabled();
129                             } else {
130                                 throw noMatch();
131                             }
132                         }
133                     }.get(); // this extracts the received message
134
135                     assertFalse(notificationEnabled);
136
137                     final String out = new ExpectMsg<String>(duration("3 seconds"), "match hint") {
138                         // do not put code outside this method, will run afterwards
139                         @Override
140                         protected String match(Object in) {
141                             if (in.getClass().equals(RegisterChangeListenerReply.class)) {
142                                 RegisterChangeListenerReply reply =
143                                     (RegisterChangeListenerReply) in;
144                                 return reply.getListenerRegistrationPath()
145                                     .toString();
146                             } else {
147                                 throw noMatch();
148                             }
149                         }
150                     }.get(); // this extracts the received message
151
152                     assertTrue(out.matches(
153                         "akka:\\/\\/test\\/user\\/testRegisterChangeListener\\/\\$.*"));
154                 }
155
156
157             };
158         }};
159     }
160
161     @Test
162     public void testCreateTransaction(){
163         new JavaTestKit(getSystem()) {{
164             final ShardIdentifier identifier =
165                 ShardIdentifier.builder().memberName("member-1")
166                     .shardName("inventory").type("config").build();
167
168             final Props props = Shard.props(identifier, Collections.EMPTY_MAP, shardContext);
169             final ActorRef subject =
170                 getSystem().actorOf(props, "testCreateTransaction");
171
172             // Wait for a specific log message to show up
173             final boolean result =
174                 new JavaTestKit.EventFilter<Boolean>(Logging.Info.class
175                 ) {
176                     @Override
177                     protected Boolean run() {
178                         return true;
179                     }
180                 }.from(subject.path().toString())
181                     .message("Switching from state Candidate to Leader")
182                     .occurrences(1).exec();
183
184             Assert.assertEquals(true, result);
185
186             new Within(duration("3 seconds")) {
187                 @Override
188                 protected void run() {
189
190                     subject.tell(
191                         new UpdateSchemaContext(TestModel.createTestContext()),
192                         getRef());
193
194                     subject.tell(new CreateTransaction("txn-1", TransactionProxy.TransactionType.READ_ONLY.ordinal() ).toSerializable(),
195                         getRef());
196
197                     final String out = new ExpectMsg<String>(duration("3 seconds"), "match hint") {
198                         // do not put code outside this method, will run afterwards
199                         @Override
200                         protected String match(Object in) {
201                             if (in instanceof CreateTransactionReply) {
202                                 CreateTransactionReply reply =
203                                     (CreateTransactionReply) in;
204                                 return reply.getTransactionActorPath()
205                                     .toString();
206                             } else {
207                                 throw noMatch();
208                             }
209                         }
210                     }.get(); // this extracts the received message
211
212                     assertTrue("Unexpected transaction path " + out,
213                         out.contains("akka://test/user/testCreateTransaction/shard-txn-1"));
214                     expectNoMsg();
215                 }
216             };
217         }};
218     }
219
220     @Test
221     public void testPeerAddressResolved(){
222         new JavaTestKit(getSystem()) {{
223             Map<ShardIdentifier, String> peerAddresses = new HashMap<>();
224
225             final ShardIdentifier identifier =
226                 ShardIdentifier.builder().memberName("member-1")
227                     .shardName("inventory").type("config").build();
228
229             peerAddresses.put(identifier, null);
230             final Props props = Shard.props(identifier, peerAddresses, shardContext);
231             final ActorRef subject =
232                 getSystem().actorOf(props, "testPeerAddressResolved");
233
234             new Within(duration("3 seconds")) {
235                 @Override
236                 protected void run() {
237
238                     subject.tell(
239                         new PeerAddressResolved(identifier, "akka://foobar"),
240                         getRef());
241
242                     expectNoMsg();
243                 }
244             };
245         }};
246     }
247
248     private AsyncDataChangeListener<YangInstanceIdentifier, NormalizedNode<?, ?>> noOpDataChangeListener() {
249         return new AsyncDataChangeListener<YangInstanceIdentifier, NormalizedNode<?, ?>>() {
250             @Override
251             public void onDataChanged(
252                 AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> change) {
253
254             }
255         };
256     }
257 }