Move AbstractDOMDataBroker to mdsal-dom-spi
[mdsal.git] / dom / mdsal-dom-broker / src / test / java / org / opendaylight / mdsal / dom / broker / DOMTransactionChainTest.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.mdsal.dom.broker;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertNotNull;
12 import static org.junit.Assert.assertThrows;
13 import static org.junit.Assert.assertTrue;
14 import static org.opendaylight.mdsal.common.api.LogicalDatastoreType.CONFIGURATION;
15 import static org.opendaylight.mdsal.common.api.LogicalDatastoreType.OPERATIONAL;
16
17 import com.google.common.collect.ImmutableMap;
18 import com.google.common.util.concurrent.ListenableFuture;
19 import com.google.common.util.concurrent.ListeningExecutorService;
20 import com.google.common.util.concurrent.MoreExecutors;
21 import java.util.Optional;
22 import java.util.concurrent.ExecutionException;
23 import java.util.concurrent.Executors;
24 import java.util.concurrent.TimeUnit;
25 import java.util.concurrent.TimeoutException;
26 import org.junit.Before;
27 import org.junit.Test;
28 import org.opendaylight.mdsal.common.api.CommitInfo;
29 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
30 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
31 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
32 import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
33 import org.opendaylight.mdsal.dom.spi.AbstractDOMDataBroker;
34 import org.opendaylight.mdsal.dom.spi.store.DOMStore;
35 import org.opendaylight.mdsal.dom.store.inmemory.InMemoryDOMDataStore;
36 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
37 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
38 import org.opendaylight.yangtools.yang.data.spi.node.ImmutableNodes;
39
40 public class DOMTransactionChainTest extends AbstractDatastoreTest {
41
42     private AbstractDOMDataBroker domBroker;
43
44     @Before
45     public void setupStore() {
46         final InMemoryDOMDataStore operStore = new InMemoryDOMDataStore("OPER",
47                 MoreExecutors.newDirectExecutorService());
48         final InMemoryDOMDataStore configStore = new InMemoryDOMDataStore("CFG",
49                 MoreExecutors.newDirectExecutorService());
50
51         operStore.onModelContextUpdated(SCHEMA_CONTEXT);
52         configStore.onModelContextUpdated(SCHEMA_CONTEXT);
53
54         final ImmutableMap<LogicalDatastoreType, DOMStore> stores =
55                 ImmutableMap.<LogicalDatastoreType, DOMStore>builder()
56                 .put(CONFIGURATION, configStore)
57                 .put(OPERATIONAL, operStore)
58                 .build();
59
60         final ListeningExecutorService executor = MoreExecutors.listeningDecorator(
61                 Executors.newSingleThreadExecutor());
62         domBroker = new SerializedDOMDataBroker(stores, executor);
63     }
64
65     @Test
66     public void testTransactionChainNoConflict() throws InterruptedException, ExecutionException, TimeoutException {
67         final DOMTransactionChain txChain = domBroker.createTransactionChain();
68         assertNotNull(txChain);
69
70         /**
71          * We allocate new read-write transaction and write /test.
72          */
73         final DOMDataTreeWriteTransaction firstTx = allocateAndWrite(txChain);
74
75         /**
76          * First transaction is marked as ready, we are able to allocate chained
77          * transactions.
78          */
79         final ListenableFuture<? extends CommitInfo> firstWriteTxFuture = firstTx.commit();
80
81         /**
82          * We allocate chained transaction - read transaction.
83          */
84         final DOMDataTreeReadTransaction secondReadTx = txChain.newReadOnlyTransaction();
85
86         /**
87          *
88          * We test if we are able to read data from tx, read should not fail
89          * since we are using chained transaction.
90          *
91          *
92          */
93         assertTestContainerExists(secondReadTx);
94
95         /**
96          * We allocate next transaction, which is still based on first one, but
97          * is read-write.
98          *
99          */
100         final DOMDataTreeWriteTransaction thirdDeleteTx = allocateAndDelete(txChain);
101
102         /**
103          * We commit first transaction
104          *
105          */
106         assertCommitSuccessful(firstWriteTxFuture);
107
108         /**
109          * Allocates transaction from data store.
110          *
111          */
112         final DOMDataTreeReadTransaction storeReadTx = domBroker.newReadOnlyTransaction();
113
114         /**
115          * We verify transaction is committed to store, container should exist
116          * in datastore.
117          */
118         assertTestContainerExists(storeReadTx);
119
120         /**
121          * third transaction is sealed and committed.
122          */
123         assertCommitSuccessful(thirdDeleteTx.commit());
124
125         /**
126          * We close transaction chain.
127          */
128         txChain.close();
129
130         txChain.future().get(1000, TimeUnit.MILLISECONDS);
131     }
132
133     @Test
134     public void testTransactionChainNotSealed() {
135         final var txChain = domBroker.createTransactionChain();
136         assertNotNull(txChain);
137
138         /**
139          * We allocate new read-write transaction and write /test
140          */
141         allocateAndWrite(txChain);
142
143         /**
144          * We allocate chained transaction - read transaction, note first one is
145          * still not committed to datastore, so this allocation should fail with
146          * IllegalStateException.
147          */
148         // actual backing tx allocation happens on put
149         final var ex = assertThrows(IllegalStateException.class, () -> allocateAndWrite(txChain));
150         assertEquals("Previous transaction OPER-0 is not ready yet", ex.getMessage());
151     }
152
153     private static DOMDataTreeWriteTransaction allocateAndDelete(final DOMTransactionChain txChain)
154             throws InterruptedException, ExecutionException {
155         final DOMDataTreeWriteTransaction tx = txChain.newWriteOnlyTransaction();
156         /**
157          * We delete node in third transaction
158          */
159         tx.delete(LogicalDatastoreType.OPERATIONAL, TestModel.TEST_PATH);
160         return tx;
161     }
162
163     private static DOMDataTreeWriteTransaction allocateAndWrite(final DOMTransactionChain txChain) {
164         final var tx = txChain.newWriteOnlyTransaction();
165         writeTestContainer(tx);
166         return tx;
167     }
168
169     private static void assertCommitSuccessful(final ListenableFuture<? extends CommitInfo> firstWriteTxFuture)
170             throws InterruptedException, ExecutionException {
171         firstWriteTxFuture.get();
172     }
173
174     private static void assertTestContainerExists(final DOMDataTreeReadTransaction readTx)
175             throws InterruptedException, ExecutionException {
176         final ListenableFuture<Optional<NormalizedNode>> readFuture = readTx.read(OPERATIONAL, TestModel.TEST_PATH);
177         final Optional<NormalizedNode> readedData = readFuture.get();
178         assertTrue(readedData.isPresent());
179     }
180
181     private static void writeTestContainer(final DOMDataTreeWriteTransaction tx) {
182         tx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.newContainerBuilder()
183             .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
184             .build());
185     }
186 }