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.util.concurrent.ListenableFuture;
20 import java.util.function.Consumer;
21 import org.junit.Assert;
22 import org.junit.Test;
23 import org.mockito.Mock;
24 import org.opendaylight.controller.cluster.access.commands.AbortLocalTransactionRequest;
25 import org.opendaylight.controller.cluster.access.commands.CommitLocalTransactionRequest;
26 import org.opendaylight.controller.cluster.access.commands.ModifyTransactionRequest;
27 import org.opendaylight.controller.cluster.access.commands.ModifyTransactionRequestBuilder;
28 import org.opendaylight.controller.cluster.access.commands.TransactionAbortRequest;
29 import org.opendaylight.controller.cluster.access.commands.TransactionCanCommitSuccess;
30 import org.opendaylight.controller.cluster.access.commands.TransactionCommitSuccess;
31 import org.opendaylight.controller.cluster.access.commands.TransactionDelete;
32 import org.opendaylight.controller.cluster.access.commands.TransactionDoCommitRequest;
33 import org.opendaylight.controller.cluster.access.commands.TransactionMerge;
34 import org.opendaylight.controller.cluster.access.commands.TransactionModification;
35 import org.opendaylight.controller.cluster.access.commands.TransactionPreCommitRequest;
36 import org.opendaylight.controller.cluster.access.commands.TransactionPreCommitSuccess;
37 import org.opendaylight.controller.cluster.access.commands.TransactionRequest;
38 import org.opendaylight.controller.cluster.access.commands.TransactionWrite;
39 import org.opendaylight.controller.cluster.access.concepts.Response;
40 import org.opendaylight.controller.cluster.access.concepts.TransactionIdentifier;
41 import org.opendaylight.yangtools.yang.data.api.schema.tree.CursorAwareDataTreeModification;
42 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
43 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
45 public class LocalReadWriteProxyTransactionTest extends LocalProxyTransactionTest<LocalReadWriteProxyTransaction> {
47 private CursorAwareDataTreeModification modification;
50 protected LocalReadWriteProxyTransaction createTransaction(final ProxyHistory parent,
51 final TransactionIdentifier id,
52 final DataTreeSnapshot snapshot) {
53 when(snapshot.newModification()).thenReturn(modification);
54 when(modification.readNode(PATH_1)).thenReturn(com.google.common.base.Optional.of(DATA_1));
55 when(modification.readNode(PATH_3)).thenReturn(com.google.common.base.Optional.absent());
56 return new LocalReadWriteProxyTransaction(parent, TestUtils.TRANSACTION_ID, snapshot);
60 public void testIsSnapshotOnly() throws Exception {
61 Assert.assertFalse(transaction.isSnapshotOnly());
65 public void testReadOnlyView() throws Exception {
66 Assert.assertEquals(modification, transaction.readOnlyView());
71 public void testDelete() throws Exception {
72 transaction.delete(PATH_1);
73 verify(modification).delete(PATH_1);
78 public void testDirectCommit() throws Exception {
80 final ListenableFuture<Boolean> result = transaction.directCommit();
81 final TransactionTester<LocalReadWriteProxyTransaction> tester = getTester();
82 final CommitLocalTransactionRequest req = tester.expectTransactionRequest(CommitLocalTransactionRequest.class);
83 tester.replySuccess(new TransactionCommitSuccess(TRANSACTION_ID, req.getSequence()));
84 assertFutureEquals(true, result);
89 public void testCanCommit() throws Exception {
90 testRequestResponse(transaction::canCommit, CommitLocalTransactionRequest.class,
91 TransactionCanCommitSuccess::new);
96 public void testPreCommit() throws Exception {
97 testRequestResponse(transaction::preCommit, TransactionPreCommitRequest.class,
98 TransactionPreCommitSuccess::new);
103 public void testDoCommit() throws Exception {
104 testRequestResponse(transaction::doCommit, TransactionDoCommitRequest.class, TransactionCommitSuccess::new);
109 public void testMerge() throws Exception {
110 transaction.merge(PATH_1, DATA_1);
111 verify(modification).merge(PATH_1, DATA_1);
116 public void testWrite() throws Exception {
117 transaction.write(PATH_1, DATA_1);
118 verify(modification).write(PATH_1, DATA_1);
122 public void testCommitRequest() throws Exception {
123 transaction.doWrite(PATH_1, DATA_1);
124 final boolean coordinated = true;
125 final CommitLocalTransactionRequest request = transaction.commitRequest(coordinated);
126 Assert.assertEquals(coordinated, request.isCoordinated());
127 Assert.assertEquals(modification, request.getModification());
131 public void testModifyAfterCommitRequest() throws Exception {
132 transaction.doWrite(PATH_1, DATA_1);
133 final boolean coordinated = true;
134 transaction.commitRequest(coordinated);
135 assertOperationThrowsException(() -> transaction.doMerge(PATH_1, DATA_1), IllegalStateException.class);
139 public void testDoSeal() throws Exception {
140 assertOperationThrowsException(() -> transaction.getSnapshot(), IllegalStateException.class);
141 transaction.doSeal();
142 Assert.assertEquals(modification, transaction.getSnapshot());
146 public void testFlushState() throws Exception {
147 final TransactionTester<RemoteProxyTransaction> transactionTester = createRemoteProxyTransactionTester();
148 final RemoteProxyTransaction successor = transactionTester.getTransaction();
149 doAnswer(this::applyToCursorAnswer).when(modification).applyToCursor(any());
150 transaction.doSeal();
151 transaction.flushState(successor);
152 verify(modification).applyToCursor(any());
153 transactionTester.getTransaction().seal();
154 transactionTester.getTransaction().directCommit();
155 final ModifyTransactionRequest modifyRequest =
156 transactionTester.expectTransactionRequest(ModifyTransactionRequest.class);
157 checkModifications(modifyRequest);
161 public void testApplyModifyTransactionRequestCoordinated() throws Exception {
162 applyModifyTransactionRequest(true);
166 public void testApplyModifyTransactionRequestSimple() throws Exception {
167 applyModifyTransactionRequest(false);
171 public void testApplyModifyTransactionRequestAbort() throws Exception {
172 final TestProbe probe = createProbe();
173 final ModifyTransactionRequestBuilder builder =
174 new ModifyTransactionRequestBuilder(TRANSACTION_ID, probe.ref());
175 builder.setSequence(0L);
177 final ModifyTransactionRequest request = builder.build();
178 final Consumer<Response<?, ?>> callback = createCallbackMock();
179 transaction.applyModifyTransactionRequest(request, callback);
180 getTester().expectTransactionRequest(TransactionAbortRequest.class);
184 public void testHandleForwardedRemotePreCommitRequest() throws Exception {
185 final TestProbe probe = createProbe();
186 final TransactionPreCommitRequest request =
187 new TransactionPreCommitRequest(TRANSACTION_ID, 0L, probe.ref());
188 testHandleForwardedRemoteRequest(request);
192 public void testHandleForwardedRemoteDoCommitRequest() throws Exception {
193 final TestProbe probe = createProbe();
194 final TransactionDoCommitRequest request =
195 new TransactionDoCommitRequest(TRANSACTION_ID, 0L, probe.ref());
196 testHandleForwardedRemoteRequest(request);
200 public void testHandleForwardedRemoteAbortRequest() throws Exception {
201 final TestProbe probe = createProbe();
202 final TransactionAbortRequest request =
203 new TransactionAbortRequest(TRANSACTION_ID, 0L, probe.ref());
204 testHandleForwardedRemoteRequest(request);
208 public void testForwardToLocalCommit() throws Exception {
209 final TestProbe probe = createProbe();
210 final DataTreeModification mod = mock(DataTreeModification.class);
211 final TransactionRequest<?> request =
212 new CommitLocalTransactionRequest(TRANSACTION_ID, 0L, probe.ref(), mod, null, false);
213 testForwardToLocal(request, CommitLocalTransactionRequest.class);
217 public void testSendAbort() throws Exception {
218 final TestProbe probe = createProbe();
219 final TransactionRequest<?> request = new AbortLocalTransactionRequest(TRANSACTION_ID, probe.ref());
220 transaction.sendAbort(request, createCallbackMock());
221 assertOperationThrowsException(() -> transaction.delete(PATH_1), IllegalStateException.class);
224 private void applyModifyTransactionRequest(final boolean coordinated) {
225 final TestProbe probe = createProbe();
226 final ModifyTransactionRequestBuilder builder =
227 new ModifyTransactionRequestBuilder(TRANSACTION_ID, probe.ref());
228 final TransactionModification write = new TransactionWrite(PATH_1, DATA_1);
229 final TransactionModification merge = new TransactionMerge(PATH_2, DATA_2);
230 final TransactionModification delete = new TransactionDelete(PATH_3);
231 builder.addModification(write);
232 builder.addModification(merge);
233 builder.addModification(delete);
234 builder.setSequence(0L);
235 builder.setCommit(coordinated);
236 final ModifyTransactionRequest request = builder.build();
237 final Consumer<Response<?, ?>> callback = createCallbackMock();
238 transaction.applyModifyTransactionRequest(request, callback);
239 verify(modification).write(PATH_1, DATA_1);
240 verify(modification).merge(PATH_2, DATA_2);
241 verify(modification).delete(PATH_3);
242 final CommitLocalTransactionRequest commitRequest =
243 getTester().expectTransactionRequest(CommitLocalTransactionRequest.class);
244 Assert.assertEquals(modification, commitRequest.getModification());
245 Assert.assertEquals(coordinated, commitRequest.isCoordinated());