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 com.google.common.base.Optional;
16 import com.google.common.util.concurrent.CheckedFuture;
17 import com.google.common.util.concurrent.ListenableFuture;
18 import com.google.common.util.concurrent.MoreExecutors;
19 import java.io.IOException;
20 import java.util.concurrent.ExecutionException;
21 import org.junit.Before;
22 import org.junit.Ignore;
23 import org.junit.Test;
24 import org.mockito.Mockito;
25 import org.opendaylight.mdsal.common.api.ReadFailedException;
26 import org.opendaylight.mdsal.dom.spi.store.DOMStoreReadTransaction;
27 import org.opendaylight.mdsal.dom.spi.store.DOMStoreReadWriteTransaction;
28 import org.opendaylight.mdsal.dom.spi.store.DOMStoreThreePhaseCommitCohort;
29 import org.opendaylight.mdsal.dom.spi.store.DOMStoreTransactionChain;
30 import org.opendaylight.mdsal.dom.spi.store.DOMStoreWriteTransaction;
31 import org.opendaylight.mdsal.dom.spi.store.SnapshotBackedTransactions;
32 import org.opendaylight.mdsal.dom.spi.store.SnapshotBackedWriteTransaction.TransactionReadyPrototype;
33 import org.opendaylight.mdsal.dom.store.inmemory.InMemoryDOMDataStore;
34 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
35 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
36 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
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.impl.ImmutableContainerNodeBuilder;
42 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
43 import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
44 import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
46 public class InMemoryDataStoreTest {
48 private SchemaContext schemaContext;
49 private InMemoryDOMDataStore domStore;
52 public void setupStore() throws IOException, YangSyntaxErrorException, ReactorException {
53 domStore = new InMemoryDOMDataStore("TEST", MoreExecutors.newDirectExecutorService());
54 schemaContext = TestModel.createTestContext();
55 domStore.onGlobalContextUpdated(schemaContext);
59 public void testTransactionIsolation() throws InterruptedException, ExecutionException {
61 assertNotNull(domStore);
63 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
64 assertNotNull(readTx);
66 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
67 assertNotNull(writeTx);
70 * Writes /test in writeTx.
72 NormalizedNode<?, ?> testNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
73 writeTx.write(TestModel.TEST_PATH, testNode);
76 * Reads /test from writeTx Read should return container.
78 ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = writeTx.read(TestModel.TEST_PATH);
79 assertEquals("read: isPresent", true, writeTxContainer.get().isPresent());
80 assertEquals("read: data", testNode, writeTxContainer.get().get());
83 * Reads /test from readTx Read should return Absent.
85 ListenableFuture<Optional<NormalizedNode<?, ?>>> readTxContainer = readTx.read(TestModel.TEST_PATH);
86 assertEquals("read: isPresent", false, readTxContainer.get().isPresent());
90 public void testTransactionCommit() throws InterruptedException, ExecutionException {
92 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
93 assertNotNull(writeTx);
96 * Writes /test in writeTx.
98 NormalizedNode<?, ?> testNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
99 writeTx.write(TestModel.TEST_PATH, testNode);
102 * Reads /test from writeTx Read should return container.
104 ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = writeTx.read(TestModel.TEST_PATH);
105 assertEquals("read: isPresent", true, writeTxContainer.get().isPresent());
106 assertEquals("read: data", testNode, writeTxContainer.get().get());
108 DOMStoreThreePhaseCommitCohort cohort = writeTx.ready();
110 assertThreePhaseCommit(cohort);
112 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH)
114 assertEquals("After commit read: isPresent", true, afterCommitRead.isPresent());
115 assertEquals("After commit read: data", testNode, afterCommitRead.get());
119 public void testDelete() throws Exception {
121 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
122 assertNotNull( writeTx );
124 // Write /test and commit
126 writeTx.write( TestModel.TEST_PATH, ImmutableNodes.containerNode( TestModel.TEST_QNAME ) );
128 assertThreePhaseCommit( writeTx.ready() );
130 Optional<NormalizedNode<?, ?>> afterCommitRead =
131 domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH ).get();
132 assertEquals( "After commit read: isPresent", true, afterCommitRead.isPresent() );
134 // Delete /test and verify
136 writeTx = domStore.newWriteOnlyTransaction();
138 writeTx.delete( TestModel.TEST_PATH );
140 assertThreePhaseCommit( writeTx.ready() );
142 afterCommitRead = domStore.newReadOnlyTransaction().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 =
163 domStore.newReadOnlyTransaction().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();
256 @SuppressWarnings("checkstyle:IllegalThrows")
257 @Test(expected = ReadFailedException.class)
258 public void testReadWithReadOnlyTransactionClosed() throws Throwable {
260 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
261 assertNotNull( readTx );
265 doReadAndThrowEx( readTx );
268 @SuppressWarnings("checkstyle:IllegalThrows")
269 @Test(expected = ReadFailedException.class)
270 public void testReadWithReadOnlyTransactionFailure() throws Throwable {
272 DataTreeSnapshot mockSnapshot = Mockito.mock( DataTreeSnapshot.class );
273 Mockito.doThrow( new RuntimeException( "mock ex" ) ).when( mockSnapshot )
274 .readNode( Mockito.any( YangInstanceIdentifier.class ) );
276 DOMStoreReadTransaction readTx = SnapshotBackedTransactions.newReadTransaction("1", true, mockSnapshot);
278 doReadAndThrowEx( readTx );
281 @SuppressWarnings("checkstyle:IllegalThrows")
282 @Test(expected = ReadFailedException.class)
283 public void testReadWithReadWriteTransactionClosed() throws Throwable {
285 DOMStoreReadTransaction readTx = domStore.newReadWriteTransaction();
286 assertNotNull( readTx );
290 doReadAndThrowEx( readTx );
293 @SuppressWarnings("checkstyle:IllegalThrows")
294 @Test(expected = ReadFailedException.class)
295 public void testReadWithReadWriteTransactionFailure() throws Throwable {
297 DataTreeSnapshot mockSnapshot = Mockito.mock( DataTreeSnapshot.class );
298 DataTreeModification mockModification = Mockito.mock( DataTreeModification.class );
299 Mockito.doThrow( new RuntimeException( "mock ex" ) ).when( mockModification )
300 .readNode( Mockito.any( YangInstanceIdentifier.class ) );
301 Mockito.doReturn( mockModification ).when( mockSnapshot ).newModification();
302 @SuppressWarnings("unchecked")
303 TransactionReadyPrototype<String> mockReady = Mockito.mock( TransactionReadyPrototype.class );
304 DOMStoreReadTransaction readTx = SnapshotBackedTransactions.newReadWriteTransaction(
305 "1", false, mockSnapshot, mockReady);
307 doReadAndThrowEx( readTx );
310 @SuppressWarnings("checkstyle:IllegalThrows")
311 private static void doReadAndThrowEx( final DOMStoreReadTransaction readTx ) throws Throwable {
313 readTx.read(TestModel.TEST_PATH).get();
314 } catch ( ExecutionException e ) {
319 @Test(expected = IllegalStateException.class)
320 public void testWriteWithTransactionReady() throws Exception {
322 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
327 writeTx.write( TestModel.TEST_PATH, ImmutableNodes.containerNode( TestModel.TEST_QNAME ) );
330 @Test(expected = IllegalStateException.class)
331 public void testReadyWithTransactionAlreadyReady() throws Exception {
333 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
342 public void testTransactionAbort() throws InterruptedException, ExecutionException {
344 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
345 assertNotNull(writeTx);
347 assertTestContainerWrite(writeTx);
349 DOMStoreThreePhaseCommitCohort cohort = writeTx.ready();
351 assertTrue(cohort.canCommit().get().booleanValue());
352 cohort.preCommit().get();
353 cohort.abort().get();
355 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH)
357 assertFalse(afterCommitRead.isPresent());
361 public void testTransactionChain() throws InterruptedException, ExecutionException {
362 DOMStoreTransactionChain txChain = domStore.createTransactionChain();
363 assertNotNull(txChain);
366 * We alocate new read-write transaction and write /test.
368 DOMStoreReadWriteTransaction firstTx = txChain.newReadWriteTransaction();
369 assertTestContainerWrite(firstTx);
372 * First transaction is marked as ready, we are able to allocate chained
375 final DOMStoreThreePhaseCommitCohort firstWriteTxCohort = firstTx.ready();
378 * We alocate chained transaction - read transaction, note first one is
379 * still not commited to datastore.
381 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.
387 assertTestContainerExists(secondReadTx);
390 * We alocate next transaction, which is still based on first one, but
393 DOMStoreReadWriteTransaction thirdDeleteTx = txChain.newReadWriteTransaction();
396 * We test existence of /test in third transaction container should
397 * 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();