Hi, As I mentioned last week, thanks to Jeff Turner who pointed to me the httpClient testing framework from Tomcat, I was able to do some very good progress in implementing a functional testing framework for Cocoon. With some more requirements from a team here, I actually extended it quite a bit to also be able to handle incoming HTTP requests.
I called this tool AntEater (pun intended), as it's heavily based on Ant. Anteater allows one to write tests that fire HTTP requests to a Cocoon installation and test the incoming response, using simple matching operations. If Anteater and Cocoon are on the same machine, you can use normal Ant tasks to modify Cocoon files while the system is running, send another request to the server and test in the response the modified Cocoon behavior. Using Anteater we should be able to write functional tests that automatically check Cocoon after any change we do to the source code. The only testing that happens right now seems to be a manual one. The intent is to have tests written for AntEater, along with the junit tests, and perhaps a Cactus based framework (still looking at it), part of a testing suite for Cocoon. I was wondering what would be a good way to release it. As it is right now it's a standalone package, much like Ant. You install it on the local filesystem, and you get an 'anteater' script, that behaves just like the 'ant' script from ant, while adding additional tasks. The reason for a separation from Cocoon is that it's quite generic, not tied to Cocoon in any way. In fact one of the team in my group plans to use it to test generic XML based applications, involving synchronous and asynchronous SOAP messages. I append the current documentation I wrote for it. I would appreciate any comments from you on Anteater. Regards, -- Ovidiu Predescu <[EMAIL PROTECTED]> http://orion.rgv.hp.com/ (inside HP's firewall only) http://sourceforge.net/users/ovidiu/ (my SourceForge page) http://www.geocities.com/SiliconValley/Monitor/7464/ (GNU, Emacs, other stuff)
Anteater is a simple testing framework designed around Ant, from the Apache Jakarta Project. It provides an easy way to write tests for testing the functionality of a Web application or of an XML Web service. The type of tests one might write using Anteater are: - send a request to a Web server using a POST or GET HTTP request - check the returned headers, and error code from the HTTP response - assuming that the returned document is an XML document, check in the document for the existence of a particular element or compare its value with a specified value. Here is a simple example one can write using Anteater: <target name="simple"> <http> <comment>Post a simple SOAP request</comment> <soapRequest href="http://services.xmethods.net:80/soap" content="requests/get-quote"> <match responseCode="200"> <xpath select="/soap:Envelope/soap:Body/n:getQuoteResponse/Result"/> </match> </soapRequest> </http> </target> The following tasks are defined within the Anteater framework. - <http> This task is the topmost task that encloses all the HTTP actions you want to specify as part of your test. Making requests =============== - <httpRequest> Make an HTTP request to a Web server. If the client machine is behind a firewall, and the Web server under test is outside the firewall, you need to specify the http.proxyHost and http.proxyPort to the JVM for the HTTP request to work. Attributes - id (String): the name of this task, to be referred to later - host (String; default is 'localhost'): the name of the host where the Web server runs. - port (integer; default is 8080): the port number of the Web server to which the request is to be sent. - path (String; default is empty): the path of the HTTP request, including any additional GET parameters - user (String): the user name to be used with basic authentication - password (String): the password to be used when basic authentication is to be used. - href (String): the URL of the Web server. Use either a combination of the host and port attributes, or the href attribute, to specify where the server is running. - content (String): an URL of a resource whose content is to be sent to the Web server. If you don't specify any protocol, the assumed protocol is file:. If the file doesn't start with a /, it is assumed to be relative to the directory where Ant was started from. - protocol (String; default 'HTTP/1.0'): The HTTP protocol to be used. - debug (number; default 0): Debug level for messages. Use a debug level greater than 5 to get some meaningful information on what's going on over the wire. Elements - <header>: header to be passed in the HTTP request - <parameter>: specifies an additional parameter to be passed to the server - <match>: specifies the set of rules to be used to match the HTTP response against. Examples // Send an HTTP GET request to http://localhost:8080/ <httpRequest/> // Equivalent to an HTTP GET request to http://localhost/ <httpRequest port="80"/> // Equivalent to an HTTP POST request to // http://localhost:8080/servlets/example // passing the content of /etc/passwd to the Web server <httpRequest path="/servlets/example" method="POST" content="/etc/passwd"/> - <soapRequest> Send a SOAP request to a SOAP server. This is equivalent to a httpRequest, with a SOAPAction set to "", and the method set to POST. Attributes All the attributes defined in httpRequest are inherited by soapRequest. The following attributes are in addition to those: - action (String): set the SOAP action. Elements that could be used inside <httpRequest> ================================================ - <header> Set a header to be passed to the Web server. Attributes - name (String): the name of the header - value (String): the value of the header - <parameter> Set a parameter to be passed in a request to the server. Attributes - name (String): the name of the parameter - value (String): the value of the parameter - type (String): the request type. This can be used to force passing a GET parameter for an explicit POST request (defined using the method attribute of the httpRequest element). Matching on the response ======================== You can match on the response received from the server using the generic <match> element. Each <match> element specifies a collection of rules that will be checked against the response. The <match> rule succeeds if all the rules inside it succeed. Multiple <match> rules can be listed inside a request. At runtime, the set of rules described in the first <match> element are checked. If one of them fails, the second <match> element is used to do the check. This process happens until one <match> element succeeds, at which point the matching process stops. If no <match> element matches successfully, the whole matching fails and the <httpRequest> element fails. Example: In this example, the response is checked, and the "DateResult" Ant property is set to the value of the "Date" header, when the response code is 200. If 404 is returned instead, the "notFound" property is set to 1. Otherwise the "failed" attribute is set to 1. Only the property name matching the rule that succeeded is set to 1, all the rest are set to 0. <httpRequest> <match responseCode="200"> <header name="Date" assign="DateResult"/> </match> <match responseCode="404" assign="notFound"/> <match assign="failed"/> </httpRequest> The possible attributes that can be used to match on the response are: - responseCode (integer): the value of the HTTP response code. - contentEquals (URL): check if the body of the response matches exactly the contents of the file specified by the URL described by this attribute. - contentEqualsIgnoreSpaces (URL): same as above, except that the match is done ignoring any whitespace character. Here is a list of the elements that can be embedded within a <match> element: - <parameter> Checks for the existance of an HTTP parameter in the response. If only the name attribute of this element is present, the response is checked to see if the parameter exists in the response. If a value is also specified, the parameter's value is checked against that. Attributes: - name (String): the name of the HTTP parameter - value (String): the value of the HTTP parameter; no value means the parameter is checked for its existance. - assign (String): name of an Ant property that will store the actual value of the parameter. Example: // Checks if the "Date" header is present in the HTTP response, // and assigns it to the "DateResult" Ant property. <httpRequest> <match> <parameter name="Date" assign="DateResult"/> </match> </httpRequest> - <xpath> Assuming that the HTTP response contains an XML document, uses XPath to check the existance or the value of various elements. Attributes: - select (XPath expression): the XPath to look for in the body of the response. No namespaces are used, so you should use exactly the same local name for the elements as in the response document. - value (String): the value the XPath node identified above should have. If this attribute is not present, the XPath node is only checked for existance. - assign (String): the name of the Ant property to store the string value of the selected XPath expression. Example <soapRequest href="http://services.xmltoday.com/vx_engine/soap-trigger.pperl" content="test/requests/get-quote2" action="urn:vgx-realtime"> <match responseCode="200"> <xpath select="/SOAP-ENV:Envelope/SOAP-ENV:Body" assign="Body"/> </match> </soapRequest> - <header> Checks the existance of an HTTP header in the HTTP response. If the "value" attribute of this element is not present, the header is only checked for existance. Attributes - name (String): the name of the header to look for. - value (String): matches the actual value of the header against this value. If this attribute is not present, the header is only checked for existance. - assign (String): the name of an Ant property to store the actual value of the header. Accepting incoming HTTP requests ================================ Some applications, like ebXML and BizTalk based applications, will accept an HTTP request as a high level asynchronous business request. They will later generate a reply as another HTTP request to an URL specified by the client in the original message. To test such applications, we need to have the ability to listen to incoming HTTP requests. This is accomplished using the tasks described in this section. - <servletContainer> Use this task to specify that this test script needs the ability to receive incoming HTTP requests. The receiver will act as a real Web server with the ability to receive incoming HTTP requests. This element should be an immediate child of Ant's <project> element. Do not use the <receiver> element inside a target or another task. Attributes - port (integer): Port number on which the receiver should listen on. You can specify multiple ports by enumerating them using commas in between. - <listener> When this task is encountered, the normal Ant processing is stopped until a request at the URL specified by <listener> is received. You can further filter the incoming request based on its headers, parameters or POST content. This task will not return until a request matches the specified constraints. Attributes - port (integer): The port on which the message should be received). - path (String): Path to which the receiver should wait for incoming requests. - timeout (integer): Number of seconds to wait for an incoming message to come. If the timeout expires and no message has been received the listen task fails. No timeout attribute or the timeout value set to 0 is equivalent to wait indefinitely. Elements - <match>: Checks the incoming request to see if it conforms to an expected request. This element is the same as the one used to check the HTTP response, except that you can now test for more things. Matching on the incoming request ================================ The incoming message received by a <listener> task can be checked to see if it conforms with an expected request. As with the HTTP response, the incoming request you can check the parameters, the headers and the body of the message. An incoming request can be of multiple types. For example in a B2B application the incoming request can be a SOAP message that contains different XML documents. You can specify multiple matches for an incoming request by using multiple <match> elements inside the <listener> element. The rules for executing the <match> elements are the same as the ones described in the section describing matching on the HTTP response. Example: In this example the incoming request can be a SOAP message containing either an receipt acknowledge message or a SOAP fault message, indicating an error. <listener path="/receipt"> <match method="POST"> <xpath select="/soap:Envelope/soap:Body/receipt-ack"/> <xpath select="/soap:Envelope/soap:Body/response-to" assign="replyHref"/> <sendResponse href="${replyHref}/> </match> <match assign="failed"> <matchBody select="/soap:Envelope/soap:Body/rfq"/> <matchMethod code="POST"/> </match> </listener> To be able to identify which set of rules matched, you can define the optional attribute "assign". If the corresponding set of rules inside the <match> element succeed, the Ant property named by the "assign" attribute will contain 1, otherwise the value will be 0. - <match> Container of the rules to match the incoming request against. All the rules need to be true for the <match> element to succeed. Attributes - assign (boolean): Assign the result of the matching to this property. - <method>: Check the method request type (POST, GET etc.) Elements: - <header>: Match the header of the incoming request - <parameter>: Match the parameters of the incoming GET request - <xpath>: Assuming the incoming request is a POST request, and the HTTP request body contains an XML document, checks for an XPath expression. See the above description of <xpath> for more information. Examples // Send a SOAP request to a server and wait for a receipt // acknowledge document to come back in 2 hours. If nothing comes back // before 2 hours, the <listener> task fails, causing the "test" target // to fail too. <target name="test"> <http> <soapRequest href="http://some.remote.server" content="file:/some/file"/> <listener path="/receiptAck" timeout="7200"> <match method="POST"> <xpath select="/soap:Envelope/soap:Body/receipt-ack"/> </match> </listener> </http> </target> // Send a SOAP request to a server and wait for an HTTP request to // come back, without actually checking anything on the document. <target name="test"> <http> <soapRequest href="http://some.remote.server" content="file:/some/file"/> <listener path="/"/> </http> </target>
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, email: [EMAIL PROTECTED]