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;
14 import com.google.common.base.Optional;
15 import com.google.common.util.concurrent.CheckedFuture;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import com.google.common.util.concurrent.MoreExecutors;
18 import java.util.concurrent.ExecutionException;
19 import org.junit.Assert;
20 import org.junit.Before;
21 import org.junit.Ignore;
22 import org.junit.Test;
23 import org.mockito.Mockito;
24 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
25 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
26 import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction;
27 import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
28 import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
29 import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain;
30 import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction;
31 import org.opendaylight.controller.sal.core.spi.data.SnapshotBackedTransactions;
32 import org.opendaylight.controller.sal.core.spi.data.SnapshotBackedWriteTransaction.TransactionReadyPrototype;
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.DataContainerChild;
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.api.NormalizedNodeContainerBuilder;
42 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
43 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
45 public class InMemoryDataStoreTest {
47 private SchemaContext schemaContext;
48 private InMemoryDOMDataStore domStore;
51 public void setupStore() {
52 domStore = new InMemoryDOMDataStore("TEST", MoreExecutors.newDirectExecutorService());
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 = SnapshotBackedTransactions.newReadTransaction("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 @SuppressWarnings("unchecked")
300 TransactionReadyPrototype<String> mockReady = Mockito.mock( TransactionReadyPrototype.class );
301 DOMStoreReadTransaction readTx = SnapshotBackedTransactions.newReadWriteTransaction("1", false, mockSnapshot, mockReady);
303 doReadAndThrowEx( readTx );
306 private static 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 testReadyWithMissingMandatoryData() throws InterruptedException {
338 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
339 NormalizedNode<?, ?> testNode = ImmutableContainerNodeBuilder.create()
340 .withNodeIdentifier(new NodeIdentifier(TestModel.MANDATORY_DATA_TEST_QNAME))
341 .addChild(ImmutableNodes.leafNode(TestModel.OPTIONAL_QNAME, "data"))
343 writeTx.write(TestModel.MANDATORY_DATA_TEST_PATH, testNode);
344 DOMStoreThreePhaseCommitCohort ready = writeTx.ready();
346 ready.canCommit().get();
347 Assert.fail("Expected exception on canCommit");
348 } catch (ExecutionException e) {
354 public void testTransactionAbort() throws InterruptedException, ExecutionException {
356 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
357 assertNotNull(writeTx);
359 assertTestContainerWrite(writeTx);
361 DOMStoreThreePhaseCommitCohort cohort = writeTx.ready();
363 assertTrue(cohort.canCommit().get().booleanValue());
364 cohort.preCommit().get();
365 cohort.abort().get();
367 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH)
369 assertFalse(afterCommitRead.isPresent());
373 public void testTransactionChain() throws InterruptedException, ExecutionException {
374 DOMStoreTransactionChain txChain = domStore.createTransactionChain();
375 assertNotNull(txChain);
378 * We alocate new read-write transaction and write /test
382 DOMStoreReadWriteTransaction firstTx = txChain.newReadWriteTransaction();
383 assertTestContainerWrite(firstTx);
386 * First transaction is marked as ready, we are able to allocate chained
389 DOMStoreThreePhaseCommitCohort firstWriteTxCohort = firstTx.ready();
392 * We alocate chained transaction - read transaction, note first one is
393 * still not commited to datastore.
395 DOMStoreReadTransaction secondReadTx = txChain.newReadOnlyTransaction();
399 * We test if we are able to read data from tx, read should not fail
400 * since we are using chained transaction.
404 assertTestContainerExists(secondReadTx);
408 * We alocate next transaction, which is still based on first one, but
412 DOMStoreReadWriteTransaction thirdDeleteTx = txChain.newReadWriteTransaction();
415 * We test existence of /test in third transaction container should
416 * still be visible from first one (which is still uncommmited).
420 assertTestContainerExists(thirdDeleteTx);
423 * We delete node in third transaction
425 thirdDeleteTx.delete(TestModel.TEST_PATH);
428 * third transaction is sealed.
430 DOMStoreThreePhaseCommitCohort thirdDeleteTxCohort = thirdDeleteTx.ready();
433 * We commit first transaction
436 assertThreePhaseCommit(firstWriteTxCohort);
438 // Alocates store transacion
439 DOMStoreReadTransaction storeReadTx = domStore.newReadOnlyTransaction();
441 * We verify transaction is commited to store, container should exists
444 assertTestContainerExists(storeReadTx);
446 * We commit third transaction
449 assertThreePhaseCommit(thirdDeleteTxCohort);
454 public void testTransactionConflict() throws InterruptedException, ExecutionException {
455 DOMStoreReadWriteTransaction txOne = domStore.newReadWriteTransaction();
456 DOMStoreReadWriteTransaction txTwo = domStore.newReadWriteTransaction();
457 assertTestContainerWrite(txOne);
458 assertTestContainerWrite(txTwo);
461 * Commits transaction
463 assertThreePhaseCommit(txOne.ready());
466 * Asserts that txTwo could not be commited
468 assertFalse(txTwo.ready().canCommit().get());
471 private static void assertThreePhaseCommit(final DOMStoreThreePhaseCommitCohort cohort)
472 throws InterruptedException, ExecutionException {
473 assertTrue(cohort.canCommit().get().booleanValue());
474 cohort.preCommit().get();
475 cohort.commit().get();
478 private static Optional<NormalizedNode<?, ?>> assertTestContainerWrite(final DOMStoreReadWriteTransaction writeTx)
479 throws InterruptedException, ExecutionException {
482 * Writes /test in writeTx
485 writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
487 return assertTestContainerExists(writeTx);
491 * Reads /test from readTx Read should return container.
493 private static Optional<NormalizedNode<?, ?>> assertTestContainerExists(final DOMStoreReadTransaction readTx)
494 throws InterruptedException, ExecutionException {
496 ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = readTx.read(TestModel.TEST_PATH);
497 assertTrue(writeTxContainer.get().isPresent());
498 return writeTxContainer.get();