Add AbstractDataStoreClientBehavior unit tests
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / test / java / org / opendaylight / controller / cluster / databroker / actors / dds / AbstractDataStoreClientBehaviorTest.java
1 /*
2  * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.cluster.databroker.actors.dds;
9
10 import static org.mockito.Mockito.mock;
11 import static org.mockito.Mockito.verify;
12 import static org.mockito.Mockito.when;
13
14 import akka.actor.ActorRef;
15 import akka.actor.ActorSelection;
16 import akka.actor.ActorSystem;
17 import akka.actor.Status;
18 import akka.testkit.JavaTestKit;
19 import akka.testkit.TestProbe;
20 import java.util.Collections;
21 import org.junit.After;
22 import org.junit.Assert;
23 import org.junit.Before;
24 import org.junit.Test;
25 import org.opendaylight.controller.cluster.access.client.AbstractClientConnection;
26 import org.opendaylight.controller.cluster.access.client.AccessClientUtil;
27 import org.opendaylight.controller.cluster.access.client.ClientActorContext;
28 import org.opendaylight.controller.cluster.access.client.InternalCommand;
29 import org.opendaylight.controller.cluster.access.commands.ConnectClientRequest;
30 import org.opendaylight.controller.cluster.access.commands.ConnectClientSuccess;
31 import org.opendaylight.controller.cluster.access.concepts.ClientIdentifier;
32 import org.opendaylight.controller.cluster.access.concepts.FrontendIdentifier;
33 import org.opendaylight.controller.cluster.access.concepts.FrontendType;
34 import org.opendaylight.controller.cluster.access.concepts.MemberName;
35 import org.opendaylight.controller.cluster.datastore.messages.PrimaryShardInfo;
36 import org.opendaylight.controller.cluster.datastore.utils.ActorContext;
37 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
38 import org.opendaylight.yangtools.yang.data.api.schema.tree.CursorAwareDataTreeModification;
39 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
40 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
41 import scala.concurrent.Promise;
42
43 public abstract class AbstractDataStoreClientBehaviorTest {
44
45     protected static final String SHARD = "default";
46     private static final MemberName MEMBER_NAME = MemberName.forName("member-1");
47     private static final FrontendType FRONTEND_TYPE = FrontendType.forName("type-1");
48     private static final FrontendIdentifier FRONTEND_ID = FrontendIdentifier.create(MEMBER_NAME, FRONTEND_TYPE);
49     private static final ClientIdentifier CLIENT_ID = ClientIdentifier.create(FRONTEND_ID, 0);
50     private static final String PERSISTENCE_ID = "per-1";
51
52     private ActorSystem system;
53     private ClientActorContext clientContext;
54     private TestProbe clientActorProbe;
55     private TestProbe actorContextProbe;
56     private AbstractDataStoreClientBehavior behavior;
57
58     @Before
59     public void setUp() throws Exception {
60         system = ActorSystem.apply();
61         clientActorProbe = new TestProbe(system, "client");
62         actorContextProbe = new TestProbe(system, "actor-context");
63         final ActorContext context = createActorContextMock(system, actorContextProbe.ref());
64         clientContext =
65                 AccessClientUtil.createClientActorContext(system, clientActorProbe.ref(), CLIENT_ID, PERSISTENCE_ID);
66         behavior = createBehavior(clientContext, context);
67     }
68
69     protected abstract AbstractDataStoreClientBehavior createBehavior(ClientActorContext clientContext,
70                                                                       ActorContext context);
71
72     @After
73     public void tearDown() throws Exception {
74         JavaTestKit.shutdownActorSystem(system);
75     }
76
77     @Test
78     public void testResolveShardForPath() throws Exception {
79         Assert.assertEquals(0L, behavior.resolveShardForPath(YangInstanceIdentifier.EMPTY).longValue());
80     }
81
82     @Test
83     public void testHaltClient() throws Exception {
84         behavior.haltClient(new RuntimeException());
85     }
86
87     @Test
88     public void testOnCommand() throws Exception {
89         final TestProbe probe = new TestProbe(system);
90         final GetClientRequest request = new GetClientRequest(probe.ref());
91         final AbstractDataStoreClientBehavior nextBehavior = behavior.onCommand(request);
92         final Status.Success success = probe.expectMsgClass(Status.Success.class);
93         Assert.assertEquals(behavior, success.status());
94         Assert.assertSame(behavior, nextBehavior);
95     }
96
97     @Test
98     public void testOnCommandUnhandled() throws Exception {
99         final AbstractDataStoreClientBehavior nextBehavior = behavior.onCommand("unhandled");
100         Assert.assertSame(behavior, nextBehavior);
101     }
102
103     @Test
104     public void testCreateLocalHistory() throws Exception {
105         final ClientLocalHistory history = behavior.createLocalHistory();
106         Assert.assertEquals(behavior.getIdentifier(), history.getIdentifier().getClientId());
107     }
108
109     @Test
110     public void testCreateTransaction() throws Exception {
111         final ClientTransaction transaction = behavior.createTransaction();
112         Assert.assertEquals(behavior.getIdentifier(), transaction.getIdentifier().getHistoryId().getClientId());
113     }
114
115     @Test
116     public void testCreateSnapshot() throws Exception {
117         final ClientSnapshot snapshot = behavior.createSnapshot();
118         Assert.assertEquals(behavior.getIdentifier(), snapshot.getIdentifier().getHistoryId().getClientId());
119     }
120
121     @Test
122     public void testClose() throws Exception {
123         behavior.close();
124         final InternalCommand<ShardBackendInfo> internalCommand =
125                 clientActorProbe.expectMsgClass(InternalCommand.class);
126         internalCommand.execute(behavior);
127         try {
128             behavior.createLocalHistory();
129             Assert.fail("Behavior is closed and shouldn't allow to create new history.");
130         } catch (final IllegalStateException e) {
131             //ok
132         }
133     }
134
135     @Test
136     public void testGetIdentifier() throws Exception {
137         Assert.assertEquals(CLIENT_ID, behavior.getIdentifier());
138     }
139
140     @Test
141     public void testGetConnection() throws Exception {
142         //set up data tree mock
143         final CursorAwareDataTreeModification modification = mock(CursorAwareDataTreeModification.class);
144         when(modification.readNode(YangInstanceIdentifier.EMPTY)).thenReturn(com.google.common.base.Optional.absent());
145         final DataTreeSnapshot snapshot = mock(DataTreeSnapshot.class);
146         when(snapshot.newModification()).thenReturn(modification);
147         final DataTree dataTree = mock(DataTree.class);
148         when(dataTree.takeSnapshot()).thenReturn(snapshot);
149
150         final TestProbe backendProbe = new TestProbe(system, "backend");
151         final long shard = 0L;
152         behavior.createTransaction().read(YangInstanceIdentifier.EMPTY);
153         final AbstractClientConnection<ShardBackendInfo> connection = behavior.getConnection(shard);
154         //check cached connection for same shard
155         Assert.assertSame(connection, behavior.getConnection(shard));
156
157         final ConnectClientRequest connectClientRequest = actorContextProbe.expectMsgClass(ConnectClientRequest.class);
158         Assert.assertEquals(CLIENT_ID, connectClientRequest.getTarget());
159         final long sequence = 0L;
160         Assert.assertEquals(sequence, connectClientRequest.getSequence());
161         actorContextProbe.reply(new ConnectClientSuccess(CLIENT_ID, sequence, backendProbe.ref(),
162                 Collections.emptyList(), dataTree, 3));
163         Assert.assertEquals(clientActorProbe.ref(), connection.localActor());
164         //capture and execute command passed to client context
165         final InternalCommand<ShardBackendInfo> command = clientActorProbe.expectMsgClass(InternalCommand.class);
166         command.execute(behavior);
167         //check, whether command was reaplayed
168         verify(modification).readNode(YangInstanceIdentifier.EMPTY);
169     }
170
171     private static ActorContext createActorContextMock(final ActorSystem system, final ActorRef actor) {
172         final ActorContext mock = mock(ActorContext.class);
173         final Promise<PrimaryShardInfo> promise = new scala.concurrent.impl.Promise.DefaultPromise<>();
174         final ActorSelection selection = system.actorSelection(actor.path());
175         final PrimaryShardInfo shardInfo = new PrimaryShardInfo(selection, (short) 0);
176         promise.success(shardInfo);
177         when(mock.findPrimaryShardAsync(SHARD)).thenReturn(promise.future());
178         return mock;
179     }
180
181 }