2 * Copyright (c) 2016 Cisco Systems, Inc. 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.restconf.nb.jaxrs;
10 import static org.junit.Assert.assertNull;
11 import static org.junit.jupiter.api.Assertions.assertEquals;
12 import static org.junit.jupiter.api.Assertions.assertSame;
13 import static org.mockito.ArgumentMatchers.any;
14 import static org.mockito.ArgumentMatchers.eq;
15 import static org.mockito.Mockito.doReturn;
16 import static org.mockito.Mockito.mock;
18 import com.google.common.util.concurrent.Futures;
19 import java.util.List;
20 import java.util.Optional;
21 import javax.ws.rs.core.MultivaluedHashMap;
22 import org.junit.jupiter.api.BeforeEach;
23 import org.junit.jupiter.api.Test;
24 import org.junit.jupiter.api.extension.ExtendWith;
25 import org.mockito.Mock;
26 import org.mockito.junit.jupiter.MockitoExtension;
27 import org.opendaylight.mdsal.dom.api.DOMActionService;
28 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
29 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
30 import org.opendaylight.mdsal.dom.api.DOMNotificationService;
31 import org.opendaylight.mdsal.dom.api.DOMRpcImplementationNotAvailableException;
32 import org.opendaylight.mdsal.dom.api.DOMRpcResult;
33 import org.opendaylight.mdsal.dom.api.DOMRpcService;
34 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
35 import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult;
36 import org.opendaylight.mdsal.dom.spi.FixedDOMSchemaService;
37 import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
38 import org.opendaylight.yangtools.yang.common.ErrorTag;
39 import org.opendaylight.yangtools.yang.common.ErrorType;
40 import org.opendaylight.yangtools.yang.common.QName;
41 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
42 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
43 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
44 import org.opendaylight.yangtools.yang.data.spi.node.ImmutableNodes;
45 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
46 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
48 @ExtendWith(MockitoExtension.class)
49 class RestconfOperationsPostTest extends AbstractRestconfTest {
50 private static final QName RPC = QName.create("invoke:rpc:module", "2013-12-03", "rpc-test");
51 private static final ContainerNode INPUT = ImmutableNodes.newContainerBuilder()
52 .withNodeIdentifier(new NodeIdentifier(QName.create(RPC, "input")))
53 .withChild(ImmutableNodes.newContainerBuilder()
54 .withNodeIdentifier(new NodeIdentifier(QName.create(RPC, "cont")))
55 .withChild(ImmutableNodes.leafNode(QName.create(RPC, "lf"), "test"))
58 private static final ContainerNode OUTPUT = ImmutableNodes.newContainerBuilder()
59 .withNodeIdentifier(new NodeIdentifier(QName.create(RPC, "output")))
60 .withChild(ImmutableNodes.newContainerBuilder()
61 .withNodeIdentifier(new NodeIdentifier(QName.create(RPC, "cont-out")))
62 .withChild(ImmutableNodes.leafNode(QName.create(RPC, "lf-out"), "operation result"))
65 private static final EffectiveModelContext MODEL_CONTEXT =
66 YangParserTestUtils.parseYangResourceDirectory("/invoke-rpc");
69 private DOMNotificationService notificationService;
72 EffectiveModelContext modelContext() {
78 doReturn(new MultivaluedHashMap<>()).when(uriInfo).getQueryParameters();
82 void testInvokeRpcWithNonEmptyOutput() {
83 final var result = mock(ContainerNode.class);
84 doReturn(false).when(result).isEmpty();
87 assertSame(result, assertOperationOutput(200, ar -> restconf.operationsXmlPOST(
88 apiPath("invoke-rpc-module:rpc-test"), stringInputStream("""
89 <input xmlns="invoke:rpc:module"/>"""), uriInfo, ar)));
93 void testInvokeRpcWithEmptyOutput() {
94 final var result = mock(ContainerNode.class);
95 doReturn(true).when(result).isEmpty();
98 assertNull(assertEntity(204, ar -> restconf.operationsJsonPOST(apiPath("invoke-rpc-module:rpc-test"),
101 "invoke-rpc-module:input" : {
103 }"""), uriInfo, ar)));
107 void invokeRpcTest() {
108 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult(OUTPUT, List.of()))).when(rpcService)
109 .invokeRpc(RPC, INPUT);
111 assertEquals(OUTPUT, assertOperationOutput(200, ar -> restconf.operationsXmlPOST(
112 apiPath("invoke-rpc-module:rpc-test"), stringInputStream("""
113 <input xmlns="invoke:rpc:module">
117 </input>"""), uriInfo, ar)));
121 void invokeRpcErrorsAndCheckTestTest() throws Exception {
122 final var exception = new DOMRpcImplementationNotAvailableException(
123 "No implementation of RPC " + RPC + " available.");
124 doReturn(Futures.immediateFailedFuture(exception)).when(rpcService).invokeRpc(RPC, INPUT);
126 final var error = assertError(ar -> restconf.operationsJsonPOST(apiPath("invoke-rpc-module:rpc-test"),
127 stringInputStream("""
129 "invoke-rpc-module:input" : {
134 }"""), uriInfo, ar));
135 assertEquals("No implementation of RPC (invoke:rpc:module?revision=2013-12-03)rpc-test available.",
136 error.getErrorMessage());
137 assertEquals(ErrorType.RPC, error.getErrorType());
138 assertEquals(ErrorTag.OPERATION_FAILED, error.getErrorTag());
142 void invokeRpcViaMountPointTest() throws Exception {
143 doReturn(Optional.of(new FixedDOMSchemaService(MODEL_CONTEXT))).when(mountPoint)
144 .getService(DOMSchemaService.class);
145 doReturn(Optional.of(rpcService)).when(mountPoint).getService(DOMRpcService.class);
146 doReturn(Optional.empty()).when(mountPoint).getService(DOMActionService.class);
147 doReturn(Optional.empty()).when(mountPoint).getService(DOMMountPointService.class);
148 doReturn(Optional.empty()).when(mountPoint).getService(NetconfDataTreeService.class);
149 doReturn(Optional.of(dataBroker)).when(mountPoint).getService(DOMDataBroker.class);
150 doReturn(Optional.of(mountPoint)).when(mountPointService).getMountPoint(YangInstanceIdentifier.of(
151 QName.create("urn:ietf:params:xml:ns:yang:ietf-yang-library", "2019-01-04", "modules-state")));
152 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult(OUTPUT, List.of()))).when(rpcService)
153 .invokeRpc(RPC, INPUT);
155 assertEquals(OUTPUT, assertOperationOutput(200,
156 ar -> restconf.operationsJsonPOST(
157 apiPath("ietf-yang-library:modules-state/yang-ext:mount/invoke-rpc-module:rpc-test"),
158 stringInputStream("""
160 "invoke-rpc-module:input" : {
165 }"""), uriInfo, ar)));
169 void invokeRpcMissingMountPointServiceTest() {
170 doReturn(Optional.of(new FixedDOMSchemaService(MODEL_CONTEXT))).when(mountPoint)
171 .getService(DOMSchemaService.class);
172 doReturn(Optional.empty()).when(mountPoint).getService(DOMRpcService.class);
173 doReturn(Optional.empty()).when(mountPoint).getService(DOMActionService.class);
174 doReturn(Optional.empty()).when(mountPoint).getService(DOMMountPointService.class);
175 doReturn(Optional.empty()).when(mountPoint).getService(NetconfDataTreeService.class);
176 doReturn(Optional.of(dataBroker)).when(mountPoint).getService(DOMDataBroker.class);
177 doReturn(Optional.of(mountPoint)).when(mountPointService).getMountPoint(YangInstanceIdentifier.of(
178 QName.create("urn:ietf:params:xml:ns:yang:ietf-yang-library", "2019-01-04", "modules-state")));
180 final var error = assertError(
181 ar -> restconf.operationsJsonPOST(
182 apiPath("ietf-yang-library:modules-state/yang-ext:mount/invoke-rpc-module:rpc-test"),
183 stringInputStream("""
185 "invoke-rpc-module:input" : {
187 }"""), uriInfo, ar));
188 assertEquals("RPC invocation is not available", error.getErrorMessage());
189 assertEquals(ErrorType.PROTOCOL, error.getErrorType());
190 assertEquals(ErrorTag.OPERATION_NOT_SUPPORTED, error.getErrorTag());
194 void checkResponseTest() throws Exception {
195 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult(OUTPUT, List.of())))
196 .when(rpcService).invokeRpc(RPC, INPUT);
198 final var body = assertOperationOutputBody(200, ar -> restconf.operationsJsonPOST(
199 apiPath("invoke-rpc-module:rpc-test"),
200 stringInputStream("""
202 "invoke-rpc-module:input" : {
207 }"""), uriInfo, ar));
208 assertEquals(OUTPUT, body.output());
210 {"invoke-rpc-module:output":{"cont-out":{"lf-out":"operation result"}}}""", body);
212 <output xmlns="invoke:rpc:module"><cont-out><lf-out>operation result</lf-out></cont-out></output>""", body);
215 private void prepNNC(final ContainerNode result) {
216 final var qname = QName.create("invoke:rpc:module", "2013-12-03", "rpc-test");
217 final var domRpcResult = mock(DOMRpcResult.class);
218 doReturn(Futures.immediateFuture(domRpcResult)).when(rpcService).invokeRpc(eq(qname), any(ContainerNode.class));
219 doReturn(result).when(domRpcResult).value();