2 * Copyright (c) 2023 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.restconf.openapi;
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;
17 import java.util.Optional;
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;
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",
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",
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");
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",
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",
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();
72 private OpenApiObject mountPointApi;
73 private Map<String, Schema> schemas;
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));
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();
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());
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());
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());
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());
130 public void testOperationalSchema() {
131 assertEquals(EXPECTED_SCHEMAS, schemas.keySet());
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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));
240 final var type = schema.type();
242 assertEquals("object", type);
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();
253 refValue = node.ref();
254 } else if (type.equals("array")) {
255 refValue = node.items().ref();
257 assertEquals("object", type);
261 refValue = schema.ref();
263 final var schemaElement = refValue.substring(refValue.lastIndexOf("/") + 1);
264 assertTrue("Reference [" + refValue + "] not found in EXPECTED Schemas",
265 EXPECTED_SCHEMAS.contains(schemaElement));