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.netconf;
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertFalse;
12 import static org.junit.Assert.assertTrue;
13 import static org.junit.Assert.fail;
15 import akka.actor.ActorSystem;
16 import akka.actor.Status;
17 import akka.dispatch.Futures;
18 import akka.testkit.TestProbe;
19 import akka.testkit.javadsl.TestKit;
20 import akka.util.Timeout;
21 import com.google.common.util.concurrent.ListenableFuture;
22 import java.net.InetSocketAddress;
23 import java.util.Collections;
24 import java.util.Optional;
25 import java.util.concurrent.ExecutionException;
26 import java.util.concurrent.TimeUnit;
27 import java.util.concurrent.TimeoutException;
28 import org.junit.AfterClass;
29 import org.junit.Before;
30 import org.junit.Test;
31 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
32 import org.opendaylight.mdsal.common.api.ReadFailedException;
33 import org.opendaylight.netconf.api.DocumentedException;
34 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
35 import org.opendaylight.netconf.topology.singleton.messages.NormalizedNodeMessage;
36 import org.opendaylight.netconf.topology.singleton.messages.netconf.CommitRequest;
37 import org.opendaylight.netconf.topology.singleton.messages.netconf.CreateEditConfigRequest;
38 import org.opendaylight.netconf.topology.singleton.messages.netconf.DeleteEditConfigRequest;
39 import org.opendaylight.netconf.topology.singleton.messages.netconf.DiscardChangesRequest;
40 import org.opendaylight.netconf.topology.singleton.messages.netconf.GetConfigRequest;
41 import org.opendaylight.netconf.topology.singleton.messages.netconf.GetRequest;
42 import org.opendaylight.netconf.topology.singleton.messages.netconf.LockRequest;
43 import org.opendaylight.netconf.topology.singleton.messages.netconf.MergeEditConfigRequest;
44 import org.opendaylight.netconf.topology.singleton.messages.netconf.RemoveEditConfigRequest;
45 import org.opendaylight.netconf.topology.singleton.messages.netconf.ReplaceEditConfigRequest;
46 import org.opendaylight.netconf.topology.singleton.messages.netconf.UnlockRequest;
47 import org.opendaylight.netconf.topology.singleton.messages.rpc.InvokeRpcMessageReply;
48 import org.opendaylight.netconf.topology.singleton.messages.transactions.EmptyReadResponse;
49 import org.opendaylight.yangtools.yang.common.ErrorSeverity;
50 import org.opendaylight.yangtools.yang.common.ErrorType;
51 import org.opendaylight.yangtools.yang.common.QName;
52 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
53 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
54 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
55 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
57 public class ProxyNetconfServiceTest {
58 private static final RemoteDeviceId DEVICE_ID =
59 new RemoteDeviceId("dev1", InetSocketAddress.createUnresolved("localhost", 17830));
60 private static final YangInstanceIdentifier PATH = YangInstanceIdentifier.empty();
61 private static final LogicalDatastoreType STORE = LogicalDatastoreType.CONFIGURATION;
63 private static ActorSystem system = ActorSystem.apply();
64 private TestProbe masterActor;
65 private ContainerNode node;
69 masterActor = new TestProbe(system);
70 node = Builders.containerBuilder()
71 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create("", "cont")))
76 public static void staticTearDown() {
77 TestKit.shutdownActorSystem(system, true);
80 private ProxyNetconfService newSuccessfulProxyNetconfService() {
81 return new ProxyNetconfService(DEVICE_ID, Futures.successful(masterActor.ref()),
82 system.dispatcher(), Timeout.apply(5, TimeUnit.SECONDS));
85 private ProxyNetconfService newSuccessfulProxyNetconfService(final Timeout timeout) {
86 return new ProxyNetconfService(DEVICE_ID, Futures.successful(masterActor.ref()),
87 system.dispatcher(), timeout);
91 public void testLock() {
92 ProxyNetconfService netconf = newSuccessfulProxyNetconfService();
94 masterActor.expectMsgClass(LockRequest.class);
98 public void testUnlock() {
99 ProxyNetconfService netconf = newSuccessfulProxyNetconfService();
101 masterActor.expectMsgClass(UnlockRequest.class);
105 public void testDiscardChanges() {
106 ProxyNetconfService netconf = newSuccessfulProxyNetconfService();
107 netconf.discardChanges();
108 masterActor.expectMsgClass(DiscardChangesRequest.class);
112 public void testGet() throws Exception {
113 ProxyNetconfService netconf = newSuccessfulProxyNetconfService();
114 final ListenableFuture<Optional<NormalizedNode>> get = netconf.get(PATH);
115 final GetRequest getRequest = masterActor.expectMsgClass(GetRequest.class);
116 assertEquals(PATH, getRequest.getPath());
118 masterActor.reply(new NormalizedNodeMessage(PATH, node));
119 final Optional<NormalizedNode> result = get.get(5, TimeUnit.SECONDS);
120 assertTrue(result.isPresent());
121 assertEquals(node, result.get());
125 public void testGetFailure() throws InterruptedException, TimeoutException {
126 ProxyNetconfService netconf = newSuccessfulProxyNetconfService();
128 final ListenableFuture<Optional<NormalizedNode>> get = netconf.get(PATH);
129 masterActor.expectMsgClass(GetRequest.class);
130 final RuntimeException mockEx = new RuntimeException("fail");
131 masterActor.reply(new Status.Failure(mockEx));
134 get.get(5, TimeUnit.SECONDS);
135 fail("Exception should be thrown");
136 } catch (final ExecutionException e) {
137 Throwable cause = e.getCause();
138 assertTrue("Unexpected cause " + cause, cause instanceof ReadFailedException);
139 assertEquals(mockEx, cause.getCause());
144 public void testGetEmpty() throws Exception {
145 ProxyNetconfService netconf = newSuccessfulProxyNetconfService();
146 final ListenableFuture<Optional<NormalizedNode>> get = netconf.get(PATH);
147 masterActor.expectMsgClass(GetRequest.class);
148 masterActor.reply(new EmptyReadResponse());
149 final Optional<NormalizedNode> result = get.get(5, TimeUnit.SECONDS);
150 assertFalse(result.isPresent());
154 public void testGetConfig() throws Exception {
155 ProxyNetconfService netconf = newSuccessfulProxyNetconfService();
156 final ListenableFuture<Optional<NormalizedNode>> getConfig = netconf.getConfig(PATH);
157 final GetConfigRequest getRequest = masterActor.expectMsgClass(GetConfigRequest.class);
158 assertEquals(PATH, getRequest.getPath());
160 masterActor.reply(new NormalizedNodeMessage(PATH, node));
161 final Optional<NormalizedNode> result = getConfig.get(5, TimeUnit.SECONDS);
162 assertTrue(result.isPresent());
163 assertEquals(node, result.get());
167 public void testGetConfigFailure() throws InterruptedException, TimeoutException {
168 ProxyNetconfService netconf = newSuccessfulProxyNetconfService();
170 final ListenableFuture<Optional<NormalizedNode>> getConfig = netconf.getConfig(PATH);
171 masterActor.expectMsgClass(GetConfigRequest.class);
172 final RuntimeException mockEx = new RuntimeException("fail");
173 masterActor.reply(new Status.Failure(mockEx));
176 getConfig.get(5, TimeUnit.SECONDS);
177 fail("Exception should be thrown");
178 } catch (final ExecutionException e) {
179 Throwable cause = e.getCause();
180 assertTrue("Unexpected cause " + cause, cause instanceof ReadFailedException);
181 assertEquals(mockEx, cause.getCause());
186 public void testGetConfigEmpty() throws Exception {
187 ProxyNetconfService netconf = newSuccessfulProxyNetconfService();
188 final ListenableFuture<Optional<NormalizedNode>> getConfig = netconf.getConfig(PATH);
189 masterActor.expectMsgClass(GetConfigRequest.class);
190 masterActor.reply(new EmptyReadResponse());
191 final Optional<NormalizedNode> result = getConfig.get(5, TimeUnit.SECONDS);
192 assertFalse(result.isPresent());
196 public void testMerge() {
197 ProxyNetconfService netconf = newSuccessfulProxyNetconfService();
198 netconf.merge(STORE, PATH, node, Optional.empty());
199 final MergeEditConfigRequest mergeRequest = masterActor.expectMsgClass(MergeEditConfigRequest.class);
200 assertEquals(STORE, mergeRequest.getStore());
201 assertEquals(PATH, mergeRequest.getNormalizedNodeMessage().getIdentifier());
202 assertEquals(node, mergeRequest.getNormalizedNodeMessage().getNode());
206 public void testReplace() {
207 ProxyNetconfService netconf = newSuccessfulProxyNetconfService();
208 netconf.replace(STORE, PATH, node, Optional.empty());
209 final ReplaceEditConfigRequest replaceRequest = masterActor.expectMsgClass(ReplaceEditConfigRequest.class);
210 assertEquals(STORE, replaceRequest.getStore());
211 assertEquals(PATH, replaceRequest.getNormalizedNodeMessage().getIdentifier());
212 assertEquals(node, replaceRequest.getNormalizedNodeMessage().getNode());
216 public void testCreate() {
217 ProxyNetconfService netconf = newSuccessfulProxyNetconfService();
218 netconf.create(STORE, PATH, node, Optional.empty());
219 final CreateEditConfigRequest createRequest = masterActor.expectMsgClass(CreateEditConfigRequest.class);
220 assertEquals(STORE, createRequest.getStore());
221 assertEquals(PATH, createRequest.getNormalizedNodeMessage().getIdentifier());
222 assertEquals(node, createRequest.getNormalizedNodeMessage().getNode());
226 public void testDelete() {
227 ProxyNetconfService netconf = newSuccessfulProxyNetconfService();
228 netconf.delete(STORE, PATH);
229 final DeleteEditConfigRequest deleteRequest = masterActor.expectMsgClass(DeleteEditConfigRequest.class);
230 assertEquals(STORE, deleteRequest.getStore());
231 assertEquals(PATH, deleteRequest.getPath());
235 public void testRemove() {
236 ProxyNetconfService netconf = newSuccessfulProxyNetconfService();
237 netconf.remove(STORE, PATH);
238 final RemoveEditConfigRequest removeRequest = masterActor.expectMsgClass(RemoveEditConfigRequest.class);
239 assertEquals(STORE, removeRequest.getStore());
240 assertEquals(PATH, removeRequest.getPath());
244 public void testCommit() throws InterruptedException, ExecutionException, TimeoutException {
245 ProxyNetconfService netconf = newSuccessfulProxyNetconfService();
250 public void testFutureOperationsWithMasterDown() throws InterruptedException, TimeoutException {
251 ProxyNetconfService netconf = newSuccessfulProxyNetconfService(
252 Timeout.apply(500, TimeUnit.MILLISECONDS));
254 ListenableFuture<?> future = netconf.get(PATH);
255 masterActor.expectMsgClass(GetRequest.class);
257 // master doesn't reply
259 future.get(5, TimeUnit.SECONDS);
260 fail("Exception should be thrown");
261 } catch (final ExecutionException e) {
262 Throwable cause = e.getCause();
263 assertTrue("Unexpected cause " + cause, cause instanceof ReadFailedException);
264 verifyDocumentedException(cause.getCause());
267 future = netconf.getConfig(PATH);
268 masterActor.expectMsgClass(GetConfigRequest.class);
270 // master doesn't reply
272 future.get(5, TimeUnit.SECONDS);
273 fail("Exception should be thrown");
274 } catch (final ExecutionException e) {
275 Throwable cause = e.getCause();
276 assertTrue("Unexpected cause " + cause, cause instanceof ReadFailedException);
277 verifyDocumentedException(cause.getCause());
280 future = netconf.commit();
281 masterActor.expectMsgClass(CommitRequest.class);
283 // master doesn't reply
285 future.get(5, TimeUnit.SECONDS);
286 fail("Exception should be thrown");
287 } catch (final ExecutionException e) {
288 Throwable cause = e.getCause();
289 assertTrue("Unexpected cause " + cause, cause instanceof NetconfServiceFailedException);
290 verifyDocumentedException(cause.getCause());
294 private void commit(final ProxyNetconfService netconf)
295 throws InterruptedException, ExecutionException, TimeoutException {
296 final ListenableFuture<?> submit = netconf.commit();
297 masterActor.expectMsgClass(CommitRequest.class);
298 masterActor.reply(new InvokeRpcMessageReply(null, Collections.emptyList()));
299 submit.get(5, TimeUnit.SECONDS);
302 private static void verifyDocumentedException(final Throwable cause) {
303 assertTrue("Unexpected cause " + cause, cause instanceof DocumentedException);
304 final DocumentedException de = (DocumentedException) cause;
305 assertEquals(ErrorSeverity.WARNING, de.getErrorSeverity());
306 assertEquals(DocumentedException.ErrorTag.OPERATION_FAILED, de.getErrorTag());
307 assertEquals(ErrorType.APPLICATION, de.getErrorType());