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 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() );
187 @Test(expected=ReadFailedException.class)
188 public void testReadWithReadOnlyTransactionClosed() throws Throwable {
190 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
191 assertNotNull( readTx );
195 doReadAndThrowEx( readTx );
198 @Test(expected=ReadFailedException.class)
199 public void testReadWithReadOnlyTransactionFailure() throws Throwable {
201 DataTreeSnapshot mockSnapshot = Mockito.mock( DataTreeSnapshot.class );
202 Mockito.doThrow( new RuntimeException( "mock ex" ) ).when( mockSnapshot )
203 .readNode( Mockito.any( YangInstanceIdentifier.class ) );
205 DOMStoreReadTransaction readTx = new SnapshotBackedReadTransaction( "1", mockSnapshot );
207 doReadAndThrowEx( readTx );
210 @Test(expected=ReadFailedException.class)
211 public void testReadWithReadWriteTransactionClosed() throws Throwable {
213 DOMStoreReadTransaction readTx = domStore.newReadWriteTransaction();
214 assertNotNull( readTx );
218 doReadAndThrowEx( readTx );
221 @Test(expected=ReadFailedException.class)
222 public void testReadWithReadWriteTransactionFailure() throws Throwable {
224 DataTreeSnapshot mockSnapshot = Mockito.mock( DataTreeSnapshot.class );
225 DataTreeModification mockModification = Mockito.mock( DataTreeModification.class );
226 Mockito.doThrow( new RuntimeException( "mock ex" ) ).when( mockModification )
227 .readNode( Mockito.any( YangInstanceIdentifier.class ) );
228 Mockito.doReturn( mockModification ).when( mockSnapshot ).newModification();
229 TransactionReadyPrototype mockReady = Mockito.mock( TransactionReadyPrototype.class );
230 DOMStoreReadTransaction readTx = new SnapshotBackedReadWriteTransaction( "1", mockSnapshot, mockReady );
232 doReadAndThrowEx( readTx );
235 private void doReadAndThrowEx( DOMStoreReadTransaction readTx ) throws Throwable {
238 readTx.read(TestModel.TEST_PATH).get();
239 } catch( ExecutionException e ) {
244 @Test(expected=IllegalStateException.class)
245 public void testWriteWithTransactionReady() throws Exception {
247 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
252 writeTx.write( TestModel.TEST_PATH, ImmutableNodes.containerNode( TestModel.TEST_QNAME ) );
255 @Test(expected=IllegalStateException.class)
256 public void testReadyWithTransactionAlreadyReady() throws Exception {
258 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
267 public void testTransactionAbort() throws InterruptedException, ExecutionException {
269 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
270 assertNotNull(writeTx);
272 assertTestContainerWrite(writeTx);
274 DOMStoreThreePhaseCommitCohort cohort = writeTx.ready();
276 assertTrue(cohort.canCommit().get().booleanValue());
277 cohort.preCommit().get();
278 cohort.abort().get();
280 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH)
282 assertFalse(afterCommitRead.isPresent());
286 public void testTransactionChain() throws InterruptedException, ExecutionException {
287 DOMStoreTransactionChain txChain = domStore.createTransactionChain();
288 assertNotNull(txChain);
291 * We alocate new read-write transaction and write /test
295 DOMStoreReadWriteTransaction firstTx = txChain.newReadWriteTransaction();
296 assertTestContainerWrite(firstTx);
299 * First transaction is marked as ready, we are able to allocate chained
302 DOMStoreThreePhaseCommitCohort firstWriteTxCohort = firstTx.ready();
305 * We alocate chained transaction - read transaction, note first one is
306 * still not commited to datastore.
308 DOMStoreReadTransaction secondReadTx = txChain.newReadOnlyTransaction();
312 * We test if we are able to read data from tx, read should not fail
313 * since we are using chained transaction.
317 assertTestContainerExists(secondReadTx);
321 * We alocate next transaction, which is still based on first one, but
325 DOMStoreReadWriteTransaction thirdDeleteTx = txChain.newReadWriteTransaction();
328 * We test existence of /test in third transaction container should
329 * still be visible from first one (which is still uncommmited).
333 assertTestContainerExists(thirdDeleteTx);
336 * We delete node in third transaction
338 thirdDeleteTx.delete(TestModel.TEST_PATH);
341 * third transaction is sealed.
343 DOMStoreThreePhaseCommitCohort thirdDeleteTxCohort = thirdDeleteTx.ready();
346 * We commit first transaction
349 assertThreePhaseCommit(firstWriteTxCohort);
351 // Alocates store transacion
352 DOMStoreReadTransaction storeReadTx = domStore.newReadOnlyTransaction();
354 * We verify transaction is commited to store, container should exists
357 assertTestContainerExists(storeReadTx);
359 * We commit third transaction
362 assertThreePhaseCommit(thirdDeleteTxCohort);
367 public void testTransactionConflict() throws InterruptedException, ExecutionException {
368 DOMStoreReadWriteTransaction txOne = domStore.newReadWriteTransaction();
369 DOMStoreReadWriteTransaction txTwo = domStore.newReadWriteTransaction();
370 assertTestContainerWrite(txOne);
371 assertTestContainerWrite(txTwo);
374 * Commits transaction
376 assertThreePhaseCommit(txOne.ready());
379 * Asserts that txTwo could not be commited
381 assertFalse(txTwo.ready().canCommit().get());
384 private static void assertThreePhaseCommit(final DOMStoreThreePhaseCommitCohort cohort)
385 throws InterruptedException, ExecutionException {
386 assertTrue(cohort.canCommit().get().booleanValue());
387 cohort.preCommit().get();
388 cohort.commit().get();
391 private static Optional<NormalizedNode<?, ?>> assertTestContainerWrite(final DOMStoreReadWriteTransaction writeTx)
392 throws InterruptedException, ExecutionException {
395 * Writes /test in writeTx
398 writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
400 return assertTestContainerExists(writeTx);
404 * Reads /test from readTx Read should return container.
406 private static Optional<NormalizedNode<?, ?>> assertTestContainerExists(final DOMStoreReadTransaction readTx)
407 throws InterruptedException, ExecutionException {
409 ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = readTx.read(TestModel.TEST_PATH);
410 assertTrue(writeTxContainer.get().isPresent());
411 return writeTxContainer.get();