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.spi.store.DOMStoreReadTransaction;
16 import org.opendaylight.mdsal.dom.spi.store.DOMStoreReadWriteTransaction;
17 import org.opendaylight.mdsal.dom.spi.store.DOMStoreThreePhaseCommitCohort;
18 import org.opendaylight.mdsal.dom.spi.store.DOMStoreTransactionChain;
19 import org.opendaylight.mdsal.dom.spi.store.DOMStoreWriteTransaction;
20 import org.opendaylight.mdsal.dom.spi.store.SnapshotBackedTransactions;
21 import org.opendaylight.mdsal.dom.spi.store.SnapshotBackedWriteTransaction.TransactionReadyPrototype;
23 import org.opendaylight.mdsal.common.api.ReadFailedException;
24 import com.google.common.base.Optional;
25 import com.google.common.util.concurrent.CheckedFuture;
26 import com.google.common.util.concurrent.ListenableFuture;
27 import com.google.common.util.concurrent.MoreExecutors;
28 import java.util.concurrent.ExecutionException;
29 import org.junit.Before;
30 import org.junit.Ignore;
31 import org.junit.Test;
32 import org.mockito.Mockito;
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;
43 public class InMemoryDataStoreTest {
45 private SchemaContext schemaContext;
46 private InMemoryDOMDataStore domStore;
49 public void setupStore() {
50 domStore = new InMemoryDOMDataStore("TEST", MoreExecutors.newDirectExecutorService());
51 schemaContext = TestModel.createTestContext();
52 domStore.onGlobalContextUpdated(schemaContext);
56 public void testTransactionIsolation() throws InterruptedException, ExecutionException {
58 assertNotNull(domStore);
60 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
61 assertNotNull(readTx);
63 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
64 assertNotNull(writeTx);
67 * Writes /test in writeTx
69 NormalizedNode<?, ?> testNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
70 writeTx.write(TestModel.TEST_PATH, testNode);
73 * Reads /test from writeTx Read should return container.
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());
80 * Reads /test from readTx Read should return Absent.
82 ListenableFuture<Optional<NormalizedNode<?, ?>>> readTxContainer = readTx.read(TestModel.TEST_PATH);
83 assertEquals("read: isPresent", false, readTxContainer.get().isPresent());
87 public void testTransactionCommit() throws InterruptedException, ExecutionException {
89 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
90 assertNotNull(writeTx);
93 * Writes /test in writeTx
95 NormalizedNode<?, ?> testNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
96 writeTx.write(TestModel.TEST_PATH, testNode);
99 * Reads /test from writeTx Read should return container.
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());
105 DOMStoreThreePhaseCommitCohort cohort = writeTx.ready();
107 assertThreePhaseCommit(cohort);
109 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH)
111 assertEquals("After commit read: isPresent", true, afterCommitRead.isPresent());
112 assertEquals("After commit read: data", testNode, afterCommitRead.get());
116 public void testDelete() throws Exception {
118 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
119 assertNotNull( writeTx );
121 // Write /test and commit
123 writeTx.write( TestModel.TEST_PATH, ImmutableNodes.containerNode( TestModel.TEST_QNAME ) );
125 assertThreePhaseCommit( writeTx.ready() );
127 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().
128 read(TestModel.TEST_PATH ).get();
129 assertEquals( "After commit read: isPresent", true, afterCommitRead.isPresent() );
131 // Delete /test and verify
133 writeTx = domStore.newWriteOnlyTransaction();
135 writeTx.delete( TestModel.TEST_PATH );
137 assertThreePhaseCommit( writeTx.ready() );
139 afterCommitRead = domStore.newReadOnlyTransaction().
140 read(TestModel.TEST_PATH ).get();
141 assertEquals( "After commit read: isPresent", false, afterCommitRead.isPresent() );
145 public void testMerge() throws Exception {
147 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
148 assertNotNull( writeTx );
150 ContainerNode containerNode = ImmutableContainerNodeBuilder.create()
151 .withNodeIdentifier( new NodeIdentifier( TestModel.TEST_QNAME ) )
152 .addChild( ImmutableNodes.mapNodeBuilder( TestModel.OUTER_LIST_QNAME )
153 .addChild( ImmutableNodes.mapEntry( TestModel.OUTER_LIST_QNAME,
154 TestModel.ID_QNAME, 1 ) ).build() ).build();
156 writeTx.merge( TestModel.TEST_PATH, containerNode );
158 assertThreePhaseCommit( writeTx.ready() );
160 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().
161 read(TestModel.TEST_PATH ).get();
162 assertEquals( "After commit read: isPresent", true, afterCommitRead.isPresent() );
163 assertEquals( "After commit read: data", containerNode, afterCommitRead.get() );
165 // Merge a new list entry node
167 writeTx = domStore.newWriteOnlyTransaction();
168 assertNotNull( writeTx );
170 containerNode = ImmutableContainerNodeBuilder.create()
171 .withNodeIdentifier( new NodeIdentifier( TestModel.TEST_QNAME ) )
172 .addChild( ImmutableNodes.mapNodeBuilder( TestModel.OUTER_LIST_QNAME )
173 .addChild( ImmutableNodes.mapEntry( TestModel.OUTER_LIST_QNAME,
174 TestModel.ID_QNAME, 1 ) )
175 .addChild( ImmutableNodes.mapEntry( TestModel.OUTER_LIST_QNAME,
176 TestModel.ID_QNAME, 2 ) ).build() ).build();
178 writeTx.merge( TestModel.TEST_PATH, containerNode );
180 assertThreePhaseCommit( writeTx.ready() );
182 afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH ).get();
183 assertEquals( "After commit read: isPresent", true, afterCommitRead.isPresent() );
184 assertEquals( "After commit read: data", containerNode, afterCommitRead.get() );
189 public void testExistsForExistingData() throws Exception {
191 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
192 assertNotNull( writeTx );
194 ContainerNode containerNode = ImmutableContainerNodeBuilder.create()
195 .withNodeIdentifier( new NodeIdentifier( TestModel.TEST_QNAME ) )
196 .addChild( ImmutableNodes.mapNodeBuilder( TestModel.OUTER_LIST_QNAME )
197 .addChild( ImmutableNodes.mapEntry( TestModel.OUTER_LIST_QNAME,
198 TestModel.ID_QNAME, 1 ) ).build() ).build();
200 writeTx.merge( TestModel.TEST_PATH, containerNode );
202 CheckedFuture<Boolean, ReadFailedException> exists =
203 writeTx.exists(TestModel.TEST_PATH);
205 assertEquals(true, exists.checkedGet());
207 DOMStoreThreePhaseCommitCohort ready = writeTx.ready();
209 ready.preCommit().get();
211 ready.commit().get();
213 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
214 assertNotNull( readTx );
217 readTx.exists(TestModel.TEST_PATH);
219 assertEquals(true, exists.checkedGet());
223 public void testExistsForNonExistingData() throws Exception {
225 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
226 assertNotNull( writeTx );
228 CheckedFuture<Boolean, ReadFailedException> exists =
229 writeTx.exists(TestModel.TEST_PATH);
231 assertEquals(false, exists.checkedGet());
233 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
234 assertNotNull( readTx );
237 readTx.exists(TestModel.TEST_PATH);
239 assertEquals(false, exists.checkedGet());
242 @Test(expected=ReadFailedException.class)
243 public void testExistsThrowsReadFailedException() throws Exception {
245 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
246 assertNotNull( readTx );
250 readTx.exists(TestModel.TEST_PATH).checkedGet();
255 @Test(expected=ReadFailedException.class)
256 public void testReadWithReadOnlyTransactionClosed() throws Throwable {
258 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
259 assertNotNull( readTx );
263 doReadAndThrowEx( readTx );
266 @Test(expected=ReadFailedException.class)
267 public void testReadWithReadOnlyTransactionFailure() throws Throwable {
269 DataTreeSnapshot mockSnapshot = Mockito.mock( DataTreeSnapshot.class );
270 Mockito.doThrow( new RuntimeException( "mock ex" ) ).when( mockSnapshot )
271 .readNode( Mockito.any( YangInstanceIdentifier.class ) );
273 DOMStoreReadTransaction readTx = SnapshotBackedTransactions.newReadTransaction("1", true, mockSnapshot);
275 doReadAndThrowEx( readTx );
278 @Test(expected=ReadFailedException.class)
279 public void testReadWithReadWriteTransactionClosed() throws Throwable {
281 DOMStoreReadTransaction readTx = domStore.newReadWriteTransaction();
282 assertNotNull( readTx );
286 doReadAndThrowEx( readTx );
289 @Test(expected=ReadFailedException.class)
290 public void testReadWithReadWriteTransactionFailure() throws Throwable {
292 DataTreeSnapshot mockSnapshot = Mockito.mock( DataTreeSnapshot.class );
293 DataTreeModification mockModification = Mockito.mock( DataTreeModification.class );
294 Mockito.doThrow( new RuntimeException( "mock ex" ) ).when( mockModification )
295 .readNode( Mockito.any( YangInstanceIdentifier.class ) );
296 Mockito.doReturn( mockModification ).when( mockSnapshot ).newModification();
297 @SuppressWarnings("unchecked")
298 TransactionReadyPrototype<String> mockReady = Mockito.mock( TransactionReadyPrototype.class );
299 DOMStoreReadTransaction readTx = SnapshotBackedTransactions.newReadWriteTransaction("1", false, mockSnapshot, mockReady);
301 doReadAndThrowEx( readTx );
304 private static void doReadAndThrowEx( final DOMStoreReadTransaction readTx ) throws Throwable {
306 readTx.read(TestModel.TEST_PATH).get();
307 } catch( ExecutionException e ) {
312 @Test(expected=IllegalStateException.class)
313 public void testWriteWithTransactionReady() throws Exception {
315 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
320 writeTx.write( TestModel.TEST_PATH, ImmutableNodes.containerNode( TestModel.TEST_QNAME ) );
323 @Test(expected=IllegalStateException.class)
324 public void testReadyWithTransactionAlreadyReady() throws Exception {
326 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
335 public void testTransactionAbort() throws InterruptedException, ExecutionException {
337 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
338 assertNotNull(writeTx);
340 assertTestContainerWrite(writeTx);
342 DOMStoreThreePhaseCommitCohort cohort = writeTx.ready();
344 assertTrue(cohort.canCommit().get().booleanValue());
345 cohort.preCommit().get();
346 cohort.abort().get();
348 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH)
350 assertFalse(afterCommitRead.isPresent());
354 public void testTransactionChain() throws InterruptedException, ExecutionException {
355 DOMStoreTransactionChain txChain = domStore.createTransactionChain();
356 assertNotNull(txChain);
359 * We alocate new read-write transaction and write /test
363 DOMStoreReadWriteTransaction firstTx = txChain.newReadWriteTransaction();
364 assertTestContainerWrite(firstTx);
367 * First transaction is marked as ready, we are able to allocate chained
370 DOMStoreThreePhaseCommitCohort firstWriteTxCohort = firstTx.ready();
373 * We alocate chained transaction - read transaction, note first one is
374 * still not commited to datastore.
376 DOMStoreReadTransaction secondReadTx = txChain.newReadOnlyTransaction();
380 * We test if we are able to read data from tx, read should not fail
381 * since we are using chained transaction.
385 assertTestContainerExists(secondReadTx);
389 * We alocate next transaction, which is still based on first one, but
393 DOMStoreReadWriteTransaction thirdDeleteTx = txChain.newReadWriteTransaction();
396 * We test existence of /test in third transaction container should
397 * still be visible from first one (which is still uncommmited).
401 assertTestContainerExists(thirdDeleteTx);
404 * We delete node in third transaction
406 thirdDeleteTx.delete(TestModel.TEST_PATH);
409 * third transaction is sealed.
411 DOMStoreThreePhaseCommitCohort thirdDeleteTxCohort = thirdDeleteTx.ready();
414 * We commit first transaction
417 assertThreePhaseCommit(firstWriteTxCohort);
419 // Alocates store transacion
420 DOMStoreReadTransaction storeReadTx = domStore.newReadOnlyTransaction();
422 * We verify transaction is commited to store, container should exists
425 assertTestContainerExists(storeReadTx);
427 * We commit third transaction
430 assertThreePhaseCommit(thirdDeleteTxCohort);
435 public void testTransactionConflict() throws InterruptedException, ExecutionException {
436 DOMStoreReadWriteTransaction txOne = domStore.newReadWriteTransaction();
437 DOMStoreReadWriteTransaction txTwo = domStore.newReadWriteTransaction();
438 assertTestContainerWrite(txOne);
439 assertTestContainerWrite(txTwo);
442 * Commits transaction
444 assertThreePhaseCommit(txOne.ready());
447 * Asserts that txTwo could not be commited
449 assertFalse(txTwo.ready().canCommit().get());
452 private static void assertThreePhaseCommit(final DOMStoreThreePhaseCommitCohort cohort)
453 throws InterruptedException, ExecutionException {
454 assertTrue(cohort.canCommit().get().booleanValue());
455 cohort.preCommit().get();
456 cohort.commit().get();
459 private static Optional<NormalizedNode<?, ?>> assertTestContainerWrite(final DOMStoreReadWriteTransaction writeTx)
460 throws InterruptedException, ExecutionException {
463 * Writes /test in writeTx
466 writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
468 return assertTestContainerExists(writeTx);
472 * Reads /test from readTx Read should return container.
474 private static Optional<NormalizedNode<?, ?>> assertTestContainerExists(final DOMStoreReadTransaction readTx)
475 throws InterruptedException, ExecutionException {
477 ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = readTx.read(TestModel.TEST_PATH);
478 assertTrue(writeTxContainer.get().isPresent());
479 return writeTxContainer.get();