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