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 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;
20 import java.util.concurrent.ExecutionException;
22 import org.junit.Before;
23 import org.junit.Ignore;
24 import org.junit.Test;
25 import org.mockito.Mockito;
26 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
27 import org.opendaylight.controller.md.sal.dom.store.impl.SnapshotBackedWriteTransaction.TransactionReadyPrototype;
28 import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction;
29 import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
30 import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
31 import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain;
32 import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction;
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;
44 public class InMemoryDataStoreTest {
46 private SchemaContext schemaContext;
47 private InMemoryDOMDataStore domStore;
50 public void setupStore() {
51 domStore = new InMemoryDOMDataStore("TEST", MoreExecutors.sameThreadExecutor(),
52 MoreExecutors.sameThreadExecutor());
53 schemaContext = TestModel.createTestContext();
54 domStore.onGlobalContextUpdated(schemaContext);
58 public void testTransactionIsolation() throws InterruptedException, ExecutionException {
60 assertNotNull(domStore);
62 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
63 assertNotNull(readTx);
65 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
66 assertNotNull(writeTx);
69 * Writes /test in writeTx
71 NormalizedNode<?, ?> testNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
72 writeTx.write(TestModel.TEST_PATH, testNode);
75 * Reads /test from writeTx Read should return container.
77 ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = writeTx.read(TestModel.TEST_PATH);
78 assertEquals("read: isPresent", true, writeTxContainer.get().isPresent());
79 assertEquals("read: data", testNode, writeTxContainer.get().get());
82 * Reads /test from readTx Read should return Absent.
84 ListenableFuture<Optional<NormalizedNode<?, ?>>> readTxContainer = readTx.read(TestModel.TEST_PATH);
85 assertEquals("read: isPresent", false, readTxContainer.get().isPresent());
89 public void testTransactionCommit() throws InterruptedException, ExecutionException {
91 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
92 assertNotNull(writeTx);
95 * Writes /test in writeTx
97 NormalizedNode<?, ?> testNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
98 writeTx.write(TestModel.TEST_PATH, testNode);
101 * Reads /test from writeTx Read should return container.
103 ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = writeTx.read(TestModel.TEST_PATH);
104 assertEquals("read: isPresent", true, writeTxContainer.get().isPresent());
105 assertEquals("read: data", testNode, writeTxContainer.get().get());
107 DOMStoreThreePhaseCommitCohort cohort = writeTx.ready();
109 assertThreePhaseCommit(cohort);
111 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH)
113 assertEquals("After commit read: isPresent", true, afterCommitRead.isPresent());
114 assertEquals("After commit read: data", testNode, afterCommitRead.get());
118 public void testDelete() throws Exception {
120 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
121 assertNotNull( writeTx );
123 // Write /test and commit
125 writeTx.write( TestModel.TEST_PATH, ImmutableNodes.containerNode( TestModel.TEST_QNAME ) );
127 assertThreePhaseCommit( writeTx.ready() );
129 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().
130 read(TestModel.TEST_PATH ).get();
131 assertEquals( "After commit read: isPresent", true, afterCommitRead.isPresent() );
133 // Delete /test and verify
135 writeTx = domStore.newWriteOnlyTransaction();
137 writeTx.delete( TestModel.TEST_PATH );
139 assertThreePhaseCommit( writeTx.ready() );
141 afterCommitRead = domStore.newReadOnlyTransaction().
142 read(TestModel.TEST_PATH ).get();
143 assertEquals( "After commit read: isPresent", false, afterCommitRead.isPresent() );
147 public void testMerge() throws Exception {
149 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
150 assertNotNull( writeTx );
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();
158 writeTx.merge( TestModel.TEST_PATH, containerNode );
160 assertThreePhaseCommit( writeTx.ready() );
162 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().
163 read(TestModel.TEST_PATH ).get();
164 assertEquals( "After commit read: isPresent", true, afterCommitRead.isPresent() );
165 assertEquals( "After commit read: data", containerNode, afterCommitRead.get() );
167 // Merge a new list entry node
169 writeTx = domStore.newWriteOnlyTransaction();
170 assertNotNull( writeTx );
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();
180 writeTx.merge( TestModel.TEST_PATH, containerNode );
182 assertThreePhaseCommit( writeTx.ready() );
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() );
191 public void testExistsForExistingData() throws Exception {
193 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
194 assertNotNull( writeTx );
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();
202 writeTx.merge( TestModel.TEST_PATH, containerNode );
204 CheckedFuture<Boolean, ReadFailedException> exists =
205 writeTx.exists(TestModel.TEST_PATH);
207 assertEquals(true, exists.checkedGet());
209 DOMStoreThreePhaseCommitCohort ready = writeTx.ready();
211 ready.preCommit().get();
213 ready.commit().get();
215 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
216 assertNotNull( readTx );
219 readTx.exists(TestModel.TEST_PATH);
221 assertEquals(true, exists.checkedGet());
225 public void testExistsForNonExistingData() throws Exception {
227 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
228 assertNotNull( writeTx );
230 CheckedFuture<Boolean, ReadFailedException> exists =
231 writeTx.exists(TestModel.TEST_PATH);
233 assertEquals(false, exists.checkedGet());
235 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
236 assertNotNull( readTx );
239 readTx.exists(TestModel.TEST_PATH);
241 assertEquals(false, exists.checkedGet());
244 @Test(expected=ReadFailedException.class)
245 public void testExistsThrowsReadFailedException() throws Exception {
247 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
248 assertNotNull( readTx );
252 readTx.exists(TestModel.TEST_PATH).checkedGet();
257 @Test(expected=ReadFailedException.class)
258 public void testReadWithReadOnlyTransactionClosed() throws Throwable {
260 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
261 assertNotNull( readTx );
265 doReadAndThrowEx( readTx );
268 @Test(expected=ReadFailedException.class)
269 public void testReadWithReadOnlyTransactionFailure() throws Throwable {
271 DataTreeSnapshot mockSnapshot = Mockito.mock( DataTreeSnapshot.class );
272 Mockito.doThrow( new RuntimeException( "mock ex" ) ).when( mockSnapshot )
273 .readNode( Mockito.any( YangInstanceIdentifier.class ) );
275 DOMStoreReadTransaction readTx = new SnapshotBackedReadTransaction("1", true, mockSnapshot);
277 doReadAndThrowEx( readTx );
280 @Test(expected=ReadFailedException.class)
281 public void testReadWithReadWriteTransactionClosed() throws Throwable {
283 DOMStoreReadTransaction readTx = domStore.newReadWriteTransaction();
284 assertNotNull( readTx );
288 doReadAndThrowEx( readTx );
291 @Test(expected=ReadFailedException.class)
292 public void testReadWithReadWriteTransactionFailure() throws Throwable {
294 DataTreeSnapshot mockSnapshot = Mockito.mock( DataTreeSnapshot.class );
295 DataTreeModification mockModification = Mockito.mock( DataTreeModification.class );
296 Mockito.doThrow( new RuntimeException( "mock ex" ) ).when( mockModification )
297 .readNode( Mockito.any( YangInstanceIdentifier.class ) );
298 Mockito.doReturn( mockModification ).when( mockSnapshot ).newModification();
299 TransactionReadyPrototype mockReady = Mockito.mock( TransactionReadyPrototype.class );
300 DOMStoreReadTransaction readTx = new SnapshotBackedReadWriteTransaction("1", false, mockSnapshot, mockReady);
302 doReadAndThrowEx( readTx );
305 private void doReadAndThrowEx( final DOMStoreReadTransaction readTx ) throws Throwable {
308 readTx.read(TestModel.TEST_PATH).get();
309 } catch( ExecutionException e ) {
314 @Test(expected=IllegalStateException.class)
315 public void testWriteWithTransactionReady() throws Exception {
317 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
322 writeTx.write( TestModel.TEST_PATH, ImmutableNodes.containerNode( TestModel.TEST_QNAME ) );
325 @Test(expected=IllegalStateException.class)
326 public void testReadyWithTransactionAlreadyReady() throws Exception {
328 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
337 public void testTransactionAbort() throws InterruptedException, ExecutionException {
339 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
340 assertNotNull(writeTx);
342 assertTestContainerWrite(writeTx);
344 DOMStoreThreePhaseCommitCohort cohort = writeTx.ready();
346 assertTrue(cohort.canCommit().get().booleanValue());
347 cohort.preCommit().get();
348 cohort.abort().get();
350 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH)
352 assertFalse(afterCommitRead.isPresent());
356 public void testTransactionChain() throws InterruptedException, ExecutionException {
357 DOMStoreTransactionChain txChain = domStore.createTransactionChain();
358 assertNotNull(txChain);
361 * We alocate new read-write transaction and write /test
365 DOMStoreReadWriteTransaction firstTx = txChain.newReadWriteTransaction();
366 assertTestContainerWrite(firstTx);
369 * First transaction is marked as ready, we are able to allocate chained
372 DOMStoreThreePhaseCommitCohort firstWriteTxCohort = firstTx.ready();
375 * We alocate chained transaction - read transaction, note first one is
376 * still not commited to datastore.
378 DOMStoreReadTransaction secondReadTx = txChain.newReadOnlyTransaction();
382 * We test if we are able to read data from tx, read should not fail
383 * since we are using chained transaction.
387 assertTestContainerExists(secondReadTx);
391 * We alocate next transaction, which is still based on first one, but
395 DOMStoreReadWriteTransaction thirdDeleteTx = txChain.newReadWriteTransaction();
398 * We test existence of /test in third transaction container should
399 * still be visible from first one (which is still uncommmited).
403 assertTestContainerExists(thirdDeleteTx);
406 * We delete node in third transaction
408 thirdDeleteTx.delete(TestModel.TEST_PATH);
411 * third transaction is sealed.
413 DOMStoreThreePhaseCommitCohort thirdDeleteTxCohort = thirdDeleteTx.ready();
416 * We commit first transaction
419 assertThreePhaseCommit(firstWriteTxCohort);
421 // Alocates store transacion
422 DOMStoreReadTransaction storeReadTx = domStore.newReadOnlyTransaction();
424 * We verify transaction is commited to store, container should exists
427 assertTestContainerExists(storeReadTx);
429 * We commit third transaction
432 assertThreePhaseCommit(thirdDeleteTxCohort);
437 public void testTransactionConflict() throws InterruptedException, ExecutionException {
438 DOMStoreReadWriteTransaction txOne = domStore.newReadWriteTransaction();
439 DOMStoreReadWriteTransaction txTwo = domStore.newReadWriteTransaction();
440 assertTestContainerWrite(txOne);
441 assertTestContainerWrite(txTwo);
444 * Commits transaction
446 assertThreePhaseCommit(txOne.ready());
449 * Asserts that txTwo could not be commited
451 assertFalse(txTwo.ready().canCommit().get());
454 private static void assertThreePhaseCommit(final DOMStoreThreePhaseCommitCohort cohort)
455 throws InterruptedException, ExecutionException {
456 assertTrue(cohort.canCommit().get().booleanValue());
457 cohort.preCommit().get();
458 cohort.commit().get();
461 private static Optional<NormalizedNode<?, ?>> assertTestContainerWrite(final DOMStoreReadWriteTransaction writeTx)
462 throws InterruptedException, ExecutionException {
465 * Writes /test in writeTx
468 writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
470 return assertTestContainerExists(writeTx);
474 * Reads /test from readTx Read should return container.
476 private static Optional<NormalizedNode<?, ?>> assertTestContainerExists(final DOMStoreReadTransaction readTx)
477 throws InterruptedException, ExecutionException {
479 ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = readTx.read(TestModel.TEST_PATH);
480 assertTrue(writeTxContainer.get().isPresent());
481 return writeTxContainer.get();