Added:
tomcat/trunk/modules/tomcat-lite/test/org/apache/tomcat/test/watchdog/WatchdogTestImpl.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/modules/tomcat-lite/test/org/apache/tomcat/test/watchdog/WatchdogTestImpl.java?rev=884421&view=auto
==============================================================================
---
tomcat/trunk/modules/tomcat-lite/test/org/apache/tomcat/test/watchdog/WatchdogTestImpl.java
(added)
+++
tomcat/trunk/modules/tomcat-lite/test/org/apache/tomcat/test/watchdog/WatchdogTestImpl.java
Thu Nov 26 06:55:49 2009
@@ -0,0 +1,1172 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.
+ */
+
+/**
+ * @Author Costin, Ramesh.Mandava
+ */
+
+package org.apache.tomcat.test.watchdog;
+
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import org.apache.tomcat.lite.io.Hex;
+
+// derived from Jsp
+
+public class WatchdogTestImpl {
+
+ int failureCount = 0;
+
+ int passCount = 0;
+
+ Throwable lastError;
+
+ boolean hasFailed = false;
+
+ String prefix = "http";
+
+ String host = "localhost";
+
+ String localHost = null;
+
+ String localIP = null;
+
+ int port = 8080;
+
+ int debug = 0;
+
+ String description = "No description";
+
+ String request;
+
+ HashMap requestHeaders = new HashMap();
+
+ String content;
+
+ // true if task is nested
+ private boolean nested = false;
+
+ // Expected response
+ boolean magnitude = true;
+
+ boolean exactMatch = false;
+
+ // expect a response body
+ boolean expectResponseBody = true;
+
+ // Match the body against a golden file
+ String goldenFile;
+
+ // Match the body against a string
+ String responseMatch;
+
+ // the response should include the following headers
+ HashMap expectHeaders = new HashMap();
+
+ // Headers that should not be found in response
+ HashMap unexpectedHeaders = new HashMap();
+
+ // Match request line
+ String returnCode = "";
+
+ String returnCodeMsg = "";
+
+ // Actual response
+ String responseLine;
+
+ byte[] responseBody;
+
+ HashMap headers;
+
+ // For Report generation
+ StringBuffer resultOut = new StringBuffer();
+
+ boolean firstTask = false;
+
+ boolean lastTask = false;
+
+ String expectedString;
+
+ String actualString;
+
+ String testName;
+
+ String assertion;
+
+ String testStrategy;
+
+ // For Session Tracking
+ static Hashtable sessionHash;
+
+ static Hashtable cookieHash;
+
+ String testSession;
+
+ Vector cookieVector;
+
+ URL requestURL;
+
+ CookieController cookieController;
+
+ /**
+ * Creates a new <code>GTest</code> instance.
+ *
+ */
+ public WatchdogTestImpl() {
+ }
+
+ /**
+ * <code>setTestSession</code> adds a CookieController for the value of
+ * sessionName
+ *
+ * @param sessionName
+ * a <code>String</code> value
+ */
+ public void setTestSession(String sessionName) {
+ testSession = sessionName;
+
+ if (sessionHash == null) {
+ sessionHash = new Hashtable();
+ } else if (sessionHash.get(sessionName) == null) {
+ sessionHash.put(sessionName, new CookieController());
+ }
+ }
+
+ /**
+ * <code>setTestName</code> sets the current test name.
+ *
+ * @param tn
+ * current testname.
+ */
+ public void setTestName(String tn) {
+ testName = tn;
+ }
+
+ /**
+ * <code>setAssertion</code> sets the assertion text for the current test.
+ *
+ * @param assertion
+ * assertion text
+ */
+ public void setAssertion(String assertion) {
+ this.assertion = assertion;
+ }
+
+ /**
+ * <code>setTestStrategy</code> sets the test strategy for the current
test.
+ *
+ * @param strategy
+ * test strategy text
+ */
+ public void setTestStrategy(String strategy) {
+ testStrategy = strategy;
+ }
+
+ /**
+ * <code>getTestName</code> returns the current test name.
+ *
+ * @return a <code>String</code> value
+ */
+ public String getTestName() {
+ return testName;
+ }
+
+ /**
+ * <code>getAssertion</code> returns the current assertion text.
+ *
+ * @return a <code>String</code> value
+ */
+ public String getAssertion() {
+ return assertion;
+ }
+
+ /**
+ * <code>getTestStrategy</code> returns the current test strategy test.
+ *
+ * @return a <code>String</code> value
+ */
+ public String getTestStrategy() {
+ return testStrategy;
+ }
+
+ /**
+ * <code>setFirstTask</code> denotes that current task being executed is
the
+ * first task within the list.
+ *
+ * @param a
+ * <code>boolean</code> value
+ */
+ public void setFirstTask(boolean val) {
+ firstTask = val;
+ }
+
+ /**
+ * <code>setLastTask</code> denotes that the current task being executed is
+ * the last task within the list.
+ *
+ * @param a
+ * <code>boolean</code> value
+ */
+ public void setLastTask(boolean val) {
+ lastTask = val;
+ }
+
+ /**
+ * <code>setPrefix</code> sets the protocol prefix. Defaults to "http"
+ *
+ * @param prefix
+ * Either http or https
+ */
+ public void setPrefix(String prefix) {
+ this.prefix = prefix;
+ }
+
+ /**
+ * <code>setHost</code> sets hostname where the target server is running.
+ * Defaults to "localhost"
+ *
+ * @param h
+ * a <code>String</code> value
+ */
+ public void setHost(String h) {
+ this.host = h;
+ }
+
+ /**
+ * <code>setPort</code> sets the port that the target server is listening
+ * on. Defaults to "8080"
+ *
+ * @param portS
+ * a <code>String</code> value
+ */
+ public void setPort(String portS) {
+ this.port = Integer.valueOf(portS).intValue();
+ }
+
+ /**
+ * <code>setExactMatch</code> determines if a byte-by-byte comparsion is
+ * made of the server's response and the test's goldenFile, or if a token
+ * comparison is made. By default, only a token comparison is made
+ * ("false").
+ *
+ * @param exact
+ * a <code>String</code> value
+ */
+ public void setExactMatch(String exact) {
+ exactMatch = Boolean.valueOf(exact).booleanValue();
+ }
+
+ /**
+ * <code>setContent</code> String value upon which the request header
+ * Content-Length is based upon.
+ *
+ * @param s
+ * a <code>String</code> value
+ */
+ public void setContent(String s) {
+ this.content = s;
+ }
+
+ /**
+ * <code>setDebug</code> enables debug output. By default, this is disabled
+ * ( value of "0" ).
+ *
+ * @param debugS
+ * a <code>String</code> value
+ */
+ public void setDebug(String debugS) {
+ debug = Integer.valueOf(debugS).intValue();
+ }
+
+ /**
+ * <code>setMagnitude</code> Expected return value of the test execution.
+ * Defaults to "true"
+ *
+ * @param magnitudeS
+ * a <code>String</code> value
+ */
+ public void setMagnitude(String magnitudeS) {
+ magnitude = Boolean.valueOf(magnitudeS).booleanValue();
+ }
+
+ /**
+ * <code>setGoldenFile</code> Sets the goldenfile that will be used to
+ * validate the server's response.
+ *
+ * @param s
+ * fully qualified path and filename
+ */
+ public void setGoldenFile(String s) {
+ this.goldenFile = s;
+ }
+
+ /**
+ * <code>setExpectResponseBody</code> sets a flag to indicate if a response
+ * body is expected from the server or not
+ *
+ * @param b
+ * a <code>boolean</code> value
+ */
+ public void setExpectResponseBody(boolean b) {
+ this.expectResponseBody = b;
+ }
+
+ /**
+ * <code>setExpectHeaders</code> Configures GTest to look for the header
+ * passed in the server's response.
+ *
+ * @param s
+ * a <code>String</code> value in the format of
+ * <header-field>:<header-value>
+ */
+ public void setExpectHeaders(String s) {
+ this.expectHeaders = new HashMap();
+ StringTokenizer tok = new StringTokenizer(s, "|");
+ while (tok.hasMoreElements()) {
+ String header = (String) tok.nextElement();
+ setHeaderDetails(header, expectHeaders, false);
+ }
+ }
+
+ /**
+ * <code>setUnexpectedHeaders</code> Configures GTest to look for the
header
+ * passed to validate that it doesn't exist in the server's response.
+ *
+ * @param s
+ * a <code>String</code> value in the format of
+ * <header-field>:<header-value>
+ */
+ public void setUnexpectedHeaders(String s) {
+ this.unexpectedHeaders = new HashMap();
+ setHeaderDetails(s, unexpectedHeaders, false);
+ }
+
+ public void setNested(String s) {
+ nested = Boolean.valueOf(s).booleanValue();
+ }
+
+ /**
+ * <code>setResponseMatch</code> Match the passed value in the server's
+ * response.
+ *
+ * @param s
+ * a <code>String</code> value
+ */
+ public void setResponseMatch(String s) {
+ this.responseMatch = s;
+ }
+
+ /**
+ * <code>setRequest</code> Sets the HTTP/HTTPS request to be sent to the
+ * target server Ex. GET /servlet_path/val HTTP/1.0
+ *
+ * @param s
+ * a <code>String</code> value in the form of METHOD PATH
+ * HTTP_VERSION
+ */
+ public void setRequest(String s) {
+ this.request = s;
+ }
+
+ /**
+ * <code>setReturnCode</code> Sets the expected return code from the
+ * server's response.
+ *
+ * @param code
+ * a valid HTTP response status code
+ */
+ public void setReturnCode(String code) {
+ this.returnCode = code;
+ }
+
+ /**
+ * Describe <code>setReturnCodeMsg</code> Sets the expected return message
+ * to be found in the server's response.
+ *
+ * @param code
+ * a valid HTTP resonse status code
+ * @param message
+ * a <code>String</code> value
+ */
+ public void setReturnCodeMsg(String message) {
+ this.returnCodeMsg = message;
+ }
+
+ /**
+ * <code>setRequestHeaders</code> Configures the request headers GTest
+ * should send to the target server.
+ *
+ * @param s
+ * a <code>String</code> value in for format of
+ * <field-name>:<field-value>
+ */
+ public void setRequestHeaders(String s) {
+ requestHeaders = new HashMap();
+ StringTokenizer tok = new StringTokenizer(s, "|");
+ while (tok.hasMoreElements()) {
+ String header = (String) tok.nextElement();
+ setHeaderDetails(header, requestHeaders, true);
+ }
+ }
+
+ // Inner tests are not used currently, can be reworked
+
+ // /**
+ // * Add a Task to this container
+ // *
+ // * @param Task to add
+ // */
+ // public void addTask(Task task) {
+ // children.add(task);
+ // }
+
+ /**
+ * <code>execute</code> Executes the test.
+ *
+ * @exception BuildException
+ * if an error occurs
+ */
+ public void execute() {
+
+ try {
+
+ if (resultOut != null && !nested) {
+ resultOut.append("\ntestName: " + testName);
+ resultOut.append("\nreq: " + request);
+ resultOut.append("\nassertion: " + assertion);
+ resultOut.append("\ntestStrategy: " + testStrategy);
+ }
+
+ WatchdogHttpClient.dispatch(this);
+
+ hasFailed = !checkResponse(magnitude);
+
+ // if ( !children.isEmpty() ) {
+ // Iterator iter = children.iterator();
+ // while (iter.hasNext()) {
+ // Task task = (Task) iter.next();
+ // task.perform();
+ // }
+ // }
+
+ if (!hasFailed && !nested) {
+ passCount++;
+ if (resultOut != null) {
+ resultOut.append("<result>PASS</result>\n");
+ }
+// System.out.println(" PASSED " + testName + " ("
+// + request + ")");
+ } else if (hasFailed && !nested) {
+ failureCount++;
+ if (resultOut != null) {
+ resultOut.append("<result>FAIL</result>\n");
+ }
+ System.out.println(" FAILED " + testName + "\n ("
+ + request + ")\n" + resultOut.toString());
+ }
+
+ } catch (Exception ex) {
+ failureCount++;
+ System.out.println(" FAIL " + description + " (" + request + ")");
+ lastError = ex;
+ ex.printStackTrace();
+ } finally {
+ if (!nested) {
+ hasFailed = false;
+ }
+ }
+ }
+
+ /**
+ * <code>checkResponse</code> Executes various response checking mechanisms
+ * against the server's response. Checks include:
+ * <ul>
+ * <li>expected headers
+ * <li>unexpected headers
+ * <li>return codes and messages in the Status-Line
+ * <li>response body comparison againt a goldenfile
+ * </ul>
+ *
+ * @param testCondition
+ * a <code>boolean</code> value
+ * @return a <code>boolean</code> value
+ * @exception Exception
+ * if an error occurs
+ */
+ private boolean checkResponse(boolean testCondition) throws Exception {
+ boolean match = false;
+
+ if (responseLine != null) {
+ // If returnCode doesn't match
+ if (responseLine.indexOf("HTTP/1.") > -1) {
+
+ if (!returnCode.equals("")) {
+ boolean resCode = (responseLine.indexOf(returnCode) > -1);
+ boolean resMsg = (responseLine.indexOf(returnCodeMsg) >
-1);
+
+ if (returnCodeMsg.equals("")) {
+ match = resCode;
+ } else {
+ match = (resCode && resMsg);
+ }
+
+ if (match != testCondition) {
+
+ if (resultOut != null) {
+ String expectedStatusCode = "<expectedStatusCode>"
+ + returnCode + "</expectedReturnCode>\n";
+ String expectedReasonPhrase =
"<expectedReasonPhrase>"
+ + returnCodeMsg +
"</expectedReasonPhrase>";
+ actualString = "<actualStatusLine>" + responseLine
+ + "</actualStatusLine>\n";
+ resultOut.append(expectedStatusCode);
+ resultOut.append(expectedReasonPhrase);
+ resultOut.append(actualString);
+ }
+
+ return false;
+ }
+ }
+ } else {
+ resultOut.append("\n<failure>Wrong Http version: "
+ + responseLine + "</failure>");
+ return false;
+ }
+ } else {
+ resultOut.append("\n<failure>No response from server</failure>");
+ return false;
+ }
+
+ /*
+ * Check for headers the test expects to be in the server's response
+ */
+
+ // Duplicate set of response headers
+ HashMap copiedHeaders = cloneHeaders(headers);
+
+ // used for error reporting
+ String currentHeaderField = null;
+ String currentHeaderValue = null;
+
+ if (!expectHeaders.isEmpty()) {
+ boolean found = false;
+ String expHeader = null;
+
+ if (!headers.isEmpty()) {
+ Iterator expectIterator = expectHeaders.keySet().iterator();
+ while (expectIterator.hasNext()) {
+ found = false;
+ String expFieldName = (String) expectIterator.next();
+ currentHeaderField = expFieldName;
+ ArrayList expectValues = (ArrayList) expectHeaders
+ .get(expFieldName);
+ Iterator headersIterator = copiedHeaders.keySet()
+ .iterator();
+
+ while (headersIterator.hasNext()) {
+ String headerFieldName = (String) headersIterator
+ .next();
+ ArrayList headerValues = (ArrayList) copiedHeaders
+ .get(headerFieldName);
+
+ // compare field names and values in an HTTP 1.x
+ // compliant fashion
+ if ((headerFieldName.equalsIgnoreCase(expFieldName))) {
+ int hSize = headerValues.size();
+ int eSize = expectValues.size();
+
+ // number of expected headers found in server
+ // response
+ int numberFound = 0;
+
+ for (int i = 0; i < eSize; i++) {
+ currentHeaderValue = (String) expectValues
+ .get(i);
+
+ /*
+ * Handle the Content-Type header appropriately
+ * based on the the test is configured to look
+ * for.
+ */
+ if (currentHeaderField
+ .equalsIgnoreCase("content-type")) {
+ String resVal = (String) headerValues
+ .get(0);
+ if (currentHeaderValue.indexOf(';') > -1) {
+ if (currentHeaderValue.equals(resVal))
{
+ numberFound++;
+ headerValues.remove(0);
+ }
+ } else if (resVal
+ .indexOf(currentHeaderValue) > -1)
{
+ numberFound++;
+ headerValues.remove(0);
+ }
+ } else if (currentHeaderField
+ .equalsIgnoreCase("location")) {
+ String resVal = (String) headerValues
+ .get(0);
+ int idx = currentHeaderValue
+ .indexOf(":80/");
+ if (idx > -1) {
+ String tempValue = currentHeaderValue
+ .substring(0, idx)
+ + currentHeaderValue
+ .substring(idx + 3);
+ if (currentHeaderValue.equals(resVal)
+ || tempValue.equals(resVal)) {
+ numberFound++;
+ headerValues.remove(0);
+ }
+ } else {
+ if (currentHeaderValue.equals(resVal))
{
+ numberFound++;
+ headerValues.remove(0);
+ }
+ }
+ } else if (headerValues
+ .contains(currentHeaderValue)) {
+ numberFound++;
+ headerValues.remove(headerValues
+ .indexOf(currentHeaderValue));
+ }
+ }
+ if (numberFound == eSize) {
+ found = true;
+ }
+ }
+ }
+ if (!found) {
+ /*
+ * Expected headers not found in server response. Break
+ * the processing loop.
+ */
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ StringBuffer actualBuffer = new StringBuffer(128);
+ if (resultOut != null) {
+ expectedString = "<expectedHeaderNotFound>"
+ + currentHeaderField + ": " + currentHeaderValue
+ + "</expectedHeader>\n";
+ }
+ if (!headers.isEmpty()) {
+ Iterator iter = headers.keySet().iterator();
+ while (iter.hasNext()) {
+ String headerName = (String) iter.next();
+ ArrayList vals = (ArrayList) headers.get(headerName);
+ String[] val = (String[]) vals.toArray(new String[vals
+ .size()]);
+ for (int i = 0; i < val.length; i++) {
+ if (resultOut != null) {
+ actualBuffer.append("<actualHeader>"
+ + headerName + ": " + val[i]
+ + "</actualHeader>\n");
+ }
+ }
+ }
+ if (resultOut != null) {
+ resultOut.append(expectedString);
+ resultOut.append(actualBuffer.toString());
+ }
+ }
+ return false;
+ }
+ }
+
+ /*
+ * Check to see if we're looking for unexpected headers. If we are,
+ * compare the values in the unexectedHeaders ArrayList against the
+ * headers from the server response. if the unexpected header is found,
+ * then return false.
+ */
+
+ if (!unexpectedHeaders.isEmpty()) {
+ boolean found = false;
+ String unExpHeader = null;
+ // Check if we got any unexpected headers
+
+ if (!copiedHeaders.isEmpty()) {
+ Iterator unexpectedIterator = unexpectedHeaders.keySet()
+ .iterator();
+ while (unexpectedIterator.hasNext()) {
+ found = false;
+ String unexpectedFieldName = (String) unexpectedIterator
+ .next();
+ ArrayList unexpectedValues = (ArrayList) unexpectedHeaders
+ .get(unexpectedFieldName);
+ Iterator headersIterator = copiedHeaders.keySet()
+ .iterator();
+
+ while (headersIterator.hasNext()) {
+ String headerFieldName = (String) headersIterator
+ .next();
+ ArrayList headerValues = (ArrayList) copiedHeaders
+ .get(headerFieldName);
+
+ // compare field names and values in an HTTP 1.x
+ // compliant fashion
+ if ((headerFieldName
+ .equalsIgnoreCase(unexpectedFieldName))) {
+ int hSize = headerValues.size();
+ int eSize = unexpectedValues.size();
+ int numberFound = 0;
+ for (int i = 0; i < eSize; i++) {
+ if (headerValues.contains(unexpectedValues
+ .get(i))) {
+ numberFound++;
+ if (headerValues.indexOf(headerFieldName)
>= 0) {
+ headerValues.remove(headerValues
+ .indexOf(headerFieldName));
+ }
+ }
+ }
+ if (numberFound == eSize) {
+ found = true;
+ }
+ }
+ }
+ if (!found) {
+ /*
+ * Expected headers not found in server response. Break
+ * the processing loop.
+ */
+ break;
+ }
+ }
+ }
+
+ if (found) {
+ resultOut.append("\n Unexpected header received from server: "
+ + unExpHeader);
+ return false;
+ }
+ }
+
+ if (responseMatch != null) {
+ // check if we got the string we wanted
+ if (expectResponseBody && responseBody == null) {
+ resultOut.append("\n ERROR: got no response, expecting "
+ + responseMatch);
+ return false;
+ }
+ String responseBodyString = new String(responseBody);
+ if (responseBodyString.indexOf(responseMatch) < 0) {
+ resultOut.append("\n ERROR: expecting match on "
+ + responseMatch);
+ resultOut.append("\n Received: \n" + responseBodyString);
+ }
+ }
+
+ if (!expectResponseBody && responseBody != null) {
+ resultOut
+ .append("Received a response body from the server where
none was expected");
+ return false;
+ }
+
+ // compare the body
+ if (goldenFile == null)
+ return true;
+
+ // Get the expected result from the "golden" file.
+ byte[] expResult = getExpectedResult();
+ String expResultS = (expResult == null) ? "" : new String(expResult);
+ // Compare the results and set the status
+ boolean cmp = true;
+
+ if (exactMatch) {
+ cmp = compare(responseBody, expResult);
+ } else {
+ cmp = compareWeak(responseBody, expResult);
+ }
+
+ if (cmp != testCondition) {
+
+ if (resultOut != null) {
+ expectedString = "<expectedBody>" + new String(expResult)
+ + "</expectedBody>\n";
+ actualString = "<actualBody>"
+ + (responseBody != null ? new String(responseBody)
+ : "null") + "</actualBody>\n";
+ resultOut.append(expectedString);
+ resultOut.append(actualString);
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Replaces any |client.ip| and |client.host| parameter marks with the host
+ * and IP values of the host upon which Watchdog is running.
+ *
+ * @param request
+ * An HTTP request.
+ */
+ String replaceMarkers(String req, Socket socket) {
+
+ final String CLIENT_IP = "client.ip";
+ final String CLIENT_HOME = "client.host";
+
+ if (localIP == null || localHost == null) {
+ InetAddress addr = socket.getLocalAddress();
+ localHost = addr.getHostName();
+ localIP = addr.getHostAddress();
+ }
+
+ if (req.indexOf('|') > -1) {
+ StringTokenizer tok = new StringTokenizer(request, "|");
+ StringBuffer sb = new StringBuffer(50);
+
+ while (tok.hasMoreElements()) {
+ String token = tok.nextToken();
+ if (token.equals(CLIENT_IP)) {
+ sb.append(localIP);
+ } else if (token.equals(CLIENT_HOME)) {
+ sb.append(localHost);
+ } else {
+ sb.append(token);
+ }
+ }
+ return sb.toString();
+ } else {
+ return req;
+ }
+ }
+
+ /**
+ * <code>getExpectedResult</code> returns a byte array containing the
+ * content of the configured goldenfile
+ *
+ * @return goldenfile as a byte[]
+ * @exception IOException
+ * if an error occurs
+ */
+ private byte[] getExpectedResult() throws IOException {
+ byte[] expResult = { 'N', 'O', ' ', 'G', 'O', 'L', 'D', 'E', 'N', 'F',
+ 'I', 'L', 'E', ' ', 'F', 'O', 'U', 'N', 'D' };
+
+ try {
+ InputStream in = new BufferedInputStream(new FileInputStream(
+ goldenFile));
+ return readBody(in);
+ } catch (Exception ex) {
+ System.out.println("Golden file not found: " + goldenFile);
+ return expResult;
+ }
+ }
+
+ /**
+ * <code>compare</code> compares the two byte arrays passed in to verify
+ * that the lengths of the arrays are equal, and that the content of the
two
+ * arrays, byte for byte are equal.
+ *
+ * @param fromServer
+ * a <code>byte[]</code> value
+ * @param fromGoldenFile
+ * a <code>byte[]</code> value
+ * @return <code>boolean</code> true if equal, otherwise false
+ */
+ private boolean compare(byte[] fromServer, byte[] fromGoldenFile) {
+ if (fromServer == null || fromGoldenFile == null) {
+ return false;
+ }
+
+ /*
+ * Check to see that the respose and golden file lengths are equal. If
+ * they are not, dump the hex and don't bother comparing the bytes. If
+ * they are equal, iterate through the byte arrays and compare each
+ * byte. If the bytes don't match, dump the hex representation of the
+ * server response and the goldenfile and return false.
+ */
+ if (fromServer.length != fromGoldenFile.length) {
+ StringBuffer sb = new StringBuffer(50);
+ sb.append(" Response and golden files lengths do not match!\n");
+ sb.append(" Server response length: ");
+ sb.append(fromServer.length);
+ sb.append("\n Goldenfile length: ");
+ sb.append(fromGoldenFile.length);
+ resultOut.append(sb.toString());
+ sb = null;
+ // dump the hex representation of the byte arrays
+ dumpHex(fromServer, fromGoldenFile);
+
+ return false;
+ } else {
+
+ int i = 0;
+ int j = 0;
+
+ while ((i < fromServer.length) && (j < fromGoldenFile.length)) {
+ if (fromServer[i] != fromGoldenFile[j]) {
+ resultOut.append("\n Error at position " + (i + 1));
+ // dump the hex representation of the byte arrays
+ dumpHex(fromServer, fromGoldenFile);
+
+ return false;
+ }
+
+ i++;
+ j++;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * <code>compareWeak</code> creates new Strings from the passed arrays and
+ * then uses a StringTokenizer to compare non-whitespace tokens.
+ *
+ * @param fromServer
+ * a <code>byte[]</code> value
+ * @param fromGoldenFile
+ * a <code>byte[]</code> value
+ * @return a <code>boolean</code> value
+ */
+ private boolean compareWeak(byte[] fromServer, byte[] fromGoldenFile) {
+ if (fromServer == null || fromGoldenFile == null) {
+ return false;
+ }
+
+ boolean status = true;
+
+ String server = new String(fromServer);
+ String golden = new String(fromGoldenFile);
+
+ StringTokenizer st1 = new StringTokenizer(server);
+
+ StringTokenizer st2 = new StringTokenizer(golden);
+
+ while (st1.hasMoreTokens() && st2.hasMoreTokens()) {
+ String tok1 = st1.nextToken();
+ String tok2 = st2.nextToken();
+
+ if (!tok1.equals(tok2)) {
+ resultOut.append("\t FAIL*** : Rtok1 = " + tok1 + ", Etok2 = "
+ + tok2);
+ status = false;
+ }
+ }
+
+ if (st1.hasMoreTokens() || st2.hasMoreTokens()) {
+ status = false;
+ }
+
+ if (!status) {
+ StringBuffer sb = new StringBuffer(255);
+ sb
+ .append("ERROR: Server's response and configured
goldenfile do not match!\n");
+ sb.append("Response received from server:\n");
+ sb
+
.append("---------------------------------------------------------\n");
+ sb.append(server);
+ sb.append("\nContent of Goldenfile:\n");
+ sb
+
.append("---------------------------------------------------------\n");
+ sb.append(golden);
+ sb.append("\n");
+ resultOut.append(sb.toString());
+ }
+ return status;
+ }
+
+ /**
+ * <code>readBody</code> reads the body of the response from the
+ * InputStream.
+ *
+ * @param input
+ * an <code>InputStream</code>
+ * @return a <code>byte[]</code> representation of the response
+ */
+ private byte[] readBody(InputStream input) {
+ StringBuffer sb = new StringBuffer(255);
+ while (true) {
+ try {
+ int ch = input.read();
+
+ if (ch < 0) {
+ if (sb.length() == 0) {
+ return (null);
+ } else {
+ break;
+ }
+ }
+ sb.append((char) ch);
+
+ } catch (IOException ex) {
+ return null;
+ }
+ }
+ return sb.toString().getBytes();
+ }
+
+ /**
+ * <code>setHeaderDetails</code> Wrapper method for parseHeader. Allows
easy
+ * addition of headers to the specified HashMap
+ *
+ * @param line
+ * a <code>String</code> value
+ * @param headerMap
+ * a <code>HashMap</code> value
+ * @param isRequest
+ * a <code>boolean</code> indicating if the passed Header
HashMap
+ * is for request headers
+ */
+ void setHeaderDetails(String line, HashMap headerHash, boolean isRequest) {
+ StringTokenizer stk = new StringTokenizer(line, "##");
+
+ while (stk.hasMoreElements()) {
+ String presentHeader = stk.nextToken();
+ parseHeader(presentHeader, headerHash, isRequest);
+ }
+ }
+
+ /**
+ * <code>parseHeader</code> parses input headers in format of "key:value"
+ * The parsed header field-name will be used as a key in the passed HashMap
+ * object, and the values found will be stored in an ArrayList associated
+ * with the field-name key.
+ *
+ * @param line
+ * String representation of an HTTP header line.
+ * @param headers
+ * a<code>HashMap</code> to store key/value header objects.
+ * @param isRequest
+ * set to true if the headers being processed are
requestHeaders.
+ */
+ void parseHeader(String line, HashMap headerMap, boolean isRequest) {
+ // Parse the header name and value
+ int colon = line.indexOf(":");
+
+ if (colon < 0) {
+ resultOut
+ .append("\n ERROR: Header is in incorrect format: " +
line);
+ return;
+ }
+
+ String name = line.substring(0, colon).trim();
+ String value = line.substring(colon + 1).trim();
+
+ if ((cookieVector != null) && (name.equalsIgnoreCase("Set-Cookie"))) {
+ cookieVector.addElement(value);
+ /*
+ * if ( ( value.indexOf("JSESSIONID") > -1 ) ||
+ * (value.indexOf("jsessionid") > -1 ) ) { String sessionId=
+ * value.substring( value.indexOf("=")+1); if ( testSession != null
+ * ) { sessionHash.put( testSession, sessionId ); }
+ * System.out.println("Got Session-ID : " + sessionId ); }
+ */
+ }
+
+ // System.out.println("HEADER: " +name + " " + value);
+
+ ArrayList values = (ArrayList) headerMap.get(name);
+ if (values == null) {
+ values = new ArrayList();
+ }
+ // HACK
+ if (value.indexOf(',') > -1 && !isRequest
+ && !name.equalsIgnoreCase("Date")) {
+ StringTokenizer st = new StringTokenizer(value, ",");
+ while (st.hasMoreElements()) {
+ values.add(st.nextToken());
+ }
+ } else {
+ values.add(value);
+ }
+
+ headerMap.put(name, values);
+ }
+
+ /**
+ * <code>dumpHex</code> helper method to dump formatted hex output of the
+ * server response and the goldenfile.
+ *
+ * @param serverResponse
+ * a <code>byte[]</code> value
+ * @param goldenFile
+ * a <code>byte[]</code> value
+ */
+ private void dumpHex(byte[] serverResponse, byte[] goldenFile) {
+ StringBuffer outBuf = new StringBuffer(
+ (serverResponse.length + goldenFile.length) * 2);
+
+ String fromServerString = Hex.getHexDump(serverResponse, 0,
+ serverResponse.length, true);
+ String fromGoldenFileString = Hex.getHexDump(goldenFile, 0,
+ goldenFile.length, true);
+
+ outBuf
+ .append(" Hex dump of server response and goldenfile
below.\n\n### RESPONSE FROM SERVER ###\n");
+ outBuf.append("----------------------------\n");
+ outBuf.append(fromServerString);
+ outBuf.append("\n\n### GOLDEN FILE ###\n");
+ outBuf.append("-------------------\n");
+ outBuf.append(fromGoldenFileString);
+ outBuf.append("\n\n### END OF DUMP ###\n");
+
+ resultOut.append(outBuf.toString());
+
+ }
+
+ /**
+ * <code>cloneHeaders</code> returns a "cloned" HashMap of the map passed
+ * in.
+ *
+ * @param map
+ * a <code>HashMap</code> value
+ * @return a <code>HashMap</code> value
+ */
+ private HashMap cloneHeaders(HashMap map) {
+ HashMap dupMap = new HashMap();
+ Iterator iter = map.keySet().iterator();
+
+ while (iter.hasNext()) {
+ String key = new String((String) iter.next());
+ ArrayList origValues = (ArrayList) map.get(key);
+ ArrayList dupValues = new ArrayList();
+
+ String[] dupVal = (String[]) origValues
+ .toArray(new String[origValues.size()]);
+ for (int i = 0; i < dupVal.length; i++) {
+ dupValues.add(new String(dupVal[i]));
+ }
+
+ dupMap.put(key, dupValues);
+ }
+ return dupMap;
+ }
+
+}
Propchange:
tomcat/trunk/modules/tomcat-lite/test/org/apache/tomcat/test/watchdog/WatchdogTestImpl.java
------------------------------------------------------------------------------
svn:eol-style = native
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]