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