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.Matchers.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.function.Consumer;
19 import org.junit.Assert;
20 import org.junit.Test;
21 import org.mockito.ArgumentCaptor;
22 import org.mockito.invocation.InvocationOnMock;
23 import org.mockito.stubbing.Answer;
24 import org.opendaylight.controller.cluster.access.client.ClientActorBehavior;
25 import org.opendaylight.controller.cluster.access.client.InternalCommand;
26 import org.opendaylight.controller.cluster.access.commands.AbortLocalTransactionRequest;
27 import org.opendaylight.controller.cluster.access.commands.CommitLocalTransactionRequest;
28 import org.opendaylight.controller.cluster.access.commands.ExistsTransactionRequest;
29 import org.opendaylight.controller.cluster.access.commands.ExistsTransactionSuccess;
30 import org.opendaylight.controller.cluster.access.commands.ModifyTransactionRequest;
31 import org.opendaylight.controller.cluster.access.commands.PersistenceProtocol;
32 import org.opendaylight.controller.cluster.access.commands.ReadTransactionRequest;
33 import org.opendaylight.controller.cluster.access.commands.ReadTransactionSuccess;
34 import org.opendaylight.controller.cluster.access.commands.TransactionPurgeRequest;
35 import org.opendaylight.controller.cluster.access.commands.TransactionRequest;
36 import org.opendaylight.controller.cluster.access.concepts.Response;
37 import org.opendaylight.yangtools.yang.data.api.schema.tree.CursorAwareDataTreeModification;
38 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModificationCursor;
40 public abstract class LocalProxyTransactionTest<T extends LocalProxyTransaction>
41 extends AbstractProxyTransactionTest<T> {
45 public void testExists() throws Exception {
46 assertFutureEquals(true, transaction.exists(PATH_1));
47 assertFutureEquals(false, transaction.exists(PATH_3));
52 public void testRead() throws Exception {
53 assertFutureEquals(com.google.common.base.Optional.of(DATA_1), transaction.read(PATH_1));
54 assertFutureEquals(com.google.common.base.Optional.absent(), transaction.read(PATH_3));
58 public void testAbort() throws Exception {
60 getTester().expectTransactionRequest(AbortLocalTransactionRequest.class);
63 @SuppressWarnings("unchecked")
64 private void setupExecuteInActor() {
66 inv.getArgumentAt(0, InternalCommand.class).execute(mock(ClientActorBehavior.class));
68 }).when(context).executeInActor(any(InternalCommand.class));
72 public void testHandleForwardedRemoteReadRequest() throws Exception {
73 final TestProbe probe = createProbe();
74 final ReadTransactionRequest request =
75 new ReadTransactionRequest(TRANSACTION_ID, 0L, probe.ref(), PATH_1, true);
76 final Consumer<Response<?, ?>> callback = createCallbackMock();
77 setupExecuteInActor();
79 transaction.handleReplayedRemoteRequest(request, callback, Ticker.systemTicker().read());
80 final ArgumentCaptor<Response> captor = ArgumentCaptor.forClass(Response.class);
81 verify(callback).accept(captor.capture());
82 final Response value = captor.getValue();
83 Assert.assertTrue(value instanceof ReadTransactionSuccess);
84 final ReadTransactionSuccess success = (ReadTransactionSuccess) value;
85 Assert.assertTrue(success.getData().isPresent());
86 Assert.assertEquals(DATA_1, success.getData().get());
90 public void testHandleForwardedRemoteExistsRequest() throws Exception {
91 final TestProbe probe = createProbe();
92 final ExistsTransactionRequest request =
93 new ExistsTransactionRequest(TRANSACTION_ID, 0L, probe.ref(), PATH_1, true);
94 final Consumer<Response<?, ?>> callback = createCallbackMock();
95 setupExecuteInActor();
97 transaction.handleReplayedRemoteRequest(request, callback, Ticker.systemTicker().read());
98 final ArgumentCaptor<Response> captor = ArgumentCaptor.forClass(Response.class);
99 verify(callback).accept(captor.capture());
100 final Response value = captor.getValue();
101 Assert.assertTrue(value instanceof ExistsTransactionSuccess);
102 final ExistsTransactionSuccess success = (ExistsTransactionSuccess) value;
103 Assert.assertTrue(success.getExists());
107 public void testHandleForwardedRemotePurgeRequest() throws Exception {
108 final TestProbe probe = createProbe();
109 final TransactionPurgeRequest request =
110 new TransactionPurgeRequest(TRANSACTION_ID, 0L, probe.ref());
111 testHandleForwardedRemoteRequest(request);
116 public void testForwardToRemoteAbort() throws Exception {
117 final TestProbe probe = createProbe();
118 final AbortLocalTransactionRequest request = new AbortLocalTransactionRequest(TRANSACTION_ID, probe.ref());
119 final ModifyTransactionRequest modifyRequest = testForwardToRemote(request, ModifyTransactionRequest.class);
120 Assert.assertTrue(modifyRequest.getPersistenceProtocol().isPresent());
121 Assert.assertEquals(PersistenceProtocol.ABORT, modifyRequest.getPersistenceProtocol().get());
126 public void testForwardToRemoteCommit() throws Exception {
127 final TestProbe probe = createProbe();
128 final CursorAwareDataTreeModification modification = mock(CursorAwareDataTreeModification.class);
129 final CommitLocalTransactionRequest request =
130 new CommitLocalTransactionRequest(TRANSACTION_ID, 0L, probe.ref(), modification, null, true);
131 doAnswer(this::applyToCursorAnswer).when(modification).applyToCursor(any());
132 final ModifyTransactionRequest modifyRequest = testForwardToRemote(request, ModifyTransactionRequest.class);
133 verify(modification).applyToCursor(any());
134 Assert.assertTrue(modifyRequest.getPersistenceProtocol().isPresent());
135 Assert.assertEquals(PersistenceProtocol.THREE_PHASE, modifyRequest.getPersistenceProtocol().get());
136 checkModifications(modifyRequest);
140 public void testForwardToLocalAbort() throws Exception {
141 final TestProbe probe = createProbe();
142 final AbortLocalTransactionRequest request = new AbortLocalTransactionRequest(TRANSACTION_ID, probe.ref());
143 testForwardToLocal(request, AbortLocalTransactionRequest.class);
147 public void testForwardToLocalPurge() throws Exception {
148 final TestProbe probe = createProbe();
149 final TransactionPurgeRequest request = new TransactionPurgeRequest(TRANSACTION_ID, 0L, probe.ref());
150 testForwardToLocal(request, TransactionPurgeRequest.class);
153 protected <T extends TransactionRequest> T testForwardToLocal(final TransactionRequest toForward,
154 final Class<T> expectedMessageClass) {
155 final Consumer<Response<?, ?>> callback = createCallbackMock();
156 final TransactionTester<LocalReadWriteProxyTransaction> transactionTester = createLocalProxy();
157 final LocalReadWriteProxyTransaction successor = transactionTester.getTransaction();
158 transaction.forwardToLocal(successor, toForward, callback);
159 return transactionTester.expectTransactionRequest(expectedMessageClass);
163 * To emulate side effect of void method.
164 * {@link CursorAwareDataTreeModification#applyToCursor(DataTreeModificationCursor)}
166 * @param invocation invocation
167 * @return void - always null
169 protected Answer applyToCursorAnswer(final InvocationOnMock invocation) {
170 final DataTreeModificationCursor cursor =
171 invocation.getArgumentAt(0, DataTreeModificationCursor.class);
172 cursor.write(PATH_1.getLastPathArgument(), DATA_1);
173 cursor.merge(PATH_2.getLastPathArgument(), DATA_2);
174 cursor.delete(PATH_3.getLastPathArgument());