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.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;
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;
42 public abstract class LocalProxyTransactionTest<T extends LocalProxyTransaction>
43 extends AbstractProxyTransactionTest<T> {
47 public void testExists() throws Exception {
48 assertFutureEquals(Boolean.TRUE, transaction.exists(PATH_1));
49 assertFutureEquals(Boolean.FALSE, transaction.exists(PATH_3));
54 public void testRead() throws Exception {
55 assertFutureEquals(Optional.of(DATA_1), transaction.read(PATH_1));
56 assertFutureEquals(Optional.empty(), transaction.read(PATH_3));
60 public void testAbort() {
62 getTester().expectTransactionRequest(AbortLocalTransactionRequest.class);
65 @SuppressWarnings("unchecked")
66 private void setupExecuteInActor() {
68 inv.getArgument(0, InternalCommand.class).execute(mock(ClientActorBehavior.class));
70 }).when(context).executeInActor(any(InternalCommand.class));
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();
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());
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();
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());
109 public void testHandleForwardedRemotePurgeRequest() {
110 final TestProbe probe = createProbe();
111 final TransactionPurgeRequest request = 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 assertTrue(modifyRequest.getPersistenceProtocol().isPresent());
122 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 assertTrue(modifyRequest.getPersistenceProtocol().isPresent());
136 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());