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.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;
51 public class DOMBrokerTest extends AbstractDatastoreTest {
53 private AbstractDOMDataBroker domBroker;
54 private ListeningExecutorService executor;
55 private ExecutorService futureExecutor;
56 private CommitExecutorService commitExecutor;
59 public void setupStore() {
60 final InMemoryDOMDataStore operStore = new InMemoryDOMDataStore("OPER",
61 MoreExecutors.newDirectExecutorService());
62 final InMemoryDOMDataStore configStore = new InMemoryDOMDataStore("CFG",
63 MoreExecutors.newDirectExecutorService());
65 operStore.onGlobalContextUpdated(SCHEMA_CONTEXT);
66 configStore.onGlobalContextUpdated(SCHEMA_CONTEXT);
68 final ImmutableMap<LogicalDatastoreType, DOMStore> stores =
69 ImmutableMap.<LogicalDatastoreType, DOMStore>builder()
70 .put(CONFIGURATION, configStore)
71 .put(OPERATIONAL, operStore)
74 commitExecutor = new CommitExecutorService(Executors.newSingleThreadExecutor());
75 futureExecutor = SpecialExecutors.newBlockingBoundedCachedThreadPool(1, 5, "FCB", DOMBrokerTest.class);
76 executor = new DeadlockDetectingListeningExecutorService(commitExecutor,
77 TransactionCommitDeadlockException.DEADLOCK_EXCEPTION_SUPPLIER, futureExecutor);
78 domBroker = new SerializedDOMDataBroker(stores, executor);
82 public void tearDown() {
83 if (executor != null) {
84 executor.shutdownNow();
87 if (futureExecutor != null) {
88 futureExecutor.shutdownNow();
92 @Test(timeout = 10000)
93 public void testTransactionIsolation() throws InterruptedException, ExecutionException {
94 assertNotNull(domBroker);
96 final DOMDataTreeReadTransaction readTx = domBroker.newReadOnlyTransaction();
97 assertNotNull(readTx);
99 final DOMDataTreeWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
100 assertNotNull(writeTx);
103 * Writes /test in writeTx.
106 writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
109 * Reads /test from readTx Read should return Absent.
112 final ListenableFuture<Optional<NormalizedNode<?, ?>>> readTxContainer = readTx
113 .read(OPERATIONAL, TestModel.TEST_PATH);
114 assertFalse(readTxContainer.get().isPresent());
117 @Test(timeout = 10000)
118 public void testTransactionCommit() throws InterruptedException, ExecutionException {
119 final DOMDataTreeWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
120 assertNotNull(writeTx);
122 * Writes /test in writeTx
125 writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
127 writeTx.commit().get();
129 final Optional<NormalizedNode<?, ?>> afterCommitRead = domBroker.newReadOnlyTransaction()
130 .read(OPERATIONAL, TestModel.TEST_PATH).get();
131 assertTrue(afterCommitRead.isPresent());
134 @Test(expected = TransactionCommitFailedException.class)
135 @SuppressWarnings({"checkstyle:AvoidHidingCauseException", "checkstyle:IllegalThrows"})
136 public void testRejectedCommit() throws Throwable {
137 commitExecutor.delegate = Mockito.mock(ExecutorService.class);
138 Mockito.doThrow(new RejectedExecutionException("mock"))
139 .when(commitExecutor.delegate).execute(Mockito.any(Runnable.class));
140 Mockito.doNothing().when(commitExecutor.delegate).shutdown();
141 Mockito.doReturn(Collections.emptyList()).when(commitExecutor.delegate).shutdownNow();
142 Mockito.doReturn("").when(commitExecutor.delegate).toString();
143 Mockito.doReturn(Boolean.TRUE).when(commitExecutor.delegate)
144 .awaitTermination(Mockito.anyLong(), Mockito.any(TimeUnit.class));
146 final DOMDataTreeWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
147 writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
150 writeTx.commit().get(5, TimeUnit.SECONDS);
151 } catch (ExecutionException e) {
156 @SuppressWarnings("checkstyle:IllegalCatch")
157 AtomicReference<Throwable> submitTxAsync(final DOMDataTreeWriteTransaction writeTx) {
158 final AtomicReference<Throwable> caughtEx = new AtomicReference<>();
162 } catch (final Throwable e) {
170 @Test(expected = ReadFailedException.class)
171 @SuppressWarnings({"checkstyle:IllegalThrows", "checkstyle:AvoidHidingCauseException"})
172 public void basicTests() throws Throwable {
173 final DataContainerChild<?, ?> outerList = ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
174 .withChild(ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1))
176 final NormalizedNode<?, ?> testContainer = Builders.containerBuilder()
177 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TestModel.TEST_QNAME))
178 .withChild(outerList)
181 DOMDataTreeWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
182 final DOMDataTreeReadTransaction readRx = domBroker.newReadOnlyTransaction();
183 assertNotNull(writeTx);
184 assertNotNull(readRx);
185 assertNotNull(((SerializedDOMDataBroker) domBroker).getCommitStatsTracker());
187 writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
188 writeTx.commit().get();
189 assertFalse(writeTx.cancel());
191 assertEquals(false, domBroker.newReadOnlyTransaction().exists(CONFIGURATION, TestModel.TEST_PATH).get());
192 assertEquals(true, domBroker.newReadOnlyTransaction().exists(OPERATIONAL, TestModel.TEST_PATH).get());
193 assertEquals(false, domBroker.newReadOnlyTransaction().exists(OPERATIONAL, TestModel.TEST2_PATH).get());
195 writeTx = domBroker.newWriteOnlyTransaction();
196 writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
197 writeTx.delete(OPERATIONAL, TestModel.TEST_PATH);
198 writeTx.commit().get();
199 assertEquals(false, domBroker.newReadOnlyTransaction().exists(OPERATIONAL, TestModel.TEST_PATH).get());
200 assertTrue(domBroker.newWriteOnlyTransaction().cancel());
202 writeTx = domBroker.newWriteOnlyTransaction();
203 writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
204 writeTx.merge(OPERATIONAL, TestModel.TEST_PATH, testContainer);
205 writeTx.commit().get();
206 assertEquals(Boolean.TRUE, domBroker.newReadOnlyTransaction().exists(OPERATIONAL, TestModel.TEST_PATH).get());
207 assertEquals(Boolean.TRUE, domBroker.newReadOnlyTransaction().read(OPERATIONAL, TestModel.TEST_PATH).get()
208 .get().toString().contains(testContainer.toString()));
212 //Expected exception after close call
215 readRx.read(OPERATIONAL, TestModel.TEST_PATH).get();
216 } catch (ExecutionException e) {
221 @SuppressWarnings({"checkstyle:IllegalThrows", "checkstyle:IllegalCatch"})
223 public void closeTest() throws Exception {
224 final String testException = "TestException";
226 domBroker.setCloseable(() -> {
227 throw new Exception(testException);
232 } catch (final Exception e) {
233 assertTrue(e.getMessage().contains(testException));
237 static class CommitExecutorService extends ForwardingExecutorService {
239 ExecutorService delegate;
241 CommitExecutorService(final ExecutorService delegate) {
242 this.delegate = delegate;
246 protected ExecutorService delegate() {