package io.swagger; import io.swagger.jaxrs.Reader; import io.swagger.models.ExternalDocs; import io.swagger.models.Operation; import io.swagger.models.Swagger; import io.swagger.models.Tag; import io.swagger.models.parameters.BodyParameter; import io.swagger.models.parameters.FormParameter; import io.swagger.models.parameters.HeaderParameter; import io.swagger.models.parameters.Parameter; import io.swagger.models.parameters.PathParameter; import io.swagger.models.parameters.QueryParameter; import io.swagger.resources.AnnotatedInterfaceImpl; import io.swagger.resources.ApiConsumesProducesResource; import io.swagger.resources.ApiMultipleConsumesProducesResource; import io.swagger.resources.BookResource; import io.swagger.resources.BothConsumesProducesResource; import io.swagger.resources.DescendantResource; import io.swagger.resources.IndirectImplicitParamsImpl; import io.swagger.resources.NoConsumesProducesResource; import io.swagger.resources.Resource1970; import io.swagger.resources.ResourceWithAnnotationsOnlyInInterfaceImpl; import io.swagger.resources.ResourceWithClassLevelApiResourceNoMethodLevelApiResources; import io.swagger.resources.ResourceWithCustomException; import io.swagger.resources.ResourceWithCustomExceptionAndClassLevelApiResource; import io.swagger.resources.ResourceWithDeprecatedMethod; import io.swagger.resources.ResourceWithEmptyPath; import io.swagger.resources.ResourceWithExternalDocs; import io.swagger.resources.ResourceWithImplicitFileParam; import io.swagger.resources.ResourceWithImplicitParams; import io.swagger.resources.ResourceWithKnownInjections; import io.swagger.resources.ResourceWithValidation; import io.swagger.resources.RsConsumesProducesResource; import io.swagger.resources.RsMultipleConsumesProducesResource; import io.swagger.resources.SimpleMethods; import org.testng.annotations.Test; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.HEAD; import javax.ws.rs.OPTIONS; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.core.MediaType; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.math.BigDecimal; import java.util.Arrays; import java.util.List; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; public class ReaderTest { private static final String APPLICATION_XML = "application/xml"; private static final String TEXT_PLAIN = "text/plain"; private static final String TEXT_HTML = "text/html"; private static final String TEXT_XML = "text/xml"; private static final String TEXT_JSON = "text/json"; private static final String CHARSET8 = ";charset=UTF-8"; private static final String TEXT_XML_CHARSET = TEXT_XML + CHARSET8; private static final String TEXT_HTML_CHARSET = TEXT_HTML + CHARSET8; @Test(description = "scan methods") public void scanMethods() { Method[] methods = SimpleMethods.class.getMethods(); Reader reader = new Reader(new Swagger()); for (Method method : methods) { if (isValidRestPath(method)) { Operation operation = reader.parseMethod(method); assertNotNull(operation); } } } @Test(description = "scan consumes and produces values with api class level annotations") public void scanConsumesProducesValuesWithApiClassLevelAnnotations() { Swagger swagger = getSwagger(ApiConsumesProducesResource.class); assertEquals(getGet(swagger, "/{id}").getConsumes().get(0), MediaType.APPLICATION_XHTML_XML); assertEquals(getGet(swagger, "/{id}").getProduces().get(0), MediaType.APPLICATION_ATOM_XML); assertEquals(getGet(swagger, "/{id}/value").getConsumes().get(0), APPLICATION_XML); assertEquals(getGet(swagger, "/{id}/value").getConsumes().get(1), TEXT_HTML_CHARSET); assertEquals(getGet(swagger, "/{id}/value").getProduces().get(0), TEXT_PLAIN); assertEquals(getGet(swagger, "/{id}/value").getProduces().get(1), TEXT_XML_CHARSET); assertEquals(getPut(swagger, "/{id}").getConsumes().get(0), MediaType.APPLICATION_JSON); assertEquals(getPut(swagger, "/{id}").getConsumes().get(1), TEXT_HTML_CHARSET); assertEquals(getPut(swagger, "/{id}").getProduces().get(0), TEXT_PLAIN); assertEquals(getPut(swagger, "/{id}").getProduces().get(1), TEXT_XML_CHARSET); assertEquals(getPut(swagger, "/{id}/value").getConsumes().get(0), APPLICATION_XML); assertEquals(getPut(swagger, "/{id}/value").getProduces().get(0), TEXT_PLAIN); } @Test(description = "scan consumes and produces values with api class level annotations") public void scanMultipleConsumesProducesValuesWithApiClassLevelAnnotations() { Swagger swagger = getSwagger(ApiMultipleConsumesProducesResource.class); assertEquals(getGet(swagger, "/{id}").getConsumes(), Arrays.asList(MediaType.APPLICATION_XHTML_XML, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON)); assertEquals(getGet(swagger, "/{id}").getProduces(), Arrays.asList(MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML)); } @Test(description = "scan consumes and produces values with rs class level annotations") public void scanConsumesProducesValuesWithRsClassLevelAnnotations() { Swagger swagger = getSwagger(RsConsumesProducesResource.class); assertEquals(getGet(swagger, "/{id}").getConsumes().get(0), "application/yaml"); assertEquals(getGet(swagger, "/{id}").getProduces().get(0), APPLICATION_XML); assertEquals(getGet(swagger, "/{id}/value").getConsumes().get(0), APPLICATION_XML); assertEquals(getGet(swagger, "/{id}/value").getProduces().get(0), TEXT_PLAIN); assertEquals(getPut(swagger, "/{id}").getConsumes().get(0), MediaType.APPLICATION_JSON); assertEquals(getPut(swagger, "/{id}").getProduces().get(0), TEXT_PLAIN); assertEquals(getPut(swagger, "/{id}/value").getConsumes().get(0), APPLICATION_XML); assertEquals(getPut(swagger, "/{id}/value").getProduces().get(0), TEXT_PLAIN); assertEquals(getPut(swagger, "/split").getProduces(), Arrays.asList("image/jpeg", "image/gif", "image/png")); assertEquals(getPut(swagger, "/split").getConsumes(), Arrays.asList("image/jpeg", "image/gif", "image/png")); } @Test(description = "scan multiple consumes and produces values with rs class level annotations") public void scanMultipleConsumesProducesValuesWithRsClassLevelAnnotations() { Swagger swagger = getSwagger(RsMultipleConsumesProducesResource.class); assertEquals(getGet(swagger, "/{id}").getConsumes(), Arrays.asList(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML)); assertEquals(getGet(swagger, "/{id}").getProduces(), Arrays.asList(MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON)); } @Test(description = "scan consumes and produces values with both class level annotations") public void scanConsumesProducesValuesWithBothClassLevelAnnotations() { Swagger swagger = getSwagger(BothConsumesProducesResource.class); assertEquals(getGet(swagger, "/{id}").getConsumes().get(0), MediaType.APPLICATION_XHTML_XML); assertEquals(getGet(swagger, "/{id}").getProduces().get(0), MediaType.APPLICATION_ATOM_XML); assertEquals(getGet(swagger, "/{id}/value").getConsumes().get(0), APPLICATION_XML); assertEquals(getGet(swagger, "/{id}/value").getProduces().get(0), TEXT_PLAIN); assertEquals(getGet(swagger, "/{id}/{name}/value").getConsumes().get(0), MediaType.APPLICATION_JSON); assertEquals(getGet(swagger, "/{id}/{name}/value").getProduces().get(0), TEXT_PLAIN); assertEquals(getGet(swagger, "/{id}/{type}/value").getConsumes().get(0), APPLICATION_XML); assertEquals(getGet(swagger, "/{id}/{type}/value").getProduces().get(0), TEXT_HTML); assertEquals(getPut(swagger, "/{id}").getConsumes().get(0), MediaType.APPLICATION_JSON); assertEquals(getPut(swagger, "/{id}").getProduces().get(0), TEXT_PLAIN); assertEquals(getPut(swagger, "/{id}/value").getConsumes().get(0), APPLICATION_XML); assertEquals(getPut(swagger, "/{id}/value").getProduces().get(0), TEXT_PLAIN); } @Test(description = "scan consumes and produces values with no class level annotations") public void scanConsumesProducesValuesWithoutClassLevelAnnotations() { Swagger swagger = getSwagger(NoConsumesProducesResource.class); assertNull(getGet(swagger, "/{id}").getConsumes()); assertNull(getGet(swagger, "/{id}").getProduces()); assertEquals(getGet(swagger, "/{id}/value").getConsumes().get(0), APPLICATION_XML); assertEquals(getGet(swagger, "/{id}/value").getProduces().get(0), TEXT_PLAIN); assertEquals(getPut(swagger, "/{id}").getConsumes().get(0), MediaType.APPLICATION_JSON); assertEquals(getPut(swagger, "/{id}").getProduces().get(0), TEXT_PLAIN); assertEquals(getPut(swagger, "/{id}/value").getConsumes().get(0), APPLICATION_XML); assertEquals(getPut(swagger, "/{id}/value").getProduces().get(0), TEXT_PLAIN); } @Test(description = "scan class level and field level annotations") public void scanClassAndFieldLevelAnnotations() { Swagger swagger = getSwagger(ResourceWithKnownInjections.class); List<Parameter> resourceParameters = getGet(swagger, "/resource/{id}").getParameters(); assertNotNull(resourceParameters); assertEquals(resourceParameters.size(), 3); assertEquals(resourceParameters.get(0).getName(), "id"); assertEquals(resourceParameters.get(1).getName(), "fieldParam"); assertEquals(resourceParameters.get(2).getName(), "methodParam"); List<Parameter> subResourceParameters = getGet(swagger, "/resource/{id}/subresource1").getParameters(); assertNotNull(subResourceParameters); assertEquals(subResourceParameters.size(), 3); assertEquals(subResourceParameters.get(0).getName(), "id"); assertEquals(subResourceParameters.get(1).getName(), "fieldParam"); assertEquals(subResourceParameters.get(2).getName(), "subResourceParam"); } private Boolean isValidRestPath(Method method) { for (Class<? extends Annotation> item : Arrays.asList(GET.class, PUT.class, POST.class, DELETE.class, OPTIONS.class, HEAD.class)) { if (method.getAnnotation(item) != null) { return true; } } return false; } @Test(description = "scan overridden method in descendantResource") public void scanOverriddenMethod() { Swagger swagger = getSwagger(DescendantResource.class); Operation overriddenMethodWithTypedParam = getGet(swagger, "/pet/{petId1}"); assertNotNull(overriddenMethodWithTypedParam); assertEquals(overriddenMethodWithTypedParam.getParameters().get(0).getDescription(), "ID of pet to return child"); Operation methodWithoutTypedParam = getGet(swagger, "/pet/{petId2}"); assertNotNull(methodWithoutTypedParam); Operation overriddenMethodWithoutTypedParam = getGet(swagger, "/pet/{petId3}"); assertNotNull(overriddenMethodWithoutTypedParam); Operation methodWithoutTypedParamFromDescendant = getGet(swagger, "/pet/{petId4}"); assertNotNull(methodWithoutTypedParamFromDescendant); Operation methodFromInterface = getGet(swagger, "/pet/{petId5}"); assertNotNull(methodFromInterface); } @Test(description = "scan annotation from interface, issue#1427") public void scanInterfaceTest() { final Swagger swagger = new Reader(new Swagger()).read(AnnotatedInterfaceImpl.class); assertNotNull(swagger); assertNotNull(swagger.getPath("/v1/users/{id}").getGet()); } @Test(description = "scan indirect implicit params from interface") public void scanImplicitParamInterfaceTest() { final Swagger swagger = new Reader(new Swagger()).read(IndirectImplicitParamsImpl.class); assertNotNull(swagger); assertEquals(swagger.getPath("/v1/users/{id}").getGet().getParameters().size(), 2); } @Test(description = "scan indirect implicit params from overridden method") public void scanImplicitParamOverriddenMethodTest() { final Swagger swagger = new Reader(new Swagger()).read(IndirectImplicitParamsImpl.class); assertNotNull(swagger); assertEquals(swagger.getPath("/v1/users").getPost().getParameters().size(), 2); } @Test(description = "scan implicit params") public void scanImplicitParam() { Swagger swagger = getSwagger(ResourceWithImplicitParams.class); List<Parameter> params = swagger.getPath("/testString").getPost().getParameters(); assertNotNull(params); assertEquals(params.size(), 7); assertEquals(params.get(0).getName(), "sort"); assertEquals(params.get(0).getIn(), "query"); PathParameter pathParam = (PathParameter) params.get(1); assertEquals(pathParam.getName(), "type"); assertEquals(pathParam.getIn(), "path"); assertEquals(pathParam.getEnum().size(), 3); assertEquals(pathParam.getType(), "string"); HeaderParameter headerParam = (HeaderParameter) params.get(2); assertEquals(headerParam.getName(), "size"); assertEquals(headerParam.getIn(), "header"); assertEquals(headerParam.getMinimum(), new BigDecimal(1.0)); FormParameter formParam = (FormParameter) params.get(3); assertEquals(formParam.getName(), "width"); assertEquals(formParam.getIn(), "formData"); assertEquals(formParam.getMaximum(), new BigDecimal(1.0)); assertEquals(params.get(4).getName(), "width"); assertEquals(params.get(4).getIn(), "formData"); QueryParameter queryParam = (QueryParameter) params.get(5); assertEquals(queryParam.getName(), "height"); assertEquals(queryParam.getIn(), "query"); assertEquals(queryParam.getMinimum(), new BigDecimal(3.0)); assertEquals(queryParam.getMaximum(), new BigDecimal(4.0)); BodyParameter bodyParam = (BodyParameter) params.get(6); assertEquals(bodyParam.getName(), "body"); assertEquals(bodyParam.getIn(), "body"); assertTrue(bodyParam.getRequired()); } @Test(description = "scan implicit params with file objct") public void scanImplicitWithFile() { Swagger swagger = getSwagger(ResourceWithImplicitFileParam.class); Parameter param = swagger.getPath("/testString").getPost().getParameters().get(0); assertTrue(param instanceof FormParameter); FormParameter fp = (FormParameter) param; assertEquals("file", fp.getType()); } @Test(description = "scan Deprecated annotation") public void scanDeprecatedAnnotation() { Swagger swagger = getSwagger(ResourceWithDeprecatedMethod.class); assertTrue(getGet(swagger, "/testDeprecated").isDeprecated()); assertNull(getGet(swagger, "/testAllowed").isDeprecated()); } @Test(description = "scan empty path annotation") public void scanEmptyPathAnnotation() { Swagger swagger = getSwagger(ResourceWithEmptyPath.class); assertNotNull(getGet(swagger, "/")); } @Test(description = "it should scan parameters from base resource class") public void scanParametersFromBaseResource(){ Swagger swagger = getSwagger(BookResource.class); assertNotNull(swagger); List<Parameter> parameters = getGet(swagger, "/{id}/v1/books/{name}").getParameters(); assertEquals(parameters.size(), 4); Parameter description = parameters.get(0); assertTrue(description instanceof PathParameter); assertEquals(description.getName(), "description"); assertEquals(description.getDescription(), "Overridden description"); Parameter id = parameters.get(1); assertTrue(id instanceof PathParameter); assertEquals(id.getName(), "id"); assertEquals(id.getDescription(), "The Identifier of entity"); Parameter test = parameters.get(2); assertTrue(test instanceof QueryParameter); assertEquals(test.getName(), "test"); assertEquals(test.getDescription(), "Test Query Param"); Parameter name = parameters.get(3); assertTrue(name instanceof PathParameter); assertEquals(name.getName(), "name"); assertEquals(name.getDescription(), "The books name"); } @Test(description = "it should scan parameters with Swagger and JSR-303 bean validation annotations") public void scanBeanValidation(){ Swagger swagger = getSwagger(ResourceWithValidation.class); assertNotNull(swagger); QueryParameter par = (QueryParameter) swagger.getPaths().get("/303").getOperations().get(0).getParameters().get(0); assertTrue(par.getRequired()); assertEquals(par.getMinimum(), new BigDecimal(10)); par = (QueryParameter) swagger.getPaths().get("/swagger-and-303").getOperations().get(0).getParameters().get(0); assertTrue(par.getRequired()); assertEquals(par.getMinimum(), new BigDecimal(7)); par = (QueryParameter) swagger.getPaths().get("/swagger").getOperations().get(0).getParameters().get(0); assertTrue(par.getRequired()); assertEquals(par.getMinimum(), new BigDecimal(7)); } @Test(description = "scan resource with annotated exception") public void scanDeclaredExceptions() { Swagger swagger = getSwagger(ResourceWithCustomException.class); assertNotNull(swagger); Operation operation = getGet(swagger, "/{id}"); assertEquals(operation.getResponses().size(), 3); assertTrue(operation.getResponses().containsKey("200")); assertTrue(operation.getResponses().containsKey("400")); assertTrue(operation.getResponses().containsKey("404")); } @Test(description = "scan resource with annotated exception") public void scanDeclaredExceptionsAndCombineWithMethodResponses() { Swagger swagger = getSwagger(ResourceWithCustomException.class); assertNotNull(swagger); Operation operation = getPut(swagger, "/{id}"); assertEquals(operation.getResponses().size(), 4); assertTrue(operation.getResponses().containsKey("200")); assertTrue(operation.getResponses().containsKey("400")); assertTrue(operation.getResponses().containsKey("404")); assertTrue(operation.getResponses().containsKey("409")); } @Test(description = "scan resource with annotated exception") public void scanDeclaredExceptionsAndCombineWithMethodResponsesClassLevel() { Swagger swagger = getSwagger(ResourceWithCustomExceptionAndClassLevelApiResource.class); assertNotNull(swagger); Operation operation = getPut(swagger, "/{id}"); assertEquals(operation.getResponses().size(), 5); assertTrue(operation.getResponses().containsKey("200")); assertTrue(operation.getResponses().containsKey("400")); assertTrue(operation.getResponses().containsKey("404")); assertTrue(operation.getResponses().containsKey("403")); assertTrue(operation.getResponses().containsKey("409")); assertEquals(operation.getResponses().get("409").getDescription(), "Conflict"); swagger = getSwagger(ResourceWithClassLevelApiResourceNoMethodLevelApiResources.class); assertNotNull(swagger); operation = getPut(swagger, "/{id}"); assertEquals(operation.getResponses().size(), 2); assertTrue(operation.getResponses().containsKey("403")); assertTrue(operation.getResponses().containsKey("409")); } @Test(description = "scan resource (impl) which has the Api annotations only declared in its interface") public void scanApiAnnotationWhichAreOnlyPresentInInterfaceAndNotInImplementation() { Swagger swagger = getSwagger(ResourceWithAnnotationsOnlyInInterfaceImpl.class); assertNotNull(swagger); final List<Tag> tags = swagger.getTags(); assertEquals(tags.size(), 1); assertEquals(tags.get(0).getName(), "someTag"); } @Test(description = "scan resource (impl) which has the ApiParam annotations only declared in its interface") public void scanApiImplicitParamAnnotationWhichAreOnlyPresentInInterfaceAndNotInImplementation() { Swagger swagger = getSwagger(ResourceWithAnnotationsOnlyInInterfaceImpl.class); assertNotNull(swagger); List<Parameter> parameters = getGet(swagger, "/pet/randomPet").getParameters(); assertNotNull(parameters); assertEquals(parameters.size(), 1); assertEquals(parameters.get(0).getName(), "petImplicitIdParam"); } @Test(description = "scan resource per #1970") public void scanBigDecimal() { Swagger swagger = getSwagger(Resource1970.class); assertNotNull(swagger); PathParameter parameter = (PathParameter)swagger.getPath("/v1/{param1}").getGet().getParameters().get(0); assertEquals(parameter.getType(), "number"); } @Test(description = "scan external docs on method") public void scanExternalDocsOnMethod() { Swagger swagger = getSwagger(ResourceWithExternalDocs.class); ExternalDocs externalDocsForGet = swagger.getPath("/testString").getGet().getExternalDocs(); assertNull(externalDocsForGet); ExternalDocs externalDocsForPost = swagger.getPath("/testString").getPost().getExternalDocs(); assertNotNull(externalDocsForPost); assertEquals("Test Description", externalDocsForPost.getDescription()); assertEquals("https://swagger.io/", externalDocsForPost.getUrl()); } private Swagger getSwagger(Class<?> cls) { return new Reader(new Swagger()).read(cls); } private Operation getGet(Swagger swagger, String path) { return swagger.getPath(path).getGet(); } private Operation getPut(Swagger swagger, String path) { return swagger.getPath(path).getPut(); } }