Repository: eclipse/microprofile-open-api
Pull request #136 (2017-12-08 16:34:41)

Updated servlet to get serverurl/user/pwd from its caller + TCK tests
PR for #69:
- Added TCK tests
- Passed username/password/serverurl from the test into the servlet

Signed-off-by: Navid Shakibapour <navid.shakibapour@gmail.com>


Patch:
diff --git a/tck/pom.xml b/tck/pom.xml
index 76fa985..d63ccdc 100644
--- a/tck/pom.xml
+++ b/tck/pom.xml
@@ -106,13 +106,6 @@
             <version>2.0</version>
         </dependency>
 
-        <dependency>
-            <groupId>javax.servlet</groupId>
-            <artifactId>javax.servlet-api</artifactId>
-            <version>3.1.0</version>
-            <scope>provided</scope>
-        </dependency>
-
          <dependency>
              <groupId>io.rest-assured</groupId>
              <artifactId>rest-assured</artifactId>
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
index aac70b7..74234a8 100644
--- 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
@@ -21,6 +21,8 @@ import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.Arrays;
 import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
 
 import javax.servlet.ServletException;
 import javax.servlet.annotation.WebServlet;
@@ -49,26 +51,22 @@ public class YamlToJsonConverterServlet extends HttpServlet {
     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 = "/openapi";
 
-    private String username;
-    private String password;
-    private String serverUrl;
+    public static final String TCK_HEADER_USERNAME = "x-tck-username";
+    public static final String TCK_HEADER_PASSWORD = "x-tck-password";
+    public static final String TCK_HEADER_SERVERURL = "x-tck-serverurl";
 
-    @Override
-    public void init() throws ServletException {
-        username = System.getProperty("test.user");
-        password = System.getProperty("test.pwd");
+    private Set<String> ignoredHeaders = new HashSet<>(Arrays.asList(TCK_HEADER_USERNAME, TCK_HEADER_PASSWORD, TCK_HEADER_SERVERURL));
 
-        serverUrl = System.getProperty("test.url");
-        if (serverUrl == null) {
-            serverUrl = DEFAULT_PROTOCOL + "://" + DEFAULT_HOST + ":" + DEFAULT_PORT;
-        }
-    }
+    private String username = null;
+    private String password = null;
+    private String serverUrl = DEFAULT_PROTOCOL + "://" + DEFAULT_HOST + ":" + DEFAULT_PORT;
 
     @Override
     public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+        extractProperties(request);
+
         BufferedReader rd = null;
         PrintWriter writer = null;
 
@@ -88,9 +86,11 @@ public class YamlToJsonConverterServlet extends HttpServlet {
             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());
+                if (!ignoredHeaders.contains(headerName)) {
+                    Enumeration<String> headers = request.getHeaders(headerName);
+                    while (headers.hasMoreElements()) {
+                        targetRequest.addHeader(headerName, headers.nextElement());
+                    }
                 }
             }
 
@@ -130,4 +130,10 @@ public class YamlToJsonConverterServlet extends HttpServlet {
             }
         }
     }
+
+    private void extractProperties(HttpServletRequest request) {
+        serverUrl = request.getHeader(TCK_HEADER_SERVERURL);
+        username = request.getHeader(TCK_HEADER_USERNAME);
+        password = request.getHeader(TCK_HEADER_PASSWORD);
+    }
 }


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
index c411caa..7018451 100644
--- a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/EndpointTest.java
+++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/EndpointTest.java
@@ -24,6 +24,7 @@ import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.either;
 import static org.hamcrest.Matchers.empty;
 import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasItem;
 import static org.hamcrest.Matchers.hasItems;
 import static org.hamcrest.Matchers.hasKey;
 import static org.hamcrest.Matchers.hasSize;
