Hi all,

I've seen some demand for testing RESTful services (for example useful for testing AtomPub servers) with webtest. Currently, this cannot be done using webtest because "invoke" does not allow to change the content type for POST requests; Plus, HTTP method PUT cannot be used to send content.

Marc said earlier a patch would be welcome (http://lists.canoo.com/pipermail/webtest/2008q1/010021.html): > I don't think that you will be able to send a body currently with PUT for instance. Any patch is welcome.

So, I've attached a patch that solves this problem and makes webtest usable for any RESTful service (a door opener for a huge comunity). The patch should be 100% backwards compatible with hitherto functionality. It adds an additional attribute "contentType" which can be used to overwrite the content-type HTTP header. Also, I've enabled the PUT method to send body data within this patch.

I hope this is helpful for others as well and would be happy if it makes it into the trunk. Thank you for all your fantastic work.

cheers,

Dennis

--
Dennis Knochenwefel
Software Architect

28msec Inc.
http://www.28msec.com
http://twitter.com/28msec

Index: src/main/java/com/canoo/webtest/steps/request/InvokePage.java
===================================================================
--- src/main/java/com/canoo/webtest/steps/request/InvokePage.java       
(Revision 117476)
+++ src/main/java/com/canoo/webtest/steps/request/InvokePage.java       
(Arbeitskopie)
@@ -38,6 +38,7 @@
     private String fMethod = "GET";
     private File fContentFile;
     private String fContent;
+    private String fContentType;
 
     private String fSoapAction;
 
@@ -48,8 +49,25 @@
     public String getUrl() {
         return fUrl;
     }
+    
+    public String getContentType() {
+        return fContentType;
+    }
 
     /**
+     * Sets the HTTP Content Type.
+     *
+     * @param contentType
+     * @webtest.parameter
+     *   required="no"
+     *   description="Sets the Content type of the request. Defaults to 
'application/x-www-form-urlencoded' for a POST request."
+     */
+    public void setContentType(final String contentType) {
+       fContentType = contentType;
+    }
+    
+    /**
      * Alternative to set the content of a SOAP message.
      * @param txt the content
      * @webtest.nested.parameter
@@ -86,7 +104,7 @@
      * @webtest.parameter
      *   required="no"
      *   default="GET"
-     *   description="Sets the HTTP Method, i.e. whether the invoke is a GET 
or POST."
+     *   description="Sets the HTTP Method, i.e. whether the invoke is a GET 
or POST. Also, more advanced HTTP methods like PUT, DELETE, HEAD, or OPTIONS 
can be used."
      */
     public void setMethod(final String method) {
         fMethod = method;
@@ -143,40 +161,58 @@
     }
 
     protected void verifyParameters() {
-        super.verifyParameters();
-        nullParamCheck(getUrl(), "url");
-        paramCheck(getContent() != null && getContentFile() != null, "Only one 
of 'content' and 'contentFile' must be set.");
-        paramCheck("POST".equals(getMethod()) && getContent() == null && 
getContentFile() == null,
-                "One of 'content' or 'contentFile' must be set for POST.");
+       super.verifyParameters();
+       nullParamCheck(getUrl(), "url");
+        paramCheck(getContent() != null && getContentFile() != null, 
+                       "Only one of 'content' and 'contentFile' must be set.");
+       
+        String method=getMethod().toUpperCase();
+        paramCheck(!"POST".equals(method) 
+                       && !"GET".equals(method)
+                       && !"PUT".equals(method)
+                       && !"DELETE".equals(method)
+                       && !"HEAD".equals(method)
+                       && !"OPTIONS".equals(method),
+                "'method' must be one of GET, POST, PUT, DELETE, HEAD, or 
OPTIONS.");
+        paramCheck("POST".equals(method) && getContent() == null && 
getContentFile() == null,
+                "One of 'content' or 'contentFile' must be set for POST 
requests.");
+        paramCheck("PUT".equals(method) && getContent() == null && 
getContentFile() == null,
+                "One of 'content' or 'contentFile' must be set for PUT 
requests.");
+        paramCheck("GET".equals(method) && !(getContent() == null && 
getContentFile() == null),
+                "'content' and 'contentFile' must not be set for GET 
requests.");
+        paramCheck("DELETE".equals(method) && !(getContent() == null && 
getContentFile() == null),
+                "'content' and 'contentFile' must not be set for GET 
requests.");
+
     }
 
     protected Page findTarget() throws IOException, SAXException {
-        if ("POST".equals(getMethod())) {
-            return findTargetByPost();
+          fCompleteUrl = getContext().getConfig().getUrlForPage(getUrl());
+        final WebRequest request = new WebRequest(new URL(fCompleteUrl));
+        request.setHttpMethod(HttpMethod.valueOf(getMethod().toUpperCase()));
+        if ("POST".equals(getMethod().toUpperCase()) || 
"PUT".equals(getMethod().toUpperCase())) {
+            return findTargetByPostOrPut(request);
         }
-        fCompleteUrl = getContext().getConfig().getUrlForPage(getUrl());
-        final WebRequest settings = new WebRequest(new URL(fCompleteUrl));
-        settings.setHttpMethod(HttpMethod.valueOf(getMethod().toUpperCase()));
-        return getResponse(settings);
+        return getResponse(request);
     }
 
-    private Page findTargetByPost() throws IOException, SAXException {
-        String url = getContext().getConfig().getUrlForPage(getUrl());
-        final WebRequest settings = new WebRequest(new URL(url), 
HttpMethod.POST);
-        
-        // get default encoding
+    private Page findTargetByPostOrPut(WebRequest request) throws IOException, 
SAXException {
+       // get default encoding
         final String charset = System.getProperty("file.encoding");
         
         final Map headers = new HashMap();
         if (!StringUtils.isEmpty(fSoapAction)) {
+               
             headers.put("Content-type", "text/xml; charset=" + charset);
             headers.put("SOAPAction", fSoapAction);
-        } 
+        }
+        else if(!StringUtils.isEmpty(fContentType)) {
+            headers.put("Content-type", fContentType);
+        }
         else {
-            // TODO: is this the correct Content-type for non-SOAP posts?
             headers.put("Content-type", "application/x-www-form-urlencoded");
         }
-        settings.setAdditionalHeaders(headers);
+        
+        request.setAdditionalHeaders(headers);
         final String content;
         if (getContent() != null) {
             content = getContent();
@@ -184,9 +220,9 @@
         else {
             content = FileUtil.readFileToString(getContentFile(), this);
         }
-        settings.setRequestBody(content);
-        settings.setCharset(charset);
-        return getResponse(settings);
+        request.setRequestBody(content);
+        request.setCharset(charset);
+        return getResponse(request);
     }
 
     protected String getLogMessageForTarget() {

Reply via email to