2 * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.controller.cluster.databroker.actors.dds;
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertFalse;
12 import static org.mockito.ArgumentMatchers.any;
13 import static org.mockito.Mockito.doAnswer;
14 import static org.mockito.Mockito.mock;
15 import static org.mockito.Mockito.verify;
16 import static org.mockito.Mockito.when;
17 import static org.opendaylight.controller.cluster.databroker.actors.dds.TestUtils.assertFutureEquals;
18 import static org.opendaylight.controller.cluster.databroker.actors.dds.TestUtils.assertOperationThrowsException;
20 import akka.testkit.TestProbe;
21 import com.google.common.base.Ticker;
22 import com.google.common.util.concurrent.ListenableFuture;
23 import java.util.Optional;
24 import java.util.function.Consumer;
25 import org.junit.Test;
26 import org.mockito.Mock;
27 import org.opendaylight.controller.cluster.access.commands.AbortLocalTransactionRequest;
28 import org.opendaylight.controller.cluster.access.commands.CommitLocalTransactionRequest;
29 import org.opendaylight.controller.cluster.access.commands.ModifyTransactionRequest;
30 import org.opendaylight.controller.cluster.access.commands.ModifyTransactionRequestBuilder;
31 import org.opendaylight.controller.cluster.access.commands.TransactionAbortRequest;
32 import org.opendaylight.controller.cluster.access.commands.TransactionCanCommitSuccess;
33 import org.opendaylight.controller.cluster.access.commands.TransactionCommitSuccess;
34 import org.opendaylight.controller.cluster.access.commands.TransactionDelete;
35 import org.opendaylight.controller.cluster.access.commands.TransactionDoCommitRequest;
36 import org.opendaylight.controller.cluster.access.commands.TransactionMerge;
37 import org.opendaylight.controller.cluster.access.commands.TransactionModification;
38 import org.opendaylight.controller.cluster.access.commands.TransactionPreCommitRequest;
39 import org.opendaylight.controller.cluster.access.commands.TransactionPreCommitSuccess;
40 import org.opendaylight.controller.cluster.access.commands.TransactionRequest;
41 import org.opendaylight.controller.cluster.access.commands.TransactionWrite;
42 import org.opendaylight.controller.cluster.access.concepts.Response;
43 import org.opendaylight.controller.cluster.access.concepts.TransactionIdentifier;
44 import org.opendaylight.yangtools.yang.data.tree.api.CursorAwareDataTreeModification;
45 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeModification;
46 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeSnapshot;
48 public class LocalReadWriteProxyTransactionTest extends LocalProxyTransactionTest<LocalReadWriteProxyTransaction> {
50 private CursorAwareDataTreeModification modification;
53 protected LocalReadWriteProxyTransaction createTransaction(final ProxyHistory parent,
54 final TransactionIdentifier id,
55 final DataTreeSnapshot snapshot) {
56 when(snapshot.newModification()).thenReturn(modification);
57 when(modification.readNode(PATH_1)).thenReturn(Optional.of(DATA_1));
58 when(modification.readNode(PATH_3)).thenReturn(Optional.empty());
59 return new LocalReadWriteProxyTransaction(parent, TestUtils.TRANSACTION_ID, snapshot);
63 public void testIsSnapshotOnly() {
64 assertFalse(transaction.isSnapshotOnly());
68 public void testReadOnlyView() {
69 assertEquals(modification, transaction.readOnlyView());
74 public void testDelete() {
75 transaction.delete(PATH_1);
76 verify(modification).delete(PATH_1);
81 public void testDirectCommit() throws Exception {
83 final ListenableFuture<Boolean> result = transaction.directCommit();
84 final TransactionTester<LocalReadWriteProxyTransaction> tester = getTester();
85 final CommitLocalTransactionRequest req = tester.expectTransactionRequest(CommitLocalTransactionRequest.class);
86 tester.replySuccess(new TransactionCommitSuccess(TRANSACTION_ID, req.getSequence()));
87 assertFutureEquals(Boolean.TRUE, result);
92 public void testCanCommit() {
93 testRequestResponse(transaction::canCommit, CommitLocalTransactionRequest.class,
94 TransactionCanCommitSuccess::new);
99 public void testPreCommit() {
100 testRequestResponse(transaction::preCommit, TransactionPreCommitRequest.class,
101 TransactionPreCommitSuccess::new);
106 public void testDoCommit() {
107 testRequestResponse(transaction::doCommit, TransactionDoCommitRequest.class, TransactionCommitSuccess::new);
112 public void testMerge() {
113 transaction.merge(PATH_1, DATA_1);
114 verify(modification).merge(PATH_1, DATA_1);
119 public void testWrite() {
120 transaction.write(PATH_1, DATA_1);
121 verify(modification).write(PATH_1, DATA_1);
125 public void testCommitRequest() {
126 transaction.doWrite(PATH_1, DATA_1);
127 final boolean coordinated = true;
128 final CommitLocalTransactionRequest request = transaction.commitRequest(coordinated);
129 assertEquals(coordinated, request.isCoordinated());
130 assertEquals(modification, request.getModification());
134 public void testModifyAfterCommitRequest() throws Exception {
135 transaction.doWrite(PATH_1, DATA_1);
136 final boolean coordinated = true;
137 transaction.commitRequest(coordinated);
138 assertOperationThrowsException(() -> transaction.doMerge(PATH_1, DATA_1), IllegalStateException.class);
142 public void testSealOnly() throws Exception {
143 assertOperationThrowsException(() -> transaction.getSnapshot(), IllegalStateException.class);
144 transaction.sealOnly();
145 assertEquals(modification, transaction.getSnapshot());
149 public void testFlushState() {
150 final TransactionTester<RemoteProxyTransaction> transactionTester = createRemoteProxyTransactionTester();
151 final RemoteProxyTransaction successor = transactionTester.getTransaction();
152 doAnswer(LocalProxyTransactionTest::applyToCursorAnswer).when(modification).applyToCursor(any());
153 transaction.sealOnly();
154 final TransactionRequest<?> request = transaction.flushState().orElseThrow();
155 transaction.forwardToSuccessor(successor, request, null);
156 verify(modification).applyToCursor(any());
157 transactionTester.getTransaction().seal();
158 transactionTester.getTransaction().directCommit();
159 final ModifyTransactionRequest modifyRequest =
160 transactionTester.expectTransactionRequest(ModifyTransactionRequest.class);
161 checkModifications(modifyRequest);
165 public void testApplyModifyTransactionRequestCoordinated() {
166 applyModifyTransactionRequest(true);
170 public void testApplyModifyTransactionRequestSimple() {
171 applyModifyTransactionRequest(false);
175 public void testApplyModifyTransactionRequestAbort() {
176 final TestProbe probe = createProbe();
177 final ModifyTransactionRequestBuilder builder =
178 new ModifyTransactionRequestBuilder(TRANSACTION_ID, probe.ref());
179 builder.setSequence(0L);
181 final ModifyTransactionRequest request = builder.build();
182 final Consumer<Response<?, ?>> callback = createCallbackMock();
183 transaction.replayModifyTransactionRequest(request, callback, Ticker.systemTicker().read());
184 getTester().expectTransactionRequest(AbortLocalTransactionRequest.class);
188 public void testHandleForwardedRemotePreCommitRequest() {
189 final TestProbe probe = createProbe();
190 final TransactionPreCommitRequest request =
191 new TransactionPreCommitRequest(TRANSACTION_ID, 0L, probe.ref());
192 testHandleForwardedRemoteRequest(request);
196 public void testHandleForwardedRemoteDoCommitRequest() {
197 final TestProbe probe = createProbe();
198 final TransactionDoCommitRequest request =
199 new TransactionDoCommitRequest(TRANSACTION_ID, 0L, probe.ref());
200 testHandleForwardedRemoteRequest(request);
204 public void testHandleForwardedRemoteAbortRequest() {
205 final TestProbe probe = createProbe();
206 final TransactionAbortRequest request =
207 new TransactionAbortRequest(TRANSACTION_ID, 0L, probe.ref());
208 testHandleForwardedRemoteRequest(request);
212 public void testForwardToLocalCommit() {
213 final TestProbe probe = createProbe();
214 final DataTreeModification mod = mock(DataTreeModification.class);
215 final TransactionRequest<?> request =
216 new CommitLocalTransactionRequest(TRANSACTION_ID, 0L, probe.ref(), mod, null, false);
217 testForwardToLocal(request, CommitLocalTransactionRequest.class);
221 public void testSendAbort() throws Exception {
222 final TestProbe probe = createProbe();
223 final TransactionRequest<?> request = new AbortLocalTransactionRequest(TRANSACTION_ID, probe.ref());
224 transaction.sendAbort(request, createCallbackMock());
225 assertOperationThrowsException(() -> transaction.delete(PATH_1), IllegalStateException.class);
228 private void applyModifyTransactionRequest(final boolean coordinated) {
229 final TestProbe probe = createProbe();
230 final ModifyTransactionRequestBuilder builder =
231 new ModifyTransactionRequestBuilder(TRANSACTION_ID, probe.ref());
232 final TransactionModification write = new TransactionWrite(PATH_1, DATA_1);
233 final TransactionModification merge = new TransactionMerge(PATH_2, DATA_2);
234 final TransactionModification delete = new TransactionDelete(PATH_3);
235 builder.addModification(write);
236 builder.addModification(merge);
237 builder.addModification(delete);
238 builder.setSequence(0L);
239 builder.setCommit(coordinated);
240 final ModifyTransactionRequest request = builder.build();
241 final Consumer<Response<?, ?>> callback = createCallbackMock();
242 transaction.replayModifyTransactionRequest(request, callback, Ticker.systemTicker().read());
243 verify(modification).write(PATH_1, DATA_1);
244 verify(modification).merge(PATH_2, DATA_2);
245 verify(modification).delete(PATH_3);
246 final CommitLocalTransactionRequest commitRequest =
247 getTester().expectTransactionRequest(CommitLocalTransactionRequest.class);
248 assertEquals(modification, commitRequest.getModification());
249 assertEquals(coordinated, commitRequest.isCoordinated());