checkStyleViolationSeverity=error implemented for mdsal-dom-inmemory-datastore
[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.base.Optional;
16 import com.google.common.util.concurrent.CheckedFuture;
17 import com.google.common.util.concurrent.ListenableFuture;
18 import com.google.common.util.concurrent.MoreExecutors;
19 import java.io.IOException;
20 import java.util.concurrent.ExecutionException;
21 import org.junit.Before;
22 import org.junit.Ignore;
23 import org.junit.Test;
24 import org.mockito.Mockito;
25 import org.opendaylight.mdsal.common.api.ReadFailedException;
26 import org.opendaylight.mdsal.dom.spi.store.DOMStoreReadTransaction;
27 import org.opendaylight.mdsal.dom.spi.store.DOMStoreReadWriteTransaction;
28 import org.opendaylight.mdsal.dom.spi.store.DOMStoreThreePhaseCommitCohort;
29 import org.opendaylight.mdsal.dom.spi.store.DOMStoreTransactionChain;
30 import org.opendaylight.mdsal.dom.spi.store.DOMStoreWriteTransaction;
31 import org.opendaylight.mdsal.dom.spi.store.SnapshotBackedTransactions;
32 import org.opendaylight.mdsal.dom.spi.store.SnapshotBackedWriteTransaction.TransactionReadyPrototype;
33 import org.opendaylight.mdsal.dom.store.inmemory.InMemoryDOMDataStore;
34 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
35 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
36 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
37 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
38 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
39 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
40 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
41 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
42 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
43 import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
44 import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
45
46 public class InMemoryDataStoreTest {
47
48     private SchemaContext schemaContext;
49     private InMemoryDOMDataStore domStore;
50
51     @Before
52     public void setupStore() throws IOException, YangSyntaxErrorException, ReactorException {
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 =
131                 domStore.newReadOnlyTransaction().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().read(TestModel.TEST_PATH ).get();
143         assertEquals( "After commit read: isPresent", false, afterCommitRead.isPresent() );
144     }
145
146     @Test
147     public void testMerge() throws Exception {
148
149         DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
150         assertNotNull( writeTx );
151
152         ContainerNode containerNode = ImmutableContainerNodeBuilder.create()
153                 .withNodeIdentifier( new NodeIdentifier( TestModel.TEST_QNAME ) )
154                 .addChild( ImmutableNodes.mapNodeBuilder( TestModel.OUTER_LIST_QNAME )
155                         .addChild( ImmutableNodes.mapEntry( TestModel.OUTER_LIST_QNAME,
156                                                             TestModel.ID_QNAME, 1 ) ).build() ).build();
157
158         writeTx.merge( TestModel.TEST_PATH, containerNode );
159
160         assertThreePhaseCommit( writeTx.ready() );
161
162         Optional<NormalizedNode<?, ?>> afterCommitRead =
163                 domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH ).get();
164         assertEquals( "After commit read: isPresent", true, afterCommitRead.isPresent() );
165         assertEquals( "After commit read: data", containerNode, afterCommitRead.get() );
166
167         // Merge a new list entry node
168
169         writeTx = domStore.newWriteOnlyTransaction();
170         assertNotNull( writeTx );
171
172         containerNode = ImmutableContainerNodeBuilder.create()
173                 .withNodeIdentifier( new NodeIdentifier( TestModel.TEST_QNAME ) )
174                 .addChild( ImmutableNodes.mapNodeBuilder( TestModel.OUTER_LIST_QNAME )
175                         .addChild( ImmutableNodes.mapEntry( TestModel.OUTER_LIST_QNAME,
176                                                             TestModel.ID_QNAME, 1 ) )
177                         .addChild( ImmutableNodes.mapEntry( TestModel.OUTER_LIST_QNAME,
178                                                             TestModel.ID_QNAME, 2 ) ).build() ).build();
179
180         writeTx.merge( TestModel.TEST_PATH, containerNode );
181
182         assertThreePhaseCommit( writeTx.ready() );
183
184         afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH ).get();
185         assertEquals( "After commit read: isPresent", true, afterCommitRead.isPresent() );
186         assertEquals( "After commit read: data", containerNode, afterCommitRead.get() );
187     }
188
189
190     @Test
191     public void testExistsForExistingData() throws Exception {
192
193         DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
194         assertNotNull( writeTx );
195
196         ContainerNode containerNode = ImmutableContainerNodeBuilder.create()
197             .withNodeIdentifier( new NodeIdentifier( TestModel.TEST_QNAME ) )
198             .addChild( ImmutableNodes.mapNodeBuilder( TestModel.OUTER_LIST_QNAME )
199                 .addChild( ImmutableNodes.mapEntry( TestModel.OUTER_LIST_QNAME,
200                     TestModel.ID_QNAME, 1 ) ).build() ).build();
201
202         writeTx.merge( TestModel.TEST_PATH, containerNode );
203
204         CheckedFuture<Boolean, ReadFailedException> exists =
205             writeTx.exists(TestModel.TEST_PATH);
206
207         assertEquals(true, exists.checkedGet());
208
209         DOMStoreThreePhaseCommitCohort ready = writeTx.ready();
210
211         ready.preCommit().get();
212
213         ready.commit().get();
214
215         DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
216         assertNotNull( readTx );
217
218         exists =
219             readTx.exists(TestModel.TEST_PATH);
220
221         assertEquals(true, exists.checkedGet());
222     }
223
224     @Test
225     public void testExistsForNonExistingData() throws Exception {
226
227         DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
228         assertNotNull( writeTx );
229
230         CheckedFuture<Boolean, ReadFailedException> exists =
231             writeTx.exists(TestModel.TEST_PATH);
232
233         assertEquals(false, exists.checkedGet());
234
235         DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
236         assertNotNull( readTx );
237
238         exists =
239             readTx.exists(TestModel.TEST_PATH);
240
241         assertEquals(false, exists.checkedGet());
242     }
243
244     @Test(expected = ReadFailedException.class)
245     public void testExistsThrowsReadFailedException() throws Exception {
246
247         DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
248         assertNotNull( readTx );
249
250         readTx.close();
251
252         readTx.exists(TestModel.TEST_PATH).checkedGet();
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")
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 testTransactionAbort() throws InterruptedException, ExecutionException {
343
344         DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
345         assertNotNull(writeTx);
346
347         assertTestContainerWrite(writeTx);
348
349         DOMStoreThreePhaseCommitCohort cohort = writeTx.ready();
350
351         assertTrue(cohort.canCommit().get().booleanValue());
352         cohort.preCommit().get();
353         cohort.abort().get();
354
355         Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH)
356                 .get();
357         assertFalse(afterCommitRead.isPresent());
358     }
359
360     @Test
361     public void testTransactionChain() throws InterruptedException, ExecutionException {
362         DOMStoreTransactionChain txChain = domStore.createTransactionChain();
363         assertNotNull(txChain);
364
365         /**
366          * We alocate new read-write transaction and write /test.
367          */
368         DOMStoreReadWriteTransaction firstTx = txChain.newReadWriteTransaction();
369         assertTestContainerWrite(firstTx);
370
371         /**
372          * First transaction is marked as ready, we are able to allocate chained
373          * transactions.
374          */
375         final DOMStoreThreePhaseCommitCohort firstWriteTxCohort = firstTx.ready();
376
377         /**
378          * We alocate chained transaction - read transaction, note first one is
379          * still not commited to datastore.
380          */
381         DOMStoreReadTransaction secondReadTx = txChain.newReadOnlyTransaction();
382
383         /**
384          * We test if we are able to read data from tx, read should not fail
385          * since we are using chained transaction.
386          */
387         assertTestContainerExists(secondReadTx);
388
389         /**
390          * We alocate next transaction, which is still based on first one, but
391          * is read-write.
392          */
393         DOMStoreReadWriteTransaction thirdDeleteTx = txChain.newReadWriteTransaction();
394
395         /**
396          * We test existence of /test in third transaction container should
397          * still be visible from first one (which is still uncommmited).
398          */
399         assertTestContainerExists(thirdDeleteTx);
400
401         /**
402          * We delete node in third transaction.
403          */
404         thirdDeleteTx.delete(TestModel.TEST_PATH);
405
406         /**
407          * third transaction is sealed.
408          */
409         DOMStoreThreePhaseCommitCohort thirdDeleteTxCohort = thirdDeleteTx.ready();
410
411         /**
412          * We commit first transaction.
413          *
414          */
415         assertThreePhaseCommit(firstWriteTxCohort);
416
417         // Alocates store transacion
418         DOMStoreReadTransaction storeReadTx = domStore.newReadOnlyTransaction();
419         /**
420          * We verify transaction is commited to store, container should exists
421          * in datastore.
422          */
423         assertTestContainerExists(storeReadTx);
424         /**
425          * We commit third transaction
426          *
427          */
428         assertThreePhaseCommit(thirdDeleteTxCohort);
429     }
430
431     @Test
432     @Ignore
433     public void testTransactionConflict() throws InterruptedException, ExecutionException {
434         DOMStoreReadWriteTransaction txOne = domStore.newReadWriteTransaction();
435         DOMStoreReadWriteTransaction txTwo = domStore.newReadWriteTransaction();
436         assertTestContainerWrite(txOne);
437         assertTestContainerWrite(txTwo);
438
439         /**
440          * Commits transaction
441          */
442         assertThreePhaseCommit(txOne.ready());
443
444         /**
445          * Asserts that txTwo could not be commited
446          */
447         assertFalse(txTwo.ready().canCommit().get());
448     }
449
450     private static void assertThreePhaseCommit(final DOMStoreThreePhaseCommitCohort cohort)
451             throws InterruptedException, ExecutionException {
452         assertTrue(cohort.canCommit().get().booleanValue());
453         cohort.preCommit().get();
454         cohort.commit().get();
455     }
456
457     private static Optional<NormalizedNode<?, ?>> assertTestContainerWrite(final DOMStoreReadWriteTransaction writeTx)
458             throws InterruptedException, ExecutionException {
459         /**
460          *
461          * Writes /test in writeTx
462          *
463          */
464         writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
465
466         return assertTestContainerExists(writeTx);
467     }
468
469     /**
470      * Reads /test from readTx Read should return container.
471      */
472     private static Optional<NormalizedNode<?, ?>> assertTestContainerExists(final DOMStoreReadTransaction readTx)
473             throws InterruptedException, ExecutionException {
474
475         ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = readTx.read(TestModel.TEST_PATH);
476         assertTrue(writeTxContainer.get().isPresent());
477         return writeTxContainer.get();
478     }
479
480 }