2 * Copyright (c) 2016 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.netconf.client.mdsal.spi;
10 import static org.junit.Assert.assertThrows;
11 import static org.mockito.ArgumentMatchers.any;
12 import static org.mockito.Mockito.never;
13 import static org.mockito.Mockito.verify;
14 import static org.mockito.Mockito.when;
16 import com.google.common.util.concurrent.FutureCallback;
17 import org.junit.Before;
18 import org.junit.Test;
19 import org.junit.runner.RunWith;
20 import org.mockito.ArgumentCaptor;
21 import org.mockito.Captor;
22 import org.mockito.Mock;
23 import org.mockito.junit.MockitoJUnitRunner;
24 import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
25 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
26 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
27 import org.opendaylight.mdsal.dom.api.DOMTransactionChainClosedException;
28 import org.opendaylight.yangtools.concepts.Registration;
29 import org.opendaylight.yangtools.yang.common.Empty;
31 @RunWith(MockitoJUnitRunner.StrictStubs.class)
32 public class TxChainTest {
34 private DOMDataBroker broker;
36 private FutureCallback<Empty> listener;
38 private DOMDataTreeReadTransaction readOnlyTx;
40 private AbstractWriteTx writeOnlyTx1;
42 private AbstractWriteTx writeOnlyTx2;
44 private AbstractWriteTx writeOnlyTx3;
46 private Registration registration1;
48 private Registration registration2;
50 private Registration registration3;
52 private ArgumentCaptor<TxListener> captor;
53 private TxChain chain;
57 when(broker.newReadOnlyTransaction()).thenReturn(readOnlyTx);
58 when(broker.newWriteOnlyTransaction()).thenReturn(writeOnlyTx1)
59 .thenReturn(writeOnlyTx2).thenReturn(writeOnlyTx3);
60 when(writeOnlyTx1.addListener(any())).thenReturn(registration1);
61 when(writeOnlyTx2.addListener(any())).thenReturn(registration2);
62 when(writeOnlyTx3.addListener(any())).thenReturn(registration3);
63 chain = new TxChain(broker);
64 chain.addCallback(listener);
68 public void testNewReadOnlyTransactionPrevSubmitted() {
69 chain.newWriteOnlyTransaction();
70 verify(writeOnlyTx1).addListener(captor.capture());
71 captor.getValue().onTransactionSubmitted(writeOnlyTx1);
72 chain.newReadOnlyTransaction();
76 public void testNewReadOnlyTransactionPrevNotSubmitted() {
77 chain.newWriteOnlyTransaction();
78 assertThrows(IllegalStateException.class, chain::newReadOnlyTransaction);
82 public void testNewReadWriteTransactionPrevSubmitted() {
83 chain.newReadWriteTransaction();
84 verify(writeOnlyTx1).addListener(captor.capture());
85 captor.getValue().onTransactionSubmitted(writeOnlyTx1);
86 chain.newReadWriteTransaction();
90 public void testNewReadWriteTransactionPrevNotSubmitted() {
91 chain.newReadWriteTransaction();
92 assertThrows(IllegalStateException.class, chain::newReadWriteTransaction);
96 public void testNewWriteOnlyTransactionPrevSubmitted() {
97 chain.newWriteOnlyTransaction();
98 verify(writeOnlyTx1).addListener(captor.capture());
99 captor.getValue().onTransactionSubmitted(writeOnlyTx1);
100 chain.newWriteOnlyTransaction();
104 public void testNewWriteOnlyTransactionPrevNotSubmitted() {
105 chain.newWriteOnlyTransaction();
106 assertThrows(IllegalStateException.class, chain::newWriteOnlyTransaction);
110 public void testCloseAfterFinished() {
112 verify(listener).onSuccess(Empty.value());
113 assertThrows(DOMTransactionChainClosedException.class, chain::newReadOnlyTransaction);
117 public void testChainFail() {
118 final AbstractWriteTx writeTx = chain.newWriteOnlyTransaction();
119 verify(writeOnlyTx1).addListener(captor.capture());
121 final TransactionCommitFailedException cause = new TransactionCommitFailedException("fail");
122 captor.getValue().onTransactionFailed(writeOnlyTx1, cause);
123 verify(registration1).close();
124 verify(listener).onFailure(cause);
128 public void testChainSuccess() {
129 final AbstractWriteTx writeTx = chain.newWriteOnlyTransaction();
131 verify(writeOnlyTx1).addListener(captor.capture());
133 captor.getValue().onTransactionSuccessful(writeOnlyTx1);
134 verify(registration1).close();
135 verify(listener).onSuccess(Empty.value());
139 public void testCancel() {
140 final AbstractWriteTx writeTx = chain.newWriteOnlyTransaction();
141 verify(writeOnlyTx1).addListener(captor.capture());
143 captor.getValue().onTransactionCancelled(writeOnlyTx1);
144 chain.newWriteOnlyTransaction();
148 public void testMultiplePendingTransactions() {
150 final AbstractWriteTx writeTx1 = chain.newWriteOnlyTransaction();
151 final var captor1 = ArgumentCaptor.forClass(TxListener.class);
152 verify(writeOnlyTx1).addListener(captor1.capture());
155 captor1.getValue().onTransactionSubmitted(writeOnlyTx1);
158 final AbstractWriteTx writeTx2 = chain.newWriteOnlyTransaction();
159 final var captor2 = ArgumentCaptor.forClass(TxListener.class);
160 verify(writeTx2).addListener(captor2.capture());
163 captor2.getValue().onTransactionSubmitted(writeOnlyTx2);
166 final AbstractWriteTx writeTx3 = chain.newWriteOnlyTransaction();
167 final var captor3 = ArgumentCaptor.forClass(TxListener.class);
168 verify(writeTx3).addListener(captor3.capture());
171 captor3.getValue().onTransactionCancelled(writeOnlyTx3);
176 //complete first two transactions successfully
177 captor1.getValue().onTransactionSuccessful(writeOnlyTx1);
178 captor2.getValue().onTransactionSuccessful(writeOnlyTx2);
180 verify(registration1).close();
181 verify(registration2).close();
182 verify(registration3).close();
183 verify(listener).onSuccess(Empty.value());
187 public void testMultiplePendingTransactionsFail() {
189 final AbstractWriteTx writeTx1 = chain.newWriteOnlyTransaction();
190 final var captor1 = ArgumentCaptor.forClass(TxListener.class);
191 verify(writeOnlyTx1).addListener(captor1.capture());
194 captor1.getValue().onTransactionSubmitted(writeOnlyTx1);
197 final AbstractWriteTx writeTx2 = chain.newWriteOnlyTransaction();
198 final var captor2 = ArgumentCaptor.forClass(TxListener.class);
199 verify(writeTx2).addListener(captor2.capture());
202 captor2.getValue().onTransactionSubmitted(writeOnlyTx2);
205 final AbstractWriteTx writeTx3 = chain.newWriteOnlyTransaction();
206 final var captor3 = ArgumentCaptor.forClass(TxListener.class);
207 verify(writeTx3).addListener(captor3.capture());
211 //fail 1st transaction
212 final Exception cause1 = new Exception("fail");
213 captor1.getValue().onTransactionFailed(writeOnlyTx1, cause1);
214 //current unsubmitted transaction should be cancelled
215 verify(writeTx3).cancel();
216 captor3.getValue().onTransactionCancelled(writeTx3);
217 //2nd transaction success
218 captor2.getValue().onTransactionSuccessful(writeOnlyTx2);
220 verify(registration1).close();
221 verify(registration2).close();
222 verify(registration3).close();
223 verify(listener).onFailure(cause1);
224 // 1 transaction failed, onTransactionChainSuccessful must not be called
225 verify(listener, never()).onSuccess(any());