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