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