Remove dependency on general-entity
[mdsal.git] / dom / mdsal-dom-inmemory-datastore / src / test / java / org / opendaylight / controller / md / sal / dom / store / impl / InMemoryDataStoreTest.java
1 /*
2  * Copyright (c) 2014 Cisco 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.md.sal.dom.store.impl;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertFalse;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertTrue;
14
15 import com.google.common.util.concurrent.ListenableFuture;
16 import com.google.common.util.concurrent.MoreExecutors;
17 import java.util.Optional;
18 import java.util.concurrent.ExecutionException;
19 import org.junit.Assert;
20 import org.junit.Before;
21 import org.junit.Ignore;
22 import org.junit.Test;
23 import org.mockito.Mockito;
24 import org.opendaylight.mdsal.common.api.ReadFailedException;
25 import org.opendaylight.mdsal.dom.spi.store.DOMStoreReadTransaction;
26 import org.opendaylight.mdsal.dom.spi.store.DOMStoreReadWriteTransaction;
27 import org.opendaylight.mdsal.dom.spi.store.DOMStoreThreePhaseCommitCohort;
28 import org.opendaylight.mdsal.dom.spi.store.DOMStoreTransactionChain;
29 import org.opendaylight.mdsal.dom.spi.store.DOMStoreWriteTransaction;
30 import org.opendaylight.mdsal.dom.spi.store.SnapshotBackedTransactions;
31 import org.opendaylight.mdsal.dom.spi.store.SnapshotBackedWriteTransaction.TransactionReadyPrototype;
32 import org.opendaylight.mdsal.dom.store.inmemory.InMemoryDOMDataStore;
33 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
34 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
35 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
36 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
37 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
38 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
39 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
40 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
41 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
42
43 public class InMemoryDataStoreTest {
44
45     private SchemaContext schemaContext;
46     private InMemoryDOMDataStore domStore;
47
48     @Before
49     public void setupStore() {
50         domStore = new InMemoryDOMDataStore("TEST", MoreExecutors.newDirectExecutorService());
51         schemaContext = TestModel.createTestContext();
52         domStore.onGlobalContextUpdated(schemaContext);
53     }
54
55     @Test
56     public void testTransactionIsolation() throws InterruptedException, ExecutionException {
57
58         assertNotNull(domStore);
59
60         DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
61         assertNotNull(readTx);
62
63         DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
64         assertNotNull(writeTx);
65
66         /**
67          * Writes /test in writeTx.
68          */
69         NormalizedNode<?, ?> testNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
70         writeTx.write(TestModel.TEST_PATH, testNode);
71
72         /**
73          * Reads /test from writeTx Read should return container.
74          */
75         ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = writeTx.read(TestModel.TEST_PATH);
76         assertEquals("read: isPresent", true, writeTxContainer.get().isPresent());
77         assertEquals("read: data", testNode, writeTxContainer.get().get());
78
79         /**
80          * Reads /test from readTx Read should return Absent.
81          */
82         ListenableFuture<Optional<NormalizedNode<?, ?>>> readTxContainer = readTx.read(TestModel.TEST_PATH);
83         assertEquals("read: isPresent", false, readTxContainer.get().isPresent());
84     }
85
86     @Test
87     public void testTransactionCommit() throws InterruptedException, ExecutionException {
88
89         DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
90         assertNotNull(writeTx);
91
92         /**
93          * Writes /test in writeTx.
94          */
95         NormalizedNode<?, ?> testNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
96         writeTx.write(TestModel.TEST_PATH, testNode);
97
98         /**
99          * Reads /test from writeTx Read should return container.
100          */
101         ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = writeTx.read(TestModel.TEST_PATH);
102         assertEquals("read: isPresent", true, writeTxContainer.get().isPresent());
103         assertEquals("read: data", testNode, writeTxContainer.get().get());
104
105         DOMStoreThreePhaseCommitCohort cohort = writeTx.ready();
106
107         assertThreePhaseCommit(cohort);
108
109         Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH)
110                 .get();
111         assertEquals("After commit read: isPresent", true, afterCommitRead.isPresent());
112         assertEquals("After commit read: data", testNode, afterCommitRead.get());
113     }
114
115     @Test
116     public void testDelete() throws Exception {
117
118         DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
119         assertNotNull(writeTx);
120
121         // Write /test and commit
122
123         writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
124
125         assertThreePhaseCommit(writeTx.ready());
126
127         Optional<NormalizedNode<?, ?>> afterCommitRead =
128                 domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH).get();
129         assertEquals("After commit read: isPresent", true, afterCommitRead.isPresent());
130
131         // Delete /test and verify
132
133         writeTx = domStore.newWriteOnlyTransaction();
134
135         writeTx.delete(TestModel.TEST_PATH);
136
137         assertThreePhaseCommit(writeTx.ready());
138
139         afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH).get();
140         assertEquals("After commit read: isPresent", false, afterCommitRead.isPresent());
141     }
142
143     @Test
144     public void testMerge() throws Exception {
145
146         DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
147         assertNotNull(writeTx);
148
149         ContainerNode containerNode = ImmutableContainerNodeBuilder.create()
150                 .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
151                 .addChild(ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
152                         .addChild(ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME,
153                                                             TestModel.ID_QNAME, 1)).build()).build();
154
155         writeTx.merge(TestModel.TEST_PATH, containerNode);
156
157         assertThreePhaseCommit(writeTx.ready());
158
159         Optional<NormalizedNode<?, ?>> afterCommitRead =
160                 domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH).get();
161         assertEquals("After commit read: isPresent", true, afterCommitRead.isPresent());
162         assertEquals("After commit read: data", containerNode, afterCommitRead.get());
163
164         // Merge a new list entry node
165
166         writeTx = domStore.newWriteOnlyTransaction();
167         assertNotNull(writeTx);
168
169         containerNode = ImmutableContainerNodeBuilder.create()
170                 .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
171                 .addChild(ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
172                         .addChild(ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME,
173                                                             TestModel.ID_QNAME, 1))
174                         .addChild(ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME,
175                                                             TestModel.ID_QNAME, 2)).build()).build();
176
177         writeTx.merge(TestModel.TEST_PATH, containerNode);
178
179         assertThreePhaseCommit(writeTx.ready());
180
181         afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH).get();
182         assertEquals("After commit read: isPresent", true, afterCommitRead.isPresent());
183         assertEquals("After commit read: data", containerNode, afterCommitRead.get());
184     }
185
186
187     @Test
188     public void testExistsForExistingData() throws Exception {
189
190         DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
191         assertNotNull(writeTx);
192
193         ContainerNode containerNode = ImmutableContainerNodeBuilder.create()
194             .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
195             .addChild(ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
196                 .addChild(ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME,
197                     TestModel.ID_QNAME, 1)).build()).build();
198
199         writeTx.merge(TestModel.TEST_PATH, containerNode);
200
201         ListenableFuture<Boolean> exists = writeTx.exists(TestModel.TEST_PATH);
202
203         assertEquals(Boolean.TRUE, exists.get());
204
205         DOMStoreThreePhaseCommitCohort ready = writeTx.ready();
206
207         ready.preCommit().get();
208
209         ready.commit().get();
210
211         DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
212         assertNotNull(readTx);
213
214         exists =
215             readTx.exists(TestModel.TEST_PATH);
216
217         assertEquals(Boolean.TRUE, exists.get());
218     }
219
220     @Test
221     public void testExistsForNonExistingData() throws Exception {
222
223         DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
224         assertNotNull(writeTx);
225
226         ListenableFuture<Boolean> exists = writeTx.exists(TestModel.TEST_PATH);
227
228         assertEquals(Boolean.FALSE, exists.get());
229
230         DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
231         assertNotNull(readTx);
232
233         exists =
234             readTx.exists(TestModel.TEST_PATH);
235
236         assertEquals(Boolean.FALSE, exists.get());
237     }
238
239     @Test(expected = ReadFailedException.class)
240     @SuppressWarnings({"checkstyle:IllegalThrows", "checkstyle:AvoidHidingCauseException"})
241     public void testExistsThrowsReadFailedException() throws Throwable {
242
243         DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
244         assertNotNull(readTx);
245
246         readTx.close();
247
248         try {
249             readTx.exists(TestModel.TEST_PATH).get();
250         } catch (ExecutionException e) {
251             throw e.getCause();
252         }
253     }
254
255
256     @SuppressWarnings("checkstyle:IllegalThrows")
257     @Test(expected = ReadFailedException.class)
258     public void testReadWithReadOnlyTransactionClosed() throws Throwable {
259
260         DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
261         assertNotNull(readTx);
262
263         readTx.close();
264
265         doReadAndThrowEx(readTx);
266     }
267
268     @SuppressWarnings("checkstyle:IllegalThrows")
269     @Test(expected = ReadFailedException.class)
270     public void testReadWithReadOnlyTransactionFailure() throws Throwable {
271
272         DataTreeSnapshot mockSnapshot = Mockito.mock(DataTreeSnapshot.class);
273         Mockito.doThrow(new RuntimeException("mock ex")).when(mockSnapshot)
274         .readNode(Mockito.any(YangInstanceIdentifier.class));
275
276         DOMStoreReadTransaction readTx = SnapshotBackedTransactions.newReadTransaction("1", true, mockSnapshot);
277
278         doReadAndThrowEx(readTx);
279     }
280
281     @SuppressWarnings("checkstyle:IllegalThrows")
282     @Test(expected = ReadFailedException.class)
283     public void testReadWithReadWriteTransactionClosed() throws Throwable {
284
285         DOMStoreReadTransaction readTx = domStore.newReadWriteTransaction();
286         assertNotNull(readTx);
287
288         readTx.close();
289
290         doReadAndThrowEx(readTx);
291     }
292
293     @SuppressWarnings("checkstyle:IllegalThrows")
294     @Test(expected = ReadFailedException.class)
295     public void testReadWithReadWriteTransactionFailure() throws Throwable {
296
297         DataTreeSnapshot mockSnapshot = Mockito.mock(DataTreeSnapshot.class);
298         DataTreeModification mockModification = Mockito.mock(DataTreeModification.class);
299         Mockito.doThrow(new RuntimeException("mock ex")).when(mockModification)
300         .readNode(Mockito.any(YangInstanceIdentifier.class));
301         Mockito.doReturn(mockModification).when(mockSnapshot).newModification();
302         @SuppressWarnings("unchecked")
303         TransactionReadyPrototype<String> mockReady = Mockito.mock(TransactionReadyPrototype.class);
304         DOMStoreReadTransaction readTx = SnapshotBackedTransactions.newReadWriteTransaction(
305                 "1", false, mockSnapshot, mockReady);
306
307         doReadAndThrowEx(readTx);
308     }
309
310     @SuppressWarnings({ "checkstyle:IllegalThrows", "checkstyle:avoidHidingCauseException" })
311     private static void doReadAndThrowEx(final DOMStoreReadTransaction readTx) throws Throwable {
312         try {
313             readTx.read(TestModel.TEST_PATH).get();
314         } catch (ExecutionException e) {
315             throw e.getCause();
316         }
317     }
318
319     @Test(expected = IllegalStateException.class)
320     public void testWriteWithTransactionReady() throws Exception {
321
322         DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
323
324         writeTx.ready();
325
326         // Should throw ex
327         writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
328     }
329
330     @Test(expected = IllegalStateException.class)
331     public void testReadyWithTransactionAlreadyReady() throws Exception {
332
333         DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
334
335         writeTx.ready();
336
337         // Should throw ex
338         writeTx.ready();
339     }
340
341     @Test
342     public void testReadyWithMissingMandatoryData() throws InterruptedException {
343         DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
344         NormalizedNode<?, ?> testNode = ImmutableContainerNodeBuilder.create()
345                 .withNodeIdentifier(new NodeIdentifier(TestModel.MANDATORY_DATA_TEST_QNAME))
346                 .addChild(ImmutableNodes.leafNode(TestModel.OPTIONAL_QNAME, "data"))
347                 .build();
348         writeTx.write(TestModel.MANDATORY_DATA_TEST_PATH, testNode);
349         DOMStoreThreePhaseCommitCohort ready = writeTx.ready();
350         try {
351             ready.canCommit().get();
352             Assert.fail("Expected exception on canCommit");
353         } catch (ExecutionException e) {
354             // nop
355         }
356     }
357
358     @Test
359     public void testTransactionAbort() throws InterruptedException, ExecutionException {
360
361         DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
362         assertNotNull(writeTx);
363
364         assertTestContainerWrite(writeTx);
365
366         DOMStoreThreePhaseCommitCohort cohort = writeTx.ready();
367
368         assertTrue(cohort.canCommit().get().booleanValue());
369         cohort.preCommit().get();
370         cohort.abort().get();
371
372         Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH)
373                 .get();
374         assertFalse(afterCommitRead.isPresent());
375     }
376
377     @Test
378     public void testTransactionChain() throws InterruptedException, ExecutionException {
379         DOMStoreTransactionChain txChain = domStore.createTransactionChain();
380         assertNotNull(txChain);
381
382         /**
383          * We alocate new read-write transaction and write /test.
384          */
385         DOMStoreReadWriteTransaction firstTx = txChain.newReadWriteTransaction();
386         assertTestContainerWrite(firstTx);
387
388         /**
389          * First transaction is marked as ready, we are able to allocate chained
390          * transactions.
391          */
392         final DOMStoreThreePhaseCommitCohort firstWriteTxCohort = firstTx.ready();
393
394         /**
395          * We alocate chained transaction - read transaction, note first one is
396          * still not commited to datastore.
397          */
398         DOMStoreReadTransaction secondReadTx = txChain.newReadOnlyTransaction();
399
400         /**
401          * We test if we are able to read data from tx, read should not fail
402          * since we are using chained transaction.
403          */
404         assertTestContainerExists(secondReadTx);
405
406         /**
407          * We alocate next transaction, which is still based on first one, but
408          * is read-write.
409          */
410         DOMStoreReadWriteTransaction thirdDeleteTx = txChain.newReadWriteTransaction();
411
412         /**
413          * We test existence of /test in third transaction container should
414          * still be visible from first one (which is still uncommmited).
415          */
416         assertTestContainerExists(thirdDeleteTx);
417
418         /**
419          * We delete node in third transaction.
420          */
421         thirdDeleteTx.delete(TestModel.TEST_PATH);
422
423         /**
424          * third transaction is sealed.
425          */
426         DOMStoreThreePhaseCommitCohort thirdDeleteTxCohort = thirdDeleteTx.ready();
427
428         /**
429          * We commit first transaction.
430          *
431          */
432         assertThreePhaseCommit(firstWriteTxCohort);
433
434         // Alocates store transacion
435         DOMStoreReadTransaction storeReadTx = domStore.newReadOnlyTransaction();
436         /**
437          * We verify transaction is commited to store, container should exists
438          * in datastore.
439          */
440         assertTestContainerExists(storeReadTx);
441         /**
442          * We commit third transaction
443          *
444          */
445         assertThreePhaseCommit(thirdDeleteTxCohort);
446     }
447
448     @Test
449     @Ignore
450     public void testTransactionConflict() throws InterruptedException, ExecutionException {
451         DOMStoreReadWriteTransaction txOne = domStore.newReadWriteTransaction();
452         DOMStoreReadWriteTransaction txTwo = domStore.newReadWriteTransaction();
453         assertTestContainerWrite(txOne);
454         assertTestContainerWrite(txTwo);
455
456         /**
457          * Commits transaction
458          */
459         assertThreePhaseCommit(txOne.ready());
460
461         /**
462          * Asserts that txTwo could not be commited
463          */
464         assertFalse(txTwo.ready().canCommit().get());
465     }
466
467     private static void assertThreePhaseCommit(final DOMStoreThreePhaseCommitCohort cohort)
468             throws InterruptedException, ExecutionException {
469         assertTrue(cohort.canCommit().get().booleanValue());
470         cohort.preCommit().get();
471         cohort.commit().get();
472     }
473
474     private static Optional<NormalizedNode<?, ?>> assertTestContainerWrite(final DOMStoreReadWriteTransaction writeTx)
475             throws InterruptedException, ExecutionException {
476         /**
477          *
478          * Writes /test in writeTx
479          *
480          */
481         writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
482
483         return assertTestContainerExists(writeTx);
484     }
485
486     /**
487      * Reads /test from readTx Read should return container.
488      */
489     private static Optional<NormalizedNode<?, ?>> assertTestContainerExists(final DOMStoreReadTransaction readTx)
490             throws InterruptedException, ExecutionException {
491
492         ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = readTx.read(TestModel.TEST_PATH);
493         assertTrue(writeTxContainer.get().isPresent());
494         return writeTxContainer.get();
495     }
496
497 }