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.Before;
20 import org.junit.Ignore;
21 import org.junit.Test;
22 import org.mockito.Mockito;
23 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
24 import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction;
25 import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
26 import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
27 import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain;
28 import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction;
29 import org.opendaylight.controller.sal.core.spi.data.SnapshotBackedTransactions;
30 import org.opendaylight.controller.sal.core.spi.data.SnapshotBackedWriteTransaction.TransactionReadyPrototype;
31 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
32 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
33 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
34 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
35 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
36 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
37 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
38 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
39 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
41 public class InMemoryDataStoreTest {
43 private SchemaContext schemaContext;
44 private InMemoryDOMDataStore domStore;
47 public void setupStore() {
48 domStore = new InMemoryDOMDataStore("TEST", MoreExecutors.newDirectExecutorService());
49 schemaContext = TestModel.createTestContext();
50 domStore.onGlobalContextUpdated(schemaContext);
54 public void testTransactionIsolation() throws InterruptedException, ExecutionException {
56 assertNotNull(domStore);
58 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
59 assertNotNull(readTx);
61 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
62 assertNotNull(writeTx);
65 * Writes /test in writeTx
67 NormalizedNode<?, ?> testNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
68 writeTx.write(TestModel.TEST_PATH, testNode);
71 * Reads /test from writeTx Read should return container.
73 ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = writeTx.read(TestModel.TEST_PATH);
74 assertEquals("read: isPresent", true, writeTxContainer.get().isPresent());
75 assertEquals("read: data", testNode, writeTxContainer.get().get());
78 * Reads /test from readTx Read should return Absent.
80 ListenableFuture<Optional<NormalizedNode<?, ?>>> readTxContainer = readTx.read(TestModel.TEST_PATH);
81 assertEquals("read: isPresent", false, readTxContainer.get().isPresent());
85 public void testTransactionCommit() throws InterruptedException, ExecutionException {
87 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
88 assertNotNull(writeTx);
91 * Writes /test in writeTx
93 NormalizedNode<?, ?> testNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
94 writeTx.write(TestModel.TEST_PATH, testNode);
97 * Reads /test from writeTx Read should return container.
99 ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = writeTx.read(TestModel.TEST_PATH);
100 assertEquals("read: isPresent", true, writeTxContainer.get().isPresent());
101 assertEquals("read: data", testNode, writeTxContainer.get().get());
103 DOMStoreThreePhaseCommitCohort cohort = writeTx.ready();
105 assertThreePhaseCommit(cohort);
107 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH)
109 assertEquals("After commit read: isPresent", true, afterCommitRead.isPresent());
110 assertEquals("After commit read: data", testNode, afterCommitRead.get());
114 public void testDelete() throws Exception {
116 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
117 assertNotNull( writeTx );
119 // Write /test and commit
121 writeTx.write( TestModel.TEST_PATH, ImmutableNodes.containerNode( TestModel.TEST_QNAME ) );
123 assertThreePhaseCommit( writeTx.ready() );
125 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().
126 read(TestModel.TEST_PATH ).get();
127 assertEquals( "After commit read: isPresent", true, afterCommitRead.isPresent() );
129 // Delete /test and verify
131 writeTx = domStore.newWriteOnlyTransaction();
133 writeTx.delete( TestModel.TEST_PATH );
135 assertThreePhaseCommit( writeTx.ready() );
137 afterCommitRead = domStore.newReadOnlyTransaction().
138 read(TestModel.TEST_PATH ).get();
139 assertEquals( "After commit read: isPresent", false, afterCommitRead.isPresent() );
143 public void testMerge() throws Exception {
145 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
146 assertNotNull( writeTx );
148 ContainerNode containerNode = ImmutableContainerNodeBuilder.create()
149 .withNodeIdentifier( new NodeIdentifier( TestModel.TEST_QNAME ) )
150 .addChild( ImmutableNodes.mapNodeBuilder( TestModel.OUTER_LIST_QNAME )
151 .addChild( ImmutableNodes.mapEntry( TestModel.OUTER_LIST_QNAME,
152 TestModel.ID_QNAME, 1 ) ).build() ).build();
154 writeTx.merge( TestModel.TEST_PATH, containerNode );
156 assertThreePhaseCommit( writeTx.ready() );
158 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().
159 read(TestModel.TEST_PATH ).get();
160 assertEquals( "After commit read: isPresent", true, afterCommitRead.isPresent() );
161 assertEquals( "After commit read: data", containerNode, afterCommitRead.get() );
163 // Merge a new list entry node
165 writeTx = domStore.newWriteOnlyTransaction();
166 assertNotNull( writeTx );
168 containerNode = ImmutableContainerNodeBuilder.create()
169 .withNodeIdentifier( new NodeIdentifier( TestModel.TEST_QNAME ) )
170 .addChild( ImmutableNodes.mapNodeBuilder( TestModel.OUTER_LIST_QNAME )
171 .addChild( ImmutableNodes.mapEntry( TestModel.OUTER_LIST_QNAME,
172 TestModel.ID_QNAME, 1 ) )
173 .addChild( ImmutableNodes.mapEntry( TestModel.OUTER_LIST_QNAME,
174 TestModel.ID_QNAME, 2 ) ).build() ).build();
176 writeTx.merge( TestModel.TEST_PATH, containerNode );
178 assertThreePhaseCommit( writeTx.ready() );
180 afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH ).get();
181 assertEquals( "After commit read: isPresent", true, afterCommitRead.isPresent() );
182 assertEquals( "After commit read: data", containerNode, afterCommitRead.get() );
187 public void testExistsForExistingData() throws Exception {
189 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
190 assertNotNull( writeTx );
192 ContainerNode containerNode = ImmutableContainerNodeBuilder.create()
193 .withNodeIdentifier( new NodeIdentifier( TestModel.TEST_QNAME ) )
194 .addChild( ImmutableNodes.mapNodeBuilder( TestModel.OUTER_LIST_QNAME )
195 .addChild( ImmutableNodes.mapEntry( TestModel.OUTER_LIST_QNAME,
196 TestModel.ID_QNAME, 1 ) ).build() ).build();
198 writeTx.merge( TestModel.TEST_PATH, containerNode );
200 CheckedFuture<Boolean, ReadFailedException> exists =
201 writeTx.exists(TestModel.TEST_PATH);
203 assertEquals(true, exists.checkedGet());
205 DOMStoreThreePhaseCommitCohort ready = writeTx.ready();
207 ready.preCommit().get();
209 ready.commit().get();
211 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
212 assertNotNull( readTx );
215 readTx.exists(TestModel.TEST_PATH);
217 assertEquals(true, exists.checkedGet());
221 public void testExistsForNonExistingData() throws Exception {
223 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
224 assertNotNull( writeTx );
226 CheckedFuture<Boolean, ReadFailedException> exists =
227 writeTx.exists(TestModel.TEST_PATH);
229 assertEquals(false, exists.checkedGet());
231 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
232 assertNotNull( readTx );
235 readTx.exists(TestModel.TEST_PATH);
237 assertEquals(false, exists.checkedGet());
240 @Test(expected=ReadFailedException.class)
241 public void testExistsThrowsReadFailedException() throws Exception {
243 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
244 assertNotNull( readTx );
248 readTx.exists(TestModel.TEST_PATH).checkedGet();
253 @Test(expected=ReadFailedException.class)
254 public void testReadWithReadOnlyTransactionClosed() throws Throwable {
256 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
257 assertNotNull( readTx );
261 doReadAndThrowEx( readTx );
264 @Test(expected=ReadFailedException.class)
265 public void testReadWithReadOnlyTransactionFailure() throws Throwable {
267 DataTreeSnapshot mockSnapshot = Mockito.mock( DataTreeSnapshot.class );
268 Mockito.doThrow( new RuntimeException( "mock ex" ) ).when( mockSnapshot )
269 .readNode( Mockito.any( YangInstanceIdentifier.class ) );
271 DOMStoreReadTransaction readTx = SnapshotBackedTransactions.newReadTransaction("1", true, mockSnapshot);
273 doReadAndThrowEx( readTx );
276 @Test(expected=ReadFailedException.class)
277 public void testReadWithReadWriteTransactionClosed() throws Throwable {
279 DOMStoreReadTransaction readTx = domStore.newReadWriteTransaction();
280 assertNotNull( readTx );
284 doReadAndThrowEx( readTx );
287 @Test(expected=ReadFailedException.class)
288 public void testReadWithReadWriteTransactionFailure() throws Throwable {
290 DataTreeSnapshot mockSnapshot = Mockito.mock( DataTreeSnapshot.class );
291 DataTreeModification mockModification = Mockito.mock( DataTreeModification.class );
292 Mockito.doThrow( new RuntimeException( "mock ex" ) ).when( mockModification )
293 .readNode( Mockito.any( YangInstanceIdentifier.class ) );
294 Mockito.doReturn( mockModification ).when( mockSnapshot ).newModification();
295 @SuppressWarnings("unchecked")
296 TransactionReadyPrototype<String> mockReady = Mockito.mock( TransactionReadyPrototype.class );
297 DOMStoreReadTransaction readTx = SnapshotBackedTransactions.newReadWriteTransaction("1", false, mockSnapshot, mockReady);
299 doReadAndThrowEx( readTx );
302 private static void doReadAndThrowEx( final DOMStoreReadTransaction readTx ) throws Throwable {
304 readTx.read(TestModel.TEST_PATH).get();
305 } catch( ExecutionException e ) {
310 @Test(expected=IllegalStateException.class)
311 public void testWriteWithTransactionReady() throws Exception {
313 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
318 writeTx.write( TestModel.TEST_PATH, ImmutableNodes.containerNode( TestModel.TEST_QNAME ) );
321 @Test(expected=IllegalStateException.class)
322 public void testReadyWithTransactionAlreadyReady() throws Exception {
324 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
333 public void testTransactionAbort() throws InterruptedException, ExecutionException {
335 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
336 assertNotNull(writeTx);
338 assertTestContainerWrite(writeTx);
340 DOMStoreThreePhaseCommitCohort cohort = writeTx.ready();
342 assertTrue(cohort.canCommit().get().booleanValue());
343 cohort.preCommit().get();
344 cohort.abort().get();
346 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH)
348 assertFalse(afterCommitRead.isPresent());
352 public void testTransactionChain() throws InterruptedException, ExecutionException {
353 DOMStoreTransactionChain txChain = domStore.createTransactionChain();
354 assertNotNull(txChain);
357 * We alocate new read-write transaction and write /test
361 DOMStoreReadWriteTransaction firstTx = txChain.newReadWriteTransaction();
362 assertTestContainerWrite(firstTx);
365 * First transaction is marked as ready, we are able to allocate chained
368 DOMStoreThreePhaseCommitCohort firstWriteTxCohort = firstTx.ready();
371 * We alocate chained transaction - read transaction, note first one is
372 * still not commited to datastore.
374 DOMStoreReadTransaction secondReadTx = txChain.newReadOnlyTransaction();
378 * We test if we are able to read data from tx, read should not fail
379 * since we are using chained transaction.
383 assertTestContainerExists(secondReadTx);
387 * We alocate next transaction, which is still based on first one, but
391 DOMStoreReadWriteTransaction thirdDeleteTx = txChain.newReadWriteTransaction();
394 * We test existence of /test in third transaction container should
395 * still be visible from first one (which is still uncommmited).
399 assertTestContainerExists(thirdDeleteTx);
402 * We delete node in third transaction
404 thirdDeleteTx.delete(TestModel.TEST_PATH);
407 * third transaction is sealed.
409 DOMStoreThreePhaseCommitCohort thirdDeleteTxCohort = thirdDeleteTx.ready();
412 * We commit first transaction
415 assertThreePhaseCommit(firstWriteTxCohort);
417 // Alocates store transacion
418 DOMStoreReadTransaction storeReadTx = domStore.newReadOnlyTransaction();
420 * We verify transaction is commited to store, container should exists
423 assertTestContainerExists(storeReadTx);
425 * We commit third transaction
428 assertThreePhaseCommit(thirdDeleteTxCohort);
433 public void testTransactionConflict() throws InterruptedException, ExecutionException {
434 DOMStoreReadWriteTransaction txOne = domStore.newReadWriteTransaction();
435 DOMStoreReadWriteTransaction txTwo = domStore.newReadWriteTransaction();
436 assertTestContainerWrite(txOne);
437 assertTestContainerWrite(txTwo);
440 * Commits transaction
442 assertThreePhaseCommit(txOne.ready());
445 * Asserts that txTwo could not be commited
447 assertFalse(txTwo.ready().canCommit().get());
450 private static void assertThreePhaseCommit(final DOMStoreThreePhaseCommitCohort cohort)
451 throws InterruptedException, ExecutionException {
452 assertTrue(cohort.canCommit().get().booleanValue());
453 cohort.preCommit().get();
454 cohort.commit().get();
457 private static Optional<NormalizedNode<?, ?>> assertTestContainerWrite(final DOMStoreReadWriteTransaction writeTx)
458 throws InterruptedException, ExecutionException {
461 * Writes /test in writeTx
464 writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
466 return assertTestContainerExists(writeTx);
470 * Reads /test from readTx Read should return container.
472 private static Optional<NormalizedNode<?, ?>> assertTestContainerExists(final DOMStoreReadTransaction readTx)
473 throws InterruptedException, ExecutionException {
475 ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = readTx.read(TestModel.TEST_PATH);
476 assertTrue(writeTxContainer.get().isPresent());
477 return writeTxContainer.get();