OpenApi: Fix parameter types for paths 53/108553/4
authorlubos-cicut <lubos.cicut@pantheon.tech>
Tue, 10 Oct 2023 18:37:19 +0000 (20:37 +0200)
committerIvan Hrasko <ivan.hrasko@pantheon.tech>
Tue, 31 Oct 2023 08:29:49 +0000 (08:29 +0000)
Corrected the hard-coded "string" type for path parameters type to the
proper type. Created a test to verify that the Schema type is assigned
with the expected type.

JIRA: NETCONF-1168
Change-Id: I0c1ff3dd04044507840fe2c484145e8c5740776a
Signed-off-by: lubos-cicut <lubos.cicut@pantheon.tech>
Signed-off-by: Ivan Hrasko <ivan.hrasko@pantheon.tech>
(cherry picked from commit dd28415b7e9615f5f7e54dcc299c452d6a815cb9)

restconf/sal-rest-docgen/src/main/java/org/opendaylight/netconf/sal/rest/doc/impl/BaseYangSwaggerGenerator.java
restconf/sal-rest-docgen/src/test/java/org/opendaylight/netconf/sal/rest/doc/impl/ApiDocGeneratorRFC8040Test.java
restconf/sal-rest-docgen/src/test/java/org/opendaylight/netconf/sal/rest/doc/impl/MountPointSwaggerTest.java
restconf/sal-rest-docgen/src/test/resources/yang/typed-params.yang [new file with mode: 0644]

index 75832e18ca4e965e7f702f21fd4dd01893b8a321..58253deaa5272967f391e093334e10d0dc3ec254 100644 (file)
@@ -66,10 +66,21 @@ import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.OperationDefinition;
 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.OperationDefinition;
 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.Int16TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.Int32TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.Int64TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.Int8TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.Uint16TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.Uint32TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.Uint64TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.Uint8TypeDefinition;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -541,7 +552,7 @@ public abstract class BaseYangSwaggerGenerator {
 
                 final ObjectNode typeParent = getTypeParentNode(pathParam, oaversion);
 
 
                 final ObjectNode typeParent = getTypeParentNode(pathParam, oaversion);
 
-                typeParent.put("type", "string");
+                typeParent.put("type", getAllowedType((ListSchemaNode) schemaNode, listKey));
                 pathParam.put("in", "path");
                 pathParam.put("required", true);
 
                 pathParam.put("in", "path");
                 pathParam.put("required", true);
 
@@ -551,6 +562,48 @@ public abstract class BaseYangSwaggerGenerator {
         return path.toString();
     }
 
         return path.toString();
     }
 
