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 org.opendaylight.mdsal.dom.store.inmemory.InMemoryDOMDataStore;
17 import org.opendaylight.mdsal.dom.spi.store.DOMStoreReadTransaction;
18 import org.opendaylight.mdsal.dom.spi.store.DOMStoreReadWriteTransaction;
19 import org.opendaylight.mdsal.dom.spi.store.DOMStoreThreePhaseCommitCohort;
20 import org.opendaylight.mdsal.dom.spi.store.DOMStoreTransactionChain;
21 import org.opendaylight.mdsal.dom.spi.store.DOMStoreWriteTransaction;
22 import org.opendaylight.mdsal.dom.spi.store.SnapshotBackedTransactions;
23 import org.opendaylight.mdsal.dom.spi.store.SnapshotBackedWriteTransaction.TransactionReadyPrototype;
24 import org.opendaylight.mdsal.common.api.ReadFailedException;
25 import com.google.common.base.Optional;
26 import com.google.common.util.concurrent.CheckedFuture;
27 import com.google.common.util.concurrent.ListenableFuture;
28 import com.google.common.util.concurrent.MoreExecutors;
29 import java.io.IOException;
30 import java.util.concurrent.ExecutionException;
31 import org.junit.Before;
32 import org.junit.Ignore;
33 import org.junit.Test;
34 import org.mockito.Mockito;
35 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
36 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
37 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
38 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
39 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
40 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
41 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
42 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
43 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
44 import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
45 import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
47 public class InMemoryDataStoreTest {
49 private SchemaContext schemaContext;
50 private InMemoryDOMDataStore domStore;
53 public void setupStore() throws IOException, YangSyntaxErrorException, ReactorException {
54 domStore = new InMemoryDOMDataStore("TEST", MoreExecutors.newDirectExecutorService());
55 schemaContext = TestModel.createTestContext();
56 domStore.onGlobalContextUpdated(schemaContext);
60 public void testTransactionIsolation() throws InterruptedException, ExecutionException {
62 assertNotNull(domStore);
64 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
65 assertNotNull(readTx);
67 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
68 assertNotNull(writeTx);
71 * Writes /test in writeTx
73 NormalizedNode<?, ?> testNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
74 writeTx.write(TestModel.TEST_PATH, testNode);
77 * Reads /test from writeTx Read should return container.
79 ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = writeTx.read(TestModel.TEST_PATH);
80 assertEquals("read: isPresent", true, writeTxContainer.get().isPresent());
81 assertEquals("read: data", testNode, writeTxContainer.get().get());
84 * Reads /test from readTx Read should return Absent.
86 ListenableFuture<Optional<NormalizedNode<?, ?>>> readTxContainer = readTx.read(TestModel.TEST_PATH);
87 assertEquals("read: isPresent", false, readTxContainer.get().isPresent());
91 public void testTransactionCommit() throws InterruptedException, ExecutionException {
93 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
94 assertNotNull(writeTx);
97 * Writes /test in writeTx
99 NormalizedNode<?, ?> testNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
100 writeTx.write(TestModel.TEST_PATH, testNode);
103 * Reads /test from writeTx Read should return container.
105 ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = writeTx.read(TestModel.TEST_PATH);
106 assertEquals("read: isPresent", true, writeTxContainer.get().isPresent());
107 assertEquals("read: data", testNode, writeTxContainer.get().get());
109 DOMStoreThreePhaseCommitCohort cohort = writeTx.ready();
111 assertThreePhaseCommit(cohort);
113 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH)
115 assertEquals("After commit read: isPresent", true, afterCommitRead.isPresent());
116 assertEquals("After commit read: data", testNode, afterCommitRead.get());
120 public void testDelete() throws Exception {
122 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
123 assertNotNull( writeTx );
125 // Write /test and commit
127 writeTx.write( TestModel.TEST_PATH, ImmutableNodes.containerNode( TestModel.TEST_QNAME ) );
129 assertThreePhaseCommit( writeTx.ready() );
131 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().
132 read(TestModel.TEST_PATH ).get();
133 assertEquals( "After commit read: isPresent", true, afterCommitRead.isPresent() );
135 // Delete /test and verify
137 writeTx = domStore.newWriteOnlyTransaction();
139 writeTx.delete( TestModel.TEST_PATH );
141 assertThreePhaseCommit( writeTx.ready() );
143 afterCommitRead = domStore.newReadOnlyTransaction().
144 read(TestModel.TEST_PATH ).get();
145 assertEquals( "After commit read: isPresent", false, afterCommitRead.isPresent() );
149 public void testMerge() throws Exception {
151 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
152 assertNotNull( writeTx );
154 ContainerNode containerNode = ImmutableContainerNodeBuilder.create()
155 .withNodeIdentifier( new NodeIdentifier( TestModel.TEST_QNAME ) )
156 .addChild( ImmutableNodes.mapNodeBuilder( TestModel.OUTER_LIST_QNAME )
157 .addChild( ImmutableNodes.mapEntry( TestModel.OUTER_LIST_QNAME,
158 TestModel.ID_QNAME, 1 ) ).build() ).build();
160 writeTx.merge( TestModel.TEST_PATH, containerNode );
162 assertThreePhaseCommit( writeTx.ready() );
164 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().
165 read(TestModel.TEST_PATH ).get();
166 assertEquals( "After commit read: isPresent", true, afterCommitRead.isPresent() );
167 assertEquals( "After commit read: data", containerNode, afterCommitRead.get() );
169 // Merge a new list entry node
171 writeTx = domStore.newWriteOnlyTransaction();
172 assertNotNull( writeTx );
174 containerNode = ImmutableContainerNodeBuilder.create()
175 .withNodeIdentifier( new NodeIdentifier( TestModel.TEST_QNAME ) )
176 .addChild( ImmutableNodes.mapNodeBuilder( TestModel.OUTER_LIST_QNAME )
177 .addChild( ImmutableNodes.mapEntry( TestModel.OUTER_LIST_QNAME,
178 TestModel.ID_QNAME, 1 ) )
179 .addChild( ImmutableNodes.mapEntry( TestModel.OUTER_LIST_QNAME,
180 TestModel.ID_QNAME, 2 ) ).build() ).build();
182 writeTx.merge( TestModel.TEST_PATH, containerNode );
184 assertThreePhaseCommit( writeTx.ready() );
186 afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH ).get();
187 assertEquals( "After commit read: isPresent", true, afterCommitRead.isPresent() );
188 assertEquals( "After commit read: data", containerNode, afterCommitRead.get() );
193 public void testExistsForExistingData() throws Exception {
195 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
196 assertNotNull( writeTx );
198 ContainerNode containerNode = ImmutableContainerNodeBuilder.create()
199 .withNodeIdentifier( new NodeIdentifier( TestModel.TEST_QNAME ) )
200 .addChild( ImmutableNodes.mapNodeBuilder( TestModel.OUTER_LIST_QNAME )
201 .addChild( ImmutableNodes.mapEntry( TestModel.OUTER_LIST_QNAME,
202 TestModel.ID_QNAME, 1 ) ).build() ).build();
204 writeTx.merge( TestModel.TEST_PATH, containerNode );
206 CheckedFuture<Boolean, ReadFailedException> exists =
207 writeTx.exists(TestModel.TEST_PATH);
209 assertEquals(true, exists.checkedGet());
211 DOMStoreThreePhaseCommitCohort ready = writeTx.ready();
213 ready.preCommit().get();
215 ready.commit().get();
217 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
218 assertNotNull( readTx );
221 readTx.exists(TestModel.TEST_PATH);
223 assertEquals(true, exists.checkedGet());
227 public void testExistsForNonExistingData() throws Exception {
229 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
230 assertNotNull( writeTx );
232 CheckedFuture<Boolean, ReadFailedException> exists =
233 writeTx.exists(TestModel.TEST_PATH);
235 assertEquals(false, exists.checkedGet());
237 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
238 assertNotNull( readTx );
241 readTx.exists(TestModel.TEST_PATH);
243 assertEquals(false, exists.checkedGet());
246 @Test(expected=ReadFailedException.class)
247 public void testExistsThrowsReadFailedException() throws Exception {
249 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
250 assertNotNull( readTx );
254 readTx.exists(TestModel.TEST_PATH).checkedGet();
259 @Test(expected=ReadFailedException.class)
260 public void testReadWithReadOnlyTransactionClosed() throws Throwable {
262 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
263 assertNotNull( readTx );
267 doReadAndThrowEx( readTx );
270 @Test(expected=ReadFailedException.class)
271 public void testReadWithReadOnlyTransactionFailure() throws Throwable {
273 DataTreeSnapshot mockSnapshot = Mockito.mock( DataTreeSnapshot.class );
274 Mockito.doThrow( new RuntimeException( "mock ex" ) ).when( mockSnapshot )
275 .readNode( Mockito.any( YangInstanceIdentifier.class ) );
277 DOMStoreReadTransaction readTx = SnapshotBackedTransactions.newReadTransaction("1", true, mockSnapshot);
279 doReadAndThrowEx( readTx );
282 @Test(expected=ReadFailedException.class)
283 public void testReadWithReadWriteTransactionClosed() throws Throwable {
285 DOMStoreReadTransaction readTx = domStore.newReadWriteTransaction();
286 assertNotNull( readTx );
290 doReadAndThrowEx( readTx );
293 @Test(expected=ReadFailedException.class)
294 public void testReadWithReadWriteTransactionFailure() throws Throwable {
296 DataTreeSnapshot mockSnapshot = Mockito.mock( DataTreeSnapshot.class );
297 DataTreeModification mockModification = Mockito.mock( DataTreeModification.class );
298 Mockito.doThrow( new RuntimeException( "mock ex" ) ).when( mockModification )
299 .readNode( Mockito.any( YangInstanceIdentifier.class ) );
300 Mockito.doReturn( mockModification ).when( mockSnapshot ).newModification();
301 @SuppressWarnings("unchecked")
302 TransactionReadyPrototype<String> mockReady = Mockito.mock( TransactionReadyPrototype.class );
303 DOMStoreReadTransaction readTx = SnapshotBackedTransactions.newReadWriteTransaction("1", false, mockSnapshot, mockReady);
305 doReadAndThrowEx( readTx );
308 private static void doReadAndThrowEx( final DOMStoreReadTransaction readTx ) throws Throwable {
310 readTx.read(TestModel.TEST_PATH).get();
311 } catch( ExecutionException e ) {
316 @Test(expected=IllegalStateException.class)
317 public void testWriteWithTransactionReady() throws Exception {
319 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
324 writeTx.write( TestModel.TEST_PATH, ImmutableNodes.containerNode( TestModel.TEST_QNAME ) );
327 @Test(expected=IllegalStateException.class)
328 public void testReadyWithTransactionAlreadyReady() throws Exception {
330 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
339 public void testTransactionAbort() throws InterruptedException, ExecutionException {
341 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
342 assertNotNull(writeTx);
344 assertTestContainerWrite(writeTx);
346 DOMStoreThreePhaseCommitCohort cohort = writeTx.ready();
348 assertTrue(cohort.canCommit().get().booleanValue());
349 cohort.preCommit().get();
350 cohort.abort().get();
352 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH)
354 assertFalse(afterCommitRead.isPresent());
358 public void testTransactionChain() throws InterruptedException, ExecutionException {
359 DOMStoreTransactionChain txChain = domStore.createTransactionChain();
360 assertNotNull(txChain);
363 * We alocate new read-write transaction and write /test
367 DOMStoreReadWriteTransaction firstTx = txChain.newReadWriteTransaction();
368 assertTestContainerWrite(firstTx);
371 * First transaction is marked as ready, we are able to allocate chained
374 DOMStoreThreePhaseCommitCohort firstWriteTxCohort = firstTx.ready();
377 * We alocate chained transaction - read transaction, note first one is
378 * still not commited to datastore.
380 DOMStoreReadTransaction secondReadTx = txChain.newReadOnlyTransaction();
384 * We test if we are able to read data from tx, read should not fail
385 * since we are using chained transaction.
389 assertTestContainerExists(secondReadTx);
393 * We alocate next transaction, which is still based on first one, but
397 DOMStoreReadWriteTransaction thirdDeleteTx = txChain.newReadWriteTransaction();
400 * We test existence of /test in third transaction container should
401 * still be visible from first one (which is still uncommmited).
405 assertTestContainerExists(thirdDeleteTx);
408 * We delete node in third transaction
410 thirdDeleteTx.delete(TestModel.TEST_PATH);
413 * third transaction is sealed.
415 DOMStoreThreePhaseCommitCohort thirdDeleteTxCohort = thirdDeleteTx.ready();
418 * We commit first transaction
421 assertThreePhaseCommit(firstWriteTxCohort);
423 // Alocates store transacion
424 DOMStoreReadTransaction storeReadTx = domStore.newReadOnlyTransaction();
426 * We verify transaction is commited to store, container should exists
429 assertTestContainerExists(storeReadTx);
431 * We commit third transaction
434 assertThreePhaseCommit(thirdDeleteTxCohort);
439 public void testTransactionConflict() throws InterruptedException, ExecutionException {
440 DOMStoreReadWriteTransaction txOne = domStore.newReadWriteTransaction();
441 DOMStoreReadWriteTransaction txTwo = domStore.newReadWriteTransaction();
442 assertTestContainerWrite(txOne);
443 assertTestContainerWrite(txTwo);
446 * Commits transaction
448 assertThreePhaseCommit(txOne.ready());
451 * Asserts that txTwo could not be commited
453 assertFalse(txTwo.ready().canCommit().get());
456 private static void assertThreePhaseCommit(final DOMStoreThreePhaseCommitCohort cohort)
457 throws InterruptedException, ExecutionException {
458 assertTrue(cohort.canCommit().get().booleanValue());
459 cohort.preCommit().get();
460 cohort.commit().get();
463 private static Optional<NormalizedNode<?, ?>> assertTestContainerWrite(final DOMStoreReadWriteTransaction writeTx)
464 throws InterruptedException, ExecutionException {
467 * Writes /test in writeTx
470 writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
472 return assertTestContainerExists(writeTx);
476 * Reads /test from readTx Read should return container.
478 private static Optional<NormalizedNode<?, ?>> assertTestContainerExists(final DOMStoreReadTransaction readTx)
479 throws InterruptedException, ExecutionException {
481 ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = readTx.read(TestModel.TEST_PATH);
482 assertTrue(writeTxContainer.get().isPresent());
483 return writeTxContainer.get();