Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/****************************************************************
* 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. *
****************************************************************/
package org.apache.james.test.functional;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
/**
* A protocol session which can be run against a reader and writer, which checks
* the server response against the expected values. TODO make ProtocolSession
* itself be a permissible ProtocolElement, so that we can nest and reuse
* sessions.
*
* @author Darrell DeBoer
*
* @version $Revision: 898100 $
*/
public class ProtocolSession {
private boolean continued = false;
private boolean continuationExpected = false;
private int maxSessionNumber;
protected List testElements = new ArrayList();
private Iterator elementsIterator;
private HostSystem.Session[] sessions;
private ProtocolElement nextTest;
private boolean continueAfterFailure = false;
public final boolean isContinueAfterFailure() {
return continueAfterFailure;
}
public final void setContinueAfterFailure(boolean continueAfterFailure) {
this.continueAfterFailure = continueAfterFailure;
}
/**
* Returns the number of sessions required to run this ProtocolSession. If
* the number of readers and writers provided is less than this number, an
* exception will occur when running the tests.
*/
public int getSessionCount() {
return maxSessionNumber + 1;
}
/**
* Executes the ProtocolSession in real time against the readers and writers
* supplied, writing client requests and reading server responses in the
* order that they appear in the test elements. The index of a reader/writer
* in the array corresponds to the number of the session. If an exception
* occurs, no more test elements are executed.
*
* @param out
* The client requests are written to here.
* @param in
* The server responses are read from here.
*/
public void runSessions(HostSystem.Session[] sessions) throws Exception {
this.sessions = sessions;
elementsIterator = testElements.iterator();
while (elementsIterator.hasNext()) {
Object obj = elementsIterator.next();
if (obj instanceof ProtocolElement) {
ProtocolElement test = (ProtocolElement) obj;
test.testProtocol(sessions, continueAfterFailure);
}
}
}
public void doContinue() {
try {
if (continuationExpected) {
continued = true;
while (elementsIterator.hasNext()) {
Object obj = elementsIterator.next();
if (obj instanceof ProtocolElement) {
nextTest = (ProtocolElement) obj;
if (!nextTest.isClient()) {
break;
}
nextTest.testProtocol(sessions, continueAfterFailure);
}
}
if (!elementsIterator.hasNext()) {
nextTest = null;
}
} else {
throw new RuntimeException("Unexpected continuation");
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* adds a new Client request line to the test elements
*/
public void CL(String clientLine) {
testElements.add(new ClientRequest(clientLine));
}
/**
* adds a new Server Response line to the test elements, with the specified
* location.
*/
public void SL(String serverLine, String location) {
testElements.add(new ServerResponse(serverLine, location));
}
/**
* adds a new Server Unordered Block to the test elements.
*/
public void SUB(List serverLines, String location) {
testElements
.add(new ServerUnorderedBlockResponse(serverLines, location));
}
/**
* adds a new Client request line to the test elements
*/
public void CL(int sessionNumber, String clientLine) {
this.maxSessionNumber = Math.max(this.maxSessionNumber, sessionNumber);
testElements.add(new ClientRequest(sessionNumber, clientLine));
}
/**
* Adds a continuation. To allow one thread to be used for testing.
*/
public void CONT(int sessionNumber) throws Exception {
this.maxSessionNumber = Math.max(this.maxSessionNumber, sessionNumber);
testElements.add(new ContinuationElement(sessionNumber));
}
/**
* adds a new Server Response line to the test elements, with the specified
* location.
*/
public void SL(int sessionNumber, String serverLine, String location,
String lastClientMessage) {
this.maxSessionNumber = Math.max(this.maxSessionNumber, sessionNumber);
testElements.add(new ServerResponse(sessionNumber, serverLine,
location, lastClientMessage));
}
/**
* adds a new Server Unordered Block to the test elements.
*/
public void SUB(int sessionNumber, List serverLines, String location,
String lastClientMessage) {
this.maxSessionNumber = Math.max(this.maxSessionNumber, sessionNumber);
testElements.add(new ServerUnorderedBlockResponse(sessionNumber,
serverLines, location, lastClientMessage));
}
/**
* A client request, which write the specified message to a Writer.
*/
private class ClientRequest implements ProtocolElement {
private int sessionNumber;
private String message;
/**
* Initialises the ClientRequest with the supplied message.
*/
public ClientRequest(String message) {
this(-1, message);
}
/**
* Initialises the ClientRequest, with a message and session number.
*
* @param sessionNumber
* @param message
*/
public ClientRequest(int sessionNumber, String message) {
this.sessionNumber = sessionNumber;
this.message = message;
}
/**
* Writes the request message to the PrintWriters. If the sessionNumber ==
* -1, the request is written to *all* supplied writers, otherwise, only
* the writer for this session is writted to.
*
* @throws Exception
*/
public void testProtocol(HostSystem.Session[] sessions,
boolean continueAfterFailure) throws Exception {
if (sessionNumber < 0) {
for (int i = 0; i < sessions.length; i++) {
HostSystem.Session session = sessions[i];
writeMessage(session);
}
} else {
HostSystem.Session session = sessions[sessionNumber];
writeMessage(session);
}
}
private void writeMessage(HostSystem.Session session) throws Exception {
session.writeLine(message);
}
public boolean isClient() {
return true;
}
}
/**
* Represents a single-line server response, which reads a line from a
* reader, and compares it with the defined regular expression definition of
* this line.
*/
private class ServerResponse implements ProtocolElement {
private String lastClientMessage;
private int sessionNumber;
private String expectedLine;
protected String location;
/**
* Sets up a server response.
*
* @param expectedPattern
* A Perl regular expression pattern used to test the line
* recieved.
* @param location
* A descriptive value to use in error messages.
*/
public ServerResponse(String expectedPattern, String location) {
this(-1, expectedPattern, location, null);
}
/**
* Sets up a server response.
*
* @param sessionNumber
* The number of session for a multi-session test
* @param expectedPattern
* A Perl regular expression pattern used to test the line
* recieved.
* @param location
* A descriptive value to use in error messages.
*/
public ServerResponse(int sessionNumber, String expectedPattern,
String location, String lastClientMessage) {
this.sessionNumber = sessionNumber;
this.expectedLine = expectedPattern;
this.location = location;
this.lastClientMessage = lastClientMessage;
}
/**
* Reads a line from the supplied reader, and tests that it matches the
* expected regular expression. If the sessionNumber == -1, then all
* readers are tested, otherwise, only the reader for this session is
* tested.
*
* @param out
* Is ignored.
* @param in
* The server response is read from here.
* @throws InvalidServerResponseException
* If the actual server response didn't match the regular
* expression expected.
*/
public void testProtocol(HostSystem.Session[] sessions,
boolean continueAfterFailure) throws Exception {
if (sessionNumber < 0) {
for (int i = 0; i < sessions.length; i++) {
HostSystem.Session session = sessions[i];
checkResponse(session, continueAfterFailure);
}
} else {
HostSystem.Session session = sessions[sessionNumber];
checkResponse(session, continueAfterFailure);
}
}
protected void checkResponse(HostSystem.Session session,
boolean continueAfterFailure) throws Exception {
String testLine = readLine(session);
if (!match(expectedLine, testLine)) {
String errMsg = "\nLocation: " + location + "\nLastClientMsg: "
+ lastClientMessage + "\nExpected: '" + expectedLine
+ "'\nActual : '" + testLine + "'";
if (continueAfterFailure) {
System.out.println(errMsg);
} else {
throw new InvalidServerResponseException(errMsg);
}
}
}
/**
* A convenience method which returns true if the actual string matches
* the expected regular expression.
*
* @param expected
* The regular expression used for matching.
* @param actual
* The actual message to match.
* @return true if the actual matches the expected.
*/
protected boolean match(String expected, String actual) {
final boolean result = Pattern.matches(expected, actual);
return result;
}
/**
* Grabs a line from the server and throws an error message if it
* doesn't work out
*
* @return String of the line from the server
*/
protected String readLine(HostSystem.Session session) throws Exception {
try {
return session.readLine();
} catch (IOException e) {
String errMsg = "\nLocation: " + location + "\nExpected: "
+ expectedLine + "\nReason: Server Timeout.";
throw new InvalidServerResponseException(errMsg);
}
}
public boolean isClient() {
return false;
}
}
/**
* Represents a set of lines which must be recieved from the server, in a
* non-specified order.
*/
private class ServerUnorderedBlockResponse extends ServerResponse {
private List expectedLines = new ArrayList();
/**
* Sets up a ServerUnorderedBlockResponse with the list of expected
* lines.
*
* @param expectedLines
* A list containing a reqular expression for each expected
* line.
* @param location
* A descriptive location string for error messages.
*/
public ServerUnorderedBlockResponse(List expectedLines, String location) {
this(-1, expectedLines, location, null);
}
/**
* Sets up a ServerUnorderedBlockResponse with the list of expected
* lines.
*
* @param sessionNumber
* The number of the session to expect this block, for a
* multi-session test.
* @param expectedLines
* A list containing a reqular expression for each expected
* line.
* @param location
* A descriptive location string for error messages.
*/
public ServerUnorderedBlockResponse(int sessionNumber,
List expectedLines, String location, String lastClientMessage) {
super(sessionNumber, "", location,
lastClientMessage);
this.expectedLines = expectedLines;
}
/**
* Reads lines from the server response and matches them against the
* list of expected regular expressions. Each regular expression in the
* expected list must be matched by only one server response line.
*
* @param reader
* Server responses are read from here.
* @throws InvalidServerResponseException
* If a line is encountered which doesn't match one of the
* expected lines.
*/
protected void checkResponse(HostSystem.Session session,
boolean continueAfterFailure) throws Exception {
List testLines = new ArrayList(expectedLines);
while (testLines.size() > 0) {
String actualLine = readLine(session);
boolean foundMatch = false;
for (int i = 0; i < testLines.size(); i++) {
String expected = (String) testLines.get(i);
if (match(expected, actualLine)) {
foundMatch = true;
testLines.remove(expected);
break;
}
}
if (!foundMatch) {
StringBuffer errMsg = new StringBuffer().append(
"\nLocation: ").append(location).append(
"\nExpected one of: ");
Iterator iter = expectedLines.iterator();
while (iter.hasNext()) {
errMsg.append("\n ");
errMsg.append(iter.next());
}
errMsg.append("\nActual: ").append(actualLine);
if (continueAfterFailure) {
System.out.println(errMsg.toString());
} else {
throw new InvalidServerResponseException(errMsg
.toString());
}
}
}
}
}
private class ContinuationElement implements ProtocolElement {
private final int sessionNumber;
public ContinuationElement(final int sessionNumber) throws Exception {
this.sessionNumber = sessionNumber < 0 ? 0 : sessionNumber;
}
public void testProtocol(HostSystem.Session[] sessions,
boolean continueAfterFailure) throws Exception {
HostSystem.Session session = sessions[sessionNumber];
continuationExpected = true;
continued = false;
String testLine = session.readLine();
if (!"+".equals(testLine) || !continued) {
final String message = "Expected continuation";
if (continueAfterFailure) {
System.out.print(message);
} else {
throw new InvalidServerResponseException(message);
}
}
continuationExpected = false;
continued = false;
if (nextTest != null) {
nextTest.testProtocol(sessions, continueAfterFailure);
}
}
public boolean isClient() {
return false;
}
}
/**
* Represents a generic protocol element, which may write requests to the
* server, read responses from the server, or both. Implementations should
* test the server response against an expected response, and throw an
* exception on mismatch.
*/
private interface ProtocolElement {
/**
* Executes the ProtocolElement against the supplied session.
*
* @param continueAfterFailure
* TODO
* @throws Exception
*/
void testProtocol(HostSystem.Session[] sessions,
boolean continueAfterFailure) throws Exception;
boolean isClient();
}
/**
* An exception which is thrown when the actual response from a server is
* different from that expected.
*/
@SuppressWarnings("serial")
public class InvalidServerResponseException extends Exception {
public InvalidServerResponseException(String message) {
super(message);
}
}
}