2 * Copyright (c) 2021 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.sal.rest.doc.impl;
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertFalse;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertNull;
14 import static org.junit.Assert.assertTrue;
15 import static org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder.CONTENT_KEY;
16 import static org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder.REF_KEY;
17 import static org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder.REQUEST_BODY_KEY;
18 import static org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder.RESPONSES_KEY;
19 import static org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder.SCHEMA_KEY;
20 import static org.opendaylight.netconf.sal.rest.doc.model.builder.OperationBuilder.getAppropriateModelPrefix;
22 import com.fasterxml.jackson.databind.JsonNode;
23 import com.fasterxml.jackson.databind.node.ArrayNode;
24 import com.fasterxml.jackson.databind.node.JsonNodeFactory;
25 import com.fasterxml.jackson.databind.node.ObjectNode;
26 import com.google.common.collect.ImmutableList;
27 import com.google.common.collect.Sets;
28 import java.util.ArrayList;
29 import java.util.HashSet;
30 import java.util.List;
32 import java.util.stream.Collectors;
33 import java.util.stream.StreamSupport;
34 import org.junit.Test;
35 import org.opendaylight.netconf.sal.rest.doc.swagger.OpenApiObject;
36 import org.opendaylight.netconf.sal.rest.doc.swagger.SwaggerObject;
38 public final class ApiDocGeneratorRFC8040Test extends AbstractApiDocTest {
39 private static final String NAME = "toaster2";
40 private static final String MY_YANG = "my-yang";
41 private static final String MY_YANG_REVISION = "2022-10-06";
42 private static final String REVISION_DATE = "2009-11-20";
43 private static final String NAME_2 = "toaster";
44 private static final String REVISION_DATE_2 = "2009-11-20";
45 private static final String PATH_PARAMS_TEST_MODULE = "path-params-test";
46 private static final String MANDATORY_TEST = "mandatory-test";
47 private static final String CONFIG_ROOT_CONTAINER = "mandatory-test_config_root-container";
48 private static final String ROOT_CONTAINER = "mandatory-test_root-container";
49 private static final String CONFIG_MANDATORY_CONTAINER = "mandatory-test_root-container_config_mandatory-container";
50 private static final String MANDATORY_CONTAINER = "mandatory-test_root-container_mandatory-container";
51 private static final String CONFIG_MANDATORY_LIST = "mandatory-test_root-container_config_mandatory-list";
52 private static final String CONFIG_MANDATORY_LIST_POST = "mandatory-test_root-container_config_mandatory-list_post";
53 private static final String MANDATORY_LIST = "mandatory-test_root-container_mandatory-list";
54 private static final String MANDATORY_TEST_MODULE = "mandatory-test_config_module";
55 private static final String CHOICE_TEST_MODULE = "choice-test";
56 private static final String PROPERTIES = "properties";
57 private static final String CONTAINER = "container";
58 private static final String LIST = "list";
60 private final ApiDocGeneratorRFC8040 generator = new ApiDocGeneratorRFC8040(SCHEMA_SERVICE);
63 * Test that paths are generated according to the model.
66 public void testPaths() {
67 final SwaggerObject doc = (SwaggerObject) generator.getApiDeclaration(NAME, REVISION_DATE, URI_INFO,
68 ApiDocServiceImpl.OAversion.V2_0);
70 assertEquals(List.of("/rests/data",
71 "/rests/data/toaster2:toaster",
72 "/rests/data/toaster2:toaster/toasterSlot={slotId}",
73 "/rests/data/toaster2:toaster/toasterSlot={slotId}/toaster-augmented:slotInfo",
74 "/rests/data/toaster2:lst",
75 "/rests/data/toaster2:lst/cont1",
76 "/rests/data/toaster2:lst/cont1/cont11",
77 "/rests/data/toaster2:lst/cont1/lst11",
78 "/rests/data/toaster2:lst/lst1={key1},{key2}",
79 "/rests/operations/toaster2:make-toast",
80 "/rests/operations/toaster2:cancel-toast",
81 "/rests/operations/toaster2:restock-toaster"),
82 ImmutableList.copyOf(doc.getPaths().fieldNames()));
86 * Test that generated configuration paths allow to use operations: get, put, delete and post.
89 public void testConfigPaths() {
90 final List<String> configPaths = List.of("/rests/data/toaster2:lst",
91 "/rests/data/toaster2:lst/cont1",
92 "/rests/data/toaster2:lst/cont1/cont11",
93 "/rests/data/toaster2:lst/cont1/lst11",
94 "/rests/data/toaster2:lst/lst1={key1},{key2}");
96 final SwaggerObject doc = (SwaggerObject) generator.getApiDeclaration(NAME, REVISION_DATE, URI_INFO,
97 ApiDocServiceImpl.OAversion.V2_0);
99 for (final String path : configPaths) {
100 final JsonNode node = doc.getPaths().get(path);
101 assertFalse(node.path("get").isMissingNode());
102 assertFalse(node.path("put").isMissingNode());
103 assertFalse(node.path("delete").isMissingNode());
104 assertFalse(node.path("post").isMissingNode());
109 * Test that generated document contains the following definitions.
112 public void testDefinitions() {
113 final SwaggerObject doc = (SwaggerObject) generator.getApiDeclaration(NAME, REVISION_DATE, URI_INFO,
114 ApiDocServiceImpl.OAversion.V2_0);
116 final ObjectNode definitions = doc.getDefinitions();
117 assertNotNull(definitions);
119 final JsonNode configLstTop = definitions.get("toaster2_config_lst_TOP");
120 assertNotNull(configLstTop);
121 DocGenTestHelper.containsReferences(configLstTop, "toaster2:lst", "#/definitions/toaster2_config_lst");
123 final JsonNode configLst = definitions.get("toaster2_config_lst");
124 assertNotNull(configLst);
125 DocGenTestHelper.containsReferences(configLst, "lst1", "#/definitions/toaster2_lst_config_lst1");
126 DocGenTestHelper.containsReferences(configLst, "cont1", "#/definitions/toaster2_lst_config_cont1");
128 final JsonNode configLst1Top = definitions.get("toaster2_lst_config_lst1_TOP");
129 assertNotNull(configLst1Top);
130 DocGenTestHelper.containsReferences(configLst1Top, "toaster2:lst1", "#/definitions/toaster2_lst_config_lst1");
132 final JsonNode configLst1 = definitions.get("toaster2_lst_config_lst1");
133 assertNotNull(configLst1);
135 final JsonNode configCont1Top = definitions.get("toaster2_lst_config_cont1_TOP");
136 assertNotNull(configCont1Top);
137 DocGenTestHelper.containsReferences(configCont1Top, "toaster2:cont1",
138 "#/definitions/toaster2_lst_config_cont1");
140 final JsonNode configCont1 = definitions.get("toaster2_lst_config_cont1");
141 assertNotNull(configCont1);
142 DocGenTestHelper.containsReferences(configCont1, "cont11", "#/definitions/toaster2_lst_cont1_config_cont11");
143 DocGenTestHelper.containsReferences(configCont1, "lst11", "#/definitions/toaster2_lst_cont1_config_lst11");
145 final JsonNode configCont11Top = definitions.get("toaster2_lst_cont1_config_cont11_TOP");
146 assertNotNull(configCont11Top);
147 DocGenTestHelper.containsReferences(configCont11Top, "toaster2:cont11",
148 "#/definitions/toaster2_lst_cont1_config_cont11");
150 final JsonNode configCont11 = definitions.get("toaster2_lst_cont1_config_cont11");
151 assertNotNull(configCont11);
153 final JsonNode configLst11Top = definitions.get("toaster2_lst_cont1_config_lst11_TOP");
154 assertNotNull(configLst11Top);
155 DocGenTestHelper.containsReferences(configLst11Top, "toaster2:lst11",
156 "#/definitions/toaster2_lst_cont1_config_lst11");
158 final JsonNode configLst11 = definitions.get("toaster2_lst_cont1_config_lst11");
159 assertNotNull(configLst11);
163 * Test that generated document contains RPC definition for "make-toast" with correct input.
166 public void testRPC() {
167 final SwaggerObject doc = (SwaggerObject) generator.getApiDeclaration(NAME_2, REVISION_DATE_2, URI_INFO,
168 ApiDocServiceImpl.OAversion.V2_0);
171 final ObjectNode definitions = doc.getDefinitions();
172 final JsonNode inputTop = definitions.get("toaster_make-toast_input_TOP");
173 assertNotNull(inputTop);
174 final String testString = "{\"toaster:input\":{\"$ref\":\"#/definitions/toaster_make-toast_input\"}}";
175 assertEquals(testString, inputTop.get("properties").toString());
176 final JsonNode input = definitions.get("toaster_make-toast_input");
177 final JsonNode properties = input.get("properties");
178 assertTrue(properties.has("toasterDoneness"));
179 assertTrue(properties.has("toasterToastType"));
183 public void testMandatory() {
184 final var doc = (OpenApiObject) generator.getApiDeclaration(MANDATORY_TEST, null, URI_INFO,
185 ApiDocServiceImpl.OAversion.V3_0);
187 final var definitions = doc.getComponents().getSchemas();
188 final var containersWithRequired = new ArrayList<String>();
190 final var reqRootContainerElements = Set.of("mandatory-root-leaf", "mandatory-container",
191 "mandatory-first-choice", "mandatory-list");
192 verifyRequiredField(definitions.get(CONFIG_ROOT_CONTAINER), reqRootContainerElements);
193 containersWithRequired.add(CONFIG_ROOT_CONTAINER);
194 verifyRequiredField(definitions.get(ROOT_CONTAINER), reqRootContainerElements);
195 containersWithRequired.add(ROOT_CONTAINER);
197 final var reqMandatoryContainerElements = Set.of("mandatory-leaf", "leaf-list-with-min-elements");
198 verifyRequiredField(definitions.get(CONFIG_MANDATORY_CONTAINER), reqMandatoryContainerElements);
199 containersWithRequired.add(CONFIG_MANDATORY_CONTAINER);
200 verifyRequiredField(definitions.get(MANDATORY_CONTAINER), reqMandatoryContainerElements);
201 containersWithRequired.add(MANDATORY_CONTAINER);
203 final var reqMandatoryListElements = Set.of("mandatory-list-field");
204 verifyRequiredField(definitions.get(CONFIG_MANDATORY_LIST), reqMandatoryListElements);
205 containersWithRequired.add(CONFIG_MANDATORY_LIST);
206 verifyRequiredField(definitions.get(MANDATORY_LIST), reqMandatoryListElements);
207 containersWithRequired.add(MANDATORY_LIST);
209 final var testModuleMandatoryArray = Set.of("root-container", "root-mandatory-list");
210 verifyRequiredField(definitions.get(MANDATORY_TEST_MODULE), testModuleMandatoryArray);
211 containersWithRequired.add(MANDATORY_TEST_MODULE);
213 verifyThatPropertyDoesNotHaveRequired(containersWithRequired, definitions);
217 * Test that request parameters are correctly numbered.
220 * It means we should have name and name1, etc. when we have the same parameter in path multiple times.
223 public void testParametersNumbering() {
224 final var doc = (OpenApiObject) generator.getApiDeclaration(PATH_PARAMS_TEST_MODULE, null, URI_INFO,
225 ApiDocServiceImpl.OAversion.V3_0);
227 var pathToList1 = "/rests/data/path-params-test:cont/list1={name}";
228 assertTrue(doc.getPaths().has(pathToList1));
229 assertEquals(List.of("name"), getPathGetParameters(doc.getPaths(), pathToList1));
231 var pathToList2 = "/rests/data/path-params-test:cont/list1={name}/list2={name1}";
232 assertTrue(doc.getPaths().has(pathToList2));
233 assertEquals(List.of("name", "name1"), getPathGetParameters(doc.getPaths(), pathToList2));
235 var pathToList3 = "/rests/data/path-params-test:cont/list3={name}";
236 assertTrue(doc.getPaths().has(pathToList3));
237 assertEquals(List.of("name"), getPathGetParameters(doc.getPaths(), pathToList3));
239 var pathToList4 = "/rests/data/path-params-test:cont/list1={name}/list4={name1}";
240 assertTrue(doc.getPaths().has(pathToList4));
241 assertEquals(List.of("name", "name1"), getPathGetParameters(doc.getPaths(), pathToList4));
243 var pathToList5 = "/rests/data/path-params-test:cont/list1={name}/cont2";
244 assertTrue(doc.getPaths().has(pathToList4));
245 assertEquals(List.of("name"), getPathGetParameters(doc.getPaths(), pathToList5));
248 private static void verifyThatPropertyDoesNotHaveRequired(final List<String> expected,
249 final ObjectNode definitions) {
250 final var fields = definitions.fields();
251 while (fields.hasNext()) {
252 final var next = fields.next();
253 final var nodeName = next.getKey();
254 final var jsonNode = next.getValue();
255 if (expected.contains(nodeName)) {
258 assertNull("Json node " + nodeName + " should not have 'required' field in body",
259 jsonNode.get("required"));
263 private static void verifyRequiredField(final JsonNode rootContainer, final Set<String> expected) {
264 assertNotNull(rootContainer);
265 final var required = rootContainer.get("required");
266 assertNotNull(required);
267 assertTrue(required.isArray());
268 final var actualContainerArray = StreamSupport.stream(required.spliterator(), false)
269 .map(JsonNode::textValue)
270 .collect(Collectors.toSet());
271 assertEquals(expected, actualContainerArray);
275 * Test that request parameters are correctly typed.
278 public void testParametersTypes() {
279 final var doc = (OpenApiObject) generator.getApiDeclaration("typed-params", "2023-10-24", URI_INFO,
280 ApiDocServiceImpl.OAversion.V3_0);
281 final var pathToContainer = "/rests/data/typed-params:typed/";
282 final var integerTypes = List.of("uint64", "uint32", "uint16", "uint8", "int64", "int32", "int16", "int8");
283 for (final var type: integerTypes) {
284 final var typeKey = type + "-key";
285 final var path = pathToContainer + type + "={" + typeKey + "}";
286 assertTrue(doc.getPaths().has(path));
287 assertEquals("integer", doc.getPaths().get(path).get("get").get("parameters").get(0).get("schema")
288 .get("type").textValue());
293 * Test that request for actions is correct and has parameters.
296 public void testActionPathsParams() {
297 final var doc = (OpenApiObject) generator.getApiDeclaration("action-types", null, URI_INFO,
298 ApiDocServiceImpl.OAversion.V3_0);
300 final var pathWithParameters = "/rests/operations/action-types:list={name}/list-action";
301 assertTrue(doc.getPaths().has(pathWithParameters));
302 assertEquals(List.of("name"), getPathPostParameters(doc.getPaths(), pathWithParameters));
304 final var pathWithoutParameters = "/rests/operations/action-types:multi-container/inner-container/action";
305 assertTrue(doc.getPaths().has(pathWithoutParameters));
306 assertEquals(List.of(), getPathPostParameters(doc.getPaths(), pathWithoutParameters));
310 public void testChoice() {
311 final var doc = (SwaggerObject) generator.getApiDeclaration(CHOICE_TEST_MODULE, null, URI_INFO,
312 ApiDocServiceImpl.OAversion.V2_0);
315 final var definitions = doc.getDefinitions();
316 JsonNode firstContainer = definitions.get("choice-test_first-container");
317 assertEquals("default-value",
318 firstContainer.get(PROPERTIES).get("leaf-default").get("default").asText());
319 assertFalse(firstContainer.get(PROPERTIES).has("leaf-non-default"));
321 JsonNode secondContainer = definitions.get("choice-test_second-container");
322 assertTrue(secondContainer.get(PROPERTIES).has("leaf-first-case"));
323 assertFalse(secondContainer.get(PROPERTIES).has("leaf-second-case"));
327 public void testSimpleOpenApiObjects() {
328 final var doc = (OpenApiObject) generator.getApiDeclaration(MY_YANG, MY_YANG_REVISION, URI_INFO,
329 ApiDocServiceImpl.OAversion.V3_0);
330 assertEquals(List.of("/rests/data", "/rests/data/my-yang:data"),
331 ImmutableList.copyOf(doc.getPaths().fieldNames()));
333 final var JsonNodeMyYangData = doc.getPaths().get("/rests/data/my-yang:data");
334 verifyRequestRef(JsonNodeMyYangData.path("post"),
335 "#/components/schemas/my-yang_config_data",
336 "#/components/schemas/my-yang_config_data");
337 verifyRequestRef(JsonNodeMyYangData.path("put"), "#/components/schemas/my-yang_config_data_TOP",
338 "#/components/schemas/my-yang_config_data");
339 verifyRequestRef(JsonNodeMyYangData.path("get"), "#/components/schemas/my-yang_data_TOP",
340 "#/components/schemas/my-yang_data");
342 // Test `components/schemas` objects
343 final var definitions = doc.getComponents().getSchemas();
344 assertEquals(5, definitions.size());
345 assertTrue(definitions.has("my-yang_config_data"));
346 assertTrue(definitions.has("my-yang_config_data_TOP"));
347 assertTrue(definitions.has("my-yang_data"));
348 assertTrue(definitions.has("my-yang_data_TOP"));
349 assertTrue(definitions.has("my-yang_config_module"));
353 public void testToaster2OpenApiObjects() {
354 final var doc = (OpenApiObject) generator.getApiDeclaration(NAME, REVISION_DATE, URI_INFO,
355 ApiDocServiceImpl.OAversion.V3_0);
356 final var jsonNodeToaster = doc.getPaths().get("/rests/data/toaster2:toaster");
357 verifyPostRequestRef(jsonNodeToaster.path("post"),
358 "#/components/schemas/toaster2_toaster_config_toasterSlot",
359 "#/components/schemas/toaster2_toaster_config_toasterSlot", LIST);
360 verifyRequestRef(jsonNodeToaster.path("put"), "#/components/schemas/toaster2_config_toaster_TOP",
361 "#/components/schemas/toaster2_config_toaster");
362 verifyRequestRef(jsonNodeToaster.path("get"), "#/components/schemas/toaster2_toaster_TOP",
363 "#/components/schemas/toaster2_toaster");
365 final var jsonNodeToasterSlot = doc.getPaths().get("/rests/data/toaster2:toaster/toasterSlot={slotId}");
366 verifyPostRequestRef(jsonNodeToasterSlot.path("post"),
367 "#/components/schemas/toaster2_toaster_toasterSlot_config_slotInfo",
368 "#/components/schemas/toaster2_toaster_toasterSlot_config_slotInfo", CONTAINER);
369 verifyRequestRef(jsonNodeToasterSlot.path("put"),
370 "#/components/schemas/toaster2_toaster_config_toasterSlot_TOP",
371 "#/components/schemas/toaster2_toaster_config_toasterSlot");
372 verifyRequestRef(jsonNodeToasterSlot.path("get"), "#/components/schemas/toaster2_toaster_toasterSlot_TOP",
373 "#/components/schemas/toaster2_toaster_toasterSlot");
375 final var jsonNodeSlotInfo = doc.getPaths().get(
376 "/rests/data/toaster2:toaster/toasterSlot={slotId}/toaster-augmented:slotInfo");
377 verifyRequestRef(jsonNodeSlotInfo.path("post"),
378 "#/components/schemas/toaster2_toaster_toasterSlot_config_slotInfo",
379 "#/components/schemas/toaster2_toaster_toasterSlot_config_slotInfo");
380 verifyRequestRef(jsonNodeSlotInfo.path("put"),
381 "#/components/schemas/toaster2_toaster_toasterSlot_config_slotInfo_TOP",
382 "#/components/schemas/toaster2_toaster_toasterSlot_config_slotInfo");
383 verifyRequestRef(jsonNodeSlotInfo.path("get"), "#/components/schemas/toaster2_toaster_toasterSlot_slotInfo_TOP",
384 "#/components/schemas/toaster2_toaster_toasterSlot_slotInfo");
386 final var jsonNodeLst = doc.getPaths().get("/rests/data/toaster2:lst");
387 verifyPostRequestRef(jsonNodeLst.path("post"), "#/components/schemas/toaster2_lst_config_cont1",
388 "#/components/schemas/toaster2_lst_config_cont1", CONTAINER);
389 verifyRequestRef(jsonNodeLst.path("put"), "#/components/schemas/toaster2_config_lst_TOP",
390 "#/components/schemas/toaster2_config_lst");
391 verifyRequestRef(jsonNodeLst.path("get"), "#/components/schemas/toaster2_lst_TOP",
392 "#/components/schemas/toaster2_lst");
394 final var jsonNodeLst1 = doc.getPaths().get("/rests/data/toaster2:lst/lst1={key1},{key2}");
395 verifyRequestRef(jsonNodeLst1.path("post"), "#/components/schemas/toaster2_lst_config_lst1",
396 "#/components/schemas/toaster2_lst_config_lst1");
397 verifyRequestRef(jsonNodeLst1.path("put"), "#/components/schemas/toaster2_lst_config_lst1_TOP",
398 "#/components/schemas/toaster2_lst_config_lst1");
399 verifyRequestRef(jsonNodeLst1.path("get"), "#/components/schemas/toaster2_lst_lst1_TOP",
400 "#/components/schemas/toaster2_lst_lst1");
402 final var jsonNodeMakeToast = doc.getPaths().get("/rests/operations/toaster2:make-toast");
403 assertTrue(jsonNodeMakeToast.path("get").isMissingNode());
404 verifyRequestRef(jsonNodeMakeToast.path("post"), "#/components/schemas/toaster2_make-toast_input_TOP",
405 "#/components/schemas/toaster2_make-toast_input");
407 final var jsonNodeCancelToast = doc.getPaths().get("/rests/operations/toaster2:cancel-toast");
408 assertTrue(jsonNodeCancelToast.path("get").isMissingNode());
409 // Test RPC with empty input
410 final var postContent = jsonNodeCancelToast.path("post").get("requestBody").get("content");
411 final var jsonSchema = postContent.get("application/json").get("schema");
412 assertNull(jsonSchema.get("$ref"));
413 assertEquals(2, jsonSchema.size());
414 final var xmlSchema = postContent.get("application/xml").get("schema");
415 assertNull(xmlSchema.get("$ref"));
416 assertEquals(2, xmlSchema.size());
417 // Test `components/schemas` objects
418 final var definitions = doc.getComponents().getSchemas();
419 assertEquals(44, definitions.size());
423 * Test that reference to schema in each path is valid (all referenced schemas exist).
426 public void testRootPostSchemaReference() {
427 final var document = (OpenApiObject) generator.getApiDeclaration(NAME, REVISION_DATE, URI_INFO,
428 ApiDocServiceImpl.OAversion.V3_0);
429 assertNotNull(document);
430 final var expectedSchema = "toaster2_config_module";
431 // verify schema reference itself
432 verifyRequestRef(document.getPaths().path("/rests/data").path("post"),
433 getAppropriateModelPrefix(ApiDocServiceImpl.OAversion.V3_0) + expectedSchema,
434 getAppropriateModelPrefix(ApiDocServiceImpl.OAversion.V3_0) + expectedSchema);
435 // verify existence of the schemas being referenced
436 assertTrue("The expected referenced schema (" + expectedSchema + ") is not created",
437 document.getComponents().getSchemas().has(expectedSchema));
441 * Test that reference to schema in each path is valid (all referenced schemas exist).
444 public void testSchemasExistenceSingleModule() {
445 final var document = (OpenApiObject) generator.getApiDeclaration(NAME, REVISION_DATE, URI_INFO,
446 ApiDocServiceImpl.OAversion.V3_0);
447 assertNotNull(document);
448 final var referencedSchemas = new HashSet<String>();
449 for (final var elements = document.getPaths().elements(); elements.hasNext(); ) {
450 final var path = elements.next();
451 referencedSchemas.addAll(extractSchemaRefFromPath(path, ApiDocServiceImpl.OAversion.V3_0));
453 final var schemaNamesIterator = document.getComponents().getSchemas().fieldNames();
454 final var schemaNames = Sets.newHashSet(schemaNamesIterator);
455 for (final var ref : referencedSchemas) {
456 assertTrue("Referenced schema " + ref + " does not exist", schemaNames.contains(ref));
461 * Test that checks if namespace for rpc is present.
464 public void testRpcNamespace() {
465 final var doc = (OpenApiObject) generator.getApiDeclaration(NAME_2, REVISION_DATE, URI_INFO,
466 ApiDocServiceImpl.OAversion.V3_0);
468 final var path = doc.getPaths().get("/rests/operations/toaster:cancel-toast");
470 final var post = path.get("post");
472 final var requestBody = post.get("requestBody");
473 assertNotNull(requestBody);
474 final var content = requestBody.get("content");
475 assertNotNull(content);
476 final var application = content.get("application/xml");
477 assertNotNull(application);
478 final var schema = application.get("schema");
479 assertNotNull(schema);
480 final var xml = schema.get("xml");
482 final var namespace = xml.get("namespace");
483 assertNotNull(namespace);
484 assertEquals("http://netconfcentral.org/ns/toaster", namespace.asText());
488 * Test that checks if namespace for actions is present.
491 public void testActionsNamespace() {
492 final var doc = (OpenApiObject) generator.getApiDeclaration("action-types", null, URI_INFO,
493 ApiDocServiceImpl.OAversion.V3_0);
495 final var path = doc.getPaths().get("/rests/operations/action-types:multi-container/inner-container/action");
497 final var post = path.get("post");
499 final var requestBody = post.get("requestBody");
500 assertNotNull(requestBody);
501 final var content = requestBody.get("content");
502 assertNotNull(content);
503 final var application = content.get("application/xml");
504 assertNotNull(application);
505 final var schema = application.get("schema");
506 assertNotNull(schema);
507 final var xml = schema.get("xml");
509 final var namespace = xml.get("namespace");
510 assertNotNull(namespace);
511 assertEquals("urn:ietf:params:xml:ns:yang:test:action:types", namespace.asText());
515 * Test that number of elements in payload is correct.
517 @SuppressWarnings("unchecked")
519 public void testLeafListWithMinElementsPayload() {
520 final var doc = (OpenApiObject) generator.getApiDeclaration(MANDATORY_TEST, null, URI_INFO,
521 ApiDocServiceImpl.OAversion.V3_0);
523 final var paths = doc.getPaths();
524 final var path = paths.path("/rests/data/mandatory-test:root-container/mandatory-container");
525 final var requestBody = path.path("post").path("requestBody").path("content");
526 final var jsonRef = requestBody.path("application/json").path("schema").path("$ref");
527 final var xmlRef = requestBody.path("application/xml").path("schema").path("$ref");
528 final var schema = doc.getComponents().getSchemas().path("mandatory-test_root-container_mandatory-container");
529 final var minItems = schema.path("properties").path("leaf-list-with-min-elements").path("minItems");
530 final var listOfExamples = ((ArrayNode) schema.path("properties").path("leaf-list-with-min-elements")
532 final var expectedListOfExamples = JsonNodeFactory.instance.arrayNode()
533 .add("Some leaf-list-with-min-elements")
534 .add("Some leaf-list-with-min-elements");
535 assertFalse(listOfExamples.isMissingNode());
536 assertEquals(xmlRef, jsonRef);
537 assertEquals(2, minItems.intValue());
538 assertEquals(expectedListOfExamples, listOfExamples);
542 * Test JSON and XML references for request operation.
544 private static void verifyRequestRef(final JsonNode path, final String expectedJsonRef,
545 final String expectedXmlRef) {
546 final JsonNode postContent;
547 if (path.get("requestBody") != null) {
548 postContent = path.get("requestBody").get("content");
550 postContent = path.get("responses").get("200").get("content");
552 assertNotNull(postContent);
553 final var postJsonRef = postContent.get("application/json").get("schema").get("$ref");
554 assertNotNull(postJsonRef);
555 assertEquals(expectedJsonRef, postJsonRef.textValue());
556 final var postXmlRef = postContent.get("application/xml").get("schema").get("$ref");
557 assertNotNull(postXmlRef);
558 assertEquals(expectedXmlRef, postXmlRef.textValue());
561 private static void verifyPostRequestRef(final JsonNode path, final String expectedJsonRef,
562 final String expectedXmlRef, String nodeType) {
563 final JsonNode postContent;
564 if (path.get("requestBody") != null) {
565 postContent = path.get("requestBody").get("content");
567 postContent = path.get("responses").get("200").get("content");
569 assertNotNull(postContent);
570 final String postJsonRef;
571 if (nodeType.equals(CONTAINER)) {
572 postJsonRef = postContent.path("application/json").path("schema").path("properties").elements().next()
573 .path("$ref").textValue();
575 postJsonRef = postContent.path("application/json").path("schema").path("properties").elements().next()
576 .path("items").path("$ref").textValue();
578 assertEquals(expectedJsonRef, postJsonRef);
579 final var postXmlRef = postContent.get("application/xml").get("schema").get("$ref");
580 assertNotNull(postXmlRef);
581 assertEquals(expectedXmlRef, postXmlRef.textValue());
584 private static Set<String> extractSchemaRefFromPath(final JsonNode path,
585 final ApiDocServiceImpl.OAversion oaversion) {
586 if (path == null || path.isMissingNode()) {
589 final var references = new HashSet<String>();
590 final var get = path.path("get");
591 if (!get.isMissingNode()) {
593 schemaRefFromContent(get.path(RESPONSES_KEY).path("200").path(CONTENT_KEY), oaversion));
595 final var post = path.path("post");
596 if (!post.isMissingNode()) {
597 references.addAll(schemaRefFromContent(post.path(REQUEST_BODY_KEY).path(CONTENT_KEY), oaversion));
599 final var put = path.path("put");
600 if (!put.isMissingNode()) {
601 references.addAll(schemaRefFromContent(put.path(REQUEST_BODY_KEY).path(CONTENT_KEY), oaversion));
603 final var patch = path.path("patch");
604 if (!patch.isMissingNode()) {
605 references.addAll(schemaRefFromContent(patch.path(REQUEST_BODY_KEY).path(CONTENT_KEY), oaversion));
610 private static Set<String> schemaRefFromContent(final JsonNode content,
611 final ApiDocServiceImpl.OAversion oaversion) {
612 final HashSet<String> refs = new HashSet<>();
613 content.fieldNames().forEachRemaining(mediaType -> {
614 final JsonNode ref = content.path(mediaType).path(SCHEMA_KEY).path(REF_KEY);
615 if (ref != null && !ref.isMissingNode()) {
616 refs.add(ref.asText().replaceFirst(getAppropriateModelPrefix(oaversion), ""));