OpenApi: Add parameters into actions 84/105884/24
authorYaroslav Lastivka <yaroslav.lastivka@pantheon.tech>
Wed, 10 May 2023 11:01:09 +0000 (14:01 +0300)
committerIvan Hrasko <ivan.hrasko@pantheon.tech>
Thu, 22 Jun 2023 11:47:18 +0000 (13:47 +0200)
Some devices using actions have invalid swagger URLs
generated. The problem is that we do not generate parameters
for actions.

Implemented logic for adding “pathParameters” to path parameters
for actions.

JIRA: NETCONF-860
Change-Id: If01af731770029fb8f7529312417a3ea46fd5841
Signed-off-by: Yaroslav Lastivka <yaroslav.lastivka@pantheon.tech>
Signed-off-by: Ivan Hrasko <ivan.hrasko@pantheon.tech>
restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/BaseYangOpenApiGenerator.java
restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/builder/OperationBuilder.java
restconf/restconf-openapi/src/test/java/org/opendaylight/restconf/openapi/impl/OpenApiGeneratorRFC8040Test.java
restconf/restconf-openapi/src/test/java/org/opendaylight/restconf/openapi/mountpoints/MountPointOpenApiTest.java

index 3b744197632ee9a686a6c6bb9e15cfc78f32ea2e..7c03e38b28ff11d025191cc5763c62f02851ae29 100644 (file)
@@ -252,11 +252,12 @@ public abstract class BaseYangOpenApiGenerator {
             }
         }
 
+        final ArrayNode pathParams = JsonNodeFactory.instance.arrayNode();
         for (final RpcDefinition rpcDefinition : module.getRpcs()) {
             final String resolvedPath = getResourcePath("operations", context) + "/" + moduleName + ":"
                     + rpcDefinition.getQName().getLocalName();
             addOperations(rpcDefinition, moduleName, deviceName, paths, moduleName, definitionNames,
-                resolvedPath);
+                resolvedPath, pathParams);
         }
 
         LOG.debug("Number of Paths found [{}]", paths.size());
@@ -315,7 +316,8 @@ public abstract class BaseYangOpenApiGenerator {
             ((ActionNodeContainer) node).getActions().forEach(actionDef -> {
                 final String resolvedPath = "/rests/operations" + resourcePath.substring(11)
                         + "/" + resolvePathArgumentsName(actionDef.getQName(), node.getQName(), schemaContext);
-                addOperations(actionDef, moduleName, deviceName, paths, parentName, definitionNames, resolvedPath);
+                addOperations(actionDef, moduleName, deviceName, paths, parentName, definitionNames, resolvedPath,
+                    pathParams);
             });
         }
 
@@ -438,9 +440,10 @@ public abstract class BaseYangOpenApiGenerator {
 
     private static void addOperations(final OperationDefinition operDef, final String moduleName,
             final Optional<String> deviceName, final Map<String, Path> paths, final String parentName,
-            final DefinitionNames definitionNames, final String resourcePath) {
+            final DefinitionNames definitionNames, final String resourcePath, final ArrayNode parentPathParams) {
         final var pathBuilder = new Path.Builder();
-        pathBuilder.post(buildPostOperation(operDef, moduleName, deviceName, parentName, definitionNames));
+        pathBuilder.post(buildPostOperation(operDef, moduleName, deviceName, parentName, definitionNames,
+            parentPathParams));
         paths.put(resourcePath, pathBuilder.build());
     }
 
index faf9691a1f0921f51ec415b44172c623a61ba73a..921a2084ad46f32040c19f86ca03ee2b79ba7703 100644 (file)
@@ -206,8 +206,9 @@ public final class OperationBuilder {
     }
 
     public static Operation buildPostOperation(final OperationDefinition operDef, final String moduleName,
-            final Optional<String> deviceName, final String parentName, final DefinitionNames definitionNames) {
-        final ArrayNode parameters = JsonNodeFactory.instance.arrayNode();
+            final Optional<String> deviceName, final String parentName, final DefinitionNames definitionNames,
+            final ArrayNode parentPathParameters) {
+        final ArrayNode parameters = JsonNodeFactory.instance.arrayNode().addAll(parentPathParameters);
         final String operationName = operDef.getQName().getLocalName();
         final String inputName = operationName + INPUT_SUFFIX;
         final String summary = buildSummaryValue(HttpMethod.POST, moduleName, deviceName, operationName);
index e0f179e8615a549920cc259abfa8da78c1c9c97f..2a7926fb2761b2f1ec56bc8d608f2f16bc40f58b 100644 (file)
@@ -309,6 +309,23 @@ public final class OpenApiGeneratorRFC8040Test {
         assertEquals(List.of("name"), getPathParameters(doc.paths(), pathToList5));
     }
 
+    /**
+     * Test that request for actions is correct and has parameters.
+     */
+    @Test
+    public void testActionPathsParams() {
+        final var module = context.findModule("action-types").orElseThrow();
+        final var doc = generator.getOpenApiSpec(module, "http", "localhost:8181", "/", "", context);
+
+        final var pathWithParameters = "/rests/operations/action-types:list={name}/list-action";
+        assertTrue(doc.paths().containsKey(pathWithParameters));
+        assertEquals(List.of("name"), getPathParameters(doc.paths(), pathWithParameters));
+
+        final var pathWithoutParameters = "/rests/operations/action-types:multi-container/inner-container/action";
+        assertTrue(doc.paths().containsKey(pathWithoutParameters));
+        assertEquals(List.of(), getPathParameters(doc.paths(), pathWithoutParameters));
+    }
+
     @Test
     public void testSimpleOpenApiObjects() {
         final var module = context.findModule("my-yang", Revision.of("2022-10-06")).orElseThrow();
index 4630623740c23fbfdc6a6344390c803c8295fcf0..3f1a05e9f84c8d0a22b59fcc4456da4388f8b017 100644 (file)
@@ -229,4 +229,26 @@ public final class MountPointOpenApiTest {
         assertTrue(mountPointApi.paths().containsKey(pathToList5));
         assertEquals(List.of("name"), getPathParameters(mountPointApi.paths(), pathToList5));
     }
+
+    /**
+     * Test that request for actions is correct and has parameters.
+     */
+    @Test
+    public void testActionPathsParamsForMountPointApi() throws Exception {
+        final var mockInfo = DocGenTestHelper.createMockUriInfo(HTTP_URL);
+        openApi.onMountPointCreated(INSTANCE_ID);
+
+        final var mountPointApi = openApi.getMountPointApi(mockInfo, 1L, Optional.empty());
+        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.paths().containsKey(pathWithParameters));
+        assertEquals(List.of("name"), getPathParameters(mountPointApi.paths(), pathWithParameters));
+
+        final var pathWithoutParameters =
+            "/rests/operations/nodes/node=123/yang-ext:mount/action-types:multi-container/inner-container/action";
+        assertTrue(mountPointApi.paths().containsKey(pathWithoutParameters));
+        assertEquals(List.of(), getPathParameters(mountPointApi.paths(), pathWithoutParameters));
+    }
 }