Merge "Add exists method on DOMStoreReadTransaction and DOMDataReadTransaction"
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / test / java / org / opendaylight / controller / cluster / datastore / ShardTransactionTest.java
1 package org.opendaylight.controller.cluster.datastore;
2
3 import akka.actor.ActorRef;
4 import akka.actor.Props;
5 import akka.actor.Terminated;
6 import akka.testkit.JavaTestKit;
7 import akka.testkit.TestActorRef;
8 import com.google.common.util.concurrent.ListeningExecutorService;
9 import com.google.common.util.concurrent.MoreExecutors;
10 import org.junit.Assert;
11 import org.junit.Test;
12 import org.opendaylight.controller.cluster.datastore.exceptions.UnknownMessageException;
13 import org.opendaylight.controller.cluster.datastore.identifiers.ShardIdentifier;
14 import org.opendaylight.controller.cluster.datastore.messages.CloseTransaction;
15 import org.opendaylight.controller.cluster.datastore.messages.CloseTransactionReply;
16 import org.opendaylight.controller.cluster.datastore.messages.DataExists;
17 import org.opendaylight.controller.cluster.datastore.messages.DataExistsReply;
18 import org.opendaylight.controller.cluster.datastore.messages.DeleteData;
19 import org.opendaylight.controller.cluster.datastore.messages.DeleteDataReply;
20 import org.opendaylight.controller.cluster.datastore.messages.MergeData;
21 import org.opendaylight.controller.cluster.datastore.messages.MergeDataReply;
22 import org.opendaylight.controller.cluster.datastore.messages.ReadData;
23 import org.opendaylight.controller.cluster.datastore.messages.ReadDataReply;
24 import org.opendaylight.controller.cluster.datastore.messages.ReadyTransaction;
25 import org.opendaylight.controller.cluster.datastore.messages.ReadyTransactionReply;
26 import org.opendaylight.controller.cluster.datastore.messages.WriteData;
27 import org.opendaylight.controller.cluster.datastore.messages.WriteDataReply;
28 import org.opendaylight.controller.cluster.datastore.modification.CompositeModification;
29 import org.opendaylight.controller.cluster.datastore.modification.DeleteModification;
30 import org.opendaylight.controller.cluster.datastore.modification.MergeModification;
31 import org.opendaylight.controller.cluster.datastore.modification.Modification;
32 import org.opendaylight.controller.cluster.datastore.modification.WriteModification;
33 import org.opendaylight.controller.md.cluster.datastore.model.TestModel;
34 import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore;
35 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
36 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
37 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
38
39 import java.util.Collections;
40
41 import static org.junit.Assert.assertEquals;
42 import static org.junit.Assert.assertTrue;
43
44 public class ShardTransactionTest extends AbstractActorTest {
45     private static ListeningExecutorService storeExecutor =
46         MoreExecutors.listeningDecorator(MoreExecutors.sameThreadExecutor());
47
48     private static final InMemoryDOMDataStore store =
49         new InMemoryDOMDataStore("OPER", storeExecutor, MoreExecutors.sameThreadExecutor());
50
51     private static final SchemaContext testSchemaContext = TestModel.createTestContext();
52
53     private static final ShardIdentifier SHARD_IDENTIFIER =
54         ShardIdentifier.builder().memberName("member-1")
55             .shardName("inventory").type("config").build();
56
57
58     static {
59         store.onGlobalContextUpdated(testSchemaContext);
60     }
61
62     @Test
63     public void testOnReceiveReadData() throws Exception {
64         new JavaTestKit(getSystem()) {{
65             final ActorRef shard = getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP));
66             final Props props =
67                 ShardTransaction.props(store.newReadOnlyTransaction(), shard, testSchemaContext);
68             final ActorRef subject = getSystem().actorOf(props, "testReadData");
69
70             new Within(duration("1 seconds")) {
71                 @Override
72                 protected void run() {
73
74                     subject.tell(
75                         new ReadData(YangInstanceIdentifier.builder().build()).toSerializable(),
76                         getRef());
77
78                     final String out = new ExpectMsg<String>(duration("1 seconds"), "match hint") {
79                         // do not put code outside this method, will run afterwards
80                         @Override
81                         protected String match(Object in) {
82                             if (in.getClass().equals(ReadDataReply.SERIALIZABLE_CLASS)) {
83                               if (ReadDataReply.fromSerializable(testSchemaContext,YangInstanceIdentifier.builder().build(), in)
84                                   .getNormalizedNode()!= null) {
85                                     return "match";
86                                 }
87                                 return null;
88                             } else {
89                                 throw noMatch();
90                             }
91                         }
92                     }.get(); // this extracts the received message
93
94                     assertEquals("match", out);
95
96                     expectNoMsg();
97                 }
98
99
100             };
101         }};
102     }
103
104     @Test
105     public void testOnReceiveReadDataWhenDataNotFound() throws Exception {
106         new JavaTestKit(getSystem()) {{
107             final ActorRef shard = getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP));
108             final Props props =
109                 ShardTransaction.props( store.newReadOnlyTransaction(), shard, testSchemaContext);
110             final ActorRef subject = getSystem().actorOf(props, "testReadDataWhenDataNotFound");
111
112             new Within(duration("1 seconds")) {
113                 @Override
114                 protected void run() {
115
116                     subject.tell(
117                         new ReadData(TestModel.TEST_PATH).toSerializable(),
118                         getRef());
119
120                     final String out = new ExpectMsg<String>(duration("1 seconds"), "match hint") {
121                         // do not put code outside this method, will run afterwards
122                         @Override
123                         protected String match(Object in) {
124                             if (in.getClass().equals(ReadDataReply.SERIALIZABLE_CLASS)) {
125                                 if (ReadDataReply.fromSerializable(testSchemaContext,TestModel.TEST_PATH, in)
126                                     .getNormalizedNode()
127                                     == null) {
128                                     return "match";
129                                 }
130                                 return null;
131                             } else {
132                                 throw noMatch();
133                             }
134                         }
135                     }.get(); // this extracts the received message
136
137                     assertEquals("match", out);
138
139                     expectNoMsg();
140                 }
141
142
143             };
144         }};
145     }
146
147     @Test
148     public void testOnReceiveDataExistsPositive() throws Exception {
149         new JavaTestKit(getSystem()) {{
150             final ActorRef shard = getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP));
151             final Props props =
152                 ShardTransaction.props(store.newReadOnlyTransaction(), shard, testSchemaContext);
153             final ActorRef subject = getSystem().actorOf(props, "testDataExistsPositive");
154
155             new Within(duration("1 seconds")) {
156                 @Override
157                 protected void run() {
158
159                     subject.tell(
160                         new DataExists(YangInstanceIdentifier.builder().build()).toSerializable(),
161                         getRef());
162
163                     final String out = new ExpectMsg<String>(duration("1 seconds"), "match hint") {
164                         // do not put code outside this method, will run afterwards
165                         @Override
166                         protected String match(Object in) {
167                             if (in.getClass().equals(DataExistsReply.SERIALIZABLE_CLASS)) {
168                                 if (DataExistsReply.fromSerializable(in)
169                                     .exists()) {
170                                     return "match";
171                                 }
172                                 return null;
173                             } else {
174                                 throw noMatch();
175                             }
176                         }
177                     }.get(); // this extracts the received message
178
179                     assertEquals("match", out);
180
181                     expectNoMsg();
182                 }
183
184
185             };
186         }};
187     }
188
189     @Test
190     public void testOnReceiveDataExistsNegative() throws Exception {
191         new JavaTestKit(getSystem()) {{
192             final ActorRef shard = getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP));
193             final Props props =
194                 ShardTransaction.props(store.newReadOnlyTransaction(), shard, testSchemaContext);
195             final ActorRef subject = getSystem().actorOf(props, "testDataExistsNegative");
196
197             new Within(duration("1 seconds")) {
198                 @Override
199                 protected void run() {
200
201                     subject.tell(
202                         new DataExists(TestModel.TEST_PATH).toSerializable(),
203                         getRef());
204
205                     final String out = new ExpectMsg<String>(duration("1 seconds"), "match hint") {
206                         // do not put code outside this method, will run afterwards
207                         @Override
208                         protected String match(Object in) {
209                             if (in.getClass().equals(DataExistsReply.SERIALIZABLE_CLASS)) {
210                                 if (!DataExistsReply.fromSerializable(in)
211                                     .exists()) {
212                                     return "match";
213                                 }
214                                 return null;
215                             } else {
216                                 throw noMatch();
217                             }
218                         }
219                     }.get(); // this extracts the received message
220
221                     assertEquals("match", out);
222
223                     expectNoMsg();
224                 }
225
226
227             };
228         }};
229     }
230
231     private void assertModification(final ActorRef subject,
232         final Class<? extends Modification> modificationType) {
233         new JavaTestKit(getSystem()) {{
234             new Within(duration("1 seconds")) {
235                 @Override
236                 protected void run() {
237                     subject
238                         .tell(new ShardTransaction.GetCompositedModification(),
239                             getRef());
240
241                     final CompositeModification compositeModification =
242                         new ExpectMsg<CompositeModification>(duration("1 seconds"), "match hint") {
243                             // do not put code outside this method, will run afterwards
244                             @Override
245                             protected CompositeModification match(Object in) {
246                                 if (in instanceof ShardTransaction.GetCompositeModificationReply) {
247                                     return ((ShardTransaction.GetCompositeModificationReply) in)
248                                         .getModification();
249                                 } else {
250                                     throw noMatch();
251                                 }
252                             }
253                         }.get(); // this extracts the received message
254
255                     assertTrue(
256                         compositeModification.getModifications().size() == 1);
257                     assertEquals(modificationType,
258                         compositeModification.getModifications().get(0)
259                             .getClass());
260
261                 }
262             };
263         }};
264     }
265
266     @Test
267     public void testOnReceiveWriteData() throws Exception {
268         new JavaTestKit(getSystem()) {{
269             final ActorRef shard = getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP));
270             final Props props =
271                 ShardTransaction.props(store.newWriteOnlyTransaction(), shard, TestModel.createTestContext());
272             final ActorRef subject =
273                 getSystem().actorOf(props, "testWriteData");
274
275             new Within(duration("1 seconds")) {
276                 @Override
277                 protected void run() {
278
279                     subject.tell(new WriteData(TestModel.TEST_PATH,
280                         ImmutableNodes.containerNode(TestModel.TEST_QNAME), TestModel.createTestContext()).toSerializable(),
281                         getRef());
282
283                     final String out = new ExpectMsg<String>(duration("1 seconds"), "match hint") {
284                         // do not put code outside this method, will run afterwards
285                         @Override
286                         protected String match(Object in) {
287                             if (in.getClass().equals(WriteDataReply.SERIALIZABLE_CLASS)) {
288                                 return "match";
289                             } else {
290                                 throw noMatch();
291                             }
292                         }
293                     }.get(); // this extracts the received message
294
295                     assertEquals("match", out);
296
297                     assertModification(subject, WriteModification.class);
298                     expectNoMsg();
299                 }
300
301
302             };
303         }};
304     }
305
306     @Test
307     public void testOnReceiveMergeData() throws Exception {
308         new JavaTestKit(getSystem()) {{
309             final ActorRef shard = getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP));
310             final Props props =
311                 ShardTransaction.props(store.newReadWriteTransaction(), shard, testSchemaContext);
312             final ActorRef subject =
313                 getSystem().actorOf(props, "testMergeData");
314
315             new Within(duration("1 seconds")) {
316                 @Override
317                 protected void run() {
318
319                     subject.tell(new MergeData(TestModel.TEST_PATH,
320                         ImmutableNodes.containerNode(TestModel.TEST_QNAME), testSchemaContext).toSerializable(),
321                         getRef());
322
323                     final String out = new ExpectMsg<String>(duration("500 milliseconds"), "match hint") {
324                         // do not put code outside this method, will run afterwards
325                         @Override
326                         protected String match(Object in) {
327                             if (in.getClass().equals(MergeDataReply.SERIALIZABLE_CLASS)) {
328                                 return "match";
329                             } else {
330                                 throw noMatch();
331                             }
332                         }
333                     }.get(); // this extracts the received message
334
335                     assertEquals("match", out);
336
337                     assertModification(subject, MergeModification.class);
338
339                     expectNoMsg();
340                 }
341
342
343             };
344         }};
345     }
346
347     @Test
348     public void testOnReceiveDeleteData() throws Exception {
349         new JavaTestKit(getSystem()) {{
350             final ActorRef shard = getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP));
351             final Props props =
352                 ShardTransaction.props( store.newWriteOnlyTransaction(), shard, TestModel.createTestContext());
353             final ActorRef subject =
354                 getSystem().actorOf(props, "testDeleteData");
355
356             new Within(duration("1 seconds")) {
357                 @Override
358                 protected void run() {
359
360                     subject.tell(new DeleteData(TestModel.TEST_PATH).toSerializable(), getRef());
361
362                     final String out = new ExpectMsg<String>(duration("1 seconds"), "match hint") {
363                         // do not put code outside this method, will run afterwards
364                         @Override
365                         protected String match(Object in) {
366                             if (in.getClass().equals(DeleteDataReply.SERIALIZABLE_CLASS)) {
367                                 return "match";
368                             } else {
369                                 throw noMatch();
370                             }
371                         }
372                     }.get(); // this extracts the received message
373
374                     assertEquals("match", out);
375
376                     assertModification(subject, DeleteModification.class);
377                     expectNoMsg();
378                 }
379
380
381             };
382         }};
383     }
384
385
386     @Test
387     public void testOnReceiveReadyTransaction() throws Exception {
388         new JavaTestKit(getSystem()) {{
389             final ActorRef shard = getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP));
390             final Props props =
391                 ShardTransaction.props( store.newReadWriteTransaction(), shard, TestModel.createTestContext());
392             final ActorRef subject =
393                 getSystem().actorOf(props, "testReadyTransaction");
394
395             new Within(duration("1 seconds")) {
396                 @Override
397                 protected void run() {
398
399                     subject.tell(new ReadyTransaction().toSerializable(), getRef());
400
401                     final String out = new ExpectMsg<String>(duration("1 seconds"), "match hint") {
402                         // do not put code outside this method, will run afterwards
403                         @Override
404                         protected String match(Object in) {
405                             if (in.getClass().equals(ReadyTransactionReply.SERIALIZABLE_CLASS)) {
406                                 return "match";
407                             } else {
408                                 throw noMatch();
409                             }
410                         }
411                     }.get(); // this extracts the received message
412
413                     assertEquals("match", out);
414
415                     expectNoMsg();
416                 }
417
418
419             };
420         }};
421
422     }
423
424     @Test
425     public void testOnReceiveCloseTransaction() throws Exception {
426         new JavaTestKit(getSystem()) {{
427             final ActorRef shard = getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP));
428             final Props props =
429                 ShardTransaction.props(store.newReadWriteTransaction(), shard, TestModel.createTestContext());
430             final ActorRef subject =
431                 getSystem().actorOf(props, "testCloseTransaction");
432
433             watch(subject);
434
435             new Within(duration("2 seconds")) {
436                 @Override
437                 protected void run() {
438
439                     subject.tell(new CloseTransaction().toSerializable(), getRef());
440
441                     final String out = new ExpectMsg<String>(duration("1 seconds"), "match hint") {
442                         // do not put code outside this method, will run afterwards
443                         @Override
444                         protected String match(Object in) {
445                             if (in.getClass().equals(CloseTransactionReply.SERIALIZABLE_CLASS)) {
446                                 return "match";
447                             } else {
448                                 throw noMatch();
449                             }
450                         }
451                     }.get(); // this extracts the received message
452
453                     assertEquals("match", out);
454
455                     final String termination = new ExpectMsg<String>(duration("1 seconds"), "match hint") {
456                         // do not put code outside this method, will run afterwards
457                         @Override
458                         protected String match(Object in) {
459                             if (in instanceof Terminated) {
460                                 return "match";
461                             } else {
462                                 throw noMatch();
463                             }
464                         }
465                     }.get(); // this extracts the received message
466
467
468                     expectNoMsg();
469                 }
470
471
472             };
473         }};
474
475     }
476
477
478   @Test
479   public void testNegativePerformingWriteOperationOnReadTransaction() throws Exception {
480     try {
481
482         final ActorRef shard = getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP));
483         final Props props =
484             ShardTransaction.props(store.newReadOnlyTransaction(), shard, TestModel.createTestContext());
485          final TestActorRef subject = TestActorRef.apply(props,getSystem());
486
487         subject.receive(new DeleteData(TestModel.TEST_PATH).toSerializable(), ActorRef.noSender());
488         Assert.assertFalse(true);
489
490
491     } catch (Exception cs) {
492       assertEquals(UnknownMessageException.class.getSimpleName(), cs.getClass().getSimpleName());
493       assertTrue(cs.getMessage(), cs.getMessage().startsWith("Unknown message received "));
494     }
495   }
496 }