aca1901557aebfb7ce2f61ddaf6a1454eb086c3b
[mdsal.git] / dom / mdsal-dom-broker / src / test / java / org / opendaylight / mdsal / dom / broker / DOMBrokerTest.java
1 /*
2  * Copyright (c) 2014, 2015 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.assertFalse;
12 import static org.junit.Assert.assertNotNull;
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.ForwardingExecutorService;
19 import com.google.common.util.concurrent.ListeningExecutorService;
20 import com.google.common.util.concurrent.MoreExecutors;
21 import java.util.Collections;
22 import java.util.Optional;
23 import java.util.concurrent.ExecutionException;
24 import java.util.concurrent.ExecutorService;
25 import java.util.concurrent.Executors;
26 import java.util.concurrent.RejectedExecutionException;
27 import java.util.concurrent.TimeUnit;
28 import java.util.concurrent.atomic.AtomicReference;
29 import org.junit.After;
30 import org.junit.Before;
31 import org.junit.Test;
32 import org.mockito.Mockito;
33 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
34 import org.opendaylight.mdsal.common.api.ReadFailedException;
35 import org.opendaylight.mdsal.common.api.TransactionCommitDeadlockException;
36 import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
37 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
38 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
39 import org.opendaylight.mdsal.dom.spi.store.DOMStore;
40 import org.opendaylight.mdsal.dom.store.inmemory.InMemoryDOMDataStore;
41 import org.opendaylight.yangtools.util.concurrent.DeadlockDetectingListeningExecutorService;
42 import org.opendaylight.yangtools.util.concurrent.SpecialExecutors;
43 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
44 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
45 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
46 import org.opendaylight.yangtools.yang.data.spi.node.ImmutableNodes;
47
48 public class DOMBrokerTest extends AbstractDatastoreTest {
49
50     private AbstractDOMDataBroker domBroker;
51     private ListeningExecutorService executor;
52     private ExecutorService futureExecutor;
53     private CommitExecutorService commitExecutor;
54
55     @Before
56     public void setupStore() {
57         final InMemoryDOMDataStore operStore = new InMemoryDOMDataStore("OPER",
58                 MoreExecutors.newDirectExecutorService());
59         final InMemoryDOMDataStore configStore = new InMemoryDOMDataStore("CFG",
60                 MoreExecutors.newDirectExecutorService());
61
62         operStore.onModelContextUpdated(SCHEMA_CONTEXT);
63         configStore.onModelContextUpdated(SCHEMA_CONTEXT);
64
65         final ImmutableMap<LogicalDatastoreType, DOMStore> stores =
66                 ImmutableMap.<LogicalDatastoreType, DOMStore>builder()
67                 .put(CONFIGURATION, configStore)
68                 .put(OPERATIONAL, operStore)
69                 .build();
70
71         commitExecutor = new CommitExecutorService(Executors.newSingleThreadExecutor());
72         futureExecutor = SpecialExecutors.newBlockingBoundedCachedThreadPool(1, 5, "FCB", DOMBrokerTest.class);
73         executor = new DeadlockDetectingListeningExecutorService(commitExecutor,
74                 TransactionCommitDeadlockException.DEADLOCK_EXCEPTION_SUPPLIER, futureExecutor);
75         domBroker = new SerializedDOMDataBroker(stores, executor);
76     }
77
78     @After
79     public void tearDown() {
80         if (executor != null) {
81             executor.shutdownNow();
82         }
83
84         if (futureExecutor != null) {
85             futureExecutor.shutdownNow();
86         }
87     }
88
89     @Test(timeout = 10000)
90     public void testTransactionIsolation() throws InterruptedException, ExecutionException {
91         assertNotNull(domBroker);
92
93         final DOMDataTreeReadTransaction readTx = domBroker.newReadOnlyTransaction();
94         assertNotNull(readTx);
95
96         final DOMDataTreeWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
97         assertNotNull(writeTx);
98
99         /**
100          * Writes /test in writeTx.
101          *
102          */
103         writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.newContainerBuilder()
104             .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
105             .build());
106
107         /**
108          * Reads /test from readTx Read should return Absent.
109          *
110          */
111         final var readTxContainer = readTx.read(OPERATIONAL, TestModel.TEST_PATH);
112         assertEquals(Optional.empty(), readTxContainer.get());
113     }
114
115     @Test(timeout = 10000)
116     public void testTransactionCommit() throws InterruptedException, ExecutionException {
117         final DOMDataTreeWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
118         assertNotNull(writeTx);
119         /**
120          * Writes /test in writeTx
121          *
122          */
123         writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.newContainerBuilder()
124             .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
125             .build());
126
127         writeTx.commit().get();
128
129         final var afterCommitRead = domBroker.newReadOnlyTransaction().read(OPERATIONAL, TestModel.TEST_PATH).get();
130         assertTrue(afterCommitRead.isPresent());
131     }
132
133     @Test(expected = TransactionCommitFailedException.class)
134     @SuppressWarnings({"checkstyle:AvoidHidingCauseException", "checkstyle:IllegalThrows"})
135     public void testRejectedCommit() throws Throwable {
136         commitExecutor.delegate = Mockito.mock(ExecutorService.class);
137         Mockito.doThrow(new RejectedExecutionException("mock"))
138             .when(commitExecutor.delegate).execute(Mockito.any(Runnable.class));
139         Mockito.doNothing().when(commitExecutor.delegate).shutdown();
140         Mockito.doReturn(Collections.emptyList()).when(commitExecutor.delegate).shutdownNow();
141         Mockito.doReturn("").when(commitExecutor.delegate).toString();
142         Mockito.doReturn(Boolean.TRUE).when(commitExecutor.delegate)
143             .awaitTermination(Mockito.anyLong(), Mockito.any(TimeUnit.class));
144
145         final DOMDataTreeWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
146         writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.newContainerBuilder()
147             .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
148             .build());
149
150         try {
151             writeTx.commit().get(5, TimeUnit.SECONDS);
152         } catch (ExecutionException e) {
153             throw e.getCause();
154         }
155     }
156
157     @SuppressWarnings("checkstyle:IllegalCatch")
158     AtomicReference<Throwable> submitTxAsync(final DOMDataTreeWriteTransaction writeTx) {
159         final AtomicReference<Throwable> caughtEx = new AtomicReference<>();
160         new Thread(() -> {
161             try {
162                 writeTx.commit();
163             } catch (final Throwable e) {
164                 caughtEx.set(e);
165             }
166         }).start();
167
168         return caughtEx;
169     }
170
171     @Test(expected = ReadFailedException.class)
172     @SuppressWarnings({"checkstyle:IllegalThrows", "checkstyle:AvoidHidingCauseException"})
173     public void basicTests() throws Throwable {
174         final DataContainerChild outerList = ImmutableNodes.newSystemMapBuilder()
175             .withNodeIdentifier(new NodeIdentifier(TestModel.OUTER_LIST_QNAME))
176             .withChild(TestUtils.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1))
177             .build();
178         final ContainerNode testContainer = ImmutableNodes.newContainerBuilder()
179                 .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
180                 .withChild(outerList)
181                 .build();
182
183         DOMDataTreeWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
184         final DOMDataTreeReadTransaction readRx = domBroker.newReadOnlyTransaction();
185         assertNotNull(writeTx);
186         assertNotNull(readRx);
187         assertNotNull(((SerializedDOMDataBroker) domBroker).getCommitStatsTracker());
188
189         writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.newContainerBuilder()
190             .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
191             .build());
192         writeTx.commit().get();
193         assertFalse(writeTx.cancel());
194
195         assertFalse(domBroker.newReadOnlyTransaction().exists(CONFIGURATION, TestModel.TEST_PATH).get());
196         assertTrue(domBroker.newReadOnlyTransaction().exists(OPERATIONAL, TestModel.TEST_PATH).get());
197         assertFalse(domBroker.newReadOnlyTransaction().exists(OPERATIONAL, TestModel.TEST2_PATH).get());
198
199         writeTx = domBroker.newWriteOnlyTransaction();
200         writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.newContainerBuilder()
201             .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
202             .build());
203         writeTx.delete(OPERATIONAL, TestModel.TEST_PATH);
204         writeTx.commit().get();
205         assertFalse(domBroker.newReadOnlyTransaction().exists(OPERATIONAL, TestModel.TEST_PATH).get());
206         assertTrue(domBroker.newWriteOnlyTransaction().cancel());
207
208         writeTx = domBroker.newWriteOnlyTransaction();
209         writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.newContainerBuilder()
210             .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
211             .build());
212         writeTx.merge(OPERATIONAL, TestModel.TEST_PATH, testContainer);
213         writeTx.commit().get();
214         assertTrue(domBroker.newReadOnlyTransaction().exists(OPERATIONAL, TestModel.TEST_PATH).get());
215         assertTrue(domBroker.newReadOnlyTransaction().read(OPERATIONAL, TestModel.TEST_PATH).get()
216                  .orElseThrow().toString().contains(testContainer.toString()));
217
218         readRx.read(OPERATIONAL, TestModel.TEST_PATH).get(); // init backing tx before close
219         readRx.close();
220
221         //Expected exception after close call
222
223         try {
224             readRx.read(OPERATIONAL, TestModel.TEST_PATH).get();
225         } catch (ExecutionException e) {
226             throw e.getCause();
227         }
228     }
229
230     @SuppressWarnings({"checkstyle:IllegalThrows", "checkstyle:IllegalCatch"})
231     @Test
232     public void closeTest() throws Exception {
233         final String testException = "TestException";
234
235         domBroker.setCloseable(() -> {
236             throw new Exception(testException);
237         });
238
239         try {
240             domBroker.close();
241         } catch (final Exception e) {
242             assertTrue(e.getMessage().contains(testException));
243         }
244     }
245
246     static class CommitExecutorService extends ForwardingExecutorService {
247
248         ExecutorService delegate;
249
250         CommitExecutorService(final ExecutorService delegate) {
251             this.delegate = delegate;
252         }
253
254         @Override
255         protected ExecutorService delegate() {
256             return delegate;
257         }
258     }
259 }