You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by da...@apache.org on 2003/11/26 15:18:38 UTC
cvs commit: james-server/proposals/imap2/test/org/apache/james/test AbstractProtocolTest.java FileProtocolSessionBuilder.java ProtocolSession.java
darrell 2003/11/26 06:18:38
Modified: proposals/imap2 build-test.xml
proposals/imap2/java/org/apache/james/imapserver
ImapSessionImpl.java
proposals/imap2/java/org/apache/james/imapserver/commands
CloseCommand.java ExpungeCommand.java
proposals/imap2/test/org/apache/james/remotemanager
RemoteManagerLogin.test
proposals/imap2/test/org/apache/james/test
AbstractProtocolTest.java
FileProtocolSessionBuilder.java
ProtocolSession.java
Added: proposals/imap2/test/org/apache/james/imapserver
TestConcurrentSessions.java
proposals/imap2/test/org/apache/james/imapserver/concurrent
Concurrent.todo.txt ExistsResponse.test
FetchResponse.test
Log:
- Better in-process protocol testing in Imap: now handles multi-session protocol tests.
- Added a few tests for concurrent mailbox access.
Revision Changes Path
1.7 +9 -0 james-server/proposals/imap2/build-test.xml
Index: build-test.xml
===================================================================
RCS file: /home/cvs/james-server/proposals/imap2/build-test.xml,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- build-test.xml 13 Jul 2003 12:04:29 -0000 1.6
+++ build-test.xml 26 Nov 2003 14:18:37 -0000 1.7
@@ -133,6 +133,7 @@
<test name="org.apache.james.imapserver.TestOtherCommandsInSelectedState"/>
<test name="org.apache.james.imapserver.TestSelectedCommandsInSelectedState"/>
<test name="org.apache.james.imapserver.TestCompound"/>
+ <test name="org.apache.james.imapserver.TestConcurrentSessions"/>
</junit>
</target>
@@ -171,12 +172,20 @@
<test name="org.apache.james.imapserver.TestOtherCommandsInSelectedState"/>
<test name="org.apache.james.imapserver.TestSelectedCommandsInSelectedState"/>
<test name="org.apache.james.imapserver.TestCompound"/>
+ <test name="org.apache.james.imapserver.TestConcurrentSessions"/>
</junit>
</target>
<target name="build-and-test">
<ant antfile="proposals/imap2/build.xml" target="main"/>
<antcall target="unit-tests"/>
+ </target>
+
+ <target name="copytests">
+ <mkdir dir="${build.dir}/tests"/>
+ <copy todir="${build.dir}/tests">
+ <fileset dir="${test.dir}" includes="**/*.test"/>
+ </copy>
</target>
</project>
1.7 +3 -1 james-server/proposals/imap2/java/org/apache/james/imapserver/ImapSessionImpl.java
Index: ImapSessionImpl.java
===================================================================
RCS file: /home/cvs/james-server/proposals/imap2/java/org/apache/james/imapserver/ImapSessionImpl.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- ImapSessionImpl.java 21 Jul 2003 23:31:04 -0000 1.6
+++ ImapSessionImpl.java 26 Nov 2003 14:18:37 -0000 1.7
@@ -177,6 +177,8 @@
public void deselect()
{
this.state = ImapSessionState.AUTHENTICATED;
+ // TODO is there more to do here, to cleanup the mailbox.
+ this.selectedMailbox = null;
}
public void setSelected( ImapMailbox mailbox, boolean readOnly )
1.5 +3 -2 james-server/proposals/imap2/java/org/apache/james/imapserver/commands/CloseCommand.java
Index: CloseCommand.java
===================================================================
RCS file: /home/cvs/james-server/proposals/imap2/java/org/apache/james/imapserver/commands/CloseCommand.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- CloseCommand.java 13 Jul 2003 06:04:56 -0000 1.4
+++ CloseCommand.java 26 Nov 2003 14:18:37 -0000 1.5
@@ -90,7 +90,8 @@
mailbox.expunge();
}
session.deselect();
-
+
+// Don't send unsolicited responses on close.
session.unsolicitedResponses( response );
response.commandComplete( this );
}
1.7 +1 -2 james-server/proposals/imap2/java/org/apache/james/imapserver/commands/ExpungeCommand.java
Index: ExpungeCommand.java
===================================================================
RCS file: /home/cvs/james-server/proposals/imap2/java/org/apache/james/imapserver/commands/ExpungeCommand.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- ExpungeCommand.java 23 Oct 2003 01:55:12 -0000 1.6
+++ ExpungeCommand.java 26 Nov 2003 14:18:37 -0000 1.7
@@ -91,7 +91,6 @@
ImapMailbox mailbox = session.getSelected();
mailbox.expunge();
- System.out.println("here");
session.unsolicitedResponses( response );
response.commandComplete( this );
1.1 james-server/proposals/imap2/test/org/apache/james/imapserver/TestConcurrentSessions.java
Index: TestConcurrentSessions.java
===================================================================
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2003, Wotif.com. All rights reserved.
//
// This is unpublished proprietary source code of Wotif.com.
// The copyright notice above does not evidence any actual or intended
// publication of such source code.
//
////////////////////////////////////////////////////////////////////////////////
package org.apache.james.imapserver;
import org.apache.james.imapserver.TestCommandsInAuthenticatedState;
import junit.framework.Test;
import junit.framework.TestSuite;
/**
* @author <a href="mailto:ddeboer@thoughtworks.com">Darrell DeBoer</a>
* @version $Id: TestConcurrentSessions.java,v 1.1 2003/11/26 14:18:38 darrell Exp $
*/
public class TestConcurrentSessions extends TestCommandsInAuthenticatedState {
public TestConcurrentSessions(String fileName) {
super(fileName);
}
/**
* Runs all tests which verify the behaviour of IMAP under multiple concurrent sessions.
*/
public static Test suite() throws Exception
{
TestSuite suite = new TestSuite();
// Not valid in this state
suite.addTest( new TestConcurrentSessions( "concurrent/FetchResponse" ) );
suite.addTest( new TestConcurrentSessions( "concurrent/ExistsResponse" ) );
return suite;
}
}
1.1 james-server/proposals/imap2/test/org/apache/james/imapserver/concurrent/Concurrent.todo.txt
Index: Concurrent.todo.txt
===================================================================
Simple tests:
1 Send FETCH response when another session performs a STORE against a message
(concurrent/FetchResponse.test)
2 Send EXISTS and RECENT responses when a message is added
(concurrent/ExistsResponse.test) - still need RECENT
3 Expunge response when another session performs a EXPUNGE against the mailbox
From RFC2180
3. Deletion/Renaming of a multi-accessed mailbox
### Need to pick one of these 3...
3.1. The server MAY fail the DELETE/RENAME command of a multi-accessed
mailbox
3.3. The server MAY allow the DELETE/RENAME of a multi-accessed
mailbox, but disconnect all other clients who have the mailbox
accessed by sending a untagged BYE response.
3.4. The server MAY allow the RENAME of a multi-accessed mailbox by
simply changing the name attribute on the mailbox.
-----------------------------------------------------------------------
4.1. Fetching of expunged messages
4.1.2 The server MAY allow the EXPUNGE of a multi-accessed mailbox,
and on subsequent FETCH commands return FETCH responses only for
non-expunged messages and a tagged NO.
C2: B001 FETCH 3:5 ENVELOPE
S2: * 3 FETCH ENVELOPE . . . (ENVELOPE info returned)
S2: B001 NO Some of the requested messages no longer exist
### Return what you can, and send a "no": i like this.
-0---------------------------------------------------------------------
4.2. Storing of expunged messages
4.2.1 If the ".SILENT" suffix is used, and the STORE completed
successfully for all the non-expunged messages, the server SHOULD
return a tagged OK.
4.2.2. If the ".SILENT" suffix is not used, and only expunged messages
are referenced, the server SHOULD return only a tagged NO.
4.2.3. If the ".SILENT" suffix is not used, and a mixture of expunged
and non-expunged messages are referenced, the server MAY set the
flags and return a FETCH response for the non-expunged messages
along with a tagged NO.
### Update what you can, and return "NO"
4.2.4. If the ".SILENT" suffix is not used, and a mixture of expunged
and non-expunged messages are referenced, the server MAY return
an untagged NO and not set any flags.
### Don't update anything, and return "NO"
1.1 james-server/proposals/imap2/test/org/apache/james/imapserver/concurrent/ExistsResponse.test
Index: ExistsResponse.test
===================================================================
# Tests that appending a message from one session triggers an EXISTS response
# in a concurrent session on the same mailbox
# TODO:
# a) Check sending of EXISTS response when using other selected state commands.
# eg FETCH, STORE, COPY...
# b) Check sending of EXISTS response when using other non-selected state commands
# eg CREATE, APPEND...
# c) Get RECENT working
SESSION: 1
C: 1a CREATE existsresponse
S: 1a OK CREATE completed.
C: 1b STATUS existsresponse (MESSAGES)
S: \* STATUS existsresponse \(MESSAGES 0\)
S: 1b OK STATUS completed
SESSION: 2
C: 2a SELECT existsresponse
S: \* FLAGS \(\\Answered \\Deleted \\Draft \\Flagged \\Seen\)
S: \* 0 EXISTS
S: \* 0 RECENT
S: \* OK \[UIDVALIDITY \d+\]
S: \* OK No messages unseen
S: \* OK \[PERMANENTFLAGS \(\\Answered \\Deleted \\Draft \\Flagged \\Seen\)\]
S: 2a OK \[READ-WRITE\] SELECT completed
SESSION: 1
C: 1c APPEND existsresponse (\Deleted) {310+}
C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
C: From: Fred Foobar <fo...@Blurdybloop.COM>
C: Subject: afternoon meeting
C: To: mooch@owatagu.siam.edu
C: Message-Id: <B2...@Blurdybloop.COM>
C: MIME-Version: 1.0
C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
C:
C: Hello Joe, do you think we can meet at 3:30 tomorrow?
C:
S: 1c OK APPEND completed
SESSION: 2
C: 2b NOOP
S: \* 1 EXISTS
#S: \* 1 RECENT
S: 2b OK NOOP completed
C: 2c DELETE existsresponse
S: 2c OK DELETE completed
1.1 james-server/proposals/imap2/test/org/apache/james/imapserver/concurrent/FetchResponse.test
Index: FetchResponse.test
===================================================================
# Tests that updates made by one session trigger a fetch response
# in a concurrent session on the same mailbox
# TODO: Check sending of fetch responses when using other selected state commands.
# eg FETCH, STORE, COPY...
SESSION: 1
C: 1a CREATE multibox
S: 1a OK CREATE completed.
C: 1b STATUS multibox (MESSAGES)
S: \* STATUS multibox \(MESSAGES 0\)
S: 1b OK STATUS completed
C: 1c APPEND multibox (\Deleted) {310+}
C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
C: From: Fred Foobar <fo...@Blurdybloop.COM>
C: Subject: afternoon meeting
C: To: mooch@owatagu.siam.edu
C: Message-Id: <B2...@Blurdybloop.COM>
C: MIME-Version: 1.0
C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
C:
C: Hello Joe, do you think we can meet at 3:30 tomorrow?
C:
S: 1c OK APPEND completed
C: 1d SELECT multibox
S: \* FLAGS \(\\Answered \\Deleted \\Draft \\Flagged \\Seen\)
S: \* 1 EXISTS
S: \* \d+ RECENT
S: \* OK \[UIDVALIDITY \d+\]
S: \* OK \[UNSEEN 1\] Message 1 is the first unseen
S: \* OK \[PERMANENTFLAGS \(\\Answered \\Deleted \\Draft \\Flagged \\Seen\)\]
S: 1d OK \[READ-WRITE\] SELECT completed
SESSION: 2
C: 2a SELECT multibox
S: \* FLAGS \(\\Answered \\Deleted \\Draft \\Flagged \\Seen\)
S: \* 1 EXISTS
S: \* \d+ RECENT
S: \* OK \[UIDVALIDITY \d+\]
S: \* OK \[UNSEEN 1\] Message 1 is the first unseen
S: \* OK \[PERMANENTFLAGS \(\\Answered \\Deleted \\Draft \\Flagged \\Seen\)\]
S: 2a OK \[READ-WRITE\] SELECT completed
SESSION: 1
C: 1e STORE 1 FLAGS (\Deleted)
S: \* 1 FETCH \(FLAGS \(\\Deleted\)\)
S: 1e OK STORE completed
# On NOOP, we get the Fetch Response from the Session1 update.
SESSION: 2
C: 2b NOOP
S: \* 1 FETCH \(FLAGS \(\\Deleted\)\)
S: 2b OK NOOP completed
C: 2c CLOSE
S: 2c OK CLOSE completed
SESSION: 1
C: 1f CLOSE
S: 1f OK CLOSE completed
C: 1g DELETE multibox
S: 1g OK DELETE completed
1.2 +1 -1 james-server/proposals/imap2/test/org/apache/james/remotemanager/RemoteManagerLogin.test
Index: RemoteManagerLogin.test
===================================================================
RCS file: /home/cvs/james-server/proposals/imap2/test/org/apache/james/remotemanager/RemoteManagerLogin.test,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- RemoteManagerLogin.test 22 Nov 2002 02:09:54 -0000 1.1
+++ RemoteManagerLogin.test 26 Nov 2003 14:18:38 -0000 1.2
@@ -1,4 +1,4 @@
-S: JAMES Remote Administration Tool 2.1a1-cvs
+S: JAMES Remote Administration Tool .*
S: Please enter your login and password
S: Login id:
C: root
1.8 +123 -37 james-server/proposals/imap2/test/org/apache/james/test/AbstractProtocolTest.java
Index: AbstractProtocolTest.java
===================================================================
RCS file: /home/cvs/james-server/proposals/imap2/test/org/apache/james/test/AbstractProtocolTest.java,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- AbstractProtocolTest.java 8 Mar 2003 21:13:58 -0000 1.7
+++ AbstractProtocolTest.java 26 Nov 2003 14:18:38 -0000 1.8
@@ -65,6 +65,7 @@
import org.apache.james.imapserver.ImapSessionImpl;
import org.apache.james.imapserver.ImapTest;
import org.apache.james.imapserver.JamesImapHost;
+import org.apache.james.imapserver.ProtocolException;
import org.apache.james.imapserver.store.MailboxException;
import org.apache.james.userrepository.AbstractUsersRepository;
import org.apache.james.userrepository.DefaultUser;
@@ -79,6 +80,10 @@
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
+import java.io.IOException;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.io.OutputStream;
import java.net.Socket;
import java.util.HashMap;
import java.util.Iterator;
@@ -151,11 +156,17 @@
private void runSocketProtocolSessions()
throws Exception
{
- Socket socket = new Socket( host, port );
- socket.setSoTimeout( timeout );
+ Socket[] socket = new Socket[testElements.getSessionCount()];
+ PrintWriter[] out = new PrintWriter[socket.length];
+ BufferedReader[] in = new BufferedReader[socket.length];
+
+ for (int i = 0; i < socket.length; i++) {
+ socket[i] = new Socket(host, port);
+ socket[i].setSoTimeout(timeout);
+ out[i] = new PrintWriter(socket[i].getOutputStream());
+ in[i] = new BufferedReader(new InputStreamReader(socket[i].getInputStream()));
+ }
- PrintWriter out = new PrintWriter( socket.getOutputStream(), true );
- BufferedReader in = new BufferedReader( new InputStreamReader( socket.getInputStream() ) );
try {
preElements.runLiveSession( out, in );
testElements.runLiveSession( out, in );
@@ -165,9 +176,11 @@
fail( e.getMessage() );
}
- out.close();
- in.close();
- socket.close();
+ for (int i = 0; i < socket.length; i++) {
+ out[i].close();
+ in[i].close();
+ socket[i].close();
+ }
}
/**
@@ -175,42 +188,39 @@
* This does not require that James be running, and is useful for rapid development and
* debugging.
*
- * Instead of sending requests to a socket, requests are written to a CharArrayWriter,
- * which then constructs a Reader which can be given to the ImapRequestHandler.
- * Likewise, server responses are written to a CHarArrayWriter, and the associate reader
- * is parsed to ensure that the responses match those expected.
+ * Instead of sending requests to a socket connected to a running instance of James,
+ * this method uses the {@link MockImapServer} to simplify testing. One mock instance
+ * is required per protocol session/connection. These share the same underlying
+ * Mailboxes, because of the way {@link #getImapSession()} works.
*/
private void runLocalProtocolSessions() throws Exception
{
- ByteArrayOutputStream clientRequestCollector = new ByteArrayOutputStream();
- PrintWriter clientOut = new PrintWriter( clientRequestCollector );
- preElements.writeClient( clientOut );
- testElements.writeClient( clientOut );
- postElements.writeClient( clientOut );
-
- InputStream clientIn = new ByteArrayInputStream( clientRequestCollector.toByteArray() );
- clientRequestCollector.close();
-
- ByteArrayOutputStream serverResponseCollector = new ByteArrayOutputStream();
- serverResponseCollector.write( "* OK IMAP4rev1 Server XXX ready".getBytes() );
- serverResponseCollector.write( '\r' );
- serverResponseCollector.write( '\n' );
-
- ImapSession session = getImapSession();
- ImapRequestHandler requestHandler = new ImapRequestHandler();
- while( requestHandler.handleRequest( clientIn, serverResponseCollector, session ) ) {};
-
- InputStream serverInstream = new ByteArrayInputStream( serverResponseCollector.toByteArray() );
- BufferedReader serverIn = new BufferedReader( new InputStreamReader( serverInstream ) );
+ MockImapServer[] socket = new MockImapServer[testElements.getSessionCount()];
+ PrintWriter[] out = new PrintWriter[socket.length];
+ BufferedReader[] in = new BufferedReader[socket.length];
+
+ for (int i = 0; i < socket.length; i++) {
+ socket[i] = new MockImapServer(getImapSession());
+ out[i] = socket[i].getWriter();
+ in[i] = socket[i].getReader();
+ socket[i].start();
+ }
try {
- preElements.testResponse( serverIn );
- testElements.testResponse( serverIn );
- postElements.testResponse( serverIn );
- }
- catch ( ProtocolSession.InvalidServerResponseException e ) {
- fail( e.getMessage() );
+ preElements.runLiveSession( out, in );
+ testElements.runLiveSession( out, in );
+ postElements.runLiveSession( out, in );
+ }
+ catch ( ProtocolSession.InvalidServerResponseException e ) {
+ fail( e.getMessage() );
+ }
+
+ for (int i = 0; i < socket.length; i++) {
+ out[i].close();
+ in[i].close();
+ socket[i].stopServer();
}
+
}
/**
@@ -266,6 +276,82 @@
protected void doUpdateUser( User user )
{
users.put( user.getUserName(), user );
+ }
+ }
+
+ /**
+ * A simple test utility which allows testing of Imap commands without
+ * deployment of the full server. Piped input and output streams are used
+ * to provide the equivilant of a socket interface.
+ */
+ private class MockImapServer extends Thread {
+ private ImapRequestHandler handler = new ImapRequestHandler();
+
+ private PipedInputStream requestInputStream;
+ private PipedOutputStream requestOutputStream;
+
+ private PipedInputStream responseInputStream;
+ private PipedOutputStream responseOutputStream;
+
+ private ImapSession session;
+ private ProtocolException exception;
+
+ private boolean running;
+
+ /**
+ * Creates a MockImapServer, with a handler for the session provided.
+ */
+ public MockImapServer(ImapSession session) throws IOException {
+ this.session = session;
+ requestOutputStream = new PipedOutputStream();
+ requestInputStream = new PipedInputStream(requestOutputStream);
+
+ responseInputStream = new PipedInputStream();
+ responseOutputStream = new PipedOutputStream(responseInputStream);
+
+ }
+
+ /**
+ * Core loop where Imap commands are handled
+ */
+ public void run() {
+ running = true;
+ try {
+ responseOutputStream.write( "* OK IMAP4rev1 Server XXX ready".getBytes() );
+ responseOutputStream.write( '\r' );
+ responseOutputStream.write( '\n' );
+ } catch (IOException e) {
+ throw new RuntimeException("Couldn't write welcome message", e);
+ }
+
+ while (running) {
+ try {
+ handler.handleRequest(requestInputStream, responseOutputStream, session);
+ } catch (ProtocolException e) {
+ exception = e;
+ break;
+ }
+ }
+
+ }
+
+ /**
+ * @return A writer which is used to send commands to the mock server.
+ */
+ public PrintWriter getWriter() {
+ return new PrintWriter(requestOutputStream);
+ }
+
+ /**
+ * @return A reader which is used to read responses from the mock server.
+ */
+ public BufferedReader getReader() {
+ return new BufferedReader(new InputStreamReader(responseInputStream));
+ }
+
+ /** stop the running server thread.*/
+ public void stopServer() {
+ running = false;
}
}
}
1.7 +14 -5 james-server/proposals/imap2/test/org/apache/james/test/FileProtocolSessionBuilder.java
Index: FileProtocolSessionBuilder.java
===================================================================
RCS file: /home/cvs/james-server/proposals/imap2/test/org/apache/james/test/FileProtocolSessionBuilder.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- FileProtocolSessionBuilder.java 8 Mar 2003 21:13:58 -0000 1.6
+++ FileProtocolSessionBuilder.java 26 Nov 2003 14:18:38 -0000 1.7
@@ -78,6 +78,7 @@
private static final String OPEN_UNORDERED_BLOCK_TAG = "SUB {";
private static final String CLOSE_UNORDERED_BLOCK_TAG = "}";
private static final String COMMENT_TAG = "#";
+ private static final String SESSION_TAG = "SESSION:";
/**
* Builds a ProtocolSession by reading lines from the test file
@@ -122,9 +123,10 @@
String fileName )
throws Exception
{
+ int sessionNumber = -1;
BufferedReader reader = new BufferedReader( new InputStreamReader( is ) );
String next;
- int lineNumber = 1;
+ int lineNumber = -1;
while ( ( next = reader.readLine() ) != null ) {
String location = fileName + ":" + lineNumber;
if ( next.startsWith( CLIENT_TAG ) ) {
@@ -132,14 +134,14 @@
if ( next.length() > 3 ) {
clientMsg = next.substring( 3 );
}
- session.CL( clientMsg );
+ session.CL( sessionNumber, clientMsg );
}
else if ( next.startsWith( SERVER_TAG ) ) {
String serverMsg = "";
if ( next.length() > 3 ) {
serverMsg = next.substring( 3 );
}
- session.SL( serverMsg, location );
+ session.SL( sessionNumber, serverMsg, location );
}
else if ( next.startsWith( OPEN_UNORDERED_BLOCK_TAG ) ) {
List unorderedLines = new ArrayList( 5 );
@@ -155,11 +157,18 @@
lineNumber++;
}
- session.SUB( unorderedLines, location );
+ session.SUB( sessionNumber, unorderedLines, location );
}
else if ( next.startsWith( COMMENT_TAG )
|| next.trim().length() == 0 ) {
// ignore these lines.
+ }
+ else if ( next.startsWith(SESSION_TAG)) {
+ String number = next.substring(SESSION_TAG.length()).trim();
+ if (number.length() == 0) {
+ throw new Exception("No session number specified");
+ }
+ sessionNumber = Integer.parseInt(number);
}
else {
String prefix = next;
1.7 +140 -86 james-server/proposals/imap2/test/org/apache/james/test/ProtocolSession.java
Index: ProtocolSession.java
===================================================================
RCS file: /home/cvs/james-server/proposals/imap2/test/org/apache/james/test/ProtocolSession.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- ProtocolSession.java 8 Mar 2003 21:13:58 -0000 1.6
+++ ProtocolSession.java 26 Nov 2003 14:18:38 -0000 1.7
@@ -78,19 +78,29 @@
*/
public class ProtocolSession
{
+ private int maxSessionNumber;
protected List testElements = new ArrayList();
private static final Perl5Util perl = new Perl5Util();
/**
- * Executes the ProtocolSession in real time against the reader and writer
+ * 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.
+ * 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 runLiveSession( PrintWriter out, BufferedReader in ) throws Exception
- {
+ public void runLiveSession(PrintWriter[] out, BufferedReader[] in) throws InvalidServerResponseException {
for ( Iterator iter = testElements.iterator(); iter.hasNext(); ) {
Object obj = iter.next();
if ( obj instanceof ProtocolElement ) {
@@ -101,70 +111,54 @@
}
/**
- * Write an entire client session to the specified PrintWriter. Server
- * responses are not collected, but clients may collect themfor later
- * testing with {@link #testResponse}.
- * @param out The client requests are written to here.
+ * adds a new Client request line to the test elements
*/
- public void writeClient( PrintWriter out ) throws Exception
+ public void CL( String clientLine )
{
- Iterator iterator = testElements.iterator();
- while ( iterator.hasNext() ) {
- ProtocolElement element = (ProtocolElement) iterator.next();
- if ( element instanceof ClientRequest ) {
- element.testProtocol( out, null );
- }
- }
+ testElements.add( new ClientRequest( clientLine ) );
}
/**
- * Reads Server responses from the supplied Buffered reader, ensuring that
- * they match the expected responses for the protocol session. This permits
- * clients to run a session asynchronously, by first writing the client requests
- * with {@link #writeClient} and later testing the responses.
- * @param in The server responses are read from here.
+ * adds a new Server Response line to the test elements, with the specified location.
*/
- public void testResponse( BufferedReader in ) throws Exception
+ public void SL( String serverLine, String location )
{
- Iterator iterator = testElements.iterator();
- while ( iterator.hasNext() ) {
- ProtocolElement element = (ProtocolElement) iterator.next();
- if ( element instanceof ServerResponse ) {
- element.testProtocol( null, in );
- }
- }
+ testElements.add( new ServerResponse( serverLine, location ) );
}
/**
- * adds a new Client request line to the test elements
+ * adds a new Server Unordered Block to the test elements.
*/
- public void CL( String clientLine )
+ public void SUB( List serverLines, String location )
{
- testElements.add( new ClientRequest( clientLine ) );
+ testElements.add( new ServerUnorderedBlockResponse( serverLines, location ) );
}
/**
- * adds a new Server Response line to the test elements, with the specified location.
+ * adds a new Client request line to the test elements
*/
- public void SL( String serverLine, String location )
+ public void CL( int sessionNumber, String clientLine )
{
- testElements.add( new ServerResponse( serverLine, location ) );
+ this.maxSessionNumber = Math.max(this.maxSessionNumber, sessionNumber);
+ testElements.add( new ClientRequest( sessionNumber, clientLine ) );
}
/**
- * adds a new Server Unordered Block to the test elements.
+ * adds a new Server Response line to the test elements, with the specified location.
*/
- public void SUB( List serverLines, String location )
+ public void SL( int sessionNumber, String serverLine, String location )
{
- testElements.add( new ServerUnorderedBlockResponse( serverLines, location ) );
+ this.maxSessionNumber = Math.max(this.maxSessionNumber, sessionNumber);
+ testElements.add( new ServerResponse( sessionNumber, serverLine, location ) );
}
/**
- * Adds a ProtocolElement to the test elements.
+ * adds a new Server Unordered Block to the test elements.
*/
- public void addProtocolElement( ProtocolElement element )
+ public void SUB( int sessionNumber, List serverLines, String location )
{
- testElements.add( element );
+ this.maxSessionNumber = Math.max(this.maxSessionNumber, sessionNumber);
+ testElements.add( new ServerUnorderedBlockResponse( sessionNumber, serverLines, location ) );
}
/**
@@ -172,6 +166,7 @@
*/
private class ClientRequest implements ProtocolElement
{
+ private int sessionNumber;
private String message;
/**
@@ -179,18 +174,43 @@
*/
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 PrintWriter.
+ * 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.
*/
- public void testProtocol( PrintWriter out, BufferedReader in )
+ public void testProtocol( PrintWriter[] out, BufferedReader[] in )
{
- out.write( message );
- out.write( '\r' );
- out.write( '\n' );
- out.flush();
+ if (sessionNumber < 0) {
+ for (int i = 0; i < out.length; i++) {
+ PrintWriter printWriter = out[i];
+ writeMessage(printWriter);
+ }
+ }
+ else {
+ PrintWriter writer = out[sessionNumber];
+ writeMessage(writer);
+ }
+ }
+
+ private void writeMessage(PrintWriter writer) {
+ writer.write(message);
+ writer.write('\r');
+ writer.write('\n');
+ writer.flush();
}
}
@@ -201,6 +221,7 @@
*/
private class ServerResponse implements ProtocolElement
{
+ private int sessionNumber;
private String expectedLine;
protected String location;
@@ -212,22 +233,49 @@
*/
public ServerResponse( String expectedPattern, String location )
{
+ this(-1, expectedPattern, location);
+ }
+
+ /**
+ * 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 )
+ {
+ this.sessionNumber = sessionNumber;
this.expectedLine = expectedPattern;
this.location = location;
}
/**
* Reads a line from the supplied reader, and tests that it matches
- * the expected regular expression.
+ * 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( PrintWriter out, BufferedReader in )
+ public void testProtocol( PrintWriter[] out, BufferedReader[] in )
throws InvalidServerResponseException
{
- String testLine = readLine( in );
+ if (sessionNumber < 0) {
+ for (int i = 0; i < in.length; i++) {
+ BufferedReader reader = in[i];
+ checkResponse(reader);
+ }
+ }
+ else {
+ BufferedReader reader = in[sessionNumber];
+ checkResponse(reader);
+ }
+ }
+
+ protected void checkResponse(BufferedReader reader) throws InvalidServerResponseException {
+ String testLine = readLine(reader);
if ( ! match( expectedLine, testLine ) ) {
String errMsg = "\nLocation: " + location +
"\nExcpected: " + expectedLine +
@@ -260,12 +308,11 @@
{
try {
return in.readLine();
- }
- catch ( IOException e ) {
+ } catch (IOException e) {
String errMsg = "\nLocation: " + location +
- "\nExpected: " + expectedLine +
- "\nReason: Server Timeout.";
- throw new InvalidServerResponseException( errMsg );
+ "\nExpected: " + expectedLine +
+ "\nReason: Server Timeout.";
+ throw new InvalidServerResponseException(errMsg);
}
}
}
@@ -286,7 +333,21 @@
*/
public ServerUnorderedBlockResponse( List expectedLines, String location )
{
- super( "<Unordered Block>", location );
+ this(-1, expectedLines, location);
+ }
+
+ /**
+ * 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 )
+ {
+ super( sessionNumber, "<Unordered Block>", location );
this.expectedLines = expectedLines;
}
@@ -294,46 +355,39 @@
* 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 out Is ignored.
- * @param in Server responses are read from here.
+ * @param reader Server responses are read from here.
* @throws InvalidServerResponseException If a line is encountered which doesn't
* match one of the expected lines.
*/
- public void testProtocol( PrintWriter out, BufferedReader in )
- throws InvalidServerResponseException
- {
- List testLines = new ArrayList( expectedLines );
- while ( testLines.size() > 0 )
- {
- String actualLine = readLine( in );
- boolean foundMatch = false;
+ protected void checkResponse(BufferedReader reader) throws InvalidServerResponseException {
+ List testLines = new ArrayList(expectedLines);
+ while (testLines.size() > 0) {
+ String actualLine = readLine(reader);
- for ( int i = 0; i < testLines.size(); i++ )
- {
- String expected = (String)testLines.get( i );
- if ( match( expected, actualLine ))
- {
+ 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 );
+ testLines.remove(expected);
break;
}
}
- if (! foundMatch )
- {
+ if (!foundMatch) {
StringBuffer errMsg = new StringBuffer()
- .append( "\nLocation: " )
- .append( location )
- .append( "\nExpected one of: " );
+ .append("\nLocation: ")
+ .append(location)
+ .append("\nExpected one of: ");
Iterator iter = expectedLines.iterator();
- while ( iter.hasNext() ) {
- errMsg.append( "\n " );
- errMsg.append( iter.next() );
+ while (iter.hasNext()) {
+ errMsg.append("\n ");
+ errMsg.append(iter.next());
}
- errMsg.append("\nActual: " )
- .append( actualLine );
+ errMsg.append("\nActual: ")
+ .append(actualLine);
- throw new InvalidServerResponseException( errMsg.toString() );
+ throw new InvalidServerResponseException(errMsg.toString());
}
}
}
@@ -344,7 +398,7 @@
* read responses from the server, or both. Implementations should test the server
* response against an expected response, and throw an exception on mismatch.
*/
- interface ProtocolElement
+ private interface ProtocolElement
{
/**
* Executes the ProtocolElement against the supplied read and writer.
@@ -353,7 +407,7 @@
* @throws InvalidServerResponseException If the actual server response
* doesn't match the one expected.
*/
- void testProtocol( PrintWriter out, BufferedReader in )
+ void testProtocol( PrintWriter[] out, BufferedReader[] in )
throws InvalidServerResponseException;
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org