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.base.Optional;
18 import com.google.common.collect.ImmutableMap;
19 import com.google.common.util.concurrent.ForwardingExecutorService;
20 import com.google.common.util.concurrent.ListenableFuture;
21 import com.google.common.util.concurrent.ListeningExecutorService;
22 import com.google.common.util.concurrent.MoreExecutors;
23 import java.util.Collections;
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;
52 public class DOMBrokerTest {
54 private SchemaContext schemaContext;
55 private AbstractDOMDataBroker domBroker;
56 private ListeningExecutorService executor;
57 private ExecutorService futureExecutor;
58 private CommitExecutorService commitExecutor;
61 public void setupStore() throws Exception {
62 final InMemoryDOMDataStore operStore = new InMemoryDOMDataStore("OPER",
63 MoreExecutors.newDirectExecutorService());
64 final InMemoryDOMDataStore configStore = new InMemoryDOMDataStore("CFG",
65 MoreExecutors.newDirectExecutorService());
66 schemaContext = TestModel.createTestContext();
68 operStore.onGlobalContextUpdated(schemaContext);
69 configStore.onGlobalContextUpdated(schemaContext);
71 final ImmutableMap<LogicalDatastoreType, DOMStore> stores =
72 ImmutableMap.<LogicalDatastoreType, DOMStore>builder()
73 .put(CONFIGURATION, configStore)
74 .put(OPERATIONAL, operStore)
77 commitExecutor = new CommitExecutorService(Executors.newSingleThreadExecutor());
78 futureExecutor = SpecialExecutors.newBlockingBoundedCachedThreadPool(1, 5, "FCB");
79 executor = new DeadlockDetectingListeningExecutorService(commitExecutor,
80 TransactionCommitDeadlockException.DEADLOCK_EXCEPTION_SUPPLIER, futureExecutor);
81 domBroker = new SerializedDOMDataBroker(stores, executor);
85 public void tearDown() {
86 if (executor != null ) {
87 executor.shutdownNow();
90 if (futureExecutor != null) {
91 futureExecutor.shutdownNow();
95 @Test(timeout = 10000)
96 public void testTransactionIsolation() throws InterruptedException, ExecutionException {
97 assertNotNull(domBroker);
99 final DOMDataTreeReadTransaction readTx = domBroker.newReadOnlyTransaction();
100 assertNotNull(readTx);
102 final DOMDataTreeWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
103 assertNotNull(writeTx);
106 * Writes /test in writeTx.
109 writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
112 * Reads /test from readTx Read should return Absent.
115 final ListenableFuture<Optional<NormalizedNode<?, ?>>> readTxContainer = readTx
116 .read(OPERATIONAL, TestModel.TEST_PATH);
117 assertFalse(readTxContainer.get().isPresent());
120 @Test(timeout = 10000)
121 public void testTransactionCommit() throws InterruptedException, ExecutionException {
122 final DOMDataTreeWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
123 assertNotNull(writeTx);
125 * Writes /test in writeTx
128 writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
130 writeTx.submit().get();
132 final Optional<NormalizedNode<?, ?>> afterCommitRead = domBroker.newReadOnlyTransaction()
133 .read(OPERATIONAL, TestModel.TEST_PATH).get();
134 assertTrue(afterCommitRead.isPresent());
137 @Test(expected = TransactionCommitFailedException.class)
138 public void testRejectedCommit() throws Exception {
139 commitExecutor.delegate = Mockito.mock( ExecutorService.class );
140 Mockito.doThrow( new RejectedExecutionException( "mock" ) )
141 .when( commitExecutor.delegate ).execute( Mockito.any( Runnable.class ) );
142 Mockito.doNothing().when( commitExecutor.delegate ).shutdown();
143 Mockito.doReturn( Collections.emptyList() ).when( commitExecutor.delegate ).shutdownNow();
144 Mockito.doReturn( "" ).when( commitExecutor.delegate ).toString();
145 Mockito.doReturn( true ).when( commitExecutor.delegate )
146 .awaitTermination( Mockito.anyLong(), Mockito.any( TimeUnit.class ) );
148 final DOMDataTreeWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
149 writeTx.put( OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME) );
151 writeTx.submit().checkedGet( 5, TimeUnit.SECONDS );
154 @SuppressWarnings("checkstyle:IllegalCatch")
155 AtomicReference<Throwable> submitTxAsync( final DOMDataTreeWriteTransaction writeTx ) {
156 final AtomicReference<Throwable> caughtEx = new AtomicReference<>();
163 } catch ( final Throwable e ) {
173 @Test(expected = ReadFailedException.class)
174 public void basicTests() throws Exception {
175 final DataContainerChild<?, ?> outerList = ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
176 .withChild(ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1))
178 final NormalizedNode<?, ?> testContainer = Builders.containerBuilder()
179 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TestModel.TEST_QNAME))
180 .withChild(outerList)
183 DOMDataTreeWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
184 final DOMDataTreeReadTransaction readRx = domBroker.newReadOnlyTransaction();
185 assertNotNull(writeTx);
186 assertNotNull(readRx);
188 writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
189 writeTx.submit().get();
190 assertFalse(writeTx.cancel());
192 assertEquals(false, domBroker.newReadOnlyTransaction().exists(CONFIGURATION, TestModel.TEST_PATH).get());
193 assertEquals(true, domBroker.newReadOnlyTransaction().exists(OPERATIONAL, TestModel.TEST_PATH).get());
194 assertEquals(false, domBroker.newReadOnlyTransaction().exists(OPERATIONAL, TestModel.TEST2_PATH).get());
196 writeTx = domBroker.newWriteOnlyTransaction();
197 writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
198 writeTx.delete(OPERATIONAL, TestModel.TEST_PATH);
199 writeTx.submit().get();
200 assertEquals(false, domBroker.newReadOnlyTransaction().exists(OPERATIONAL, TestModel.TEST_PATH).get());
201 assertTrue(domBroker.newWriteOnlyTransaction().cancel());
203 writeTx = domBroker.newWriteOnlyTransaction();
204 writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
205 writeTx.merge(OPERATIONAL, TestModel.TEST_PATH, testContainer);
206 writeTx.submit().get();
207 assertEquals(true, domBroker.newReadOnlyTransaction().exists(OPERATIONAL, TestModel.TEST_PATH).get());
208 assertEquals(true, domBroker.newReadOnlyTransaction().read(OPERATIONAL, TestModel.TEST_PATH).get()
209 .get().toString().contains(testContainer.toString()));
212 //Expected exception after close call
213 readRx.read(OPERATIONAL, TestModel.TEST_PATH).checkedGet();
216 @SuppressWarnings({"checkstyle:IllegalThrows", "checkstyle:IllegalCatch"})
218 public void closeTest() throws Exception {
219 final String testException = "TestException";
221 domBroker.setCloseable(() -> {
222 throw new Exception(testException);
227 } catch (final Exception e) {
228 assertTrue(e.getMessage().contains(testException));
232 static class CommitExecutorService extends ForwardingExecutorService {
234 ExecutorService delegate;
236 CommitExecutorService( final ExecutorService delegate ) {
237 this.delegate = delegate;
241 protected ExecutorService delegate() {