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.assertSame;
12 import static org.junit.Assert.assertThrows;
13 import static org.mockito.Mockito.doReturn;
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.CLIENT_ID;
18 import akka.actor.ActorRef;
19 import akka.actor.ActorSelection;
20 import akka.actor.ActorSystem;
21 import akka.actor.Status;
22 import akka.testkit.TestProbe;
23 import akka.testkit.javadsl.TestKit;
24 import java.util.List;
25 import java.util.Optional;
26 import org.junit.After;
27 import org.junit.Before;
28 import org.junit.Test;
29 import org.opendaylight.controller.cluster.access.client.AbstractClientConnection;
30 import org.opendaylight.controller.cluster.access.client.AccessClientUtil;
31 import org.opendaylight.controller.cluster.access.client.ClientActorContext;
32 import org.opendaylight.controller.cluster.access.client.InternalCommand;
33 import org.opendaylight.controller.cluster.access.commands.ConnectClientRequest;
34 import org.opendaylight.controller.cluster.access.commands.ConnectClientSuccess;
35 import org.opendaylight.controller.cluster.datastore.messages.PrimaryShardInfo;
36 import org.opendaylight.controller.cluster.datastore.utils.ActorUtils;
37 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
38 import org.opendaylight.yangtools.yang.data.tree.api.CursorAwareDataTreeModification;
39 import org.opendaylight.yangtools.yang.data.tree.api.DataTree;
40 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeSnapshot;
41 import scala.concurrent.Promise;
43 public abstract class AbstractDataStoreClientBehaviorTest {
45 protected static final String SHARD = "default";
46 private static final String PERSISTENCE_ID = "per-1";
48 private ActorSystem system;
49 private ClientActorContext clientContext;
50 private TestProbe clientActorProbe;
51 private TestProbe actorContextProbe;
52 private AbstractDataStoreClientBehavior behavior;
56 system = ActorSystem.apply();
57 clientActorProbe = new TestProbe(system, "client");
58 actorContextProbe = new TestProbe(system, "actor-context");
59 final ActorUtils context = createActorContextMock(system, actorContextProbe.ref());
61 AccessClientUtil.createClientActorContext(system, clientActorProbe.ref(), CLIENT_ID, PERSISTENCE_ID);
62 behavior = createBehavior(clientContext, context);
65 @SuppressWarnings("checkstyle:hiddenField")
66 protected abstract AbstractDataStoreClientBehavior createBehavior(ClientActorContext clientContext,
70 public void tearDown() {
71 TestKit.shutdownActorSystem(system);
75 public void testResolveShardForPath() {
76 assertEquals(0L, behavior.resolveShardForPath(YangInstanceIdentifier.empty()).longValue());
80 public void testHaltClient() {
81 behavior.haltClient(new RuntimeException());
85 public void testOnCommand() {
86 final TestProbe probe = new TestProbe(system);
87 final GetClientRequest request = new GetClientRequest(probe.ref());
88 final AbstractDataStoreClientBehavior nextBehavior = behavior.onCommand(request);
89 final Status.Success success = probe.expectMsgClass(Status.Success.class);
90 assertEquals(behavior, success.status());
91 assertSame(behavior, nextBehavior);
95 public void testOnCommandUnhandled() {
96 final AbstractDataStoreClientBehavior nextBehavior = behavior.onCommand("unhandled");
97 assertSame(behavior, nextBehavior);
101 public void testCreateLocalHistory() {
102 final ClientLocalHistory history = behavior.createLocalHistory();
103 assertEquals(behavior.getIdentifier(), history.getIdentifier().getClientId());
107 public void testCreateTransaction() {
108 final ClientTransaction transaction = behavior.createTransaction();
109 assertEquals(behavior.getIdentifier(), transaction.getIdentifier().getHistoryId().getClientId());
113 public void testCreateSnapshot() {
114 final ClientSnapshot snapshot = behavior.createSnapshot();
115 assertEquals(behavior.getIdentifier(), snapshot.getIdentifier().getHistoryId().getClientId());
119 public void testClose() {
121 final InternalCommand<ShardBackendInfo> internalCommand =
122 clientActorProbe.expectMsgClass(InternalCommand.class);
123 internalCommand.execute(behavior);
125 assertThrows(IllegalStateException.class, () -> behavior.createLocalHistory());
129 public void testGetIdentifier() {
130 assertEquals(CLIENT_ID, behavior.getIdentifier());
134 public void testGetConnection() {
135 //set up data tree mock
136 final CursorAwareDataTreeModification modification = mock(CursorAwareDataTreeModification.class);
137 doReturn(Optional.empty()).when(modification).readNode(YangInstanceIdentifier.empty());
138 final DataTreeSnapshot snapshot = mock(DataTreeSnapshot.class);
139 doReturn(modification).when(snapshot).newModification();
140 final DataTree dataTree = mock(DataTree.class);
141 doReturn(snapshot).when(dataTree).takeSnapshot();
143 final TestProbe backendProbe = new TestProbe(system, "backend");
144 final long shard = 0L;
146 behavior.createTransaction().read(YangInstanceIdentifier.empty());
147 final AbstractClientConnection<ShardBackendInfo> connection = behavior.getConnection(shard);
148 //check cached connection for same shard
149 assertSame(connection, behavior.getConnection(shard));
151 final ConnectClientRequest connectClientRequest = actorContextProbe.expectMsgClass(ConnectClientRequest.class);
152 assertEquals(CLIENT_ID, connectClientRequest.getTarget());
153 final long sequence = 0L;
154 assertEquals(sequence, connectClientRequest.getSequence());
155 actorContextProbe.reply(new ConnectClientSuccess(CLIENT_ID, sequence, backendProbe.ref(), List.of(), dataTree,
157 assertEquals(clientActorProbe.ref(), connection.localActor());
158 //capture and execute command passed to client context
159 final InternalCommand<ShardBackendInfo> command = clientActorProbe.expectMsgClass(InternalCommand.class);
160 command.execute(behavior);
161 //check, whether command was reaplayed
162 verify(modification).readNode(YangInstanceIdentifier.empty());
165 private static ActorUtils createActorContextMock(final ActorSystem system, final ActorRef actor) {
166 final ActorUtils mock = mock(ActorUtils.class);
167 final Promise<PrimaryShardInfo> promise = new scala.concurrent.impl.Promise.DefaultPromise<>();
168 final ActorSelection selection = system.actorSelection(actor.path());
169 final PrimaryShardInfo shardInfo = new PrimaryShardInfo(selection, (short) 0);
170 promise.success(shardInfo);
171 doReturn(promise.future()).when(mock).findPrimaryShardAsync(SHARD);