2 * Copyright (c) 2014, 2015 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.mdsal.dom.broker;
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;
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;
48 public class DOMBrokerTest extends AbstractDatastoreTest {
50 private AbstractDOMDataBroker domBroker;
51 private ListeningExecutorService executor;
52 private ExecutorService futureExecutor;
53 private CommitExecutorService commitExecutor;
56 public void setupStore() {
57 final InMemoryDOMDataStore operStore = new InMemoryDOMDataStore("OPER",
58 MoreExecutors.newDirectExecutorService());
59 final InMemoryDOMDataStore configStore = new InMemoryDOMDataStore("CFG",
60 MoreExecutors.newDirectExecutorService());
62 operStore.onModelContextUpdated(SCHEMA_CONTEXT);
63 configStore.onModelContextUpdated(SCHEMA_CONTEXT);
65 final ImmutableMap<LogicalDatastoreType, DOMStore> stores =
66 ImmutableMap.<LogicalDatastoreType, DOMStore>builder()
67 .put(CONFIGURATION, configStore)
68 .put(OPERATIONAL, operStore)
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);
79 public void tearDown() {
80 if (executor != null) {
81 executor.shutdownNow();
84 if (futureExecutor != null) {
85 futureExecutor.shutdownNow();
89 @Test(timeout = 10000)
90 public void testTransactionIsolation() throws InterruptedException, ExecutionException {
91 assertNotNull(domBroker);
93 final DOMDataTreeReadTransaction readTx = domBroker.newReadOnlyTransaction();
94 assertNotNull(readTx);
96 final DOMDataTreeWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
97 assertNotNull(writeTx);
100 * Writes /test in writeTx.
103 writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.newContainerBuilder()
104 .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
108 * Reads /test from readTx Read should return Absent.
111 final var readTxContainer = readTx.read(OPERATIONAL, TestModel.TEST_PATH);
112 assertEquals(Optional.empty(), readTxContainer.get());
115 @Test(timeout = 10000)
116 public void testTransactionCommit() throws InterruptedException, ExecutionException {
117 final DOMDataTreeWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
118 assertNotNull(writeTx);
120 * Writes /test in writeTx
123 writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.newContainerBuilder()
124 .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
127 writeTx.commit().get();
129 final var afterCommitRead = domBroker.newReadOnlyTransaction().read(OPERATIONAL, TestModel.TEST_PATH).get();
130 assertTrue(afterCommitRead.isPresent());
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));
145 final DOMDataTreeWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
146 writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.newContainerBuilder()
147 .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
151 writeTx.commit().get(5, TimeUnit.SECONDS);
152 } catch (ExecutionException e) {
157 @SuppressWarnings("checkstyle:IllegalCatch")
158 AtomicReference<Throwable> submitTxAsync(final DOMDataTreeWriteTransaction writeTx) {
159 final AtomicReference<Throwable> caughtEx = new AtomicReference<>();
163 } catch (final Throwable e) {
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))
178 final ContainerNode testContainer = ImmutableNodes.newContainerBuilder()
179 .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
180 .withChild(outerList)
183 DOMDataTreeWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
184 final DOMDataTreeReadTransaction readRx = domBroker.newReadOnlyTransaction();
185 assertNotNull(writeTx);
186 assertNotNull(readRx);
187 assertNotNull(((SerializedDOMDataBroker) domBroker).getCommitStatsTracker());
189 writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.newContainerBuilder()
190 .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
192 writeTx.commit().get();
193 assertFalse(writeTx.cancel());
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());
199 writeTx = domBroker.newWriteOnlyTransaction();
200 writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.newContainerBuilder()
201 .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
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());
208 writeTx = domBroker.newWriteOnlyTransaction();
209 writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.newContainerBuilder()
210 .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME))
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()));
218 readRx.read(OPERATIONAL, TestModel.TEST_PATH).get(); // init backing tx before close
221 //Expected exception after close call
224 readRx.read(OPERATIONAL, TestModel.TEST_PATH).get();
225 } catch (ExecutionException e) {
230 @SuppressWarnings({"checkstyle:IllegalThrows", "checkstyle:IllegalCatch"})
232 public void closeTest() throws Exception {
233 final String testException = "TestException";
235 domBroker.setCloseable(() -> {
236 throw new Exception(testException);
241 } catch (final Exception e) {
242 assertTrue(e.getMessage().contains(testException));
246 static class CommitExecutorService extends ForwardingExecutorService {
248 ExecutorService delegate;
250 CommitExecutorService(final ExecutorService delegate) {
251 this.delegate = delegate;
255 protected ExecutorService delegate() {