+ * An functional integration test that runs during maven's integration-test phase,
+ * uses RestAssured to define REST API tests, and Jetty's Maven plugin to serve a simple
+ * sample app just prior to the integration-test phase starting.
+ */
+public class OpenApiResourceIT extends AbstractAnnotationTest {
+ private static final String EXPECTED_JSON = "{\n" +
+ " \"openapi\": \"3.0.0\",\n" +
+ " \"paths\": {\n" +
+ " \"/widgets/{widgetId}\": {\n" +
+ " \"get\": {\n" +
+ " \"tags\": [\n" +
+ " \"widgets\"\n" +
+ " ],\n" +
+ " \"summary\": \"Find pet by ID\",\n" +
+ " \"description\": \"Returns a pet when ID <= 10. ID > 10 or nonintegers will simulate API error conditions\",\n" +
+ " \"operationId\": \"getWidget\",\n" +
+ " \"parameters\": [\n" +
+ " {\n" +
+ " \"name\": \"widgetId\",\n" +
+ " \"in\": \"path\",\n" +
+ " \"required\": true,\n" +
+ " \"schema\": {\n" +
+ " \"type\": \"string\"\n" +
+ " }\n" +
+ " }\n" +
+ " ],\n" +
+ " \"responses\": {\n" +
+ " \"200\": {\n" +
+ " \"description\": \"Returns widget with matching id\",\n" +
+ " \"content\": {\n" +
+ " \"application/json\": {\n" +
+ " \"schema\": {\n" +
+ " \"$ref\": \"#/components/schemas/Widget\"\n" +
+ " }\n" +
+ " }\n" +
+ " }\n" +
+ " }\n" +
+ " }\n" +
+ " }\n" +
+ " }\n" +
+ " },\n" +
+ " \"components\": {\n" +
+ " \"schemas\": {\n" +
+ " \"Widget\": {\n" +
+ " \"type\": \"object\",\n" +
+ " \"properties\": {\n" +
+ " \"a\": {\n" +
+ " \"type\": \"string\"\n" +
+ " },\n" +
+ " \"b\": {\n" +
+ " \"type\": \"string\"\n" +
+ " },\n" +
+ " \"id\": {\n" +
+ " \"type\": \"string\"\n" +
+ " }\n" +
+ " }\n" +
+ " }\n" +
+ " }\n" +
+ " }\n" +
+ "}";
+ private static final String EXPECTED_YAML = "openapi: 3.0.0\n" +
+ "paths:\n" +
+ " /widgets/{widgetId}:\n" +
+ " get:\n" +
+ " tags:\n" +
+ " - widgets\n" +
+ " summary: Find pet by ID\n" +
+ " description: Returns a pet when ID <= 10. ID > 10 or nonintegers will simulate\n" +
+ " API error conditions\n" +
+ " operationId: getWidget\n" +
+ " parameters:\n" +
+ " - name: widgetId\n" +
+ " in: path\n" +
+ " required: true\n" +
+ " schema:\n" +
+ " type: string\n" +
+ " responses:\n" +
+ " 200:\n" +
+ " description: Returns widget with matching id\n" +
+ " content:\n" +
+ " application/json:\n" +
+ " schema:\n" +
+ " $ref: '#/components/schemas/Widget'\n" +
+ "components:\n" +
+ " schemas:\n" +
+ " Widget:\n" +
+ " type: object\n" +
+ " properties:\n" +
+ " a:\n" +
+ " type: string\n" +
+ " b:\n" +
+ " type: string\n" +
+ " id:\n" +
+ " type: string\n";
+
+ private static final int jettyPort = System.getProperties().containsKey("jetty.port") ? Integer.parseInt(System.getProperty("jetty.port")): -1;
+
+ @BeforeMethod
+ public void checkJetty() {
+ if (jettyPort == -1) {
+ throw new SkipException("Jetty not configured");
+ }
+ }
+
+ @Test
+ public void testSwaggerJson() throws Exception {
+
+ String actualBody = given()
+ .port(jettyPort)
+ .log().all()
+ .when()
+ .get("/openapi.json")
+ .then()
+ .log().all()
+ .assertThat()
+ .statusCode(200)
+ .contentType(ContentType.JSON)
+ .extract()
+ .response().body().asString();
+
+ compareAsJson(actualBody, EXPECTED_JSON);
+ }
+
+ @Test
+ public void testSwaggerJsonUsingAcceptHeader() throws Exception {
+ String actualBody = given()
+ .port(jettyPort)
+ .log().all()
+ .accept(ContentType.JSON)
+ .when()
+ .get("/openapi")
+ .then()
+ .log().all()
+ .assertThat()
+ .statusCode(200)
+ .contentType(ContentType.JSON)
+ .extract().response().body().asString();
+
+ compareAsJson(actualBody, EXPECTED_JSON);
+ }
+
+ @Test
+ public void testSwaggerYaml() throws Exception {
+ String actualBody = given()
+ .port(jettyPort)
+ .log().all()
+ .when()
+ .get("/openapi.yaml")
+ .then()
+ .log().all()
+ .assertThat()
+ .statusCode(200)
+ .contentType("application/yaml")
+ .extract().response().body().asString();
+
+ compareAsYaml(actualBody, EXPECTED_YAML);
+ }
+
+ @Test
+ public void testSwaggerYamlUsingAcceptHeader() throws Exception {
+ String actualBody = given()
+ .port(jettyPort)
+ .log().all()
+ .accept("application/yaml")
+ .when()
+ .get("/openapi")
+ .then()
+ .log().all()
+ .assertThat()
+ .statusCode(200)
+ .contentType("application/yaml")
+ .extract().response().body().asString();
+
+ compareAsYaml(actualBody, EXPECTED_YAML);
+ }
+}
diff --git a/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/it/model/Widget.java b/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/it/model/Widget.java
new file mode 100644
index 0000000000..31c2290688
--- /dev/null
+++ b/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/it/model/Widget.java
@@ -0,0 +1,35 @@
+package io.swagger.v3.jaxrs2.it.model;
+
+public class Widget {
+
+ private String a;
+ private String b;
+ private String id;
+
+ public String getA() {
+ return a;
+ }
+
+ public Widget setA(String a) {
+ this.a = a;
+ return this;
+ }
+
+ public String getB() {
+ return b;
+ }
+
+ public Widget setB(String b) {
+ this.b = b;
+ return this;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public Widget setId(String id) {
+ this.id = id;
+ return this;
+ }
+}
diff --git a/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/it/resources/WidgetResource.java b/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/it/resources/WidgetResource.java
new file mode 100644
index 0000000000..ce2e84069e
--- /dev/null
+++ b/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/it/resources/WidgetResource.java
@@ -0,0 +1,37 @@
+package io.swagger.v3.jaxrs2.it.resources;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+
+import io.swagger.v3.jaxrs2.it.model.Widget;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.tags.Tag;
+
+import javax.ws.rs.core.Response;
+
+@Path("/widgets")
+@Tag(name="widgets")
+@Produces("application/json")
+@Consumes("application/json")
+public class WidgetResource {
+
+ @Path("/{widgetId}")
+ @GET
+ @Operation(summary = "Find pet by ID",
+ description = "Returns a pet when ID <= 10. ID > 10 or nonintegers will simulate API error conditions",
+ responses = @ApiResponse(
+ content = @Content(schema = @Schema(implementation = Widget.class)),
+ description = "Returns widget with matching id",
+ responseCode = "200"
+ )
+ )
+ public Response getWidget(@PathParam("widgetId") String widgetId) {
+ return Response.ok(new Widget().setA("foo").setB("bar")).build();
+ }
+}
diff --git a/modules/swagger-jaxrs2/src/test/webapp/WEB-INF/web.xml b/modules/swagger-jaxrs2/src/test/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000000..c370bda00e
--- /dev/null
+++ b/modules/swagger-jaxrs2/src/test/webapp/WEB-INF/web.xml
@@ -0,0 +1,31 @@
+
+