@@ -35,8 +36,11 @@ import java.io.File;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
+import org.apache.commons.lang3.StringUtils;
 import org.eclipse.microprofile.openapi.tck.utils.YamlToJsonConverterServlet;
 import org.jboss.arquillian.container.test.api.Deployment;
 import org.jboss.arquillian.container.test.api.RunAsClient;
@@ -62,11 +66,15 @@ public class EndpointTest {
     private static final int DEFAULT_PORT = 9080;
 
     private static ValidatableResponse vr;
+    private static String serverUrl;
+    private static String username;
+    private static String password;
+    private static Map<String, String> headers = new HashMap<>();
 
     @BeforeClass
     public static void setUp() throws MalformedURLException {
         // set base URI and port number to use for all requests
-        String serverUrl = System.getProperty("test.url");
+        serverUrl = System.getProperty("test.url");
         String protocol = DEFAULT_PROTOCOL;
         String host = DEFAULT_HOST;
         int port = DEFAULT_PORT;
@@ -81,19 +89,25 @@ public class EndpointTest {
         RestAssured.baseURI = protocol + "://" + host;
         RestAssured.port = port;
 
-        String userName = System.getProperty("test.user");
-        String password = System.getProperty("test.pwd");
+        username = System.getProperty("test.user");
+        password = System.getProperty("test.pwd");
 
-        if (userName != null && password != null) {
-            RestAssured.authentication = RestAssured.basic(userName, password);
+        if (username != null && password != null) {
+            RestAssured.authentication = RestAssured.basic(username, password);
             RestAssured.useRelaxedHTTPSValidation();
         }
         RestAssured.defaultParser = Parser.JSON;
-    }
-
-    @Before
-    public void setUpTest() {
-        vr = given().when().get("/proxy").then().statusCode(200);
+        
+        if (StringUtils.isBlank(serverUrl)) {
+            serverUrl = DEFAULT_PROTOCOL + "://" + DEFAULT_HOST + ":" + DEFAULT_PORT;
+        }
+        headers.put(YamlToJsonConverterServlet.TCK_HEADER_SERVERURL, serverUrl);
+        if (StringUtils.isNotBlank(username)) {
+            headers.put(YamlToJsonConverterServlet.TCK_HEADER_USERNAME, username);
+        }
+        if (StringUtils.isNotBlank(password)) {
+            headers.put(YamlToJsonConverterServlet.TCK_HEADER_PASSWORD, password);
+        }
     }
 
     @Deployment(name = "proxy")
@@ -118,6 +132,11 @@ public class EndpointTest {
                 .addAsManifestResource("openapi.yaml", "openapi/openapi.yaml");
     }
 
+    @Before
+    public void setUpTest() {
+        vr = given().headers(headers).when().get("/proxy").then().statusCode(200);
+    }
+
     @Test
     @RunAsClient
     public void testVersion() {
@@ -356,7 +375,7 @@ public class EndpointTest {
         vr.body(reviewParameters, hasSize(1));
         vr.body(reviewParameters + ".findAll { it }.name", contains("id"));
         vr.body(reviewParameters + ".findAll { it.name == 'id' }.in", both(hasSize(1)).and(contains("path")));
-        // vr.body(reviewParameters + ".findAll { it.name == 'id' }.description", both(hasSize(1)).and(contains("ID of the booking")));
+        vr.body(reviewParameters + ".findAll { it.name == 'id' }.description", both(hasSize(1)).and(contains("ID of the booking")));
         vr.body(reviewParameters + ".findAll { it.name == 'id' }.required", both(hasSize(1)).and(contains(true)));
         vr.body(reviewParameters + ".findAll { it.name == 'id' }.content.'*/*'.schema.type", both(hasSize(1)).and(contains("integer")));
     }
@@ -371,7 +390,6 @@ public class EndpointTest {
             vr.body(bookingParameters + ".findAll { it }.name", contains("id"));
 
             vr.body(bookingParameters + ".findAll { it.name == 'id' }.in", both(hasSize(1)).and(contains("path")));
-            // TODO
             vr.body(bookingParameters + ".findAll { it.name == 'id' }.description", both(hasSize(1)).and(contains("ID of the booking")));
             vr.body(bookingParameters + ".findAll { it.name == 'id' }.required", both(hasSize(1)).and(contains(true)));
             vr.body(bookingParameters + ".findAll { it.name == 'id' }.schema.type", both(hasSize(1)).and(contains("integer")));
@@ -416,6 +434,54 @@ public class EndpointTest {
         vr.body(explode, equalTo(true));
     }
 
+    @Test
+    @RunAsClient
+    public void testSecuritySchemesInComponents() throws InterruptedException {
+        String s = "components.securitySchemes";
+        vr.body(s, hasKey("httpTestScheme"));
+        vr.body(s, hasKey("airlinesRatingApp_auth"));
+        vr.body(s, hasKey("reviewoauth2"));
+
+        vr.body(s + ".httpTestScheme.type", equalTo("http"));
+        vr.body(s + ".httpTestScheme.description", equalTo("user security scheme"));
+        vr.body(s + ".httpTestScheme.scheme", equalTo("testScheme"));
+
+        vr.body(s + ".airlinesRatingApp_auth.type", equalTo("apiKey"));
+        vr.body(s + ".airlinesRatingApp_auth.description", equalTo("authentication needed to access Airlines app"));
+        vr.body(s + ".airlinesRatingApp_auth.name", equalTo("api_key"));
+        vr.body(s + ".airlinesRatingApp_auth.in", equalTo("header"));
+
+        vr.body(s + ".reviewoauth2.type", equalTo("oauth2"));
+        vr.body(s + ".reviewoauth2.description", equalTo("authentication needed to create and delete reviews"));
+
+        String t = "components.securitySchemes.reviewoauth2.flows";
+        vr.body(t + ".implicit.authorizationUrl", equalTo("https://example.com/api/oauth/dialog"));
+        vr.body(t + ".implicit.scopes.'write:reviews'", equalTo("create a review"));
+        vr.body(t + ".authorizationCode.authorizationUrl", equalTo("https://example.com/api/oauth/dialog"));
+        vr.body(t + ".authorizationCode.tokenUrl", equalTo("https://example.com/api/oauth/token"));
+        vr.body(t + ".password.refreshUrl", equalTo("https://example.com/api/oauth/refresh"));
+        vr.body(t + ".clientCredentials.authorizationUrl", equalTo("https://example.com/api/oauth/clientcredentials"));
+        vr.body(t + ".clientCredentials.scopes.'read:reviews'", equalTo("search for a review"));
+    }
+
+    @Test
+    @RunAsClient
+    public void testOAuthAnnotations() throws InterruptedException {
+        String endpoint = "components.securitySchemes.reviewoauth2.flows.";
+
+        vr.body(endpoint + "implicit.authorizationUrl", equalTo("https://example.com/api/oauth/dialog"));
+        vr.body(endpoint + "implicit.scopes.'write:reviews'", equalTo("create a review"));
+
+        vr.body(endpoint + "authorizationCode.authorizationUrl", equalTo("https://example.com/api/oauth/dialog"));
+        vr.body(endpoint + "authorizationCode.tokenUrl", equalTo("https://example.com/api/oauth/token"));
+
+        vr.body(endpoint + "password.tokenUrl", equalTo("https://example.com/api/oauth/token"));
+        vr.body(endpoint + "password.refreshUrl", equalTo("https://example.com/api/oauth/refresh"));
+
+        vr.body(endpoint + "clientCredentials.tokenUrl", equalTo("https://example.com/api/oauth/token"));
+        vr.body(endpoint + "clientCredentials.scopes.'read:reviews'", equalTo("search for a review"));
+    }
+    
     @Test
     @RunAsClient
     public void testSecurityRequirement() throws InterruptedException {
@@ -424,6 +490,11 @@ public class EndpointTest {
         vr.body("paths.'/reviews'.post.security.reviewoauth2[0][0]", equalTo("write:reviews"));
         vr.body("paths.'/reviews'.post.security.reviewoauth2", hasSize(1));
 
+        vr.body("paths.'/bookings'.post.security.bookingSecurityScheme[0][0]", equalTo("write:bookings"));
+        vr.body("paths.'/bookings'.post.security.bookingSecurityScheme[0][1]", equalTo("read:bookings"));
+        vr.body("paths.'/reviews'.post.security.bookingSecurityScheme", hasSize(1));
+        vr.body("paths.'/bookings'.post.security.bookingSecurityScheme[0]", hasSize(2));
+
         vr.body("paths.'/user'.post.security.httpTestScheme[0][0]", equalTo("write:users"));
         vr.body("paths.'/user'.post.security.httpTestScheme", hasSize(1));
 
@@ -445,36 +516,163 @@ public class EndpointTest {
         vr.body("paths.'/user/{id}'.get.security.httpTestScheme[0][0]", equalTo("write:users"));
         vr.body("paths.'/user/{id}'.get.security.httpTestScheme", hasSize(1));
 
-        vr.body("paths.'/user/{login}'.get.security.httpTestScheme[0][0]", equalTo(null));
-        vr.body("paths.'/user/{logout}'.get.security.httpTestScheme[0][0]", equalTo(null));
+        vr.body("paths.'/user/login'.get.security.httpTestScheme[0][0]", equalTo("write:users"));
+        vr.body("paths.'/user/login'.get.security.httpTestScheme", hasSize(1));
+
+        vr.body("paths.'/user/logout'.get.security.httpTestScheme[0][0]", equalTo("write:users"));
+        vr.body("paths.'/user/logout'.get.security.httpTestScheme", hasSize(1));
     }
 
     @Test
     @RunAsClient
-    public void testSecuritySchemesInComponents() throws InterruptedException {
+    public void testSecuritySchemes() throws InterruptedException {
         String s = "components.securitySchemes";
         vr.body(s, hasKey("httpTestScheme"));
         vr.body(s, hasKey("airlinesRatingApp_auth"));
         vr.body(s, hasKey("reviewoauth2"));
+        vr.body(s, hasKey("bookingSecurityScheme"));
+    }
 
-        vr.body(s + ".httpTestScheme.type", equalTo("http"));
-        vr.body(s + ".httpTestScheme.description", equalTo("user security scheme"));
-        vr.body(s + ".httpTestScheme.name", equalTo("httpTestScheme"));
-        vr.body(s + ".httpTestScheme.scheme", equalTo("testScheme"));
+    @Test
+    @RunAsClient
+    public void testSecurityScheme() throws InterruptedException {
+        String http = "components.securitySchemes.httpTestScheme.";
+        vr.body(http + "type", equalTo("http"));
+        vr.body(http + "description", equalTo("user security scheme"));
+        vr.body(http + "scheme", equalTo("testScheme"));
+
+        String booking = "components.securitySchemes.bookingSecurityScheme.";
+        vr.body(booking + "type", equalTo("openIdConnect"));
+        vr.body(booking + "description", equalTo("Security Scheme for booking resource"));
+        vr.body(booking + "openIdConnectUrl", equalTo("http://openidconnect.com/testurl"));
+
+        String auth = "components.securitySchemes.airlinesRatingApp_auth.";
+        vr.body(auth + "type", equalTo("apiKey"));
+        vr.body(auth + "description", equalTo("authentication needed to access Airlines app"));
+        vr.body(auth + "name", equalTo("api_key"));
+        vr.body(auth + "in", equalTo("header"));
+        
+        String reviewoauth2 = "components.securitySchemes.reviewoauth2.";
+        vr.body(reviewoauth2 + "type", equalTo("oauth2"));
+        vr.body(reviewoauth2 + "description", equalTo("authentication needed to create and delete reviews"));
+    }
 
-        vr.body(s + ".airlinesRatingApp_auth.type", equalTo("apiKey"));
-        vr.body(s + ".airlinesRatingApp_auth.description", equalTo("authentication needed to access Airlines app"));
-        vr.body(s + ".airlinesRatingApp_auth.name", equalTo("airlinesRatingApp_auth"));
-        vr.body(s + ".airlinesRatingApp_auth.in", equalTo("header"));
+    @Test
+    @RunAsClient
+    public void testOAuthFlows() throws InterruptedException {
+        String t = "components.securitySchemes.reviewoauth2.flows";
+        vr.body(t, hasKey("implicit"));
+        vr.body(t, hasKey("authorizationCode"));
+        vr.body(t, hasKey("password"));
+        vr.body(t, hasKey("clientCredentials"));
+    }
 
-        vr.body(s + ".reviewoauth2.type", equalTo("oauth2"));
-        vr.body(s + ".reviewoauth2.description", equalTo("authentication needed to create and delete reviews"));
-        vr.body(s + ".reviewoauth2.name", equalTo("reviewoauth2"));
+    @Test
+    @RunAsClient
+    public void testOAuthFlow() throws InterruptedException {
+        String implicit = "components.securitySchemes.reviewoauth2.flows.implicit.";
+        vr.body(implicit + "authorizationUrl", equalTo("https://example.com/api/oauth/dialog"));
 
-        String t = "components.securitySchemes.reviewoauth2.flows";
-        vr.body(t + ".implicit.authorizationUrl", equalTo("https://example.com/api/oauth/dialog"));
-        vr.body(t + ".implicit.scopes.'write:reviews'", equalTo("create a review"));
-        vr.body(t + ".authorizationCode.authorizationUrl", equalTo("https://example.com/api/oauth/dialog"));
-        vr.body(t + ".authorizationCode.tokenUrl", equalTo("https://example.com/api/oauth/token"));
+        String authCode = "components.securitySchemes.reviewoauth2.flows.authorizationCode.";
+        vr.body(authCode + "authorizationUrl", equalTo("https://example.com/api/oauth/dialog"));
+        vr.body(authCode + "tokenUrl", equalTo("https://example.com/api/oauth/token"));
+
+        String password = "components.securitySchemes.reviewoauth2.flows.password.";
+        vr.body(password + "refreshUrl", equalTo("https://example.com/api/oauth/refresh"));
+
+        String client = "components.securitySchemes.reviewoauth2.flows.clientCredentials.";
+        vr.body(client + "tokenUrl", equalTo("https://example.com/api/oauth/token"));   
+    }
+
+    @Test
+    @RunAsClient
+    public void testOAuthScope() throws InterruptedException {
+        String implicit = "components.securitySchemes.reviewoauth2.flows.implicit.";
+        vr.body(implicit + "scopes.'write:reviews'", equalTo("create a review"));
+
+        String client = "components.securitySchemes.reviewoauth2.flows.clientCredentials.";
+        vr.body(client + "scopes.'read:reviews'", equalTo("search for a review"));   
+    }
+
+    @Test
+    @RunAsClient
+    public void testEncodingRequestBody() throws InterruptedException {
+        String s = "paths.'/user'.post.requestBody.content.'application/json'.encoding.email.";
+        vr.body(s + "contentType", equalTo("text/plain"));
+        vr.body(s + "style", equalTo("form"));
+        vr.body(s + "explode", equalTo(true));
+        vr.body(s + "allowReserved", equalTo(true));
+    }
+
+    @Test
+    @RunAsClient
+    public void testEncodingResponses() throws InterruptedException {
+        String s = "paths.'/user/{username}'.put.responses.'200'.content.'application/json'.encoding.password.";
+        vr.body(s + "contentType", equalTo("text/plain"));
+        vr.body(s + "style", equalTo("form"));
+        vr.body(s + "explode", equalTo(true));
+        vr.body(s + "allowReserved", equalTo(true));
+
+        String t = "paths.'/user/{username}'.put.responses.'200'.content.'application/xml'.encoding.password.";
+        vr.body(t + "contentType", equalTo("text/plain"));
+        vr.body(t + "style", equalTo("form"));
+        vr.body(t + "explode", equalTo(true));
+        vr.body(t + "allowReserved", equalTo(true));
+    }
+
+    @Test
+    @RunAsClient
+    public void testLink() throws InterruptedException {
+        String s = "paths.'/user/{id}'.get.responses.'200'.links.'User name'.";
+        vr.body(s + "operationId", equalTo("getUserByName"));
+        vr.body(s + "description", equalTo("The username corresponding to provided user id"));
+
+        String t = "paths.'/user/{id}'.get.responses.'200'.links.Review.";
+        vr.body(t + "operationRef", equalTo("/db/reviews/{userName}"));
+        vr.body(t + "description", equalTo("The reviews provided by user"));
+        
+        String k = "paths.'/reviews'.post.responses.'201'.links.Review.";
+        vr.body(k + "operationId", equalTo("getReviewById"));
+        vr.body(k + "description", equalTo("get the review that was added"));
+    }
+
+    @Test
+    @RunAsClient
+    public void testLinkParameter() throws InterruptedException {
+        String s = "paths.'/user/{id}'.get.responses.'200'.links.'User name'.";
+        vr.body(s + "parameters.userId", equalTo("$request.path.id"));
+
+        String t = "paths.'/user/{id}'.get.responses.'200'.links.Review.";
+        vr.body(t + "parameters.'path.userName'", equalTo("$response.body#userName"));
+
+        String k = "paths.'/reviews'.post.responses.'201'.links.Review.";
+        vr.body(k + "parameters.reviewId", equalTo("$request.path.id"));
+    }
+
+    @Test
+    @RunAsClient
+    public void testSchema() {
+        // Basic properties
+        vr.body("components.schemas.AirlinesRef.ref", equalTo("#/components/schemas/Airlines"));
+        vr.body("components.schemas.Airlines.title", equalTo("Airlines"));
+        vr.body("paths.‘/bookings’.post.responses.‘201’.content.‘application/json’.schema.type", equalTo("string"));
+        vr.body("components.schemas.id.format", equalTo("int32"));
+        vr.body("paths.‘/user’.post.requestBody.content.‘application/json’.schema.required", hasItem("password"));
+        vr.body("paths.‘/bookings’.post.responses.‘201’.content.‘application/json’.schema.description", equalTo("id of the new booking"));
+        vr.body("paths.‘/user’.post.requestBody.content.‘application/json’.schema.properties.password.example", hasItem("bobSm37"));
+        vr.body("paths.‘/user/createWithArray’.post.parameters.find{ it.name == ‘userArray’ }.content.‘application/json’.schema.nullable",
+                equalTo(true));
+        vr.body("paths.‘/user/createWithArray’.post.parameters.find{ it.name == ‘userArray’ }.content.‘application/json’.schema.writeOnly",
+                equalTo(true));
+
+        // Object properties
+        vr.body("paths.‘/user’.post.requestBody.content.‘application/json’.schema.maxproperties", equalTo(1024));
+        vr.body("paths.‘/user’.post.requestBody.content.‘application/json’.schema.minproperties", equalTo(1));
+        vr.body("paths.‘/user’.post.requestBody.content.‘application/json’.schema.requiredProperties", hasItems("id", "username", "password"));
+
+        // Array properties
+        vr.body("paths.‘/user/createWithArray’.post.parameters.‘userArray’.content.schema.maxItems", equalTo(20));
+        vr.body("paths.‘/user/createWithArray’.post.parameters.‘userArray’.content.schema.minItems", equalTo(2));
+        vr.body("paths.‘/user/createWithArray’.post.parameters.‘userArray’.content.schema.uniqueItems", equalTo(true));
     }
 }