2 * Copyright (c) 2020 PANTHEON.tech, 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.netconf.topology.singleton.impl.actors;
10 import static org.junit.Assert.assertEquals;
11 import static org.mockito.Mockito.doReturn;
12 import static org.mockito.Mockito.timeout;
13 import static org.mockito.Mockito.verify;
14 import static org.mockito.Mockito.when;
15 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFailedFluentFuture;
16 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture;
18 import akka.actor.ActorRef;
19 import akka.actor.ActorSystem;
20 import akka.actor.Status;
21 import akka.testkit.TestActorRef;
22 import akka.testkit.TestProbe;
23 import akka.testkit.javadsl.TestKit;
24 import akka.util.Timeout;
25 import com.google.common.util.concurrent.Futures;
26 import com.google.common.util.concurrent.ListenableFuture;
27 import java.time.Duration;
28 import java.util.Optional;
29 import java.util.concurrent.TimeUnit;
30 import org.junit.AfterClass;
31 import org.junit.Before;
32 import org.junit.Test;
33 import org.junit.runner.RunWith;
34 import org.mockito.Mock;
35 import org.mockito.junit.MockitoJUnitRunner;
36 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
37 import org.opendaylight.mdsal.common.api.ReadFailedException;
38 import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
39 import org.opendaylight.mdsal.dom.api.DOMRpcResult;
40 import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult;
41 import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
42 import org.opendaylight.netconf.topology.singleton.impl.netconf.NetconfServiceFailedException;
43 import org.opendaylight.netconf.topology.singleton.messages.NormalizedNodeMessage;
44 import org.opendaylight.netconf.topology.singleton.messages.netconf.CommitRequest;
45 import org.opendaylight.netconf.topology.singleton.messages.netconf.CreateEditConfigRequest;
46 import org.opendaylight.netconf.topology.singleton.messages.netconf.DeleteEditConfigRequest;
47 import org.opendaylight.netconf.topology.singleton.messages.netconf.GetConfigRequest;
48 import org.opendaylight.netconf.topology.singleton.messages.netconf.GetRequest;
49 import org.opendaylight.netconf.topology.singleton.messages.netconf.LockRequest;
50 import org.opendaylight.netconf.topology.singleton.messages.netconf.MergeEditConfigRequest;
51 import org.opendaylight.netconf.topology.singleton.messages.netconf.RemoveEditConfigRequest;
52 import org.opendaylight.netconf.topology.singleton.messages.netconf.ReplaceEditConfigRequest;
53 import org.opendaylight.netconf.topology.singleton.messages.rpc.InvokeRpcMessageReply;
54 import org.opendaylight.netconf.topology.singleton.messages.transactions.EmptyReadResponse;
55 import org.opendaylight.yangtools.util.concurrent.FluentFutures;
56 import org.opendaylight.yangtools.yang.common.ErrorTag;
57 import org.opendaylight.yangtools.yang.common.ErrorType;
58 import org.opendaylight.yangtools.yang.common.QName;
59 import org.opendaylight.yangtools.yang.common.RpcError;
60 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
61 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
62 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
63 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
64 import org.opendaylight.yangtools.yang.data.spi.node.ImmutableNodes;
66 @RunWith(MockitoJUnitRunner.StrictStubs.class)
67 public class NetconfDataTreeServiceActorTest {
68 static final YangInstanceIdentifier PATH = YangInstanceIdentifier.of();
69 static final LogicalDatastoreType STORE = LogicalDatastoreType.CONFIGURATION;
70 static final Timeout TIMEOUT = Timeout.apply(5, TimeUnit.SECONDS);
71 static final ContainerNode NODE = ImmutableNodes.newContainerBuilder()
72 .withNodeIdentifier(new NodeIdentifier(QName.create("", "cont")))
75 private static ActorSystem system = ActorSystem.apply();
78 private NetconfDataTreeService netconfService;
80 private TestProbe probe;
81 private ActorRef actorRef;
85 actorRef = TestActorRef.create(system,
86 NetconfDataTreeServiceActor.props(netconfService, Duration.ofSeconds(2)));
87 probe = TestProbe.apply(system);
91 public static void staticTearDown() {
92 TestKit.shutdownActorSystem(system, true);
96 public void testGet() {
97 doReturn(immediateFluentFuture(Optional.of(NODE))).when(netconfService).get(PATH);
98 actorRef.tell(new GetRequest(PATH), probe.ref());
100 verify(netconfService).get(PATH);
101 final NormalizedNodeMessage response = probe.expectMsgClass(NormalizedNodeMessage.class);
102 assertEquals(NODE, response.getNode());
106 public void testGetEmpty() {
107 doReturn(immediateFluentFuture(Optional.empty())).when(netconfService).get(PATH);
108 actorRef.tell(new GetRequest(PATH), probe.ref());
110 verify(netconfService).get(PATH);
111 probe.expectMsgClass(EmptyReadResponse.class);
115 public void testGetFailure() {
116 final ReadFailedException cause = new ReadFailedException("fail");
117 doReturn(immediateFailedFluentFuture(cause)).when(netconfService).get(PATH);
118 actorRef.tell(new GetRequest(PATH), probe.ref());
120 verify(netconfService).get(PATH);
121 final Status.Failure response = probe.expectMsgClass(Status.Failure.class);
122 assertEquals(cause, response.cause());
126 public void testGetConfig() {
127 doReturn(immediateFluentFuture(Optional.of(NODE))).when(netconfService).getConfig(PATH);
128 actorRef.tell(new GetConfigRequest(PATH), probe.ref());
130 verify(netconfService).getConfig(PATH);
131 final NormalizedNodeMessage response = probe.expectMsgClass(NormalizedNodeMessage.class);
132 assertEquals(NODE, response.getNode());
136 public void testGetConfigEmpty() {
137 doReturn(immediateFluentFuture(Optional.empty())).when(netconfService).getConfig(PATH);
138 actorRef.tell(new GetConfigRequest(PATH), probe.ref());
140 verify(netconfService).getConfig(PATH);
141 probe.expectMsgClass(EmptyReadResponse.class);
145 public void testGetConfigFailure() {
146 final ReadFailedException cause = new ReadFailedException("fail");
147 doReturn(immediateFailedFluentFuture(cause)).when(netconfService).getConfig(PATH);
148 actorRef.tell(new GetConfigRequest(PATH), probe.ref());
150 verify(netconfService).getConfig(PATH);
151 final Status.Failure response = probe.expectMsgClass(Status.Failure.class);
152 assertEquals(cause, response.cause());
156 public void testLock() {
157 final ListenableFuture<? extends DOMRpcResult> future = Futures.immediateFuture(new DefaultDOMRpcResult());
158 doReturn(future).when(netconfService).lock();
159 actorRef.tell(new LockRequest(), probe.ref());
160 verify(netconfService).lock();
164 public void testMerge() {
165 doReturn(FluentFutures.immediateFluentFuture(new DefaultDOMRpcResult())).when(netconfService)
166 .merge(STORE, PATH, NODE, Optional.empty());
167 final NormalizedNodeMessage node = new NormalizedNodeMessage(PATH, NODE);
168 actorRef.tell(new MergeEditConfigRequest(STORE, node, null), probe.ref());
169 verify(netconfService).merge(STORE, PATH, NODE, Optional.empty());
173 public void testReplace() {
174 doReturn(FluentFutures.immediateFluentFuture(new DefaultDOMRpcResult())).when(netconfService)
175 .replace(STORE, PATH, NODE, Optional.empty());
176 final NormalizedNodeMessage node = new NormalizedNodeMessage(PATH, NODE);
177 actorRef.tell(new ReplaceEditConfigRequest(STORE, node, null), probe.ref());
178 verify(netconfService).replace(STORE, PATH, NODE, Optional.empty());
182 public void testCreate() {
183 doReturn(FluentFutures.immediateFluentFuture(new DefaultDOMRpcResult())).when(netconfService)
184 .create(STORE, PATH, NODE, Optional.empty());
185 final NormalizedNodeMessage node = new NormalizedNodeMessage(PATH, NODE);
186 actorRef.tell(new CreateEditConfigRequest(STORE, node, null), probe.ref());
187 verify(netconfService).create(STORE, PATH, NODE, Optional.empty());
191 public void testDelete() {
192 doReturn(FluentFutures.immediateFluentFuture(new DefaultDOMRpcResult())).when(netconfService)
193 .delete(STORE, PATH);
194 actorRef.tell(new DeleteEditConfigRequest(STORE, PATH), probe.ref());
195 verify(netconfService).delete(STORE, PATH);
199 public void testRemove() {
200 doReturn(FluentFutures.immediateFluentFuture(new DefaultDOMRpcResult())).when(netconfService)
201 .remove(STORE, PATH);
202 actorRef.tell(new RemoveEditConfigRequest(STORE, PATH), probe.ref());
203 verify(netconfService).remove(STORE, PATH);
207 public void testCommit() {
208 doReturn(FluentFutures.immediateFluentFuture(new DefaultDOMRpcResult())).when(netconfService).commit();
209 actorRef.tell(new CommitRequest(), probe.ref());
211 verify(netconfService).commit();
212 probe.expectMsgClass(InvokeRpcMessageReply.class);
216 public void testCommitFail() {
217 final RpcError rpcError = RpcResultBuilder.newError(ErrorType.APPLICATION, new ErrorTag("fail"), "fail");
218 final TransactionCommitFailedException failure = new TransactionCommitFailedException("fail", rpcError);
219 final NetconfServiceFailedException cause = new NetconfServiceFailedException(
220 String.format("%s: Commit of operation failed", 1), failure);
221 when(netconfService.commit()).thenReturn(FluentFutures.immediateFailedFluentFuture(cause));
222 actorRef.tell(new CommitRequest(), probe.ref());
224 verify(netconfService).commit();
225 final Status.Failure response = probe.expectMsgClass(Status.Failure.class);
226 assertEquals(cause, response.cause());
230 public void testIdleTimeout() {
231 final TestProbe testProbe = new TestProbe(system);
232 testProbe.watch(actorRef);
233 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).unlock();
234 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).discardChanges();
235 verify(netconfService, timeout(3000)).discardChanges();
236 verify(netconfService, timeout(3000)).unlock();
237 testProbe.expectTerminated(actorRef, TIMEOUT.duration());