Default AsyncWriteTransaction.submit()
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / test / java / org / opendaylight / controller / cluster / databroker / compat / LegacyDOMDataBrokerAdapterTest.java
1 /*
2  * Copyright (c) 2017 Inocybe Technologies 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.databroker.compat;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertNotNull;
12 import static org.junit.Assert.assertTrue;
13 import static org.junit.Assert.fail;
14 import static org.mockito.Matchers.any;
15 import static org.mockito.Matchers.anyObject;
16 import static org.mockito.Matchers.eq;
17 import static org.mockito.Mockito.doAnswer;
18 import static org.mockito.Mockito.doNothing;
19 import static org.mockito.Mockito.doReturn;
20 import static org.mockito.Mockito.inOrder;
21 import static org.mockito.Mockito.mock;
22 import static org.mockito.Mockito.verify;
23
24 import com.google.common.base.Optional;
25 import com.google.common.collect.ImmutableMap;
26 import com.google.common.util.concurrent.CheckedFuture;
27 import com.google.common.util.concurrent.Futures;
28 import com.google.common.util.concurrent.MoreExecutors;
29 import java.util.Arrays;
30 import java.util.Collection;
31 import java.util.concurrent.ExecutionException;
32 import java.util.concurrent.TimeUnit;
33 import java.util.concurrent.TimeoutException;
34 import org.junit.Before;
35 import org.junit.Test;
36 import org.mockito.ArgumentCaptor;
37 import org.mockito.InOrder;
38 import org.mockito.Mock;
39 import org.mockito.MockitoAnnotations;
40 import org.opendaylight.controller.cluster.databroker.ConcurrentDOMDataBroker;
41 import org.opendaylight.controller.cluster.datastore.DistributedDataStoreInterface;
42 import org.opendaylight.controller.cluster.datastore.exceptions.NoShardLeaderException;
43 import org.opendaylight.controller.md.cluster.datastore.model.TestModel;
44 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
45 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
46 import org.opendaylight.controller.md.sal.common.api.data.DataStoreUnavailableException;
47 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
48 import org.opendaylight.controller.md.sal.common.api.data.OptimisticLockFailedException;
49 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
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.ClusteredDOMDataTreeChangeListener;
53 import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
54 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
55 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
56 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeListener;
57 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
58 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeCommitCohortRegistry;
59 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeIdentifier;
60 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
61 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
62 import org.opendaylight.mdsal.dom.api.DOMDataTreeCommitCohort;
63 import org.opendaylight.mdsal.dom.api.DOMDataTreeCommitCohortRegistration;
64 import org.opendaylight.mdsal.dom.spi.store.DOMStoreReadTransaction;
65 import org.opendaylight.mdsal.dom.spi.store.DOMStoreReadWriteTransaction;
66 import org.opendaylight.mdsal.dom.spi.store.DOMStoreThreePhaseCommitCohort;
67 import org.opendaylight.mdsal.dom.spi.store.DOMStoreTransactionChain;
68 import org.opendaylight.mdsal.dom.spi.store.DOMStoreTreeChangePublisher;
69 import org.opendaylight.mdsal.dom.spi.store.DOMStoreWriteTransaction;
70 import org.opendaylight.yangtools.concepts.ListenerRegistration;
71 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
72 import org.opendaylight.yangtools.yang.data.api.schema.tree.ConflictingModificationAppliedException;
73 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
74 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
75 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
76
77 /**
78  * Unit tests for LegacyDOMDataBrokerAdapter.
79  *
80  * @author Thomas Pantelis
81  */
82 public class LegacyDOMDataBrokerAdapterTest {
83     @Mock
84     private TestDOMStore mockOperStore;
85
86     @Mock
87     private TestDOMStore mockConfigStore;
88
89     @Mock
90     private DOMStoreReadTransaction mockReadTx;
91
92     @Mock
93     private DOMStoreWriteTransaction mockWriteTx;
94
95     @Mock
96     private DOMStoreReadWriteTransaction mockReadWriteTx;
97
98     @Mock
99     private DOMStoreThreePhaseCommitCohort mockCommitCohort;
100
101     private LegacyDOMDataBrokerAdapter adapter;
102     private NormalizedNode<?,?> dataNode;
103
104     @Before
105     public void setup() {
106         MockitoAnnotations.initMocks(this);
107
108         ConcurrentDOMDataBroker backendBroker = new ConcurrentDOMDataBroker(ImmutableMap.of(
109                 org.opendaylight.mdsal.common.api.LogicalDatastoreType.OPERATIONAL, mockOperStore,
110                 org.opendaylight.mdsal.common.api.LogicalDatastoreType.CONFIGURATION, mockConfigStore),
111                 MoreExecutors.newDirectExecutorService());
112
113         adapter = new LegacyDOMDataBrokerAdapter(backendBroker);
114
115         doReturn(Futures.immediateFuture(Boolean.TRUE)).when(mockCommitCohort).canCommit();
116         doReturn(Futures.immediateFuture(null)).when(mockCommitCohort).preCommit();
117         doReturn(Futures.immediateFuture(null)).when(mockCommitCohort).commit();
118         doReturn(Futures.immediateFuture(null)).when(mockCommitCohort).abort();
119
120         dataNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
121
122         doReturn(mockWriteTx).when(mockConfigStore).newWriteOnlyTransaction();
123         doNothing().when(mockWriteTx).write(TestModel.TEST_PATH, dataNode);
124         doNothing().when(mockWriteTx).merge(TestModel.TEST_PATH, dataNode);
125         doNothing().when(mockWriteTx).delete(TestModel.TEST_PATH);
126         doNothing().when(mockWriteTx).close();
127         doReturn(mockCommitCohort).when(mockWriteTx).ready();
128
129         doReturn(mockReadTx).when(mockConfigStore).newReadOnlyTransaction();
130         doReturn(Futures.immediateCheckedFuture(Optional.of(dataNode))).when(mockReadTx).read(TestModel.TEST_PATH);
131         doReturn(Futures.immediateCheckedFuture(Boolean.TRUE)).when(mockReadTx).exists(TestModel.TEST_PATH);
132
133         doReturn(mockReadWriteTx).when(mockConfigStore).newReadWriteTransaction();
134         doNothing().when(mockReadWriteTx).write(TestModel.TEST_PATH, dataNode);
135         doReturn(mockCommitCohort).when(mockReadWriteTx).ready();
136         doReturn(Futures.immediateCheckedFuture(Optional.of(dataNode))).when(mockReadWriteTx).read(TestModel.TEST_PATH);
137
138         DOMStoreTransactionChain mockTxChain = mock(DOMStoreTransactionChain.class);
139         doReturn(mockReadTx).when(mockTxChain).newReadOnlyTransaction();
140         doReturn(mockWriteTx).when(mockTxChain).newWriteOnlyTransaction();
141         doReturn(mockReadWriteTx).when(mockTxChain).newReadWriteTransaction();
142         doReturn(mockTxChain).when(mockConfigStore).createTransactionChain();
143
144         doReturn(mock(DOMStoreTransactionChain.class)).when(mockOperStore).createTransactionChain();
145     }
146
147     @Test
148     public void testReadOnlyTransaction() throws Exception {
149         DOMDataReadOnlyTransaction tx = adapter.newReadOnlyTransaction();
150
151         // Test successful read
152
153         CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> readFuture =
154                 tx.read(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH);
155         Optional<NormalizedNode<?, ?>> readOptional = readFuture.get();
156         assertEquals("isPresent", true, readOptional.isPresent());
157         assertEquals("NormalizedNode", dataNode, readOptional.get());
158
159         // Test successful exists
160
161         CheckedFuture<Boolean, ReadFailedException> existsFuture =
162                 tx.exists(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH);
163         assertEquals("exists", Boolean.TRUE, existsFuture.get());
164
165         // Test failed read
166
167         String errorMsg = "mock read error";
168         Throwable cause = new RuntimeException();
169         doReturn(Futures.immediateFailedCheckedFuture(new org.opendaylight.mdsal.common.api.ReadFailedException(
170                 errorMsg, cause))).when(mockReadTx).read(TestModel.TEST_PATH);
171
172         try {
173             tx.read(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH).checkedGet();
174             fail("Expected ReadFailedException");
175         } catch (ReadFailedException e) {
176             assertEquals("getMessage", errorMsg, e.getMessage());
177             assertEquals("getCause", cause, e.getCause());
178         }
179
180         // Test close
181         tx.close();
182         verify(mockReadTx).close();
183     }
184
185     @Test
186     public void testWriteOnlyTransaction() throws Exception {
187         // Test successful write operations and submit
188
189         DOMDataWriteTransaction tx = adapter.newWriteOnlyTransaction();
190
191         tx.put(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, dataNode);
192         verify(mockWriteTx).write(TestModel.TEST_PATH, dataNode);
193
194         tx.merge(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, dataNode);
195         verify(mockWriteTx).merge(TestModel.TEST_PATH, dataNode);
196
197         tx.delete(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH);
198         verify(mockWriteTx).delete(TestModel.TEST_PATH);
199
200         tx.commit().get(5, TimeUnit.SECONDS);
201
202         InOrder inOrder = inOrder(mockCommitCohort);
203         inOrder.verify(mockCommitCohort).canCommit();
204         inOrder.verify(mockCommitCohort).preCommit();
205         inOrder.verify(mockCommitCohort).commit();
206
207         // Test cancel
208
209         tx = adapter.newWriteOnlyTransaction();
210         tx.put(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, dataNode);
211         tx.cancel();
212         verify(mockWriteTx).close();
213
214         // Test submit with OptimisticLockFailedException
215
216         String errorMsg = "mock OptimisticLockFailedException";
217         Throwable cause = new ConflictingModificationAppliedException(TestModel.TEST_PATH, "mock");
218         doReturn(Futures.immediateFailedFuture(new org.opendaylight.mdsal.common.api.OptimisticLockFailedException(
219                 errorMsg, cause))).when(mockCommitCohort).canCommit();
220
221         try {
222             tx = adapter.newWriteOnlyTransaction();
223             tx.put(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, dataNode);
224             commit(tx);
225             fail("Expected OptimisticLockFailedException");
226         } catch (OptimisticLockFailedException e) {
227             assertEquals("getMessage", errorMsg, e.getMessage());
228             assertEquals("getCause", cause, e.getCause());
229         }
230
231         // Test submit with TransactionCommitFailedException
232
233         errorMsg = "mock TransactionCommitFailedException";
234         cause = new DataValidationFailedException(TestModel.TEST_PATH, "mock");
235         doReturn(Futures.immediateFailedFuture(new org.opendaylight.mdsal.common.api.TransactionCommitFailedException(
236                 errorMsg, cause))).when(mockCommitCohort).canCommit();
237
238         try {
239             tx = adapter.newWriteOnlyTransaction();
240             tx.put(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, dataNode);
241             commit(tx);
242             fail("Expected TransactionCommitFailedException");
243         } catch (TransactionCommitFailedException e) {
244             assertEquals("getMessage", errorMsg, e.getMessage());
245             assertEquals("getCause", cause, e.getCause());
246         }
247
248         // Test submit with DataStoreUnavailableException
249
250         errorMsg = "mock NoShardLeaderException";
251         cause = new NoShardLeaderException("mock");
252         doReturn(Futures.immediateFailedFuture(cause)).when(mockCommitCohort).canCommit();
253
254         try {
255             tx = adapter.newWriteOnlyTransaction();
256             tx.put(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, dataNode);
257             commit(tx);
258             fail("Expected TransactionCommitFailedException");
259         } catch (TransactionCommitFailedException e) {
260             assertEquals("getCause type", DataStoreUnavailableException.class, e.getCause().getClass());
261             assertEquals("Root cause", cause, e.getCause().getCause());
262         }
263
264         // Test submit with RuntimeException
265
266         errorMsg = "mock RuntimeException";
267         cause = new RuntimeException(errorMsg);
268         doReturn(Futures.immediateFailedFuture(cause)).when(mockCommitCohort).canCommit();
269
270         try {
271             tx = adapter.newWriteOnlyTransaction();
272             tx.put(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, dataNode);
273             commit(tx);
274             fail("Expected TransactionCommitFailedException");
275         } catch (TransactionCommitFailedException e) {
276             assertEquals("getCause", cause, e.getCause());
277         }
278     }
279
280     @Test
281     public void testReadWriteTransaction() throws Exception {
282         DOMDataReadWriteTransaction tx = adapter.newReadWriteTransaction();
283
284         CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> readFuture =
285                 tx.read(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH);
286         Optional<NormalizedNode<?, ?>> readOptional = readFuture.get();
287         assertEquals("isPresent", true, readOptional.isPresent());
288         assertEquals("NormalizedNode", dataNode, readOptional.get());
289
290         tx.put(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, dataNode);
291         verify(mockReadWriteTx).write(TestModel.TEST_PATH, dataNode);
292
293         tx.commit().get(5, TimeUnit.SECONDS);
294
295         InOrder inOrder = inOrder(mockCommitCohort);
296         inOrder.verify(mockCommitCohort).canCommit();
297         inOrder.verify(mockCommitCohort).preCommit();
298         inOrder.verify(mockCommitCohort).commit();
299     }
300
301     @SuppressWarnings("rawtypes")
302     @Test
303     public void testTransactionChain() throws Exception {
304         TransactionChainListener mockListener = mock(TransactionChainListener.class);
305         doNothing().when(mockListener).onTransactionChainSuccessful(anyObject());
306         doNothing().when(mockListener).onTransactionChainFailed(anyObject(), anyObject(), anyObject());
307
308         DOMTransactionChain chain = adapter.createTransactionChain(mockListener);
309
310         // Test read-only tx
311
312         DOMDataReadOnlyTransaction readTx = chain.newReadOnlyTransaction();
313
314         CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> readFuture =
315                 readTx.read(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH);
316         Optional<NormalizedNode<?, ?>> readOptional = readFuture.get();
317         assertEquals("isPresent", true, readOptional.isPresent());
318         assertEquals("NormalizedNode", dataNode, readOptional.get());
319
320         // Test write-only tx
321
322         DOMDataWriteTransaction writeTx = chain.newWriteOnlyTransaction();
323
324         writeTx.put(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, dataNode);
325         verify(mockWriteTx).write(TestModel.TEST_PATH, dataNode);
326         writeTx.commit().get(5, TimeUnit.SECONDS);
327
328         InOrder inOrder = inOrder(mockCommitCohort);
329         inOrder.verify(mockCommitCohort).canCommit();
330         inOrder.verify(mockCommitCohort).preCommit();
331         inOrder.verify(mockCommitCohort).commit();
332
333         // Test read-write tx
334
335         DOMDataReadWriteTransaction readWriteTx = chain.newReadWriteTransaction();
336
337         readFuture = readWriteTx.read(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH);
338         readOptional = readFuture.get();
339         assertEquals("isPresent", true, readOptional.isPresent());
340         assertEquals("NormalizedNode", dataNode, readOptional.get());
341
342         chain.close();
343         verify(mockListener).onTransactionChainSuccessful(chain);
344
345         // Test failed chain
346
347         doReturn(Futures.immediateFailedFuture(new org.opendaylight.mdsal.common.api.TransactionCommitFailedException(
348                 "mock", (Throwable)null))).when(mockCommitCohort).canCommit();
349
350         chain = adapter.createTransactionChain(mockListener);
351
352         writeTx = chain.newWriteOnlyTransaction();
353
354         try {
355             writeTx.put(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, dataNode);
356             commit(writeTx);
357             fail("Expected TransactionCommitFailedException");
358         } catch (TransactionCommitFailedException e) {
359             // expected
360         }
361
362         ArgumentCaptor<AsyncTransaction> failedTx = ArgumentCaptor.forClass(AsyncTransaction.class);
363         verify(mockListener).onTransactionChainFailed(eq(chain), failedTx.capture(),
364                 any(TransactionCommitFailedException.class));
365     }
366
367     @SuppressWarnings("unchecked")
368     @Test
369     public void testDataTreeChangeListener() {
370         DOMDataTreeChangeService domDTCLService =
371                 (DOMDataTreeChangeService) adapter.getSupportedExtensions().get(DOMDataTreeChangeService.class);
372         assertNotNull("DOMDataTreeChangeService not found", domDTCLService);
373
374         ArgumentCaptor<org.opendaylight.mdsal.dom.api.DOMDataTreeChangeListener> storeDTCL =
375                 ArgumentCaptor.forClass(org.opendaylight.mdsal.dom.api.DOMDataTreeChangeListener.class);
376         ListenerRegistration<org.opendaylight.mdsal.dom.api.DOMDataTreeChangeListener> mockReg =
377                 mock(ListenerRegistration.class);
378         doNothing().when(mockReg).close();
379         doAnswer(invocation -> storeDTCL.getValue()).when(mockReg).getInstance();
380         doReturn(mockReg).when(mockConfigStore).registerTreeChangeListener(eq(TestModel.TEST_PATH),
381                 storeDTCL.capture());
382
383         DOMDataTreeChangeListener brokerDTCL = mock(DOMDataTreeChangeListener.class);
384         ListenerRegistration<DOMDataTreeChangeListener> reg = domDTCLService.registerDataTreeChangeListener(
385                 new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH), brokerDTCL);
386         assertEquals("getInstance", brokerDTCL, reg.getInstance());
387
388         Collection<DataTreeCandidate> changes = Arrays.asList(mock(DataTreeCandidate.class));
389         storeDTCL.getValue().onDataTreeChanged(changes);
390         verify(brokerDTCL).onDataTreeChanged(changes);
391
392         reg.close();
393         verify(mockReg).close();
394
395         // Test ClusteredDOMDataTreeChangeListener
396
397         ArgumentCaptor<org.opendaylight.mdsal.dom.api.DOMDataTreeChangeListener> storeClusteredDTCL =
398                 ArgumentCaptor.forClass(org.opendaylight.mdsal.dom.api.DOMDataTreeChangeListener.class);
399         mockReg = mock(ListenerRegistration.class);
400         doReturn(mockReg).when(mockConfigStore).registerTreeChangeListener(eq(TestModel.TEST_PATH),
401                 storeClusteredDTCL.capture());
402
403         final ClusteredDOMDataTreeChangeListener brokerClusteredDTCL = mock(ClusteredDOMDataTreeChangeListener.class);
404         domDTCLService.registerDataTreeChangeListener(new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION,
405                 TestModel.TEST_PATH), brokerClusteredDTCL);
406
407         assertTrue("Expected ClusteredDOMDataTreeChangeListener: " + storeClusteredDTCL.getValue(),
408                 storeClusteredDTCL.getValue()
409                     instanceof org.opendaylight.mdsal.dom.api.ClusteredDOMDataTreeChangeListener);
410         storeClusteredDTCL.getValue().onDataTreeChanged(changes);
411         verify(brokerClusteredDTCL).onDataTreeChanged(changes);
412     }
413
414     @SuppressWarnings("unchecked")
415     @Test
416     public void testDataTreeCommitCohortRegistry() {
417         DOMDataTreeCommitCohortRegistry domCohortRegistry = (DOMDataTreeCommitCohortRegistry)
418                 adapter.getSupportedExtensions().get(DOMDataTreeCommitCohortRegistry.class);
419         assertNotNull("DOMDataTreeCommitCohortRegistry not found", domCohortRegistry);
420
421         DOMDataTreeCommitCohort mockCohort = mock(DOMDataTreeCommitCohort.class);
422         org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier treeId =
423                 new org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier(
424                     org.opendaylight.mdsal.common.api.LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH);
425         DOMDataTreeCommitCohortRegistration<DOMDataTreeCommitCohort> mockReg =
426                 mock(DOMDataTreeCommitCohortRegistration.class);
427         doReturn(mockReg).when(mockConfigStore).registerCommitCohort(treeId, mockCohort);
428
429         DOMDataTreeCommitCohortRegistration<DOMDataTreeCommitCohort> reg = domCohortRegistry.registerCommitCohort(
430                 treeId, mockCohort);
431         assertEquals("DOMDataTreeCommitCohortRegistration", mockReg, reg);
432
433         verify(mockConfigStore).registerCommitCohort(treeId, mockCohort);
434     }
435
436     @Test
437     public void testDataChangeListener() {
438         DOMDataChangeListener listener = mock(DOMDataChangeListener.class);
439         ListenerRegistration<DOMDataChangeListener> mockReg = mock(ListenerRegistration.class);
440         doReturn(mockReg).when(mockConfigStore).registerChangeListener(
441                 TestModel.TEST_PATH, listener, DataChangeScope.ONE);
442
443         ListenerRegistration<DOMDataChangeListener> reg = adapter.registerDataChangeListener(
444                 LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, listener, DataChangeScope.ONE);
445         assertEquals("ListenerRegistration<DOMDataChangeListener>", mockReg, reg);
446
447         verify(mockConfigStore).registerChangeListener(TestModel.TEST_PATH, listener, DataChangeScope.ONE);
448     }
449
450     @Test
451     @Deprecated
452     public void testSubmit() throws Exception {
453         DOMDataWriteTransaction tx = adapter.newWriteOnlyTransaction();
454
455         tx.put(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, dataNode);
456         verify(mockWriteTx).write(TestModel.TEST_PATH, dataNode);
457
458         tx.submit().get(5, TimeUnit.SECONDS);
459
460         InOrder inOrder = inOrder(mockCommitCohort);
461         inOrder.verify(mockCommitCohort).canCommit();
462         inOrder.verify(mockCommitCohort).preCommit();
463         inOrder.verify(mockCommitCohort).commit();
464
465         String errorMsg = "mock OptimisticLockFailedException";
466         Throwable cause = new ConflictingModificationAppliedException(TestModel.TEST_PATH, "mock");
467         doReturn(Futures.immediateFailedFuture(new org.opendaylight.mdsal.common.api.TransactionCommitFailedException(
468                 errorMsg, cause))).when(mockCommitCohort).canCommit();
469
470         try {
471             tx = adapter.newWriteOnlyTransaction();
472             tx.put(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, dataNode);
473             commit(tx);
474             fail("Expected TransactionCommitFailedException");
475         } catch (TransactionCommitFailedException e) {
476             assertEquals("getMessage", errorMsg, e.getMessage());
477             assertEquals("getCause", cause, e.getCause());
478         }
479     }
480
481     @SuppressWarnings("checkstyle:AvoidHidingCauseException")
482     private static void commit(DOMDataWriteTransaction tx)
483             throws TransactionCommitFailedException, InterruptedException, TimeoutException {
484         try {
485             tx.commit().get(5, TimeUnit.SECONDS);
486         } catch (ExecutionException e) {
487             assertTrue("Expected TransactionCommitFailedException. Actual: " + e.getCause(),
488                     e.getCause() instanceof TransactionCommitFailedException);
489             throw (TransactionCommitFailedException)e.getCause();
490         }
491     }
492
493     private interface TestDOMStore extends DistributedDataStoreInterface, DOMStoreTreeChangePublisher,
494             org.opendaylight.mdsal.dom.api.DOMDataTreeCommitCohortRegistry {
495     }
496 }