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