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.util.concurrent.ExecutionException;
20 import org.junit.Assert;
21 import org.junit.Before;
22 import org.junit.Ignore;
23 import org.junit.Test;
24 import org.mockito.Mockito;
25 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
26 import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction;
27 import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
28 import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
29 import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain;
30 import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction;
31 import org.opendaylight.controller.sal.core.spi.data.SnapshotBackedTransactions;
32 import org.opendaylight.controller.sal.core.spi.data.SnapshotBackedWriteTransaction.TransactionReadyPrototype;
33 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
34 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
35 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
36 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
37 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
38 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
39 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
40 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
41 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
43 public class InMemoryDataStoreTest {
45 private SchemaContext schemaContext;
46 private InMemoryDOMDataStore domStore;
49 public void setupStore() {
50 domStore = new InMemoryDOMDataStore("TEST", MoreExecutors.newDirectExecutorService());
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().read(TestModel.TEST_PATH)
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().read(TestModel.TEST_PATH).get();
140 assertEquals("After commit read: isPresent", false, afterCommitRead.isPresent());
144 public void testMerge() throws Exception {
146 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
147 assertNotNull(writeTx);
149 ContainerNode containerNode = ImmutableContainerNodeBuilder.create()
150 .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
151 .addChild(ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
152 .addChild(ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)).build())
155 writeTx.merge(TestModel.TEST_PATH, containerNode);
157 assertThreePhaseCommit(writeTx.ready());
159 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH)
161 assertEquals("After commit read: isPresent", true, afterCommitRead.isPresent());
162 assertEquals("After commit read: data", containerNode, afterCommitRead.get());
164 // Merge a new list entry node
166 writeTx = domStore.newWriteOnlyTransaction();
167 assertNotNull(writeTx);
169 containerNode = ImmutableContainerNodeBuilder.create()
170 .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
171 .addChild(ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
172 .addChild(ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1))
173 .addChild(ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 2)).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, TestModel.ID_QNAME, 1)).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();
251 @Test(expected = ReadFailedException.class)
252 public void testReadWithReadOnlyTransactionClosed() throws Exception {
254 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
255 assertNotNull(readTx);
259 doReadAndThrowEx(readTx);
262 @Test(expected = ReadFailedException.class)
263 public void testReadWithReadOnlyTransactionFailure() throws Exception {
265 DataTreeSnapshot mockSnapshot = Mockito.mock(DataTreeSnapshot.class);
266 Mockito.doThrow(new RuntimeException("mock ex")).when(mockSnapshot)
267 .readNode(Mockito.any(YangInstanceIdentifier.class));
269 DOMStoreReadTransaction readTx = SnapshotBackedTransactions.newReadTransaction("1", true, mockSnapshot);
271 doReadAndThrowEx(readTx);
274 @Test(expected = ReadFailedException.class)
275 public void testReadWithReadWriteTransactionClosed() throws Exception {
277 DOMStoreReadTransaction readTx = domStore.newReadWriteTransaction();
278 assertNotNull(readTx);
282 doReadAndThrowEx(readTx);
285 @Test(expected = ReadFailedException.class)
286 public void testReadWithReadWriteTransactionFailure() throws Exception {
288 DataTreeSnapshot mockSnapshot = Mockito.mock(DataTreeSnapshot.class);
289 DataTreeModification mockModification = Mockito.mock(DataTreeModification.class);
290 Mockito.doThrow(new RuntimeException("mock ex")).when(mockModification)
291 .readNode(Mockito.any(YangInstanceIdentifier.class));
292 Mockito.doReturn(mockModification).when(mockSnapshot).newModification();
293 @SuppressWarnings("unchecked")
294 TransactionReadyPrototype<String> mockReady = Mockito.mock(TransactionReadyPrototype.class);
295 DOMStoreReadTransaction readTx = SnapshotBackedTransactions.newReadWriteTransaction("1", false, mockSnapshot,
298 doReadAndThrowEx(readTx);
301 private static void doReadAndThrowEx(final DOMStoreReadTransaction readTx) throws ReadFailedException {
302 readTx.read(TestModel.TEST_PATH).checkedGet();
305 @Test(expected = IllegalStateException.class)
306 public void testWriteWithTransactionReady() throws Exception {
308 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
313 writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
316 @Test(expected = IllegalStateException.class)
317 public void testReadyWithTransactionAlreadyReady() throws Exception {
319 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
328 public void testReadyWithMissingMandatoryData() throws InterruptedException {
329 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
330 NormalizedNode<?, ?> testNode = ImmutableContainerNodeBuilder.create()
331 .withNodeIdentifier(new NodeIdentifier(TestModel.MANDATORY_DATA_TEST_QNAME))
332 .addChild(ImmutableNodes.leafNode(TestModel.OPTIONAL_QNAME, "data"))
334 writeTx.write(TestModel.MANDATORY_DATA_TEST_PATH, testNode);
335 DOMStoreThreePhaseCommitCohort ready = writeTx.ready();
337 ready.canCommit().get();
338 Assert.fail("Expected exception on canCommit");
339 } catch (ExecutionException e) {
345 public void testTransactionAbort() throws InterruptedException, ExecutionException {
347 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
348 assertNotNull(writeTx);
350 assertTestContainerWrite(writeTx);
352 DOMStoreThreePhaseCommitCohort cohort = writeTx.ready();
354 assertTrue(cohort.canCommit().get().booleanValue());
355 cohort.preCommit().get();
356 cohort.abort().get();
358 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH)
360 assertFalse(afterCommitRead.isPresent());
364 public void testTransactionChain() throws InterruptedException, ExecutionException {
365 DOMStoreTransactionChain txChain = domStore.createTransactionChain();
366 assertNotNull(txChain);
369 * We alocate new read-write transaction and write /test
371 DOMStoreReadWriteTransaction firstTx = txChain.newReadWriteTransaction();
372 assertTestContainerWrite(firstTx);
375 * First transaction is marked as ready, we are able to allocate chained
378 final DOMStoreThreePhaseCommitCohort firstWriteTxCohort = firstTx.ready();
381 * We alocate chained transaction - read transaction, note first one is
382 * still not commited to datastore.
384 DOMStoreReadTransaction secondReadTx = txChain.newReadOnlyTransaction();
387 * We test if we are able to read data from tx, read should not fail
388 * since we are using chained transaction.
390 assertTestContainerExists(secondReadTx);
393 * We alocate next transaction, which is still based on first one, but
396 DOMStoreReadWriteTransaction thirdDeleteTx = txChain.newReadWriteTransaction();
399 * We test existence of /test in third transaction container should
400 * 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
417 assertThreePhaseCommit(firstWriteTxCohort);
419 // Alocates store transacion
420 DOMStoreReadTransaction storeReadTx = domStore.newReadOnlyTransaction();
423 * We verify transaction is commited to store, container should exists
426 assertTestContainerExists(storeReadTx);
429 * 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 {
463 * Writes /test in writeTx
465 writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
467 return assertTestContainerExists(writeTx);
471 * Reads /test from readTx Read should return container.
473 private static Optional<NormalizedNode<?, ?>> assertTestContainerExists(final DOMStoreReadTransaction readTx)
474 throws InterruptedException, ExecutionException {
476 ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = readTx.read(TestModel.TEST_PATH);
477 assertTrue(writeTxContainer.get().isPresent());
478 return writeTxContainer.get();