+    private static String getAllowedType(final ListSchemaNode list, final QName key) {
+        final var keyType = ((LeafSchemaNode) list.getDataChildByName(key)).getType();
+
+        // see: https://datatracker.ietf.org/doc/html/rfc7950#section-4.2.4
+        // see: https://swagger.io/docs/specification/data-models/data-types/
+        // TODO: Java 21 use pattern matching for switch
+        if (keyType instanceof Int8TypeDefinition) {
+            return "integer";
+        }
+        if (keyType instanceof Int16TypeDefinition) {
+            return "integer";
+        }
+        if (keyType instanceof Int32TypeDefinition) {
+            return "integer";
+        }
+        if (keyType instanceof Int64TypeDefinition) {
+            return "integer";
+        }
+        if (keyType instanceof Uint8TypeDefinition) {
+            return "integer";
+        }
+        if (keyType instanceof Uint16TypeDefinition) {
+            return "integer";
+        }
+        if (keyType instanceof Uint32TypeDefinition) {
+            return "integer";
+        }
+        if (keyType instanceof Uint64TypeDefinition) {
+            return "integer";
+        }
+
+        if (keyType instanceof DecimalTypeDefinition) {
+            return "number";
+        }
+
+        if (keyType instanceof BooleanTypeDefinition) {
+            return "boolean";
+        }
+
+        return "string";
+    }
+
     private String createUniquePathParamName(final String clearName, final ArrayNode pathParams) {
         for (final JsonNode pathParam : pathParams) {
             if (isNamePicked(clearName, pathParam)) {
     private String createUniquePathParamName(final String clearName, final ArrayNode pathParams) {
         for (final JsonNode pathParam : pathParams) {
             if (isNamePicked(clearName, pathParam)) {
index 976ad02d62d38afdcde96629850748ae7d94b9c1..9d525ca6fec85f9004971023f079066326df7cef 100644 (file)
@@ -271,6 +271,24 @@ public final class ApiDocGeneratorRFC8040Test extends AbstractApiDocTest {
         assertEquals(expected, actualContainerArray);
     }
 
         assertEquals(expected, actualContainerArray);
     }
 
+    /**
+     * Test that request parameters are correctly typed.
+     */
+    @Test
+    public void testParametersTypes() {
+        final var doc = (OpenApiObject) generator.getApiDeclaration("typed-params", "2023-10-24", URI_INFO,
+            ApiDocServiceImpl.OAversion.V3_0);
+        final var pathToContainer = "/rests/data/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 that request for actions is correct and has parameters.
      */
index 5d8b433b7336e642578ce5d8982600f88db73901..c1db115ba1353bd41d662d865d18703ec53255ab 100644 (file)
@@ -160,6 +160,25 @@ public final class MountPointSwaggerTest extends AbstractApiDocTest {
         assertEquals(List.of("name"), getPathParameters(mountPointApi.getPaths(), pathToList5));
     }
 
         assertEquals(List.of("name"), getPathParameters(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 that request for actions is correct and has parameters.
      */
diff --git a/restconf/sal-rest-docgen/src/test/resources/yang/typed-params.yang b/restconf/sal-rest-docgen/src/test/resources/yang/typed-params.yang
new file mode 100644 (file)
index 0000000..67bc93c
--- /dev/null
@@ -0,0 +1,176 @@
+module typed-params {
+    yang-version 1.1;
+    namespace "urn:typed-params";
+    prefix "tparams";
+
+    revision "2023-10-24" {
+        description "Initial revision.";
+    }
+
+    container typed {
+        list string {
+            key string-key;
+            leaf string-key {
+                type string;
+            }
+            leaf value {
+                type string;
+            }
+        }
+        list binary {
+            key binary-key;
+            leaf binary-key {
+                type binary;
+            }
+            leaf value {
+                type string;
+            }
+        }
+        list bits {
+            key bits-key;
+            leaf bits-key {
+                type bits {
+                    bit UP;
+                }
+            }
+            leaf value {
+                type string;
+            }
+        }
+        list boolean {
+            key boolean-key;
+            leaf boolean-key {
+                type boolean;
+            }
+            leaf value {
+                type string;
+            }
+        }
+        list empty {
+            key empty-key;
+            leaf empty-key {
+                type empty;
+            }
+            leaf value {
+                type string;
+            }
+        }
+        list enumeration {
+            key enumeration-key;
+            leaf enumeration-key {
+                type enumeration {
+                    enum first;
+                    enum second;
+                    enum third;
+                }
+            }
+            leaf value {
+                type string;
+            }
+        }
+        list instance-identifier {
+            key instance-identifier-key;
+            leaf instance-identifier-key {
+                type instance-identifier;
+            }
+            leaf value {
+                type string;
+            }
+        }
+        list int8 {
+            key int8-key;
+            leaf int8-key {
+                type int8;
+            }
+            leaf value {
+                type string;
+            }
+        }
+        list int16 {
+            key int16-key;
+            leaf int16-key {
+                type int16;
+            }
+            leaf value {
+                type string;
+            }
+        }
+        list int32 {
+            key int32-key;
+            leaf int32-key {
+                type int32;
+            }
+            leaf value {
+                type string;
+            }
+        }
+        list int64 {
+            key int64-key;
+            leaf int64-key {
+                type int64;
+            }
+            leaf value {
+                type string;
+            }
+        }
+        list uint8 {
+            key uint8-key;
+            leaf uint8-key {
+                type uint8;
+            }
+            leaf value {
+                type string;
+            }
+        }
+        list uint16 {
+            key uint16-key;
+            leaf uint16-key {
+                type uint16;
+            }
+            leaf value {
+                type string;
+            }
+        }
+        list uint32 {
+            key uint32-key;
+            leaf uint32-key {
+                type uint32;
+            }
+            leaf value {
+                type string;
+            }
+        }
+        list uint64 {
+            key uint64-key;
+            leaf uint64-key {
+                type uint64;
+            }
+            leaf value {
+                type string;
+            }
+        }
+        list decimal64 {
+            key decimal64-key;
+            leaf decimal64-key {
+                type decimal64 {
+                    fraction-digits 2;
+                }
+            }
+            leaf value {
+                type string;
+            }
+        }
+        list union {
+            key union-key;
+            leaf union-key {
+                type union {
+                    type int32;
+                    type string;
+                }
+            }
+            leaf value {
+                type string;
+            }
+        }
+    }
+}
\ No newline at end of file