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.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;
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.api.schema.tree.CursorAwareDataTreeModification;
39 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModificationCursor;
41 public abstract class LocalProxyTransactionTest<T extends LocalProxyTransaction>
42 extends AbstractProxyTransactionTest<T> {
46 public void testExists() throws Exception {
47 assertFutureEquals(Boolean.TRUE, transaction.exists(PATH_1));
48 assertFutureEquals(Boolean.FALSE, transaction.exists(PATH_3));
53 public void testRead() throws Exception {
54 assertFutureEquals(Optional.of(DATA_1), transaction.read(PATH_1));
55 assertFutureEquals(Optional.empty(), transaction.read(PATH_3));
59 public void testAbort() {
61 getTester().expectTransactionRequest(AbortLocalTransactionRequest.class);
64 @SuppressWarnings("unchecked")
65 private void setupExecuteInActor() {
67 inv.<InternalCommand<?>>getArgument(0).execute(mock(ClientActorBehavior.class));
69 }).when(context).executeInActor(any(InternalCommand.class));
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();
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());
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();
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());
108 public void testHandleForwardedRemotePurgeRequest() {
109 final TestProbe probe = createProbe();
110 final TransactionPurgeRequest request =
111 new TransactionPurgeRequest(TRANSACTION_ID, 0L, probe.ref());
112 testHandleForwardedRemoteRequest(request);
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());
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);
141 public void testForwardToLocalAbort() {
142 final TestProbe probe = createProbe();
143 final AbortLocalTransactionRequest request = new AbortLocalTransactionRequest(TRANSACTION_ID, probe.ref());
144 testForwardToLocal(request, AbortLocalTransactionRequest.class);
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);
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);
164 * To emulate side effect of void method.
165 * {@link CursorAwareDataTreeModification#applyToCursor(DataTreeModificationCursor)}
167 * @param invocation invocation
168 * @return void - always null
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());