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.ListenableFuture;
17 import com.google.common.util.concurrent.MoreExecutors;
18 import java.io.IOException;
19 import java.util.concurrent.ExecutionException;
20 import org.junit.Before;
21 import org.junit.Ignore;
22 import org.junit.Test;
23 import org.mockito.Mockito;
24 import org.opendaylight.mdsal.common.api.ReadFailedException;
25 import org.opendaylight.mdsal.dom.spi.store.DOMStoreReadTransaction;
26 import org.opendaylight.mdsal.dom.spi.store.DOMStoreReadWriteTransaction;
27 import org.opendaylight.mdsal.dom.spi.store.DOMStoreThreePhaseCommitCohort;
28 import org.opendaylight.mdsal.dom.spi.store.DOMStoreTransactionChain;
29 import org.opendaylight.mdsal.dom.spi.store.DOMStoreWriteTransaction;
30 import org.opendaylight.mdsal.dom.spi.store.SnapshotBackedTransactions;
31 import org.opendaylight.mdsal.dom.spi.store.SnapshotBackedWriteTransaction.TransactionReadyPrototype;
32 import org.opendaylight.mdsal.dom.store.inmemory.InMemoryDOMDataStore;
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;
42 import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
43 import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
45 public class InMemoryDataStoreTest {
47 private SchemaContext schemaContext;
48 private InMemoryDOMDataStore domStore;
51 public void setupStore() throws IOException, YangSyntaxErrorException, ReactorException {
52 domStore = new InMemoryDOMDataStore("TEST", MoreExecutors.newDirectExecutorService());
53 schemaContext = TestModel.createTestContext();
54 domStore.onGlobalContextUpdated(schemaContext);
58 public void testTransactionIsolation() throws InterruptedException, ExecutionException {
60 assertNotNull(domStore);
62 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
63 assertNotNull(readTx);
65 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
66 assertNotNull(writeTx);
69 * Writes /test in writeTx.
71 NormalizedNode<?, ?> testNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
72 writeTx.write(TestModel.TEST_PATH, testNode);
75 * Reads /test from writeTx Read should return container.
77 ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = writeTx.read(TestModel.TEST_PATH);
78 assertEquals("read: isPresent", true, writeTxContainer.get().isPresent());
79 assertEquals("read: data", testNode, writeTxContainer.get().get());
82 * Reads /test from readTx Read should return Absent.
84 ListenableFuture<Optional<NormalizedNode<?, ?>>> readTxContainer = readTx.read(TestModel.TEST_PATH);
85 assertEquals("read: isPresent", false, readTxContainer.get().isPresent());
89 public void testTransactionCommit() throws InterruptedException, ExecutionException {
91 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
92 assertNotNull(writeTx);
95 * Writes /test in writeTx.
97 NormalizedNode<?, ?> testNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
98 writeTx.write(TestModel.TEST_PATH, testNode);
101 * Reads /test from writeTx Read should return container.
103 ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = writeTx.read(TestModel.TEST_PATH);
104 assertEquals("read: isPresent", true, writeTxContainer.get().isPresent());
105 assertEquals("read: data", testNode, writeTxContainer.get().get());
107 DOMStoreThreePhaseCommitCohort cohort = writeTx.ready();
109 assertThreePhaseCommit(cohort);
111 Optional<NormalizedNode<?, ?>> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH)
113 assertEquals("After commit read: isPresent", true, afterCommitRead.isPresent());
114 assertEquals("After commit read: data", testNode, afterCommitRead.get());
118 public void testDelete() throws Exception {
120 DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction();
121 assertNotNull(writeTx);
123 // Write /test and commit
125 writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
127 assertThreePhaseCommit(writeTx.ready());
129 Optional<NormalizedNode<?, ?>> afterCommitRead =
130 domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH).get();
131 assertEquals("After commit read: isPresent", true, afterCommitRead.isPresent());
133 // Delete /test and verify
135 writeTx = domStore.newWriteOnlyTransaction();
137 writeTx.delete(TestModel.TEST_PATH);
139 assertThreePhaseCommit(writeTx.ready());
141 afterCommitRead = domStore.newReadOnlyTransaction().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 =
162 domStore.newReadOnlyTransaction().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 ListenableFuture<Boolean> exists = writeTx.exists(TestModel.TEST_PATH);
205 assertEquals(Boolean.TRUE, exists.get());
207 DOMStoreThreePhaseCommitCohort ready = writeTx.ready();
209 ready.preCommit().get();
211 ready.commit().get();
213 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
214 assertNotNull(readTx);
217 readTx.exists(TestModel.TEST_PATH);
219 assertEquals(Boolean.TRUE, exists.get());
223 public void testExistsForNonExistingData() throws Exception {
225 DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
226 assertNotNull(writeTx);
228 ListenableFuture<Boolean> exists = writeTx.exists(TestModel.TEST_PATH);
230 assertEquals(Boolean.FALSE, exists.get());
232 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
233 assertNotNull(readTx);
236 readTx.exists(TestModel.TEST_PATH);
238 assertEquals(Boolean.FALSE, exists.get());
241 @Test(expected = ReadFailedException.class)
242 public void testExistsThrowsReadFailedException() throws Exception {
244 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
245 assertNotNull(readTx);
249 readTx.exists(TestModel.TEST_PATH).checkedGet();
253 @SuppressWarnings("checkstyle:IllegalThrows")
254 @Test(expected = ReadFailedException.class)
255 public void testReadWithReadOnlyTransactionClosed() throws Throwable {
257 DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction();
258 assertNotNull(readTx);
262 doReadAndThrowEx(readTx);
265 @SuppressWarnings("checkstyle:IllegalThrows")
266 @Test(expected = ReadFailedException.class)
267 public void testReadWithReadOnlyTransactionFailure() throws Throwable {
269 DataTreeSnapshot mockSnapshot = Mockito.mock(DataTreeSnapshot.class);
270 Mockito.doThrow(new RuntimeException("mock ex")).when(mockSnapshot)
271 .readNode(Mockito.any(YangInstanceIdentifier.class));
273 DOMStoreReadTransaction readTx = SnapshotBackedTransactions.newReadTransaction("1", true, mockSnapshot);
275 doReadAndThrowEx(readTx);
278 @SuppressWarnings("checkstyle:IllegalThrows")
279 @Test(expected = ReadFailedException.class)
280 public void testReadWithReadWriteTransactionClosed() throws Throwable {
282 DOMStoreReadTransaction readTx = domStore.newReadWriteTransaction();
283 assertNotNull(readTx);
287 doReadAndThrowEx(readTx);
290 @SuppressWarnings("checkstyle:IllegalThrows")
291 @Test(expected = ReadFailedException.class)
292 public void testReadWithReadWriteTransactionFailure() throws Throwable {
294 DataTreeSnapshot mockSnapshot = Mockito.mock(DataTreeSnapshot.class);
295 DataTreeModification mockModification = Mockito.mock(DataTreeModification.class);
296 Mockito.doThrow(new RuntimeException("mock ex")).when(mockModification)
297 .readNode(Mockito.any(YangInstanceIdentifier.class));
298 Mockito.doReturn(mockModification).when(mockSnapshot).newModification();
299 @SuppressWarnings("unchecked")
300 TransactionReadyPrototype<String> mockReady = Mockito.mock(TransactionReadyPrototype.class);
301 DOMStoreReadTransaction readTx = SnapshotBackedTransactions.newReadWriteTransaction(
302 "1", false, mockSnapshot, mockReady);
304 doReadAndThrowEx(readTx);
307 @SuppressWarnings({ "checkstyle:IllegalThrows", "checkstyle:avoidHidingCauseException" })
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.
365 DOMStoreReadWriteTransaction firstTx = txChain.newReadWriteTransaction();
366 assertTestContainerWrite(firstTx);
369 * First transaction is marked as ready, we are able to allocate chained
372 final DOMStoreThreePhaseCommitCohort firstWriteTxCohort = firstTx.ready();
375 * We alocate chained transaction - read transaction, note first one is
376 * still not commited to datastore.
378 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.
384 assertTestContainerExists(secondReadTx);
387 * We alocate next transaction, which is still based on first one, but
390 DOMStoreReadWriteTransaction thirdDeleteTx = txChain.newReadWriteTransaction();
393 * We test existence of /test in third transaction container should
394 * still be visible from first one (which is still uncommmited).
396 assertTestContainerExists(thirdDeleteTx);
399 * We delete node in third transaction.
401 thirdDeleteTx.delete(TestModel.TEST_PATH);
404 * third transaction is sealed.
406 DOMStoreThreePhaseCommitCohort thirdDeleteTxCohort = thirdDeleteTx.ready();
409 * We commit first transaction.
412 assertThreePhaseCommit(firstWriteTxCohort);
414 // Alocates store transacion
415 DOMStoreReadTransaction storeReadTx = domStore.newReadOnlyTransaction();
417 * We verify transaction is commited to store, container should exists
420 assertTestContainerExists(storeReadTx);
422 * We commit third transaction
425 assertThreePhaseCommit(thirdDeleteTxCohort);
430 public void testTransactionConflict() throws InterruptedException, ExecutionException {
431 DOMStoreReadWriteTransaction txOne = domStore.newReadWriteTransaction();
432 DOMStoreReadWriteTransaction txTwo = domStore.newReadWriteTransaction();
433 assertTestContainerWrite(txOne);
434 assertTestContainerWrite(txTwo);
437 * Commits transaction
439 assertThreePhaseCommit(txOne.ready());
442 * Asserts that txTwo could not be commited
444 assertFalse(txTwo.ready().canCommit().get());
447 private static void assertThreePhaseCommit(final DOMStoreThreePhaseCommitCohort cohort)
448 throws InterruptedException, ExecutionException {
449 assertTrue(cohort.canCommit().get().booleanValue());
450 cohort.preCommit().get();
451 cohort.commit().get();
454 private static Optional<NormalizedNode<?, ?>> assertTestContainerWrite(final DOMStoreReadWriteTransaction writeTx)
455 throws InterruptedException, ExecutionException {
458 * Writes /test in writeTx
461 writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
463 return assertTestContainerExists(writeTx);
467 * Reads /test from readTx Read should return container.
469 private static Optional<NormalizedNode<?, ?>> assertTestContainerExists(final DOMStoreReadTransaction readTx)
470 throws InterruptedException, ExecutionException {
472 ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = readTx.read(TestModel.TEST_PATH);
473 assertTrue(writeTxContainer.get().isPresent());
474 return writeTxContainer.get();