Refactor pretty printing
[netconf.git] / restconf / restconf-nb / src / test / java / org / opendaylight / restconf / nb / jaxrs / RestconfOperationsPostTest.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. 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.restconf.nb.jaxrs;
9
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;
17
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;
47
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"))
56             .build())
57         .build();
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"))
63             .build())
64         .build();
65     private static final EffectiveModelContext MODEL_CONTEXT =
66         YangParserTestUtils.parseYangResourceDirectory("/invoke-rpc");
67
68     @Mock
69     private DOMNotificationService notificationService;
70
71     @Override
72     EffectiveModelContext modelContext() {
73         return MODEL_CONTEXT;
74     }
75
76     @BeforeEach
77     void setupUriInfo() {
78         doReturn(new MultivaluedHashMap<>()).when(uriInfo).getQueryParameters();
79     }
80
81     @Test
82     void testInvokeRpcWithNonEmptyOutput() {
83         final var result = mock(ContainerNode.class);
84         doReturn(false).when(result).isEmpty();
85
86         prepNNC(result);
87         assertSame(result, assertOperationOutput(200, ar -> restconf.operationsXmlPOST(
88             apiPath("invoke-rpc-module:rpc-test"), stringInputStream("""
89                 <input xmlns="invoke:rpc:module"/>"""), uriInfo, ar)));
90     }
91
92     @Test
93     void testInvokeRpcWithEmptyOutput() {
94         final var result = mock(ContainerNode.class);
95         doReturn(true).when(result).isEmpty();
96
97         prepNNC(result);
98         assertNull(assertEntity(204, ar -> restconf.operationsJsonPOST(apiPath("invoke-rpc-module:rpc-test"),
99             stringInputStream("""
100                 {
101                   "invoke-rpc-module:input" : {
102                   }
103                 }"""), uriInfo, ar)));
104     }
105
106     @Test
107     void invokeRpcTest() {
108         doReturn(Futures.immediateFuture(new DefaultDOMRpcResult(OUTPUT, List.of()))).when(rpcService)
109             .invokeRpc(RPC, INPUT);
110
111         assertEquals(OUTPUT, assertOperationOutput(200, ar -> restconf.operationsXmlPOST(
112             apiPath("invoke-rpc-module:rpc-test"), stringInputStream("""
113                 <input xmlns="invoke:rpc:module">
114                   <cont>
115                     <lf>test</lf>
116                   </cont>
117                 </input>"""), uriInfo, ar)));
118     }
119
120     @Test
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);
125
126         final var error = assertError(ar -> restconf.operationsJsonPOST(apiPath("invoke-rpc-module:rpc-test"),
127             stringInputStream("""
128                 {
129                   "invoke-rpc-module:input" : {
130                     "cont" : {
131                       "lf" : "test"
132                     }
133                   }
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());
139     }
140
141     @Test
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);
154
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("""
159                     {
160                       "invoke-rpc-module:input" : {
161                         "cont" : {
162                           "lf" : "test"
163                         }
164                       }
165                     }"""), uriInfo, ar)));
166     }
167
168     @Test
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")));
179
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("""
184                     {
185                       "invoke-rpc-module:input" : {
186                       }
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());
191     }
192
193     @Test
194     void checkResponseTest() throws Exception {
195         doReturn(Futures.immediateFuture(new DefaultDOMRpcResult(OUTPUT, List.of())))
196             .when(rpcService).invokeRpc(RPC, INPUT);
197
198         final var body = assertOperationOutputBody(200, ar -> restconf.operationsJsonPOST(
199             apiPath("invoke-rpc-module:rpc-test"),
200             stringInputStream("""
201                 {
202                   "invoke-rpc-module:input" : {
203                     "cont" : {
204                       "lf" : "test"
205                     }
206                   }
207                 }"""), uriInfo, ar));
208         assertEquals(OUTPUT, body.output());
209         assertJson("""
210             {"invoke-rpc-module:output":{"cont-out":{"lf-out":"operation result"}}}""", body);
211         assertXml("""
212             <output xmlns="invoke:rpc:module"><cont-out><lf-out>operation result</lf-out></cont-out></output>""", body);
213     }
214
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();
220     }
221 }