KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > james > test > AbstractProtocolTest


1 /***********************************************************************
2  * Copyright (c) 2000-2004 The Apache Software Foundation. *
3  * All rights reserved. *
4  * ------------------------------------------------------------------- *
5  * Licensed under the Apache License, Version 2.0 (the "License"); you *
6  * may not use this file except in compliance with the License. You *
7  * may obtain a copy of the License at: *
8  * *
9  * http://www.apache.org/licenses/LICENSE-2.0 *
10  * *
11  * Unless required by applicable law or agreed to in writing, software *
12  * distributed under the License is distributed on an "AS IS" BASIS, *
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or *
14  * implied. See the License for the specific language governing *
15  * permissions and limitations under the License. *
16  ***********************************************************************/

17
18 package org.apache.james.test;
19
20 import junit.framework.TestCase;
21
22 import java.io.*;
23 import java.util.*;
24 import java.net.Socket JavaDoc;
25
26 /**
27  * Abstract Protocol Test is the root of all of the James Imap Server test
28  * cases. It provides functionality to create text files for matching
29  * client requests and server responses. In order to use it however you
30  * must create a sub class and set all the file names, etc up yourself.
31  * All Comments are written by Andy Oliver who is still trying to figure out
32  * some of it himself so don't take this as gospel
33  *
34  */

