stas 01/12/24 11:30:25
Modified: src/devel/writing_tests writing_tests.pod
Log:
document how to:
- start multiple servers
- use multiple user agents
- hit the same interpreter
Revision Changes Path
1.25 +133 -0 modperl-docs/src/devel/writing_tests/writing_tests.pod
Index: writing_tests.pod
===================================================================
RCS file: /home/cvs/modperl-docs/src/devel/writing_tests/writing_tests.pod,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -r1.24 -r1.25
--- writing_tests.pod 2001/12/24 05:47:46 1.24
+++ writing_tests.pod 2001/12/24 19:30:25 1.25
@@ -888,6 +888,139 @@
=back
+=head2 Request Generation Methods
+
+META: here goes the explanation of shortcuts: GET_BODY, POST_BODY,
+etc.
+
+=head2 Starting Multiple Servers
+
+By default the C<Apache::Test> framework sets up only a single server
+to test against.
+
+In some cases you need to have more than one server. If this is the
+situation, you have to override the I<maxclients> configuration
+directive, whose default is 1. Usually this is done in C<t/TEST.PL> by
+subclassing the parent test run class and overriding the
+new_test_config() method. For example if the parent class is
+C<Apache::TestRunPerl>, you can change your C<t/TEST.PL> to be:
+
+ use strict;
+ use warnings FATAL => 'all';
+
+ use lib "../lib"; # test against the source lib for easier dev
+ use lib map {("../blib/$_", "../../blib/$_")} qw(lib arch);
+
+ use Apache::TestRunPerl ();
+
+ package MyTest;
+
+ our @ISA = qw(Apache::TestRunPerl);
+
+ # subclass new_test_config to add some config vars which will be
+ # replaced in generated httpd.conf
+ sub new_test_config {
+ my $self = shift;
+
+ $self->{conf_opts}->{maxclients} = 2;
+
+ return $self->SUPER::new_test_config;
+ }
+
+ MyTest->new->run(@ARGV);
+
+=head2 Multiple User Agents
+
+By default the C<Apache::Test> framework uses a single user agent
+which talks to the server (this is the C<LWP> user agent, if you have
+C<LWP> installed). You almost never use this agent directly in the
+tests, but via various wrappers. However if you need a second user
+agent you can clone these. For example:
+
+ my $ua2 = Apache::TestRequest::user_agent()->clone;
+
+
+=head2 Hitting the Same Interpreter (Server Thread/Process Instance)
+
+When a single instance of the server thread/process is running, all
+the tests go through the same server. However if the C<Apache::Test>
+framework was configured to to run a few instances, two subsequent
+sub-tests may not hit the same server instance. In certain tests
+(e.g. testing the closure effect or the C<BEGIN> blocks) it's
+important to make sure that a sequence of sub-tests are run against
+the same server instance. The C<Apache::Test> framework supports this
+internally.
+
+Here is an example from C<ModPerl::Registry> closure tests. Using the
+counter closure problem under C<ModPerl::Registry>:
+
+ cgi-bin/closure.pl
+ ------------------
+ #!perl -w
+ print "Content-type: text/plain\r\n\r\n";
+
+ # this is a closure (when compiled inside handler()):
+ my $counter = 0;
+ counter();
+
+ sub counter {
+ #warn "$$";
+ print ++$counter;
+ }
+
+If this script get invoked twice in a row and we make sure that it
+gets executed by the same server instance, the first time it'll return
+1 and the second time 2. So here is the gist of the request part that
+makes sure that its two subsequent requests hit the same server
+instance:
+
+ closure.t
+ ---------
+ ...
+ my $url = "/same_interp/cgi-bin/closure.pl";
+ my $same_interp = Apache::TestRequest::same_interp_tie($url);
+
+ # should be no closure effect, always returns 1
+ my $first = req($same_interp, $url);
+ my $second = req($same_interp, $url);
+ ok t_cmp(
+ 1,
+ $first && $second && ($second - $first),
+ "the closure problem is there",
+ );
+ sub req {
+ my($same_interp, $url) = @_;
+ my $res = Apache::TestRequest::same_interp_do($same_interp,
+ \&GET, $url);
+ return $res ? $res->content : undef;
+ }
+
+In this test we generate two requests to I<cgi-bin/closure.pl> and
+expect the returned value to increment for each new request, because
+of the closure problem generated by C<ModPerl::Registry>. Since we
+don't know whether some other test has called this script already, we
+simply check whether the substraction of the two subsequent requests'
+outputs gives a value of 1.
+
+The test starts by requesting the server to tie a single instance to
+all requests made with a certain identifier. This is done using the
+same_interp_tie() function which returns a unique server instance's
+indentifier. From now on any requests made through same_interp_do()
+and supplying this indentifier as the first argument will be served by
+the same server instance. The second argument to same_interp_do() is
+the method to use for generating the request and the third is the URL
+to use. Extra arguments can be supplied if needed by the request
+generation method (e.g. headers).
+
+This technique works for testing purposes where we know that we have
+just a few server instances. What happens internally is when
+same_interp_tie() is called the server instance that served it returns
+its unique UUID, so when we want to hit the same server instance in
+subsequent requests we generate the same request until we learn that
+we are being served by the server instance that we want. This magic is
+done by using a fixup handler which returns C<OK> only if it sees that
+its unique id matches. As you understand this technique would be very
+inefficient in production with many server instances.
=head1 How to Write Tests
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]