4a82645974e2d845f408ec88691c0d3fa5f7d83b
[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.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;
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() 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();
67
68         operStore.onGlobalContextUpdated(schemaContext);
69         configStore.onGlobalContextUpdated(schemaContext);
70
71         final ImmutableMap<LogicalDatastoreType, DOMStore> stores = ImmutableMap.<LogicalDatastoreType, DOMStore> builder()
72                 .put(CONFIGURATION, configStore)
73                 .put(OPERATIONAL, operStore)
74                 .build();
75
76         commitExecutor = new CommitExecutorService(Executors.newSingleThreadExecutor());
77         futureExecutor = SpecialExecutors.newBlockingBoundedCachedThreadPool(1, 5, "FCB");
78         executor = new DeadlockDetectingListeningExecutorService(commitExecutor,
79                 TransactionCommitDeadlockException.DEADLOCK_EXCEPTION_SUPPLIER, futureExecutor);
80         domBroker = new SerializedDOMDataBroker(stores, executor);
81     }
82
83     @After
84     public void tearDown() {
85         if( executor != null ) {
86             executor.shutdownNow();
87         }
88
89         if(futureExecutor != null) {
90             futureExecutor.shutdownNow();
91         }
92     }
93
94     @Test(timeout=10000)
95     public void testTransactionIsolation() throws InterruptedException, ExecutionException {
96         assertNotNull(domBroker);
97
98         final DOMDataTreeReadTransaction readTx = domBroker.newReadOnlyTransaction();
99         assertNotNull(readTx);
100
101         final DOMDataTreeWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
102         assertNotNull(writeTx);
103
104         /**
105          *
106          * Writes /test in writeTx
107          *
108          */
109         writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
110
111         /**
112          *
113          * Reads /test from readTx Read should return Absent.
114          *
115          */
116         final ListenableFuture<Optional<NormalizedNode<?, ?>>> readTxContainer = readTx
117                 .read(OPERATIONAL, TestModel.TEST_PATH);
118         assertFalse(readTxContainer.get().isPresent());
119     }
120
121     @Test(timeout=10000)
122     public void testTransactionCommit() throws InterruptedException, ExecutionException {
123         final DOMDataTreeWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
124         assertNotNull(writeTx);
125         /**
126          *
127          * Writes /test in writeTx
128          *
129          */
130         writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
131
132         writeTx.submit().get();
133
134         final Optional<NormalizedNode<?, ?>> afterCommitRead = domBroker.newReadOnlyTransaction()
135                 .read(OPERATIONAL, TestModel.TEST_PATH).get();
136         assertTrue(afterCommitRead.isPresent());
137     }
138
139     @Test(expected=TransactionCommitFailedException.class)
140     public void testRejectedCommit() throws Exception {
141         commitExecutor.delegate = Mockito.mock( ExecutorService.class );
142         Mockito.doThrow( new RejectedExecutionException( "mock" ) )
143             .when( commitExecutor.delegate ).execute( Mockito.any( Runnable.class ) );
144         Mockito.doNothing().when( commitExecutor.delegate ).shutdown();
145         Mockito.doReturn( Collections.emptyList() ).when( commitExecutor.delegate ).shutdownNow();
146         Mockito.doReturn( "" ).when( commitExecutor.delegate ).toString();
147         Mockito.doReturn( true ).when( commitExecutor.delegate )
148             .awaitTermination( Mockito.anyLong(), Mockito.any( TimeUnit.class ) );
149
150         final DOMDataTreeWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
151         writeTx.put( OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME) );
152
153         writeTx.submit().checkedGet( 5, TimeUnit.SECONDS );
154     }
155
156     AtomicReference<Throwable> submitTxAsync( final DOMDataTreeWriteTransaction writeTx ) {
157         final AtomicReference<Throwable> caughtEx = new AtomicReference<>();
158         new Thread() {
159             @Override
160             public void run() {
161
162                 try {
163                     writeTx.submit();
164                 } catch( final Throwable e ) {
165                     caughtEx.set( e );
166                 }
167             }
168
169         }.start();
170
171         return caughtEx;
172     }
173
174     @Test(expected = ReadFailedException.class)
175     public void basicTests() throws Exception {
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
189         writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
190         writeTx.submit().get();
191         assertFalse(writeTx.cancel());
192
193         assertEquals(false, domBroker.newReadOnlyTransaction().exists(CONFIGURATION, TestModel.TEST_PATH).get());
194         assertEquals(true, domBroker.newReadOnlyTransaction().exists(OPERATIONAL, TestModel.TEST_PATH).get());
195         assertEquals(false, domBroker.newReadOnlyTransaction().exists(OPERATIONAL, TestModel.TEST2_PATH).get());
196
197         writeTx = domBroker.newWriteOnlyTransaction();
198         writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
199         writeTx.delete(OPERATIONAL, TestModel.TEST_PATH);
200         writeTx.submit().get();
201         assertEquals(false, domBroker.newReadOnlyTransaction().exists(OPERATIONAL, TestModel.TEST_PATH).get());
202         assertTrue(domBroker.newWriteOnlyTransaction().cancel());
203
204         writeTx = domBroker.newWriteOnlyTransaction();
205         writeTx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
206         writeTx.merge(OPERATIONAL, TestModel.TEST_PATH, testContainer);
207         writeTx.submit().get();
208         assertEquals(true, domBroker.newReadOnlyTransaction().exists(OPERATIONAL, TestModel.TEST_PATH).get());
209         assertEquals(true, domBroker.newReadOnlyTransaction().read(OPERATIONAL, TestModel.TEST_PATH).get()
210                  .get().toString().contains(testContainer.toString()));
211
212         readRx.close();
213         //Expected exception after close call
214         readRx.read(OPERATIONAL, TestModel.TEST_PATH).checkedGet();
215     }
216
217     @Test
218     public void closeTest() throws Exception {
219         final String TEST_EXCEPTION = "TestException";
220
221         domBroker.setCloseable(() -> { throw new Exception(TEST_EXCEPTION); });
222         try{
223             domBroker.close();
224         }catch(final Exception e){
225             assertTrue(e.getMessage().contains(TEST_EXCEPTION));
226         }
227     }
228
229     static class CommitExecutorService extends ForwardingExecutorService {
230
231         ExecutorService delegate;
232
233         public CommitExecutorService( final ExecutorService delegate ) {
234             this.delegate = delegate;
235         }
236
237         @Override
238         protected ExecutorService delegate() {
239             return delegate;
240         }
241     }
242 }