35 public abstract class AbstractProtocolTest extends TestCase
36 {
37     private Socket JavaDoc _socket;
38     private PrintWriter _out;
39     private BufferedReader _in;
40     protected String JavaDoc _host = "127.0.0.1";
41
42     protected int _port;
43     protected int _timeout = 0;
44
45     protected List _preElements = new ArrayList();
46     protected List _testElements = new ArrayList();
47     protected List _postElements = new ArrayList();
48
49     public AbstractProtocolTest( String JavaDoc s )
50     {
51         super( s );
52     }
53
54     // comment in TestCase
55
public void setUp() throws Exception JavaDoc
56     {
57         super.setUp();
58         _testElements.clear();
59
60         _socket = new Socket JavaDoc( _host, _port );
61         _socket.setSoTimeout( _timeout );
62         _out = new PrintWriter( _socket.getOutputStream(), true );
63         _in = new BufferedReader( new InputStreamReader( _socket.getInputStream() ) );
64     }
65
66     // comment in TestCase
67
protected void tearDown() throws Exception JavaDoc
68     {
69         _out.close();
70         _in.close();
71         _socket.close();
72         super.tearDown();
73     }
74
75     // comment in TestCase
76
protected void executeTests() throws Exception JavaDoc
77     {
78         executeTest( _preElements );
79         executeTest( _testElements );
80         executeTest( _postElements );
81     }
82
83     /**
84      * executes the test case as specified in the file. Commands in
85      * CL: elements are sent to the server, and the SL: lines are verified
86      * against those returning from the server. The order is important
87      * unless in a "SUB:" block in which case the order is not important and
88      * the test will pass if any line in the SUB: block matches.
89      */

90     protected void executeTest( List protocolLines ) throws Exception JavaDoc
91     {
92         for ( Iterator iter = protocolLines.iterator(); iter.hasNext(); ) {
93             Object JavaDoc obj = iter.next();
94             if ( obj instanceof ProtocolLine ) {
95             ProtocolLine test = (ProtocolLine) obj;
96             test.testProtocol( _out, _in );
97             } else if ( obj instanceof List ) {
98                //System.err.println("skipping over unordered block");
99
List testlist = (List) obj;
100                for (int k = 0; k < testlist.size(); k++) {
101                   ProtocolLine test = (ProtocolLine) testlist.get(k);
102                   test.testProtocolBlock( _out, _in, testlist);
103                }
104             }
105         }
106     }
107
108     /**
109      * adds a new Client request line to the test elements
110      */

111     protected void CL( String JavaDoc clientLine )
112     {
113         _testElements.add( new ClientRequest( clientLine ) );
114     }
115
116     /**
117      * adds a new Server Response line to the test elements
118      */

119     protected void SL( String JavaDoc serverLine )
120     {
121         _testElements.add( new ServerResponse( serverLine ) );
122     }
123
124     /**
125      * This Line is sent to the server (everything after "CL: ") in expectation
126      * that the server will respond.
127      */

128     protected class ClientRequest implements ProtocolLine
129     {
130         private String JavaDoc _msg;
131
132         public ClientRequest( String JavaDoc msg )
133         {
134             _msg = msg;
135         }
136
137         /**
138          * Sends the request to the server
139          */

140         public void testProtocol( PrintWriter out, BufferedReader in ) throws Exception JavaDoc
141         {
142             out.println( _msg );
143         }
144
145         /**
146          * This should NOT be called, CL is not blockable! Runtime exception
147          * will be thrown. Implemented because of "ProtocolLine"
148          */

149         public void testProtocolBlock( PrintWriter out, BufferedReader in, List list)
150         throws Exception JavaDoc {
151             //out.println( _msg );
152
throw new RuntimeException JavaDoc("Syntax error in test case, CL is not "+
153                                        "able to be used in a SUB: block");
154         }
155     }
156
157     /**
158      * This line is what is in the test case file, it is verified against the
159      * actual line returned from the server.
160      */

161     protected class ServerResponse implements ProtocolLine
162     {
163         private String JavaDoc _msg;
164         private List _elementTests;
165         private boolean _ignoreExtraCharacters = false;
166         private String JavaDoc _location;
167
168         /**
169          * Constructs a ServerResponse, builds the tests
170          * @param msg the server response line
171          * @param location a string containing the location number for error
172          * messages to give you a clue of where in the file you where
173          * @param ignoreExtraCharacters whether to ignore EndOfLine or not
174          */

175         public ServerResponse( String JavaDoc msg,
176                            String JavaDoc location,
177                            boolean ignoreExtraCharacters)
178         {
179             _msg = msg;
180             _elementTests = buildElementTests( getMessageTokens( _msg ) );
181             if ( ! ignoreExtraCharacters ) {
182                 _elementTests.add( new EndOfLineTest() );
183             }
184
185             _location = location;
186         }
187
188         /**
189          * Cheap version of ServerResponse(String, String, boolean) this
190          * assumes you don't want to ignore the end of line
191          * @param msg the server response line
192          * @param location a string containing the location number for error
193          * messages to give you a clue of where in the file you where
194          */

195         public ServerResponse( String JavaDoc msg,
196                            String JavaDoc location )
197         {
198             this( msg, location, false );
199         }
200
201         /**
202          * Cheap version of ServerResponse(String, String, boolean) this
203          * sends "null" for location
204          * @param msg the server response line
205          * @param ignoreExtraCharacters whether to ignore EndOfLine or not
206          */

207         public ServerResponse( String JavaDoc msg, boolean ignoreExtraCharacters )
208         {
209             this( msg, null, ignoreExtraCharacters );
210         }
211
212         /**
213          * Cheap version of ServerResponse(String, String, boolean) this
214          * sends "null" for location and false for ignore the EOL
215          * @param msg the server response line
216          */

217         public ServerResponse( String JavaDoc msg )
218         {
219             this( msg, null, false );
220         }
221
222         /**
223          * Special method for dealing with anything in the "SUB" block,
224          * it ignores the order of whats in the SUB block and only throws
225          * an assertion at the end if nothing matched
226          * @param out PrintWriter for talking to the server
227          * @param in BufferedReader for getting the server response
228          * @param testslist List containing the lines of the block, should
229          * contain ServerResponse objects
230          */

231         public void testProtocolBlock( PrintWriter out, BufferedReader in,
232                                       List testslist) throws Exception JavaDoc {
233             //System.err.println("in new TestProtocol");
234
String JavaDoc testLine = readLine( in );
235             if ( _ignoreExtraCharacters
236                     && ( testLine.length() > _msg.length() ) ) {
237                 testLine = testLine.substring( 0, _msg.length() );
238             }
239
240             ListIterator testTokens = getMessageTokens( testLine ).listIterator();
241             Iterator theblock = testslist.iterator();
242             boolean assertval = false;
243             while (theblock.hasNext()) {
244               assertval = testProtocolInBlock( out, in, testTokens, testLine);
245               if (assertval = true) {
246                   break;
247               }
248             }
249             if (assertval == false) {
250                     System.err.println("returning failure in block");
251             }
252             assertTrue("Someting in block matched (false)", assertval);
253             
254         }
255  
256         /**
257          * Called by testProtocolBlock. Tests one line and returns true or
258          * false.
259          * @param out PrintWriter for talking to the server
260          * @param in BufferedReader for getting the server response
261          * @param testTokens ListIterator containing a list of the tokens in
262          * the testLine
263          * @param testLine is the response from the server
264          */

265         public boolean testProtocolInBlock( PrintWriter out, BufferedReader in, ListIterator testTokens, String JavaDoc testLine) throws Exception JavaDoc
266         {
267             boolean retval = false;
268             Iterator tests = _elementTests.iterator();
269             while ( tests.hasNext() ) {
270                 ElementTest test = (ElementTest)tests.next();
271                 if ( _location != null ) {
272                     test.setLocation( _location );
273                 }
274                 //System.err.println("testLine="+testLine);
275
retval = test.softTest( testTokens, testLine );
276                 if (retval == false) {
277                    break;
278                 }
279             }
280             return retval;
281         }
282
283         /**
284          * Default version of testing. Tests the response from the server and
285          * assumes that every SL line between CL lines is in the same order.
286          * @param out PrintWriter for talking to the server
287          * @param in BufferedReader for getting the server response
288          */

289         public void testProtocol( PrintWriter out, BufferedReader in ) throws Exception JavaDoc
290         {
291             String JavaDoc testLine = readLine( in );
292             if ( _ignoreExtraCharacters
293                     && ( testLine.length() > _msg.length() ) ) {
294                 testLine = testLine.substring( 0, _msg.length() );
295             }
296
297             ListIterator testTokens = getMessageTokens( testLine ).listIterator();
298             Iterator tests = _elementTests.iterator();
299             while ( tests.hasNext() ) {
300                 ElementTest test = (ElementTest)tests.next();
301                 if ( _location != null ) {
302                     test.setLocation( _location );
303                 }
304                 test.test( testTokens, testLine );
305             }
306         }
307
308         /**
309          * Grabs a line from the server and throws an error message if it
310          * doesn't work out
311          * @param in BufferedReader for getting the server response
312          * @return String of the line from the server
313          */

314         private String JavaDoc readLine( BufferedReader in ) throws Exception JavaDoc
315         {
316             try {
317                 return in.readLine();
318             }
319             catch ( InterruptedIOException e ) {
320                 String JavaDoc errMsg = "\nLocation: " + _location +
321                                 "\nExpected: " + _msg +
322                                 "\nReason: Server Timeout.";
323                 fail( errMsg );
324                 return "";
325             }
326         }
327
328         private List getMessageTokens( String JavaDoc message )
329         {
330             List tokenList = new ArrayList();
331             StringTokenizer tokens = new StringTokenizer( message, " \t\n\r\f\"\'{}()[];$", true );
332             while ( tokens.hasMoreTokens() ) {
333                 tokenList.add( tokens.nextToken() );
334             }
335             return tokenList;
336         }
337
338         private List buildElementTests( List tokenList )
339         {
340             List elementTests = new ArrayList();
341             for ( int i = 0; i < tokenList.size(); i++ ) {
342                 if ( ( i < ( tokenList.size() - 3 ) )
343                         && tokenList.get( i ).equals( "$" )
344                         && tokenList.get( i+1 ).equals( "{" )
345                         && tokenList.get( i+3 ).equals( "}" ) ) {
346                     // For now, assume all special tokens are simple consume tokens.
347
String JavaDoc special = (String JavaDoc) tokenList.get( i+2 );
348                     elementTests.add( buildSpecialTest( special ) );
349                     i += 3;
350                 }
351                 else {
352                     elementTests.add( new StringElementTest( (String JavaDoc)tokenList.get( i ) ) );
353                 }
354             }
355             return elementTests;
356         }
357
358         /**
359          * An atomic unit of a ProtocolLine
360          */

361         private abstract class ElementTest
362         {
363             protected String JavaDoc _description;
364
365             void setLocation( String JavaDoc location ) {
366                 _description = "\nLocation: " + location;
367             }
368
369             void test( ListIterator testElements, String JavaDoc fullTestLine ) throws Exception JavaDoc
370             {
371                 _description += "\nActual : " + fullTestLine +
372                                 "\nExpected: " + _msg +
373                                 "\nReason: ";
374                 doTest( testElements );
375             }
376
377             void test( ListIterator testElements ) throws Exception JavaDoc
378             {
379                 _description += "Reason: ";
380                 doTest( testElements );
381             }
382   
383             boolean softTest( ListIterator testElements, String JavaDoc line) throws Exception JavaDoc {
384                 return doNonAssertingTest(testElements);
385             }
386
387             abstract void doTest( ListIterator testElements ) throws Exception JavaDoc;
388
389             /**
390              * non Asserting version of doTest that instead of throwing an
391              * assert, just gently retunrs a boolean
392              * @param testElements the elements to test with
393              * @return boolean true if success false if failed
394              */

395             abstract boolean doNonAssertingTest( ListIterator testElements)
396               throws Exception JavaDoc;
397         }
398         
399         /**
400          * An element test which always fails with a null
401          */

402         
403         /**
404          * An element test which does a simple String comparison with the element.
405          */

406         private class StringElementTest extends ElementTest
407         {
408             private String JavaDoc _elementValue;
409
410             public StringElementTest( String JavaDoc elementValue )
411             {
412                 _elementValue = elementValue;
413             }
414         
415             //comment in ElementTest
416
public boolean doNonAssertingTest( ListIterator testElements )
417             throws Exception JavaDoc {
418                 String JavaDoc next;
419                 if ( testElements.hasNext() ) {
420                     next = (String JavaDoc) testElements.next();
421                 }
422                 else {
423                     next = "No more elements";
424                 }
425                 if ( !_elementValue.equals(next) ) {
426                   //System.err.println("emement value="+_elementValue+
427
//" did not =next+"+
428
//next);
429
return false;
430                 }
431                   //System.err.println("emement value="+_elementValue+
432
//" did =next+"+
433
//next);
434
return true;
435             }
436
437             public void doTest( ListIterator testElements ) throws Exception JavaDoc
438             {
439                 String JavaDoc next;
440                 if ( testElements.hasNext() ) {
441                     next = (String JavaDoc) testElements.next();
442                 }
443                 else {
444                     next = "No more elements";
445                 }
446                 assertEquals( _description, _elementValue, next );
447             }
448         }
449
450         private ElementTest buildSpecialTest( String JavaDoc testName )
451         {
452             if ( testName.startsWith("ignore") ) {
453                 return new ConsumeElementTest( testName );
454             }
455             if ( testName.startsWith("rfcDate") ) {
456                 return new RfcDateElementTest( testName );
457             }
458             else {
459                 return new StringElementTest( "${" + testName + "}" );
460             }
461         }
462
463
464         /**
465          * A simple element test which simply consumes a specified number of test elements,
466          * ignoring the actual element values.
467          */

468         private class ConsumeElementTest extends ElementTest
469         {
470             private int _elementsToConsume;
471             ConsumeElementTest( String JavaDoc token )
472             {
473                 if ( token.equals("ignore") ) {
474                     _elementsToConsume = 1;
475                 }
476                 else if ( token.startsWith( "ignore-") ) {
477                     _elementsToConsume = Integer.parseInt( token.substring( "ignore-".length() ) );
478                 }
479                 else {
480                     _elementsToConsume = Integer.parseInt( token );
481                 }
482             }
483
484             ConsumeElementTest(int number)
485             {
486                 _elementsToConsume = number;
487             }
488
489             public void doTest( ListIterator testElements ) throws Exception JavaDoc
490             {
491                 for ( int i = 0; i < _elementsToConsume; i++ )
492                 {
493                     if ( ! testElements.hasNext() ) {
494                         fail( _description + "Not enough elements to ignore." );
495                     }
496                     String JavaDoc ignored = (String JavaDoc)testElements.next();
497                 }
498             }
499             public boolean doNonAssertingTest( ListIterator testElements ) throws Exception JavaDoc
500             {
501                 for ( int i = 0; i < _elementsToConsume; i++ )
502                 {
503                     if ( ! testElements.hasNext() ) {
504                         return false;
505                     }
506                     String JavaDoc ignored = (String JavaDoc)testElements.next();
507                 }
508                 return true;
509             }
510         }
511
512         /**
513          * Accepts an RFC date (or anything with 12 tokens - todo make this better)
514          */

515         private class RfcDateElementTest extends ConsumeElementTest
516         {
517             public RfcDateElementTest( String JavaDoc token )
518             {
519                 super( 11 );
520             }
521         }
522
523         /**
524          * A Test that ensures that no more tokens are present.
525          */

526         private class EndOfLineTest extends ElementTest
527         {
528             public void doTest( ListIterator testElements ) throws Exception JavaDoc
529             {
530                 if ( testElements.hasNext() ) {
531                     String JavaDoc nextElement = (String JavaDoc)testElements.next();
532                     fail( _description + "End of line expected, found '" + nextElement + "'" );
533                 }
534             }
535         
536             public boolean doNonAssertingTest( ListIterator testElements )
537             throws Exception JavaDoc
538             {
539                 if ( testElements.hasNext() ) {
540                     String JavaDoc nextElement = (String JavaDoc)testElements.next();
541                     return false;
542                 }
543                 return true;
544             }
545         }
546     }
547
548     protected interface ProtocolLine
549     {
550         void testProtocol( PrintWriter out, BufferedReader in ) throws Exception JavaDoc;
551         void testProtocolBlock(PrintWriter out, BufferedReader in, List list)
552         throws Exception JavaDoc;
553     }
554
555     protected void addTestFile( String JavaDoc fileName ) throws Exception JavaDoc
556     {
557         addTestFile( fileName, _testElements );
558     }
559
560     protected void addTestFile( String JavaDoc fileName, List protocolLines ) throws Exception JavaDoc
561     {
562         // Need to find local resource.
563
InputStream is = this.getClass().getResourceAsStream( fileName );
564         if ( is == null ) {
565             throw new Exception JavaDoc("Test Resource '" + fileName + "' not found." );
566         }
567
568         addProtocolLinesFromStream( is, protocolLines, fileName );
569     }
570
571     private void addProtocolLinesFromStream( InputStream is, List protocolLines, String JavaDoc fileName ) throws Exception JavaDoc
572     {
573         BufferedReader reader = new BufferedReader( new InputStreamReader( is ) );
574         String JavaDoc next;
575         int lineNumber = 1;
576         while ( ( next = reader.readLine() ) != null ) {
577             String JavaDoc location = fileName + ":" + lineNumber;
578             if ( next.startsWith( "C: " ) ) {
579                 String JavaDoc clientMsg = next.substring( 3 );
580                 protocolLines.add( new ClientRequest( clientMsg ) );
581             }
582             else if ( next.startsWith( "S: " ) ) {
583                 String JavaDoc serverMsg = next.substring( 3 );
584                 if ( serverMsg.endsWith("//") ) {
585                     serverMsg = serverMsg.substring( 0, serverMsg.length() - 2 );
586                     protocolLines.add( new ServerResponse( serverMsg, location, true ) );
587                 }
588                 else {
589                     protocolLines.add( new ServerResponse( serverMsg, location, false ) );
590                 }
591
592             } else if ( next.startsWith("SUB: ") ) {
593               //System.err.println("Hit SUB ");
594
List unorderedBlock = new ArrayList(5);
595               next = reader.readLine();
596               //System.err.println("next = " + next);
597
String JavaDoc serverMsg = next.substring( 3 );
598               while ( !next.startsWith("SUB:") ) {
599                    unorderedBlock.add(
600                                new ServerResponse( serverMsg, location, false )
601                                      );
602                    next = reader.readLine();
603                    serverMsg = next.substring( 3 );
604                    lineNumber++;
605                    //System.err.println("next = " + next);
606
}
607               protocolLines.add(unorderedBlock);
608             } else if ( next.startsWith( "//" )
609                       || next.trim().length() == 0 ) {
610                 // ignore these lines.
611
}
612             else {
613                 String JavaDoc prefix = next;
614                 if ( next.length() > 3 ) {
615                     prefix = next.substring( 0, 3 );
616                 }
617                 throw new Exception JavaDoc( "Invalid line prefix: " + prefix );
618             }
619             lineNumber++;
620         }
621
622     }
623 }
624
Popular Tags