From 47f851239293496f453cc08ed38a8bb11102a0d4 Mon Sep 17 00:00:00 2001 From: Bartosz Michalik Date: Tue, 13 Sep 2022 16:04:13 +0200 Subject: [PATCH] Fix for #57 (#58) fix for #57 --- .gitignore | 1 - README.md | 54 ++++-- cli/pom.xml | 14 +- .../com/mrv/yangtools/codegen/main/Main.java | 16 +- .../mrv/yangtools/codegen/main/Issue57.java | 82 +++++++++ cli/src/test/resources/bug_57/input.yang | 36 ++++ examples/maven-plugin-example/pom.xml | 164 ------------------ .../src/main/yang/example.yang | 93 ---------- .../src/main/yang/second.yang | 36 ---- examples/pom.xml | 1 - pom.xml | 4 +- swagger-generator/pom.xml | 8 +- .../yangtools/codegen/SwaggerGenerator.java | 9 +- .../ReplaceDefinitionsProcessor.java | 39 ++--- .../impl/postprocessor/CollapseTypesTest.java | 131 ++++++++++++++ .../mrv/yangtools/codegen/issues/Issue57.java | 22 +++ .../yangtools/test/utils/SwaggerReader.java | 2 +- .../src/test/resources/bug_57/input.yang | 36 ++++ .../replace-definitions-minimal.yaml | 69 ++++++++ 19 files changed, 466 insertions(+), 351 deletions(-) create mode 100644 cli/src/test/java/com/mrv/yangtools/codegen/main/Issue57.java create mode 100644 cli/src/test/resources/bug_57/input.yang delete mode 100644 examples/maven-plugin-example/pom.xml delete mode 100644 examples/maven-plugin-example/src/main/yang/example.yang delete mode 100644 examples/maven-plugin-example/src/main/yang/second.yang create mode 100644 swagger-generator/src/test/java/com/mrv/yangtools/codegen/impl/postprocessor/CollapseTypesTest.java create mode 100644 swagger-generator/src/test/java/com/mrv/yangtools/codegen/issues/Issue57.java create mode 100644 swagger-generator/src/test/resources/bug_57/input.yang create mode 100644 swagger-generator/src/test/resources/replace-definitions-minimal.yaml diff --git a/.gitignore b/.gitignore index 247f060d..5b6bb361 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -*.yaml .idea/ **/*.iml target/ diff --git a/README.md b/README.md index a2b61717..1ea06c75 100644 --- a/README.md +++ b/README.md @@ -37,26 +37,50 @@ we have prepared our own version of the code generator. You might run it standal You can easily run ```SwaggerGenerator``` from the command-line: ``` -java -jar ~/.m2/repository/com/mrv/yangtools/swagger-generator-cli/1.0-SNAPSHOT/swagger-generator-cli-1.0-SNAPSHOT-executable.jar +java -jar swagger-generator-cli-<>-executable.jar Argument "module ..." is required - module ... : List of YANG module names to generate in swagger output - -output file : File to generate, containing the output - defaults to stdout - (default: ) - -yang-dir path : Directory to search for YANG modules - defaults to current - directory (default: ) - -api-version string : The current version of your API (default: 1.0) - -format enum : The output format (options: YAML, JSON) (default: YAML) - -content-type string: Content type the API generates / consumes (default: application/yang-data+json) - -simplify-hierarchy : Use it to generate Swagger which with simplified inheritence model which can be used with standard code generators. (default: false) - -use-namespaces : Use namespaces in resource URI (default: false) - -fullCrud : If the flag is set to false path are generated for GET operations only. (default: true) - -elements : Define YANG elements to focus on. (default: DATA + RPC) - -authentication : Authentication definition (options: BASIC, NONE) (default: NONE) +module ... : List of YANG module names to generate + in swagger output + -api-version file : Version of api generated - default 1.0 + (default: 1.0) + -authentication [BASIC | NONE] : Authentication definition (default: + NONE) + -content-type VAL : Content type the API generates / + consumes - default application/yang-dat + a+json (default: application/yang-data+ + json) + -elements [DATA | RPC | DATA_AND_RPC] : Define YANG elements to focus on. + Defaul DATA + RPC (default: + DATA_AND_RPC) + -format [YAML | JSON] : Output format of generated file - + defaults to yaml with options of json + or yaml (default: YAML) + -fullCrud : If the flag is set to false path are + generated for GET operations only. + Default true (default: true) + -output file : File to generate, containing the + output - defaults to stdout (default: ) + -reuse-groupings : Use it to generate Swagger which + attempts to reuse structurally + identical grouping types. Default + false (default: false) + -simplify-hierarchy : Use it to generate Swagger which with + simplified inheritence model which can + be used with standard code generators. + Default false (default: false) + -use-namespaces : Use namespaces in resource URI + (default: false) + -use-odl-path-format : Select to use bierman-02 RESTCONF path + format. Default false (default: false) + -yang-dir path : Directory to search for YANG modules - + defaults to current directory. + Multiple dirs might be separated by + system path separator (default: ) ``` For example: ``` -java -jar ~/.m2/repository/com/mrv/yangtools/swagger-generator-cli/1.0-SNAPSHOT/swagger-generator-cli-1.0-SNAPSHOT-executable.jar \ +java -jar swagger-generator-cli-<>-executable.jar \ -yang-dir examples/build-standalone/src/main/resources \ -output swagger.yaml \ mef-services diff --git a/cli/pom.xml b/cli/pom.xml index 134d8f62..d1e2b1cf 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -9,10 +9,6 @@ 4.0.0 - - 1.5.9 - - swagger-generator-cli @@ -34,6 +30,16 @@ args4j 2.33 + + junit + junit + + + io.swagger + swagger-parser + 1.0.61 + test + diff --git a/cli/src/main/java/com/mrv/yangtools/codegen/main/Main.java b/cli/src/main/java/com/mrv/yangtools/codegen/main/Main.java index 0047e446..5850b81b 100644 --- a/cli/src/main/java/com/mrv/yangtools/codegen/main/Main.java +++ b/cli/src/main/java/com/mrv/yangtools/codegen/main/Main.java @@ -58,6 +58,9 @@ public class Main { @Option(name = "-simplify-hierarchy", usage = "Use it to generate Swagger which with simplified inheritence model which can be used with standard code generators. Default false") public boolean simplified = false; + @Option(name = "-reuse-groupings", usage = "Use it to generate Swagger which attempts to reuse structurally identical grouping types. Default false") + public boolean reuseGroupings = false; + @Option(name = "-use-namespaces", usage="Use namespaces in resource URI") public boolean useNamespaces = false; @@ -84,7 +87,7 @@ public enum AuthenticationMechanism { BASIC, NONE } - OutputStream out = System.out; + public OutputStream out = System.out; public static void main(String[] args) { @@ -104,13 +107,13 @@ public static void main(String[] args) { } } - protected void init() throws FileNotFoundException { + void init() throws FileNotFoundException { if (output != null && output.trim().length() > 0) { out = new FileOutputStream(output); } } - protected void generate() throws IOException, ReactorException { + void generate() throws IOException, ReactorException { final PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:*.yang"); final SchemaContext context = buildSchemaContext(yangDir, p -> matcher.matches(p.getFileName())); @@ -149,13 +152,16 @@ protected void generate() throws IOException, ReactorException { .pathHandler(pathHandler) .elements(map(elementType)); - generator - .appendPostProcessor(new CollapseTypes()); + if(AuthenticationMechanism.BASIC.equals(authenticationMechanism)) { generator.appendPostProcessor(new AddSecurityDefinitions().withSecurityDefinition("api_sec", new BasicAuthDefinition())); } + if(reuseGroupings) { + generator.appendPostProcessor(new CollapseTypes()); + } + if(simplified) { generator.appendPostProcessor(new SingleParentInheritenceModel()); } diff --git a/cli/src/test/java/com/mrv/yangtools/codegen/main/Issue57.java b/cli/src/test/java/com/mrv/yangtools/codegen/main/Issue57.java new file mode 100644 index 00000000..807860ed --- /dev/null +++ b/cli/src/test/java/com/mrv/yangtools/codegen/main/Issue57.java @@ -0,0 +1,82 @@ +package com.mrv.yangtools.codegen.main; + +import io.swagger.models.Swagger; +import io.swagger.parser.SwaggerParser; +import org.junit.Assert; +import org.junit.Test; +import org.kohsuke.args4j.CmdLineParser; + +import java.io.ByteArrayOutputStream; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Paths; +import java.util.List; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class Issue57 { + private static String path; + + static { + try { + path = Paths.get(Issue57.class.getResource("/bug_57/").toURI()).toAbsolutePath().toString(); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + + @Test + public void testRegular() { + + List args = Stream.of( + "-yang-dir", + path + ).collect(Collectors.toList()); + + Swagger swagger = runParser(args); + assertContainsOnly(swagger, s -> s.endsWith("Input"), + "objects.createobject.Input","objects.updateobject.Input"); + } + + @Test + public void testOptimized() { + + List args = Stream.of( + "-reuse-groupings", + "-yang-dir", + path + ).collect(Collectors.toList()); + + Swagger swagger = runParser(args); + + assertContainsOnly(swagger, s -> s.endsWith("Input"), "objects.createobject.Input"); + } + + private void assertContainsOnly(Swagger swagger, Predicate filterDefs, String... name) { + Set result = swagger.getDefinitions().keySet().stream() + .filter(filterDefs) + .collect(Collectors.toSet()); + Set expected = Stream.of(name) + .collect(Collectors.toSet()); + Assert.assertEquals(expected, result); + } + + private Swagger runParser(List args) { + Main main = new Main(); + CmdLineParser parser = new CmdLineParser(main); + try { + parser.parseArgument(args); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + main.out = baos; + main.init(); + main.generate(); + + return new SwaggerParser().parse(new String(baos.toByteArray(), StandardCharsets.UTF_8)); + } catch (Exception e) { + throw new RuntimeException(e); + } + + } +} diff --git a/cli/src/test/resources/bug_57/input.yang b/cli/src/test/resources/bug_57/input.yang new file mode 100644 index 00000000..628cfd66 --- /dev/null +++ b/cli/src/test/resources/bug_57/input.yang @@ -0,0 +1,36 @@ +module objects { + + yang-version "1.1"; + namespace "urn:objects"; + prefix "obje"; + + grouping id_1 { + leaf id_1 { + type "string"; + } + } + + grouping id_2 { + leaf id_2 { + type "string"; + } + } + + rpc create-object { + input { + uses id_1; + uses id_2; + } + output { + } + } + + rpc update-object { + input { + uses id_1; + uses id_2; + } + output { + } + } +} \ No newline at end of file diff --git a/examples/maven-plugin-example/pom.xml b/examples/maven-plugin-example/pom.xml deleted file mode 100644 index d756155e..00000000 --- a/examples/maven-plugin-example/pom.xml +++ /dev/null @@ -1,164 +0,0 @@ - - - - - - examples - com.mrv.yangtools - 1.1.15-SNAPSHOT - - 4.0.0 - - - io.swagger - swagger-annotations - 1.5.21 - - - com.fasterxml.jackson.core - jackson-annotations - 2.8.0 - - - - - ${project.basedir}/target/generated-sources/swagger - 1.5.21 - - - maven-plugin-example - - - - org.opendaylight.yangtools - yang-maven-plugin - ${yangtools.version} - - - ${project.groupId} - swagger-maven-plugin - ${project.version} - jar - - - - - - generate-sources - - - - - com.mrv.yangtools.maven.gen.swagger.MavenSwaggerGenerator - ${swaggerGeneratorPath} - - - true - - - - - - - io.swagger - swagger-codegen-maven-plugin - ${swagger.codegen.version} - - - ${project.groupId} - swagger-codegen-jaxrs - ${project.version} - - - - - - - generate - - - - ${swaggerGeneratorPath}/yang.swagger - - - jaxrs-mrv - - - - java8 - - - false - target/generated-sources/jaxRS - - - - - - - - - - org.eclipse.m2e - lifecycle-mapping - 1.0.0 - - - - - - io.swagger - - swagger-codegen-maven-plugin - - - [2.2.1,) - - - generate - - - - - - - - - - org.opendaylight.yangtools - - - yang-maven-plugin - - - [1.0.0-Boron,) - - - - generate-sources - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/maven-plugin-example/src/main/yang/example.yang b/examples/maven-plugin-example/src/main/yang/example.yang deleted file mode 100644 index 6fbdddd3..00000000 --- a/examples/maven-plugin-example/src/main/yang/example.yang +++ /dev/null @@ -1,93 +0,0 @@ -module example-module { - namespace "http://amartus/ns/yang/example-module"; - prefix s; - organization "test-yang"; - description "example-module to demo maven integration"; - - revision 2016-06-22 { - description "Final"; - } - - typedef myint1 { - type int32 { - range 1..4096; - } - } - - grouping resource { - container state { - leaf id { - type int32; - } - leaf status { - type string; - } - } - leaf name { - type string; - } - } - - rpc addResource { - input { - leaf zip-code { - type string; - } - uses resource; - } - output { - container response { - leaf configrmation { - type string; - } - uses resource; - } - } - } - - container some-root { - leaf id { type string; } - - list children1 { - leaf id { - type myint1; - } - - leaf str { - type string; - } - - list children2 { - leaf id { - type int32; - } - leaf parent-id { - type leafref { - path "../../id"; - } - } - key "id parent-id"; - } - - list children3 { - config false; - leaf id { - type int32; - } - leaf parent-id { - type leafref { - path "../../id"; - } - } - container desc { - leaf owner { type string; } - leaf description { type string; } - } - key "id parent-id"; - } - - key "id"; - } - } - -} \ No newline at end of file diff --git a/examples/maven-plugin-example/src/main/yang/second.yang b/examples/maven-plugin-example/src/main/yang/second.yang deleted file mode 100644 index db0267e3..00000000 --- a/examples/maven-plugin-example/src/main/yang/second.yang +++ /dev/null @@ -1,36 +0,0 @@ -module pingpong-module { - namespace "http://amartus/ns/yang/pingpong-module"; - prefix s; - organization "test-yang"; - description "example-module to demo maven integration"; - - revision 2016-08-08 { - description "Final"; - } - - container configuration { - leaf customize { - type boolean; - } - container test { - leaf test { - type string; - } - } - } - - rpc ping { - input { - leaf ping { - type string; - } - } - output { - container response { - leaf pong { - type string; - } - } - } - } -} \ No newline at end of file diff --git a/examples/pom.xml b/examples/pom.xml index 5680f935..66fec194 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,7 +21,6 @@ 4.0.0 pom - maven-plugin-example build-standalone diff --git a/pom.xml b/pom.xml index 4388440f..83a609b7 100644 --- a/pom.xml +++ b/pom.xml @@ -31,8 +31,8 @@ 1.2.9 - 1.5.9 2.2.1 + 1.6.6 1.2.1 4.1.0 @@ -139,7 +139,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.3 + 3.10.1 1.8 1.8 diff --git a/swagger-generator/pom.xml b/swagger-generator/pom.xml index ad8e7485..f40a78f4 100644 --- a/swagger-generator/pom.xml +++ b/swagger-generator/pom.xml @@ -20,10 +20,6 @@ 4.0.0 - - 1.5.9 - - swagger-generator @@ -54,14 +50,14 @@ swagger-core ${swagger.version} - io.swagger swagger-parser - [1.0.31,1.9.99) + 1.0.61 test + junit junit diff --git a/swagger-generator/src/main/java/com/mrv/yangtools/codegen/SwaggerGenerator.java b/swagger-generator/src/main/java/com/mrv/yangtools/codegen/SwaggerGenerator.java index 6e7d8481..2337826e 100644 --- a/swagger-generator/src/main/java/com/mrv/yangtools/codegen/SwaggerGenerator.java +++ b/swagger-generator/src/main/java/com/mrv/yangtools/codegen/SwaggerGenerator.java @@ -1,11 +1,12 @@ /* - * Copyright (c) 2018 Amartus. All rights reserved. + * Copyright (c) 2018-2022 Amartus. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Damian Mrozowicz + * Bartosz Michalik */ package com.mrv.yangtools.codegen; @@ -23,6 +24,8 @@ import com.mrv.yangtools.common.SwaggerUtils; import io.swagger.models.Info; import io.swagger.models.Swagger; +import io.swagger.util.Json; +import io.swagger.util.Yaml; import org.opendaylight.yangtools.yang.model.api.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -200,11 +203,11 @@ public SwaggerGenerator elements(Elements... elements) { public SwaggerGenerator format(Format f) { switch(f) { case YAML: - mapper = new ObjectMapper(new YAMLFactory()); + mapper = Yaml.mapper(); break; case JSON: default: - mapper = new ObjectMapper(new JsonFactory()); + mapper = Json.mapper(); } mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); return this; diff --git a/swagger-generator/src/main/java/com/mrv/yangtools/codegen/impl/postprocessor/ReplaceDefinitionsProcessor.java b/swagger-generator/src/main/java/com/mrv/yangtools/codegen/impl/postprocessor/ReplaceDefinitionsProcessor.java index 39c35b4e..03adf0cc 100644 --- a/swagger-generator/src/main/java/com/mrv/yangtools/codegen/impl/postprocessor/ReplaceDefinitionsProcessor.java +++ b/swagger-generator/src/main/java/com/mrv/yangtools/codegen/impl/postprocessor/ReplaceDefinitionsProcessor.java @@ -25,7 +25,7 @@ import java.util.stream.Collectors; /** - * Processor that allows replacing one definitions with another in any swagger. + * Processor that allows replacing one definition with another one in any swagger. * This implementation is simple and limited only to the type definitions that are aggregators of references. * @author bartosz.michalik@amartus.com */ @@ -51,13 +51,19 @@ public void accept(Swagger target) { private void fixModel(String name, Model m, Map replacements) { ModelImpl fixProperties = null; + + if(m instanceof RefModel) { + fixRefModel((RefModel) m, replacements); + return; + } + if(m instanceof ModelImpl) { fixProperties = (ModelImpl) m; } if(m instanceof ComposedModel) { ComposedModel cm = (ComposedModel) m; - fixComposedModel(name, cm, replacements); + fixComposedModel(cm, replacements); fixProperties = cm.getAllOf().stream() .filter(c -> c instanceof ModelImpl).map(c -> (ModelImpl)c) .findFirst().orElse(null); @@ -88,13 +94,13 @@ private void fixModel(String name, Model m, Map replacements) { } private boolean fixProperty(RefProperty p, Map replacements) { if(replacements.containsKey(p.getSimpleRef())) { - p.set$ref(replacements.get(p.getSimpleRef())); + p.set$ref("#/definitions/" + replacements.get(p.getSimpleRef())); return true; } return false; } - private void fixComposedModel(String name, ComposedModel m, Map replacements) { + private void fixComposedModel(ComposedModel m, Map replacements) { Set toReplace = m.getAllOf().stream().filter(c -> c instanceof RefModel).map(cm -> (RefModel) cm) .filter(rm -> replacements.containsKey(rm.getSimpleRef())).collect(Collectors.toSet()); toReplace.forEach(r -> { @@ -107,6 +113,11 @@ private void fixComposedModel(String name, ComposedModel m, Map }); } + private void fixRefModel(RefModel model, Map replacements) { + if(replacements.containsKey(model.getSimpleRef())) { + model.set$ref("#/definitions/" + replacements.get(model.getSimpleRef())); + } + } private void fixOperation(Operation operation, Map replacements) { operation.getResponses().values() @@ -126,26 +137,14 @@ private void fixOperation(Operation operation, Map replacements) private void fixParameter(Parameter p, Map replacements) { if(!(p instanceof BodyParameter)) return; BodyParameter bp = (BodyParameter) p; - if(!(bp.getSchema() instanceof RefModel)) return; - RefModel ref = (RefModel) bp.getSchema(); - if(replacements.containsKey(ref.getSimpleRef())) { - String replacement = replacements.get(ref.getSimpleRef()); - bp.setDescription(bp.getDescription().replace(ref.getSimpleRef(), replacement)); - bp.setSchema(new RefModel(replacement)); - } + fixModel(null, bp.getSchema(), replacements); } private void fixResponse(Response r, Map replacements) { - if(! (r.getSchema() instanceof RefProperty)) return; - RefProperty schema = (RefProperty) r.getSchema(); - if(replacements.containsKey(schema.getSimpleRef())) { - String replacement = replacements.get(schema.getSimpleRef()); - if(r.getDescription() != null) - r.setDescription(r.getDescription().replace(schema.getSimpleRef(), replacement)); - schema.setDescription(replacement); - r.setSchema(new RefProperty(replacement)); + Model model = r.getResponseSchema(); + if(model != null) { + fixModel(null, model, replacements); } - } } diff --git a/swagger-generator/src/test/java/com/mrv/yangtools/codegen/impl/postprocessor/CollapseTypesTest.java b/swagger-generator/src/test/java/com/mrv/yangtools/codegen/impl/postprocessor/CollapseTypesTest.java new file mode 100644 index 00000000..7fb95b00 --- /dev/null +++ b/swagger-generator/src/test/java/com/mrv/yangtools/codegen/impl/postprocessor/CollapseTypesTest.java @@ -0,0 +1,131 @@ +package com.mrv.yangtools.codegen.impl.postprocessor; + +import com.mrv.yangtools.codegen.SwaggerGenerator; +import com.mrv.yangtools.test.utils.SwaggerReader; +import io.swagger.models.*; +import io.swagger.models.parameters.BodyParameter; +import io.swagger.models.parameters.Parameter; +import io.swagger.models.parameters.RefParameter; +import io.swagger.models.properties.ArrayProperty; +import io.swagger.models.properties.Property; +import io.swagger.models.properties.RefProperty; +import org.hamcrest.CoreMatchers; +import org.hamcrest.MatcherAssert; +import org.junit.Assert; +import org.junit.Test; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class CollapseTypesTest { + @Test + public void testReduceSameStructures() { + Swagger swagger = swaggerForClasspath("/replace-definitions-minimal.yaml"); + + long initial = countDefinitions(swagger); + + new CollapseTypes().accept(swagger); + + long target = countDefinitions(swagger); + + Assert.assertEquals(initial - 1, target); + MatcherAssert.assertThat(danglingRefs(swagger), CoreMatchers.equalTo(new HashSet())); + } + + private Stream references(Property model) { + if(model instanceof ArrayProperty) { + return references(((ArrayProperty) model).getItems()); + } + if(model instanceof RefProperty) { + return Stream.of(((RefProperty) model).get$ref()); + } + return Stream.empty(); + } + + private Stream references(Model model) { + if(model == null) { + return Stream.empty(); + } + if(model.getReference() != null) { + return Stream.of(model.getReference()); + } + if(model instanceof ModelImpl) { + return model.getProperties().values() + .stream().flatMap(this::references); + } + if(model instanceof ComposedModel) { + ComposedModel cm = (ComposedModel) model; + return cm.getAllOf().stream().flatMap(this::references); + } + return Stream.empty(); + } + + private Stream references(Swagger swagger) { + return Stream.concat( + swagger.getDefinitions().values().stream() + .flatMap(this::references), + swagger.getPaths().values().stream() + .flatMap(this::references) + ); + } + + private Stream references(Path path) { + return path.getOperations().stream() + .flatMap(this::references); + } + + private Stream references(Operation operation) { + return Stream.concat( + operation.getParameters().stream().flatMap(this::references), + operation.getResponses().values().stream().flatMap(this::references) + ); + } + + private Stream references(Parameter parameter) { + if(parameter instanceof RefParameter) { + return Stream.of(((RefParameter) parameter).get$ref()); + } + if(parameter instanceof BodyParameter) { + return references(((BodyParameter) parameter).getSchema()); + } + return Stream.empty(); + } + private Stream references(Response response) { + return references(response.getResponseSchema()); + } + private Set danglingRefs(Swagger swagger) { + Set definitions = swagger.getDefinitions().keySet(); + Set allRef = references(swagger) + .filter(r -> r.startsWith("#/definitions")) + .map(r -> r.substring("#/definitions/".length())) + .collect(Collectors.toSet()); + allRef.removeAll(definitions); + return allRef; + } + + protected long countDefinitions(Swagger swagger) { + return countDefinitions(swagger, it -> true); + } + protected long countDefinitions(Swagger swagger, Predicate> filter) { + return swagger.getDefinitions().entrySet().stream() + .filter(filter) + .count(); + } + + protected Swagger swaggerForClasspath(String path) { + try(InputStream input = CollapseTypesTest.class + .getResourceAsStream(path)) { + + return new SwaggerReader().read(new InputStreamReader(input), SwaggerGenerator.Format.YAML); + } catch(Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/swagger-generator/src/test/java/com/mrv/yangtools/codegen/issues/Issue57.java b/swagger-generator/src/test/java/com/mrv/yangtools/codegen/issues/Issue57.java new file mode 100644 index 00000000..486980fb --- /dev/null +++ b/swagger-generator/src/test/java/com/mrv/yangtools/codegen/issues/Issue57.java @@ -0,0 +1,22 @@ +package com.mrv.yangtools.codegen.issues; + +import com.mrv.yangtools.codegen.AbstractItTest; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class Issue57 extends AbstractItTest { + @Test + public void testIssue57() { + swaggerFor(p -> p.getParent().getFileName().toString().equals("bug_57")); + Set result = swagger.getDefinitions().keySet().stream() + .filter(s -> s.endsWith("Input")) + .collect(Collectors.toSet()); + Set expected = Stream.of("objects.createobject.Input", "objects.updateobject.Input") + .collect(Collectors.toSet()); + Assert.assertEquals(expected, result); + } +} diff --git a/swagger-generator/src/test/java/com/mrv/yangtools/test/utils/SwaggerReader.java b/swagger-generator/src/test/java/com/mrv/yangtools/test/utils/SwaggerReader.java index d49f7e6a..6714b121 100644 --- a/swagger-generator/src/test/java/com/mrv/yangtools/test/utils/SwaggerReader.java +++ b/swagger-generator/src/test/java/com/mrv/yangtools/test/utils/SwaggerReader.java @@ -30,7 +30,7 @@ */ public class SwaggerReader { - Swagger read(Reader reader, SwaggerGenerator.Format format) throws IOException { + public Swagger read(Reader reader, SwaggerGenerator.Format format) throws IOException { ObjectMapper objectMapper = format == SwaggerGenerator.Format.JSON ? new ObjectMapper(new JsonFactory()) : new ObjectMapper(new YAMLFactory()); diff --git a/swagger-generator/src/test/resources/bug_57/input.yang b/swagger-generator/src/test/resources/bug_57/input.yang new file mode 100644 index 00000000..628cfd66 --- /dev/null +++ b/swagger-generator/src/test/resources/bug_57/input.yang @@ -0,0 +1,36 @@ +module objects { + + yang-version "1.1"; + namespace "urn:objects"; + prefix "obje"; + + grouping id_1 { + leaf id_1 { + type "string"; + } + } + + grouping id_2 { + leaf id_2 { + type "string"; + } + } + + rpc create-object { + input { + uses id_1; + uses id_2; + } + output { + } + } + + rpc update-object { + input { + uses id_1; + uses id_2; + } + output { + } + } +} \ No newline at end of file diff --git a/swagger-generator/src/test/resources/replace-definitions-minimal.yaml b/swagger-generator/src/test/resources/replace-definitions-minimal.yaml new file mode 100644 index 00000000..b230fc3d --- /dev/null +++ b/swagger-generator/src/test/resources/replace-definitions-minimal.yaml @@ -0,0 +1,69 @@ +swagger: "2.0" +info: + description: "TEST" + version: "1.0.0-SNAPSHOT" + title: "Test" +host: "localhost:8080" +basePath: "/restconf" +consumes: + - "application/json" +produces: + - "application/json" +paths: + /operations/create-object: + post: + tags: + - "objects" + parameters: + - in: "body" + name: "objects.createobject.Input.body-param" + required: false + schema: + properties: + input: + $ref: "#/definitions/objects.createobject.Input" + responses: + "400": + description: "Internal error" + "201": + description: "No response" + /operations/update-object: + post: + tags: + - "objects" + parameters: + - in: "body" + name: "objects.updateobject.Input.body-param" + required: false + schema: + properties: + input: + $ref: "#/definitions/objects.updateobject.Input" + responses: + "400": + description: "Internal error" + "200": + description: "OK" + schema: + $ref: "#/definitions/objects.updateobject.Input" + "201": + description: "No response" +definitions: + objects.Id2: + type: "object" + properties: + id_2: + type: "string" + objects.Id1: + type: "object" + properties: + id_1: + type: "string" + objects.createobject.Input: + allOf: + - $ref: "#/definitions/objects.Id2" + - $ref: "#/definitions/objects.Id1" + objects.updateobject.Input: + allOf: + - $ref: "#/definitions/objects.Id2" + - $ref: "#/definitions/objects.Id1" \ No newline at end of file