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 java.util.concurrent.ExecutionException;
17 import org.junit.Before;
18 import org.junit.Ignore;
19 import org.junit.Test;
20 import org.mockito.Mockito;
21 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
22 import org.opendaylight.controller.md.sal.dom.store.impl.SnapshotBackedWriteTransaction.TransactionReadyPrototype;
23 import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction;
24 import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
25 import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
26 import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain;
27 import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction;
28 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
29 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
30 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
33 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
34 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
35 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
36 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
38 import com.google.common.base.Optional;
39 import com.google.common.util.concurrent.ListenableFuture;
40 import com.google.common.util.concurrent.MoreExecutors;
43 public class InMemoryDataStoreTest {
45 private SchemaContext schemaContext;
46 private InMemoryDOMDataStore domStore;
49 public void setupStore() {
50 domStore = new InMemoryDOMDataStore("TEST", MoreExecutors.sameThreadExecutor(),
51 MoreExecutors.sameThreadExecutor());
52 schemaContext = TestModel.createTestContext();
53 domStore.onGlobalContextUpdated(schemaContext);
57 public void testTransactionIsolation() throws InterruptedException, ExecutionException {
59 assertNotNull(domStore);
61 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
62 assertNotNull(readTx);
64 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
65 assertNotNull(writeTx);
68 * Writes /test in writeTx
70 NormalizedNode<?, ?> testNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
71 writeTx.write(TestModel.TEST_PATH, testNode);
74 * Reads /test from writeTx Read should return container.
76 ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = writeTx.read(TestModel.TEST_PATH);
77 assertEquals("read: isPresent", true, writeTxContainer.get().isPresent());
78 assertEquals("read: data", testNode, writeTxContainer.get().get());
81 * Reads /test from readTx Read should return Absent.
83 ListenableFuture<Optional<NormalizedNode<?, ?>>> readTxContainer = readTx.read(TestModel.TEST_PATH);
84 assertEquals("read: isPresent", false, readTxContainer.get().isPresent());
88 public void testTransactionCommit() throws InterruptedException, ExecutionException {
90 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
91 assertNotNull(writeTx);
94 * Writes /test in writeTx
96 NormalizedNode<?, ?> testNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
97 writeTx.write(TestModel.TEST_PATH, testNode);
100 * Reads /test from writeTx Read should return container.
102 ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = writeTx.read(TestModel.TEST_PATH);
103 assertEquals("read: isPresent", true, writeTxContainer.get().isPresent());
104 assertEquals("read: data", testNode, writeTxContainer.get().get());
106 DOMStoreThreePhaseCommitCohort cohort = writeTx.ready();
108 assertThreePhaseCommit(cohort);
110 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH)
112 assertEquals("After commit read: isPresent", true, afterCommitRead.isPresent());
113 assertEquals("After commit read: data", testNode, afterCommitRead.get());
117 public void testDelete() throws Exception {
119 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
120 assertNotNull( writeTx );
122 // Write /test and commit
124 writeTx.write( TestModel.TEST_PATH, ImmutableNodes.containerNode( TestModel.TEST_QNAME ) );
126 assertThreePhaseCommit( writeTx.ready() );
128 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().
129 read(TestModel.TEST_PATH ).get();
130 assertEquals( "After commit read: isPresent", true, afterCommitRead.isPresent() );
132 // Delete /test and verify
134 writeTx = domStore.newWriteOnlyTransaction();
136 writeTx.delete( TestModel.TEST_PATH );
138 assertThreePhaseCommit( writeTx.ready() );
140 afterCommitRead = domStore.newReadOnlyTransaction().
141 read(TestModel.TEST_PATH ).get();
142 assertEquals( "After commit read: isPresent", false, afterCommitRead.isPresent() );
146 public void testMerge() throws Exception {
148 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
149 assertNotNull( writeTx );
151 ContainerNode containerNode = ImmutableContainerNodeBuilder.create()
152 .withNodeIdentifier( new NodeIdentifier( TestModel.TEST_QNAME ) )
153 .addChild( ImmutableNodes.mapNodeBuilder( TestModel.OUTER_LIST_QNAME )
154 .addChild( ImmutableNodes.mapEntry( TestModel.OUTER_LIST_QNAME,
155 TestModel.ID_QNAME, 1 ) ).build() ).build();
157 writeTx.merge( TestModel.TEST_PATH, containerNode );
159 assertThreePhaseCommit( writeTx.ready() );
161 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().
162 read(TestModel.TEST_PATH ).get();
163 assertEquals( "After commit read: isPresent", true, afterCommitRead.isPresent() );
164 assertEquals( "After commit read: data", containerNode, afterCommitRead.get() );
166 // Merge a new list entry node
168 writeTx = domStore.newWriteOnlyTransaction();
169 assertNotNull( writeTx );
171 containerNode = ImmutableContainerNodeBuilder.create()
172 .withNodeIdentifier( new NodeIdentifier( TestModel.TEST_QNAME ) )
173 .addChild( ImmutableNodes.mapNodeBuilder( TestModel.OUTER_LIST_QNAME )
174 .addChild( ImmutableNodes.mapEntry( TestModel.OUTER_LIST_QNAME,
175 TestModel.ID_QNAME, 1 ) )
176 .addChild( ImmutableNodes.mapEntry( TestModel.OUTER_LIST_QNAME,
177 TestModel.ID_QNAME, 2 ) ).build() ).build();
179 writeTx.merge( TestModel.TEST_PATH, containerNode );
181 assertThreePhaseCommit( writeTx.ready() );
183 afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH ).get();
184 assertEquals( "After commit read: isPresent", true, afterCommitRead.isPresent() );
185 assertEquals( "After commit read: data", containerNode, afterCommitRead.get() );
188 @Test(expected=ReadFailedException.class)
189 public void testReadWithReadOnlyTransactionClosed() throws Throwable {
191 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
192 assertNotNull( readTx );
196 doReadAndThrowEx( readTx );
199 @Test(expected=ReadFailedException.class)
200 public void testReadWithReadOnlyTransactionFailure() throws Throwable {
202 DataTreeSnapshot mockSnapshot = Mockito.mock( DataTreeSnapshot.class );
203 Mockito.doThrow( new RuntimeException( "mock ex" ) ).when( mockSnapshot )
204 .readNode( Mockito.any( YangInstanceIdentifier.class ) );
206 DOMStoreReadTransaction readTx = new SnapshotBackedReadTransaction( "1", mockSnapshot );
208 doReadAndThrowEx( readTx );
211 @Test(expected=ReadFailedException.class)
212 public void testReadWithReadWriteTransactionClosed() throws Throwable {
214 DOMStoreReadTransaction readTx = domStore.newReadWriteTransaction();
215 assertNotNull( readTx );
219 doReadAndThrowEx( readTx );
222 @Test(expected=ReadFailedException.class)
223 public void testReadWithReadWriteTransactionFailure() throws Throwable {
225 DataTreeSnapshot mockSnapshot = Mockito.mock( DataTreeSnapshot.class );
226 DataTreeModification mockModification = Mockito.mock( DataTreeModification.class );
227 Mockito.doThrow( new RuntimeException( "mock ex" ) ).when( mockModification )
228 .readNode( Mockito.any( YangInstanceIdentifier.class ) );
229 Mockito.doReturn( mockModification ).when( mockSnapshot ).newModification();
230 TransactionReadyPrototype mockReady = Mockito.mock( TransactionReadyPrototype.class );
231 DOMStoreReadTransaction readTx = new SnapshotBackedReadWriteTransaction( "1", mockSnapshot, mockReady );
233 doReadAndThrowEx( readTx );
236 private void doReadAndThrowEx( DOMStoreReadTransaction readTx ) throws Throwable {
239 readTx.read(TestModel.TEST_PATH).get();
240 } catch( ExecutionException e ) {
245 @Test(expected=IllegalStateException.class)
246 public void testWriteWithTransactionReady() throws Exception {
248 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
253 writeTx.write( TestModel.TEST_PATH, ImmutableNodes.containerNode( TestModel.TEST_QNAME ) );
256 @Test(expected=IllegalStateException.class)
257 public void testReadyWithTransactionAlreadyReady() throws Exception {
259 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
268 public void testTransactionAbort() throws InterruptedException, ExecutionException {
270 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
271 assertNotNull(writeTx);
273 assertTestContainerWrite(writeTx);
275 DOMStoreThreePhaseCommitCohort cohort = writeTx.ready();
277 assertTrue(cohort.canCommit().get().booleanValue());
278 cohort.preCommit().get();
279 cohort.abort().get();
281 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH)
283 assertFalse(afterCommitRead.isPresent());
287 public void testTransactionChain() throws InterruptedException, ExecutionException {
288 DOMStoreTransactionChain txChain = domStore.createTransactionChain();
289 assertNotNull(txChain);
292 * We alocate new read-write transaction and write /test
296 DOMStoreReadWriteTransaction firstTx = txChain.newReadWriteTransaction();
297 assertTestContainerWrite(firstTx);
300 * First transaction is marked as ready, we are able to allocate chained
303 DOMStoreThreePhaseCommitCohort firstWriteTxCohort = firstTx.ready();
306 * We alocate chained transaction - read transaction, note first one is
307 * still not commited to datastore.
309 DOMStoreReadTransaction secondReadTx = txChain.newReadOnlyTransaction();
313 * We test if we are able to read data from tx, read should not fail
314 * since we are using chained transaction.
318 assertTestContainerExists(secondReadTx);
322 * We alocate next transaction, which is still based on first one, but
326 DOMStoreReadWriteTransaction thirdDeleteTx = txChain.newReadWriteTransaction();
329 * We test existence of /test in third transaction container should
330 * still be visible from first one (which is still uncommmited).
334 assertTestContainerExists(thirdDeleteTx);
337 * We delete node in third transaction
339 thirdDeleteTx.delete(TestModel.TEST_PATH);
342 * third transaction is sealed.
344 DOMStoreThreePhaseCommitCohort thirdDeleteTxCohort = thirdDeleteTx.ready();
347 * We commit first transaction
350 assertThreePhaseCommit(firstWriteTxCohort);
352 // Alocates store transacion
353 DOMStoreReadTransaction storeReadTx = domStore.newReadOnlyTransaction();
355 * We verify transaction is commited to store, container should exists
358 assertTestContainerExists(storeReadTx);
360 * We commit third transaction
363 assertThreePhaseCommit(thirdDeleteTxCohort);
368 public void testTransactionConflict() throws InterruptedException, ExecutionException {
369 DOMStoreReadWriteTransaction txOne = domStore.newReadWriteTransaction();
370 DOMStoreReadWriteTransaction txTwo = domStore.newReadWriteTransaction();
371 assertTestContainerWrite(txOne);
372 assertTestContainerWrite(txTwo);
375 * Commits transaction
377 assertThreePhaseCommit(txOne.ready());
380 * Asserts that txTwo could not be commited
382 assertFalse(txTwo.ready().canCommit().get());
385 private static void assertThreePhaseCommit(final DOMStoreThreePhaseCommitCohort cohort)
386 throws InterruptedException, ExecutionException {
387 assertTrue(cohort.canCommit().get().booleanValue());
388 cohort.preCommit().get();
389 cohort.commit().get();
392 private static Optional<NormalizedNode<?, ?>> assertTestContainerWrite(final DOMStoreReadWriteTransaction writeTx)
393 throws InterruptedException, ExecutionException {
396 * Writes /test in writeTx
399 writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
401 return assertTestContainerExists(writeTx);
405 * Reads /test from readTx Read should return container.
407 private static Optional<NormalizedNode<?, ?>> assertTestContainerExists(final DOMStoreReadTransaction readTx)
408 throws InterruptedException, ExecutionException {
410 ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = readTx.read(TestModel.TEST_PATH);
411 assertTrue(writeTxContainer.get().isPresent());
412 return writeTxContainer.get();