Bug -3221 : Adding a new DataStoreUnavailableException for external applications.
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / test / java / org / opendaylight / controller / cluster / datastore / ConcurrentDOMDataBrokerTest.java
1 /*
2  * Copyright (c) 2014 Brocade Communications 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.controller.cluster.datastore;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertNotNull;
12 import static org.junit.Assert.assertSame;
13 import static org.junit.Assert.assertTrue;
14 import static org.junit.Assert.fail;
15 import static org.mockito.Mockito.doAnswer;
16 import static org.mockito.Mockito.doReturn;
17 import static org.mockito.Mockito.inOrder;
18 import static org.mockito.Mockito.mock;
19 import static org.mockito.Mockito.never;
20 import static org.mockito.Mockito.times;
21 import static org.mockito.Mockito.verify;
22 import com.google.common.collect.ImmutableMap;
23 import com.google.common.util.concurrent.CheckedFuture;
24 import com.google.common.util.concurrent.FutureCallback;
25 import com.google.common.util.concurrent.Futures;
26 import com.google.common.util.concurrent.ListenableFuture;
27 import com.google.common.util.concurrent.MoreExecutors;
28 import com.google.common.util.concurrent.SettableFuture;
29 import com.google.common.util.concurrent.Uninterruptibles;
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.Collection;
33 import java.util.List;
34 import java.util.concurrent.CountDownLatch;
35 import java.util.concurrent.ExecutionException;
36 import java.util.concurrent.SynchronousQueue;
37 import java.util.concurrent.ThreadPoolExecutor;
38 import java.util.concurrent.TimeUnit;
39 import java.util.concurrent.TimeoutException;
40 import java.util.concurrent.atomic.AtomicReference;
41 import org.junit.After;
42 import org.junit.Before;
43 import org.junit.Test;
44 import org.mockito.InOrder;
45 import org.mockito.invocation.InvocationOnMock;
46 import org.mockito.stubbing.Answer;
47 import org.opendaylight.controller.cluster.datastore.exceptions.NoShardLeaderException;
48 import org.opendaylight.controller.md.sal.common.api.data.DataStoreUnavailableException;
49 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
50 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
51 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
52 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
53 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
54 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
55 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
56 import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore;
57 import org.opendaylight.controller.sal.core.spi.data.DOMStore;
58 import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction;
59 import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
60 import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
61 import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain;
62 import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction;
63 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
64 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
65
66 /**
67  * Unit tests for DOMConcurrentDataCommitCoordinator.
68  *
69  * @author Thomas Pantelis
70  */
71 public class ConcurrentDOMDataBrokerTest {
72
73     private final DOMDataWriteTransaction transaction = mock(DOMDataWriteTransaction.class);
74     private final DOMStoreThreePhaseCommitCohort mockCohort1 = mock(DOMStoreThreePhaseCommitCohort.class);
75     private final DOMStoreThreePhaseCommitCohort mockCohort2 = mock(DOMStoreThreePhaseCommitCohort.class);
76     private final ThreadPoolExecutor futureExecutor =
77             new ThreadPoolExecutor(0, 1, 5, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
78     private ConcurrentDOMDataBroker coordinator;
79
80     @Before
81     public void setup() {
82         doReturn("tx").when(transaction).getIdentifier();
83
84         DOMStore store = new InMemoryDOMDataStore("OPER",
85             MoreExecutors.sameThreadExecutor());
86
87         coordinator = new ConcurrentDOMDataBroker(ImmutableMap.of(LogicalDatastoreType.OPERATIONAL, store), futureExecutor);
88     }
89
90     @After
91     public void tearDown() {
92         futureExecutor.shutdownNow();
93     }
94
95     @Test
96     public void testSuccessfulSubmitAsync() throws Throwable {
97         testSuccessfulSubmit(true);
98     }
99
100     @Test
101     public void testSuccessfulSubmitSync() throws Throwable {
102         testSuccessfulSubmit(false);
103     }
104
105     private void testSuccessfulSubmit(final boolean doAsync) throws Throwable {
106         final CountDownLatch asyncCanCommitContinue = new CountDownLatch(1);
107         Answer<ListenableFuture<Boolean>> asyncCanCommit = new Answer<ListenableFuture<Boolean>>() {
108             @Override
109             public ListenableFuture<Boolean> answer(final InvocationOnMock invocation) {
110                 final SettableFuture<Boolean> future = SettableFuture.create();
111                 if(doAsync) {
112                     new Thread() {
113                         @Override
114                         public void run() {
115                             Uninterruptibles.awaitUninterruptibly(asyncCanCommitContinue,
116                                     10, TimeUnit.SECONDS);
117                             future.set(true);
118                         }
119                     }.start();
120                 } else {
121                     future.set(true);
122                 }
123
124                 return future;
125             }
126         };
127
128         doAnswer(asyncCanCommit).when(mockCohort1).canCommit();
129         doReturn(Futures.immediateFuture(null)).when(mockCohort1).preCommit();
130         doReturn(Futures.immediateFuture(null)).when(mockCohort1).commit();
131
132         doReturn(Futures.immediateFuture(true)).when(mockCohort2).canCommit();
133         doReturn(Futures.immediateFuture(null)).when(mockCohort2).preCommit();
134         doReturn(Futures.immediateFuture(null)).when(mockCohort2).commit();
135
136         CheckedFuture<Void, TransactionCommitFailedException> future = coordinator.submit(
137                 transaction, Arrays.asList(mockCohort1, mockCohort2));
138
139         final CountDownLatch doneLatch = new CountDownLatch(1);
140         final AtomicReference<Throwable> caughtEx = new AtomicReference<>();
141         Futures.addCallback(future, new FutureCallback<Void>() {
142             @Override
143             public void onSuccess(final Void result) {
144                 doneLatch.countDown();
145             }
146
147             @Override
148             public void onFailure(final Throwable t) {
149                 caughtEx.set(t);
150                 doneLatch.countDown();
151             }
152         });
153
154         asyncCanCommitContinue.countDown();
155
156         assertEquals("Submit complete", true, doneLatch.await(5, TimeUnit.SECONDS));
157
158         if(caughtEx.get() != null) {
159             throw caughtEx.get();
160         }
161
162         assertEquals("Task count", doAsync ? 1 : 0, futureExecutor.getTaskCount());
163
164         InOrder inOrder = inOrder(mockCohort1, mockCohort2);
165         inOrder.verify(mockCohort1).canCommit();
166         inOrder.verify(mockCohort2).canCommit();
167         inOrder.verify(mockCohort1).preCommit();
168         inOrder.verify(mockCohort2).preCommit();
169         inOrder.verify(mockCohort1).commit();
170         inOrder.verify(mockCohort2).commit();
171     }
172
173     @Test
174     public void testSubmitWithNegativeCanCommitResponse() throws Exception {
175         doReturn(Futures.immediateFuture(true)).when(mockCohort1).canCommit();
176         doReturn(Futures.immediateFuture(null)).when(mockCohort1).abort();
177
178         doReturn(Futures.immediateFuture(false)).when(mockCohort2).canCommit();
179         doReturn(Futures.immediateFuture(null)).when(mockCohort2).abort();
180
181         DOMStoreThreePhaseCommitCohort mockCohort3 = mock(DOMStoreThreePhaseCommitCohort.class);
182         doReturn(Futures.immediateFuture(false)).when(mockCohort3).canCommit();
183         doReturn(Futures.immediateFuture(null)).when(mockCohort3).abort();
184
185         CheckedFuture<Void, TransactionCommitFailedException> future = coordinator.submit(
186                 transaction, Arrays.asList(mockCohort1, mockCohort2, mockCohort3));
187
188         assertFailure(future, null, mockCohort1, mockCohort2, mockCohort3);
189     }
190
191     private void assertFailure(final CheckedFuture<Void, TransactionCommitFailedException> future,
192             final Exception expCause, final DOMStoreThreePhaseCommitCohort... mockCohorts)
193                     throws Exception {
194         try {
195             future.checkedGet(5, TimeUnit.SECONDS);
196             fail("Expected TransactionCommitFailedException");
197         } catch (TransactionCommitFailedException e) {
198             if(expCause != null) {
199                 assertSame("Expected cause", expCause.getClass(), e.getCause().getClass());
200             }
201
202             InOrder inOrder = inOrder((Object[])mockCohorts);
203             for(DOMStoreThreePhaseCommitCohort c: mockCohorts) {
204                 inOrder.verify(c).abort();
205             }
206         } catch (TimeoutException e) {
207             throw e;
208         }
209     }
210
211     @Test
212     public void testSubmitWithCanCommitException() throws Exception {
213         doReturn(Futures.immediateFuture(true)).when(mockCohort1).canCommit();
214         doReturn(Futures.immediateFuture(null)).when(mockCohort1).abort();
215
216         IllegalStateException cause = new IllegalStateException("mock");
217         doReturn(Futures.immediateFailedFuture(cause)).when(mockCohort2).canCommit();
218         doReturn(Futures.immediateFuture(null)).when(mockCohort2).abort();
219
220         CheckedFuture<Void, TransactionCommitFailedException> future = coordinator.submit(
221                 transaction, Arrays.asList(mockCohort1, mockCohort2));
222
223         assertFailure(future, cause, mockCohort1, mockCohort2);
224     }
225
226     @Test
227     public void testSubmitWithCanCommitDataStoreUnavailableException() throws Exception {
228         doReturn(Futures.immediateFuture(true)).when(mockCohort1).canCommit();
229         doReturn(Futures.immediateFuture(null)).when(mockCohort1).abort();
230         NoShardLeaderException rootCause = new NoShardLeaderException("mock");
231         DataStoreUnavailableException cause = new DataStoreUnavailableException(rootCause.getMessage(), rootCause);
232         doReturn(Futures.immediateFailedFuture(rootCause)).when(mockCohort2).canCommit();
233         doReturn(Futures.immediateFuture(null)).when(mockCohort2).abort();
234
235         CheckedFuture<Void, TransactionCommitFailedException> future = coordinator.submit(
236             transaction, Arrays.asList(mockCohort1, mockCohort2));
237
238         assertFailure(future, cause, mockCohort1, mockCohort2);
239     }
240
241     @Test
242     public void testSubmitWithPreCommitException() throws Exception {
243         doReturn(Futures.immediateFuture(true)).when(mockCohort1).canCommit();
244         doReturn(Futures.immediateFuture(null)).when(mockCohort1).preCommit();
245         doReturn(Futures.immediateFuture(null)).when(mockCohort1).abort();
246
247         doReturn(Futures.immediateFuture(true)).when(mockCohort2).canCommit();
248         IllegalStateException cause = new IllegalStateException("mock");
249         doReturn(Futures.immediateFailedFuture(cause)).when(mockCohort2).preCommit();
250         doReturn(Futures.immediateFuture(null)).when(mockCohort2).abort();
251
252         DOMStoreThreePhaseCommitCohort mockCohort3 = mock(DOMStoreThreePhaseCommitCohort.class);
253         doReturn(Futures.immediateFuture(true)).when(mockCohort3).canCommit();
254         doReturn(Futures.immediateFailedFuture(new IllegalStateException("mock2"))).
255                 when(mockCohort3).preCommit();
256         doReturn(Futures.immediateFuture(null)).when(mockCohort3).abort();
257
258         CheckedFuture<Void, TransactionCommitFailedException> future = coordinator.submit(
259                 transaction, Arrays.asList(mockCohort1, mockCohort2, mockCohort3));
260
261         assertFailure(future, cause, mockCohort1, mockCohort2, mockCohort3);
262     }
263
264     @Test
265     public void testSubmitWithCommitException() throws Exception {
266         doReturn(Futures.immediateFuture(true)).when(mockCohort1).canCommit();
267         doReturn(Futures.immediateFuture(null)).when(mockCohort1).preCommit();
268         doReturn(Futures.immediateFuture(null)).when(mockCohort1).commit();
269         doReturn(Futures.immediateFuture(null)).when(mockCohort1).abort();
270
271         doReturn(Futures.immediateFuture(true)).when(mockCohort2).canCommit();
272         doReturn(Futures.immediateFuture(null)).when(mockCohort2).preCommit();
273         IllegalStateException cause = new IllegalStateException("mock");
274         doReturn(Futures.immediateFailedFuture(cause)).when(mockCohort2).commit();
275         doReturn(Futures.immediateFuture(null)).when(mockCohort2).abort();
276
277         DOMStoreThreePhaseCommitCohort mockCohort3 = mock(DOMStoreThreePhaseCommitCohort.class);
278         doReturn(Futures.immediateFuture(true)).when(mockCohort3).canCommit();
279         doReturn(Futures.immediateFuture(null)).when(mockCohort3).preCommit();
280         doReturn(Futures.immediateFailedFuture(new IllegalStateException("mock2"))).
281                 when(mockCohort3).commit();
282         doReturn(Futures.immediateFuture(null)).when(mockCohort3).abort();
283
284         CheckedFuture<Void, TransactionCommitFailedException> future = coordinator.submit(
285                 transaction, Arrays.asList(mockCohort1, mockCohort2, mockCohort3));
286
287         assertFailure(future, cause, mockCohort1, mockCohort2, mockCohort3);
288     }
289
290     @Test
291     public void testSubmitWithAbortException() throws Exception {
292         doReturn(Futures.immediateFuture(true)).when(mockCohort1).canCommit();
293         doReturn(Futures.immediateFailedFuture(new IllegalStateException("mock abort error"))).
294                 when(mockCohort1).abort();
295
296         IllegalStateException cause = new IllegalStateException("mock canCommit error");
297         doReturn(Futures.immediateFailedFuture(cause)).when(mockCohort2).canCommit();
298         doReturn(Futures.immediateFuture(null)).when(mockCohort2).abort();
299
300         CheckedFuture<Void, TransactionCommitFailedException> future = coordinator.submit(
301                 transaction, Arrays.asList(mockCohort1, mockCohort2));
302
303         assertFailure(future, cause, mockCohort1, mockCohort2);
304     }
305
306     @Test
307     public void testCreateReadWriteTransaction(){
308         DOMStore domStore = mock(DOMStore.class);
309         ConcurrentDOMDataBroker dataBroker = new ConcurrentDOMDataBroker(ImmutableMap.of(LogicalDatastoreType.OPERATIONAL,
310                 domStore, LogicalDatastoreType.CONFIGURATION, domStore), futureExecutor);
311         dataBroker.newReadWriteTransaction();
312
313         verify(domStore, never()).newReadWriteTransaction();
314     }
315
316
317     @Test
318     public void testCreateWriteOnlyTransaction(){
319         DOMStore domStore = mock(DOMStore.class);
320         ConcurrentDOMDataBroker dataBroker = new ConcurrentDOMDataBroker(ImmutableMap.of(LogicalDatastoreType.OPERATIONAL,
321                 domStore, LogicalDatastoreType.CONFIGURATION, domStore), futureExecutor);
322         dataBroker.newWriteOnlyTransaction();
323
324         verify(domStore, never()).newWriteOnlyTransaction();
325     }
326
327     @Test
328     public void testCreateReadOnlyTransaction(){
329         DOMStore domStore = mock(DOMStore.class);
330         ConcurrentDOMDataBroker dataBroker = new ConcurrentDOMDataBroker(ImmutableMap.of(LogicalDatastoreType.OPERATIONAL,
331                 domStore, LogicalDatastoreType.CONFIGURATION, domStore), futureExecutor);
332         dataBroker.newReadOnlyTransaction();
333
334         verify(domStore, never()).newReadOnlyTransaction();
335     }
336
337     @Test
338     public void testLazySubTransactionCreationForReadWriteTransactions(){
339         DOMStore configDomStore = mock(DOMStore.class);
340         DOMStore operationalDomStore = mock(DOMStore.class);
341         DOMStoreReadWriteTransaction storeTxn = mock(DOMStoreReadWriteTransaction.class);
342
343         doReturn(storeTxn).when(operationalDomStore).newReadWriteTransaction();
344         doReturn(storeTxn).when(configDomStore).newReadWriteTransaction();
345
346         ConcurrentDOMDataBroker dataBroker = new ConcurrentDOMDataBroker(ImmutableMap.of(LogicalDatastoreType.OPERATIONAL,
347                 operationalDomStore, LogicalDatastoreType.CONFIGURATION, configDomStore), futureExecutor);
348         DOMDataReadWriteTransaction dataTxn = dataBroker.newReadWriteTransaction();
349
350         dataTxn.put(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().build(), mock(NormalizedNode.class));
351         dataTxn.put(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().build(), mock(NormalizedNode.class));
352         dataTxn.read(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().build());
353
354         verify(configDomStore, never()).newReadWriteTransaction();
355         verify(operationalDomStore, times(1)).newReadWriteTransaction();
356
357         dataTxn.put(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.builder().build(), mock(NormalizedNode.class));
358
359         verify(configDomStore, times(1)).newReadWriteTransaction();
360         verify(operationalDomStore, times(1)).newReadWriteTransaction();
361
362     }
363
364     @Test
365     public void testLazySubTransactionCreationForWriteOnlyTransactions(){
366         DOMStore configDomStore = mock(DOMStore.class);
367         DOMStore operationalDomStore = mock(DOMStore.class);
368         DOMStoreWriteTransaction storeTxn = mock(DOMStoreWriteTransaction.class);
369
370         doReturn(storeTxn).when(operationalDomStore).newWriteOnlyTransaction();
371         doReturn(storeTxn).when(configDomStore).newWriteOnlyTransaction();
372
373         ConcurrentDOMDataBroker dataBroker = new ConcurrentDOMDataBroker(ImmutableMap.of(LogicalDatastoreType.OPERATIONAL,
374                 operationalDomStore, LogicalDatastoreType.CONFIGURATION, configDomStore), futureExecutor);
375         DOMDataWriteTransaction dataTxn = dataBroker.newWriteOnlyTransaction();
376
377         dataTxn.put(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().build(), mock(NormalizedNode.class));
378         dataTxn.put(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().build(), mock(NormalizedNode.class));
379
380         verify(configDomStore, never()).newWriteOnlyTransaction();
381         verify(operationalDomStore, times(1)).newWriteOnlyTransaction();
382
383         dataTxn.put(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.builder().build(), mock(NormalizedNode.class));
384
385         verify(configDomStore, times(1)).newWriteOnlyTransaction();
386         verify(operationalDomStore, times(1)).newWriteOnlyTransaction();
387
388     }
389
390
391     @Test
392     public void testLazySubTransactionCreationForReadOnlyTransactions(){
393         DOMStore configDomStore = mock(DOMStore.class);
394         DOMStore operationalDomStore = mock(DOMStore.class);
395         DOMStoreReadTransaction storeTxn = mock(DOMStoreReadTransaction.class);
396
397         doReturn(storeTxn).when(operationalDomStore).newReadOnlyTransaction();
398         doReturn(storeTxn).when(configDomStore).newReadOnlyTransaction();
399
400         ConcurrentDOMDataBroker dataBroker = new ConcurrentDOMDataBroker(ImmutableMap.of(LogicalDatastoreType.OPERATIONAL,
401                 operationalDomStore, LogicalDatastoreType.CONFIGURATION, configDomStore), futureExecutor);
402         DOMDataReadOnlyTransaction dataTxn = dataBroker.newReadOnlyTransaction();
403
404         dataTxn.read(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().build());
405         dataTxn.read(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().build());
406
407         verify(configDomStore, never()).newReadOnlyTransaction();
408         verify(operationalDomStore, times(1)).newReadOnlyTransaction();
409
410         dataTxn.read(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.builder().build());
411
412         verify(configDomStore, times(1)).newReadOnlyTransaction();
413         verify(operationalDomStore, times(1)).newReadOnlyTransaction();
414
415     }
416
417     @Test
418     public void testSubmitWithOnlyOneSubTransaction() throws InterruptedException {
419         DOMStore configDomStore = mock(DOMStore.class);
420         DOMStore operationalDomStore = mock(DOMStore.class);
421         DOMStoreReadWriteTransaction mockStoreReadWriteTransaction = mock(DOMStoreReadWriteTransaction.class);
422         DOMStoreThreePhaseCommitCohort mockCohort = mock(DOMStoreThreePhaseCommitCohort.class);
423
424         doReturn(mockStoreReadWriteTransaction).when(operationalDomStore).newReadWriteTransaction();
425         doReturn(mockCohort).when(mockStoreReadWriteTransaction).ready();
426         doReturn(Futures.immediateFuture(false)).when(mockCohort).canCommit();
427         doReturn(Futures.immediateFuture(null)).when(mockCohort).abort();
428
429         final CountDownLatch latch = new CountDownLatch(1);
430         final List<DOMStoreThreePhaseCommitCohort> commitCohorts = new ArrayList();
431
432         ConcurrentDOMDataBroker dataBroker = new ConcurrentDOMDataBroker(ImmutableMap.of(LogicalDatastoreType.OPERATIONAL,
433                 operationalDomStore, LogicalDatastoreType.CONFIGURATION, configDomStore), futureExecutor) {
434             @Override
435             public CheckedFuture<Void, TransactionCommitFailedException> submit(DOMDataWriteTransaction transaction, Collection<DOMStoreThreePhaseCommitCohort> cohorts) {
436                 commitCohorts.addAll(cohorts);
437                 latch.countDown();
438                 return super.submit(transaction, cohorts);
439             }
440         };
441         DOMDataReadWriteTransaction domDataReadWriteTransaction = dataBroker.newReadWriteTransaction();
442
443         domDataReadWriteTransaction.delete(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().build());
444
445         domDataReadWriteTransaction.submit();
446
447         latch.await(10, TimeUnit.SECONDS);
448
449         assertTrue(commitCohorts.size() == 1);
450     }
451
452     @Test
453     public void testSubmitWithOnlyTwoSubTransactions() throws InterruptedException {
454         DOMStore configDomStore = mock(DOMStore.class);
455         DOMStore operationalDomStore = mock(DOMStore.class);
456         DOMStoreReadWriteTransaction operationalTransaction = mock(DOMStoreReadWriteTransaction.class);
457         DOMStoreReadWriteTransaction configTransaction = mock(DOMStoreReadWriteTransaction.class);
458         DOMStoreThreePhaseCommitCohort mockCohortOperational = mock(DOMStoreThreePhaseCommitCohort.class);
459         DOMStoreThreePhaseCommitCohort mockCohortConfig = mock(DOMStoreThreePhaseCommitCohort.class);
460
461         doReturn(operationalTransaction).when(operationalDomStore).newReadWriteTransaction();
462         doReturn(configTransaction).when(configDomStore).newReadWriteTransaction();
463
464         doReturn(mockCohortOperational).when(operationalTransaction).ready();
465         doReturn(Futures.immediateFuture(false)).when(mockCohortOperational).canCommit();
466         doReturn(Futures.immediateFuture(null)).when(mockCohortOperational).abort();
467
468         doReturn(mockCohortConfig).when(configTransaction).ready();
469         doReturn(Futures.immediateFuture(false)).when(mockCohortConfig).canCommit();
470         doReturn(Futures.immediateFuture(null)).when(mockCohortConfig).abort();
471
472
473         final CountDownLatch latch = new CountDownLatch(1);
474         final List<DOMStoreThreePhaseCommitCohort> commitCohorts = new ArrayList();
475
476         ConcurrentDOMDataBroker dataBroker = new ConcurrentDOMDataBroker(ImmutableMap.of(LogicalDatastoreType.OPERATIONAL,
477                 operationalDomStore, LogicalDatastoreType.CONFIGURATION, configDomStore), futureExecutor) {
478             @Override
479             public CheckedFuture<Void, TransactionCommitFailedException> submit(DOMDataWriteTransaction transaction, Collection<DOMStoreThreePhaseCommitCohort> cohorts) {
480                 commitCohorts.addAll(cohorts);
481                 latch.countDown();
482                 return super.submit(transaction, cohorts);
483             }
484         };
485         DOMDataReadWriteTransaction domDataReadWriteTransaction = dataBroker.newReadWriteTransaction();
486
487         domDataReadWriteTransaction.put(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().build(), mock(NormalizedNode.class));
488         domDataReadWriteTransaction.merge(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.builder().build(), mock(NormalizedNode.class));
489
490         domDataReadWriteTransaction.submit();
491
492         latch.await(10, TimeUnit.SECONDS);
493
494         assertTrue(commitCohorts.size() == 2);
495     }
496
497     @Test
498     public void testCreateTransactionChain(){
499         DOMStore domStore = mock(DOMStore.class);
500         ConcurrentDOMDataBroker dataBroker = new ConcurrentDOMDataBroker(ImmutableMap.of(LogicalDatastoreType.OPERATIONAL,
501                 domStore, LogicalDatastoreType.CONFIGURATION, domStore), futureExecutor);
502
503         dataBroker.createTransactionChain(mock(TransactionChainListener.class));
504
505         verify(domStore, times(2)).createTransactionChain();
506
507     }
508
509     @Test
510     public void testCreateTransactionOnChain(){
511         DOMStore domStore = mock(DOMStore.class);
512         ConcurrentDOMDataBroker dataBroker = new ConcurrentDOMDataBroker(ImmutableMap.of(LogicalDatastoreType.OPERATIONAL,
513                 domStore, LogicalDatastoreType.CONFIGURATION, domStore), futureExecutor);
514
515         DOMStoreReadWriteTransaction operationalTransaction = mock(DOMStoreReadWriteTransaction.class);
516         DOMStoreTransactionChain mockChain = mock(DOMStoreTransactionChain.class);
517
518         doReturn(mockChain).when(domStore).createTransactionChain();
519         doReturn(operationalTransaction).when(mockChain).newWriteOnlyTransaction();
520
521         DOMTransactionChain transactionChain = dataBroker.createTransactionChain(mock(TransactionChainListener.class));
522
523         DOMDataWriteTransaction domDataWriteTransaction = transactionChain.newWriteOnlyTransaction();
524
525         verify(mockChain, never()).newWriteOnlyTransaction();
526
527         domDataWriteTransaction.put(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().build(), mock(NormalizedNode.class));
528     }
529
530     @Test
531     public void testEmptyTransactionSubmitSucceeds() throws ExecutionException, InterruptedException {
532         DOMStore domStore = mock(DOMStore.class);
533         ConcurrentDOMDataBroker dataBroker = new ConcurrentDOMDataBroker(ImmutableMap.of(LogicalDatastoreType.OPERATIONAL,
534                 domStore, LogicalDatastoreType.CONFIGURATION, domStore), futureExecutor);
535
536         CheckedFuture<Void, TransactionCommitFailedException> submit1 = dataBroker.newWriteOnlyTransaction().submit();
537
538         assertNotNull(submit1);
539
540         submit1.get();
541
542         CheckedFuture<Void, TransactionCommitFailedException> submit2 = dataBroker.newReadWriteTransaction().submit();
543
544         assertNotNull(submit2);
545
546         submit2.get();
547     }
548
549 }