Repository: eclipse/microprofile-open-api
Pull request #110 (2017-12-05 13:50:36)

Tck sample test
PR for #61 and #69:
- Sample test for hitting the `/openapi` endpoint and checking for OpenAPI version
- Added a servlet to forward calls to `/openapi` and convert YAML to JSON in the response
- Added required libraries for running the servlet when creating deployable app.


Patch:
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/callbacks/Callback.java b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/callbacks/Callback.java
index 756322b..569a22c 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/callbacks/Callback.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/callbacks/Callback.java
@@ -64,12 +64,8 @@ public @interface Callback {
 
     /**
      * Reference value to a Callback object.
-     * <p>
-     * This property provides a reference to an object defined elsewhere. This property and
-     * all other properties are mutually exclusive. If other properties are defined in addition
-     * to the ref property then the result is undefined.
-     * 
-     * @return reference to a callback object definition
+     *
+     * @return reference to a callback
      **/
     String ref() default "";
 }
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/headers/Header.java b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/headers/Header.java
index 5278289..decca0d 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/headers/Header.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/headers/Header.java
@@ -81,11 +81,7 @@ public @interface Header {
 
     /**
      * Reference value to a Header object.
-     * <p>
-     * This property provides a reference to an object defined elsewhere. This property and
-     * all other properties are mutually exclusive. If other properties are defined in addition
-     * to the ref property then the result is undefined.
-     * 
+     *
      * @return reference to a header
      **/
     String ref() default "";
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/links/Link.java b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/links/Link.java
index a90583e..9e4cd28 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/links/Link.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/links/Link.java
@@ -90,10 +90,6 @@ public @interface Link {
 
     /**
      * Reference value to a Link object.
-     * <p>
-     * This property provides a reference to an object defined elsewhere. This property and
-     * all other properties are mutually exclusive. If other properties are defined in addition
-     * to the ref property then the result is undefined.
      *
      * @return reference to a link
      **/
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/ExampleObject.java b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/ExampleObject.java
index 7b12fff..b55b145 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/ExampleObject.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/ExampleObject.java
@@ -77,10 +77,6 @@ public @interface ExampleObject {
 
     /**
      * Reference value to an Example object.
-     * <p>
-     * This property provides a reference to an object defined elsewhere. This property and
-     * all other properties are mutually exclusive. If other properties are defined in addition
-     * to the ref property then the result is undefined.
      *
      * @return reference to an example
      **/
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/Schema.java b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/Schema.java
index 721eab5..4e86318 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/Schema.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/Schema.java
@@ -211,12 +211,8 @@ public @interface Schema {
 
     /**
      * Reference value to a Schema definition.
-     * <p>
-     * This property provides a reference to an object defined elsewhere. This property and
-     * all other properties are mutually exclusive. If other properties are defined in addition
-     * to the ref property then the result is undefined.
      * 
-     * @return a reference to a schema definition
+     * @return a reference to this schema
      **/
     String ref() default "";
 
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/parameters/Parameter.java b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/parameters/Parameter.java
index 90b67df..2184ed9 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/parameters/Parameter.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/parameters/Parameter.java
@@ -192,10 +192,6 @@ public @interface Parameter {
 
     /**
      * Reference value to a Parameter object.
-     * <p>
-     * This property provides a reference to an object defined elsewhere. This property and
-     * all other properties are mutually exclusive. If other properties are defined in addition
-     * to the ref property then the result is undefined.
      *
      * @return reference to a parameter
      **/
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/parameters/RequestBody.java b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/parameters/RequestBody.java
index 6676e4f..1fd5a5d 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/parameters/RequestBody.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/parameters/RequestBody.java
@@ -67,10 +67,6 @@ public @interface RequestBody {
     
     /**
      * Reference value to a RequestBody object.
-     * <p>
-     * This property provides a reference to an object defined elsewhere. This property and
-     * all other properties are mutually exclusive. If other properties are defined in addition
-     * to the ref property then the result is undefined.
      *
      * @return reference to a request body
      **/
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/responses/APIResponse.java b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/responses/APIResponse.java
index a7d5eea..3ba12b1 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/responses/APIResponse.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/responses/APIResponse.java
@@ -100,10 +100,6 @@ public @interface APIResponse {
 
     /**
      * Reference value to a Response object.
-     * <p>
-     * This property provides a reference to an object defined elsewhere. This property and
-     * all other properties are mutually exclusive. If other properties are defined in addition
-     * to the ref property then the result is undefined.
      *
      * @return reference to a response
      **/
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/security/SecurityScheme.java b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/security/SecurityScheme.java
index 27b50a9..954dc6b 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/security/SecurityScheme.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/security/SecurityScheme.java
@@ -120,10 +120,6 @@ public @interface SecurityScheme {
 
     /**
      * Reference value to a SecurityScheme object.
-     * <p>
-     * This property provides a reference to an object defined elsewhere. This property and
-     * all other properties are mutually exclusive. If other properties are defined in addition
-     * to the ref property then the result is undefined.
      *
      * @return reference to a security scheme
      **/
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/servers/ServerVariable.java b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/servers/ServerVariable.java
index 7fb1362..7948c27 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/servers/ServerVariable.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/servers/ServerVariable.java
@@ -42,7 +42,7 @@ public @interface ServerVariable {
      * 
      * @return array of possible values for this ServerVariable
      **/
-    String[] enumeration() default {};
+    String[] enumeration() default "";
 
     /**
      * The default value of this server variable. This is a REQUIRED property.
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/tags/Tag.java b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/tags/Tag.java
index 068a43a..dbd70bb 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/tags/Tag.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/tags/Tag.java
@@ -103,10 +103,6 @@ public @interface Tag {
 
     /**
      * Reference value to a Tag object.
-     * <p>
-     * This property provides a reference to an object defined elsewhere. This property and
-     * all other properties are mutually exclusive. If other properties are defined in addition
-     * to the ref property then the result is undefined.
      *
      * @return reference to a tag
      **/
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/Reference.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/Reference.java
index 420db34..39e39ba 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/models/Reference.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/Reference.java
@@ -18,7 +18,7 @@
 package org.eclipse.microprofile.openapi.models;
 
 /**
- * Base interface for OpenAPI model objects that can make reference to other objects.
+ * Base interface for OpenAPI model objects that can be references to other objects.
  */
 public interface Reference<T extends Reference<T>> {
 
@@ -31,30 +31,8 @@ public interface Reference<T extends Reference<T>> {
 
     /**
      * Sets this Reference's reference property to the given string.
-     * <p>
-     * Normally a full reference string is a JSON pointer 
-     * <a href="https://tools.ietf.org/html/rfc6901">RFC6901</a> which indicates an object
-     * definition in the components section of the current OpenAPI document. For example 
-     * the schema of a request body may be #/components/schemas/Payload or the definition 
-     * of a parameter could be #/components/parameters/Routing.HostName.
-     * <p>
-     * If you provide a short name then the name will automatically be expanded to
-     * the appropriate full reference string. A short name is a string which is not a 
-     * JSON pointer in that it does not contain a "/".
-     * <p>
-     * The appropriate full reference is determined by the context. 
-     * For a parameter the short name will be prefixed by 
-     * "#/components/parameters/" to create "#/components/parameters/ShortName". 
-     * <pre><code>parameter.setRef("ShortName"); // #/components/parameters/ShortName</code></pre>
-     * For a response the prefix is "#/components/responses/":
-     * <pre><code>response.setRef("NotFound"); // #/components/responses/NotFound</code></pre>
-     * <p>
-     * This property provides a reference to an object defined elsewhere. This property and 
-     * all other properties are mutually exclusive. If other properties are defined in addition 
-     * to the reference property then the result is undefined. 
-     * 
-     * @param ref a reference to a T object in the components section of this OpenAPI document
-     * or a JSON pointer to another document. 
+     *
+     * @param ref a reference to a T object in the components in this OpenAPI document
      **/
     void setRef(String ref);
 
diff --git a/tck/pom.xml b/tck/pom.xml
index 928b8c9..8d07305 100644
--- a/tck/pom.xml
+++ b/tck/pom.xml
@@ -112,5 +112,45 @@
             <version>3.1.0</version>
             <scope>provided</scope>
         </dependency>
+
+         <dependency>
+             <groupId>io.rest-assured</groupId>
+             <artifactId>rest-assured</artifactId>
+             <version>3.0.6</version>
+             <scope>compile</scope>
+         </dependency>
+
+         <dependency>
+             <groupId>org.hamcrest</groupId>
+             <artifactId>hamcrest-all</artifactId>
+             <version>1.3</version>
+             <scope>compile</scope>
+         </dependency>
+
+         <dependency>
+             <groupId>javax.servlet</groupId>
+             <artifactId>javax.servlet-api</artifactId>
+             <version>3.1.0</version>
+             <scope>compile</scope>
+         </dependency>
+
+         <dependency>
+             <groupId>org.apache.httpcomponents</groupId>
+             <artifactId>httpclient</artifactId>
+             <version>4.5.2</version>
+             <scope>compile</scope>
+         </dependency>
+
+         <dependency>
+             <groupId>com.fasterxml.jackson.core</groupId>
+             <artifactId>jackson-databind</artifactId>
+             <version>2.9.2</version>
+         </dependency>
+
+         <dependency>
+             <groupId>com.fasterxml.jackson.dataformat</groupId>
+             <artifactId>jackson-dataformat-yaml</artifactId>
+             <version>2.9.2</version>
+         </dependency>
     </dependencies>
 </project>
diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/apps/airlines/JAXRSApp.java b/tck/src/main/java/org/eclipse/microprofile/openapi/apps/airlines/JAXRSApp.java
index 02cf160..531ff8b 100644
--- a/tck/src/main/java/org/eclipse/microprofile/openapi/apps/airlines/JAXRSApp.java
+++ b/tck/src/main/java/org/eclipse/microprofile/openapi/apps/airlines/JAXRSApp.java
@@ -23,14 +23,7 @@ import javax.ws.rs.core.Application;
 import org.eclipse.microprofile.openapi.annotations.info.Contact;
 import org.eclipse.microprofile.openapi.annotations.info.Info;
 import org.eclipse.microprofile.openapi.annotations.info.License;
-import org.eclipse.microprofile.openapi.annotations.links.Link;
-import org.eclipse.microprofile.openapi.annotations.links.LinkParameter;
-import org.eclipse.microprofile.openapi.annotations.media.Content;
-import org.eclipse.microprofile.openapi.annotations.media.ExampleObject;
 import org.eclipse.microprofile.openapi.annotations.media.Schema;
-import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
-import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody;
-import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
 import org.eclipse.microprofile.openapi.annotations.tags.Tag;
 import org.eclipse.microprofile.openapi.annotations.security.SecurityScheme;
 import org.eclipse.microprofile.openapi.annotations.security.SecurityRequirement;
@@ -38,15 +31,9 @@ import org.eclipse.microprofile.openapi.annotations.servers.Server;
 import org.eclipse.microprofile.openapi.annotations.servers.ServerVariable;
 import org.eclipse.microprofile.openapi.annotations.enums.SecuritySchemeIn;
 import org.eclipse.microprofile.openapi.annotations.enums.SecuritySchemeType;
-import org.eclipse.microprofile.openapi.annotations.headers.Header;
 import org.eclipse.microprofile.openapi.annotations.ExternalDocumentation;
 import org.eclipse.microprofile.openapi.annotations.OpenAPIDefinition;
-import org.eclipse.microprofile.openapi.annotations.Operation;
-import org.eclipse.microprofile.openapi.annotations.callbacks.Callback;
-import org.eclipse.microprofile.openapi.annotations.Components;
-import org.eclipse.microprofile.openapi.apps.airlines.model.Airline;
-import org.eclipse.microprofile.openapi.apps.airlines.model.Booking;
-import org.eclipse.microprofile.openapi.apps.airlines.model.Review;
+
 import org.eclipse.microprofile.openapi.apps.airlines.resources.AirlinesResource;
 import org.eclipse.microprofile.openapi.apps.airlines.resources.AvailabilityResource;
 import org.eclipse.microprofile.openapi.apps.airlines.resources.BookingResource;
@@ -54,11 +41,7 @@ import org.eclipse.microprofile.openapi.apps.airlines.resources.ReviewResource;
 
 @ApplicationPath("/")
 @OpenAPIDefinition(
-    tags = {
-            @Tag(name = "Airlines", description = "airlines app"),
-            @Tag(name="user", description="Operations about user"),
-            @Tag(name="create", description="Operations about create")
-    },
+    tags = @Tag(name = "Airlines", description = "airlines app"),
     externalDocs = @ExternalDocumentation(
         description = "instructions for how to deploy this app",
         url = "https://github.com/microservices-api/oas3-airlines/blob/master/README.md"),
@@ -97,46 +80,7 @@ import org.eclipse.microprofile.openapi.apps.airlines.resources.ReviewResource;
                     description = "Flight availabilities",
                     defaultValue = "availability")
             })
-        },
-        components = @Components(
-                schemas = { 
-                        @Schema(name = "Bookings", type = "array", implementation = Booking.class),
-                        @Schema(name = "Airlines", type = "array", implementation = Airline.class),
-                        @Schema(name = "AirlinesRef", ref = "#/components/schemas/Airlines") }, 
-                responses = {
-                        @APIResponse(name = "FoundAirlines", responseCode = "200", description = "successfully found airlines", 
-                                content = @Content(mediaType = "application/json", schema = @Schema(type = "array", implementation = Airline.class))),
-                        @APIResponse(name = "FoundBookings", responseCode = "200", description = "Bookings retrieved", 
-                                content = @Content(schema = @Schema(type = "array", implementation = Booking.class))) }, 
-                parameters = {
-                        @Parameter(name = "departureDate", required = true, description = "Customer departure date", 
-                                schema = @Schema(implementation = String.class)),
-                        @Parameter(name = "username", description = "The name that needs to be deleted", 
-                        schema = @Schema(type = "String"), required = true) }, 
-                examples = {
-                        @ExampleObject(name = "review", summary = "External review example", 
-                                externalValue = "http://foo.bar/examples/review-example.json"),
-                        @ExampleObject(name = "user", summary = "External user example", 
-                                externalValue = "http://foo.bar/examples/user-example.json") }, 
-                requestBodies = {
-                        @RequestBody(name = "review", content = @Content(mediaType = "application/json", 
-                                schema = @Schema(implementation = Review.class)), required = true, description = "example review to add") }, 
-                headers = {
-                        @Header(name = "Max-Rate", description = "Maximum rate", schema = @Schema(type = "integer"), 
-                                required = true, allowEmptyValue = true, deprecated = true),
-                        @Header(name = "Request-Limit", description = "The number of allowed requests in the current period", 
-                                schema = @Schema(type = "integer")) }, 
-                securitySchemes = {
-                        @SecurityScheme(securitySchemeName = "httpTestScheme", description = "user security scheme", 
-                                type = SecuritySchemeType.HTTP, scheme = "testScheme") }, 
-                links = {
-                        @Link(name = "UserName", description = "The username corresponding to provided user id", operationId = "getUserByName", 
-                                parameters = @LinkParameter(name = "userId", expression = "$request.path.id")) }, 
-                callbacks = {
-                        @Callback(name = "GetBookings", callbackUrlExpression = "http://localhost:9080/airlines/bookings", 
-                                operation = @Operation(summary = "Retrieve all bookings for current user", 
-                                responses = {@APIResponse(ref = "FoundBookings") })) 
-                        }))
+        })
 @SecurityScheme(
     securitySchemeName = "airlinesRatingApp_auth",
     description = "authentication needed to access Airlines app",
diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/apps/airlines/resources/AirlinesResource.java b/tck/src/main/java/org/eclipse/microprofile/openapi/apps/airlines/resources/AirlinesResource.java
index 4a90e0a..1dfda59 100644
--- a/tck/src/main/java/org/eclipse/microprofile/openapi/apps/airlines/resources/AirlinesResource.java
+++ b/tck/src/main/java/org/eclipse/microprofile/openapi/apps/airlines/resources/AirlinesResource.java
@@ -93,7 +93,15 @@ public class AirlinesResource {
         tags = {"airlines"},
         responses = {
             @APIResponse(
-                ref = "FoundAirlines"
+                responseCode = "200",
+                description = "successful operation",
+                content = @Content(
+                    mediaType = "application/json",
+                    schema = @Schema(
+                        type = "array",
+                        implementation = Airline.class
+                    )
+                )
             ),
             @APIResponse(
                 responseCode = "404",
diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/apps/airlines/resources/ReviewResource.java b/tck/src/main/java/org/eclipse/microprofile/openapi/apps/airlines/resources/ReviewResource.java
index 3ef49e1..77ab402 100644
--- a/tck/src/main/java/org/eclipse/microprofile/openapi/apps/airlines/resources/ReviewResource.java
+++ b/tck/src/main/java/org/eclipse/microprofile/openapi/apps/airlines/resources/ReviewResource.java
@@ -42,7 +42,6 @@ import org.eclipse.microprofile.openapi.annotations.servers.Server;
 import org.eclipse.microprofile.openapi.annotations.servers.ServerVariable;
 import org.eclipse.microprofile.openapi.annotations.tags.Tags;
 import org.eclipse.microprofile.openapi.annotations.media.Content;
-import org.eclipse.microprofile.openapi.annotations.headers.Header;
 import org.eclipse.microprofile.openapi.annotations.media.Schema;
 import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody;
 import org.eclipse.microprofile.openapi.annotations.media.ExampleObject;
@@ -118,8 +117,7 @@ public class ReviewResource {
                     type = "array",
                     implementation = Review.class
                 )
-            ),
-            headers = @Header(ref="Request-Limit")
+            )
         )
     )
     @Produces("application/json")
diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/apps/airlines/resources/UserResource.java b/tck/src/main/java/org/eclipse/microprofile/openapi/apps/airlines/resources/UserResource.java
index 7d8a83c..17c6027 100644
--- a/tck/src/main/java/org/eclipse/microprofile/openapi/apps/airlines/resources/UserResource.java
+++ b/tck/src/main/java/org/eclipse/microprofile/openapi/apps/airlines/resources/UserResource.java
@@ -30,11 +30,8 @@ import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
 import org.eclipse.microprofile.openapi.annotations.enums.ParameterIn;
 import org.eclipse.microprofile.openapi.annotations.enums.ParameterStyle;
 import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
-import org.eclipse.microprofile.openapi.annotations.responses.APIResponses;
 import org.eclipse.microprofile.openapi.annotations.security.SecurityScheme;
 import org.eclipse.microprofile.openapi.annotations.servers.Server;
-import org.eclipse.microprofile.openapi.annotations.tags.Tag;
-import org.eclipse.microprofile.openapi.annotations.tags.Tags;
 import org.eclipse.microprofile.openapi.annotations.enums.SecuritySchemeType;
 import org.eclipse.microprofile.openapi.annotations.security.SecurityRequirement;
 import org.eclipse.microprofile.openapi.annotations.media.Content;
@@ -87,22 +84,12 @@ public class UserResource {
     static UserData userData = new UserData();
 
     @POST
-    @Tags(refs={"user","create"})
-    @APIResponses(value={
-            @APIResponse(
-                    responseCode = "200",
-                    description = "New user record successfully created."
-                ),
-                @APIResponse(
-                    responseCode = "400",
-                    description = "Unable to create this user record."
-                )
-    })
     @Operation(
         method = "post",
         summary = "Create user",
         description = "This can only be done by the logged in user.",
         operationId = "createUser",
+        tags = {"user"},
         requestBody = @RequestBody(
             description = "Record of a new user to be created in the system.",
             required = true,
@@ -214,6 +201,16 @@ public class UserResource {
                 required = true,
                 schema = @Schema(type = "integer")
             )
+        },
+        responses = {
+            @APIResponse(
+                responseCode = "200",
+                description = "New user record successfully created."
+            ),
+            @APIResponse(
+                responseCode = "400",
+                description = "Unable to create this user record."
+            )
         })
     public Response createUser(
         @Parameter(
@@ -227,12 +224,11 @@ public class UserResource {
 
     @POST
     @Path("/createWithArray")
-    @Tag(ref="user")
     @Operation(
         method = "post",
         summary = "Creates list of users with given input array", //Array of User objects
         operationId = "createUsersFromArray",
-        /* tags = {"user"}, //this operation intentionally doesn't have tags attribute, since above Tag ref should apply */
+        tags = {"user"},
         parameters = {
             @Parameter(
                 name = "userArray",
@@ -563,10 +559,6 @@ public class UserResource {
 
     @GET
     @Path("/logout")
-    @APIResponse(
-                responseCode = "200",
-                description = "Successful user logout."
-                )
     @Operation(
         method = "get",
         summary = "Logs out current logged in user session",
@@ -575,7 +567,13 @@ public class UserResource {
         externalDocs = @ExternalDocumentation(
             description = "Policy on user security.",
             url = "http://exampleurl.com/policy"
-            ))
+            ),
+        responses = {
+            @APIResponse(
+                responseCode = "200",
+                description = "Successful user logout."
+                )
+            })
     public Response logoutUser() {
     return Response.ok().entity("").build();
     }
diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/utils/YamlToJsonConverterServlet.java b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/utils/YamlToJsonConverterServlet.java
new file mode 100644
index 0000000..90118cc
--- /dev/null
+++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/utils/YamlToJsonConverterServlet.java
@@ -0,0 +1,133 @@
+/**
+ * Copyright (c) 2017 Contributors to the Eclipse Foundation
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.eclipse.microprofile.openapi.tck.utils;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.Enumeration;
+
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.apache.http.HttpResponse;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.BasicCredentialsProvider;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.util.EntityUtils;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+
+@WebServlet("/")
+public class YamlToJsonConverterServlet extends HttpServlet {
+    private static final long serialVersionUID = 1L;
+
+    private static final String DEFAULT_PROTOCOL = "http";
+    private static final String DEFAULT_HOST = "localhost";
+    private static final int DEFAULT_PORT = 9080;
+
+    private static final String OPENAPI_PATH = "/api/docs";
+
+    private String username;
+    private String password;
+    private String serverUrl;
+
+    @Override
+    public void init() throws ServletException {
+        username = System.getProperty("test.user");
+        password = System.getProperty("test.pwd");
+
+        serverUrl = System.getProperty("test.url");
+        if (serverUrl == null) {
+            serverUrl = DEFAULT_PROTOCOL + "://" + DEFAULT_HOST + ":" + DEFAULT_PORT;
+        }
+    }
+
+    @Override
+    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+        BufferedReader rd = null;
+        PrintWriter writer = null;
+
+        try {
+            HttpClientBuilder builder = HttpClientBuilder.create();
+            if (username != null && password != null) {
+                CredentialsProvider provider = new BasicCredentialsProvider();
+                UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username, password);
+                provider.setCredentials(AuthScope.ANY, credentials);
+                builder.setDefaultCredentialsProvider(provider);
+            }
+
+            HttpClient client = builder.build();
+            HttpGet targetRequest = new HttpGet(serverUrl + OPENAPI_PATH);
+
+            // Copy request headers
+            Enumeration<String> headerNames = request.getHeaderNames();
+            while (headerNames.hasMoreElements()) {
+                String headerName = headerNames.nextElement();
+                Enumeration<String> headers = request.getHeaders(headerName);
+                while (headers.hasMoreElements()) {
+                    targetRequest.addHeader(headerName, headers.nextElement());
+                }
+            }
+
+            // Forward the request
+            HttpResponse targetResponse = client.execute(targetRequest);
+
+            // Copy response headers
+            response.setStatus(targetResponse.getStatusLine().getStatusCode());
+            Arrays.stream(targetResponse.getAllHeaders()).forEach(h -> response.addHeader(h.getName(), h.getValue()));
+
+            // Copy the content
+            String yaml = EntityUtils.toString(targetResponse.getEntity());
+
+            // Convert the yaml to json
+            ObjectMapper yamlReader = new ObjectMapper(new YAMLFactory());
+            Object obj = yamlReader.readValue(yaml, Object.class);
+
+            ObjectMapper jsonWriter = new ObjectMapper();
+            String json = jsonWriter.writeValueAsString(obj);
+            writer = response.getWriter();
+            writer.print(json);
+            writer.close();
+        }
+        catch (Exception e) {
+            response.sendError(500, "Failed to convert the request: " + ExceptionUtils.getMessage(e));
+        }
+        finally {
+            if (rd != null) {
+                try {
+                    rd.close();
+                }
+                catch (IOException e) {
+                }
+            }
+            if (writer != null) {
+                writer.close();
+            }
+        }
+    }
+}
diff --git a/tck/src/main/resources/openapi.yaml b/tck/src/main/resources/openapi.yaml
new file mode 100644
index 0000000..ead3a4d
--- /dev/null
+++ b/tck/src/main/resources/openapi.yaml
@@ -0,0 +1,74 @@
+# Copyright (c) 2017 Contributors to the Eclipse Foundation
+# <p>
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# <p>
+# http://www.apache.org/licenses/LICENSE-2.0
+# <p>
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+ 
+openapi: 3.0.0
+info:
+  title: Callback Example
+  version: 1.0.0
+paths:
+  /streams:
+    post:
+      description: subscribes a client to receive out-of-band data
+      parameters:
+        - name: callbackUrl
+          in: query
+          required: true
+          description: |
+            the location where data will be sent.  Must be network accessible
+            by the source server
+          schema:
+            type: string
+            format: uri
+            example: https://tonys-server.com
+      responses:
+        '201':
+          description: subscription successfully created
+          content:
+            application/json:
+              schema:
+                description: subscription information
+                required:
+                  - subscriptionId
+                properties:
+                  subscriptionId:
+                    description: this unique identifier allows management of the subscription
+                    type: string
+                    example: 2531329f-fb09-4ef7-887e-84e648214436
+      callbacks:
+        # the name `onData` is a convenience locator
+        onData:
+          # when data is sent, it will be sent to the `callbackUrl` provided
+          # when making the subscription PLUS the suffix `/data`
+          '{$request.query.callbackUrl}/data':
+            post:
+              requestBody:
+                description: subscription payload
+                content:
+                  application/json:
+                    schema:
+                      properties:
+                        timestamp:
+                          type: string
+                          format: date-time
+                        userData:
+                          type: string
+              responses:
+                '202':
+                  description: |
+                    Your server implementation should return this HTTP status code
+                    if the data was received successfully
+                '204':
+                  description: |
+                    Your server should return this HTTP status code if no longer interested
+                    in further updates
\ No newline at end of file


Test patch:
diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/EndpointTest.java b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/EndpointTest.java
new file mode 100644
index 0000000..9c433a8
--- /dev/null
+++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/EndpointTest.java
@@ -0,0 +1,109 @@
+/**
+ * Copyright (c) 2017 Contributors to the Eclipse Foundation
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.eclipse.microprofile.openapi.tck;
+
+import static io.restassured.RestAssured.given;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.equalTo;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.eclipse.microprofile.openapi.tck.utils.YamlToJsonConverterServlet;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.container.test.api.RunAsClient;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.EmptyAsset;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import io.restassured.RestAssured;
+import io.restassured.parsing.Parser;
+import io.restassured.response.Response;
+
+@RunWith(Arquillian.class)
+public class EndpointTest {
+    private static final String APPLICATION_JSON = "application/json";
+    private static final String APPLICATION_YAML = "application/yaml";
+
+    private static final String DEFAULT_PROTOCOL = "http";
+    private static final String DEFAULT_HOST = "localhost";
+    private static final int DEFAULT_PORT = 9080;
+
+    @BeforeClass
+    static public void setup() throws MalformedURLException {
+        // set base URI and port number to use for all requests
+        String serverUrl = System.getProperty("test.url");
+        String protocol = DEFAULT_PROTOCOL;
+        String host = DEFAULT_HOST;
+        int port = DEFAULT_PORT;
+
+        if (serverUrl != null) {
+            URL url = new URL(serverUrl);
+            protocol = url.getProtocol();
+            host = url.getHost();
+            port = (url.getPort() == -1) ? DEFAULT_PORT : url.getPort();
+        }
+
+        RestAssured.baseURI = protocol + "://" + host;
+        RestAssured.port = port;
+
+        String userName = System.getProperty("test.user");
+        String password = System.getProperty("test.pwd");
+
+        if (userName != null && password != null) {
+            RestAssured.authentication = RestAssured.basic(userName, password);
+            RestAssured.useRelaxedHTTPSValidation();
+        }
+    }
+
+    @Deployment(name = "proxy")
+    public static WebArchive createProxy() {
+        WebArchive war = ShrinkWrap.create(WebArchive.class, "proxy.war")
+                .addClass(YamlToJsonConverterServlet.class)
+                .addAsLibraries(new File("./lib/httpclient-4.5.2.jar"))
+                .addAsLibraries(new File("./lib/httpcore-4.4.4.jar"))
+                .addAsLibraries(new File("./lib/jackson-core-2.9.2.jar"))
+                .addAsLibraries(new File("./lib/jackson-dataformat-yaml-2.9.2.jar"))
+                .addAsLibraries(new File("./lib/jackson-databind-2.9.2.jar"))
+                .addAsLibraries(new File("./lib/jackson-annotations-2.9.1.jar"))
+                .addAsLibraries(new File("./lib/snakeyaml-1.18.jar"))
+                .addAsLibraries(new File("./lib/commons-logging-1.2.jar"));
+        System.out.println(war.toString(true));
+        return war;
+    }
+
+    @Deployment(name = "airlines")
+    public static WebArchive createDeployment() {
+        WebArchive war = ShrinkWrap.create(WebArchive.class, "airlines.war")
+                .addPackages(true, "org.eclipse.microprofile.openapi.apps.airlines")
+                .addAsManifestResource(EmptyAsset.INSTANCE, "/openapi/openapi.yaml");
+        System.out.println(war.toString(true));
+        return war;
+    }
+
+    @Test
+    @RunAsClient
+    public void testVersion() throws InterruptedException {
+        Response response = given().when().get("/proxy");
+        response.then().parser("", Parser.JSON).statusCode(200).body("openapi", equalTo("3.0.0")).body("info.description", containsString("Liberty"));
+    }
+}