diff --git a/core/esmf-aspect-model-document-generators/src/main/java/org/eclipse/esmf/aspectmodel/generator/openapi/AspectModelOpenApiGenerator.java b/core/esmf-aspect-model-document-generators/src/main/java/org/eclipse/esmf/aspectmodel/generator/openapi/AspectModelOpenApiGenerator.java index 2e8bc5588..8f64dc6b0 100644 --- a/core/esmf-aspect-model-document-generators/src/main/java/org/eclipse/esmf/aspectmodel/generator/openapi/AspectModelOpenApiGenerator.java +++ b/core/esmf-aspect-model-document-generators/src/main/java/org/eclipse/esmf/aspectmodel/generator/openapi/AspectModelOpenApiGenerator.java @@ -63,16 +63,19 @@ public class AspectModelOpenApiGenerator private static final String FIELD_DESCRIPTION = "description"; private static final String FIELD_FILTER = "Filter"; private static final String FIELD_GET = "get"; + private static final String FIELD_POST = "post"; + private static final String FIELD_PUT = "put"; + private static final String FIELD_PATCH = "patch"; private static final String FIELD_OBJECT = "object"; private static final String FIELD_OPERATION = "Operation"; private static final String FIELD_OPERATION_ID = "operationId"; private static final String FIELD_OPERATION_RESPONSE = "OperationResponse"; protected static final String FIELD_PAGING_SCHEMA = "PagingSchema"; private static final String FIELD_PARAMETERS = "parameters"; - private static final String FIELD_POST = "post"; private static final String FIELD_PROPERTIES = "properties"; private static final String FIELD_RPC = "JsonRpc"; private static final String FIELD_REQUEST_BODIES = "requestBodies"; + private static final String FIELD_REQUEST_BODY = "requestBody"; private static final String FIELD_REQUIRED = "required"; private static final String FIELD_RESPONSES = "responses"; private static final String FIELD_SCHEMA = "schema"; @@ -118,9 +121,9 @@ public OpenApiSchemaArtifact apply( final Aspect aspect, final OpenApiSchemaGene final ObjectNode rootNode = getRootJsonNode( config.generateCommentForSeeAttributes() ); final String apiVersion = getApiVersion( aspect, config.useSemanticVersion() ); - ( (ObjectNode) rootNode.get( "info" ) ).put( "title", aspect.getPreferredName( config.locale() ) ); - ( (ObjectNode) rootNode.get( "info" ) ).put( "version", apiVersion ); - ( (ObjectNode) rootNode.get( "info" ) ).put( AspectModelJsonSchemaVisitor.SAMM_EXTENSION, + ((ObjectNode) rootNode.get( "info" )).put( "title", aspect.getPreferredName( config.locale() ) ); + ((ObjectNode) rootNode.get( "info" )).put( "version", apiVersion ); + ((ObjectNode) rootNode.get( "info" )).put( AspectModelJsonSchemaVisitor.SAMM_EXTENSION, aspect.getAspectModelUrn().map( Object::toString ).orElse( "" ) ); setServers( rootNode, config.baseUrl(), apiVersion, READ_SERVER_PATH ); final boolean includePaging = includePaging( aspect, config.pagingOption() ); @@ -332,7 +335,7 @@ private String getApiVersion( final Aspect aspect, final boolean useSemanticVers private void setResponseBodies( final Aspect aspect, final ObjectNode jsonNode, final boolean includePaging ) { final ObjectNode componentsResponseNode = (ObjectNode) jsonNode.get( FIELD_COMPONENTS ).get( FIELD_RESPONSES ); final ObjectNode referenceNode = FACTORY.objectNode() - .put( REF, COMPONENTS_SCHEMAS + ( includePaging ? FIELD_PAGING_SCHEMA : aspect.getName() ) ); + .put( REF, COMPONENTS_SCHEMAS + (includePaging ? FIELD_PAGING_SCHEMA : aspect.getName()) ); final ObjectNode contentNode = getApplicationNode( referenceNode ); componentsResponseNode.set( aspect.getName(), contentNode ); contentNode.put( FIELD_DESCRIPTION, "The request was successful." ); @@ -506,9 +509,25 @@ private ObjectNode getPathsNode( final Aspect aspect, final OpenApiSchemaGenerat pathNode.set( FIELD_GET, getRequestEndpointsRead( aspect, propertiesNode, config.resourcePath() ) ); + boolean includeCrud = config.includeCrud(); + + if ( includeCrud || config.includePost() ) { + pathNode.set( FIELD_POST, getRequestEndpointsCreate( aspect, propertiesNode, config.resourcePath() ) ); + } + + if ( includeCrud || config.includePut() ) { + pathNode.set( FIELD_PUT, getRequestEndpointsUpdate( aspect, propertiesNode, config.resourcePath(), true ) ); + } + + if ( includeCrud || config.includePatch() ) { + pathNode.set( FIELD_PATCH, getRequestEndpointsUpdate( aspect, propertiesNode, config.resourcePath(), false ) ); + } + if ( config.includeQueryApi() ) { - pathNode.set( FIELD_POST, + final ObjectNode includeQueryPathNode = FACTORY.objectNode(); + includeQueryPathNode.set( FIELD_POST, getRequestEndpointFilter( aspect, propertiesNode, config.baseUrl(), apiVersion, config.resourcePath() ) ); + endpointPathsNode.set( config.baseUrl() + String.format( QUERY_SERVER_PATH, apiVersion ), includeQueryPathNode ); } final Optional operationsNode = getRequestEndpointOperations( aspect, propertiesNode, config.baseUrl(), apiVersion, @@ -532,7 +551,7 @@ private Optional getRequestEndpointOperations( final Aspect aspect, objectNode.set( "tags", FACTORY.arrayNode().add( aspect.getName() ) ); objectNode.put( FIELD_OPERATION_ID, FIELD_POST + FIELD_OPERATION + aspect.getName() ); objectNode.set( FIELD_PARAMETERS, getRequiredParameters( parameterNode, isEmpty( resourcePath ) ) ); - objectNode.set( "requestBody", FACTORY.objectNode().put( REF, COMPONENTS_REQUESTS + FIELD_OPERATION ) ); + objectNode.set( FIELD_REQUEST_BODY, FACTORY.objectNode().put( REF, COMPONENTS_REQUESTS + FIELD_OPERATION ) ); final ObjectNode responseNode = FACTORY.objectNode(); objectNode.set( FIELD_RESPONSES, responseNode ); responseNode.set( "200", FACTORY.objectNode().put( REF, COMPONENTS_RESPONSES + FIELD_OPERATION_RESPONSE ) ); @@ -603,7 +622,7 @@ private ObjectNode getRequestEndpointFilter( final Aspect aspect, final ObjectNo objectNode.set( "tags", FACTORY.arrayNode().add( aspect.getName() ) ); objectNode.put( FIELD_OPERATION_ID, FIELD_POST + aspect.getName() ); objectNode.set( FIELD_PARAMETERS, getRequiredParameters( parameterNode, isEmpty( resourcePath ) ) ); - objectNode.set( "requestBody", getRequestBodyForFilter() ); + objectNode.set( FIELD_REQUEST_BODY, getRequestBodyForFilter() ); objectNode.set( FIELD_RESPONSES, getResponsesForGet( aspect ) ); return objectNode; } @@ -621,6 +640,27 @@ private ObjectNode getRequestEndpointsRead( final Aspect aspect, final ObjectNod return objectNode; } + private ObjectNode getRequestEndpointsCreate( final Aspect aspect, final ObjectNode parameterNode, final String resourcePath ) { + final ObjectNode objectNode = FACTORY.objectNode(); + objectNode.set( "tags", FACTORY.arrayNode().add( aspect.getName() ) ); + objectNode.put( FIELD_OPERATION_ID, FIELD_POST + aspect.getName() ); + objectNode.set( FIELD_PARAMETERS, getRequiredParameters( parameterNode, isEmpty( resourcePath ) ) ); + objectNode.set( FIELD_REQUEST_BODY, FACTORY.objectNode() ); + objectNode.set( FIELD_RESPONSES, getResponsesForGet( aspect ) ); + return objectNode; + } + + private ObjectNode getRequestEndpointsUpdate( final Aspect aspect, final ObjectNode parameterNode, final String resourcePath, + final boolean isPut ) { + final ObjectNode objectNode = FACTORY.objectNode(); + objectNode.set( "tags", FACTORY.arrayNode().add( aspect.getName() ) ); + objectNode.put( FIELD_OPERATION_ID, (isPut ? FIELD_PUT : FIELD_PATCH) + aspect.getName() ); + objectNode.set( FIELD_PARAMETERS, getRequiredParameters( parameterNode, isEmpty( resourcePath ) ) ); + objectNode.set( FIELD_REQUEST_BODY, FACTORY.objectNode() ); + objectNode.set( FIELD_RESPONSES, getResponsesForGet( aspect ) ); + return objectNode; + } + private ObjectNode getResponsesForGet( final Aspect aspect ) { final ObjectNode responses = FACTORY.objectNode(); responses.set( "200", getSuccessfulNode( aspect ) ); diff --git a/core/esmf-aspect-model-document-generators/src/main/java/org/eclipse/esmf/aspectmodel/generator/openapi/OpenApiSchemaGenerationConfig.java b/core/esmf-aspect-model-document-generators/src/main/java/org/eclipse/esmf/aspectmodel/generator/openapi/OpenApiSchemaGenerationConfig.java index 35fa48a11..7dd6fd060 100644 --- a/core/esmf-aspect-model-document-generators/src/main/java/org/eclipse/esmf/aspectmodel/generator/openapi/OpenApiSchemaGenerationConfig.java +++ b/core/esmf-aspect-model-document-generators/src/main/java/org/eclipse/esmf/aspectmodel/generator/openapi/OpenApiSchemaGenerationConfig.java @@ -44,7 +44,14 @@ public record OpenApiSchemaGenerationConfig( String resourcePath, ObjectNode properties, PagingOption pagingOption, - boolean includeQueryApi + boolean includeQueryApi, + boolean includeCrud, + + boolean includePost, + + boolean includePut, + + boolean includePatch ) implements GenerationConfig { public OpenApiSchemaGenerationConfig { if ( locale == null ) { diff --git a/core/esmf-aspect-model-document-generators/src/test/java/org/eclipse/esmf/aspectmodel/generator/openapi/AspectModelOpenApiGeneratorTest.java b/core/esmf-aspect-model-document-generators/src/test/java/org/eclipse/esmf/aspectmodel/generator/openapi/AspectModelOpenApiGeneratorTest.java index dfbff4569..bbd7c9e56 100644 --- a/core/esmf-aspect-model-document-generators/src/test/java/org/eclipse/esmf/aspectmodel/generator/openapi/AspectModelOpenApiGeneratorTest.java +++ b/core/esmf-aspect-model-document-generators/src/test/java/org/eclipse/esmf/aspectmodel/generator/openapi/AspectModelOpenApiGeneratorTest.java @@ -87,7 +87,7 @@ public class AspectModelOpenApiGeneratorTest extends MetaModelVersions { @ParameterizedTest @EnumSource( value = TestAspect.class ) - public void testGeneration( final TestAspect testAspect ) throws IOException { + void testGeneration( final TestAspect testAspect ) throws IOException { final Aspect aspect = loadAspect( testAspect, KnownVersion.getLatest() ); final OpenApiSchemaGenerationConfig config = OpenApiSchemaGenerationConfigBuilder.builder() .useSemanticVersion( false ) @@ -108,7 +108,7 @@ public void testGeneration( final TestAspect testAspect ) throws IOException { for ( final Iterator> it = json.get( "components" ).get( "schemas" ).fields(); it.hasNext(); ) { final Map.Entry schema = it.next(); final Path keyForSchemaName = Path.of( schema.getKey() + ".json" ); - assertThat( jsonMap.keySet() ).contains( keyForSchemaName ); + assertThat( jsonMap ).containsKey( keyForSchemaName ); } final JsonNode rootDocument = jsonMap.get( Path.of( aspect.getName() + ".oai.json" ) ); assertThat( Streams.stream( rootDocument.get( "components" ).fieldNames() ).toList() ).doesNotContain( "schemas" ); @@ -119,7 +119,7 @@ public void testGeneration( final TestAspect testAspect ) throws IOException { for ( final Iterator> it = json.get( "components" ).get( "schemas" ).fields(); it.hasNext(); ) { final Map.Entry schema = it.next(); final Path keyForSchemaName = Path.of( schema.getKey() + ".yaml" ); - assertThat( yamlMap.keySet() ).contains( keyForSchemaName ); + assertThat( yamlMap ).containsKey( keyForSchemaName ); } } @@ -136,7 +136,7 @@ private void showJson( final JsonNode node ) { @ParameterizedTest @MethodSource( value = "allVersions" ) - public void testUseSemanticVersion( final KnownVersion metaModelVersion ) { + void testUseSemanticVersion( final KnownVersion metaModelVersion ) { final Aspect aspect = loadAspect( TestAspect.ASPECT_WITH_PROPERTY, metaModelVersion ); final OpenApiSchemaGenerationConfig config = OpenApiSchemaGenerationConfigBuilder.builder() .useSemanticVersion( true ) @@ -157,7 +157,7 @@ public void testUseSemanticVersion( final KnownVersion metaModelVersion ) { @ParameterizedTest @MethodSource( value = "allVersions" ) - public void testIncludeQueryApiWithSemanticVersion( final KnownVersion metaModelVersion ) { + void testIncludeQueryApiWithSemanticVersion( final KnownVersion metaModelVersion ) { final Aspect aspect = loadAspect( TestAspect.ASPECT, metaModelVersion ); final OpenApiSchemaGenerationConfig config = OpenApiSchemaGenerationConfigBuilder.builder() .useSemanticVersion( true ) @@ -168,13 +168,13 @@ public void testIncludeQueryApiWithSemanticVersion( final KnownVersion metaModel final JsonNode json = apiJsonGenerator.apply( aspect, config ).getContent(); final SwaggerParseResult result = new OpenAPIParser().readContents( json.toString(), null, null ); final OpenAPI openApi = result.getOpenAPI(); - assertThat( openApi.getPaths().get( "/" + TEST_RESOURCE_PATH ).getPost().getServers().get( 0 ).getUrl() ) + assertThat( openApi.getPaths().get( "https://test-aspect.example.com/query-api/v1.0.0" ).getPost().getServers().get( 0 ).getUrl() ) .isEqualTo( "https://test-aspect.example.com/query-api/v1.0.0" ); } @ParameterizedTest @MethodSource( value = "allVersions" ) - public void testDefaultResourcePath( final KnownVersion metaModelVersion ) { + void testDefaultResourcePath( final KnownVersion metaModelVersion ) { final Aspect aspect = loadAspect( TestAspect.ASPECT_WITHOUT_SEE_ATTRIBUTE, metaModelVersion ); final OpenApiSchemaGenerationConfig config = OpenApiSchemaGenerationConfigBuilder.builder() .useSemanticVersion( true ) @@ -185,12 +185,16 @@ public void testDefaultResourcePath( final KnownVersion metaModelVersion ) { final SwaggerParseResult result = new OpenAPIParser().readContents( json.toString(), null, null ); final OpenAPI openApi = result.getOpenAPI(); - assertThat( openApi.getPaths().keySet() ).allMatch( path -> path.equals( "/{tenant-id}/aspect-without-see-attribute" ) ); + assertThat( openApi.getPaths().get( "/{tenant-id}/aspect-without-see-attribute" ).getPost() ).isNull(); + assertThat( openApi.getPaths().get( "/{tenant-id}/aspect-without-see-attribute" ).getPut() ).isNull(); + assertThat( openApi.getPaths().get( "/{tenant-id}/aspect-without-see-attribute" ).getPatch() ).isNull(); + assertThat( openApi.getPaths().keySet() ).anyMatch( path -> path.equals( "/{tenant-id}/aspect-without-see-attribute" ) ); + assertThat( openApi.getPaths().keySet() ).anyMatch( path -> path.equals( "https://test-aspect.example.com/query-api/v1.0.0" ) ); } @ParameterizedTest @MethodSource( value = "allVersions" ) - public void testInvalidResourcePath( final KnownVersion metaModelVersion ) { + void testInvalidResourcePath( final KnownVersion metaModelVersion ) { final Aspect aspect = loadAspect( TestAspect.ASPECT_WITHOUT_SEE_ATTRIBUTE, metaModelVersion ); final OpenApiSchemaGenerationConfig config = OpenApiSchemaGenerationConfigBuilder.builder() .useSemanticVersion( true ) @@ -204,7 +208,7 @@ public void testInvalidResourcePath( final KnownVersion metaModelVersion ) { @ParameterizedTest @MethodSource( value = "allVersions" ) - public void testWithValidResourcePath( final KnownVersion metaModelVersion ) { + void testWithValidResourcePath( final KnownVersion metaModelVersion ) { final Aspect aspect = loadAspect( TestAspect.ASPECT_WITHOUT_SEE_ATTRIBUTE, metaModelVersion ); final OpenApiSchemaGenerationConfig config = OpenApiSchemaGenerationConfigBuilder.builder() .useSemanticVersion( true ) @@ -216,12 +220,13 @@ public void testWithValidResourcePath( final KnownVersion metaModelVersion ) { final SwaggerParseResult result = new OpenAPIParser().readContents( json.toString(), null, null ); final OpenAPI openApi = result.getOpenAPI(); - assertThat( openApi.getPaths().keySet() ).allMatch( path -> path.equals( "/" + TEST_RESOURCE_PATH ) ); + assertThat( openApi.getPaths().keySet() ).anyMatch( path -> path.equals( "/" + TEST_RESOURCE_PATH ) ); + assertThat( openApi.getPaths().keySet() ).anyMatch( path -> path.equals( "https://test-aspect.example.com/query-api/v1.0.0" ) ); } @ParameterizedTest @MethodSource( value = "allVersions" ) - public void testInvalidJsonParameter( final KnownVersion metaModelVersion ) { + void testInvalidJsonParameter( final KnownVersion metaModelVersion ) { final Aspect aspect = loadAspect( TestAspect.ASPECT_WITHOUT_SEE_ATTRIBUTE, metaModelVersion ); final OpenApiSchemaGenerationConfig config = OpenApiSchemaGenerationConfigBuilder.builder() .useSemanticVersion( true ) @@ -236,7 +241,7 @@ public void testInvalidJsonParameter( final KnownVersion metaModelVersion ) { @ParameterizedTest @MethodSource( value = "allVersions" ) - public void testValidParameter( final KnownVersion metaModelVersion ) throws IOException { + void testValidParameter( final KnownVersion metaModelVersion ) throws IOException { final Aspect aspect = loadAspect( TestAspect.ASPECT_WITHOUT_SEE_ATTRIBUTE, metaModelVersion ); final OpenApiSchemaGenerationConfig config = OpenApiSchemaGenerationConfigBuilder.builder() .useSemanticVersion( true ) @@ -246,11 +251,11 @@ public void testValidParameter( final KnownVersion metaModelVersion ) throws IOE .build(); final JsonNode json = apiJsonGenerator.apply( aspect, config ).getContent(); final SwaggerParseResult result = new OpenAPIParser().readContents( json.toString(), null, null ); - assertThat( result.getMessages().size() ).isZero(); + assertThat( result.getMessages() ).isEmpty(); final OpenAPI openApi = result.getOpenAPI(); assertThat( openApi.getPaths() ).hasSize( 1 ); - assertThat( openApi.getPaths().keySet() ).contains( "/my-test-aspect/{test-Id}" ); + assertThat( openApi.getPaths() ).containsKey( "/my-test-aspect/{test-Id}" ); openApi.getPaths().forEach( ( key, value ) -> { final List params = value.getGet().getParameters().stream().map( Parameter::getName ) .collect( Collectors.toList() ); @@ -261,7 +266,7 @@ public void testValidParameter( final KnownVersion metaModelVersion ) throws IOE @ParameterizedTest @MethodSource( value = "allVersions" ) - public void testInValidParameterName( final KnownVersion metaModelVersion ) throws IOException { + void testInValidParameterName( final KnownVersion metaModelVersion ) throws IOException { final ListAppender logAppender = new ListAppender<>(); final Logger logger = (Logger) LoggerFactory.getLogger( AspectModelOpenApiGenerator.class ); logger.addAppender( logAppender ); @@ -286,7 +291,7 @@ public void testInValidParameterName( final KnownVersion metaModelVersion ) thro @ParameterizedTest @MethodSource( value = "allVersions" ) - public void testYamlGenerator( final KnownVersion metaModelVersion ) throws IOException { + void testYamlGenerator( final KnownVersion metaModelVersion ) throws IOException { final Aspect aspect = loadAspect( TestAspect.ASPECT_WITHOUT_SEE_ATTRIBUTE, metaModelVersion ); final YAMLMapper yamlMapper = new YAMLMapper().enable( YAMLGenerator.Feature.MINIMIZE_QUOTES ); final OpenApiSchemaGenerationConfig yamlConfig = OpenApiSchemaGenerationConfigBuilder.builder() @@ -310,7 +315,7 @@ public void testYamlGenerator( final KnownVersion metaModelVersion ) throws IOEx @ParameterizedTest @MethodSource( value = "allVersions" ) - public void testHasQuerySchema( final KnownVersion metaModelVersion ) { + void testHasQuerySchema( final KnownVersion metaModelVersion ) { final Aspect aspect = loadAspect( TestAspect.ASPECT_WITHOUT_SEE_ATTRIBUTE, metaModelVersion ); final OpenApiSchemaGenerationConfig config = OpenApiSchemaGenerationConfigBuilder.builder() .useSemanticVersion( true ) @@ -321,13 +326,13 @@ public void testHasQuerySchema( final KnownVersion metaModelVersion ) { final SwaggerParseResult result = new OpenAPIParser().readContents( json.toString(), null, null ); final OpenAPI openApi = result.getOpenAPI(); - assertThat( openApi.getComponents().getSchemas().keySet() ).contains( "Filter" ); - assertThat( openApi.getComponents().getRequestBodies().keySet() ).contains( "Filter" ); + assertThat( openApi.getComponents().getSchemas() ).containsKey( "Filter" ); + assertThat( openApi.getComponents().getRequestBodies() ).containsKey( "Filter" ); } @ParameterizedTest @MethodSource( value = "allVersions" ) - public void testHasNoQuerySchema( final KnownVersion metaModelVersion ) { + void testHasNoQuerySchema( final KnownVersion metaModelVersion ) { final Aspect aspect = loadAspect( TestAspect.ASPECT_WITHOUT_SEE_ATTRIBUTE, metaModelVersion ); final OpenApiSchemaGenerationConfig config = OpenApiSchemaGenerationConfigBuilder.builder() .useSemanticVersion( true ) @@ -343,7 +348,7 @@ public void testHasNoQuerySchema( final KnownVersion metaModelVersion ) { @ParameterizedTest @MethodSource( value = "allVersions" ) - public void testHasPagingWithChosenPaging( final KnownVersion metaModelVersion ) { + void testHasPagingWithChosenPaging( final KnownVersion metaModelVersion ) { final Aspect aspect = loadAspect( TestAspect.ASPECT_WITH_COLLECTION, metaModelVersion ); final OpenApiSchemaGenerationConfig config = OpenApiSchemaGenerationConfigBuilder.builder() .useSemanticVersion( true ) @@ -353,7 +358,7 @@ public void testHasPagingWithChosenPaging( final KnownVersion metaModelVersion ) final JsonNode json = apiJsonGenerator.apply( aspect, config ).getContent(); final SwaggerParseResult result = new OpenAPIParser().readContents( json.toString(), null, null ); final OpenAPI openApi = result.getOpenAPI(); - assertThat( openApi.getPaths().keySet() ).contains( "/{tenant-id}/aspect-with-collection" ); + assertThat( openApi.getPaths() ).containsKey( "/{tenant-id}/aspect-with-collection" ); assertThat( openApi.getPaths().values().stream().findFirst().get().getGet().getParameters().get( 0 ).getName() ).isEqualTo( "tenant-id" ); assertThat( openApi.getPaths().values().stream().findFirst().get().getGet().getParameters().get( 1 ).getName() ).isEqualTo( "start" ); @@ -369,7 +374,7 @@ public void testHasPagingWithChosenPaging( final KnownVersion metaModelVersion ) @ParameterizedTest @MethodSource( value = "allVersions" ) - public void testHasPagingWithoutChosenPaging( final KnownVersion metaModelVersion ) { + void testHasPagingWithoutChosenPaging( final KnownVersion metaModelVersion ) { final Aspect aspect = loadAspect( TestAspect.ASPECT_WITH_TIME_SERIES, metaModelVersion ); final OpenApiSchemaGenerationConfig config = OpenApiSchemaGenerationConfigBuilder.builder() .useSemanticVersion( true ) @@ -378,7 +383,7 @@ public void testHasPagingWithoutChosenPaging( final KnownVersion metaModelVersio final JsonNode json = apiJsonGenerator.apply( aspect, config ).getContent(); final SwaggerParseResult result = new OpenAPIParser().readContents( json.toString(), null, null ); final OpenAPI openApi = result.getOpenAPI(); - assertThat( openApi.getPaths().keySet() ).contains( "/{tenant-id}/aspect-with-time-series" ); + assertThat( openApi.getPaths() ).containsKey( "/{tenant-id}/aspect-with-time-series" ); assertThat( openApi.getPaths().values().stream().findFirst().get().getGet().getParameters().get( 0 ).getName() ).isEqualTo( "tenant-id" ); assertThat( openApi.getPaths().values().stream().findFirst().get().getGet().getParameters().get( 1 ).getName() ).isEqualTo( "since" ); @@ -392,7 +397,7 @@ public void testHasPagingWithoutChosenPaging( final KnownVersion metaModelVersio @ParameterizedTest @MethodSource( value = "allVersions" ) - public void testHasPagingWitChosenCursorBasedPaging( final KnownVersion metaModelVersion ) { + void testHasPagingWitChosenCursorBasedPaging( final KnownVersion metaModelVersion ) { final Aspect aspect = loadAspect( TestAspect.ASPECT_WITH_COLLECTION, metaModelVersion ); final OpenApiSchemaGenerationConfig config = OpenApiSchemaGenerationConfigBuilder.builder() .useSemanticVersion( true ) @@ -402,7 +407,7 @@ public void testHasPagingWitChosenCursorBasedPaging( final KnownVersion metaMode final JsonNode json = apiJsonGenerator.apply( aspect, config ).getContent(); final SwaggerParseResult result = new OpenAPIParser().readContents( json.toString(), null, null ); final OpenAPI openApi = result.getOpenAPI(); - assertThat( openApi.getPaths().keySet() ).contains( "/{tenant-id}/aspect-with-collection" ); + assertThat( openApi.getPaths() ).containsKey( "/{tenant-id}/aspect-with-collection" ); assertThat( openApi.getPaths().values().stream().findFirst().get().getGet().getParameters().get( 0 ).getName() ).isEqualTo( "tenant-id" ); assertThat( openApi.getPaths().values().stream().findFirst().get().getGet().getParameters().get( 1 ).getName() ).isEqualTo( @@ -423,7 +428,7 @@ public void testHasPagingWitChosenCursorBasedPaging( final KnownVersion metaMode @ParameterizedTest @MethodSource( value = "allVersions" ) - public void testHasPagingWithWithDefaultChosenPaging( final KnownVersion metaModelVersion ) { + void testHasPagingWithWithDefaultChosenPaging( final KnownVersion metaModelVersion ) { final Aspect aspect = loadAspect( TestAspect.ASPECT_WITH_COLLECTION, metaModelVersion ); final OpenApiSchemaGenerationConfig config = OpenApiSchemaGenerationConfigBuilder.builder() .useSemanticVersion( true ) @@ -432,7 +437,7 @@ public void testHasPagingWithWithDefaultChosenPaging( final KnownVersion metaMod final JsonNode json = apiJsonGenerator.apply( aspect, config ).getContent(); final SwaggerParseResult result = new OpenAPIParser().readContents( json.toString(), null, null ); final OpenAPI openApi = result.getOpenAPI(); - assertThat( openApi.getPaths().keySet() ).contains( "/{tenant-id}/aspect-with-collection" ); + assertThat( openApi.getPaths() ).containsKey( "/{tenant-id}/aspect-with-collection" ); assertThat( openApi.getPaths().values().stream().findFirst().get().getGet().getParameters().get( 0 ).getName() ).isEqualTo( "tenant-id" ); assertThat( openApi.getPaths().values().stream().findFirst().get().getGet().getParameters().get( 1 ).getName() ).isEqualTo( "start" ); @@ -447,7 +452,7 @@ public void testHasPagingWithWithDefaultChosenPaging( final KnownVersion metaMod @ParameterizedTest @MethodSource( value = "allVersions" ) - public void testHasNoPagination( final KnownVersion metaModelVersion ) throws ProcessingException { + void testHasNoPagination( final KnownVersion metaModelVersion ) throws ProcessingException { final Aspect aspect = loadAspect( TestAspect.ASPECT_WITH_COLLECTION, metaModelVersion ); final OpenApiSchemaGenerationConfig config = OpenApiSchemaGenerationConfigBuilder.builder() .useSemanticVersion( true ) @@ -457,7 +462,7 @@ public void testHasNoPagination( final KnownVersion metaModelVersion ) throws Pr final JsonNode json = apiJsonGenerator.apply( aspect, config ).getContent(); final SwaggerParseResult result = new OpenAPIParser().readContents( json.toString(), null, null ); final OpenAPI openApi = result.getOpenAPI(); - assertThat( openApi.getPaths().keySet() ).contains( "/{tenant-id}/aspect-with-collection" ); + assertThat( openApi.getPaths() ).containsKey( "/{tenant-id}/aspect-with-collection" ); assertThat( openApi.getPaths().values().stream().findFirst().get().getGet().getResponses() .get( "200" ).get$ref() ).isEqualTo( "#/components/responses/AspectWithCollection" ); assertThat( openApi.getComponents().getResponses().get( "AspectWithCollection" ).getContent() @@ -466,7 +471,7 @@ public void testHasNoPagination( final KnownVersion metaModelVersion ) throws Pr @ParameterizedTest @MethodSource( value = "allVersions" ) - public void testAspectWithOperation( final KnownVersion metaModelVersion ) throws ProcessingException { + void testAspectWithOperation( final KnownVersion metaModelVersion ) throws ProcessingException { final Aspect aspect = loadAspect( TestAspect.ASPECT_WITH_OPERATION, metaModelVersion ); final OpenApiSchemaGenerationConfig config = OpenApiSchemaGenerationConfigBuilder.builder() .useSemanticVersion( true ) @@ -483,13 +488,13 @@ public void testAspectWithOperation( final KnownVersion metaModelVersion ) throw assertThat( openApi.getComponents().getSchemas() ).containsKey( "testOperationResponse" ); assertThat( openApi.getComponents().getSchemas() ).containsKey( "testOperationTwo" ); assertThat( openApi.getComponents().getSchemas() ).containsKey( "testOperationTwoResponse" ); - assertThat( openApi.getComponents().getSchemas().get( "Operation" ).getOneOf().size() ).isEqualTo( 2 ); - assertThat( openApi.getComponents().getSchemas().get( "OperationResponse" ).getOneOf().size() ).isEqualTo( 2 ); + assertThat( openApi.getComponents().getSchemas().get( "Operation" ).getOneOf() ).hasSize( 2 ); + assertThat( openApi.getComponents().getSchemas().get( "OperationResponse" ).getOneOf() ).hasSize( 2 ); } @ParameterizedTest @MethodSource( value = "allVersions" ) - public void testAspectWithOperationWithSeeAttribute( final KnownVersion metaModelVersion ) { + void testAspectWithOperationWithSeeAttribute( final KnownVersion metaModelVersion ) { final Aspect aspect = loadAspect( TestAspect.ASPECT_WITH_OPERATION_WITH_SEE_ATTRIBUTE, metaModelVersion ); final OpenApiSchemaGenerationConfig config = OpenApiSchemaGenerationConfigBuilder.builder() .useSemanticVersion( true ) @@ -500,16 +505,132 @@ public void testAspectWithOperationWithSeeAttribute( final KnownVersion metaMode final SwaggerParseResult result = new OpenAPIParser().readContents( json.toString(), null, null ); final OpenAPI openApi = result.getOpenAPI(); assertThat( - ( (Schema) openApi.getComponents().getSchemas().get( "testOperation" ).getAllOf() - .get( 1 ) ).getProperties() ).doesNotContainKey( + ((Schema) openApi.getComponents().getSchemas().get( "testOperation" ).getAllOf() + .get( 1 )).getProperties() ).doesNotContainKey( "params" ); - assertThat( ( (Schema) openApi.getComponents().getSchemas().get( "testOperationTwo" ).getAllOf() - .get( 1 ) ).getProperties() ).doesNotContainKey( "params" ); + assertThat( ((Schema) openApi.getComponents().getSchemas().get( "testOperationTwo" ).getAllOf() + .get( 1 )).getProperties() ).doesNotContainKey( "params" ); + } + + @ParameterizedTest + @MethodSource( value = "allVersions" ) + void testAspectWithAllCrud( final KnownVersion metaModelVersion ) { + final Aspect aspect = loadAspect( TestAspect.ASPECT_WITHOUT_SEE_ATTRIBUTE, metaModelVersion ); + final OpenApiSchemaGenerationConfig config = OpenApiSchemaGenerationConfigBuilder.builder() + .useSemanticVersion( true ) + .baseUrl( TEST_BASE_URL ) + .includeQueryApi( true ) + .includeCrud( true ) + .build(); + final JsonNode json = apiJsonGenerator.apply( aspect, config ).getContent(); + final SwaggerParseResult result = new OpenAPIParser().readContents( json.toString(), null, null ); + final OpenAPI openApi = result.getOpenAPI(); + + final String apiEndpoint = "/{tenant-id}/aspect-without-see-attribute"; + + assertThat( openApi.getPaths().get( apiEndpoint ).getGet() ).isNotNull(); + assertThat( openApi.getPaths().get( apiEndpoint ).getPost() ).isNotNull(); + assertThat( openApi.getPaths().get( apiEndpoint ).getPut() ).isNotNull(); + assertThat( openApi.getPaths().get( apiEndpoint ).getPatch() ).isNotNull(); + assertThat( openApi.getPaths().keySet() ).anyMatch( path -> path.equals( "https://test-aspect.example.com/query-api/v1.0.0" ) ); + } + + @ParameterizedTest + @MethodSource( value = "allVersions" ) + void testAspectWithPostOperation( final KnownVersion metaModelVersion ) { + final Aspect aspect = loadAspect( TestAspect.ASPECT_WITHOUT_SEE_ATTRIBUTE, metaModelVersion ); + final OpenApiSchemaGenerationConfig config = OpenApiSchemaGenerationConfigBuilder.builder() + .useSemanticVersion( true ) + .baseUrl( TEST_BASE_URL ) + .includeQueryApi( true ) + .includePost( true ) + .build(); + final JsonNode json = apiJsonGenerator.apply( aspect, config ).getContent(); + final SwaggerParseResult result = new OpenAPIParser().readContents( json.toString(), null, null ); + final OpenAPI openApi = result.getOpenAPI(); + + final String apiEndpoint = "/{tenant-id}/aspect-without-see-attribute"; + + assertThat( openApi.getPaths().get( apiEndpoint ).getGet() ).isNotNull(); + assertThat( openApi.getPaths().get( apiEndpoint ).getPost() ).isNotNull(); + assertThat( openApi.getPaths().get( apiEndpoint ).getPut() ).isNull(); + assertThat( openApi.getPaths().get( apiEndpoint ).getPatch() ).isNull(); + assertThat( openApi.getPaths().keySet() ).anyMatch( path -> path.equals( "https://test-aspect.example.com/query-api/v1.0.0" ) ); } @ParameterizedTest @MethodSource( value = "allVersions" ) - public void testAspectWithCommentForSeeAttributes( final KnownVersion metaModelVersion ) { + void testAspectWithPutOperation( final KnownVersion metaModelVersion ) { + final Aspect aspect = loadAspect( TestAspect.ASPECT_WITHOUT_SEE_ATTRIBUTE, metaModelVersion ); + final OpenApiSchemaGenerationConfig config = OpenApiSchemaGenerationConfigBuilder.builder() + .useSemanticVersion( true ) + .baseUrl( TEST_BASE_URL ) + .includeQueryApi( true ) + .includePut( true ) + .build(); + final JsonNode json = apiJsonGenerator.apply( aspect, config ).getContent(); + final SwaggerParseResult result = new OpenAPIParser().readContents( json.toString(), null, null ); + final OpenAPI openApi = result.getOpenAPI(); + + final String apiEndpoint = "/{tenant-id}/aspect-without-see-attribute"; + + assertThat( openApi.getPaths().get( apiEndpoint ).getGet() ).isNotNull(); + assertThat( openApi.getPaths().get( apiEndpoint ).getPost() ).isNull(); + assertThat( openApi.getPaths().get( apiEndpoint ).getPut() ).isNotNull(); + assertThat( openApi.getPaths().get( apiEndpoint ).getPatch() ).isNull(); + assertThat( openApi.getPaths().keySet() ).anyMatch( path -> path.equals( "https://test-aspect.example.com/query-api/v1.0.0" ) ); + } + + @ParameterizedTest + @MethodSource( value = "allVersions" ) + void testAspectWithPatchOperation( final KnownVersion metaModelVersion ) { + final Aspect aspect = loadAspect( TestAspect.ASPECT_WITHOUT_SEE_ATTRIBUTE, metaModelVersion ); + final OpenApiSchemaGenerationConfig config = OpenApiSchemaGenerationConfigBuilder.builder() + .useSemanticVersion( true ) + .baseUrl( TEST_BASE_URL ) + .includeQueryApi( true ) + .includePatch( true ) + .build(); + final JsonNode json = apiJsonGenerator.apply( aspect, config ).getContent(); + final SwaggerParseResult result = new OpenAPIParser().readContents( json.toString(), null, null ); + final OpenAPI openApi = result.getOpenAPI(); + + final String apiEndpoint = "/{tenant-id}/aspect-without-see-attribute"; + + assertThat( openApi.getPaths().get( apiEndpoint ).getGet() ).isNotNull(); + assertThat( openApi.getPaths().get( apiEndpoint ).getPost() ).isNull(); + assertThat( openApi.getPaths().get( apiEndpoint ).getPut() ).isNull(); + assertThat( openApi.getPaths().get( apiEndpoint ).getPatch() ).isNotNull(); + assertThat( openApi.getPaths().keySet() ).anyMatch( path -> path.equals( "https://test-aspect.example.com/query-api/v1.0.0" ) ); + } + + @ParameterizedTest + @MethodSource( value = "allVersions" ) + void testAspectWithPatchAndPostOperation( final KnownVersion metaModelVersion ) { + final Aspect aspect = loadAspect( TestAspect.ASPECT_WITHOUT_SEE_ATTRIBUTE, metaModelVersion ); + final OpenApiSchemaGenerationConfig config = OpenApiSchemaGenerationConfigBuilder.builder() + .useSemanticVersion( true ) + .baseUrl( TEST_BASE_URL ) + .includeQueryApi( true ) + .includePatch( true ) + .includePost( true ) + .build(); + final JsonNode json = apiJsonGenerator.apply( aspect, config ).getContent(); + final SwaggerParseResult result = new OpenAPIParser().readContents( json.toString(), null, null ); + final OpenAPI openApi = result.getOpenAPI(); + + final String apiEndpoint = "/{tenant-id}/aspect-without-see-attribute"; + + assertThat( openApi.getPaths().get( apiEndpoint ).getGet() ).isNotNull(); + assertThat( openApi.getPaths().get( apiEndpoint ).getPost() ).isNotNull(); + assertThat( openApi.getPaths().get( apiEndpoint ).getPut() ).isNull(); + assertThat( openApi.getPaths().get( apiEndpoint ).getPatch() ).isNotNull(); + assertThat( openApi.getPaths().keySet() ).anyMatch( path -> path.equals( "https://test-aspect.example.com/query-api/v1.0.0" ) ); + } + + @ParameterizedTest + @MethodSource( value = "allVersions" ) + void testAspectWithCommentForSeeAttributes( final KnownVersion metaModelVersion ) { final Aspect aspect = loadAspect( TestAspect.ASPECT_WITH_COLLECTION, metaModelVersion ); final OpenApiSchemaGenerationConfig config = OpenApiSchemaGenerationConfigBuilder.builder() .useSemanticVersion( true ) @@ -525,8 +646,8 @@ public void testAspectWithCommentForSeeAttributes( final KnownVersion metaModelV assertThat( openApi.getSpecVersion() ).isEqualTo( SpecVersion.V31 ); assertThat( openApi.getComponents().getSchemas().get( "AspectWithCollection" ).get$comment() ).isEqualTo( "See: http://example.com/" ); - assertThat( ( (Schema) openApi.getComponents().getSchemas().get( "AspectWithCollection" ).getProperties() - .get( "testProperty" ) ).get$comment() ) + assertThat( ((Schema) openApi.getComponents().getSchemas().get( "AspectWithCollection" ).getProperties() + .get( "testProperty" )).get$comment() ) .isEqualTo( "See: http://example.com/, http://example.com/me" ); assertThat( openApi.getComponents().getSchemas().get( "TestCollection" ).get$comment() ) .isEqualTo( "See: http://example.com/" ); @@ -591,9 +712,9 @@ private void validateOpenApiSpec( final JsonNode node, final OpenAPI openApi, fi .forEach( operation -> validateSuccessfulResponse( aspect.getName(), operation ) ); } ); - assertThat( openApi.getComponents().getSchemas().keySet() ).contains( aspect.getName() ); - assertThat( openApi.getComponents().getResponses().keySet() ).contains( aspect.getName() ); - assertThat( openApi.getComponents().getRequestBodies().keySet() ).contains( aspect.getName() ); + assertThat( openApi.getComponents().getSchemas() ).containsKey( aspect.getName() ); + assertThat( openApi.getComponents().getResponses() ).containsKey( aspect.getName() ); + assertThat( openApi.getComponents().getRequestBodies() ).containsKey( aspect.getName() ); assertThat( openApi.getComponents().getSchemas().get( aspect.getName() ).getExtensions() .get( AspectModelJsonSchemaVisitor.SAMM_EXTENSION ) ).isNotNull(); assertThat( @@ -639,11 +760,11 @@ private void validateUnsupportedKeywords( final JsonNode jsonNode ) throws IOExc } private void validateOperation( final OpenAPI openApi ) { - assertThat( openApi.getComponents().getSchemas().keySet() ).contains( "JsonRpc" ); - assertThat( openApi.getComponents().getSchemas().keySet() ).contains( "Operation" ); - assertThat( openApi.getComponents().getSchemas().keySet() ).contains( "OperationResponse" ); - assertThat( openApi.getComponents().getResponses().keySet() ).contains( "OperationResponse" ); - assertThat( openApi.getComponents().getRequestBodies().keySet() ).contains( "Operation" ); + assertThat( openApi.getComponents().getSchemas() ).containsKey( "JsonRpc" ); + assertThat( openApi.getComponents().getSchemas() ).containsKey( "Operation" ); + assertThat( openApi.getComponents().getSchemas() ).containsKey( "OperationResponse" ); + assertThat( openApi.getComponents().getResponses() ).containsKey( "OperationResponse" ); + assertThat( openApi.getComponents().getRequestBodies() ).containsKey( "Operation" ); } private void validateYaml( final Aspect aspect ) { diff --git a/documentation/developer-guide/modules/tooling-guide/pages/maven-plugin.adoc b/documentation/developer-guide/modules/tooling-guide/pages/maven-plugin.adoc index 937ae1dec..3bd9cd110 100644 --- a/documentation/developer-guide/modules/tooling-guide/pages/maven-plugin.adoc +++ b/documentation/developer-guide/modules/tooling-guide/pages/maven-plugin.adoc @@ -267,6 +267,10 @@ Configuration Properties: | `useSemanticApiVersion` | Use the complete semantic version of the Aspect Model as the version of the Aspect API. | `Boolean` | `false` | {nok} | `aspectResourcePath` | The resource-path` for the Aspect API endpoints. | `String` | none | {nok} | `includeQueryApi` | Include the path for the Query Aspect API Endpoint in the OpenAPI specification. | `Boolean` | `false` | {nok} +| `includeFullCrud` | Include the POST/PUT/PATCH methods in the OpenAPI specification. | `Boolean` | `false` | {nok} +| `includePost` | Include the POST method in the OpenAPI specification. | `Boolean` | `false` | {nok} +| `includePut` | Include the PUT method in the OpenAPI specification. | `Boolean` | `false` | {nok} +| `includePatch` | Include the PATCH method in the OpenAPI specification. | `Boolean` | `false` | {nok} | `excludePaging` | Exclude paging information for the Aspect API Endpoint in the OpenAPI specification. | `Boolean` | `false` | {nok} | `aspectCursorBasedPaging` | Set the used paging strategy as cursor-based paging. | `Boolean` | `false` | {nok} | `aspectOffsetBasedPaging` | Set the used paging strategy as offset-based paging. | `Boolean` | `false` | {nok} diff --git a/documentation/developer-guide/modules/tooling-guide/pages/samm-cli.adoc b/documentation/developer-guide/modules/tooling-guide/pages/samm-cli.adoc index f1c7ffe75..051a84f7a 100644 --- a/documentation/developer-guide/modules/tooling-guide/pages/samm-cli.adoc +++ b/documentation/developer-guide/modules/tooling-guide/pages/samm-cli.adoc @@ -96,7 +96,7 @@ The available options and their meaning can also be seen in the help text of the https://velocity.apache.org/[Velocity] macro library | | _--static, -s_ : generate Java domain classes for a Static Meta Model | | _--custom-resolver_ : use an external resolver for the resolution of the model elements | -.16+| aspect to openapi | Generate https://spec.openapis.org/oas/v3.0.3[OpenAPI] specification for an Aspect Model| `samm aspect AspectModel.ttl to openapi -j` +.20+| aspect to openapi | Generate https://spec.openapis.org/oas/v3.0.3[OpenAPI] specification for an Aspect Model| `samm aspect AspectModel.ttl to openapi -j` | _--output, -o_ : output file path (default: stdout) | | _--api-base-url, -b_ : the base url for the Aspect API used in the https://spec.openapis.org/oas/v3.0.3[OpenAPI] specification | `samm aspect AspectModel.ttl to openapi -j -b \http://mysite.de` @@ -111,6 +111,10 @@ The available options and their meaning can also be seen in the help text of the | _--resource-path, -r_ : the resource path for the Aspect API endpoints | For detailed description, see the section bellow | _--include-query-api, -q_ : include the path for the Query Aspect API Endpoint in the https://spec.openapis.org/oas/v3.0.3[OpenAPI] specification | + | _--include-crud, -cr_ : include the POST/PUT/PATCH methods in the OpenAPI specification | + | _--include-post, -post_ : include the POST method in the OpenAPI specification | + | _--include-put, -put_ : include the PUT method in the OpenAPI specification | + | _--include-patch, -patch_ : include the PATCH method in the OpenAPI specification | | _--paging-none, -pn_ : exclude paging information for the Aspect API Endpoint in the https://spec.openapis.org/oas/v3.0.3[OpenAPI] specification | | _--paging-cursor-based, -pc_ : in case there is more than one paging possibility, diff --git a/tools/esmf-aspect-model-maven-plugin/src/main/java/org/eclipse/esmf/aspectmodel/GenerateOpenApiSpec.java b/tools/esmf-aspect-model-maven-plugin/src/main/java/org/eclipse/esmf/aspectmodel/GenerateOpenApiSpec.java index efdc91ab1..cd965b5f7 100644 --- a/tools/esmf-aspect-model-maven-plugin/src/main/java/org/eclipse/esmf/aspectmodel/GenerateOpenApiSpec.java +++ b/tools/esmf-aspect-model-maven-plugin/src/main/java/org/eclipse/esmf/aspectmodel/GenerateOpenApiSpec.java @@ -75,6 +75,18 @@ public class GenerateOpenApiSpec extends AspectModelMojo { @Parameter( defaultValue = "false" ) private boolean includeQueryApi; + @Parameter( defaultValue = "false" ) + private boolean includeFullCrud; + + @Parameter( defaultValue = "false" ) + private boolean includePost; + + @Parameter( defaultValue = "false" ) + private boolean includePut; + + @Parameter( defaultValue = "false" ) + private boolean includePatch; + @Parameter( defaultValue = "false" ) private boolean excludePaging; @@ -112,6 +124,10 @@ public void execute() throws MojoExecutionException, MojoFailureException { .resourcePath( aspectResourcePath ) .properties( readAspectParameterFile() ) .includeQueryApi( includeQueryApi ) + .includeCrud( includeFullCrud ) + .includePost( includePost ) + .includePut( includePut ) + .includePatch( includePatch ) .pagingOption( getPagingFromArgs() ) .locale( locale ) .build(); diff --git a/tools/esmf-aspect-model-maven-plugin/src/test/java/org/eclipse/esmf/aspectmodel/GenerateOpenApiSpecTest.java b/tools/esmf-aspect-model-maven-plugin/src/test/java/org/eclipse/esmf/aspectmodel/GenerateOpenApiSpecTest.java index 1322724cc..4d7592040 100644 --- a/tools/esmf-aspect-model-maven-plugin/src/test/java/org/eclipse/esmf/aspectmodel/GenerateOpenApiSpecTest.java +++ b/tools/esmf-aspect-model-maven-plugin/src/test/java/org/eclipse/esmf/aspectmodel/GenerateOpenApiSpecTest.java @@ -17,6 +17,8 @@ import static org.assertj.core.api.Assertions.assertThatCode; import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; import org.apache.maven.plugin.Mojo; import org.apache.maven.plugin.MojoExecutionException; @@ -28,7 +30,31 @@ public void testGenerateOpenApiSpecJsonValidAspectModel() throws Exception { final File testPom = getTestFile( "src/test/resources/generate-openapi-spec-json-pom-valid-aspect-model.xml" ); final Mojo generateOpenApiSpec = lookupMojo( "generateOpenApiSpec", testPom ); assertThatCode( generateOpenApiSpec::execute ).doesNotThrowAnyException(); - assertThat( generatedFilePath( "Aspect.oai.json" ) ).exists(); + + final Path generatedFile = generatedFilePath( "Aspect.oai.json" ); + assertThat( generatedFile ).exists(); + + final String yamlContent = new String( Files.readAllBytes( generatedFile ) ); + + assertThat( yamlContent ).contains( "postAspect" ); + assertThat( yamlContent ).contains( "putAspect" ); + assertThat( yamlContent ).contains( "patchAspect" ); + } + + @Test + public void testGenerateOpenApiSpecJsonValidAspectModelWithCrudParameters() throws Exception { + final File testPom = getTestFile( "src/test/resources/generate-openapi-spec-json-pom-valid-aspect-model-with-crud-parameters.xml" ); + final Mojo generateOpenApiSpec = lookupMojo( "generateOpenApiSpec", testPom ); + assertThatCode( generateOpenApiSpec::execute ).doesNotThrowAnyException(); + + final Path generatedFile = generatedFilePath( "Aspect.oai.json" ); + assertThat( generatedFile ).exists(); + + final String yamlContent = new String( Files.readAllBytes( generatedFile ) ); + + assertThat( yamlContent ).contains( "postAspect" ); + assertThat( yamlContent ).contains( "putAspect" ); + assertThat( yamlContent ).contains( "patchAspect" ); } /** diff --git a/tools/esmf-aspect-model-maven-plugin/src/test/resources/generate-openapi-spec-json-pom-valid-aspect-model-with-crud-parameters.xml b/tools/esmf-aspect-model-maven-plugin/src/test/resources/generate-openapi-spec-json-pom-valid-aspect-model-with-crud-parameters.xml new file mode 100644 index 000000000..9950cf67b --- /dev/null +++ b/tools/esmf-aspect-model-maven-plugin/src/test/resources/generate-openapi-spec-json-pom-valid-aspect-model-with-crud-parameters.xml @@ -0,0 +1,44 @@ + + + + + 4.0.0 + + org.eclipse.esmf + test-generate-openapi-spec-mojo + 1.0 + jar + Test Generate OpenApi Spec Mojo + + + + + esmf-aspect-model-maven-plugin + + ${basedir}/../../core/esmf-test-aspect-models/src/main/resources/valid/samm_2_0_0 + + urn:samm:org.eclipse.esmf.test:1.0.0#Aspect + + http://example.com + ${basedir}/target/test-artifacts + true + true + true + json + + + + + diff --git a/tools/esmf-aspect-model-maven-plugin/src/test/resources/generate-openapi-spec-json-pom-valid-aspect-model.xml b/tools/esmf-aspect-model-maven-plugin/src/test/resources/generate-openapi-spec-json-pom-valid-aspect-model.xml index f03fd975c..02857b1e7 100644 --- a/tools/esmf-aspect-model-maven-plugin/src/test/resources/generate-openapi-spec-json-pom-valid-aspect-model.xml +++ b/tools/esmf-aspect-model-maven-plugin/src/test/resources/generate-openapi-spec-json-pom-valid-aspect-model.xml @@ -33,6 +33,7 @@ http://example.com ${basedir}/target/test-artifacts + true json diff --git a/tools/samm-cli/src/main/java/org/eclipse/esmf/aspect/to/AspectToOpenapiCommand.java b/tools/samm-cli/src/main/java/org/eclipse/esmf/aspect/to/AspectToOpenapiCommand.java index 978d865e9..637e33c26 100644 --- a/tools/samm-cli/src/main/java/org/eclipse/esmf/aspect/to/AspectToOpenapiCommand.java +++ b/tools/samm-cli/src/main/java/org/eclipse/esmf/aspect/to/AspectToOpenapiCommand.java @@ -90,6 +90,22 @@ public class AspectToOpenapiCommand extends AbstractCommand { description = "Include the path for the Query Aspect API Endpoint in the OpenAPI specification." ) private boolean includeQueryApi = false; + @CommandLine.Option( names = { "--include-crud", "-cr" }, + description = "Include all CRUD operations (POST/PUT/PATCH) in the OpenAPI specification." ) + private boolean includeFullCrud = false; + + @CommandLine.Option( names = { "--include-post", "-post" }, + description = "Include POST operation in the OpenAPI specification." ) + private boolean includePost = false; + + @CommandLine.Option( names = { "--include-put", "-put" }, + description = "Include PUT operation in the OpenAPI specification." ) + private boolean includePut = false; + + @CommandLine.Option( names = { "--include-patch", "-patch" }, + description = "Include PATCH operation in the OpenAPI specification." ) + private boolean includePatch = false; + @CommandLine.Option( names = { "--paging-none", "-pn" }, description = "Exclude paging information for the Aspect API Endpoint in the OpenAPI specification." ) private boolean excludePaging = false; @@ -138,6 +154,10 @@ public void run() { .resourcePath( aspectResourcePath ) .properties( readAspectParameterFile() ) .includeQueryApi( includeQueryApi ) + .includeCrud( includeFullCrud ) + .includePost( includePost ) + .includePut( includePut ) + .includePatch( includePatch ) .pagingOption( getPaging() ) .locale( locale ) .generateCommentForSeeAttributes( generateCommentForSeeAttributes ) diff --git a/tools/samm-cli/src/test/java/org/eclipse/esmf/SammCliTest.java b/tools/samm-cli/src/test/java/org/eclipse/esmf/SammCliTest.java index b994ed037..2da21d621 100644 --- a/tools/samm-cli/src/test/java/org/eclipse/esmf/SammCliTest.java +++ b/tools/samm-cli/src/test/java/org/eclipse/esmf/SammCliTest.java @@ -61,7 +61,7 @@ */ @ExtendWith( LogExtension.class ) @TestInstance( TestInstance.Lifecycle.PER_CLASS ) -public class SammCliTest extends MetaModelVersions { +class SammCliTest extends MetaModelVersions { protected ProcessLauncher sammCli; private final TestModel testModel = TestAspect.ASPECT_WITH_ENTITY; private final String defaultInputFile = inputFile( testModel ).getAbsolutePath(); @@ -69,13 +69,13 @@ public class SammCliTest extends MetaModelVersions { Path outputDirectory = null; @BeforeEach - public void beforeEach() throws IOException { + void beforeEach() throws IOException { sammCli = new MainClassProcessLauncher( SammCli.class ); outputDirectory = Files.createTempDirectory( "junit" ); } @AfterEach - public void afterEach() { + void afterEach() { if ( outputDirectory != null ) { final File outputDir = outputDirectory.toFile(); if ( outputDir.exists() && outputDir.isDirectory() ) { @@ -96,14 +96,14 @@ public void afterEach() { } @Test - public void testNoArgs() { + void testNoArgs() { final ExecutionResult result = sammCli.runAndExpectSuccess( "--disable-color" ); assertThat( result.stdout() ).contains( "Usage:" ); assertThat( result.stderr() ).isEmpty(); } @Test - public void testAspectWithoutSubcommand() { + void testAspectWithoutSubcommand() { final ExecutionResult result = sammCli.apply( "--disable-color", "aspect" ); assertThat( result.exitStatus() ).isEqualTo( 2 ); assertThat( result.stdout() ).isEmpty(); @@ -111,7 +111,7 @@ public void testAspectWithoutSubcommand() { } @Test - public void testWrongArgs() { + void testWrongArgs() { final ExecutionResult result = sammCli.apply( "--disable-color", "-i", "doesnotexist" ); assertThat( result.exitStatus() ).isEqualTo( 2 ); assertThat( result.stdout() ).isEmpty(); @@ -119,21 +119,21 @@ public void testWrongArgs() { } @Test - public void testHelp() { + void testHelp() { final ExecutionResult result = sammCli.runAndExpectSuccess( "--disable-color", "help" ); assertThat( result.stdout() ).contains( "Usage:" ); assertThat( result.stderr() ).isEmpty(); } @Test - public void testVerboseOutput() { + void testVerboseOutput() { final ExecutionResult result = sammCli.runAndExpectSuccess( "--disable-color", "aspect", defaultInputFile, "validate", "-vvv" ); assertThat( result.stdout() ).contains( "Input model is valid" ); assertThat( result.stderr() ).contains( "DEBUG " + AspectValidateCommand.class.getName() ); } @Test - public void testAspectMigrateToFile() { + void testAspectMigrateToFile() { final File targetFile = outputFile( "output.ttl" ); final ExecutionResult result = sammCli.runAndExpectSuccess( "--disable-color", "aspect", defaultInputFile, "migrate", "-o", targetFile.getAbsolutePath() ); @@ -144,14 +144,14 @@ public void testAspectMigrateToFile() { } @Test - public void testAspectMigrateToStdout() { + void testAspectMigrateToStdout() { final ExecutionResult result = sammCli.runAndExpectSuccess( "--disable-color", "aspect", defaultInputFile, "migrate" ); assertThat( result.stdout() ).contains( "@prefix" ); assertThat( result.stderr() ).isEmpty(); } @Test - public void testAspectPrettyPrintToFile() { + void testAspectPrettyPrintToFile() { final File targetFile = outputFile( "output.ttl" ); final ExecutionResult result = sammCli.runAndExpectSuccess( "--disable-color", "aspect", defaultInputFile, "prettyprint", "-o", targetFile.getAbsolutePath() ); @@ -162,14 +162,14 @@ public void testAspectPrettyPrintToFile() { } @Test - public void testAspectPrettyPrintToStdout() { + void testAspectPrettyPrintToStdout() { final ExecutionResult result = sammCli.runAndExpectSuccess( "--disable-color", "aspect", defaultInputFile, "prettyprint" ); assertThat( result.stdout() ).contains( "@prefix" ); assertThat( result.stderr() ).isEmpty(); } @Test - public void testAspectValidateValidModel() { + void testAspectValidateValidModel() { final ExecutionResult result = sammCli.runAndExpectSuccess( "--disable-color", "aspect", defaultInputFile, "validate" ); assertThat( result.stdout() ).contains( "Input model is valid" ); assertThat( result.stderr() ).isEmpty(); @@ -178,7 +178,7 @@ public void testAspectValidateValidModel() { @ParameterizedTest @EnumSource( TestAspect.class ) @EnabledIfSystemProperty( named = "packaging-type", matches = "native" ) - public void testAspectValidateValidModelAllTestFiles( final TestModel aspect ) { + void testAspectValidateValidModelAllTestFiles( final TestModel aspect ) { final String input = inputFile( aspect ).getAbsolutePath(); final ExecutionResult result = sammCli.runAndExpectSuccess( "--disable-color", "aspect", input, "validate" ); assertThat( result.stdout() ).contains( "Input model is valid" ); @@ -186,7 +186,7 @@ public void testAspectValidateValidModelAllTestFiles( final TestModel aspect ) { } @Test - public void testAspectValidateWithRelativePath() { + void testAspectValidateWithRelativePath() { final File workingDirectory = new File( defaultInputFile ).getParentFile(); final String relativeFileName = "." + File.separator + new File( defaultInputFile ).getName(); final ProcessLauncher.ExecutionContext executionContext = new ProcessLauncher.ExecutionContext( @@ -199,7 +199,7 @@ public void testAspectValidateWithRelativePath() { @Test @DisabledOnOs( OS.WINDOWS ) - public void testAspectValidateInvalidModel() { + void testAspectValidateInvalidModel() { final File invalidModel = inputFile( InvalidTestAspect.INVALID_SYNTAX ); final ExecutionResult result = sammCli.apply( "--disable-color", "aspect", invalidModel.getAbsolutePath(), "validate" ); assertThat( result.exitStatus() ).isEqualTo( 1 ); @@ -208,7 +208,7 @@ public void testAspectValidateInvalidModel() { } @Test - public void testAspectValidateWithDetails() { + void testAspectValidateWithDetails() { final ExecutionResult result = sammCli.runAndExpectSuccess( "--disable-color", "aspect", defaultInputFile, "validate", "--details" ); assertThat( result.stdout() ).contains( "Input model is valid" ); assertThat( result.stderr() ).isEmpty(); @@ -221,7 +221,7 @@ public void testAspectValidateWithDetails() { } @Test - public void testAspectValidateWithCustomResolver() { + void testAspectValidateWithCustomResolver() { final ExecutionResult result = sammCli.runAndExpectSuccess( "--disable-color", "aspect", defaultInputFile, "validate", "--custom-resolver", resolverCommand() ); assertThat( result.stdout() ).contains( "Input model is valid" ); @@ -229,7 +229,7 @@ public void testAspectValidateWithCustomResolver() { } @Test - public void testAspectToAasXmlToFile() { + void testAspectToAasXmlToFile() { final File targetFile = outputFile( "output.xml" ); final ExecutionResult result = sammCli.runAndExpectSuccess( "--disable-color", "aspect", defaultInputFile, "to", "aas", "--format", "xml", "-o", targetFile.getAbsolutePath() ); @@ -242,7 +242,7 @@ public void testAspectToAasXmlToFile() { @ParameterizedTest @EnumSource( TestAspect.class ) @EnabledIfSystemProperty( named = "packaging-type", matches = "native" ) - public void testAspectToAasXmlToFileAllTestFiles( final TestModel aspect ) { + void testAspectToAasXmlToFileAllTestFiles( final TestModel aspect ) { final String input = inputFile( aspect ).getAbsolutePath(); final File targetFile = outputFile( "output.xml" ); assertThat( targetFile ).doesNotExist(); @@ -255,7 +255,7 @@ public void testAspectToAasXmlToFileAllTestFiles( final TestModel aspect ) { } @Test - public void testAspectToAasXmlToStdout() { + void testAspectToAasXmlToStdout() { final ExecutionResult result = sammCli.runAndExpectSuccess( "--disable-color", "aspect", defaultInputFile, "to", "aas", "--format", "xml" ); assertThat( result.stdout() ).startsWith( "