Re-implement logic for security and securitySchemes
[netconf.git] / restconf / restconf-openapi / src / test / java / org / opendaylight / restconf / openapi / OperationalDataTest.java
1 /*
2  * Copyright (c) 2023 PANTHEON.tech, 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.restconf.openapi;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertNotNull;
12 import static org.junit.Assert.assertTrue;
13 import static org.mockito.Mockito.mock;
14 import static org.mockito.Mockito.when;
15
16 import java.util.Map;
17 import java.util.Optional;
18 import java.util.Set;
19 import org.junit.Before;
20 import org.junit.Test;
21 import org.opendaylight.mdsal.dom.api.DOMMountPoint;
22 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
23 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
24 import org.opendaylight.restconf.openapi.impl.MountPointOpenApiGeneratorRFC8040;
25 import org.opendaylight.restconf.openapi.model.OpenApiObject;
26 import org.opendaylight.restconf.openapi.model.Schema;
27 import org.opendaylight.yangtools.yang.common.QName;
28 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
29 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
30
31 public class OperationalDataTest {
32     private static final String DATA_MP_URI = "/rests/data/nodes/node=123/yang-ext:mount";
33     private static final String OPERATIONS_MP_URI = "/rests/operations/nodes/node=123/yang-ext:mount";
34     private static final Set<String> EXPECTED_SCHEMAS = Set.of(
35         "action-types_container",
36         "action-types_list",
37         "action-types_multi-container",
38         "action-types_container-action_input",
39         "action-types_container-action_output",
40         "action-types_list-action_output",
41         "action-types_list-action_input",
42         "action-types_multi-container_inner-container",
43         "operational_root",
44         "operational_root_config-container",
45         "operational_root_config-container_config-container-oper-list",
46         "operational_root_oper-container",
47         "operational_root_oper-container_config-container",
48         "operational_root_oper-container_oper-container-list");
49
50     private static final Set<String> EXPECTED_PATHS = Set.of(
51         OPERATIONS_MP_URI + "/action-types:list={name}/list-action",
52         OPERATIONS_MP_URI + "/action-types:container/container-action",
53         OPERATIONS_MP_URI + "/action-types:multi-container/inner-container/action",
54         OPERATIONS_MP_URI,
55         DATA_MP_URI + "/action-types:list={name}",
56         DATA_MP_URI + "/operational:root",
57         DATA_MP_URI + "/operational:root/oper-container/config-container",
58         DATA_MP_URI + "/operational:root/oper-container/oper-container-list={oper-container-list-leaf}",
59         DATA_MP_URI + "/action-types:multi-container",
60         DATA_MP_URI + "/action-types:multi-container/inner-container",
61         DATA_MP_URI + "/operational:root/oper-container",
62         DATA_MP_URI + "/action-types:container",
63         DATA_MP_URI + "/operational:root/config-container/config-container-oper-list={oper-container-list-leaf}",
64         DATA_MP_URI + "/operational:root/config-container",
65         DATA_MP_URI);
66     private static final String HTTP_URL = "http://localhost/path";
67     private static final YangInstanceIdentifier INSTANCE_ID = YangInstanceIdentifier.builder()
68         .node(QName.create("", "nodes"))
69         .node(QName.create("", "node"))
70         .nodeWithKey(QName.create("", "node"), QName.create("", "id"), "123").build();
71
72     private OpenApiObject mountPointApi;
73     private Map<String, Schema> schemas;
74
75     @Before
76     public void before() throws Exception {
77         final var schemaService = mock(DOMSchemaService.class);
78         final var context = YangParserTestUtils.parseYangResourceDirectory("/operational");
79         when(schemaService.getGlobalContext()).thenReturn(context);
80         final var mountPoint = mock(DOMMountPoint.class);
81         when(mountPoint.getService(DOMSchemaService.class)).thenReturn(Optional.of(schemaService));
82
83         final var service = mock(DOMMountPointService.class);
84         when(service.getMountPoint(INSTANCE_ID)).thenReturn(Optional.of(mountPoint));
85         final var openApi = new MountPointOpenApiGeneratorRFC8040(schemaService, service).getMountPointOpenApi();
86         openApi.onMountPointCreated(INSTANCE_ID);
87         final var mockInfo = DocGenTestHelper.createMockUriInfo(HTTP_URL);
88         mountPointApi = openApi.getMountPointApi(mockInfo, 1L, null);
89         assertNotNull("Failed to find Datastore API", mountPointApi);
90         schemas = mountPointApi.components().schemas();
91     }
92
93     @Test
94     public void testOperationalPath() {
95         final var paths = mountPointApi.paths();
96         assertEquals(EXPECTED_PATHS, paths.keySet());
97         for (final var path : paths.values()) {
98             if (path.get() != null) {
99                 final var responses = path.get().responses();
100                 final var response = responses.values().iterator().next();
101                 final var content = response.content();
102                 // In case of 200 no content
103                 if (content != null) {
104                     verifyOperationHaveCorrectXmlReference(content.get("application/xml").schema());
105                     verifyOperationHaveCorrectJsonReference(content.get("application/json").schema());
106                 }
107             }
108             if (path.put() != null) {
109                 final var responses = path.put().requestBody();
110                 final var content = responses.content();
111                 verifyOperationHaveCorrectXmlReference(content.get("application/xml").schema());
112                 verifyOperationHaveCorrectJsonReference(content.get("application/json").schema());
113             }
114             if (path.post() != null) {
115                 final var responses = path.post().requestBody();
116                 final var content = responses.content();
117                 verifyOperationHaveCorrectXmlReference(content.get("application/xml").schema());
118                 verifyOperationHaveCorrectJsonReference(content.get("application/json").schema());
119             }
120             if (path.patch() != null) {
121                 final var responses = path.patch().requestBody();
122                 final var content = responses.content();
123                 verifyOperationHaveCorrectXmlReference(content.get("application/yang-data+xml").schema());
124                 verifyOperationHaveCorrectJsonReference(content.get("application/yang-data+json").schema());
125             }
126         }
127     }
128
129     @Test
130     public void testOperationalSchema() {
131         assertEquals(EXPECTED_SCHEMAS, schemas.keySet());
132     }
133
134     @Test
135     public void testOperationalConfigRootSchemaProperties() {
136         final var configRoot = schemas.get("operational_root");
137         assertNotNull(configRoot);
138         final var actualProperties = configRoot.properties().keySet();
139         assertEquals(Set.of("leaf-config", "config-container"), actualProperties);
140     }
141
142     @Test
143     public void testOperationalConfigContOperListSchemaProperties() {
144         final var configContOperList = schemas.get(
145             "operational_root_config-container_config-container-oper-list");
146         assertNotNull(configContOperList);
147         final var actualProperties = configContOperList.properties().keySet();
148         assertEquals(Set.of("oper-container-list-leaf"), actualProperties);
149     }
150
151     @Test
152     public void testOperationalContListSchemaProperties() {
153         final var operContList = schemas.get("operational_root_oper-container_oper-container-list");
154         assertNotNull(operContList);
155         final var actualProperties = operContList.properties().keySet();
156         assertEquals(Set.of("oper-container-list-leaf"), actualProperties);
157     }
158
159     @Test
160     public void testOperationalConConfigContSchemaProperties() {
161         final var operConConfigCont = schemas.get("operational_root_oper-container_config-container");
162         assertNotNull(operConConfigCont);
163         final var actualProperties = operConConfigCont.properties().keySet();
164         assertEquals(Set.of("config-container-config-leaf", "opconfig-container-oper-leaf"), actualProperties);
165     }
166
167     @Test
168     public void testOperationalConfigContSchemaProperties() {
169         final var configCont = schemas.get("operational_root_config-container");
170         assertNotNull(configCont);
171         final var actualProperties = configCont.properties().keySet();
172         assertEquals(Set.of("config-container-config-leaf", "leaf-second-case"), actualProperties);
173     }
174
175     @Test
176     public void testOperationalContSchemaProperties() {
177         final var operCont = schemas.get("operational_root_oper-container");
178         assertNotNull(operCont);
179         final var actualProperties = operCont.properties().keySet();
180         assertEquals(Set.of("config-container", "oper-container-list", "leaf-first-case", "oper-leaf-first-case",
181             "oper-container-config-leaf-list"), actualProperties);
182     }
183
184     @Test
185     public void testListActionSchemaProperties() {
186         final var configRoot = schemas.get("action-types_list");
187         assertNotNull(configRoot);
188         final var actualProperties = configRoot.properties().keySet();
189         assertEquals(Set.of("name"), actualProperties);
190     }
191
192     @Test
193     public void testListActionInputSchemaProperties() {
194         final var configRoot = schemas.get("action-types_list-action_input");
195         assertNotNull(configRoot);
196         final var actualProperties = configRoot.properties().keySet();
197         assertEquals(Set.of("la-input"), actualProperties);
198     }
199
200     @Test
201     public void testListActionOutputSchemaProperties() {
202         final var configRoot = schemas.get("action-types_list-action_output");
203         assertNotNull(configRoot);
204         final var actualProperties = configRoot.properties().keySet();
205         assertEquals(Set.of("la-output"), actualProperties);
206     }
207
208     @Test
209     public void testContainerActionSchemaProperties() {
210         final var configRoot = schemas.get("action-types_container");
211         assertNotNull(configRoot);
212         final var actualProperties = configRoot.properties().keySet();
213         assertEquals(Set.of(), actualProperties);
214     }
215
216     @Test
217     public void testContainerActionInputSchemaProperties() {
218         final var configRoot = schemas.get("action-types_container-action_input");
219         assertNotNull(configRoot);
220         final var actualProperties = configRoot.properties().keySet();
221         assertEquals(Set.of("ca-input"), actualProperties);
222     }
223
224     @Test
225     public void testContainerActionOutputSchemaProperties() {
226         final var configRoot = schemas.get("action-types_container-action_output");
227         assertNotNull(configRoot);
228         final var actualProperties = configRoot.properties().keySet();
229         assertEquals(Set.of("ca-output"), actualProperties);
230     }
231
232     private static void verifyOperationHaveCorrectXmlReference(final Schema schema) {
233         final var refValue = schema.ref();
234         // In case of a POST RPC with a direct input body and no reference value
235         if (refValue != null) {
236             final var schemaElement = refValue.substring(refValue.lastIndexOf("/") + 1);
237             assertTrue("Reference [" + refValue + "] not found in EXPECTED Schemas",
238                 EXPECTED_SCHEMAS.contains(schemaElement));
239         } else {
240             final var type = schema.type();
241             assertNotNull(type);
242             assertEquals("object", type);
243         }
244     }
245
246     private static void verifyOperationHaveCorrectJsonReference(final Schema schema) {
247         final var properties = schema.properties();
248         final String refValue;
249         if (properties != null) {
250             final var node = properties.values().iterator().next();
251             final var type = node.type();
252             if (type == null) {
253                 refValue = node.ref();
254             } else if (type.equals("array")) {
255                 refValue = node.items().ref();
256             } else {
257                 assertEquals("object", type);
258                 return;
259             }
260         } else {
261             refValue = schema.ref();
262         }
263         final var schemaElement = refValue.substring(refValue.lastIndexOf("/") + 1);
264         assertTrue("Reference [" + refValue + "] not found in EXPECTED Schemas",
265                 EXPECTED_SCHEMAS.contains(schemaElement));
266     }
267 }