283913f5ea137bd1d4920fb19f1b0be062622ccb
[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.mockito.ArgumentMatchers.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.opendaylight.controller.cluster.databroker.actors.dds.TestUtils.assertFutureEquals;
15
16 import akka.testkit.TestProbe;
17 import com.google.common.base.Ticker;
18 import java.util.Optional;
19 import java.util.function.Consumer;
20 import org.junit.Assert;
21 import org.junit.Test;
22 import org.mockito.ArgumentCaptor;
23 import org.mockito.invocation.InvocationOnMock;
24 import org.mockito.stubbing.Answer;
25 import org.opendaylight.controller.cluster.access.client.ClientActorBehavior;
26 import org.opendaylight.controller.cluster.access.client.InternalCommand;
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.ExistsTransactionRequest;
30 import org.opendaylight.controller.cluster.access.commands.ExistsTransactionSuccess;
31 import org.opendaylight.controller.cluster.access.commands.ModifyTransactionRequest;
32 import org.opendaylight.controller.cluster.access.commands.PersistenceProtocol;
33 import org.opendaylight.controller.cluster.access.commands.ReadTransactionRequest;
34 import org.opendaylight.controller.cluster.access.commands.ReadTransactionSuccess;
35 import org.opendaylight.controller.cluster.access.commands.TransactionPurgeRequest;
36 import org.opendaylight.controller.cluster.access.commands.TransactionRequest;
37 import org.opendaylight.controller.cluster.access.concepts.Response;
38 import org.opendaylight.yangtools.yang.data.tree.api.CursorAwareDataTreeModification;
39 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeModificationCursor;
40
41 public abstract class LocalProxyTransactionTest<T extends LocalProxyTransaction>
42         extends AbstractProxyTransactionTest<T> {
43
44     @Override
45     @Test
46     public void testExists() throws Exception {
47         assertFutureEquals(Boolean.TRUE, transaction.exists(PATH_1));
48         assertFutureEquals(Boolean.FALSE, transaction.exists(PATH_3));
49     }
50
51     @Override
52     @Test
53     public void testRead() throws Exception {
54         assertFutureEquals(Optional.of(DATA_1), transaction.read(PATH_1));
55         assertFutureEquals(Optional.empty(), transaction.read(PATH_3));
56     }
57
58     @Test
59     public void testAbort() {
60         transaction.abort();
61         getTester().expectTransactionRequest(AbortLocalTransactionRequest.class);
62     }
63
64     @SuppressWarnings("unchecked")
65     private void setupExecuteInActor() {
66         doAnswer(inv -> {
67             inv.<InternalCommand<?>>getArgument(0).execute(mock(ClientActorBehavior.class));
68             return null;
69         }).when(context).executeInActor(any(InternalCommand.class));
70     }
71
72     @Test
73     public void testHandleForwardedRemoteReadRequest() {
74         final TestProbe probe = createProbe();
75         final ReadTransactionRequest request =
76                 new ReadTransactionRequest(TRANSACTION_ID, 0L, probe.ref(), PATH_1, true);
77         final Consumer<Response<?, ?>> callback = createCallbackMock();
78         setupExecuteInActor();
79
80         transaction.handleReplayedRemoteRequest(request, callback, Ticker.systemTicker().read());
81         final ArgumentCaptor<Response<?, ?>> captor = ArgumentCaptor.forClass(Response.class);
82         verify(callback).accept(captor.capture());
83         final Response<?, ?> value = captor.getValue();
84         Assert.assertTrue(value instanceof ReadTransactionSuccess);
85         final ReadTransactionSuccess success = (ReadTransactionSuccess) value;
86         Assert.assertTrue(success.getData().isPresent());
87         Assert.assertEquals(DATA_1, success.getData().get());
88     }
89
90     @Test
91     public void testHandleForwardedRemoteExistsRequest() {
92         final TestProbe probe = createProbe();
93         final ExistsTransactionRequest request =
94                 new ExistsTransactionRequest(TRANSACTION_ID, 0L, probe.ref(), PATH_1, true);
95         final Consumer<Response<?, ?>> callback = createCallbackMock();
96         setupExecuteInActor();
97
98         transaction.handleReplayedRemoteRequest(request, callback, Ticker.systemTicker().read());
99         final ArgumentCaptor<Response<?, ?>> captor = ArgumentCaptor.forClass(Response.class);
100         verify(callback).accept(captor.capture());
101         final Response<?, ?> value = captor.getValue();
102         Assert.assertTrue(value instanceof ExistsTransactionSuccess);
103         final ExistsTransactionSuccess success = (ExistsTransactionSuccess) value;
104         Assert.assertTrue(success.getExists());
105     }
106
107     @Test
108     public void testHandleForwardedRemotePurgeRequest() {
109         final TestProbe probe = createProbe();
110         final TransactionPurgeRequest request =
111                 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         Assert.assertTrue(modifyRequest.getPersistenceProtocol().isPresent());
122         Assert.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         Assert.assertTrue(modifyRequest.getPersistenceProtocol().isPresent());
136         Assert.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 }