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 com.google.common.base.Optional;
11 import com.google.common.util.concurrent.CheckedFuture;
12 import com.google.common.util.concurrent.ListenableFuture;
13 import com.google.common.util.concurrent.MoreExecutors;
14 import org.junit.Before;
15 import org.junit.Ignore;
16 import org.junit.Test;
17 import org.mockito.Mockito;
18 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
19 import org.opendaylight.controller.md.sal.dom.store.impl.SnapshotBackedWriteTransaction.TransactionReadyPrototype;
20 import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction;
21 import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
22 import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
23 import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain;
24 import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction;
25 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
26 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
27 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
28 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
29 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
30 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
31 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
32 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
33 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
35 import java.util.concurrent.ExecutionException;
37 import static org.junit.Assert.assertEquals;
38 import static org.junit.Assert.assertFalse;
39 import static org.junit.Assert.assertNotNull;
40 import static org.junit.Assert.assertTrue;
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() );
190 public void testExistsForExistingData() throws Exception {
192 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
193 assertNotNull( writeTx );
195 ContainerNode containerNode = ImmutableContainerNodeBuilder.create()
196 .withNodeIdentifier( new NodeIdentifier( TestModel.TEST_QNAME ) )
197 .addChild( ImmutableNodes.mapNodeBuilder( TestModel.OUTER_LIST_QNAME )
198 .addChild( ImmutableNodes.mapEntry( TestModel.OUTER_LIST_QNAME,
199 TestModel.ID_QNAME, 1 ) ).build() ).build();
201 writeTx.merge( TestModel.TEST_PATH, containerNode );
203 CheckedFuture<Boolean, ReadFailedException> exists =
204 writeTx.exists(TestModel.TEST_PATH);
206 assertEquals(true, exists.checkedGet());
208 DOMStoreThreePhaseCommitCohort ready = writeTx.ready();
210 ready.preCommit().get();
212 ready.commit().get();
214 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
215 assertNotNull( readTx );
218 readTx.exists(TestModel.TEST_PATH);
220 assertEquals(true, exists.checkedGet());
224 public void testExistsForNonExistingData() throws Exception {
226 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
227 assertNotNull( writeTx );
229 CheckedFuture<Boolean, ReadFailedException> exists =
230 writeTx.exists(TestModel.TEST_PATH);
232 assertEquals(false, exists.checkedGet());
234 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
235 assertNotNull( readTx );
238 readTx.exists(TestModel.TEST_PATH);
240 assertEquals(false, exists.checkedGet());
243 @Test(expected=ReadFailedException.class)
244 public void testExistsThrowsReadFailedException() throws Exception {
246 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
247 assertNotNull( readTx );
251 readTx.exists(TestModel.TEST_PATH).checkedGet();
256 @Test(expected=ReadFailedException.class)
257 public void testReadWithReadOnlyTransactionClosed() throws Throwable {
259 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
260 assertNotNull( readTx );
264 doReadAndThrowEx( readTx );
267 @Test(expected=ReadFailedException.class)
268 public void testReadWithReadOnlyTransactionFailure() throws Throwable {
270 DataTreeSnapshot mockSnapshot = Mockito.mock( DataTreeSnapshot.class );
271 Mockito.doThrow( new RuntimeException( "mock ex" ) ).when( mockSnapshot )
272 .readNode( Mockito.any( YangInstanceIdentifier.class ) );
274 DOMStoreReadTransaction readTx = new SnapshotBackedReadTransaction( "1", mockSnapshot );
276 doReadAndThrowEx( readTx );
279 @Test(expected=ReadFailedException.class)
280 public void testReadWithReadWriteTransactionClosed() throws Throwable {
282 DOMStoreReadTransaction readTx = domStore.newReadWriteTransaction();
283 assertNotNull( readTx );
287 doReadAndThrowEx( readTx );
290 @Test(expected=ReadFailedException.class)
291 public void testReadWithReadWriteTransactionFailure() throws Throwable {
293 DataTreeSnapshot mockSnapshot = Mockito.mock( DataTreeSnapshot.class );
294 DataTreeModification mockModification = Mockito.mock( DataTreeModification.class );
295 Mockito.doThrow( new RuntimeException( "mock ex" ) ).when( mockModification )
296 .readNode( Mockito.any( YangInstanceIdentifier.class ) );
297 Mockito.doReturn( mockModification ).when( mockSnapshot ).newModification();
298 TransactionReadyPrototype mockReady = Mockito.mock( TransactionReadyPrototype.class );
299 DOMStoreReadTransaction readTx = new SnapshotBackedReadWriteTransaction( "1", mockSnapshot, mockReady );
301 doReadAndThrowEx( readTx );
304 private void doReadAndThrowEx( DOMStoreReadTransaction readTx ) throws Throwable {
307 readTx.read(TestModel.TEST_PATH).get();
308 } catch( ExecutionException e ) {
313 @Test(expected=IllegalStateException.class)
314 public void testWriteWithTransactionReady() throws Exception {
316 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
321 writeTx.write( TestModel.TEST_PATH, ImmutableNodes.containerNode( TestModel.TEST_QNAME ) );
324 @Test(expected=IllegalStateException.class)
325 public void testReadyWithTransactionAlreadyReady() throws Exception {
327 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
336 public void testTransactionAbort() throws InterruptedException, ExecutionException {
338 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
339 assertNotNull(writeTx);
341 assertTestContainerWrite(writeTx);
343 DOMStoreThreePhaseCommitCohort cohort = writeTx.ready();
345 assertTrue(cohort.canCommit().get().booleanValue());
346 cohort.preCommit().get();
347 cohort.abort().get();
349 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH)
351 assertFalse(afterCommitRead.isPresent());
355 public void testTransactionChain() throws InterruptedException, ExecutionException {
356 DOMStoreTransactionChain txChain = domStore.createTransactionChain();
357 assertNotNull(txChain);
360 * We alocate new read-write transaction and write /test
364 DOMStoreReadWriteTransaction firstTx = txChain.newReadWriteTransaction();
365 assertTestContainerWrite(firstTx);
368 * First transaction is marked as ready, we are able to allocate chained
371 DOMStoreThreePhaseCommitCohort firstWriteTxCohort = firstTx.ready();
374 * We alocate chained transaction - read transaction, note first one is
375 * still not commited to datastore.
377 DOMStoreReadTransaction secondReadTx = txChain.newReadOnlyTransaction();
381 * We test if we are able to read data from tx, read should not fail
382 * since we are using chained transaction.
386 assertTestContainerExists(secondReadTx);
390 * We alocate next transaction, which is still based on first one, but
394 DOMStoreReadWriteTransaction thirdDeleteTx = txChain.newReadWriteTransaction();
397 * We test existence of /test in third transaction container should
398 * still be visible from first one (which is still uncommmited).
402 assertTestContainerExists(thirdDeleteTx);
405 * We delete node in third transaction
407 thirdDeleteTx.delete(TestModel.TEST_PATH);
410 * third transaction is sealed.
412 DOMStoreThreePhaseCommitCohort thirdDeleteTxCohort = thirdDeleteTx.ready();
415 * We commit first transaction
418 assertThreePhaseCommit(firstWriteTxCohort);
420 // Alocates store transacion
421 DOMStoreReadTransaction storeReadTx = domStore.newReadOnlyTransaction();
423 * We verify transaction is commited to store, container should exists
426 assertTestContainerExists(storeReadTx);
428 * We commit third transaction
431 assertThreePhaseCommit(thirdDeleteTxCohort);
436 public void testTransactionConflict() throws InterruptedException, ExecutionException {
437 DOMStoreReadWriteTransaction txOne = domStore.newReadWriteTransaction();
438 DOMStoreReadWriteTransaction txTwo = domStore.newReadWriteTransaction();
439 assertTestContainerWrite(txOne);
440 assertTestContainerWrite(txTwo);
443 * Commits transaction
445 assertThreePhaseCommit(txOne.ready());
448 * Asserts that txTwo could not be commited
450 assertFalse(txTwo.ready().canCommit().get());
453 private static void assertThreePhaseCommit(final DOMStoreThreePhaseCommitCohort cohort)
454 throws InterruptedException, ExecutionException {
455 assertTrue(cohort.canCommit().get().booleanValue());
456 cohort.preCommit().get();
457 cohort.commit().get();
460 private static Optional<NormalizedNode<?, ?>> assertTestContainerWrite(final DOMStoreReadWriteTransaction writeTx)
461 throws InterruptedException, ExecutionException {
464 * Writes /test in writeTx
467 writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
469 return assertTestContainerExists(writeTx);
473 * Reads /test from readTx Read should return container.
475 private static Optional<NormalizedNode<?, ?>> assertTestContainerExists(final DOMStoreReadTransaction readTx)
476 throws InterruptedException, ExecutionException {
478 ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = readTx.read(TestModel.TEST_PATH);
479 assertTrue(writeTxContainer.get().isPresent());
480 return writeTxContainer.get();