Cleanup Local*ProxyTransactionTest
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / test / java / org / opendaylight / controller / cluster / databroker / actors / dds / LocalProxyTransactionTest.java
1 /*
2  * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.actors.dds;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertTrue;
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.opendaylight.controller.cluster.databroker.actors.dds.TestUtils.assertFutureEquals;
17
18 import akka.testkit.TestProbe;
19 import com.google.common.base.Ticker;
20 import java.util.Optional;
21 import java.util.function.Consumer;
22 import org.junit.Test;
23 import org.mockito.ArgumentCaptor;
24 import org.mockito.invocation.InvocationOnMock;
25 import org.mockito.stubbing.Answer;
26 import org.opendaylight.controller.cluster.access.client.ClientActorBehavior;
27 import org.opendaylight.controller.cluster.access.client.InternalCommand;
28 import org.opendaylight.controller.cluster.access.commands.AbortLocalTransactionRequest;
29 import org.opendaylight.controller.cluster.access.commands.CommitLocalTransactionRequest;
30 import org.opendaylight.controller.cluster.access.commands.ExistsTransactionRequest;
31 import org.opendaylight.controller.cluster.access.commands.ExistsTransactionSuccess;
32 import org.opendaylight.controller.cluster.access.commands.ModifyTransactionRequest;
33 import org.opendaylight.controller.cluster.access.commands.PersistenceProtocol;
34 import org.opendaylight.controller.cluster.access.commands.ReadTransactionRequest;
35 import org.opendaylight.controller.cluster.access.commands.ReadTransactionSuccess;
36 import org.opendaylight.controller.cluster.access.commands.TransactionPurgeRequest;
37 import org.opendaylight.controller.cluster.access.commands.TransactionRequest;
38 import org.opendaylight.controller.cluster.access.concepts.Response;
39 import org.opendaylight.yangtools.yang.data.tree.api.CursorAwareDataTreeModification;
40 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeModificationCursor;
41
42 public abstract class LocalProxyTransactionTest<T extends LocalProxyTransaction>
43         extends AbstractProxyTransactionTest<T> {
44
45     @Override
46     @Test
47     public void testExists() throws Exception {
48         assertFutureEquals(Boolean.TRUE, transaction.exists(PATH_1));
49         assertFutureEquals(Boolean.FALSE, transaction.exists(PATH_3));
50     }
51
52     @Override
53     @Test
54     public void testRead() throws Exception {
55         assertFutureEquals(Optional.of(DATA_1), transaction.read(PATH_1));
56         assertFutureEquals(Optional.empty(), transaction.read(PATH_3));
57     }
58
59     @Test
60     public void testAbort() {
61         transaction.abort();
62         getTester().expectTransactionRequest(AbortLocalTransactionRequest.class);
63     }
64
65     @SuppressWarnings("unchecked")
66     private void setupExecuteInActor() {
67         doAnswer(inv -> {
68             inv.getArgument(0, InternalCommand.class).execute(mock(ClientActorBehavior.class));
69             return null;
70         }).when(context).executeInActor(any(InternalCommand.class));
71     }
72
73     @Test
74     public void testHandleForwardedRemoteReadRequest() {
75         final TestProbe probe = createProbe();
76         final ReadTransactionRequest request =
77                 new ReadTransactionRequest(TRANSACTION_ID, 0L, probe.ref(), PATH_1, true);
78         final Consumer<Response<?, ?>> callback = createCallbackMock();
79         setupExecuteInActor();
80
81         transaction.handleReplayedRemoteRequest(request, callback, Ticker.systemTicker().read());
82         final ArgumentCaptor<Response<?, ?>> captor = ArgumentCaptor.forClass(Response.class);
83         verify(callback).accept(captor.capture());
84         final Response<?, ?> value = captor.getValue();
85         assertTrue(value instanceof ReadTransactionSuccess);
86         final ReadTransactionSuccess success = (ReadTransactionSuccess) value;
87         assertTrue(success.getData().isPresent());
88         assertEquals(DATA_1, success.getData().get());
89     }
90
91     @Test
92     public void testHandleForwardedRemoteExistsRequest() {
93         final TestProbe probe = createProbe();
94         final ExistsTransactionRequest request =
95                 new ExistsTransactionRequest(TRANSACTION_ID, 0L, probe.ref(), PATH_1, true);
96         final Consumer<Response<?, ?>> callback = createCallbackMock();
97         setupExecuteInActor();
98
99         transaction.handleReplayedRemoteRequest(request, callback, Ticker.systemTicker().read());
100         final ArgumentCaptor<Response<?, ?>> captor = ArgumentCaptor.forClass(Response.class);
101         verify(callback).accept(captor.capture());
102         final Response<?, ?> value = captor.getValue();
103         assertTrue(value instanceof ExistsTransactionSuccess);
104         final ExistsTransactionSuccess success = (ExistsTransactionSuccess) value;
105         assertTrue(success.getExists());
106     }
107
108     @Test
109     public void testHandleForwardedRemotePurgeRequest() {
110         final TestProbe probe = createProbe();
111         final TransactionPurgeRequest request = new TransactionPurgeRequest(TRANSACTION_ID, 0L, probe.ref());
112         testHandleForwardedRemoteRequest(request);
113     }
114
115     @Override
116     @Test
117     public void testForwardToRemoteAbort() {
118         final TestProbe probe = createProbe();
119         final AbortLocalTransactionRequest request = new AbortLocalTransactionRequest(TRANSACTION_ID, probe.ref());
120         final ModifyTransactionRequest modifyRequest = testForwardToRemote(request, ModifyTransactionRequest.class);
121         assertTrue(modifyRequest.getPersistenceProtocol().isPresent());
122         assertEquals(PersistenceProtocol.ABORT, modifyRequest.getPersistenceProtocol().get());
123     }
124
125     @Override
126     @Test
127     public void testForwardToRemoteCommit() {
128         final TestProbe probe = createProbe();
129         final CursorAwareDataTreeModification modification = mock(CursorAwareDataTreeModification.class);
130         final CommitLocalTransactionRequest request =
131                 new CommitLocalTransactionRequest(TRANSACTION_ID, 0L, probe.ref(), modification, null, true);
132         doAnswer(LocalProxyTransactionTest::applyToCursorAnswer).when(modification).applyToCursor(any());
133         final ModifyTransactionRequest modifyRequest = testForwardToRemote(request, ModifyTransactionRequest.class);
134         verify(modification).applyToCursor(any());
135         assertTrue(modifyRequest.getPersistenceProtocol().isPresent());
136         assertEquals(PersistenceProtocol.THREE_PHASE, modifyRequest.getPersistenceProtocol().get());
137         checkModifications(modifyRequest);
138     }
139
140     @Test
141     public void testForwardToLocalAbort() {
142         final TestProbe probe = createProbe();
143         final AbortLocalTransactionRequest request = new AbortLocalTransactionRequest(TRANSACTION_ID, probe.ref());
144         testForwardToLocal(request, AbortLocalTransactionRequest.class);
145     }
146
147     @Test
148     public void testForwardToLocalPurge() {
149         final TestProbe probe = createProbe();
150         final TransactionPurgeRequest request = new TransactionPurgeRequest(TRANSACTION_ID, 0L, probe.ref());
151         testForwardToLocal(request, TransactionPurgeRequest.class);
152     }
153
154     protected <R extends TransactionRequest<R>> R testForwardToLocal(final TransactionRequest<?> toForward,
155                                                                      final Class<R> expectedMessageClass) {
156         final Consumer<Response<?, ?>> callback = createCallbackMock();
157         final TransactionTester<LocalReadWriteProxyTransaction> transactionTester = createLocalProxy();
158         final LocalReadWriteProxyTransaction successor = transactionTester.getTransaction();
159         transaction.forwardToLocal(successor, toForward, callback);
160         return transactionTester.expectTransactionRequest(expectedMessageClass);
161     }
162
163     /**
164      * To emulate side effect of void method.
165      * {@link CursorAwareDataTreeModification#applyToCursor(DataTreeModificationCursor)}
166      *
167      * @param invocation invocation
168      * @return void - always null
169      */
170     protected static final <T> Answer<T> applyToCursorAnswer(final InvocationOnMock invocation) {
171         final DataTreeModificationCursor cursor = invocation.getArgument(0);
172         cursor.write(PATH_1.getLastPathArgument(), DATA_1);
173         cursor.merge(PATH_2.getLastPathArgument(), DATA_2);
174         cursor.delete(PATH_3.getLastPathArgument());
175         return null;
176     }
177 }