Refactor OpenApiTestUtils methods
[netconf.git] / restconf / sal-rest-docgen / src / test / java / org / opendaylight / netconf / sal / rest / doc / impl / MountPointSwaggerTest.java
index 69e4423b0855b34ca6f3f5d3363f5103cfd2f770..623a166acf85684358d353459f859b676ae8a49d 100644 (file)
@@ -8,13 +8,17 @@
 package org.opendaylight.netconf.sal.rest.doc.impl;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
 import com.fasterxml.jackson.databind.node.ObjectNode;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -22,6 +26,7 @@ import java.util.Optional;
 import java.util.Set;
 import java.util.TreeSet;
 import javax.ws.rs.core.UriInfo;
+import org.glassfish.jersey.internal.util.collection.ImmutableMultivaluedMap;
 import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.mdsal.dom.api.DOMMountPoint;
@@ -35,17 +40,27 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 
 public final class MountPointSwaggerTest extends AbstractApiDocTest {
-    private static final String HTTP_URL = "http://localhost/path";
+    private static final String TOASTER = "toaster";
+    private static final String TOASTER_REVISION = "2009-11-20";
+    private static final Long DEVICE_ID = 1L;
+    private static final String DEVICE_NAME = "123";
+    private static final String TOASTER_NODE_PATH = "/rests/data/nodes/node=123/yang-ext:mount/toaster:toaster";
+    private static final String TOASTER_NODE_GET_SUMMARY = "GET - " + DEVICE_NAME + " - toaster - toaster";
+    private static final String GET_ALL = "http://localhost:8181/openapi/api/v3/mounts/" + DEVICE_ID;
+    private static final String GET_TOASTER = "http://localhost:8181/openapi/api/v3/mounts/%s/%s(%s)".formatted(
+            DEVICE_ID, TOASTER, TOASTER_REVISION);
     private static final YangInstanceIdentifier INSTANCE_ID = YangInstanceIdentifier.builder()
             .node(QName.create("", "nodes"))
             .node(QName.create("", "node"))
-            .nodeWithKey(QName.create("", "node"), QName.create("", "id"), "123").build();
+            .nodeWithKey(QName.create("", "node"), QName.create("", "id"), DEVICE_NAME).build();
     private static final String INSTANCE_URL = "/nodes/node=123/";
 
     private MountPointSwagger swagger;
+    private UriInfo uriDeviceAll;
+    private UriInfo uriDeviceToaster;
 
     @Before
-    public void before() {
+    public void before() throws Exception {
         // We are sharing the global schema service and the mount schema service
         // in our test.
         // OK for testing - real thing would have separate instances.
@@ -56,6 +71,11 @@ public final class MountPointSwaggerTest extends AbstractApiDocTest {
         when(service.getMountPoint(INSTANCE_ID)).thenReturn(Optional.of(mountPoint));
 
         swagger = new MountPointSwaggerGeneratorRFC8040(SCHEMA_SERVICE, service).getMountPointSwagger();
+
+        uriDeviceAll = DocGenTestHelper.createMockUriInfo(GET_ALL);
+        when(uriDeviceAll.getQueryParameters()).thenReturn(ImmutableMultivaluedMap.empty());
+        uriDeviceToaster = DocGenTestHelper.createMockUriInfo(GET_TOASTER);
+        when(uriDeviceToaster.getQueryParameters()).thenReturn(ImmutableMultivaluedMap.empty());
     }
 
     @Test()
@@ -72,11 +92,10 @@ public final class MountPointSwaggerTest extends AbstractApiDocTest {
     }
 
     @Test
-    public void testGetDataStoreApi() throws Exception {
-        final UriInfo mockInfo = DocGenTestHelper.createMockUriInfo(HTTP_URL);
+    public void testGetDataStoreApi() {
         swagger.onMountPointCreated(INSTANCE_ID); // add this ID into the list of mount points
 
-        final SwaggerObject mountPointApi = (SwaggerObject) swagger.getMountPointApi(mockInfo, 1L, "Datastores", "-",
+        final SwaggerObject mountPointApi = (SwaggerObject) swagger.getMountPointApi(URI_INFO, 1L, "Datastores", "-",
             OAversion.V2_0);
         assertNotNull("failed to find Datastore API", mountPointApi);
 
@@ -113,24 +132,218 @@ public final class MountPointSwaggerTest extends AbstractApiDocTest {
      * It means we should have name and name1, etc. when we have the same parameter in path multiple times.
      */
     @Test
-    public void testParametersNumberingForMountPointApi() throws Exception {
-        final UriInfo mockInfo = DocGenTestHelper.createMockUriInfo(HTTP_URL);
+    public void testParametersNumberingForMountPointApi() {
         swagger.onMountPointCreated(INSTANCE_ID);
 
-        final OpenApiObject mountPointApi = (OpenApiObject) swagger.getMountPointApi(mockInfo, 1L, Optional.empty(),
+        final OpenApiObject mountPointApi = (OpenApiObject) swagger.getMountPointApi(URI_INFO, 1L, Optional.empty(),
                 OAversion.V3_0);
         assertNotNull("Failed to find Datastore API", mountPointApi);
 
         var pathToList1 = "/rests/data/nodes/node=123/yang-ext:mount/path-params-test:cont/list1={name}";
         assertTrue(mountPointApi.getPaths().has(pathToList1));
-        assertEquals(List.of("name"), getPathParameters(mountPointApi.getPaths(), pathToList1));
+        assertEquals(List.of("name"), getPathGetParameters(mountPointApi.getPaths(), pathToList1));
 
         var pathToList2 = "/rests/data/nodes/node=123/yang-ext:mount/path-params-test:cont/list1={name}/list2={name1}";
         assertTrue(mountPointApi.getPaths().has(pathToList2));
-        assertEquals(List.of("name", "name1"), getPathParameters(mountPointApi.getPaths(), pathToList2));
+        assertEquals(List.of("name", "name1"), getPathGetParameters(mountPointApi.getPaths(), pathToList2));
 
         var pathToList3 = "/rests/data/nodes/node=123/yang-ext:mount/path-params-test:cont/list3={name}";
         assertTrue(mountPointApi.getPaths().has(pathToList3));
-        assertEquals(List.of("name"), getPathParameters(mountPointApi.getPaths(), pathToList3));
+        assertEquals(List.of("name"), getPathGetParameters(mountPointApi.getPaths(), pathToList3));
+
+        var pathToList4 = "/rests/data/nodes/node=123/yang-ext:mount/path-params-test:cont/list1={name}/list4={name1}";
+        assertTrue(mountPointApi.getPaths().has(pathToList4));
+        assertEquals(List.of("name", "name1"), getPathGetParameters(mountPointApi.getPaths(), pathToList4));
+
+        var pathToList5 = "/rests/data/nodes/node=123/yang-ext:mount/path-params-test:cont/list1={name}/cont2";
+        assertTrue(mountPointApi.getPaths().has(pathToList5));
+        assertEquals(List.of("name"), getPathGetParameters(mountPointApi.getPaths(), pathToList5));
+    }
+
+    /**
+     * Test that request parameters are correctly typed.
+     */
+    @Test
+    public void testParametersTypesForMountPointApi() throws Exception {
+        swagger.onMountPointCreated(INSTANCE_ID);
+        final var doc = (OpenApiObject) swagger.getMountPointApi(URI_INFO, 1L, Optional.empty(),
+            OAversion.V3_0);
+        final var pathToContainer = "/rests/data/nodes/node=123/yang-ext:mount/typed-params:typed/";
+        final var integerTypes = List.of("uint64", "uint32", "uint16", "uint8", "int64", "int32", "int16", "int8");
+        for (final var type: integerTypes) {
+            final var typeKey = type + "-key";
+            final var path = pathToContainer + type + "={" + typeKey + "}";
+            assertTrue(doc.getPaths().has(path));
+            assertEquals("integer", doc.getPaths().get(path).get("get").get("parameters").get(0).get("schema")
+                .get("type").textValue());
+        }
+    }
+
+    /**
+     * Test that request for actions is correct and has parameters.
+     */
+    @Test
+    public void testActionPathsParamsForMountPointApi() {
+        swagger.onMountPointCreated(INSTANCE_ID);
+
+        final var mountPointApi = (OpenApiObject) swagger.getMountPointApi(URI_INFO, 1L, Optional.empty(),
+            OAversion.V3_0);
+        assertNotNull("Failed to find Datastore API", mountPointApi);
+
+        final var pathWithParameters =
+            "/rests/operations/nodes/node=123/yang-ext:mount/action-types:list={name}/list-action";
+        assertTrue(mountPointApi.getPaths().has(pathWithParameters));
+        assertEquals(List.of("name"), getPathPostParameters(mountPointApi.getPaths(), pathWithParameters));
+
+        final var pathWithoutParameters =
+            "/rests/operations/nodes/node=123/yang-ext:mount/action-types:multi-container/inner-container/action";
+        assertTrue(mountPointApi.getPaths().has(pathWithoutParameters));
+        assertEquals(List.of(), getPathPostParameters(mountPointApi.getPaths(), pathWithoutParameters));
+    }
+
+    @Test
+    public void testSummaryForAllModules() {
+        swagger.onMountPointCreated(INSTANCE_ID);
+        // get OpenApiObject for the device (all modules)
+        final OpenApiObject openApiAll = (OpenApiObject) swagger.getMountPointApi(uriDeviceAll, DEVICE_ID,
+            Optional.empty(), OAversion.V3_0);
+        final var paths = openApiAll.getPaths();
+        final String getToasterSummary = openApiAll.getPaths()
+            .get(TOASTER_NODE_PATH)
+            .get("get")
+            .get("summary")
+            .asText();
+        assertEquals(TOASTER_NODE_GET_SUMMARY, getToasterSummary);
+    }
+
+    @Test
+    public void testSummaryForSingleModule() {
+        swagger.onMountPointCreated(INSTANCE_ID);
+        // get OpenApiObject for a specific module (toaster) associated with the mounted device
+        final OpenApiObject openApiToaster = (OpenApiObject) swagger.getMountPointApi(uriDeviceToaster, DEVICE_ID,
+            TOASTER, TOASTER_REVISION, OAversion.V3_0);
+        final String getToasterSummary = openApiToaster.getPaths()
+            .get(TOASTER_NODE_PATH)
+            .get("get")
+            .get("summary")
+            .asText();
+        assertEquals(TOASTER_NODE_GET_SUMMARY, getToasterSummary);
+    }
+
+    @Test
+    public void testPathsForSpecificModuleOfMounted() {
+        swagger.onMountPointCreated(INSTANCE_ID);
+        // get OpenApiObject for the device (all modules)
+        final OpenApiObject openApiAll = (OpenApiObject) swagger.getMountPointApi(uriDeviceAll, DEVICE_ID,
+            Optional.empty(), OAversion.V3_0);
+        // get OpenApiObject for a specific module (toaster(2009-11-20))
+        final OpenApiObject openApiToaster = (OpenApiObject) swagger.getMountPointApi(uriDeviceToaster, DEVICE_ID,
+            TOASTER, TOASTER_REVISION, OAversion.V3_0);
+        /*
+            filter paths from openapi for all modules down to only those that are present in openapi for toaster.
+            The object for the path, that in this case ends with "yang-ext:mount" is constructed in a different way
+            when requesting OpenApiObject for a single module compared to requesting it for all modules.
+            We do not want to include it in this particular comparison, so filter it out
+         */
+        final Set<JsonNode> toasterPathsFromAll = new HashSet<>();
+        openApiAll.getPaths().fieldNames().forEachRemaining(path -> {
+            if (openApiToaster.getPaths().has(path) && !path.endsWith("yang-ext:mount")) {
+                toasterPathsFromAll.add(openApiAll.getPaths().get(path));
+            }
+        });
+        final Set<JsonNode> toasterPathsFromToaster = new HashSet<>();
+        openApiToaster.getPaths().fieldNames().forEachRemaining(path -> {
+            if (!path.endsWith("yang-ext:mount")) {
+                toasterPathsFromToaster.add(openApiToaster.getPaths().get(path));
+            }
+        });
+        // verify that the filtered set (from openapi for all modules) is the same as the set from openapi for toaster
+        assertEquals(toasterPathsFromToaster, toasterPathsFromAll);
+    }
+
+    /**
+     * Test that checks if namespace for rpc is present.
+     */
+    @Test
+    public void testRpcNamespace() {
+        swagger.onMountPointCreated(INSTANCE_ID);
+        final OpenApiObject openApiToaster = (OpenApiObject) swagger.getMountPointApi(uriDeviceToaster, DEVICE_ID,
+            TOASTER, TOASTER_REVISION, OAversion.V3_0);
+        final var path = openApiToaster
+            .getPaths().get("/rests/operations/nodes/node=123/yang-ext:mount/toaster:cancel-toast");
+        assertNotNull(path);
+        final var post = path.get("post");
+        assertNotNull(post);
+        final var requestBody = post.get("requestBody");
+        assertNotNull(requestBody);
+        final var content = requestBody.get("content");
+        assertNotNull(content);
+        final var application = content.get("application/xml");
+        assertNotNull(application);
+        final var schema = application.get("schema");
+        assertNotNull(schema);
+        final var xml = schema.get("xml");
+        assertNotNull(xml);
+        final var namespace = xml.get("namespace");
+        assertNotNull(namespace);
+        assertEquals("http://netconfcentral.org/ns/toaster", namespace.asText());
+    }
+
+    /**
+     * Test that checks if namespace for actions is present.
+     */
+    @Test
+    public void testActionsNamespace() {
+        swagger.onMountPointCreated(INSTANCE_ID);
+        final var openApiAll = (OpenApiObject) swagger.getMountPointApi(uriDeviceAll, DEVICE_ID,
+            Optional.empty(), OAversion.V3_0);
+        final var path = openApiAll.getPaths().get(
+            "/rests/operations/nodes/node=123/yang-ext:mount/action-types:multi-container/inner-container/action");
+        assertNotNull(path);
+        final var post = path.get("post");
+        assertNotNull(post);
+        final var requestBody = post.get("requestBody");
+        assertNotNull(requestBody);
+        final var content = requestBody.get("content");
+        assertNotNull(content);
+        final var application = content.get("application/xml");
+        assertNotNull(application);
+        final var schema = application.get("schema");
+        assertNotNull(schema);
+        final var xml = schema.get("xml");
+        assertNotNull(xml);
+        final var namespace = xml.get("namespace");
+        assertNotNull(namespace);
+        assertEquals("urn:ietf:params:xml:ns:yang:test:action:types", namespace.asText());
+    }
+
+    /**
+     * Test that number of elements in payload is correct.
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testLeafListWithMinElementsPayloadOnMountPoint() {
+        swagger.onMountPointCreated(INSTANCE_ID);
+        final var mountPointApi = (OpenApiObject) swagger.getMountPointApi(uriDeviceAll, 1L, Optional.empty(),
+            OAversion.V3_0);
+        assertNotNull(mountPointApi);
+        final var paths = mountPointApi.getPaths();
+        final var path =
+            paths.path("/rests/data/nodes/node=123/yang-ext:mount/mandatory-test:root-container/mandatory-container");
+        final var requestBody = path.path("post").path("requestBody").path("content");
+        final var jsonRef = requestBody.path("application/json").path("schema").path("$ref");
+        final var xmlRef = requestBody.path("application/xml").path("schema").path("$ref");
+        final var schema =
+            mountPointApi.getComponents().getSchemas().path("mandatory-test_root-container_mandatory-container");
+        final var minItems = schema.path("properties").path("leaf-list-with-min-elements").path("minItems");
+        final var listOfExamples = ((ArrayNode) schema.path("properties").path("leaf-list-with-min-elements")
+            .path("example"));
+        final var expectedListOfExamples = JsonNodeFactory.instance.arrayNode()
+            .add("Some leaf-list-with-min-elements")
+            .add("Some leaf-list-with-min-elements");
+        assertFalse(listOfExamples.isMissingNode());
+        assertEquals(jsonRef, xmlRef);
+        assertEquals(2, minItems.intValue());
+        assertEquals(expectedListOfExamples, listOfExamples);
     }
 }