2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.controller.md.sal.dom.store.impl;
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;
15 import org.opendaylight.mdsal.dom.store.inmemory.InMemoryDOMDataStore;
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;
46 public class InMemoryDataStoreTest {
48 private SchemaContext schemaContext;
49 private InMemoryDOMDataStore domStore;
52 public void setupStore() throws IOException, YangSyntaxErrorException {
53 domStore = new InMemoryDOMDataStore("TEST", MoreExecutors.newDirectExecutorService());
54 schemaContext = TestModel.createTestContext();
55 domStore.onGlobalContextUpdated(schemaContext);
59 public void testTransactionIsolation() throws InterruptedException, ExecutionException {
61 assertNotNull(domStore);
63 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
64 assertNotNull(readTx);
66 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
67 assertNotNull(writeTx);
70 * Writes /test in writeTx
72 NormalizedNode<?, ?> testNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
73 writeTx.write(TestModel.TEST_PATH, testNode);
76 * Reads /test from writeTx Read should return container.
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());
83 * Reads /test from readTx Read should return Absent.
85 ListenableFuture<Optional<NormalizedNode<?, ?>>> readTxContainer = readTx.read(TestModel.TEST_PATH);
86 assertEquals("read: isPresent", false, readTxContainer.get().isPresent());
90 public void testTransactionCommit() throws InterruptedException, ExecutionException {
92 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
93 assertNotNull(writeTx);
96 * Writes /test in writeTx
98 NormalizedNode<?, ?> testNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
99 writeTx.write(TestModel.TEST_PATH, testNode);
102 * Reads /test from writeTx Read should return container.
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());
108 DOMStoreThreePhaseCommitCohort cohort = writeTx.ready();
110 assertThreePhaseCommit(cohort);
112 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH)
114 assertEquals("After commit read: isPresent", true, afterCommitRead.isPresent());
115 assertEquals("After commit read: data", testNode, afterCommitRead.get());
119 public void testDelete() throws Exception {
121 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
122 assertNotNull( writeTx );
124 // Write /test and commit
126 writeTx.write( TestModel.TEST_PATH, ImmutableNodes.containerNode( TestModel.TEST_QNAME ) );
128 assertThreePhaseCommit( writeTx.ready() );
130 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().
131 read(TestModel.TEST_PATH ).get();
132 assertEquals( "After commit read: isPresent", true, afterCommitRead.isPresent() );
134 // Delete /test and verify
136 writeTx = domStore.newWriteOnlyTransaction();
138 writeTx.delete( TestModel.TEST_PATH );
140 assertThreePhaseCommit( writeTx.ready() );
142 afterCommitRead = domStore.newReadOnlyTransaction().
143 read(TestModel.TEST_PATH ).get();
144 assertEquals( "After commit read: isPresent", false, afterCommitRead.isPresent() );
148 public void testMerge() throws Exception {
150 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
151 assertNotNull( writeTx );
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();
159 writeTx.merge( TestModel.TEST_PATH, containerNode );
161 assertThreePhaseCommit( writeTx.ready() );
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() );
168 // Merge a new list entry node
170 writeTx = domStore.newWriteOnlyTransaction();
171 assertNotNull( writeTx );
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();
181 writeTx.merge( TestModel.TEST_PATH, containerNode );
183 assertThreePhaseCommit( writeTx.ready() );
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() );
192 public void testExistsForExistingData() throws Exception {
194 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
195 assertNotNull( writeTx );
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();
203 writeTx.merge( TestModel.TEST_PATH, containerNode );
205 CheckedFuture<Boolean, ReadFailedException> exists =
206 writeTx.exists(TestModel.TEST_PATH);
208 assertEquals(true, exists.checkedGet());
210 DOMStoreThreePhaseCommitCohort ready = writeTx.ready();
212 ready.preCommit().get();
214 ready.commit().get();
216 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
217 assertNotNull( readTx );
220 readTx.exists(TestModel.TEST_PATH);
222 assertEquals(true, exists.checkedGet());
226 public void testExistsForNonExistingData() throws Exception {
228 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
229 assertNotNull( writeTx );
231 CheckedFuture<Boolean, ReadFailedException> exists =
232 writeTx.exists(TestModel.TEST_PATH);
234 assertEquals(false, exists.checkedGet());
236 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
237 assertNotNull( readTx );
240 readTx.exists(TestModel.TEST_PATH);
242 assertEquals(false, exists.checkedGet());
245 @Test(expected=ReadFailedException.class)
246 public void testExistsThrowsReadFailedException() throws Exception {
248 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
249 assertNotNull( readTx );
253 readTx.exists(TestModel.TEST_PATH).checkedGet();
258 @Test(expected=ReadFailedException.class)
259 public void testReadWithReadOnlyTransactionClosed() throws Throwable {
261 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
262 assertNotNull( readTx );
266 doReadAndThrowEx( readTx );
269 @Test(expected=ReadFailedException.class)
270 public void testReadWithReadOnlyTransactionFailure() throws Throwable {
272 DataTreeSnapshot mockSnapshot = Mockito.mock( DataTreeSnapshot.class );
273 Mockito.doThrow( new RuntimeException( "mock ex" ) ).when( mockSnapshot )
274 .readNode( Mockito.any( YangInstanceIdentifier.class ) );
276 DOMStoreReadTransaction readTx = SnapshotBackedTransactions.newReadTransaction("1", true, mockSnapshot);
278 doReadAndThrowEx( readTx );
281 @Test(expected=ReadFailedException.class)
282 public void testReadWithReadWriteTransactionClosed() throws Throwable {
284 DOMStoreReadTransaction readTx = domStore.newReadWriteTransaction();
285 assertNotNull( readTx );
289 doReadAndThrowEx( readTx );
292 @Test(expected=ReadFailedException.class)
293 public void testReadWithReadWriteTransactionFailure() throws Throwable {
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);
304 doReadAndThrowEx( readTx );
307 private static void doReadAndThrowEx( final DOMStoreReadTransaction readTx ) throws Throwable {
309 readTx.read(TestModel.TEST_PATH).get();
310 } catch( ExecutionException e ) {
315 @Test(expected=IllegalStateException.class)
316 public void testWriteWithTransactionReady() throws Exception {
318 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
323 writeTx.write( TestModel.TEST_PATH, ImmutableNodes.containerNode( TestModel.TEST_QNAME ) );
326 @Test(expected=IllegalStateException.class)
327 public void testReadyWithTransactionAlreadyReady() throws Exception {
329 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
338 public void testTransactionAbort() throws InterruptedException, ExecutionException {
340 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
341 assertNotNull(writeTx);
343 assertTestContainerWrite(writeTx);
345 DOMStoreThreePhaseCommitCohort cohort = writeTx.ready();
347 assertTrue(cohort.canCommit().get().booleanValue());
348 cohort.preCommit().get();
349 cohort.abort().get();
351 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH)
353 assertFalse(afterCommitRead.isPresent());
357 public void testTransactionChain() throws InterruptedException, ExecutionException {
358 DOMStoreTransactionChain txChain = domStore.createTransactionChain();
359 assertNotNull(txChain);
362 * We alocate new read-write transaction and write /test
366 DOMStoreReadWriteTransaction firstTx = txChain.newReadWriteTransaction();
367 assertTestContainerWrite(firstTx);
370 * First transaction is marked as ready, we are able to allocate chained
373 DOMStoreThreePhaseCommitCohort firstWriteTxCohort = firstTx.ready();
376 * We alocate chained transaction - read transaction, note first one is
377 * still not commited to datastore.
379 DOMStoreReadTransaction secondReadTx = txChain.newReadOnlyTransaction();
383 * We test if we are able to read data from tx, read should not fail
384 * since we are using chained transaction.
388 assertTestContainerExists(secondReadTx);
392 * We alocate next transaction, which is still based on first one, but
396 DOMStoreReadWriteTransaction thirdDeleteTx = txChain.newReadWriteTransaction();
399 * We test existence of /test in third transaction container should
400 * still be visible from first one (which is still uncommmited).
404 assertTestContainerExists(thirdDeleteTx);
407 * We delete node in third transaction
409 thirdDeleteTx.delete(TestModel.TEST_PATH);
412 * third transaction is sealed.
414 DOMStoreThreePhaseCommitCohort thirdDeleteTxCohort = thirdDeleteTx.ready();
417 * We commit first transaction
420 assertThreePhaseCommit(firstWriteTxCohort);
422 // Alocates store transacion
423 DOMStoreReadTransaction storeReadTx = domStore.newReadOnlyTransaction();
425 * We verify transaction is commited to store, container should exists
428 assertTestContainerExists(storeReadTx);
430 * We commit third transaction
433 assertThreePhaseCommit(thirdDeleteTxCohort);
438 public void testTransactionConflict() throws InterruptedException, ExecutionException {
439 DOMStoreReadWriteTransaction txOne = domStore.newReadWriteTransaction();
440 DOMStoreReadWriteTransaction txTwo = domStore.newReadWriteTransaction();
441 assertTestContainerWrite(txOne);
442 assertTestContainerWrite(txTwo);
445 * Commits transaction
447 assertThreePhaseCommit(txOne.ready());
450 * Asserts that txTwo could not be commited
452 assertFalse(txTwo.ready().canCommit().get());
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();
462 private static Optional<NormalizedNode<?, ?>> assertTestContainerWrite(final DOMStoreReadWriteTransaction writeTx)
463 throws InterruptedException, ExecutionException {
466 * Writes /test in writeTx
469 writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
471 return assertTestContainerExists(writeTx);
475 * Reads /test from readTx Read should return container.
477 private static Optional<NormalizedNode<?, ?>> assertTestContainerExists(final DOMStoreReadTransaction readTx)
478 throws InterruptedException, ExecutionException {
480 ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = readTx.read(TestModel.TEST_PATH);
481 assertTrue(writeTxContainer.get().isPresent());
482 return writeTxContainer.get();