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 assertEquals(Optional.of(DATA_1), success.getData());
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 assertTrue(value instanceof ExistsTransactionSuccess);
103 final ExistsTransactionSuccess success = (ExistsTransactionSuccess) value;
104 assertTrue(success.getExists());
108 public void testHandleForwardedRemotePurgeRequest() {
109 final TestProbe probe = createProbe();
110 final TransactionPurgeRequest request = new TransactionPurgeRequest(TRANSACTION_ID, 0L, probe.ref());
111 testHandleForwardedRemoteRequest(request);
116 public void testForwardToRemoteAbort() {
117 final TestProbe probe = createProbe();
118 final AbortLocalTransactionRequest request = new AbortLocalTransactionRequest(TRANSACTION_ID, probe.ref());
119 final ModifyTransactionRequest modifyRequest = testForwardToRemote(request, ModifyTransactionRequest.class);
120 assertEquals(Optional.of(PersistenceProtocol.ABORT), modifyRequest.getPersistenceProtocol());
125 public void testForwardToRemoteCommit() {
126 final TestProbe probe = createProbe();
127 final CursorAwareDataTreeModification modification = mock(CursorAwareDataTreeModification.class);
128 final CommitLocalTransactionRequest request =
129 new CommitLocalTransactionRequest(TRANSACTION_ID, 0L, probe.ref(), modification, null, true);
130 doAnswer(LocalProxyTransactionTest::applyToCursorAnswer).when(modification).applyToCursor(any());
131 final ModifyTransactionRequest modifyRequest = testForwardToRemote(request, ModifyTransactionRequest.class);
132 verify(modification).applyToCursor(any());
133 assertEquals(Optional.of(PersistenceProtocol.THREE_PHASE), modifyRequest.getPersistenceProtocol());
134 checkModifications(modifyRequest);
138 public void testForwardToLocalAbort() {
139 final TestProbe probe = createProbe();
140 final AbortLocalTransactionRequest request = new AbortLocalTransactionRequest(TRANSACTION_ID, probe.ref());
141 testForwardToLocal(request, AbortLocalTransactionRequest.class);
145 public void testForwardToLocalPurge() {
146 final TestProbe probe = createProbe();
147 final TransactionPurgeRequest request = new TransactionPurgeRequest(TRANSACTION_ID, 0L, probe.ref());
148 testForwardToLocal(request, TransactionPurgeRequest.class);
151 protected <R extends TransactionRequest<R>> R testForwardToLocal(final TransactionRequest<?> toForward,
152 final Class<R> expectedMessageClass) {
153 final Consumer<Response<?, ?>> callback = createCallbackMock();
154 final TransactionTester<LocalReadWriteProxyTransaction> transactionTester = createLocalProxy();
155 final LocalReadWriteProxyTransaction successor = transactionTester.getTransaction();
156 transaction.forwardToLocal(successor, toForward, callback);
157 return transactionTester.expectTransactionRequest(expectedMessageClass);
161 * To emulate side effect of void method.
162 * {@link CursorAwareDataTreeModification#applyToCursor(DataTreeModificationCursor)}
164 * @param invocation invocation
165 * @return void - always null
167 protected static final <T> Answer<T> applyToCursorAnswer(final InvocationOnMock invocation) {
168 final DataTreeModificationCursor cursor = invocation.getArgument(0);
169 cursor.write(PATH_1.getLastPathArgument(), DATA_1);
170 cursor.merge(PATH_2.getLastPathArgument(), DATA_2);
171 cursor.delete(PATH_3.getLastPathArgument());