httpunit-commit Mailing List for httpunit (Page 69)
Brought to you by:
russgold
You can subscribe to this list here.
2000 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
(5) |
Sep
(31) |
Oct
(39) |
Nov
(18) |
Dec
(6) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2001 |
Jan
(8) |
Feb
(5) |
Mar
(8) |
Apr
(25) |
May
(20) |
Jun
(23) |
Jul
(28) |
Aug
(10) |
Sep
(3) |
Oct
(32) |
Nov
(61) |
Dec
(24) |
2002 |
Jan
(50) |
Feb
(34) |
Mar
(35) |
Apr
(3) |
May
(25) |
Jun
(25) |
Jul
(30) |
Aug
(146) |
Sep
(49) |
Oct
(156) |
Nov
(121) |
Dec
(54) |
2003 |
Jan
(12) |
Feb
(79) |
Mar
(88) |
Apr
(26) |
May
(67) |
Jun
(29) |
Jul
(8) |
Aug
(16) |
Sep
(20) |
Oct
(17) |
Nov
|
Dec
(5) |
2004 |
Jan
|
Feb
(40) |
Mar
(30) |
Apr
(5) |
May
|
Jun
(83) |
Jul
(34) |
Aug
(20) |
Sep
(44) |
Oct
(46) |
Nov
|
Dec
(14) |
2005 |
Jan
(4) |
Feb
|
Mar
(5) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(4) |
Oct
|
Nov
|
Dec
(1) |
2006 |
Jan
|
Feb
|
Mar
(26) |
Apr
(8) |
May
(2) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(5) |
Nov
|
Dec
|
2008 |
Jan
|
Feb
|
Mar
|
Apr
(36) |
May
(38) |
Jun
(1) |
Jul
(1) |
Aug
|
Sep
(4) |
Oct
|
Nov
(18) |
Dec
(4) |
2009 |
Jan
|
Feb
(2) |
Mar
(3) |
Apr
|
May
|
Jun
(2) |
Jul
|
Aug
(35) |
Sep
(1) |
Oct
|
Nov
|
Dec
(1) |
2010 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(3) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2011 |
Jan
(9) |
Feb
|
Mar
|
Apr
(1) |
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(1) |
2012 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(21) |
Oct
(18) |
Nov
(1) |
Dec
|
From: Russell G. <rus...@us...> - 2001-11-27 17:31:57
|
Update of /cvsroot/httpunit/httpunit In directory usw-pr-cvs1:/tmp/cvs-serv4685 Modified Files: build.xml Log Message: Use release name as root in zip archive Index: build.xml =================================================================== RCS file: /cvsroot/httpunit/httpunit/build.xml,v retrieving revision 1.34 retrieving revision 1.35 diff -u -r1.34 -r1.35 --- build.xml 2001/11/12 20:43:50 1.34 +++ build.xml 2001/11/27 17:31:54 1.35 @@ -6,7 +6,6 @@ <property name="name" value="httpunit" /> <property name="Name" value="HttpUnit" /> <property name="version" value="1.2.7" /> - <property name="zip_version" value="1_2_7" /> <property name="src.dir" value="src" /> <property name="tstsrc.dir" value="test" /> @@ -21,6 +20,7 @@ <property name="javadoc.dir" value="${docs.dir}/api" /> <property name="dist.dir" value="dist" /> + <property name="archive.dir" value="${dist.dir}/${name}-${version}" /> <property name="classpath" value="" /> <property name="web.dir" value="web" /> <property name="packages" value="com.meterware.*" /> @@ -159,8 +159,8 @@ <!-- Creates the distribution --> <!-- =================================================================== --> <target name="dist" depends="jar,javadocs,tutorial"> - <mkdir dir="${dist.dir}" /> - <copy todir="${dist.dir}" > + <mkdir dir="${archive.dir}" /> + <copy todir="${archive.dir}" > <fileset dir="." > <include name="build.xml" /> <include name="readme.txt" /> @@ -172,9 +172,9 @@ <include name="doc/**/*.*" /> </fileset> </copy> - <copy todir="${dist.dir}/lib" file="${jars.dir}/Tidy.jar" /> - <replace file="${dist.dir}/index.html" token="var:dist " value="var:dist>" /> - <replace file="${dist.dir}/index.html" token="var:publish>" value="var:publish " /> + <copy todir="${archive.dir}/lib" file="${jars.dir}/Tidy.jar" /> + <replace file="${archive.dir}/index.html" token="var:dist " value="var:dist>" /> + <replace file="${archive.dir}/index.html" token="var:publish>" value="var:publish " /> </target> @@ -182,7 +182,7 @@ <!-- Packages the distribution with ZIP --> <!-- =================================================================== --> <target name="dist-zip" depends="dist"> - <zip zipfile="${name}_${zip_version}.zip" basedir="${dist.dir}" includes="**" /> + <zip zipfile="${name}-${version}.zip" basedir="${dist.dir}" includes="**" /> </target> @@ -196,7 +196,7 @@ </copy> <replace file="${web.dir}/index.html" token="var:dist>" value="var:dist " /> <replace file="${web.dir}/index.html" token="var:publish " value="var:publish>" /> - <replace file="${web.dir}/index.html" token="<version>" value="${zip_version}" /> + <replace file="${web.dir}/index.html" token="<version>" value="${version}" /> </target> @@ -204,7 +204,7 @@ <!-- Packages the web site with ZIP --> <!-- =================================================================== --> <target name="publish-zip" depends="publish"> - <zip zipfile="${name}_website_${zip_version}.zip" basedir="${web.dir}" includes="**" /> + <zip zipfile="${name}_website_${version}.zip" basedir="${web.dir}" includes="**" /> </target> |
From: Russell G. <rus...@us...> - 2001-11-27 16:40:51
|
Update of /cvsroot/httpunit/httpunit/test/com/meterware/httpunit In directory usw-pr-cvs1:/tmp/cvs-serv25123/test/com/meterware/httpunit Modified Files: WebLinkTest.java Log Message: Added security to servlet unit tutorial Index: WebLinkTest.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/test/com/meterware/httpunit/WebLinkTest.java,v retrieving revision 1.16 retrieving revision 1.17 diff -u -r1.16 -r1.17 --- WebLinkTest.java 2001/11/09 18:35:14 1.16 +++ WebLinkTest.java 2001/11/27 16:40:47 1.17 @@ -160,6 +160,27 @@ } + public void testLinksWithFragmentsAndParameters() throws Exception { + WebConversation wc = new WebConversation(); + defineResource( "Initial.html?age=3", "<html><head><title>Initial</title></head><body>" + + "Go to <a href=\"Next.html\">the next page.</a> <a name=\"bottom\">Bottom</a>" + + "</body></html>" ); + defineWebPage( "Next", "And go back to <a href=\"Initial.html?age=3#Bottom\">the first page.</a>" ); + + WebResponse initialPage = wc.getResponse( getHostPath() + "/Initial.html?age=3" ); + assertEquals( "Num links in initial page", 1, initialPage.getLinks().length ); + WebLink link = initialPage.getLinks()[0]; + + WebResponse nextPage = wc.getResponse( link.getRequest() ); + assertEquals( "Title of next page", "Next", nextPage.getTitle() ); + assertEquals( "Num links in next page", 1, nextPage.getLinks().length ); + link = nextPage.getLinks()[0]; + + WebResponse thirdPage = wc.getResponse( link.getRequest() ); + assertEquals( "Title of next page", "Initial", thirdPage.getTitle() ); + } + + public void testDocumentBase() throws Exception { WebConversation wc = new WebConversation(); defineWebPage( "alternate/Target", "Found me!" ); |
From: Russell G. <rus...@us...> - 2001-11-27 16:40:51
|
Update of /cvsroot/httpunit/httpunit/doc/tutorial/src/tutorial In directory usw-pr-cvs1:/tmp/cvs-serv25123/doc/tutorial/src/tutorial Modified Files: PoolEditorTest.java Log Message: Added security to servlet unit tutorial Index: PoolEditorTest.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/doc/tutorial/src/tutorial/PoolEditorTest.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- PoolEditorTest.java 2001/11/12 20:43:51 1.1 +++ PoolEditorTest.java 2001/11/27 16:40:47 1.2 @@ -11,7 +11,7 @@ public class PoolEditorTest extends TestCase { - public static void main(String args[]) { + public static void main( String args[] ) { junit.textui.TestRunner.run( suite() ); } @@ -31,8 +31,15 @@ public void testGetForm() throws Exception { ServletRunner sr = new ServletRunner( "web.xml" ); - ServletUnitClient client = sr.newClient(); + + try { + client.getResponse( "http://localhost/PoolEditor" ); + fail( "PoolEditor is not protected" ); + } catch (AuthorizationRequiredException e) { + } + + client.setAuthorization( "aUser", "pool-admin" ); client.getResponse( "http://localhost/PoolEditor" ); } @@ -121,7 +128,7 @@ response = client.getResponse( request ); form = response.getFormWithID( "pool" ); - assertEquals( "Away team 0", "", form.getParameterValue( "home0" ) ); + assertEquals( "Away team 0", "", form.getParameterValue( "away0" ) ); assertEquals( "Home team 0", "", form.getParameterValue( "home0" ) ); assertEquals( "Away team 1", "Detroit Lions", form.getParameterValue( "away1" ) ); assertEquals( "Home team 1", "Denver Broncos", form.getParameterValue( "home1" ) ); @@ -198,4 +205,5 @@ fail( "Could still edit the pool" ); } catch (IllegalRequestParameterException e) {} } + } |
From: Russell G. <rus...@us...> - 2001-11-27 16:40:50
|
Update of /cvsroot/httpunit/httpunit/doc In directory usw-pr-cvs1:/tmp/cvs-serv25123/doc Modified Files: release_notes.txt Log Message: Added security to servlet unit tutorial Index: release_notes.txt =================================================================== RCS file: /cvsroot/httpunit/httpunit/doc/release_notes.txt,v retrieving revision 1.69 retrieving revision 1.70 diff -u -r1.69 -r1.70 --- release_notes.txt 2001/11/26 14:20:12 1.69 +++ release_notes.txt 2001/11/27 16:40:47 1.70 @@ -13,7 +13,17 @@ Revision History: -22-Nov-2001 +27-Nov-2001 +Acknowledgements: + Thanks to Peter Rossbach for catching some typos in the tutorial. + +Additions: + 1. The tutorial now includes an explanation of security testing in ServletUnit + +26-Nov-2001 +Acknowledgements: + Thanks to Oliver Imbusch for finding and supplying a fix for bad parsing of link URLs with parameters and fragments. + Additions: 1. ServletUnit now handles protected URLs defined in web.xml, along with both Basic and Form authentication. Logins with non-blank usernames are also accepted, with the password being interpreted as a comma-separated list of |
From: Russell G. <rus...@us...> - 2001-11-27 16:40:50
|
Update of /cvsroot/httpunit/httpunit/doc/tutorial In directory usw-pr-cvs1:/tmp/cvs-serv25123/doc/tutorial Modified Files: build.xml index.html task1.html task1.zip task1editor-entry.html task1editor-form.html task1editor-initial.html task1editor-validation.html task2.html web.xml Log Message: Added security to servlet unit tutorial Index: build.xml =================================================================== RCS file: /cvsroot/httpunit/httpunit/doc/tutorial/build.xml,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- build.xml 2001/11/12 20:43:51 1.1 +++ build.xml 2001/11/27 16:40:47 1.2 @@ -1,6 +1,6 @@ <?xml version="1.0" ?> <!-- ======================================================================= --> -<!-- httpunit tutorial build file --> +<!-- httpunit tutorial build file --> <!-- ======================================================================= --> <project name="tutorial" default="test" basedir="."> <property name="src.dir" value="src" /> Index: index.html =================================================================== RCS file: /cvsroot/httpunit/httpunit/doc/tutorial/index.html,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- index.html 2001/11/26 14:19:26 1.2 +++ index.html 2001/11/27 16:40:47 1.3 @@ -57,7 +57,8 @@ <p>Each section of the tutorial will address a specific use of the system, and show how HttpUnit and ServletUnit can be used to write tests which verify that functionality. You should begin each section by copying the initial directory, which includes an ant build script and some classes that you will need to complete it. Running the ant script will compile the code and -run the tests. After you implement each test, it should fail until you then add the implementation.</p> +run the tests. If you are not using ant, compile and run tutorial.TutorialTestSuite. After you implement each test, +it should fail until you then add the implementation.</p> <p>Tasks</p> Index: task1.html =================================================================== RCS file: /cvsroot/httpunit/httpunit/doc/tutorial/task1.html,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- task1.html 2001/11/26 14:19:26 1.2 +++ task1.html 2001/11/27 16:40:47 1.3 @@ -9,12 +9,21 @@ <p class="location"><a href="index.html">Tutorial</a> <img src="arrow_yellow.gif" width=13 height=9 align=bottom ALT="->">Task 1</p> <h1>Creating the Pool Editor</h1> -<p>Our initial task will be the creation of the simple pool editor, following use case 1.1. We will ignore -security restrictions that permit only the administrator to access this page. +<p>Our initial task will be the creation of the simple pool editor, following use case 1.1. To restrict access to the +administrator, we will take advantage of declarative security defined by the Servlet standard. As part of this task, we will +use the Basic Authentication approach, which causes the browser to pop up a challenge dialog. The more common form-based +authentication is handled the same way that all forms should be.</p> +<p> +To begin the tutorial, create a working directory and expand <a href="task1.zip">this archive</a> into it. To run the +tutorial, you will need httpunit.jar, junit.jar, Tidy.jar, servlet.jar, and xerces.jar on your classpath. If you use +<code>ant</code>, you can either copy +them into the <code>jars</code> directory just created, or invoke ant with <code>-Dclasspath="..."</code>, specifying the locations +of those jars between the quotation marks. If you do not use <code>ant</code>, note that the main class is named +<code>tutorial.PoolEditorTest</code><p> -To begin the tutorial, create a working directory and expand <a href="task1.zip">this archive</a> into it. -Either create a jars directory and copy httpunit.jar, Tidy.jar, and xerces.jar into it, or make sure that they are on -your classpath and invoke ant passing the classpath as a property. -You will write your code in the src/tutorial sub-directory. +<p>You will write your code in the src/tutorial sub-directory.</p> -Once you are ready, proceed to <a href="task1editor-initial.html">step one</a> to begin the tutorial. \ No newline at end of file +<p>Once you are ready, proceed to <a href="task1editor-initial.html">step one</a> to begin the tutorial.</p> + +</body> +</html> \ No newline at end of file Index: task1.zip =================================================================== RCS file: /cvsroot/httpunit/httpunit/doc/tutorial/task1.zip,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 Binary files /tmp/cvsrQSXJs and /tmp/cvsalEVkL differ Index: task1editor-entry.html =================================================================== RCS file: /cvsroot/httpunit/httpunit/doc/tutorial/task1editor-entry.html,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- task1editor-entry.html 2001/11/26 14:19:26 1.2 +++ task1editor-entry.html 2001/11/27 16:40:47 1.3 @@ -39,6 +39,7 @@ ServletRunner sr = <b>new</b> ServletRunner( "web.xml" ); ServletUnitClient client = sr.newClient(); + client.setAuthorization( "aUser", "pool-admin" ); WebResponse response = client.getResponse( "http://localhost/PoolEditor" ); WebForm form = response.getFormWithID( "pool" ); @@ -83,6 +84,7 @@ <b>public void</b> testPoolEntry() <b>throws</b> Exception { ServletRunner sr = <b>new</b> ServletRunner( "web.xml" ); ServletUnitClient client = sr.newClient(); + client.setAuthorization( "aUser", "pool-admin" ); WebResponse response = client.getResponse( "http://localhost/PoolEditor" ); WebForm form = response.getFormWithID( "pool" ); @@ -95,7 +97,7 @@ response = client.getResponse( request ); // (3) submit the form form = response.getFormWithID( "pool" ); - assertEquals( "Away team 0", "", form.getParameterValue( "home0" ) ); // (4) verify the response + assertEquals( "Away team 0", "", form.getParameterValue( "away0" ) ); // (4) verify the response assertEquals( "Home team 0", "", form.getParameterValue( "home0" ) ); assertEquals( "Away team 1", "Detroit Lions", form.getParameterValue( "away1" ) ); assertEquals( "Home team 1", "Denver Broncos", form.getParameterValue( "home1" ) ); @@ -126,7 +128,7 @@ pw.println( "</body></html>" ); } -<b>private void</b> updateBettingPool( HttpServletRequest request ) { +<b>void</b> updateBettingPool( HttpServletRequest request ) { BettingPoolGame[] games = BettingPool.getGames(); <b>for</b> (int i = 0; i < games.length; i++) { games[i].setAwayTeam( request.getParameter( "away" + i ) ); Index: task1editor-form.html =================================================================== RCS file: /cvsroot/httpunit/httpunit/doc/tutorial/task1editor-form.html,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- task1editor-form.html 2001/11/26 14:19:26 1.2 +++ task1editor-form.html 2001/11/27 16:40:47 1.3 @@ -27,6 +27,7 @@ <b>public void</b> testFormAction() <b>throws</b> Exception { ServletRunner sr = <b>new</b> ServletRunner( "web.xml" ); ServletUnitClient client = sr.newClient(); + client.setAuthorization( "aUser", "pool-admin" ); WebResponse response = client.getResponse( "http://localhost/PoolEditor" ); WebForm form = response.getFormWithID( "pool" ); // (1) obtain the desired form @@ -59,6 +60,7 @@ <b>public void</b> testFormContents() <b>throws</b> Exception { ServletRunner sr = <b>new</b> ServletRunner( "web.xml" ); ServletUnitClient client = sr.newClient(); + client.setAuthorization( "aUser", "pool-admin" ); WebResponse response = client.getResponse( "http://localhost/PoolEditor" ); WebForm form = response.getFormWithID( "pool" ); @@ -100,6 +102,7 @@ <b>public void</b> testSubmitButtons() <b>throws</b> Exception { ServletRunner sr = <b>new</b> ServletRunner( "web.xml" ); ServletUnitClient client = sr.newClient(); + client.setAuthorization( "aUser", "pool-admin" ); WebResponse response = client.getResponse( "http://localhost/PoolEditor" ); WebForm form = response.getFormWithID( "pool" ); Index: task1editor-initial.html =================================================================== RCS file: /cvsroot/httpunit/httpunit/doc/tutorial/task1editor-initial.html,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- task1editor-initial.html 2001/11/26 14:19:26 1.2 +++ task1editor-initial.html 2001/11/27 16:40:47 1.3 @@ -11,7 +11,10 @@ <img src="arrow_yellow.gif" width=13 height=9 align=bottom ALT="->"> Step 1: Invoking the pool editor</p> <h1>Invoking the Pool Editor</h1> -<p class="goals">In this step, you will learn how to:<br />• Initialize ServletUnit<br />• Invoke a servlet</p> +<p class="goals">In this step, you will learn how to:<br /> +• Initialize ServletUnit<br /> +• Invoke a servlet<br /> +• Specify a username and password for basic authentication</p> <p>The first step will simply be to verify that we can register and access the servlet, which we will name <code>PoolEditorServlet</code>. A GET method to this page should return the editor form itself, while updates will be handled by a POST method to the same address. Since we are working with servlets, we can @@ -23,6 +26,7 @@ <b>import</b> com.meterware.httpunit.*; <b>import</b> com.meterware.servletunit.*; +<b>import</b> java.util.*; <b>import</b> junit.framework.*; <b>import</b> tutorial.persistence.*; @@ -41,10 +45,17 @@ } <b>public void</b> testGetForm() <b>throws</b> Exception { - ServletRunner sr = <b>new</b> ServletRunner( "web.xml" ); // (1) use the web.xml file to define mappings + ServletRunner sr = <b>new</b> ServletRunner( "web.xml" ); // (1) use the web.xml file to define mappings + ServletUnitClient client = sr.newClient(); // (2) create a client to invoke the application - ServletUnitClient client = sr.newClient(); // (2) create a client to invoke the application - client.getResponse( "http://localhost/PoolEditor" ); // (3) invoke the servlet + try { + client.getResponse( "http://localhost/PoolEditor" ); // (3) invoke the servlet w/o authorization + fail( "PoolEditor is not protected" ); + } catch (AuthorizationRequiredException e) { // (4) verify that access is denied + } + + client.setAuthorization( "aUser", "pool-admin" ); // (5) specify authorization and + client.getResponse( "http://localhost/PoolEditor" ); // invoke the servlet again } } @@ -56,7 +67,10 @@ The application is defined by an XML file which maps URL information to servlet classes.</li> <li>Creating a client which can access the application and maintain state across multiple invocations.</li> <li>Invoking the servlet via its URL. Note that ServletUnit ignores any host and port information. All URL patterns -are treated as being relative to the root ("/").</li></ol></p> +are treated as being relative to the root ("/").</li> +<li>Catching an exception which indicates that authentication is required.</li> +<li>Specifying the authorization information. ServletUnit does not maintain a database of users, no any username is +accepted, and the password is interpreted as a comma-separated list of role names associated with the user.</li></ol></p> <p>To run this code, you will also need the <a href="web.xml">web.xml</a> file in your current directory. This file maps the request URL to the Pool Editor servlet.</p> @@ -68,6 +82,7 @@ <b>package</b> tutorial; <b>import</b> java.io.*; +<b>import</b> java.util.*; <b>import</b> javax.servlet.http.*; <b>import</b> javax.servlet.ServletException; Index: task1editor-validation.html =================================================================== RCS file: /cvsroot/httpunit/httpunit/doc/tutorial/task1editor-validation.html,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- task1editor-validation.html 2001/11/26 14:19:26 1.2 +++ task1editor-validation.html 2001/11/27 16:40:47 1.3 @@ -29,6 +29,7 @@ <b>public void</b> testPoolValidation() <b>throws</b> Exception { ServletRunner sr = new ServletRunner( "web.xml" ); ServletUnitClient client = sr.newClient(); + client.setAuthorization( "aUser", "pool-admin" ); WebResponse response = client.getResponse( "http://localhost/PoolEditor" ); WebForm form = response.getFormWithID( "pool" ); WebRequest request = form.getRequest( "save", "Open Pool" ); @@ -86,6 +87,7 @@ <b>public void</b> testBadPoolOpen() <b>throws</b> Exception { ServletRunner sr = <b>new</b> ServletRunner( "web.xml" ); ServletUnitClient client = sr.newClient(); + client.setAuthorization( "aUser", "pool-admin" ); WebResponse response = client.getResponse( "http://localhost/PoolEditor" ); WebForm form = response.getFormWithID( "pool" ); WebRequest request = form.getRequest( "save", "Open Pool" ); // (1) select a submit button @@ -96,7 +98,7 @@ request.setParameter( "tiebreaker", "3" ); response = client.getResponse( request ); // (3) submit the form - WebTable errorTable = response.getTableStartingWith( "Errors Detected:" ); // (4) Look for error table + WebTable errorTable = response.getTableStartingWithPrefix( "Cannot ope" ); // (4) Look for error table assertNotNull( "No errors reported", errorTable ); String[][] cells = errorTable.asText(); // (5) Convert non-empty cells to text assertEquals( "Number of error messages provided", 2, cells.length - 1 ); @@ -108,7 +110,7 @@ <li>We select the "Open Pool" button to be included with the form submission.</li> <li>We then enter known bad values.</li> <li>We want the response when we submit the form changes.</li> -<li>We expect to find them in a table which we can recognize because its upper-leftmost non-empty cell which contain +<li>We expect to find them in a table which we can recognize because its upper-leftmost non-empty cell which starts with a known string.</li> <li>Since we want to examine the textual content of any non-empty cells in the table, we ask that the table be converted to a two-dimensional string array. In this case, there should only be one non-blank cell in each row.</li></ol></p> @@ -149,6 +151,7 @@ <b>public void</b> testGoodPoolOpen() <b>throws</b> Exception { ServletRunner sr = <b>new</b> ServletRunner( "web.xml" ); ServletUnitClient client = sr.newClient(); + client.setAuthorization( "aUser", "pool-admin" ); WebResponse response = client.getResponse( "http://localhost/PoolEditor" ); WebForm form = response.getFormWithID( "pool" ); WebRequest request = form.getRequest( "save", "Open Pool" ); Index: task2.html =================================================================== RCS file: /cvsroot/httpunit/httpunit/doc/tutorial/task2.html,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- task2.html 2001/11/26 14:19:26 1.1 +++ task2.html 2001/11/27 16:40:47 1.2 @@ -9,15 +9,17 @@ <p class="location"><a href="index.html">Tutorial</a> <img src="arrow_yellow.gif" width=13 height=9 align=bottom ALT="->">Task 2</p> <h1>Controlling access to the application</h1> -<p>Only the administrator is supposed to be able to edit the pool, but there is nothing in the code written so far -which enforces it. The servlet API provides ways to restrict application to servlets. As part of this task, we will -use the Basic Authentication approach, which causes the browser to pop up a challenge dialog. The more common form-based -authentication is handled the same way that all forms should be. In addition, we will create a front-end page with links -to those pages a user is permitted to access. +<p>At this point, we have a working pool editor, accessible only to a user with the appropriate assigned role. Any other +user will be refused when they try to access the editor. We would like to go further, and provide a common front page +to the application for all users, which will provide links to the permitted pages only.</p> +<b>This is not written</b> +<!-- To begin the tutorial, create a working directory and expand <a href="task2.zip">this archive</a> into it. Either create a jars directory and copy httpunit.jar, Tidy.jar, and xerces.jar into it, or make sure that they are on your classpath and invoke ant passing the classpath as a property. You will write your code in the src/tutorial sub-directory. -Once you are ready, proceed to <a href="task2access-authentication.html">step one</a> to begin the tutorial. \ No newline at end of file +Once you are ready, proceed to <a href="task2access-authentication.html">step one</a> to begin the tutorial. --> + +</body></html> \ No newline at end of file Index: web.xml =================================================================== RCS file: /cvsroot/httpunit/httpunit/doc/tutorial/web.xml,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- web.xml 2001/11/12 20:43:51 1.1 +++ web.xml 2001/11/27 16:40:47 1.2 @@ -8,4 +8,17 @@ <servlet-name>Editor</servlet-name> <url-pattern>/PoolEditor</url-pattern> </servlet-mapping> + <security-constraint> + <web-resource-collection> + <web-resource-name>Administration</web-resource-name> + <url-pattern>/PoolEditor</url-pattern> + </web-resource-collection> + <auth-constraint> + <role-name>pool-admin</role-name> + </auth-constraint> + </security-constraint> + <login-config> + <auth-method>BASIC</auth-method> + <realm-name>Betting Pool</realm-name> + </login-config> </web-app> |
From: Russell G. <rus...@us...> - 2001-11-27 16:40:50
|
Update of /cvsroot/httpunit/httpunit/src/com/meterware/httpunit In directory usw-pr-cvs1:/tmp/cvs-serv25123/src/com/meterware/httpunit Modified Files: WebLink.java Log Message: Added security to servlet unit tutorial Index: WebLink.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/src/com/meterware/httpunit/WebLink.java,v retrieving revision 1.12 retrieving revision 1.13 diff -u -r1.12 -r1.13 --- WebLink.java 2001/11/26 14:20:12 1.12 +++ WebLink.java 2001/11/27 16:40:47 1.13 @@ -129,7 +129,13 @@ * Returns the URL referenced by this link. This may be a relative URL. **/ public String getURLString() { - return NodeUtils.getNodeAttribute( getNode(), "href" ); + String href = NodeUtils.getNodeAttribute( getNode(), "href" ); + final int hashIndex = href.indexOf( '#' ); + if (hashIndex < 0) { + return href; + } else { + return href.substring( 0, hashIndex ); + } } |
From: Russell G. <rus...@us...> - 2001-11-26 14:20:16
|
Update of /cvsroot/httpunit/httpunit/test/com/meterware/servletunit In directory usw-pr-cvs1:/tmp/cvs-serv26171/test/com/meterware/servletunit Modified Files: HttpServletRequestTest.java StatelessTest.java WebXMLTest.java Log Message: Add support for authentication and servlet initialization params Index: HttpServletRequestTest.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/test/com/meterware/servletunit/HttpServletRequestTest.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- HttpServletRequestTest.java 2001/11/05 15:50:38 1.2 +++ HttpServletRequestTest.java 2001/11/26 14:20:13 1.3 @@ -2,7 +2,7 @@ /******************************************************************************************************************** * $Id$ * -* Copyright (c) 2000, Russell Gold +* Copyright (c) 2000-2001, Russell Gold * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated * documentation files (the "Software"), to deal in the Software without restriction, including without limitation @@ -21,6 +21,7 @@ *******************************************************************************************************************/ import java.util.Enumeration; import java.util.Vector; +import java.util.Hashtable; import javax.servlet.ServletException; import javax.servlet.http.*; @@ -53,7 +54,7 @@ public void testGetDefaultProperties() throws Exception { WebRequest wr = new GetMethodWebRequest( "http://localhost/simple" ); - HttpServletRequest request = new ServletUnitHttpRequest( wr, new ServletUnitContext() ); + HttpServletRequest request = new ServletUnitHttpRequest( wr, new ServletUnitContext(), new Hashtable() ); assertNull( "Authorization incorrectly specified", request.getAuthType() ); assertNull( "Character encoding incorrectly specified", request.getCharacterEncoding() ); assertEquals( "Parameters unexpectedly specified", "", request.getQueryString() ); @@ -64,7 +65,7 @@ WebRequest wr = new GetMethodWebRequest( "http://localhost/simple" ); wr.setParameter( "age", "12" ); wr.setParameter( "color", new String[] { "red", "blue" } ); - HttpServletRequest request = new ServletUnitHttpRequest( wr, new ServletUnitContext() ); + HttpServletRequest request = new ServletUnitHttpRequest( wr, new ServletUnitContext(), new Hashtable() ); assertEquals( "age parameter", "12", request.getParameter( "age" ) ); assertNull( "unset parameter should be null", request.getParameter( "unset" ) ); @@ -75,7 +76,7 @@ WebRequest wr = new GetMethodWebRequest( "http://localhost/simple" ); wr.setParameter( "age", "12" ); wr.setParameter( "color", new String[] { "red", "blue" } ); - HttpServletRequest request = new ServletUnitHttpRequest( wr, new ServletUnitContext() ); + HttpServletRequest request = new ServletUnitHttpRequest( wr, new ServletUnitContext(), new Hashtable() ); assertMatchingSet( "age parameter", new String[] { "12" }, request.getParameterValues( "age" ) ); assertMatchingSet( "color parameter", new String[] { "red", "blue" }, request.getParameterValues( "color" ) ); @@ -87,7 +88,7 @@ WebRequest wr = new GetMethodWebRequest( "http://localhost/simple" ); wr.setParameter( "age", "12" ); wr.setParameter( "color", new String[] { "red", "blue" } ); - HttpServletRequest request = new ServletUnitHttpRequest( wr, new ServletUnitContext() ); + HttpServletRequest request = new ServletUnitHttpRequest( wr, new ServletUnitContext(), new Hashtable() ); assertEquals( "query string", "color=red&color=blue&age=12", request.getQueryString() ); } @@ -95,7 +96,7 @@ public void testInlineSingleValuedParameter() throws Exception { WebRequest wr = new GetMethodWebRequest( "http://localhost/simple?color=red&color=blue&age=12" ); - HttpServletRequest request = new ServletUnitHttpRequest( wr, new ServletUnitContext() ); + HttpServletRequest request = new ServletUnitHttpRequest( wr, new ServletUnitContext(), new Hashtable() ); assertEquals( "age parameter", "12", request.getParameter( "age" ) ); assertNull( "unset parameter should be null", request.getParameter( "unset" ) ); @@ -104,7 +105,7 @@ public void testInlineMultiValuedParameter() throws Exception { WebRequest wr = new GetMethodWebRequest( "http://localhost/simple?color=red&color=blue&age=12" ); - HttpServletRequest request = new ServletUnitHttpRequest( wr, new ServletUnitContext() ); + HttpServletRequest request = new ServletUnitHttpRequest( wr, new ServletUnitContext(), new Hashtable() ); assertMatchingSet( "age parameter", new String[] { "12" }, request.getParameterValues( "age" ) ); assertMatchingSet( "color parameter", new String[] { "red", "blue" }, request.getParameterValues( "color" ) ); @@ -114,7 +115,7 @@ public void notestInlineQueryString() throws Exception { WebRequest wr = new GetMethodWebRequest( "http://localhost/simple?color=red&color=blue&age=12" ); - HttpServletRequest request = new ServletUnitHttpRequest( wr, new ServletUnitContext() ); + HttpServletRequest request = new ServletUnitHttpRequest( wr, new ServletUnitContext(), new Hashtable() ); assertEquals( "query string", "color=red&color=blue&age=12", request.getQueryString() ); } @@ -122,7 +123,7 @@ public void testDefaultAttributes() throws Exception { WebRequest wr = new GetMethodWebRequest( "http://localhost/simple" ); - HttpServletRequest request = new ServletUnitHttpRequest( wr, new ServletUnitContext() ); + HttpServletRequest request = new ServletUnitHttpRequest( wr, new ServletUnitContext(), new Hashtable() ); assertNull( "attribute should not be defined yet", request.getAttribute( "unset" ) ); assertTrue( "attribute enumeration should be empty", !request.getAttributeNames().hasMoreElements() ); @@ -131,7 +132,7 @@ public void testNonDefaultAttributes() throws Exception { WebRequest wr = new GetMethodWebRequest( "http://localhost/simple" ); - HttpServletRequest request = new ServletUnitHttpRequest( wr, new ServletUnitContext() ); + HttpServletRequest request = new ServletUnitHttpRequest( wr, new ServletUnitContext(), new Hashtable() ); Object value = new Integer(1); request.setAttribute( "one", value ); @@ -147,7 +148,7 @@ public void testDuplicateAttributes() throws Exception { WebRequest wr = new GetMethodWebRequest( "http://localhost/simple" ); - HttpServletRequest request = new ServletUnitHttpRequest( wr, new ServletUnitContext() ); + HttpServletRequest request = new ServletUnitHttpRequest( wr, new ServletUnitContext(), new Hashtable() ); Object value = new Integer(1); request.setAttribute( "one", value ); @@ -162,7 +163,7 @@ public void testSessionCreation() throws Exception { WebRequest wr = new GetMethodWebRequest( "http://localhost/simple" ); - HttpServletRequest request = new ServletUnitHttpRequest( wr, new ServletUnitContext() ); + HttpServletRequest request = new ServletUnitHttpRequest( wr, new ServletUnitContext(), new Hashtable() ); HttpSession session = request.getSession( /* create */ false ); assertNull( "Unexpected session found", session ); @@ -175,7 +176,7 @@ public void testDefaultCookies() throws Exception { WebRequest wr = new GetMethodWebRequest( "http://localhost/simple" ); - HttpServletRequest request = new ServletUnitHttpRequest( wr, new ServletUnitContext() ); + HttpServletRequest request = new ServletUnitHttpRequest( wr, new ServletUnitContext(), new Hashtable() ); Cookie[] cookies = request.getCookies(); assertNull( "Unexpected cookies found", cookies ); } @@ -183,7 +184,7 @@ public void testSetCookies() throws Exception { WebRequest wr = new GetMethodWebRequest( "http://localhost/simple" ); - ServletUnitHttpRequest request = new ServletUnitHttpRequest( wr, new ServletUnitContext() ); + ServletUnitHttpRequest request = new ServletUnitHttpRequest( wr, new ServletUnitContext(), new Hashtable() ); request.addCookie( new Cookie( "flavor", "vanilla" ) ); Cookie[] cookies = request.getCookies(); @@ -198,7 +199,7 @@ WebRequest wr = new GetMethodWebRequest( "http://localhost/simple" ); ServletUnitContext context = new ServletUnitContext(); - ServletUnitHttpRequest request = new ServletUnitHttpRequest( wr, context ); + ServletUnitHttpRequest request = new ServletUnitHttpRequest( wr, context, new Hashtable() ); request.addCookie( new Cookie( ServletUnitHttpSession.SESSION_COOKIE_NAME, context.newSession().getId() ) ); HttpSession session = request.getSession( /* create */ false ); Index: StatelessTest.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/test/com/meterware/servletunit/StatelessTest.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- StatelessTest.java 2001/11/08 22:07:53 1.3 +++ StatelessTest.java 2001/11/26 14:20:13 1.4 @@ -106,6 +106,21 @@ assertEquals( "requested resource", "You selected dark red", response.getText() ); } + public void testHeaderRetrieval() throws Exception { + ServletRunner sr = new ServletRunner(); + sr.registerServlet( "/Parameters", ParameterServlet.class.getName() ); + + ServletUnitClient client = sr.newClient(); + client.setHeaderField( "Sample", "Value" ); + client.setHeaderField( "Request", "Client" ); + WebRequest request = new GetMethodWebRequest( "http://localhost/Parameters?color=dark+red" ); + request.setHeaderField( "request", "Caller" ); + InvocationContext ic = client.newInvocation( request ); + assertEquals( "Sample header", "Value", ic.getRequest().getHeader( "sample" ) ); + assertEquals( "Request header", "Caller", ic.getRequest().getHeader( "Request" ) ); + } + + public void testSimplePost() throws Exception { final String resourceName = "something/interesting"; Index: WebXMLTest.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/test/com/meterware/servletunit/WebXMLTest.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- WebXMLTest.java 2001/11/08 22:07:53 1.1 +++ WebXMLTest.java 2001/11/26 14:20:13 1.2 @@ -1,21 +1,48 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2001 by Hewlett-Packard Company. All rights reserved. -//----------------------------------------------------------------------------- package com.meterware.servletunit; +/******************************************************************************************************************** +* $Id$ +* +* Copyright (c) 2001, Russell Gold +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +* documentation files (the "Software"), to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +* to permit persons to whom the Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or substantial portions +* of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +* DEALINGS IN THE SOFTWARE. +* +*******************************************************************************************************************/ +import com.meterware.httpunit.*; -import com.meterware.httpunit.WebRequest; -import com.meterware.httpunit.GetMethodWebRequest; -import com.meterware.httpunit.WebResponse; - import java.io.IOException; import java.io.PrintWriter; import java.io.ByteArrayInputStream; +import java.io.UnsupportedEncodingException; +import java.util.Hashtable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Enumeration; +import java.util.Properties; +import java.util.Map; +import java.net.URL; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.ServletException; +import org.xml.sax.SAXException; +import org.xml.sax.InputSource; +import org.w3c.dom.Document; +import org.apache.xerces.parsers.DOMParser; + import junit.framework.TestSuite; import junit.framework.TestCase; @@ -38,15 +65,11 @@ public void testBasicAccess() throws Exception { - String config = "<?xml version='1.0' encoding='ISO-8859-1'?>" + - "<web-app>" + - " <servlet><servlet-name>Simple</servlet-name>" + - " <servlet-class>" + SimpleGetServlet.class.getName() + "</servlet-class></servlet>" + - " <servlet-mapping><servlet-name>Simple</servlet-name>" + - " <url-pattern>/SimpleServlet</url-pattern></servlet-mapping>" + - "</web-app>"; + + WebXMLString wxs = new WebXMLString(); + wxs.addServlet( "/SimpleServlet", SimpleGetServlet.class ); - ServletRunner sr = new ServletRunner( new ByteArrayInputStream( config.getBytes() ) ); + ServletRunner sr = new ServletRunner( new ByteArrayInputStream( wxs.asText().getBytes() ) ); WebRequest request = new GetMethodWebRequest( "http://localhost/SimpleServlet" ); WebResponse response = sr.getResponse( request ); assertNotNull( "No response received", response ); @@ -55,9 +78,306 @@ } + public void testBasicAuthenticationConfig() throws Exception { + WebXMLString wxs = new WebXMLString(); + wxs.requireBasicAuthentication( "SampleRealm" ); + + WebApplication app = new WebApplication( newDocument( wxs.asText() ) ); + assertTrue( "Did not detect basic authentication", app.usesBasicAuthentication() ); + assertEquals( "Realm name", "SampleRealm", app.getAuthenticationRealm() ); + } + + + public void testFormAuthenticationConfig() throws Exception { + WebXMLString wxs = new WebXMLString(); + wxs.requireFormAuthentication( "SampleRealm", "/Login", "/Error" ); + + WebApplication app = new WebApplication( newDocument( wxs.asText() ) ); + assertTrue( "Did not detect form-based authentication", app.usesFormAuthentication() ); + assertEquals( "Realm name", "SampleRealm", app.getAuthenticationRealm() ); + assertEquals( "Login path", "/Login", app.getLoginURL().getFile() ); + assertEquals( "Error path", "/Error", app.getErrorURL().getFile() ); + } + + + public void testSecurityConstraint() throws Exception { + WebXMLString wxs = new WebXMLString(); + wxs.addSecureURL( "SecureArea1", "/SimpleServlet" ); + wxs.addAuthorizedRole( "SecureArea1", "supervisor" ); + + WebApplication app = new WebApplication( newDocument( wxs.asText() ) ); + assertTrue( "Did not require authorization", app.requiresAuthorization( new URL( "http://localhost/SimpleServlet" ) ) ); + assertTrue( "Should not require authorization", !app.requiresAuthorization( new URL( "http://localhost/FreeServlet" ) ) ); + assertTrue( "Should have access", app.roleMayAccess( "supervisor", new URL( "http://localhost/SimpleServlet" ) ) ); + assertTrue( "Should not have access", !app.roleMayAccess( "peon", new URL( "http://localhost/SimpleServlet" ) ) ); + } + + + public void testServletParameters() throws Exception { + WebXMLString wxs = new WebXMLString(); + Properties params = new Properties(); + params.setProperty( "color", "red" ); + params.setProperty( "age", "12" ); + wxs.addServlet( "/SimpleServlet", SimpleGetServlet.class, params ); + + ServletRunner sr = new ServletRunner( toInputStream( wxs.asText() ) ); + ServletUnitClient client = sr.newClient(); + InvocationContext ic = client.newInvocation( "http://localhost/SimpleServlet" ); + assertNull( "init parameter 'gender' should be null", ic.getServlet().getServletConfig().getInitParameter( "gender" ) ); + assertEquals( "init parameter via config", "red", ic.getServlet().getServletConfig().getInitParameter( "color" ) ); + assertEquals( "init parameter directly", "12", ((HttpServlet) ic.getServlet()).getInitParameter( "age" ) ); + } + + + private Document newDocument( String contents ) throws UnsupportedEncodingException, SAXException, IOException { + DOMParser parser = new DOMParser(); + parser.parse( new InputSource( toInputStream( contents ) ) ); + return parser.getDocument(); + } + + + private ByteArrayInputStream toInputStream( String contents ) throws UnsupportedEncodingException { + return new ByteArrayInputStream( contents.getBytes( "UTF-8" ) ); + } + + + public void testBasicAuthorization() throws Exception { + WebXMLString wxs = new WebXMLString(); + wxs.addServlet( "/SimpleServlet", SimpleGetServlet.class ); + wxs.requireBasicAuthentication( "Sample Realm" ); + wxs.addSecureURL( "SecureArea1", "/SimpleServlet" ); + wxs.addAuthorizedRole( "SecureArea1", "supervisor" ); + + ServletRunner sr = new ServletRunner( toInputStream( wxs.asText() ) ); + ServletUnitClient wc = sr.newClient(); + WebResponse response = null; + try { + response = wc.getResponse( "http://localhost/SimpleServlet" ); + fail( "Did not insist on validation for access to servlet" ); + } catch (AuthorizationRequiredException e) { + assertEquals( "Realm", "Sample Realm", e.getAuthenticationParameter( "realm" ) ); + assertEquals( "Method", "Basic", e.getAuthenticationScheme() ); + } + + try { + wc.setAuthorization( "You", "peon" ); + wc.getResponse( "http://localhost/SimpleServlet" ); + fail( "Permitted wrong user to access" ); + } catch (HttpException e) { + assertEquals( "Response code", 403, e.getResponseCode() ); + } + + wc.setAuthorization( "Me", "supervisor,agent" ); + wc.getResponse( "http://localhost/SimpleServlet" ); + + InvocationContext ic = wc.newInvocation( "http://localhost/SimpleServlet" ); + assertEquals( "Authenticated user", "Me", ic.getRequest().getRemoteUser() ); + assertTrue( "User assigned to 'bogus' role", !ic.getRequest().isUserInRole( "bogus" ) ); + assertTrue( "User not assigned to 'supervisor' role", ic.getRequest().isUserInRole( "supervisor" ) ); + } + + + public void testFormAuthentication() throws Exception { + HttpUnitOptions.setLoggingHttpHeaders( true ); + WebXMLString wxs = new WebXMLString(); + wxs.addServlet( "/Logon", SimpleLogonServlet.class ); + wxs.addServlet( "/Error", SimpleErrorServlet.class ); + wxs.addServlet( "/SimpleServlet", SimpleGetServlet.class ); + wxs.requireFormAuthentication( "Sample Realm", "/Logon", "/Error" ); + wxs.addSecureURL( "SecureArea1", "/SimpleServlet" ); + wxs.addAuthorizedRole( "SecureArea1", "supervisor" ); + + ServletRunner sr = new ServletRunner( toInputStream( wxs.asText() ) ); + ServletUnitClient wc = sr.newClient(); + WebResponse response = wc.getResponse( "http://localhost/SimpleServlet" ); + WebForm form = response.getFormWithID( "login" ); + assertNotNull( "did not find login form", form ); + + WebRequest request = form.getRequest(); + request.setParameter( "j_username", "Me" ); + request.setParameter( "j_password", "supervisor" ); + response = wc.getResponse( request ); + assertNotNull( "No response received after authentication", response ); + assertEquals( "content type", "text/html", response.getContentType() ); + assertEquals( "requested resource", SimpleGetServlet.RESPONSE_TEXT, response.getText() ); + + InvocationContext ic = wc.newInvocation( "http://localhost/SimpleServlet" ); + assertEquals( "Authenticated user", "Me", ic.getRequest().getRemoteUser() ); + assertTrue( "User assigned to 'bogus' role", !ic.getRequest().isUserInRole( "bogus" ) ); + assertTrue( "User not assigned to 'supervisor' role", ic.getRequest().isUserInRole( "supervisor" ) ); + } + + private final static String DOCTYPE = "<!DOCTYPE web-app PUBLIC " + " \"-//Sun Microsystems, Inc.//DTD WebApplication 2.2//EN\" " + " \"http://java.sun/com/j2ee/dtds/web-app_2_2.dtd\">"; + +//=============================================================================================================== + + + static class WebXMLString { + + String asText() { + StringBuffer result = new StringBuffer( "<?xml version='1.0' encoding='UTF-8'?>\n<web-app>\n" ); + for (int i = _servlets.size()-1; i >=0; i--) { + result.append( " <servlet>\n <servlet-name>servlet_" ).append( i ).append( "</servlet-name>\n" ); + result.append( " <servlet-class>" ).append( ((Class) _servlets.get(i)).getName() ).append( "</servlet-class>\n" ); + appendParams( result, "init-param", (Hashtable) _initParams.get( new Integer( i ) ) ); + result.append( " </servlet>\n" ); + } + for (int i = _mappings.size()-1; i >=0; i--) { + result.append( " <servlet-mapping>\n <servlet-name>servlet_" ).append( i ).append( "</servlet-name>\n" ); + result.append( " <url-pattern>" ).append( _mappings.get(i) ).append( "</url-pattern>\n </servlet-mapping>\n" ); + } + for (Enumeration e = _resources.elements(); e.hasMoreElements();) { + result.append( ((WebResourceSpec) e.nextElement()).asText() ); + } + result.append( _loginConfig ); + result.append( "</web-app>" ); + return result.toString(); + } + + + private void appendParams( StringBuffer result, String tagName, Hashtable params ) { + if (params == null) return; + for (Iterator it = params.entrySet().iterator(); it.hasNext();) { + Map.Entry entry = (Map.Entry) it.next(); + result.append( " <" ).append( tagName ).append( ">\n <param-name>" ).append( entry.getKey() ); + result.append( "</param-name>\n <param-value>" ).append( entry.getValue() ).append( "</param-value>\n </" ); + result.append( tagName ).append( ">\n" ); + } + } + + + void addServlet( String urlPattern, Class servletClass ) { + _servlets.add( servletClass ); + _mappings.add( urlPattern ); + } + + void addServlet( String urlPattern, Class servletClass, Properties initParams ) { + _initParams.put( new Integer( _servlets.size() ), initParams ); + addServlet( urlPattern, servletClass ); + } + + void requireBasicAuthorization( String realmName ) { + _loginConfig = " <login-config>\n" + + " <auth-method>BASIC</auth-method>\n" + + " <realm-name>" + realmName + "</realm-name>\n" + + " </login-config>\n"; + } + + void requireBasicAuthentication( String realmName ) { + _loginConfig = " <login-config>\n" + + " <auth-method>BASIC</auth-method>\n" + + " <realm-name>" + realmName + "</realm-name>\n" + + " </login-config>\n"; + } + + void requireFormAuthentication( String realmName, String loginPagePath, String errorPagePath ) { + _loginConfig = " <login-config>\n" + + " <auth-method>FORM</auth-method>\n" + + " <realm-name>" + realmName + "</realm-name>\n" + + " <form-login-config>" + + " <form-login-page>" + loginPagePath + "</form-login-page>\n" + + " <form-error-page>" + errorPagePath + "</form-error-page>\n" + + " </form-login-config>" + + " </login-config>\n"; + } + + void addSecureURL( String resourceName, String urlPattern ) { + getWebResource( resourceName ).addURLPattern( urlPattern ); + } + + void addAuthorizedRole( String resourceName, String roleName ) { + getWebResource( resourceName ).addAuthorizedRole( roleName ); + } + + private ArrayList _servlets = new ArrayList(); + private ArrayList _mappings = new ArrayList(); + private String _loginConfig = ""; + private Hashtable _resources = new Hashtable(); + private Hashtable _initParams = new Hashtable(); + + + private WebResourceSpec getWebResource( String resourceName ) { + WebResourceSpec result = (WebResourceSpec) _resources.get( resourceName ); + if (result == null) { + result = new WebResourceSpec( resourceName ); + _resources.put( resourceName, result ); + } + return result; + } + } + + + static class WebResourceSpec { + + WebResourceSpec( String name ) { + _name = name; + } + + void addURLPattern( String urlPattern ) { + _urls.add( urlPattern ); + } + + void addAuthorizedRole( String roleName ) { + _roles.add( roleName ); + } + + String asText() { + StringBuffer sb = new StringBuffer(); + sb.append( " <security-constraint>\n" ); + sb.append( " <web-resource-collection>\n" ); + sb.append( " <web-resource-name>" ).append( _name ).append( "</web-resource-name>\n" ); + for (Iterator i = _urls.iterator(); i.hasNext();) { + sb.append( " <url-pattern>" ).append( i.next() ).append( "</url-pattern>\n" ); + } + sb.append( " </web-resource-collection>\n" ); + sb.append( " <auth-constraint>\n" ); + for (Iterator i = _roles.iterator(); i.hasNext();) { + sb.append( " <role-name>" ).append( i.next() ).append( "</role-name>\n" ); + } + sb.append( " </auth-constraint>\n" ); + sb.append( " </security-constraint>\n" ); + return sb.toString(); + } + + private String _name; + private ArrayList _urls = new ArrayList(); + private ArrayList _roles = new ArrayList(); + } + +//=============================================================================================================== + + + static class SimpleLogonServlet extends HttpServlet { + static String RESPONSE_TEXT = "<html><body>\r\n" + + "<form id='login' action='j_security_check' method='POST'>\r\n" + + " <input name='j_username' />\r\n" + + " <input type='password' name='j_password' />\r\n" + + "</form></body></html>"; + + protected void doGet( HttpServletRequest req, HttpServletResponse resp ) throws ServletException, IOException { + resp.setContentType( "text/html" ); + PrintWriter pw = resp.getWriter(); + pw.print( RESPONSE_TEXT ); + pw.close(); + } + } + +//=============================================================================================================== + + + static class SimpleErrorServlet extends HttpServlet { + static String RESPONSE_TEXT = "<html><body>Sorry could not login</body></html>"; + + protected void doGet( HttpServletRequest req, HttpServletResponse resp ) throws ServletException, IOException { + resp.setContentType( "text/html" ); + PrintWriter pw = resp.getWriter(); + pw.print( RESPONSE_TEXT ); + pw.close(); + } + } //=============================================================================================================== |
From: Russell G. <rus...@us...> - 2001-11-26 14:20:16
|
Update of /cvsroot/httpunit/httpunit/src/com/meterware/servletunit In directory usw-pr-cvs1:/tmp/cvs-serv26171/src/com/meterware/servletunit Modified Files: InvocationContext.java ServletRunner.java ServletUnitClient.java ServletUnitHttpRequest.java ServletUnitHttpSession.java ServletUnitServletConfig.java ServletUnitServletContext.java Added Files: BasicAuthenticationRequiredException.java WebApplication.java Log Message: Add support for authentication and servlet initialization params ***** Error reading new file[Errno 2] No such file or directory: 'BasicAuthenticationRequiredException.java' ***** Error reading new file[Errno 2] No such file or directory: 'WebApplication.java' Index: InvocationContext.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/src/com/meterware/servletunit/InvocationContext.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- InvocationContext.java 2001/11/12 19:48:35 1.2 +++ InvocationContext.java 2001/11/26 14:20:12 1.3 @@ -21,9 +21,13 @@ *******************************************************************************************************************/ import com.meterware.httpunit.WebRequest; import com.meterware.httpunit.WebResponse; +import com.meterware.httpunit.Base64; +import com.meterware.httpunit.HttpException; import java.net.MalformedURLException; import java.net.URL; +import java.io.IOException; +import java.util.Dictionary; import javax.servlet.Servlet; import javax.servlet.ServletException; @@ -62,13 +66,39 @@ **/ public Servlet getServlet() throws ServletException { if (_servlet == null) { - _servlet = _runner.getServlet( _requestURL ); - _servlet.init( new ServletUnitServletConfig( _servlet ) ); + if (!_application.requiresAuthorization( _requestURL ) || userIsAuthorized() ) { + _servlet = _application.getServlet( _requestURL ); + } else if (_request.getRemoteUser() != null) { + throw new AccessDeniedException( _requestURL ); + } else if (_application.usesBasicAuthentication()) { + throw new BasicAuthenticationRequiredException( _application.getAuthenticationRealm() ); + } else if (_application.usesFormAuthentication()) { + _servlet = _application.getServlet( _application.getLoginURL() ); + ((ServletUnitHttpRequest) getRequest()).setOriginalURL( _requestURL ); + } else { + throw new IllegalStateException( "Authorization required but no authentication method defined" ); + } } return _servlet; } + private boolean userIsAuthorized() { + final String[] roles = _request.getRoles(); + for (int i = 0; i < roles.length; i++) { + if (_application.roleMayAccess( roles[i], _requestURL )) return true; + } + return false; + } + + + class AccessDeniedException extends HttpException { + public AccessDeniedException( URL baseURL ) { + super( 403, "Access Denied", baseURL ); + } + } + + /** * Returns the final response from the servlet. Note that this method should * only be invoked after all processing has been done to the servlet response. @@ -92,14 +122,17 @@ * Constructs a servlet invocation context for a specified servlet container, * request, and cookie headers. **/ - InvocationContext( ServletRunner runner, WebRequest request, Cookie[] cookies ) throws MalformedURLException { - _runner = runner; - _requestURL = request.getURL(); - _target = request.getTarget(); + InvocationContext( ServletRunner runner, WebRequest request, Cookie[] cookies, Dictionary clientHeaders ) throws IOException, MalformedURLException { + _application = runner._application; + _requestURL = request.getURL(); + _target = request.getTarget(); - _request = new ServletUnitHttpRequest( request, runner.getContext() ); + _request = new ServletUnitHttpRequest( request, runner.getContext(), clientHeaders ); for (int i = 0; i < cookies.length; i++) _request.addCookie( cookies[i] ); - + + if (_application.usesBasicAuthentication()) _request.readBasicAuthentication(); + else if (_application.usesFormAuthentication()) _request.readFormAuthentication(); + HttpSession session = _request.getSession( /* create */ false ); if (session != null) ((ServletUnitHttpSession) session).access(); } @@ -113,7 +146,7 @@ //------------------------------ private members --------------------------------------- - private ServletRunner _runner; + private WebApplication _application; private ServletUnitHttpRequest _request; private ServletUnitHttpResponse _response = new ServletUnitHttpResponse(); private URL _requestURL; Index: ServletRunner.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/src/com/meterware/servletunit/ServletRunner.java,v retrieving revision 1.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- ServletRunner.java 2001/11/12 19:48:35 1.7 +++ ServletRunner.java 2001/11/26 14:20:12 1.8 @@ -28,18 +28,12 @@ import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; -import java.util.Dictionary; -import java.util.Hashtable; import javax.servlet.Servlet; +import javax.servlet.ServletException; import org.apache.xerces.parsers.DOMParser; -import org.w3c.dom.NodeList; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; - import org.xml.sax.SAXException; import org.xml.sax.InputSource; @@ -52,7 +46,9 @@ /** * Default constructor, which defines no servlets. */ - public ServletRunner() {} + public ServletRunner() { + _application = new WebApplication(); + } /** @@ -61,8 +57,7 @@ public ServletRunner( String webXMLFileSpec ) throws IOException, SAXException { DOMParser parser = new DOMParser(); parser.parse( webXMLFileSpec ); - - registerServlets( parser.getDocument() ); + _application = new WebApplication( parser.getDocument() ); } @@ -72,46 +67,15 @@ public ServletRunner( InputStream webXML ) throws IOException, SAXException { DOMParser parser = new DOMParser(); parser.parse( new InputSource( webXML ) ); - - registerServlets( parser.getDocument() ); + _application = new WebApplication( parser.getDocument() ); } - private void registerServlets( Document document ) throws SAXException { - Hashtable nameToClass = new Hashtable(); - NodeList nl = document.getElementsByTagName( "servlet" ); - for (int i = 0; i < nl.getLength(); i++) registerServletClass( nameToClass, (Element) nl.item(i) ); - nl = document.getElementsByTagName( "servlet-mapping" ); - for (int i = 0; i < nl.getLength(); i++) registerServlet( nameToClass, (Element) nl.item(i) ); - } - - - private void registerServletClass( Dictionary mapping, Element servletElement ) throws SAXException { - mapping.put( getChildNodeValue( servletElement, "servlet-name" ), - getChildNodeValue( servletElement, "servlet-class" ) ); - } - - - private void registerServlet( Dictionary mapping, Element servletElement ) throws SAXException { - registerServlet( getChildNodeValue( servletElement, "url-pattern" ), - (String) mapping.get( getChildNodeValue( servletElement, "servlet-name" ) ) ); - } - - - private String getChildNodeValue( Element root, String childNodeName ) throws SAXException { - NodeList nl = root.getElementsByTagName( childNodeName ); - if (nl.getLength() != 1) throw new SAXException( "Node <" + root.getNodeName() + "> has no child named <" + childNodeName + ">" ); - Node childNode = nl.item(0).getFirstChild(); - if (childNode == null) throw new SAXException( "No value specified for <" + childNodeName + "> node" ); - if (childNode.getNodeType() != Node.TEXT_NODE) throw new SAXException( "No text value found for <" + childNodeName + "> node" ); - return childNode.getNodeValue(); - } - /** * Registers a servlet class to be run. **/ public void registerServlet( String resourceName, String servletClassName ) { - _servlets.put( asResourceName( resourceName ), servletClassName ); + _application.registerServlet( resourceName, servletClassName ); } @@ -125,6 +89,15 @@ /** + * Returns the response from the specified servlet using GET. + * @exception SAXException thrown if there is an error parsing the response + **/ + public WebResponse getResponse( String url ) throws MalformedURLException, IOException, SAXException { + return _client.getResponse( url ); + } + + + /** * Creates and returns a new web client that communicates with this servlet runner. **/ public ServletUnitClient newClient() { @@ -135,23 +108,8 @@ //-------------------------------- package methods ------------------------------------- - Servlet getServlet( URL url ) { - String className = (String) _servlets.get( getServletName( url.getFile() ) ); - if (className == null) throw new HttpNotFoundException( url ); - - try { - Class servletClass = Class.forName( className ); - if (!Servlet.class.isAssignableFrom( servletClass )) { - throw new HttpInternalErrorException( url ); - } - return (Servlet) servletClass.newInstance(); - } catch (ClassNotFoundException e) { - throw new HttpNotFoundException( url, e ); - } catch (IllegalAccessException e) { - throw new HttpInternalErrorException( url, e ); - } catch (InstantiationException e) { - throw new HttpInternalErrorException( url, e ); - } + Servlet getServlet( URL url ) throws ServletException { + return _application.getServlet( url ); } @@ -161,31 +119,10 @@ //---------------------------- private members ------------------------------------ - - /** A mapping of resource names to servlet class names. **/ - private Hashtable _servlets = new Hashtable(); + WebApplication _application; private ServletUnitClient _client = new ServletUnitClient( this ); private ServletUnitContext _context = new ServletUnitContext(); - - - private String getServletName( String urlFile ) { - if (urlFile.indexOf( '?' ) < 0) { - return urlFile; - } else { - return urlFile.substring( 0, urlFile.indexOf( '?' ) ); - } - } - - - private String asResourceName( String rawName ) { - if (rawName.startsWith( "/" )) { - return rawName; - } else { - return "/" + rawName; - } - } - } Index: ServletUnitClient.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/src/com/meterware/servletunit/ServletUnitClient.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- ServletUnitClient.java 2001/11/08 22:07:53 1.2 +++ ServletUnitClient.java 2001/11/26 14:20:12 1.3 @@ -19,19 +19,16 @@ * DEALINGS IN THE SOFTWARE. * *******************************************************************************************************************/ +import com.meterware.httpunit.*; -import com.meterware.httpunit.HttpInternalErrorException; -import com.meterware.httpunit.WebClient; -import com.meterware.httpunit.WebRequest; -import com.meterware.httpunit.WebResponse; -import com.meterware.httpunit.GetMethodWebRequest; - import java.io.IOException; import java.net.MalformedURLException; +import java.net.URL; import java.util.StringTokenizer; import java.util.Vector; +import java.util.Hashtable; import javax.servlet.ServletException; @@ -55,7 +52,7 @@ /** * Creates and returns a new invocation context from a GET request. **/ - public InvocationContext newInvocation( String requestString ) throws MalformedURLException { + public InvocationContext newInvocation( String requestString ) throws IOException, MalformedURLException { return newInvocation( new GetMethodWebRequest( requestString ) ); } @@ -63,8 +60,8 @@ /** * Creates and returns a new invocation context to test calling of servlet methods. **/ - public InvocationContext newInvocation( WebRequest request ) throws MalformedURLException { - return new InvocationContext( _runner, request, getCookies() ); + public InvocationContext newInvocation( WebRequest request ) throws IOException, MalformedURLException { + return new InvocationContext( _runner, request, getCookies(), this.getHeaderFields() ); } @@ -94,15 +91,15 @@ * Creates a web response object which represents the response to the specified web request. **/ protected WebResponse newResponse( WebRequest request ) throws MalformedURLException,IOException { - InvocationContext invocation = newInvocation( request ); try { + InvocationContext invocation = newInvocation( request ); invocation.getServlet().service( invocation.getRequest(), invocation.getResponse() ); + return invocation.getServletResponse(); } catch (ServletException e) { throw new HttpInternalErrorException( request.getURL(), e ); } - return invocation.getServletResponse(); } @@ -110,9 +107,9 @@ private ServletRunner _runner; + + final private static Cookie[] NO_COOKIES = new Cookie[0]; - final private static Cookie[] NO_COOKIES = new Cookie[0]; - private Cookie[] getCookies() { String cookieHeader = (String) getHeaderFields().get( "Cookie" ); Index: ServletUnitHttpRequest.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/src/com/meterware/servletunit/ServletUnitHttpRequest.java,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- ServletUnitHttpRequest.java 2001/11/14 14:40:31 1.6 +++ ServletUnitHttpRequest.java 2001/11/26 14:20:12 1.7 @@ -2,7 +2,7 @@ /******************************************************************************************************************** * $Id$ * -* Copyright (c) 2000, Russell Gold +* Copyright (c) 2000-2001, Russell Gold * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated * documentation files (the "Software"), to deal in the Software without restriction, including without limitation @@ -21,17 +21,21 @@ *******************************************************************************************************************/ import com.meterware.httpunit.HttpUnitUtils; import com.meterware.httpunit.WebRequest; +import com.meterware.httpunit.WebClient; +import com.meterware.httpunit.Base64; import java.io.BufferedReader; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.MalformedURLException; +import java.net.URL; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; import java.util.StringTokenizer; import java.util.Map; +import java.util.Dictionary; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.Cookie; @@ -48,9 +52,12 @@ /** * Constructs a ServletUnitHttpRequest from a WebRequest object. **/ - ServletUnitHttpRequest( WebRequest request, ServletUnitContext context ) throws MalformedURLException { + ServletUnitHttpRequest( WebRequest request, ServletUnitContext context, Dictionary clientHeaders ) throws MalformedURLException { _request = request; _context = context; + _headers = new WebClient.HeaderDictionary(); + _headers.addEntries( clientHeaders ); + _headers.addEntries( request.getHeaders() ); if (context == null) throw new IllegalArgumentException( "Context must not be null" ); String file = request.getURL().getFile(); @@ -127,7 +134,7 @@ * You can use this method with any request header. **/ public String getHeader( String name ) { - return null; + return (String) _headers.get( name ); } @@ -194,7 +201,7 @@ * Whether the user name is sent with each subsequent request depends on the browser and type of authentication. **/ public String getRemoteUser() { - return null; + return _userName; } @@ -549,6 +556,10 @@ * If the user has not been authenticated, the method returns false. **/ public boolean isUserInRole( String role ) { + if (_roles == null) return false; + for (int i = 0; i < _roles.length; i++) { + if (role.equals( _roles[i] )) return true; + } return false; } @@ -628,18 +639,83 @@ } + void writeFormAuthentication( String userName, String password ) { + getServletSession().setUserInformation( userName, toArray( password ) ); + } + + + private ServletUnitHttpSession getServletSession() { + return (ServletUnitHttpSession) getSession(); + } + + + void readFormAuthentication() { + if (getSession( /* create */ false ) != null) { + recordAuthenticationInfo( getServletSession().getUserName(), getServletSession().getRoles() ); + } + } + + + void readBasicAuthentication() { + String authorizationHeader = (String) _headers.get( "Authorization" ); + + if (authorizationHeader != null) { + String userAndPassword = Base64.decode( authorizationHeader.substring( authorizationHeader.indexOf( ' ' ) + 1 ) ); + int colonPos = userAndPassword.indexOf( ':' ); + recordAuthenticationInfo( userAndPassword.substring( 0, colonPos ), + toArray( userAndPassword.substring( colonPos+1 ) ) ); + } + } + + private String[] toArray( String roleList ) { + StringTokenizer st = new StringTokenizer( roleList, "," ); + String[] result = new String[ st.countTokens() ]; + for (int i = 0; i < result.length; i++) { + result[i] = st.nextToken(); + } + return result; + } + + + void setOriginalURL( URL originalURL ) { + getServletSession().setOriginalURL( originalURL ); + } + + + URL getOriginalURL() { + return getServletSession().getOriginalURL(); + } + + + void recordAuthenticationInfo( String userName, String[] roles ) { + _userName = userName; + _roles = roles; + } + + + String[] getRoles() { + return _roles == null ? NO_ROLES : _roles; + } + + + //--------------------------------------------- private members ---------------------------------------------- final static private String LOOPBACK_ADDRESS = "127.0.0.1"; + final static private String[] NO_ROLES = new String[0]; + + private WebRequest _request; + private WebClient.HeaderDictionary _headers; + private ServletUnitContext _context; + private ServletUnitHttpSession _session; + private Hashtable _attributes = new Hashtable(); + private Hashtable _parameters = new Hashtable(); + private Vector _cookies = new Vector(); + private String _sessionID; - private WebRequest _request; - private ServletUnitContext _context; - private ServletUnitHttpSession _session; - private Hashtable _attributes = new Hashtable(); - private Hashtable _parameters = new Hashtable(); - private Vector _cookies = new Vector(); - private String _sessionID; + private String _userName; + private String[] _roles; final static private int STATE_INITIAL = 0; @@ -681,11 +757,11 @@ state = STATE_INITIAL; } } else if (state == STATE_INITIAL) { - name = token; + name = HttpUnitUtils.decode( token ); value = ""; state = STATE_HAVE_NAME; } else { - value = token; + value = HttpUnitUtils.decode( token ); state = STATE_HAVE_VALUE; } } @@ -696,9 +772,9 @@ private void addParameter( String name, String encodedValue ) { String[] values = (String[]) _parameters.get( name ); if (values == null) { - _parameters.put( name, new String[] { HttpUnitUtils.decode( encodedValue ) } ); + _parameters.put( name, new String[] { encodedValue } ); } else { - _parameters.put( name, extendedArray( values, HttpUnitUtils.decode( encodedValue ) ) ); + _parameters.put( name, extendedArray( values, encodedValue ) ); } } Index: ServletUnitHttpSession.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/src/com/meterware/servletunit/ServletUnitHttpSession.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- ServletUnitHttpSession.java 2001/11/14 14:40:31 1.4 +++ ServletUnitHttpSession.java 2001/11/26 14:20:12 1.5 @@ -2,7 +2,7 @@ /******************************************************************************************************************** * $Id$ * -* Copyright (c) 2000, Russell Gold +* Copyright (c) 2000-2001, Russell Gold * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated * documentation files (the "Software"), to deal in the Software without restriction, including without limitation @@ -22,6 +22,7 @@ import java.util.Date; import java.util.Enumeration; import java.util.Hashtable; +import java.net.URL; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionContext; @@ -213,22 +214,62 @@ } + URL getOriginalURL() { + return _originalURL; + } + + + void setOriginalURL( URL originalURL ) { + _originalURL = originalURL; + } + + + /** + * Sets the authenticated user information for a session. + * + * @param userName the name the user supplied when logging in + * @param roles an array of role names assigned to the user + **/ + void setUserInformation( String userName, String[] roles ) { + _userName = userName; + _roles = roles; + } + + + String getUserName() { + return _userName; + } + + + String[] getRoles() { + return _roles; + } + + //------------------------------------- private members --------------------------------------- private static int _NextID = 1; - private int _maxInactiveInterval; - private final long _creationTime = new Date().getTime(); + + private final String _id = Integer.toString( _NextID++ ); - private long _lastAccessedTime = new Date().getTime(); - private boolean _isInvalid; + private int _maxInactiveInterval; + + private long _lastAccessedTime = new Date().getTime(); + + private boolean _isInvalid; + private Hashtable _values = new Hashtable(); - private boolean _isNew = true; + private boolean _isNew = true; - private final String _id = Integer.toString( _NextID++ ); + private String _userName; + + private String[] _roles; + + private URL _originalURL; } Index: ServletUnitServletConfig.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/src/com/meterware/servletunit/ServletUnitServletConfig.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- ServletUnitServletConfig.java 2000/12/13 21:56:03 1.1 +++ ServletUnitServletConfig.java 2001/11/26 14:20:12 1.2 @@ -2,7 +2,7 @@ /******************************************************************************************************************** * $Id$ * -* Copyright (c) 2000, Russell Gold +* Copyright (c) 2000-2001, Russell Gold * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated * documentation files (the "Software"), to deal in the Software without restriction, including without limitation @@ -19,7 +19,6 @@ * DEALINGS IN THE SOFTWARE. * *******************************************************************************************************************/ - import java.util.Enumeration; import java.util.Hashtable; @@ -35,16 +34,24 @@ ServletUnitServletConfig( Servlet servlet ) { + this( servlet, NO_PARAMS ); + } + + + ServletUnitServletConfig( Servlet servlet, Hashtable initParams ) { _name = servlet.getClass().getName(); - _initParameters = new Hashtable(); + _initParameters = initParams; } +//-------------------------------------------- ServletConfig methods --------------------------------------------------- + + /** * Returns the value of the specified init parameter, or null if no such init parameter is defined. **/ public String getInitParameter( String name ) { - return null; + return (String) _initParameters.get( name ); } @@ -72,10 +79,14 @@ } +//----------------------------------------------- private members ------------------------------------------------------ + + + private final static Hashtable NO_PARAMS = new Hashtable(); + private String _name; private Hashtable _initParameters; - private ServletContext _context = new ServletUnitServletContext(); } Index: ServletUnitServletContext.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/src/com/meterware/servletunit/ServletUnitServletContext.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- ServletUnitServletContext.java 2001/11/14 14:40:31 1.4 +++ ServletUnitServletContext.java 2001/11/26 14:20:12 1.5 @@ -41,8 +41,9 @@ /** * Returns a ServletContext object that corresponds to a specified URL on the server. * <p> - * This method allows servlets to gain access to the context for various parts of the server, and as needed obtain RequestDispatcher - * objects from the context. The given path must be absolute (beginning with "/") and is interpreted based on the server's document root. + * This method allows servlets to gain access to the context for various parts of the server, + * and as needed obtain RequestDispatcher objects from the context. The given path must be + * absolute (beginning with "/") and is interpreted based on the server's document root. * <p> * In a security conscious environment, the servlet container may return null for a given URL. **/ @@ -62,10 +63,10 @@ /** * Returns the minor version of the Servlet API that this servlet container supports. - * All implementations that comply with Version 2.3 must have this method return the integer 2. + * All implementations that comply with Version 2.3 must have this method return the integer 3. **/ public int getMinorVersion() { - return 2; + return 3; } |
From: Russell G. <rus...@us...> - 2001-11-26 14:20:15
|
Update of /cvsroot/httpunit/httpunit/test/com/meterware/httpunit In directory usw-pr-cvs1:/tmp/cvs-serv26171/test/com/meterware/httpunit Modified Files: PseudoServerTest.java Log Message: Add support for authentication and servlet initialization params Index: PseudoServerTest.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/test/com/meterware/httpunit/PseudoServerTest.java,v retrieving revision 1.17 retrieving revision 1.18 diff -u -r1.17 -r1.18 --- PseudoServerTest.java 2001/11/12 19:47:05 1.17 +++ PseudoServerTest.java 2001/11/26 14:20:13 1.18 @@ -126,6 +126,13 @@ } + public void testHeaderFields() throws Exception { + WebConversation wc = new WebConversation(); + wc.setHeaderField( "user-agent", "Mozilla 6" ); + assertEquals( "Mozilla 6", wc.getUserAgent() ); + } + + public void testSimpleGet() throws Exception { String resourceName = "something/interesting"; String resourceValue = "the desired content"; |
From: Russell G. <rus...@us...> - 2001-11-26 14:20:15
|
Update of /cvsroot/httpunit/httpunit/src/com/meterware/httpunit In directory usw-pr-cvs1:/tmp/cvs-serv26171/src/com/meterware/httpunit Modified Files: AuthorizationRequiredException.java Base64.java HttpException.java MessageBodyWebRequest.java PostMethodWebRequest.java PutMethodWebRequest.java WebClient.java WebConversation.java WebForm.java WebLink.java WebRequest.java Log Message: Add support for authentication and servlet initialization params Index: AuthorizationRequiredException.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/src/com/meterware/httpunit/AuthorizationRequiredException.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- AuthorizationRequiredException.java 2001/11/09 18:35:14 1.4 +++ AuthorizationRequiredException.java 2001/11/26 14:20:12 1.5 @@ -29,7 +29,7 @@ public class AuthorizationRequiredException extends RuntimeException { - AuthorizationRequiredException( String wwwAuthenticateHeader ) throws IOException { + AuthorizationRequiredException( String wwwAuthenticateHeader ) { final int index = wwwAuthenticateHeader.indexOf( ' ' ); if (index < 0) { // non-conforming header _scheme = "Basic"; @@ -38,8 +38,23 @@ _scheme = wwwAuthenticateHeader.substring( 0, index ); _params = wwwAuthenticateHeader.substring( index+1 ); } - _properties = new Properties(); - _properties.load( new ByteArrayInputStream( _params.getBytes() ) ); + loadProperties(); + } + + + private void loadProperties() { + try { + _properties = new Properties(); + _properties.load( new ByteArrayInputStream( _params.getBytes() ) ); + } catch (IOException e) { + } + } + + + protected AuthorizationRequiredException( String scheme, String params ) { + _scheme = scheme; + _params = params; + loadProperties(); } Index: Base64.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/src/com/meterware/httpunit/Base64.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- Base64.java 2000/09/01 14:54:03 1.1 +++ Base64.java 2001/11/26 14:20:12 1.2 @@ -19,7 +19,7 @@ * DEALINGS IN THE SOFTWARE. * *******************************************************************************************************************/ -class Base64 { +public class Base64 { final static String encodingChar = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; Index: HttpException.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/src/com/meterware/httpunit/HttpException.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- HttpException.java 2001/11/09 18:35:14 1.4 +++ HttpException.java 2001/11/26 14:20:12 1.5 @@ -30,12 +30,12 @@ public class HttpException extends RuntimeException { - HttpException( int responseCode ) { + protected HttpException( int responseCode ) { _responseCode = responseCode; } - HttpException( int responseCode, String responseMessage, URL baseURL ) { + protected HttpException( int responseCode, String responseMessage, URL baseURL ) { _responseMessage = responseMessage; _responseCode = responseCode; _url = baseURL; Index: MessageBodyWebRequest.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/src/com/meterware/httpunit/MessageBodyWebRequest.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- MessageBodyWebRequest.java 2001/06/06 13:25:33 1.2 +++ MessageBodyWebRequest.java 2001/11/26 14:20:12 1.3 @@ -42,7 +42,7 @@ * request. **/ abstract - protected MessageBody newMessageBody(); + protected MessageBody getMessageBody(); //---------------------------------- WebRequest methods -------------------------------- @@ -56,12 +56,15 @@ connection.setDoInput( true ); connection.setDoOutput( true ); - MessageBody mb = newMessageBody(); - connection.setRequestProperty( "Content-type", mb.getContentType() ); OutputStream stream = connection.getOutputStream(); - mb.writeTo( stream ); + getMessageBody().writeTo( stream ); stream.flush(); stream.close(); + } + + + protected String getContentType() { + return getMessageBody().getContentType(); } Index: PostMethodWebRequest.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/src/com/meterware/httpunit/PostMethodWebRequest.java,v retrieving revision 1.18 retrieving revision 1.19 diff -u -r1.18 -r1.19 --- PostMethodWebRequest.java 2001/11/09 18:35:14 1.18 +++ PostMethodWebRequest.java 2001/11/26 14:20:12 1.19 @@ -134,14 +134,12 @@ //----------------------------- MessageBodyWebRequest methods --------------------------- - protected MessageBody newMessageBody() { - if (_body != null) { - return _body; - } else if (isMimeEncoded()) { - return new MimeEncodedMessageBody( this ); - } else { - return new URLEncodedMessageBody( this ); + protected MessageBody getMessageBody() { + if (_body == null) { + _body = isMimeEncoded() ? (MessageBody) new MimeEncodedMessageBody( this ) + : (MessageBody) new URLEncodedMessageBody( this ); } + return _body; } Index: PutMethodWebRequest.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/src/com/meterware/httpunit/PutMethodWebRequest.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- PutMethodWebRequest.java 2001/06/06 13:25:33 1.2 +++ PutMethodWebRequest.java 2001/11/26 14:20:12 1.3 @@ -60,7 +60,7 @@ /** * Returns a message body based on the input stream. **/ - protected MessageBody newMessageBody() { + protected MessageBody getMessageBody() { return _body; } Index: WebClient.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/src/com/meterware/httpunit/WebClient.java,v retrieving revision 1.11 retrieving revision 1.12 diff -u -r1.11 -r1.12 --- WebClient.java 2001/11/12 19:48:35 1.11 +++ WebClient.java 2001/11/26 14:20:12 1.12 @@ -125,8 +125,8 @@ /** * Specifies the user agent identification. Used to trigger browser-specific server behavior. **/ - public void setUserAgent(String userAgent) { - setHeaderField( "User-Agent", userAgent ); + public void setUserAgent( String userAgent ) { + setHeaderField( "User-Agent", userAgent ); } @@ -134,7 +134,7 @@ * Returns the current user agent setting. **/ public String getUserAgent() { - return (String) _headers.get( "User-Agent" ); + return getHeaderField( "User-Agent" ); } @@ -151,25 +151,15 @@ * removes the header from those to be sent. **/ public void setHeaderField( String fieldName, String fieldValue ) { - fieldName = matchPreviousFieldName( fieldName ); - if (fieldValue == null) { - _headers.remove( fieldName ); - } else { - _headers.put( fieldName, fieldValue ); - } + _headers.put( fieldName, fieldValue ); } /** - * If a matching field name with different case is already known, returns the older name. - * Otherwise, returns the specified name. - **/ - private String matchPreviousFieldName( String fieldName ) { - for (Enumeration e = _headers.keys(); e.hasMoreElements(); ) { - String key = (String) e.nextElement(); - if (key.equalsIgnoreCase( fieldName )) return key; - } - return fieldName; + * Returns the value for the header field with the specified name. This method will ignore the case of the field name. + */ + public String getHeaderField( String fieldName ) { + return (String) _headers.get( fieldName ); } @@ -245,7 +235,7 @@ /** A map of header names to values. **/ - private Hashtable _headers = new Hashtable(); + private HeaderDictionary _headers = new HeaderDictionary(); /** @@ -317,6 +307,50 @@ _frameContents.remove( names[i] ); _subFrames.remove( names[i] ); } + } + +//================================================================================================== + + + static public class HeaderDictionary extends Hashtable { + + public void addEntries( Dictionary source ) { + for (Enumeration e = source.keys(); e.hasMoreElements(); ) { + Object key = e.nextElement(); + put( key, source.get( key ) ); + } + } + + public Object get( Object fieldName ) { + return (String) super.get( matchPreviousFieldName( fieldName.toString() ) ); + } + + + public Object put( Object fieldName, Object fieldValue ) { + fieldName = matchPreviousFieldName( fieldName.toString() ); + Object oldValue = super.get( fieldName ); + if (fieldValue == null) { + remove( fieldName ); + } else { + super.put( fieldName, fieldValue ); + } + return oldValue; + } + + + /** + * If a matching field name with different case is already known, returns the older name. + * Otherwise, returns the specified name. + **/ + private String matchPreviousFieldName( String fieldName ) { + for (Enumeration e = keys(); e.hasMoreElements(); ) { + String key = (String) e.nextElement(); + if (key.equalsIgnoreCase( fieldName )) return key; + } + return fieldName; + } + + } } Index: WebConversation.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/src/com/meterware/httpunit/WebConversation.java,v retrieving revision 1.22 retrieving revision 1.23 diff -u -r1.22 -r1.23 --- WebConversation.java 2001/06/06 13:25:04 1.22 +++ WebConversation.java 2001/11/26 14:20:12 1.23 @@ -55,7 +55,7 @@ **/ protected WebResponse newResponse( WebRequest request ) throws MalformedURLException, IOException { URLConnection connection = openConnection( request.getURL() ); - sendHeaders( connection, request.getHeaders() ); + sendHeaders( connection, request.getHeaderDictionary() ); if (HttpUnitOptions.isLoggingHttpHeaders()) { for (Enumeration e = getHeaderFields().keys(); e.hasMoreElements(); ) { String key = (String) e.nextElement(); Index: WebForm.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/src/com/meterware/httpunit/WebForm.java,v retrieving revision 1.31 retrieving revision 1.32 diff -u -r1.31 -r1.32 --- WebForm.java 2001/11/12 19:48:35 1.31 +++ WebForm.java 2001/11/26 14:20:12 1.32 @@ -303,7 +303,7 @@ } } } - result.setRequestHeader( "Referer", getBaseURL().toExternalForm() ); + result.setHeaderField( "Referer", getBaseURL().toExternalForm() ); return result; } Index: WebLink.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/src/com/meterware/httpunit/WebLink.java,v retrieving revision 1.11 retrieving revision 1.12 diff -u -r1.11 -r1.12 --- WebLink.java 2001/11/09 18:35:14 1.11 +++ WebLink.java 2001/11/26 14:20:12 1.12 @@ -43,7 +43,7 @@ public WebRequest getRequest() { WebRequest request = new GetMethodWebRequest( getBaseURL(), getBareURL(), getTarget() ); addPresetParameters( request ); - request.setRequestHeader( "Referer", getBaseURL().toExternalForm() ); + request.setHeaderField( "Referer", getBaseURL().toExternalForm() ); return request; } Index: WebRequest.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/src/com/meterware/httpunit/WebRequest.java,v retrieving revision 1.29 retrieving revision 1.30 diff -u -r1.29 -r1.30 --- WebRequest.java 2001/11/12 19:48:35 1.29 +++ WebRequest.java 2001/11/26 14:20:12 1.30 @@ -47,6 +47,22 @@ /** + * Sets the value of a header to be sent with this request. A header set here will override any matching header set + * in the WebClient when the request is actually sent. + */ + public void setHeaderField( String headerName, String headerValue ) { + getHeaderDictionary().put( headerName, headerValue ); + } + + /** + * Returns a copy of the headers to be sent with this request. + **/ + public Dictionary getHeaders() { + return (Dictionary) getHeaderDictionary().clone(); + } + + + /** * Sets the value of a parameter in a web request. **/ public void setParameter( String name, String value ) { @@ -274,6 +290,14 @@ /** + * Returns the content type of this request. If null, no content is specified. + */ + protected String getContentType() { + return null; + } + + + /** * Returns the character set required for this request. **/ final @@ -341,12 +365,11 @@ } - void setRequestHeader( String headerName, String headerValue ) { - _headers.put( headerName, headerValue ); - } - - - Dictionary getHeaders() { + Hashtable getHeaderDictionary() { + if (_headers == null) { + _headers = new Hashtable(); + if (getContentType() != null) _headers.put( "Content-Type", getContentType() ); + } return _headers; } @@ -445,7 +468,7 @@ private WebForm _sourceForm; private String _imageButtonName; private String _target = TOP_FRAME; - private Hashtable _headers = new Hashtable(); + private Hashtable _headers; private boolean _httpsProtocolSupportEnabled; |
From: Russell G. <rus...@us...> - 2001-11-26 14:20:14
|
Update of /cvsroot/httpunit/httpunit/doc In directory usw-pr-cvs1:/tmp/cvs-serv26171/doc Modified Files: release_notes.txt Log Message: Add support for authentication and servlet initialization params Index: release_notes.txt =================================================================== RCS file: /cvsroot/httpunit/httpunit/doc/release_notes.txt,v retrieving revision 1.68 retrieving revision 1.69 diff -u -r1.68 -r1.69 --- release_notes.txt 2001/11/14 17:11:28 1.68 +++ release_notes.txt 2001/11/26 14:20:12 1.69 @@ -13,6 +13,16 @@ Revision History: +22-Nov-2001 +Additions: + 1. ServletUnit now handles protected URLs defined in web.xml, along with both Basic and Form authentication. Logins + with non-blank usernames are also accepted, with the password being interpreted as a comma-separated list of + role names. + 2. ServletUnit now handles servlet initialization parameters defined in web.xml + +Problems fixed: + 1. ServletUnit now handles URL-encoded parameter names properly. + 14-Nov-2001 Acknowledgements: Thanks to Benoit Xhenseval for adding a mechanism to handle HTML parser errors. |
From: Russell G. <rus...@us...> - 2001-11-26 14:19:29
|
Update of /cvsroot/httpunit/httpunit/doc/tutorial In directory usw-pr-cvs1:/tmp/cvs-serv25855 Modified Files: index.html task1.html task1editor-entry.html task1editor-form.html task1editor-initial.html task1editor-validation.html tutorial.css Added Files: arrow_yellow.gif task2.html Log Message: Add tutorial navigation --- NEW FILE --- GIF89a çiJ(I©®1Ê1 <ö<tR --- NEW FILE --- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>HttpUnit Tutorial - control application access</title> <LINK REL="stylesheet" HREF="tutorial.css" TYPE="text/css"> </head> <body> <p class="location"><a href="index.html">Tutorial</a> <img src="arrow_yellow.gif" width=13 height=9 align=bottom ALT="->">Task 2</p> <h1>Controlling access to the application</h1> <p>Only the administrator is supposed to be able to edit the pool, but there is nothing in the code written so far which enforces it. The servlet API provides ways to restrict application to servlets. As part of this task, we will use the Basic Authentication approach, which causes the browser to pop up a challenge dialog. The more common form-based authentication is handled the same way that all forms should be. In addition, we will create a front-end page with links to those pages a user is permitted to access. To begin the tutorial, create a working directory and expand <a href="task2.zip">this archive</a> into it. Either create a jars directory and copy httpunit.jar, Tidy.jar, and xerces.jar into it, or make sure that they are on your classpath and invoke ant passing the classpath as a property. You will write your code in the src/tutorial sub-directory. Once you are ready, proceed to <a href="task2access-authentication.html">step one</a> to begin the tutorial. Index: index.html =================================================================== RCS file: /cvsroot/httpunit/httpunit/doc/tutorial/index.html,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- index.html 2001/11/12 20:43:51 1.1 +++ index.html 2001/11/26 14:19:26 1.2 @@ -54,12 +54,17 @@ <h2>Tutorial Organization</h2> -Each section of the tutorial will address a specific use of the system, and show how HttpUnit and ServletUnit can be used +<p>Each section of the tutorial will address a specific use of the system, and show how HttpUnit and ServletUnit can be used to write tests which verify that functionality. You should begin each section by copying the initial directory, which includes an ant build script and some classes that you will need to complete it. Running the ant script will compile the code and -run the tests. After you implement each test, it should fail until you then add the implementation. +run the tests. After you implement each test, it should fail until you then add the implementation.</p> +<p>Tasks</p> +<ul> +<li><a href="task1.html">Task 1: Create the pool editor</a> +<li><a href="task2.html">Task 2: Control access to the application</a> +</ul> Index: task1.html =================================================================== RCS file: /cvsroot/httpunit/httpunit/doc/tutorial/task1.html,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- task1.html 2001/11/12 20:43:51 1.1 +++ task1.html 2001/11/26 14:19:26 1.2 @@ -6,6 +6,8 @@ </head> <body> +<p class="location"><a href="index.html">Tutorial</a> +<img src="arrow_yellow.gif" width=13 height=9 align=bottom ALT="->">Task 1</p> <h1>Creating the Pool Editor</h1> <p>Our initial task will be the creation of the simple pool editor, following use case 1.1. We will ignore security restrictions that permit only the administrator to access this page. Index: task1editor-entry.html =================================================================== RCS file: /cvsroot/httpunit/httpunit/doc/tutorial/task1editor-entry.html,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- task1editor-entry.html 2001/11/12 20:43:51 1.1 +++ task1editor-entry.html 2001/11/26 14:19:26 1.2 @@ -5,7 +5,11 @@ <LINK REL="stylesheet" HREF="tutorial.css" TYPE="text/css"> </head> -<body><h1>Submitting a Form</h1> +<body> +<p class="location"><a href="index.html">Tutorial</a> +<img src="arrow_yellow.gif" width=13 height=9 align=bottom ALT="->"> <a href="task1.html">Task 1</a> +<img src="arrow_yellow.gif" width=13 height=9 align=bottom ALT="->"> Step 3: Submitting edits</p> +<h1>Submitting a Form</h1> <p class="goals">In this step, you will learn how to: <br />• Check form default parameter values <br />• Create a request from a form Index: task1editor-form.html =================================================================== RCS file: /cvsroot/httpunit/httpunit/doc/tutorial/task1editor-form.html,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- task1editor-form.html 2001/11/12 20:43:51 1.1 +++ task1editor-form.html 2001/11/26 14:19:26 1.2 @@ -6,6 +6,9 @@ </head> <body> +<p class="location"><a href="index.html">Tutorial</a> +<img src="arrow_yellow.gif" width=13 height=9 align=bottom ALT="->"> <a href="task1.html">Task 1</a> +<img src="arrow_yellow.gif" width=13 height=9 align=bottom ALT="->"> Step 2: The pool editor form</p> <h1>Examining a Form</h1> <p class="goals">In this step, you will learn how to: <br />• Extract a form from a web page, using its ID Index: task1editor-initial.html =================================================================== RCS file: /cvsroot/httpunit/httpunit/doc/tutorial/task1editor-initial.html,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- task1editor-initial.html 2001/11/12 20:43:51 1.1 +++ task1editor-initial.html 2001/11/26 14:19:26 1.2 @@ -6,6 +6,10 @@ </head> <body> +<p class="location"><a href="index.html">Tutorial</a> +<img src="arrow_yellow.gif" width=13 height=9 align=bottom ALT="->"> <a href="task1.html">Task 1</a> +<img src="arrow_yellow.gif" width=13 height=9 align=bottom ALT="->"> Step 1: Invoking the pool editor</p> + <h1>Invoking the Pool Editor</h1> <p class="goals">In this step, you will learn how to:<br />• Initialize ServletUnit<br />• Invoke a servlet</p> <p>The first step will simply be to verify that we can register Index: task1editor-validation.html =================================================================== RCS file: /cvsroot/httpunit/httpunit/doc/tutorial/task1editor-validation.html,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- task1editor-validation.html 2001/11/12 20:43:51 1.1 +++ task1editor-validation.html 2001/11/26 14:19:26 1.2 @@ -5,6 +5,9 @@ </head> <body> +<p class="location"><a href="index.html">Tutorial</a> +<img src="arrow_yellow.gif" width=13 height=9 align=bottom ALT="->"> <a href="task1.html">Task 1</a> +<img src="arrow_yellow.gif" width=13 height=9 align=bottom ALT="->"> Step 4: Validating data entry</p> <h1>Testing servlet internals</h1> <p class="goals">In this step, you will learn how to: <br />• Access a servlet directly during an invocation @@ -206,6 +209,6 @@ } } </pre> -<p>The pool editor is now complete.</p> +<p>The pool editor is now complete. In the <a href="task2.html">next task</a>, you will address access to the application.</p> </body></html> Index: tutorial.css =================================================================== RCS file: /cvsroot/httpunit/httpunit/doc/tutorial/tutorial.css,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- tutorial.css 2001/11/12 20:43:51 1.1 +++ tutorial.css 2001/11/26 14:19:26 1.2 @@ -1,13 +1,17 @@ -PRE { font-family: "courier new", courier; font-size: .75em; +PRE { font-family: "courier new", courier; font-size: 8pt; margin-left: 2%; margin-right: 2%; padding-top: .5em; padding-bottom: .5em; padding-right: .5em; padding-left: .5em; border-color: black; border-width: 2; border-style: solid } PRE.test-code { background-color: #cccccc } -PRE.servlet-code { background-color: #00eeee } +PRE.servlet-code { background-color: #cceeee } OL { margin-top: 0 } P.story-name { margin-left: 3em; margin-bottom: 0; font-weight: bold } P.story-contents { margin-left: 3em; margin-top: 0 } P.goals { font-family: helvetica, ariel, sans-serif; font-size: x-small; - background-color: yellow; border-color: black; border-style: solid; + background-color: #ffffdd; border-color: black; border-style: solid; border-top-width: 2px; border-bottom-width: 2px; border-left-width: 0px; border-right-width: 0px } +P.location { font-family: helvetica, ariel, sans-serif; font-size: x-small; + background-color: #ffff66; border-color: #dddddd; border-style: solid; + padding-bottom: 4px; padding-left: 4px; padding-top: 4px; + border-top-width: 0px; border-bottom-width: 2px; border-left-width: 0px; border-right-width: 0px } UL { margin-top: 0 } |
From: Russell G. <rus...@us...> - 2001-11-14 17:28:28
|
Update of /cvsroot/httpunit/httpunit/test/com/meterware/httpunit In directory usw-pr-cvs1:/tmp/cvs-serv1796/test/com/meterware/httpunit Modified Files: WebPageTest.java WebResource.java Log Message: Handle quoted character set names Index: WebPageTest.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/test/com/meterware/httpunit/WebPageTest.java,v retrieving revision 1.18 retrieving revision 1.19 diff -u -r1.18 -r1.19 --- WebPageTest.java 2001/10/26 15:41:04 1.18 +++ WebPageTest.java 2001/11/14 17:28:25 1.19 @@ -142,6 +142,23 @@ } + public void testQuotedEncoding() throws Exception { + String hebrewTitle = "\u05d0\u05d1\u05d2\u05d3"; + String page = "<html><head><title>" + hebrewTitle + "</title></head>\n" + + "<body>This has no data\n" + + "</body></html>\n"; + defineResource( "SimplePage.html", page ); + setResourceCharSet( "SimplePage.html", "\"iso-8859-8\"", true ); + + WebConversation wc = new WebConversation(); + WebRequest request = new GetMethodWebRequest( getHostPath() + "/SimplePage.html" ); + WebResponse simplePage = wc.getResponse( request ); + + assertEquals( "Title", hebrewTitle, simplePage.getTitle() ); + assertEquals( "Character set", "iso-8859-8", simplePage.getCharacterSet() ); + } + + public void testUnspecifiedEncoding() throws Exception { String hebrewTitle = "\u05d0\u05d1\u05d2\u05d3"; String page = "<html><head><title>" + hebrewTitle + "</title></head>\n" + Index: WebResource.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/test/com/meterware/httpunit/WebResource.java,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- WebResource.java 2001/11/09 18:35:14 1.6 +++ WebResource.java 2001/11/14 17:28:25 1.7 @@ -105,7 +105,7 @@ String getCharacterSet() { - return _characterSet; + return HttpUnitUtils.stripQuotes( _characterSet ); } |
From: Russell G. <rus...@us...> - 2001-11-14 17:28:28
|
Update of /cvsroot/httpunit/httpunit/src/com/meterware/httpunit In directory usw-pr-cvs1:/tmp/cvs-serv1796/src/com/meterware/httpunit Modified Files: HttpUnitUtils.java Log Message: Handle quoted character set names Index: HttpUnitUtils.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/src/com/meterware/httpunit/HttpUnitUtils.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- HttpUnitUtils.java 2001/11/08 22:07:52 1.3 +++ HttpUnitUtils.java 2001/11/14 17:28:25 1.4 @@ -37,11 +37,17 @@ while (st.hasMoreTokens()) { String parameter = st.nextToken(); if (st.hasMoreTokens()) { - String value = st.nextToken(); + String value = stripQuotes( st.nextToken() ); if (parameter.trim().equalsIgnoreCase( "charset" )) result[1] = value; } } return result; + } + + static String stripQuotes( String value ) { + if (value.startsWith( "'" ) || value.startsWith( "\"" )) value = value.substring( 1 ); + if (value.endsWith( "'" ) || value.endsWith( "\"" )) value = value.substring( 0, value.length()-1 ); + return value; } /** |
From: Russell G. <rus...@us...> - 2001-11-14 17:11:37
|
Update of /cvsroot/httpunit/httpunit/test/com/meterware/httpunit In directory usw-pr-cvs1:/tmp/cvs-serv28150/test/com/meterware/httpunit Modified Files: HttpUnitSuite.java Added Files: JTidyPrintWriterTest.java Log Message: Benoit Xhenseval: added callbacks for HTML error detection ***** Error reading new file[Errno 2] No such file or directory: 'JTidyPrintWriterTest.java' Index: HttpUnitSuite.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/test/com/meterware/httpunit/HttpUnitSuite.java,v retrieving revision 1.15 retrieving revision 1.16 diff -u -r1.15 -r1.16 --- HttpUnitSuite.java 2001/11/09 18:35:14 1.15 +++ HttpUnitSuite.java 2001/11/14 17:11:29 1.16 @@ -47,6 +47,7 @@ result.addTest( Base64Test.suite() ); result.addTest( PseudoServerTest.suite() ); result.addTest( MessageBodyRequestTest.suite() ); + result.addTest( JTidyPrintWriterTest.suite() ); addOptionalTestCase( result, "com.meterware.httpunit.XMLPageTest" ); addOptionalTestCase( result, "com.meterware.httpunit.FileUploadTest" ); return result; |
From: Russell G. <rus...@us...> - 2001-11-14 17:11:34
|
Update of /cvsroot/httpunit/httpunit/src/com/meterware/httpunit In directory usw-pr-cvs1:/tmp/cvs-serv28150/src/com/meterware/httpunit Modified Files: HttpUnitOptions.java ReceivedPage.java Added Files: HtmlErrorListener.java JTidyPrintWriter.java Log Message: Benoit Xhenseval: added callbacks for HTML error detection ***** Error reading new file[Errno 2] No such file or directory: 'HtmlErrorListener.java' ***** Error reading new file[Errno 2] No such file or directory: 'JTidyPrintWriter.java' Index: HttpUnitOptions.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/src/com/meterware/httpunit/HttpUnitOptions.java,v retrieving revision 1.12 retrieving revision 1.13 diff -u -r1.12 -r1.13 --- HttpUnitOptions.java 2001/11/09 18:35:14 1.12 +++ HttpUnitOptions.java 2001/11/14 17:11:28 1.13 @@ -4,12 +4,12 @@ * * Copyright (c) 2000-2001, Russell Gold * -* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated -* documentation files (the "Software"), to deal in the Software without restriction, including without limitation +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +* documentation files (the "Software"), to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and * to permit persons to whom the Software is furnished to do so, subject to the following conditions: * -* The above copyright notice and this permission notice shall be included in all copies or substantial portions +* The above copyright notice and this permission notice shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO @@ -20,15 +20,16 @@ * *******************************************************************************************************************/ +import java.util.Vector; /** * A collection of global options to control HttpUnit's behavior. * * @author <a href="mailto:rus...@ac...">Russell Gold</a> * @author <a href="mailto:dg...@ss...">Dave Glowacki</a> + * @author <a href="mailto:bx...@bi...">Benoit Xhenseval</a> **/ -abstract -public class HttpUnitOptions { +public abstract class HttpUnitOptions { /** * Resets all options to their default values. @@ -238,7 +239,7 @@ /** - * Returns true if HttpUnit should automatically follow page refresh requests. + * Returns true if HttpUnit should automatically follow page refresh requests. * By default, this is false, so that programs can verify the redirect page presented * to users before the browser switches to the new page. **/ @@ -248,7 +249,7 @@ /** - * Specifies whether HttpUnit should automatically follow page refresh requests. + * Specifies whether HttpUnit should automatically follow page refresh requests. * By default, this is false, so that programs can verify the redirect page presented * to users before the browser switches to the new page. Setting this to true can * cause an infinite loop on pages that refresh themselves. @@ -257,7 +258,27 @@ _autoRefresh = autoRefresh; } + /** + * Remove an Html error listener. + **/ + public static void removeHtmlErrorListener(HtmlErrorListener el) { + _listeners.removeElement(el); + } + + /** + * Add an Html error listener. + **/ + public static void addHtmlErrorListener(HtmlErrorListener el) { + _listeners.addElement(el); + } + /** + * Get the list of Html Error Listeners + **/ + public static Vector getHtmlErrorListeners() { + return _listeners; + } + //--------------------------------- private members -------------------------------------- @@ -286,5 +307,10 @@ private static String _characterSet = DEFAULT_CHARACTER_SET; private static String _contentType = DEFAULT_CONTENT_TYPE; -} + private static Vector _listeners; + + static { + _listeners = new Vector(); + } +} Index: ReceivedPage.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/src/com/meterware/httpunit/ReceivedPage.java,v retrieving revision 1.16 retrieving revision 1.17 diff -u -r1.16 -r1.17 --- ReceivedPage.java 2001/11/09 18:35:14 1.16 +++ ReceivedPage.java 2001/11/14 17:11:28 1.17 @@ -44,7 +44,7 @@ public ReceivedPage( URL url, String parentTarget, String pageText, String characterSet ) throws SAXException { - super( url, parentTarget, getDOM( pageText ), characterSet ); + super( url, parentTarget, getDOM( url, pageText ), characterSet ); setBaseAttributes(); } @@ -108,9 +108,9 @@ } - private static Node getDOM( String pageText ) throws SAXException { + private static Node getDOM( URL url, String pageText ) throws SAXException { try { - return getParser().parseDOM( new ByteArrayInputStream( pageText.getBytes( getUTFEncodingName() ) ), null ); + return getParser( url ).parseDOM( new ByteArrayInputStream( pageText.getBytes( getUTFEncodingName() ) ), null ); } catch (UnsupportedEncodingException e) { throw new RuntimeException( "UTF-8 encoding failed" ); } @@ -154,11 +154,14 @@ } - private static Tidy getParser() { + private static Tidy getParser( URL url ) { Tidy tidy = new Tidy(); tidy.setCharEncoding( org.w3c.tidy.Configuration.UTF8 ); tidy.setQuiet( true ); tidy.setShowWarnings( HttpUnitOptions.getParserWarningsEnabled() ); + if (!HttpUnitOptions.getHtmlErrorListeners().isEmpty()) { + tidy.setErrout(new JTidyPrintWriter( url )); + } return tidy; } |
From: Russell G. <rus...@us...> - 2001-11-14 17:11:33
|
Update of /cvsroot/httpunit/httpunit/doc In directory usw-pr-cvs1:/tmp/cvs-serv28150/doc Modified Files: release_notes.txt Log Message: Benoit Xhenseval: added callbacks for HTML error detection Index: release_notes.txt =================================================================== RCS file: /cvsroot/httpunit/httpunit/doc/release_notes.txt,v retrieving revision 1.67 retrieving revision 1.68 diff -u -r1.67 -r1.68 --- release_notes.txt 2001/11/14 14:40:31 1.67 +++ release_notes.txt 2001/11/14 17:11:28 1.68 @@ -14,8 +14,14 @@ Revision History: 14-Nov-2001 +Acknowledgements: + Thanks to Benoit Xhenseval for adding a mechanism to handle HTML parser errors. + Additions: 1. ServletUnit now compiles against Servlet 2.3 + 2. HttpUnitOptions now has methods addHtmlErrorListener and removeHtmlErrorListener. If a listener is registered, + it will be invoked for every error or warning generated by the parser, indicating the URL, line and column number + of the error and a textual description of the problem. Problems fixed: 1. HttpUnit should now be more tolerant of missing character encodings |
From: Russell G. <rus...@us...> - 2001-11-14 14:40:35
|
Update of /cvsroot/httpunit/httpunit/src/com/meterware/servletunit In directory usw-pr-cvs1:/tmp/cvs-serv10709/src/com/meterware/servletunit Modified Files: ServletUnitHttpRequest.java ServletUnitHttpResponse.java ServletUnitHttpSession.java ServletUnitServletContext.java Log Message: Support Servlet 2.3 API Index: ServletUnitHttpRequest.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/src/com/meterware/servletunit/ServletUnitHttpRequest.java,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- ServletUnitHttpRequest.java 2001/11/12 19:48:35 1.5 +++ ServletUnitHttpRequest.java 2001/11/14 14:40:31 1.6 @@ -24,12 +24,14 @@ import java.io.BufferedReader; import java.io.IOException; +import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; import java.util.StringTokenizer; +import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.Cookie; @@ -569,7 +571,52 @@ throw new RuntimeException( "getContextPath not implemented" ); } - + +//--------------------------------------- methods added to ServletRequest in JSDK 2.3 ---------------------------- + + /** + * Returns a java.util.Map of the parameters of this request. + * Request parameters are extra information sent with the request. For HTTP servlets, parameters are contained + * in the query string or posted form data. + * + * @since 1.3 + **/ + public Map getParameterMap() { + return null; // XXX implement me! + } + + + /** + * Overrides the name of the character encoding used in the body of this request. + * This method must be called prior to reading request parameters or reading input using getReader(). + * + * @since 1.3 + **/ + public void setCharacterEncoding( String s ) throws UnsupportedEncodingException { + // XXX implement me! + } + + +//--------------------------------------- methods added to HttpServletRequest in JSDK 2.3 ---------------------------- + + + /** + * Reconstructs the URL the client used to make the request. + * The returned URL contains a protocol, server name, port number, and server path, but + * it does not include query string parameters. + * + * Because this method returns a StringBuffer, not a string, you can modify the URL easily, for example, + * to append query parameters. + * + * This method is useful for creating redirect messages and for reporting errors. + * + * @since 1.3 + */ + public StringBuffer getRequestURL() { + return null; + } + + //--------------------------------------------- package members ---------------------------------------------- Index: ServletUnitHttpResponse.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/src/com/meterware/servletunit/ServletUnitHttpResponse.java,v retrieving revision 1.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- ServletUnitHttpResponse.java 2001/11/12 19:48:35 1.7 +++ ServletUnitHttpResponse.java 2001/11/14 14:40:31 1.8 @@ -389,8 +389,21 @@ } - -//---------------------------------------- package methods --------------------------------------- +//----------------------------- methods added to ServletResponse in JSDK 2.3 -------------------------------------- + + + /** + * Clears the content of the underlying buffer in the response without clearing headers or status code. + * If the response has been committed, this method throws an IllegalStateException. + * + * @since 1.3 + */ + public void resetBuffer() { + // XXX implement me + } + + +//---------------------------------------------- package methods -------------------------------------------------- /** Index: ServletUnitHttpSession.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/src/com/meterware/servletunit/ServletUnitHttpSession.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- ServletUnitHttpSession.java 2001/11/12 19:48:35 1.3 +++ ServletUnitHttpSession.java 2001/11/14 14:40:31 1.4 @@ -25,6 +25,7 @@ import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionContext; +import javax.servlet.ServletContext; class ServletUnitHttpSession implements HttpSession { @@ -187,7 +188,19 @@ } -//------------------------------------- package members --------------------------------------- +//---------------------------- methods added to HttpSession in JSDK 2.3 ---------------------------------------- + + + /** + * Returns the ServletContext to which this session belongs. + * + * @since 1.3 + **/ + public ServletContext getServletContext() { + return null; // XXX implement me + } + +//-------------------------------------------- package members ------------------------------------------------- /** Index: ServletUnitServletContext.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/src/com/meterware/servletunit/ServletUnitServletContext.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- ServletUnitServletContext.java 2001/08/21 19:55:16 1.3 +++ ServletUnitServletContext.java 2001/11/14 14:40:31 1.4 @@ -27,6 +27,7 @@ import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; +import java.util.Set; import javax.servlet.*; @@ -52,7 +53,7 @@ /** * Returns the major version of the Java Servlet API that this servlet container supports. - * All implementations that comply with Version 2.2 must have this method return the integer 2. + * All implementations that comply with Version 2.3 must have this method return the integer 2. **/ public int getMajorVersion() { return 2; @@ -61,7 +62,7 @@ /** * Returns the minor version of the Servlet API that this servlet container supports. - * All implementations that comply with Version 2.2 must have this method return the integer 2. + * All implementations that comply with Version 2.3 must have this method return the integer 2. **/ public int getMinorVersion() { return 2; @@ -268,6 +269,51 @@ _attributes.remove( name ); } + + +//----------------------------- methods added to ServletContext in JSDK 2.3 -------------------------------------- + + /** + * Returns a directory-like listing of all the paths to resources within the web application + * whose longest sub-path matches the supplied path argument. Paths indicating subdirectory paths end with a '/'. + * The returned paths are all relative to the root of the web application and have a leading '/'. + * For example, for a web application containing + * <p> + * /welcome.html<br /> + * /catalog/index.html<br /><br /> + * /catalog/products.html<br /> + * /catalog/offers/books.html<br /> + * /catalog/offers/music.html<br /> + * /customer/login.jsp<br /> + * /WEB-INF/web.xml<br /> + * /WEB-INF/classes/com.acme.OrderServlet.class,<br /> + * <br /> + * getResourcePaths("/") returns {"/welcome.html", "/catalog/", "/customer/", "/WEB-INF/"}<br /> + * getResourcePaths("/catalog/") returns {"/catalog/index.html", "/catalog/products.html", "/catalog/offers/"}. + * + * @param path partial path used to match the resources, which must start with a / + * @return a Set containing the directory listing, or null if there are no resources + * in the web application whose path begins with the supplied path. + * @since HttpUnit 1.3 + */ + public Set getResourcePaths( String path ) { + return null; + } + + + /** + * Returns the name of this web application correponding to this ServletContext as specified + * in the deployment descriptor for this web application by the display-name element. + * + * @return The name of the web application or null if no name has been declared in the deployment descriptor + * @since HttpUnit 1.3 + */ + public String getServletContextName() { + return null; + } + + +//------------------------------------------- private members ---------------------------------------------------- private final static Vector EMPTY_VECTOR = new Vector(); private Hashtable _attributes = new Hashtable(); |
From: Russell G. <rus...@us...> - 2001-11-14 14:40:34
|
Update of /cvsroot/httpunit/httpunit/doc In directory usw-pr-cvs1:/tmp/cvs-serv10709/doc Modified Files: release_notes.txt Log Message: Support Servlet 2.3 API Index: release_notes.txt =================================================================== RCS file: /cvsroot/httpunit/httpunit/doc/release_notes.txt,v retrieving revision 1.66 retrieving revision 1.67 diff -u -r1.66 -r1.67 --- release_notes.txt 2001/11/12 19:47:05 1.66 +++ release_notes.txt 2001/11/14 14:40:31 1.67 @@ -7,9 +7,19 @@ 3. No order is guaranteed for parameters from forms, contrary to the HTML 4.01 spec 4. No parameter validation is done for requests built from links -Limitations: HttpUnit does not support JavaScript +Limitations: + 1. HttpUnit does not support JavaScript + 2. JDK 1.2 or higher is required + Revision History: +14-Nov-2001 +Additions: + 1. ServletUnit now compiles against Servlet 2.3 + +Problems fixed: + 1. HttpUnit should now be more tolerant of missing character encodings + 12-Nov-2001 Problems fixed: 1. WebSphere cookie values ending with "=" or "==" are now handled. |
From: Russell G. <rus...@us...> - 2001-11-14 14:40:13
|
Update of /cvsroot/httpunit/httpunit/src/com/meterware/httpunit In directory usw-pr-cvs1:/tmp/cvs-serv10614/src/com/meterware/httpunit Modified Files: WebResponse.java Log Message: Handle missing file encodings Index: WebResponse.java =================================================================== RCS file: /cvsroot/httpunit/httpunit/src/com/meterware/httpunit/WebResponse.java,v retrieving revision 1.53 retrieving revision 1.54 diff -u -r1.53 -r1.54 --- WebResponse.java 2001/11/12 19:47:05 1.53 +++ WebResponse.java 2001/11/14 14:40:09 1.54 @@ -182,6 +182,11 @@ readContentTypeHeader(); if (_characterSet == null) _characterSet = getHeaderField( "Charset" ); if (_characterSet == null) _characterSet = HttpUnitOptions.getDefaultCharacterSet(); + try { + "abcd".getBytes( _characterSet ); + } catch (UnsupportedEncodingException e) { + _characterSet = getDefaultEncoding(); + } } return _characterSet; } @@ -831,6 +836,25 @@ return doc; } + private static String _defaultEncoding; + + private final static String[] DEFAULT_ENCODING_CANDIDATES = { "iso-8859-1", "us-ascii", "utf-8", "utf8" }; + + static String getDefaultEncoding() { + if (_defaultEncoding == null) { + for (int i = 0; i < DEFAULT_ENCODING_CANDIDATES.length; i++) { + try { + _defaultEncoding = DEFAULT_ENCODING_CANDIDATES[i]; + "abcd".getBytes( _defaultEncoding ); + return _defaultEncoding; + } catch (UnsupportedEncodingException e) { + } + } + } + return (_defaultEncoding = System.getProperty( "file.encoding" )); + } + + } @@ -840,7 +864,7 @@ class ByteTag { ByteTag( byte[] buffer, int start, int length ) throws UnsupportedEncodingException { - _buffer = new String( buffer, start, length, "iso-8859-1" ).toCharArray(); + _buffer = new String( buffer, start, length, WebResponse.getDefaultEncoding() ).toCharArray(); _name = nextToken(); String attribute = ""; |
From: Russell G. <rus...@us...> - 2001-11-12 20:43:54
|
Update of /cvsroot/httpunit/httpunit/doc/tutorial/src/tutorial/persistence In directory usw-pr-cvs1:/tmp/cvs-serv20182/doc/tutorial/src/tutorial/persistence Added Files: BettingPool.java BettingPoolGame.java Log Message: Added tutorial --- NEW FILE --- package tutorial.persistence; public class BettingPool { public static void reset() { for (int i = 0; i < _games.length; i++) _games[i] = new BettingPoolGame(); _tieBreakerIndex = 0; _state = INITIAL_STATE; } public static BettingPoolGame[] getGames() { return _games; } public static int getTieBreakerIndex() { return _tieBreakerIndex; } public static void setTieBreakerIndex( int tieBreakerIndex ) { if (!isEditable()) throw new IllegalStateException( "May only modify the pool in INITIAL state" ); _tieBreakerIndex = tieBreakerIndex; } public static boolean isEditable() { return _state == INITIAL_STATE; } public static void openPool() { if (!isEditable()) throw new IllegalStateException( "May only modify the pool in INITIAL state" ); _state = POOL_OPEN; } private final static int NUM_GAMES = 10; private final static int INITIAL_STATE = 0; private final static int POOL_OPEN = 1; private static int _state; private static int _tieBreakerIndex; private static BettingPoolGame[] _games = new BettingPoolGame[ NUM_GAMES ]; } --- NEW FILE --- package tutorial.persistence; public class BettingPoolGame { BettingPoolGame() { _homeTeam = _awayTeam = ""; } public String getHomeTeam() { return _homeTeam; } public void setHomeTeam( String homeTeam ) { if (!BettingPool.isEditable()) throw new IllegalStateException( "The pool is not editable" ); _homeTeam = homeTeam; } public String getAwayTeam() { return _awayTeam; } public void setAwayTeam( String awayTeam ) { if (!BettingPool.isEditable()) throw new IllegalStateException( "The pool is not editable" ); _awayTeam = awayTeam; } private String _homeTeam = ""; private String _awayTeam = ""; } |
From: Russell G. <rus...@us...> - 2001-11-12 20:43:54
|
Update of /cvsroot/httpunit/httpunit/doc/tutorial/src/tutorial In directory usw-pr-cvs1:/tmp/cvs-serv20182/doc/tutorial/src/tutorial Added Files: PoolEditorServlet.java PoolEditorTest.java Log Message: Added tutorial --- NEW FILE --- package tutorial; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import javax.servlet.http.*; import javax.servlet.ServletException; import tutorial.persistence.BettingPool; import tutorial.persistence.BettingPoolGame; public class PoolEditorServlet extends HttpServlet { protected void doPost( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException { updateBettingPool( request ); response.setContentType( "text/html" ); PrintWriter pw = response.getWriter(); pw.println( "<html><head></head><body>" ); if (request.getParameter( "save" ).equals( "Open Pool" )) { String[] errors = getValidationErrors(); if (errors.length != 0) reportErrors( pw, errors ); else { BettingPool.openPool(); } } printBody( pw ); pw.println( "</body></html>" ); } private void reportErrors( PrintWriter pw, String[] errors ) { pw.println( "<table width='90%' style='background-color=yellow; border-color: black; border-width: 2; border-style: solid'>" ); pw.println( "<tr><td colspan='2'><b>Cannot open pool for betting:</b></td></tr>" ); for (int i=0; i < errors.length; i++) { pw.println( "<tr><td width='5'> </td><td>" + errors[i] + "</td></tr>" ); } pw.println( "</table>" ); } String[] getValidationErrors() { ArrayList errorList = new ArrayList(); BettingPoolGame game = BettingPool.getGames()[ BettingPool.getTieBreakerIndex() ]; if (game.getAwayTeam().length() == 0 || game.getHomeTeam().length() == 0) { errorList.add( "Tiebreaker is not a valid game" ); } BettingPoolGame[] games = BettingPool.getGames(); for (int i = 0; i < games.length; i++) { if (games[i].getAwayTeam().length() == 0 && games[i].getHomeTeam().length() != 0) { errorList.add( "Game " + i + " has no away team" ); } else if (games[i].getAwayTeam().length() != 0 && games[i].getHomeTeam().length() == 0) { errorList.add( "Game " + i + " has no home team" ); } } String[] errors = (String[]) errorList.toArray( new String[ errorList.size() ] ); return errors; } void updateBettingPool( HttpServletRequest request ) { BettingPoolGame[] games = BettingPool.getGames(); for (int i = 0; i < games.length; i++) { games[i].setAwayTeam( request.getParameter( "away" + i ) ); games[i].setHomeTeam( request.getParameter( "home" + i ) ); } BettingPool.setTieBreakerIndex( getTieBreakerIndex( request ) ); } private int getTieBreakerIndex( HttpServletRequest request ) { try { return Integer.parseInt( request.getParameter( "tiebreaker" ) ); } catch (NumberFormatException e) { return 0; } } protected void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException { response.setContentType( "text/html" ); PrintWriter pw = response.getWriter(); pw.println( "<html><head></head><body>" ); printBody( pw ); pw.println( "</body></html>" ); } private void printBody( PrintWriter pw ) { pw.println( "<form id='pool' method='POST'>" ); pw.println( "<table>" ); pw.println( "<tr><th>Home Team</th><th>Away Team</th><th>Tiebreaker?</th></tr>" ); BettingPoolGame[] games = BettingPool.getGames(); for (int i = 0; i < games.length; i++) { pw.println( "<tr><td><input name='home" + i + "' value='" + games[i].getHomeTeam() + "'" + getReadOnlyFlag() + "></td>" ); pw.println( "<td><input name='away" + i + "' value='" + games[i].getAwayTeam() + "'" + getReadOnlyFlag() + "></td>" ); pw.print( "<td><input type='radio' name='tiebreaker' value='" + i + "'" + getReadOnlyFlag() ); if (i == BettingPool.getTieBreakerIndex()) pw.print( " checked" ); pw.println( " /></td></tr>" ); } pw.println( "</table>" ); if (BettingPool.isEditable()) { pw.println( "<input type='submit' name='save' value='Save' />" ); pw.println( "<input type='submit' name='save' value='Open Pool' />" ); } pw.println( "</form>" ); } private String getReadOnlyFlag() { return BettingPool.isEditable() ? "" : " readonly"; } } --- NEW FILE --- package tutorial; import com.meterware.httpunit.*; import com.meterware.servletunit.*; import java.util.ArrayList; import java.util.Arrays; import junit.framework.*; import tutorial.persistence.BettingPool; public class PoolEditorTest extends TestCase { public static void main(String args[]) { junit.textui.TestRunner.run( suite() ); } public static TestSuite suite() { return new TestSuite( PoolEditorTest.class ); } public PoolEditorTest( String s ) { super( s ); } public void setUp() throws Exception { BettingPool.reset(); } public void testGetForm() throws Exception { ServletRunner sr = new ServletRunner( "web.xml" ); ServletUnitClient client = sr.newClient(); client.getResponse( "http://localhost/PoolEditor" ); } public void testFormAction() throws Exception { ServletRunner sr = new ServletRunner( "web.xml" ); ServletUnitClient client = sr.newClient(); WebResponse response = client.getResponse( "http://localhost/PoolEditor" ); WebForm form = response.getFormWithID( "pool" ); assertNotNull( "No form found with ID 'pool'", form ); assertEquals( "Form method", "POST", form.getMethod() ); assertEquals( "Form action", "", form.getAction() ); } public void testFormContents() throws Exception { ServletRunner sr = new ServletRunner( "web.xml" ); ServletUnitClient client = sr.newClient(); WebResponse response = client.getResponse( "http://localhost/PoolEditor" ); WebForm form = response.getFormWithID( "pool" ); assertNotNull( "No form found with ID 'pool'", form ); for (int i = 0; i < 10; i++) { assertTrue( "Missing home team " + i, form.isTextParameter( "home" + i ) ); assertTrue( "Missing away team " + i, form.isTextParameter( "away" + i ) ); } assertEquals( "Tie breaker values", Arrays.asList( new String[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" } ), Arrays.asList( form.getOptionValues( "tiebreaker" ) ) ); } public void testSubmitButtons() throws Exception { ServletRunner sr = new ServletRunner( "web.xml" ); ServletUnitClient client = sr.newClient(); WebResponse response = client.getResponse( "http://localhost/PoolEditor" ); WebForm form = response.getFormWithID( "pool" ); assertNotNull( "No form found with ID 'pool'", form ); assertEquals( "Number of submit buttons", 2, form.getSubmitButtons().length ); assertNotNull( "Save button not found", form.getSubmitButton( "save", "Save" ) ); assertNotNull( "Open Pool button not found", form.getSubmitButton( "save", "Open Pool" ) ); } public void testPoolDisplay() throws Exception { BettingPool.getGames()[0].setAwayTeam( "New York Jets" ); BettingPool.getGames()[0].setHomeTeam( "Philadelphia Eagles" ); BettingPool.getGames()[2].setAwayTeam( "St. Louis Rams" ); BettingPool.getGames()[2].setHomeTeam( "Chicago Bears" ); BettingPool.setTieBreakerIndex(2); ServletRunner sr = new ServletRunner( "web.xml" ); ServletUnitClient client = sr.newClient(); WebResponse response = client.getResponse( "http://localhost/PoolEditor" ); WebForm form = response.getFormWithID( "pool" ); assertNotNull( "No form found with ID 'pool'", form ); assertEquals( "Away team 0", "New York Jets", form.getParameterValue( "away0" ) ); assertEquals( "Home team 0", "Philadelphia Eagles", form.getParameterValue( "home0" ) ); assertEquals( "Away team 1", "", form.getParameterValue( "away1" ) ); assertEquals( "Home team 1", "", form.getParameterValue( "home1" ) ); assertEquals( "Away team 2", "St. Louis Rams", form.getParameterValue( "away2" ) ); assertEquals( "Home team 2", "Chicago Bears", form.getParameterValue( "home2" ) ); assertEquals( "Tie breaker game", "2", form.getParameterValue( "tiebreaker" ) ); } public void testPoolEntry() throws Exception { ServletRunner sr = new ServletRunner( "web.xml" ); ServletUnitClient client = sr.newClient(); WebResponse response = client.getResponse( "http://localhost/PoolEditor" ); WebForm form = response.getFormWithID( "pool" ); assertNotNull( "No form found with ID 'pool'", form ); WebRequest request = form.getRequest( "save", "Save" ); request.setParameter( "away1", "Detroit Lions" ); request.setParameter( "home1", "Denver Broncos" ); request.setParameter( "tiebreaker", "1" ); response = client.getResponse( request ); form = response.getFormWithID( "pool" ); assertEquals( "Away team 0", "", form.getParameterValue( "home0" ) ); assertEquals( "Home team 0", "", form.getParameterValue( "home0" ) ); assertEquals( "Away team 1", "Detroit Lions", form.getParameterValue( "away1" ) ); assertEquals( "Home team 1", "Denver Broncos", form.getParameterValue( "home1" ) ); assertEquals( "Tie breaker game", "1", form.getParameterValue( "tiebreaker" ) ); } public void testPoolValidation() throws Exception { ServletRunner sr = new ServletRunner( "web.xml" ); ServletUnitClient client = sr.newClient(); WebResponse response = client.getResponse( "http://localhost/PoolEditor" ); WebForm form = response.getFormWithID( "pool" ); WebRequest request = form.getRequest( "save", "Open Pool" ); request.setParameter( "away1", "Detroit Lions" ); request.setParameter( "home1", "Denver Broncos" ); request.setParameter( "home2", "Baltimore Ravens" ); request.setParameter( "tiebreaker", "3" ); InvocationContext context = client.newInvocation( request ); PoolEditorServlet servlet = (PoolEditorServlet) context.getServlet(); servlet.updateBettingPool( context.getRequest() ); String[] errors = servlet.getValidationErrors(); assertEquals( "Number of errors reported", 2, errors.length ); assertEquals( "First error", "Tiebreaker is not a valid game", errors[0] ); assertEquals( "Second error", "Game 2 has no away team", errors[1] ); } public void testPoolOpenErrorDetection() throws Exception { ServletRunner sr = new ServletRunner( "web.xml" ); ServletUnitClient client = sr.newClient(); WebResponse response = client.getResponse( "http://localhost/PoolEditor" ); WebForm form = response.getFormWithID( "pool" ); WebRequest request = form.getRequest( "save", "Open Pool" ); request.setParameter( "away1", "Detroit Lions" ); request.setParameter( "home1", "Denver Broncos" ); request.setParameter( "home2", "Baltimore Ravens" ); request.setParameter( "tiebreaker", "3" ); response = client.getResponse( request ); WebTable errorTable = response.getTableStartingWith( "Cannot open pool for betting:" ); assertNotNull( "No errors reported", errorTable ); String[][] cells = errorTable.asText(); assertEquals( "Number of error messages provided", 2, cells.length - 1 ); assertEquals( "Error message", "Tiebreaker is not a valid game", cells[1][0] ); assertEquals( "Error message", "Game 2 has no away team", cells[2][0] ); } public void testGoodPoolOpen() throws Exception { ServletRunner sr = new ServletRunner( "web.xml" ); ServletUnitClient client = sr.newClient(); WebResponse response = client.getResponse( "http://localhost/PoolEditor" ); WebForm form = response.getFormWithID( "pool" ); WebRequest request = form.getRequest( "save", "Open Pool" ); request.setParameter( "away1", "Detroit Lions" ); request.setParameter( "home1", "Denver Broncos" ); request.setParameter( "away3", "Indianapolis Colts" ); request.setParameter( "home3", "Baltimore Ravens" ); request.setParameter( "tiebreaker", "3" ); client.getResponse( request ); // (1) ignore the response response = client.getResponse( "http://localhost/PoolEditor" ); // (2) retrieve the page separately form = response.getFormWithID( "pool" ); assertNull( "Could still update the pool", form.getSubmitButton( "save" ) ); // (3) look for the buttons try { request = form.getRequest(); request.setParameter( "home3", "Philadelphia Eagles" ); // (4) try to change an entry fail( "Could still edit the pool" ); } catch (IllegalRequestParameterException e) {} } } |
From: Russell G. <rus...@us...> - 2001-11-12 20:43:53
|
Update of /cvsroot/httpunit/httpunit/doc/tutorial In directory usw-pr-cvs1:/tmp/cvs-serv20182/doc/tutorial Added Files: build.xml index.html pool_editor_static.html task1.html task1.zip task1editor-entry.html task1editor-form.html task1editor-initial.html task1editor-validation.html tutorial.css web.xml Log Message: Added tutorial --- NEW FILE --- <?xml version="1.0" ?> <!-- ======================================================================= --> <!-- httpunit tutorial build file --> <!-- ======================================================================= --> <project name="tutorial" default="test" basedir="."> <property name="src.dir" value="src" /> <property name="jars.dir" value="jars" /> <property name="classes.dir" value="classes" /> <property name="test.class" value="tutorial.PoolEditorTest" /> <property name="classpath" value="" /> <!-- =================================================================== --> <!-- Defines the classpath used for compilation and test. --> <!-- =================================================================== --> <path id="base.classpath"> <fileset dir="${jars.dir}"> <include name="*.jar"/> </fileset> </path> <!-- =================================================================== --> <!-- Compiles the source code --> <!-- =================================================================== --> <target name="compile"> <mkdir dir="${jars.dir}" /> <mkdir dir="${classes.dir}" /> <javac srcdir="${src.dir}" destdir="${classes.dir}" debug="on" deprecation="off" optimize="off"> <classpath refid="base.classpath" /> </javac> </target> <!-- =================================================================== --> <!-- Runs the test code --> <!-- =================================================================== --> <target name="test" depends="compile"> <java classname="${test.class}" fork="yes" > <classpath> <path refid="base.classpath" /> <pathelement location="${classes.dir}" /> <pathelement location="${classpath}" /> </classpath> </java> </target> <!-- =================================================================== --> <!-- Cleans up generated stuff --> <!-- =================================================================== --> <target name="clean"> <delete dir="${classes.dir}" /> </target> </project> --- NEW FILE --- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>HttpUnit Tutorial - intro</title> <LINK REL="stylesheet" HREF="tutorial.css" TYPE="text/css"> </head> <body> <h1>HttpUnit Tutorial</h1> <p>This tutorial should help you to learn to use HttpUnit to develop and test your web sites. It will take you through the incremental development of a simple servlet-based web application using a test-first approach. That is, first you are encouraged to write and execute a test for the next piece of functionality to be added, verify that the test fails (demonstrating that the functionality is not in place), and then implement the functionality and verify that the test now passes.</p> <p>The initial tasks will use the <code>ServletRunner</code> class, thus bypassing the need for a web browser or servlet engine. Later tasks will require a web browser and a servlet engine, and use <code>WebConversation</code>.</p> <h2>The Application</h2> <p>Our application is an office sport betting pool. An administrator is designated to manage the pool, which includes opening and closing the betting. Entrants select the winner in each of the up to 10 games defined by the administrator and also guess the total score in one of those games, as designated by the administrator. The winner of the pool is the one who got the most winners correct, with any ties going to the person whose predicted total score in the tie-breaker game was closest to the actual final score.</p> <p>We will identify the following uses of the system:</p> <p class="story-name">1.1 Administrator Opens Pool</p> <p class="story-contents">The administrator defines up to ten games, specifying the home and away team for each game. He also selects one of these games as the tie-breaker. Once the data is correct, the administrator opens the pool for betting.</p> <p class="story-name">1.2 Administrator Closes Pool</p> <p class="story-contents">After the pool is open, the administrator may at any time close the pool, thus preventing any further bets or changes to existing bets.</p> <p class="story-name">1.3 Administrator Posts Results</p> <p class="story-contents">After the pool is closed, the administrator enters actual scores for each of the games played. Once all scores have been entered, the administrator posts the results.</p> <p class="story-name">2.1 Users enters a bet</p> <p class="story-contents">After the pool is open, a user may sign on and create a bet, predicting the winner of each game and the total score of the tie-breaker game. The user may change his bet until the pool is closed.</p> <p class="story-name">2.2 User views results</p> <p class="story-contents">Once the results have been posted, a user may examine his own bet to see how well he did. The system will indicate the correct predictions and the user's rank in the pool.</p> <p class="story-name">2.3 User views standings</p> <p class="story-contents">Once the results have been posted, a user may view a list of all bidders ranked by number of correct predictions.</p> <p>This application is fairly simple, and hardly robust, but contains more than enough interactions to allow us to explore development and testing with HttpUnit. <h2>Tutorial Organization</h2> Each section of the tutorial will address a specific use of the system, and show how HttpUnit and ServletUnit can be used to write tests which verify that functionality. You should begin each section by copying the initial directory, which includes an ant build script and some classes that you will need to complete it. Running the ant script will compile the code and run the tests. After you implement each test, it should fail until you then add the implementation. </body> </html> --- NEW FILE --- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head><title>UniSports Betting Pool - Definition</title></head> <body> <table width='90%' style='background-color=yellow; border-color: black; border-width: 2; border-style: solid'> <tr><td colspan='2'><b>Cannot open pool for betting:</b></td></tr> <tr><td width="5"> </td><td>No tiebreaker was specified</td></tr> </table> Enter teams for up to 10 games, selecting one as a tie-breaker. <form method="POST"> <table> <tr><th>Home Team</th><th>Away Team</th><th>Tiebreaker?</th></tr> <tr><td><input name="home0"></td><td><input name="away0"></td><td><input type="radio" name="tiebreaker" value="0"/></td></tr> <tr><td><input name="home1"></td><td><input name="away1"></td><td><input type="radio" name="tiebreaker" value="1"/></td></tr> <tr><td><input name="home2"></td><td><input name="away2"></td><td><input type="radio" name="tiebreaker" value="2"/></td></tr> <tr><td bgcolor="red"><input name="home3"></td><td><input name="away3"></td><td><input type="radio" name="tiebreaker" value="3"/></td></tr> <tr><td><input name="home4"></td><td><input name="away4"></td><td><input type="radio" name="tiebreaker" value="4"/></td></tr> <tr><td><input name="home5"></td><td><input name="away5"></td><td><input type="radio" name="tiebreaker" value="5"/></td></tr> <tr><td><input name="home6"></td><td><input name="away6"></td><td><input type="radio" name="tiebreaker" value="6"/></td></tr> <tr><td><input name="home7"></td><td><input name="away7"></td><td><input type="radio" name="tiebreaker" value="7"/></td></tr> <tr><td><input name="home8"></td><td><input name="away8"></td><td><input type="radio" name="tiebreaker" value="8"/></td></tr> <tr><td><input name="home9"></td><td><input name="away9"></td><td><input type="radio" name="tiebreaker" value="9"/></td></tr> </table> <input type="submit" name="save" value="Save"/> <input type="submit" name="save" value="Open Pool"/> </form> </body> </html> --- NEW FILE --- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>HttpUnit Tutorial - create pool editor</title> <LINK REL="stylesheet" HREF="tutorial.css" TYPE="text/css"> </head> <body> <h1>Creating the Pool Editor</h1> <p>Our initial task will be the creation of the simple pool editor, following use case 1.1. We will ignore security restrictions that permit only the administrator to access this page. To begin the tutorial, create a working directory and expand <a href="task1.zip">this archive</a> into it. Either create a jars directory and copy httpunit.jar, Tidy.jar, and xerces.jar into it, or make sure that they are on your classpath and invoke ant passing the classpath as a property. You will write your code in the src/tutorial sub-directory. Once you are ready, proceed to <a href="task1editor-initial.html">step one</a> to begin the tutorial. --- NEW FILE --- PK --- NEW FILE --- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>HttpUnit Tutorial - create pool editor - step 3</title> <LINK REL="stylesheet" HREF="tutorial.css" TYPE="text/css"> </head> <body><h1>Submitting a Form</h1> <p class="goals">In this step, you will learn how to: <br />• Check form default parameter values <br />• Create a request from a form <br />• Override the default parameter values in a request <br />• Submit a form and get a response</p> <p>We now have a form which can generate POST requests to define the betting pool. Our next step will be to build the code which handles these requests. We will start by simply recording changes, and defer validation until the administrator attempts to open the pool. For our demonstration application, we will use in-memory persistence only, and will provide ourselves with a way to clear it so that each <code>JUnit</code> test can run independantly. <h2>Testing pool display</h2> <p>The first thing we want to test and implement is the display of the current state of the pool. We will do this by setting the state directly, using the supplied entity classes and then invoke the form to display the pool. At this time, we will also add the set up code to clear the pool before each test:</p> <pre class="test-code"> <b>public void</b> setUp() <b>throws</b> Exception { BettingPool.reset(); } <b>public void</b> testPoolDisplay() <b>throws</b> Exception { BettingPool.getGames()[0].setAwayTeam( "New York Jets" ); // (1) set up data BettingPool.getGames()[0].setHomeTeam( "Philadelphia Eagles" ); BettingPool.getGames()[2].setAwayTeam( "St. Louis Rams" ); BettingPool.getGames()[2].setHomeTeam( "Chicago Bears" ); BettingPool.setTieBreakerIndex(2); ServletRunner sr = <b>new</b> ServletRunner( "web.xml" ); ServletUnitClient client = sr.newClient(); WebResponse response = client.getResponse( "http://localhost/PoolEditor" ); WebForm form = response.getFormWithID( "pool" ); assertNotNull( "No form found with ID 'pool'", form ); assertEquals( "Away team 0", "New York Jets", form.getParameterValue( "away0" ) ); // (2) check team names assertEquals( "Home team 0", "Philadelphia Eagles", form.getParameterValue( "home0" ) ); assertEquals( "Away team 1", "", form.getParameterValue( "away1" ) ); assertEquals( "Home team 1", "", form.getParameterValue( "home1" ) ); assertEquals( "Away team 2", "St. Louis Rams", form.getParameterValue( "away2" ) ); assertEquals( "Home team 2", "Chicago Bears", form.getParameterValue( "home2" ) ); assertEquals( "Tie breaker game", "2", form.getParameterValue( "tiebreaker" ) ); // (3) check radio button } </pre> <p>Here we are:<ol> <li>Setting up the data that the servlet which read to create the entry form. Here we are using a simple in-memory persistence strategy. If the servlet accessed the database, we would have to do JDBC calls here.</li> <li>Reading the names of the teams and comparing them to what we initialized. Note the test for the skipped game to verify that the defaults come through.</li> <li>Checking the state of the radio button. Note that we can use the same method <code>WebForm.getParameterValue</code> for each parameter, no matter its type.</li></ol></p> <p>As before, the above test should initially fail. We then make it work by changing the loop in <code>printBody</code> as follows:</p> <pre class="servlet-code"> BettingPoolGame[] games = BettingPool.getGames(); <b>for</b> (int i = 0; i < games.length; i++) { pw.println( "<tr><td><input name='home" + i + "' value='" + games[i].getHomeTeam() + "' ></td>" ); pw.println( "<td><input name='away" + i + "' value='" + games[i].getAwayTeam() + "'></td>" ); pw.print( "<td><input type='radio' name='tiebreaker' value='" + i + "'" ); if (i == BettingPool.getTieBreakerIndex()) pw.print( " checked" ); pw.println( " /></td></tr>" ); } </pre> <h2>Testing pool entry</h2> <p>Now that we know we can display the current state of the pool, we will verify that we can use the form to change it as well:<p /> <pre class="test-code"> <b>public void</b> testPoolEntry() <b>throws</b> Exception { ServletRunner sr = <b>new</b> ServletRunner( "web.xml" ); ServletUnitClient client = sr.newClient(); WebResponse response = client.getResponse( "http://localhost/PoolEditor" ); WebForm form = response.getFormWithID( "pool" ); assertNotNull( "No form found with ID 'pool'", form ); WebRequest request = form.getRequest( "save", "Save" ); // (1) select a submit button request.setParameter( "away1", "Detroit Lions" ); // (2) enter values into the form request.setParameter( "home1", "Denver Broncos" ); request.setParameter( "tiebreaker", "1" ); response = client.getResponse( request ); // (3) submit the form form = response.getFormWithID( "pool" ); assertEquals( "Away team 0", "", form.getParameterValue( "home0" ) ); // (4) verify the response assertEquals( "Home team 0", "", form.getParameterValue( "home0" ) ); assertEquals( "Away team 1", "Detroit Lions", form.getParameterValue( "away1" ) ); assertEquals( "Home team 1", "Denver Broncos", form.getParameterValue( "home1" ) ); assertEquals( "Tie breaker game", "1", form.getParameterValue( "tiebreaker" ) ); } </pre> <p>This is our first form submission. Take note:<ol> <li>The first step in submitting a form is obtaining a request from it. Since this form has two named submit buttons, we must specify which one we want to be included in the request.</li> <li>We make a call for each parameter that we want to set. Any parameters we do not set will be submitted with their default values.</li> <li>We submit the form by asking our client to get a response to the prepared request.</li> <li>We can use the same methods as above to check the new state of the pool. Alternately, we could have examined the BettingPool object directly.</li></ol></p> <p>This test will fail with a 405 response, since we have not defined a handler for the POST message. We do so now:</p> <pre class="servlet-code"> <b>protected void</b> doPost( HttpServletRequest request, HttpServletResponse response ) <b>throws</b> ServletException, IOException { updateBettingPool( request ); response.setContentType( "text/html" ); PrintWriter pw = response.getWriter(); pw.println( "<html><head></head><body>" ); printBody( pw ); pw.println( "</body></html>" ); } <b>private void</b> updateBettingPool( HttpServletRequest request ) { BettingPoolGame[] games = BettingPool.getGames(); <b>for</b> (int i = 0; i < games.length; i++) { games[i].setAwayTeam( request.getParameter( "away" + i ) ); games[i].setHomeTeam( request.getParameter( "home" + i ) ); } BettingPool.setTieBreakerIndex( getTieBreakerIndex( request ) ); } <b>private</b> int getTieBreakerIndex( HttpServletRequest request ) { <b>try</b> { <b>return</b> Integer.parseInt( request.getParameter( "tiebreaker" ) ); } <b>catch</b> (NumberFormatException e) { <b>return</b> 0; } } </pre> <p>Note that we are using the same <code>printBody</code> method as the <code>doGet</code> method does.</p> <p>We now have the ability to edit the pool entries. Our <a href="task1editor-validation.html">next step</a> is to add the validation and handle opening the pool to bettors. </body></html> --- NEW FILE --- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>HttpUnit Tutorial - create pool editor - step 2</title> <LINK REL="stylesheet" HREF="tutorial.css" TYPE="text/css"> </head> <body> <h1>Examining a Form</h1> <p class="goals">In this step, you will learn how to: <br />• Extract a form from a web page, using its ID <br />• Examine form attributes <br />• Check text and radio button input fields <br />• Check form submit buttons</p> <p>Now that we can invoke our servlet, the next step will be to produce the <a href="pool_editor_static.html">form</a> in response to a GET command. This form will POST back to the same URL, allow for entry of 10 pairs of team names, allow for selection of a tie-breaker game, and allow the user to either save his entries or save them <i>and</i> open the betting pool. We can write a test for each of these required behaviors.</p> <h2>Testing the Form action</h2> <p>Let us add the following test:</p> <pre class="test-code"> <b>public void</b> testFormAction() <b>throws</b> Exception { ServletRunner sr = <b>new</b> ServletRunner( "web.xml" ); ServletUnitClient client = sr.newClient(); WebResponse response = client.getResponse( "http://localhost/PoolEditor" ); WebForm form = response.getFormWithID( "pool" ); // (1) obtain the desired form assertNotNull( "No form found with ID 'pool'", form ); assertEquals( "Form method", "POST", form.getMethod() ); // (2) verify that the form uses POST assertEquals( "Form action", "", form.getAction() ); // (3) verify that the default action is used } </pre> <p>The significant points in the code are:<ol> <li>Extracting the form from the page. In this case, we use the ID (which should be unique) attribute to find the form. We could also just ask for all the forms in the page and select the first one, but this skips the need to count the number of forms in the page. If the form is not present, we will just get a null value.</li> <li>Checking that the form uses the POST method.</li> <li>Checking that the form has no <code>action</code> attribute specified and will therefore default to the URL from which it was retrieved - in the case, the same servlet that produced it.</li></ol></p> <p>Again we run the test and fix the reported errors, one by one. The <code>printBody</code> method will now look like this:</p> <pre class="servlet-code"> <b>private void</b> printBody( PrintWriter pw ) { pw.println( "<form id='pool' method='POST'>" ); pw.println( "</form>" ); } </pre> <p>and we now have two working tests.</p> <h2>Testing the form contents</h2> <p>We can now test the input fields in the form:<p /> <pre class="test-code"> <b>public void</b> testFormContents() <b>throws</b> Exception { ServletRunner sr = <b>new</b> ServletRunner( "web.xml" ); ServletUnitClient client = sr.newClient(); WebResponse response = client.getResponse( "http://localhost/PoolEditor" ); WebForm form = response.getFormWithID( "pool" ); assertNotNull( "No form found with ID 'pool'", form ); <b>for</b> (int i = 0; i < 10; i++) { assertTrue( "Missing home team " + i, form.isTextParameter( "home" + i ) ); // (1) text parameter assertTrue( "Missing away team " + i, form.isTextParameter( "away" + i ) ); // (1) text parameter } assertEquals( "Tie breaker values", Arrays.asList( new String[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" } ), Arrays.asList( form.getOptionValues( "tiebreaker" ) ) ); // (2) radio button } </pre> <p>The significant points in the code are:<ol> <li>We verify that a text parameter has been defined with the desired name for each of the 20 possible team values.</li> <li>Here we verify that we have a set of radio buttons with a specific name and each of the desired values.</li></ol></p> <p>We satisfy this test by making the <code>printBody</code> method look like this:</p> <pre class="servlet-code"> <b>private void</b> printBody( PrintWriter pw ) { pw.println( "<form id='pool' method='POST'>" ); pw.println( "<table>" ); pw.println( "<tr><th>Home Team</th><th>Away Team</th><th>Tiebreaker?</th></tr>" ); <b>for</b> (int i = 0; i < 10; i++) { pw.println( "<tr><td><input name='home" + i + "'></td>" ); pw.println( "<td><input name='away" + i + "'></td>" ); pw.println( "<td><input type='radio' name='tiebreaker' value='" + i + "'/></td></tr>" ); } pw.println( "</table>" ); pw.println( "</form>" ); } </pre> <h2>Testing the Submit Buttons</h2> <p>We confirm the presence of the desired submit buttons as follows:<p /> <pre class="test-code"> <b>public void</b> testSubmitButtons() <b>throws</b> Exception { ServletRunner sr = <b>new</b> ServletRunner( "web.xml" ); ServletUnitClient client = sr.newClient(); WebResponse response = client.getResponse( "http://localhost/PoolEditor" ); WebForm form = response.getFormWithID( "pool" ); assertNotNull( "No form found with ID 'pool'", form ); assertEquals( "Number of submit buttons", 2, form.getSubmitButtons().length ); // (1) count the buttons assertNotNull( "Save button not found", form.getSubmitButton( "save", "Save" ) ); // (2) look up by name assertNotNull( "Open Pool button not found", form.getSubmitButton( "save", "Open Pool" ) ); } </pre> <p>In this test, please note the following:<ol> <li>We ask for all the submit buttons associated with the form and just count them. This will ensure that we don't have more than we want, either.</li> <li>We ask for each button that we do want by specifying its name and value - which will be used when we submit the form.</li></ol></p> <p>This test will pass once we modify the end of <code>printBody</code>, inserting lines to generate the submit buttons:</p> <pre class="servlet-code"> } pw.println( "</table>" ); pw.println( "<input type='submit' name='save' value='Save' />" ); pw.println( "<input type='submit' name='save' value='Open Pool' />" ); pw.println( "</form>" ); } </pre> We now have our form being generated, along with tests to confirm it. In the <a href="task1editor-entry.html">next step</a>, we will test and code the response to a form submission. </body></html> --- NEW FILE --- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>HttpUnit Tutorial - create pool editor - step 1</title> <LINK REL="stylesheet" HREF="tutorial.css" TYPE="text/css"> </head> <body> <h1>Invoking the Pool Editor</h1> <p class="goals">In this step, you will learn how to:<br />• Initialize ServletUnit<br />• Invoke a servlet</p> <p>The first step will simply be to verify that we can register and access the servlet, which we will name <code>PoolEditorServlet</code>. A GET method to this page should return the editor form itself, while updates will be handled by a POST method to the same address. Since we are working with servlets, we can bypass the web server and use the <code>servletunit</code> package to run our tests.</p> <p>Here is the initial test code:</p> <pre class="test-code"> <b>package</b> tutorial; <b>import</b> com.meterware.httpunit.*; <b>import</b> com.meterware.servletunit.*; <b>import</b> junit.framework.*; <b>import</b> tutorial.persistence.*; <b>public class</b> PoolEditorTest <b>extends</b> TestCase { <b>public static void</b> main( String args[] ) { junit.textui.TestRunner.run( suite() ); } <b>public static</b> TestSuite suite() { <b>return new</b> TestSuite( PoolEditorTest.<b>class</b> ); } <b>public</b> PoolEditorTest( String s ) { <b>super</b>( s ); } <b>public void</b> testGetForm() <b>throws</b> Exception { ServletRunner sr = <b>new</b> ServletRunner( "web.xml" ); // (1) use the web.xml file to define mappings ServletUnitClient client = sr.newClient(); // (2) create a client to invoke the application client.getResponse( "http://localhost/PoolEditor" ); // (3) invoke the servlet } } </pre> <p>This code uses <code>JUnit</code> and <code>ServletUnit</code> to verify that a servlet is present at the specified address. The significant points in the code are:<ol> <li>Creating the <code>ServletRunner</code> class which represents access to a Servlet application. The application is defined by an XML file which maps URL information to servlet classes.</li> <li>Creating a client which can access the application and maintain state across multiple invocations.</li> <li>Invoking the servlet via its URL. Note that ServletUnit ignores any host and port information. All URL patterns are treated as being relative to the root ("/").</li></ol></p> <p>To run this code, you will also need the <a href="web.xml">web.xml</a> file in your current directory. This file maps the request URL to the Pool Editor servlet.</p> <p>This code should fail with a <code>HttpNotFoundException</code>, because we have not yet created the servlet class. We can now proceed to do so. Here is a simple implementation:</p> <p></p> <pre class="servlet-code"> <b>package</b> tutorial; <b>import</b> java.io.*; <b>import</b> javax.servlet.http.*; <b>import</b> javax.servlet.ServletException; <b>import</b> tutorial.persistence.*; <b>public class</b> PoolEditorServlet <b>extends</b> HttpServlet { <b>protected void</b> doGet( HttpServletRequest request, HttpServletResponse response ) <b>throws</b> ServletException, IOException { response.setContentType( "text/html" ); PrintWriter pw = response.getWriter(); pw.println( "<html><head></head><body>" ); printBody( pw ); pw.println( "</body></html>" ); } <b>private void</b> printBody( PrintWriter pw ) { pw.println( "A simple page" ); } } </pre> <p>With this code in place, the first test will now pass and we can move to <a href="task1editor-form.html">the next task</a>.</p> </body> </html> --- NEW FILE --- <html> <head> <title>HttpUnit Tutorial - create pool editor - step 4</title> <LINK REL="stylesheet" HREF="tutorial.css" TYPE="text/css"> </head> <body> <h1>Testing servlet internals</h1> <p class="goals">In this step, you will learn how to: <br />• Access a servlet directly during an invocation <br />• Extract a table from a web response, using its contents <br />• Examine the contents of an HTML table <br />• Verify that fields are marked read-only</p> <p>We are nearly done with the pool editor. We can now use it to define the contents of the pool; however, we can only permit the administrator to open the pool for betting if it is valid. We therefore have to define the validity rules. For this tutorial, the only rules that we will insist on is that all teams must have opponents, and that only a game with a pair of teams may be selected as the tie-breaker.</p> <p>We must also prevent edits to the pool once it has been opened.</p> <h2>Testing bad inputs</h2> <p>Validation is often complicated, since we have to not only check the data against our validation rules, we also have to recognize the need to validate, and modify the output to show any errors. It would be nice if we could break this into pieces and build one at a time. With <code>ServletUnit</code>, we can:<p /> <pre class="test-code"> <b>public void</b> testPoolValidation() <b>throws</b> Exception { ServletRunner sr = new ServletRunner( "web.xml" ); ServletUnitClient client = sr.newClient(); WebResponse response = client.getResponse( "http://localhost/PoolEditor" ); WebForm form = response.getFormWithID( "pool" ); WebRequest request = form.getRequest( "save", "Open Pool" ); request.setParameter( "away1", "Detroit Lions" ); request.setParameter( "home1", "Denver Broncos" ); request.setParameter( "home2", "Baltimore Ravens" ); request.setParameter( "tiebreaker", "3" ); InvocationContext context = client.newInvocation( request ); // (1) create an invocation context PoolEditorServlet servlet = (PoolEditorServlet) context.getServlet(); // (2) locate the invoked servlet servlet.updateBettingPool( context.getRequest() ); // (3) ask servlet to update the data String[] errors = servlet.getValidationErrors(); // (4) ask servlet to check the data assertEquals( "Number of errors reported", 2, errors.length ); assertEquals( "First error", "Tiebreaker is not a valid game", errors[0] ); assertEquals( "Second error", "Game 2 has no away team", errors[1] ); } </pre> <p>This test starts out like all the others, but once we have created the request, things venture into new territory:<ol> <li>Rather than simply asking for the response, we create a context in which we can step through the invocation of the servlet. This uses the same mechanisms to locate and initialize the servlet, request, and response objects, but does not actually invoke the servlet to process the request.</li> <li>We retrieve the initialized servlet and cast it in order to get at its intermediate methods.</li> <li>We call the <code>updateBettingPool</code> method (which we need to make package-accessible), passing the request object found in the context.</li> <li>We can now call a new method in the servlet which will return an array of error messages, which we can compare against our expected values for them.</li></ol></p> <p>To make this test pass, we just have to create a single new method in the servlet:</p> <pre class="servlet-code"> String[] getValidationErrors() { ArrayList errorList = <b>new</b> ArrayList(); BettingPoolGame game = BettingPool.getGames()[ BettingPool.getTieBreakerIndex() ]; <b>if</b> (game.getAwayTeam().length() == 0 || game.getHomeTeam().length() == 0) { errorList.add( "Tiebreaker is not a valid game" ); } BettingPoolGame[] games = BettingPool.getGames(); <b>for</b> (int i = 0; i < games.length; i++) { <b>if</b> (games[i].getAwayTeam().length() == 0 && games[i].getHomeTeam().length() != 0) { errorList.add( "Game " + i + " has no away team" ); } else <b>if</b> (games[i].getAwayTeam().length() != 0 && games[i].getHomeTeam().length() == 0) { errorList.add( "Game " + i + " has no home team" ); } } String[] errors = (String[]) errorList.toArray( <b>new</b> String[ errorList.size() ] ); <b>return</b> errors; } </pre> <h2>Displaying the error messages</h2> <p>Once we are sure of our validation logic, we need to have the error messages displayed. We will arrange to have any error message displayed in the top of row of the table, and we will highlight any cells containing bad inputs. We therefore ask for the response from the bad open pool request:<p /> <pre class="test-code"> <b>public void</b> testBadPoolOpen() <b>throws</b> Exception { ServletRunner sr = <b>new</b> ServletRunner( "web.xml" ); ServletUnitClient client = sr.newClient(); WebResponse response = client.getResponse( "http://localhost/PoolEditor" ); WebForm form = response.getFormWithID( "pool" ); WebRequest request = form.getRequest( "save", "Open Pool" ); // (1) select a submit button request.setParameter( "away1", "Detroit Lions" ); // (2) enter bad values into the form request.setParameter( "home1", "Denver Broncos" ); request.setParameter( "home2", "Baltimore Ravens" ); request.setParameter( "tiebreaker", "3" ); response = client.getResponse( request ); // (3) submit the form WebTable errorTable = response.getTableStartingWith( "Errors Detected:" ); // (4) Look for error table assertNotNull( "No errors reported", errorTable ); String[][] cells = errorTable.asText(); // (5) Convert non-empty cells to text assertEquals( "Number of error messages provided", 2, cells.length - 1 ); assertEquals( "Error message", "Tiebreaker is not a valid game", cells[1][0] ); assertEquals( "Error message", "Game 2 has no away team", cells[2][0] ); } </pre> <p>Note:<ol> <li>We select the "Open Pool" button to be included with the form submission.</li> <li>We then enter known bad values.</li> <li>We want the response when we submit the form changes.</li> <li>We expect to find them in a table which we can recognize because its upper-leftmost non-empty cell which contain a known string.</li> <li>Since we want to examine the textual content of any non-empty cells in the table, we ask that the table be converted to a two-dimensional string array. In this case, there should only be one non-blank cell in each row.</li></ol></p> <p>This test passes once we modify the end of the <code>doPost</code> method :</p> <pre class="servlet-code"> pw.println( "<html><head></head><body>" ); <b>if</b> (request.getParameter( "save" ).equals( "Open Pool" )) { String[] errors = getValidationErrors(); <b>if</b> (errors.length != 0) reportErrors( pw, errors ); } printBody( pw ); pw.println( "</body></html>" ); } <b>private void</b> reportErrors( PrintWriter pw, String[] errors ) { pw.println( "<table width='90%' style='background-color=yellow; " ); pw.println( " border-color: black; border-width: 2; border-style: solid'>" ); pw.println( "<tr><td colspan='2'><b>Cannot open pool for betting:</b></td></tr>" ); <b>for</b> (int i=0; i < errors.length; i++) { pw.println( "<tr><td width='5'>&nbsp;</td><td>" + errors[i] + "</td></tr>" ); } pw.println( "</table>" ); } </pre> <p>Note that we are actually displaying <i>two</i> cells for each error. The first is blank, and is simply used for formatting, as many web designers tend to do. The test code will ignore this, so that if the page is later modified to use stylesheets to control its formatting, the test will be unaffected. For this same reason, the tests in this tutorial tend to ignore formatting issues in general, and only look at structural elements. <h2>Closing the pool</h2> <p>If everything is valid, we should be able close the pool. This will be reflected by a change in state of the BettingPool object - which will later be used to change the options available to the users - and should forbid future changes to the pool itself. We will test this by verifying that the "save" submit buttons are no longer enabled:<p /> <pre class="test-code"> <b>public void</b> testGoodPoolOpen() <b>throws</b> Exception { ServletRunner sr = <b>new</b> ServletRunner( "web.xml" ); ServletUnitClient client = sr.newClient(); WebResponse response = client.getResponse( "http://localhost/PoolEditor" ); WebForm form = response.getFormWithID( "pool" ); WebRequest request = form.getRequest( "save", "Open Pool" ); request.setParameter( "away1", "Detroit Lions" ); request.setParameter( "home1", "Denver Broncos" ); request.setParameter( "away3", "Indianapolis Colts" ); request.setParameter( "home3", "Baltimore Ravens" ); request.setParameter( "tiebreaker", "3" ); client.getResponse( request ); // (1) ignore the response response = client.getResponse( "http://localhost/PoolEditor" ); // (2) retrieve the page separately form = response.getFormWithID( "pool" ); assertNull( "Could still update the pool", form.getSubmitButton( "save" ) ); // (3) look for the buttons try { request = form.getRequest(); request.setParameter( "home3", "Philadelphia Eagles" ); // (4) try to change an entry fail( "Could still edit the pool" ); } catch (IllegalRequestParameterException e) {} } </pre> <p>Note:<ol> <li>We are not interested in the response this time because we may ultimately have the browser forwarded to the main page.</li> <li>We come back to the form as though we were planning on editing it anew.</li> <li>We want to ensure that the submit buttons are disabled so the user cannot submit the form.</li> <li>We also verify that the fields are now marked readonly, which would prevent us from changing them. If the exception is not thrown, the test will be marked as failing.</li></ol></p> <p>We have to make changes in two places to make this behavior work. The following code change to <code>printBody</code> makes the form display read-only once the pool is open:</p> <pre class="servlet-code"> for (int i = 0; i < games.length; i++) { pw.println( "<tr><td><input name='home" + i + "' value='" + games[i].getHomeTeam() + "'" + getReadOnlyFlag() + "></td>" ); pw.println( "<td><input name='away" + i + "' value='" + games[i].getAwayTeam() + "'" + getReadOnlyFlag() + "></td>" ); pw.print( "<td><input type='radio' name='tiebreaker' value='" + i + "'" + getReadOnlyFlag() ); if (i == BettingPool.getTieBreakerIndex()) pw.print( " checked" ); pw.println( " /></td></tr>" ); } pw.println( "</table>" ); if (BettingPool.isEditable()) { pw.println( "<input type='submit' name='save' value='Save' />" ); pw.println( "<input type='submit' name='save' value='Open Pool' />" ); } pw.println( "</form>" ); } private String getReadOnlyFlag() { return BettingPool.isEditable() ? "" : " readonly"; } </pre> <p>and we have to make a small change to <code>doPost</code> in order to mark the pool open:</p> <pre class="servlet-code"> String[] errors = getValidationErrors(); if (errors.length != 0) reportErrors( pw, errors ); else { BettingPool.openPool(); } } </pre> <p>The pool editor is now complete.</p> </body></html> --- NEW FILE --- PRE { font-family: "courier new", courier; font-size: .75em; margin-left: 2%; margin-right: 2%; padding-top: .5em; padding-bottom: .5em; padding-right: .5em; padding-left: .5em; border-color: black; border-width: 2; border-style: solid } PRE.test-code { background-color: #cccccc } PRE.servlet-code { background-color: #00eeee } OL { margin-top: 0 } P.story-name { margin-left: 3em; margin-bottom: 0; font-weight: bold } P.story-contents { margin-left: 3em; margin-top: 0 } P.goals { font-family: helvetica, ariel, sans-serif; font-size: x-small; background-color: yellow; border-color: black; border-style: solid; border-top-width: 2px; border-bottom-width: 2px; border-left-width: 0px; border-right-width: 0px } UL { margin-top: 0 } --- NEW FILE --- <?xml version='1.0' encoding='ISO-8859-1'?> <web-app> <servlet> <servlet-name>Editor</servlet-name> <servlet-class>tutorial.PoolEditorServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>Editor</servlet-name> <url-pattern>/PoolEditor</url-pattern> </servlet-mapping> </web-app> |
From: Russell G. <rus...@us...> - 2001-11-12 20:43:53
|
Update of /cvsroot/httpunit/httpunit In directory usw-pr-cvs1:/tmp/cvs-serv20182 Modified Files: build.xml Log Message: Added tutorial Index: build.xml =================================================================== RCS file: /cvsroot/httpunit/httpunit/build.xml,v retrieving revision 1.33 retrieving revision 1.34 diff -u -r1.33 -r1.34 --- build.xml 2001/11/08 22:07:52 1.33 +++ build.xml 2001/11/12 20:43:50 1.34 @@ -1,29 +1,29 @@ -<?xml version="1.0" ?> -<!-- ======================================================================= --> -<!-- httpunit build file --> -<!-- ======================================================================= --> +<?xml version="1.0" ?> +<!-- ======================================================================= --> +<!-- httpunit build file --> +<!-- ======================================================================= --> <project name="httpunit" default="jar" basedir="."> - <property name="name" value="httpunit" /> - <property name="Name" value="HttpUnit" /> + <property name="name" value="httpunit" /> + <property name="Name" value="HttpUnit" /> <property name="version" value="1.2.7" /> <property name="zip_version" value="1_2_7" /> - - <property name="src.dir" value="src" /> - <property name="tstsrc.dir" value="test" /> - <property name="examples.dir" value="examples" /> + + <property name="src.dir" value="src" /> + <property name="tstsrc.dir" value="test" /> + <property name="examples.dir" value="examples" /> <property name="lib.dir" value="lib" /> <property name="jars.dir" value="jars" /> - - <property name="docs.dir" value="doc" /> - <property name="build.dir" value="build" /> - <property name="build.classes" value="${build.dir}/classes" /> - <property name="test.classes" value="${build.dir}/testclasses" /> + + <property name="docs.dir" value="doc" /> + <property name="build.dir" value="build" /> + <property name="build.classes" value="${build.dir}/classes" /> + <property name="test.classes" value="${build.dir}/testclasses" /> <property name="javadoc.dir" value="${docs.dir}/api" /> - - <property name="dist.dir" value="dist" /> + + <property name="dist.dir" value="dist" /> <property name="classpath" value="" /> - <property name="web.dir" value="web" /> - <property name="packages" value="com.meterware.*" /> + <property name="web.dir" value="web" /> + <property name="packages" value="com.meterware.*" /> <property name="test.class" value="com.meterware.httpunit.HttpUnitSuite" /> <property name="servlet.test.class" value="com.meterware.servletunit.ServletUnitSuite" /> @@ -35,35 +35,35 @@ <include name="*.jar"/> </fileset> </path> - - + + <!-- =================================================================== --> <!-- Check to see what optional dependencies are available --> <!-- =================================================================== --> <target name="check_for_optional_packages"> - <available property="jsdk.present" classname="javax.servlet.http.HttpServlet" + <available property="jsdk.present" classname="javax.servlet.http.HttpServlet" classpathref="base.classpath" /> - <available property="javamail.present" classname="javax.mail.internet.MimeMultipart" + <available property="javamail.present" classname="javax.mail.internet.MimeMultipart" classpathref="base.classpath" /> - <available property="xerces.present" classname="org.apache.xerces.parsers.DOMParser" + <available property="xerces.present" classname="org.apache.xerces.parsers.DOMParser" classpathref="base.classpath" /> </target> -<!-- =================================================================== --> -<!-- Prepares the build directory --> -<!-- =================================================================== --> +<!-- =================================================================== --> +<!-- Prepares the build directory --> +<!-- =================================================================== --> <target name="prepare"> - <mkdir dir="${build.dir}" /> + <mkdir dir="${build.dir}" /> </target> -<!-- =================================================================== --> -<!-- Compiles the source code --> -<!-- =================================================================== --> +<!-- =================================================================== --> +<!-- Compiles the source code --> +<!-- =================================================================== --> <target name="compile" depends="prepare,check_for_optional_packages"> - <mkdir dir="${build.classes}" /> - <javac srcdir="${src.dir}" destdir="${build.classes}" + <mkdir dir="${build.classes}" /> + <javac srcdir="${src.dir}" destdir="${build.classes}" debug="on" deprecation="on" optimize="off"> <classpath refid="base.classpath" /> <exclude name="**/servletunit/*" unless="jsdk.present" /> @@ -71,12 +71,12 @@ </target> -<!-- =================================================================== --> +<!-- =================================================================== --> <!-- Compiles the test code --> -<!-- =================================================================== --> +<!-- =================================================================== --> <target name="testcompile" depends="compile,check_for_optional_packages"> <mkdir dir="${test.classes}" /> - <javac srcdir="${tstsrc.dir}" destdir="${test.classes}" + <javac srcdir="${tstsrc.dir}" destdir="${test.classes}" debug="off" deprecation="on" optimize="off"> <classpath> <path refid="base.classpath" /> @@ -89,7 +89,7 @@ </target> -<!-- =================================================================== --> +<!-- =================================================================== --> <!-- Runs the test code --> <!-- =================================================================== --> <target name="test" depends="testcompile"> @@ -117,32 +117,49 @@ </target> +<!-- =================================================================== --> +<!-- Creates the jar archive --> <!-- =================================================================== --> -<!-- Creates the jar archive --> -<!-- =================================================================== --> <target name="jar" depends="compile"> - <mkdir dir="${lib.dir}" /> - <jar jarfile="${lib.dir}/${name}.jar" basedir="${build.classes}" includes="com/**" /> + <mkdir dir="${lib.dir}" /> + <jar jarfile="${lib.dir}/${name}.jar" basedir="${build.classes}" includes="com/**" /> </target> -<!-- =================================================================== --> -<!-- Creates the API documentation --> -<!-- =================================================================== --> +<!-- =================================================================== --> +<!-- Creates the API documentation --> +<!-- =================================================================== --> <target name="javadocs" depends="prepare"> - <mkdir dir="${javadoc.dir}" /> - <javadoc packagenames="${packages}" sourcepath="${basedir}/${src.dir}" - destdir="${javadoc.dir}" author="true" version="true" - windowtitle="${Name} ${version} API" doctitle="${Name}" - footer="Copyright &copy; 2000-2001 Russell Gold. See <a href="http://httpunit.sourceforge.net/doc/license.html">license agreement</A> for rights granted." /> + <mkdir dir="${javadoc.dir}" /> + <javadoc packagenames="${packages}" sourcepath="${basedir}/${src.dir}" + destdir="${javadoc.dir}" author="true" version="true" + windowtitle="${Name} ${version} API" doctitle="${Name}" + footer="Copyright &copy; 2000-2001 Russell Gold. See <a href="http://httpunit.sourceforge.net/doc/license.html">license agreement</A> for rights granted." /> +</target> + + +<!-- =================================================================== --> +<!-- Creates the tutorial archives --> +<!-- =================================================================== --> +<target name="tutorial" depends="jar"> + <mkdir dir="${build.dir}/tutorial" /> + <copy todir="${build.dir}/tutorial" > + <fileset dir="${docs.dir}/tutorial"> + <include name="build.xml" /> + <include name="web.xml" /> + <include name="**/persistence/*.java" /> + </fileset> + </copy> + <mkdir dir="${build.dir}/tutorial/jars" /> + <zip zipfile="${docs.dir}/tutorial/task1.zip" basedir="${build.dir}/tutorial" includes="**" /> </target> -<!-- =================================================================== --> -<!-- Creates the distribution --> -<!-- =================================================================== --> -<target name="dist" depends="jar,javadocs"> - <mkdir dir="${dist.dir}" /> +<!-- =================================================================== --> +<!-- Creates the distribution --> +<!-- =================================================================== --> +<target name="dist" depends="jar,javadocs,tutorial"> + <mkdir dir="${dist.dir}" /> <copy todir="${dist.dir}" > <fileset dir="." > <include name="build.xml" /> @@ -156,16 +173,16 @@ </fileset> </copy> <copy todir="${dist.dir}/lib" file="${jars.dir}/Tidy.jar" /> - <replace file="${dist.dir}/index.html" token="var:dist " value="var:dist>" /> - <replace file="${dist.dir}/index.html" token="var:publish>" value="var:publish " /> + <replace file="${dist.dir}/index.html" token="var:dist " value="var:dist>" /> + <replace file="${dist.dir}/index.html" token="var:publish>" value="var:publish " /> </target> -<!-- =================================================================== --> -<!-- Packages the distribution with ZIP --> -<!-- =================================================================== --> +<!-- =================================================================== --> +<!-- Packages the distribution with ZIP --> +<!-- =================================================================== --> <target name="dist-zip" depends="dist"> - <zip zipfile="${name}_${zip_version}.zip" basedir="${dist.dir}" includes="**" /> + <zip zipfile="${name}_${zip_version}.zip" basedir="${dist.dir}" includes="**" /> </target> @@ -177,37 +194,38 @@ <copy todir="${web.dir}" > <fileset dir="." includes="*.zip,index.html,doc/**"/> </copy> - <replace file="${web.dir}/index.html" token="var:dist>" value="var:dist " /> + <replace file="${web.dir}/index.html" token="var:dist>" value="var:dist " /> <replace file="${web.dir}/index.html" token="var:publish " value="var:publish>" /> - <replace file="${web.dir}/index.html" token="<version>" value="${zip_version}" /> + <replace file="${web.dir}/index.html" token="<version>" value="${zip_version}" /> </target> -<!-- =================================================================== --> -<!-- Packages the web site with ZIP --> -<!-- =================================================================== --> +<!-- =================================================================== --> +<!-- Packages the web site with ZIP --> +<!-- =================================================================== --> <target name="publish-zip" depends="publish"> - <zip zipfile="${name}_website_${zip_version}.zip" basedir="${web.dir}" includes="**" /> + <zip zipfile="${name}_website_${zip_version}.zip" basedir="${web.dir}" includes="**" /> </target> -<!-- =================================================================== --> -<!-- Cleans up generated stuff --> -<!-- =================================================================== --> +<!-- =================================================================== --> +<!-- Cleans up generated stuff --> +<!-- =================================================================== --> <target name="clean"> - <delete dir="${build.dir}" /> + <delete dir="${build.dir}" /> <delete dir="${dist.dir}" /> <delete dir="${web.dir}" /> </target> -<!-- =================================================================== --> -<!-- Total cleanup --> -<!-- =================================================================== --> +<!-- =================================================================== --> +<!-- Total cleanup --> +<!-- =================================================================== --> <target name="total-clean" depends="clean"> - <delete file="${name}_*.zip" quiet="true" /> + <delete file="${name}_*.zip" quiet="true" /> <delete dir="${docs.dir}/api" /> - <delete dir="${lib.dir}" /> + <delete dir="${docs.dir}/tutorial/*.zip" /> + <delete dir="${lib.dir}" /> </target> - + </project> |
From: Russell G. <rus...@us...> - 2001-11-12 20:23:51
|
Update of /cvsroot/httpunit/httpunit/doc/tutorial/src/tutorial/persistence In directory usw-pr-cvs1:/tmp/cvs-serv11921/doc/tutorial/src/tutorial/persistence Log Message: Directory /cvsroot/httpunit/httpunit/doc/tutorial/src/tutorial/persistence added to the repository |