File Coverage

blib/lib/HTTP/WebTest/Utils.pm
Criterion Covered Total %
statement 157 176 89.2
branch 23 46 50.0
condition n/a
subroutine 43 45 95.5
pod 8 8 100.0
total 231 275 84.0


line stmt bran cond sub pod time code
1             # $Id: Utils.pm,v 1.9 2003/03/02 11:52:10 m_ilya Exp $
2              
3             package HTTP::WebTest::Utils;
4              
5             =head1 NAME
6              
7             HTTP::WebTest::Utils - Miscellaneous subroutines used by HTTP::WebTest
8              
9             =head1 SYNOPSIS
10              
11             use HTTP::WebTest::Utils;
12              
13             *method = make_access_method($field);
14             *method = make_access_method($field, $default_value);
15             *method = make_access_method($field, sub { ... });
16              
17             find_port(hostname => $hostname);
18             my $pid = start_webserver(port => $port, server_sub => sub { ... });
19             stop_webserver($pid);
20              
21             copy_dir($src_dir, $dst_dir);
22              
23             load_package($package);
24              
25             my $ret = eval_in_playground($code);
26             die $@ if $@;
27              
28             =head1 DESCRIPTION
29              
30             This packages contains utility subroutines used by
31             L. All of them can be exported but none
32             of them is exported by default.
33              
34             =head1 SUBROUTINES
35              
36             =cut
37              
38 24     24   163 use strict;
  24         52  
  24         1627  
39              
40 24     24   144 use Cwd;
  24         42  
  24         2075  
41 24     24   29056 use File::Copy;
  24         95513  
  24         2297  
42 24     24   191 use File::Find;
  24         52  
  24         1483  
43 24     24   144 use File::Path;
  24         44  
  24         1442  
44 24     24   25802 use File::Spec::Functions;
  24         27045  
  24         2421  
45 24     24   27251 use HTTP::Daemon;
  24         15072292  
  24         441  
46              
47 24     24   27695 use base qw(Exporter);
  24         215  
  24         20088  
48              
49 24     24   169 use vars qw(@EXPORT_OK);
  24         55  
  24         28481  
50              
51             @EXPORT_OK = qw(make_access_method find_port
52             copy_dir load_package
53             eval_in_playground make_sub_in_playground
54             start_webserver stop_webserver);
55              
56             =head2 make_access_method($field, $optional_default_value)
57              
58             Creates anonymous subroutine which can be used as accessor
59             method. Method can be used with objects that are blessed hashes.
60              
61             Typical usage is
62              
63             *method = make_access_method($field, ...);
64              
65             =head3 Parameters
66              
67             =over 4
68              
69             =item * $field
70              
71             A hash field used for created accessor method.
72              
73             =item * $optional_default_value
74              
75             If C<$optional_default_value> is a code reference, uses values returned
76             by its execution as default for created accessor method. Otherwise,
77             uses C<$optional_default_value> as name of method which returns
78             default value for created accessor method.
79              
80             =back
81              
82             =head3 Returns
83              
84             =cut
85              
86             sub make_access_method {
87             # field name
88 388     388 1 1071 my $field = shift;
89             # subroutine or method which returns some default value for field
90 388         503 my $default_value = shift;
91              
92             my $sub = sub {
93 106012     106012   166172 my $self = shift;
94              
95 106012 100       283569 if(@_) {
96 4249         12232 $self->{$field} = shift;
97             }
98              
99 106012 100       357550 unless(defined $self->{$field}) {
100 344 100       1273 if(defined $default_value) {
101 255 100       761 if(ref($default_value) eq 'CODE') {
102 157         618 $self->{$field} = $default_value->($self);
103             } else {
104 98         597 $self->{$field} = $self->$default_value();
105             }
106             }
107             }
108              
109 106012         487061 return $self->{$field};
110 388         3128 };
111             }
112              
113             =head2 find_port (hostname => $hostname)
114              
115             =head3 Returns
116              
117             Free port number for network interface specified by C<$hostname>.
118              
119             =cut
120              
121             sub find_port {
122 20     20 1 100 my %param = @_;
123              
124 20         54 my $hostname = $param{hostname};
125              
126 20 50       303 my $daemon =
127             HTTP::Daemon->new(($hostname ? (LocalAddr => $hostname) : ()));
128              
129 20 50       9549 if(defined $daemon) {
130 20         211 my $port = $daemon->sockport;
131 20         974 $daemon->close;
132 20         16556 return $port;
133             }
134              
135 0         0 return undef;
136             }
137              
138             =head2 start_webserver(%params)
139              
140             Starts separate process with a test webserver.
141              
142             =head3 Parameters
143              
144             =over 4
145              
146             =item port => $port
147              
148             A port number where the test webserver listens for incoming connections.
149              
150             =item server_sub => $server_sub
151              
152             A reference on a subroutine to handle requests. It get passed two
153             named parameters: C and C.
154              
155             =back
156              
157             =cut
158              
159             sub start_webserver {
160 19     19 1 306 my %param = @_;
161              
162 19 50       310 my $daemon = HTTP::Daemon->new(LocalPort => $param{port}, Reuse => 1)
163             or die;
164              
165             # create daemon process
166 19         59744 my $pid = fork;
167 19 50       1804 die unless defined $pid;
168 19 100       4492 return $pid if $pid != 0;
169              
170             # when we are run under debugger do not stop and call debugger at
171             # the exit of the forked process. This helps to workaround problem
172             # when forked process tries to takeover and to screw the terminal
173 9         176 $DB::inhibit_exit = 0;
174              
175             # if we are running with Test::Builder do not let it output
176             # anything for daemon process
177 9 100       576733 if(Test::Builder->can('new')) {
178 8         447 Test::Builder->new->no_ending(1);
179             }
180              
181             # set 'we are working' flag
182 9         1505 my $done = 0;
183              
184             # exit on SIGTERM
185 9     9   2239 $SIG{TERM} = sub { $done = 1 };
  9         149  
186             # handle connections closed by client
187 9         254 $SIG{PIPE} = 'IGNORE';
188              
189             # handle requests till process is killed
190 9         98 eval {
191 9         144 until($done) {
192             # wait one tenth of second for connection
193 415         24401 my $rbits = '';
194 415         6945 vec($rbits, $daemon->fileno, 1) = 1;
195 415         28286343 my $nfound = select $rbits, '', '', 0.1;
196              
197             # handle incoming connections
198 415 100       6776 if($nfound > 0) {
199 183         2560 my $connect = $daemon->accept;
200 183 50       68381 die unless defined $connect;
201              
202 183         1423 while (my $request = $connect->get_request) {
203 183         2480170 $param{server_sub}->(connect => $connect,
204             request => $request);
205             }
206 183         21154134 $connect->close;
207             }
208             }
209             };
210             # in any event try to shutdown daemon nicely
211 9         196 $daemon->close;
212 9 50       633 if($@) { die $@ };
  0         0  
213              
214 9         1732 exit 0;
215             }
216              
217             =head2 stop_webserver($pid)
218              
219             Kills a test webserver specified by its PID.
220              
221             =cut
222              
223             sub stop_webserver {
224 10     10 1 6986 my $pid = shift;
225              
226 10         46732 return kill 'SIGTERM', $pid;
227             }
228              
229             =head2 copy_dir ($src_dir, $dst_dir)
230              
231             Copies directiory recursively.
232              
233             =cut
234              
235             sub copy_dir {
236 0     0 1 0 my $src_dir = shift;
237 0         0 my $dst_dir = shift;
238              
239 0         0 my $cwd = getcwd;
240              
241 0 0       0 $dst_dir = catdir($cwd, $dst_dir)
242             unless file_name_is_absolute($dst_dir);
243              
244             # define subroutine that copies files to destination directory
245             # directory
246             my $copytree = sub {
247 0     0   0 my $filename = $_;
248              
249 0         0 my $rel_dirname = $File::Find::dir;
250              
251 0 0       0 if(-d $filename) {
252             # create this directory in destination directory tree
253 0         0 my $path = catdir($dst_dir, $rel_dirname, $filename);
254 0 0       0 mkpath($path) unless -d $path;
255             }
256              
257 0 0       0 if(-f $filename) {
258             # copy this file to destination directory tree, create
259             # subdirectory if neccessary
260 0         0 my $path = catdir($dst_dir, $rel_dirname);
261 0 0       0 mkpath($path) unless -d $path;
262              
263 0 0       0 copy($filename, catfile($path, $filename))
264             or die "HTTP::WebTest: Can't copy file: $!";
265             }
266 0         0 };
267              
268             # descend recursively from directory, copy files to destination
269             # directory
270 0 0       0 chdir $src_dir
271             or die "HTTP::WebTest: Can't chdir to directory '$src_dir': $!";
272 0         0 find($copytree, '.');
273 0 0       0 chdir $cwd
274             or die "HTTP::WebTest: Can't chdir to directory '$cwd': $!";
275             }
276              
277             =head2 load_package ($package)
278              
279             Loads package unless it is already loaded.
280              
281             =cut
282              
283             sub load_package {
284 693     693 1 12517 my $package = shift;
285              
286             # check if package is loaded already (we are asuming that all of
287             # them have method 'new')
288 693 100       9004 return if $package->can('new');
289              
290 89         54735 eval "require $package";
291              
292 89 50       1266 die $@ if $@;
293             }
294              
295             =head2 eval_in_playground ($code)
296              
297             Evaluates perl code inside playground package.
298              
299             =head3 Returns
300              
301             A return value of evaluated code.
302              
303             =cut
304              
305             sub eval_in_playground {
306 73     73 1 231 my $code = shift;
307              
308 22     22   62 return eval <
  22     3   31  
  22     4   243  
  3     4   15  
  3     4   7  
  3     3   76  
  3     3   16  
  3     3   8  
  3     3   104  
  3     3   19  
  3     3   7  
  3     3   80  
  4     3   29  
  4     3   13  
  4     3   85  
  4     2   539  
  4     2   15  
  4     2   124  
  4     2   15403  
  3     2   5  
  4     2   191  
  4     2   37  
  4     2   2114  
  4     2   249  
  4     2   44  
  4         18  
  4         434  
  4         101  
  4         141  
  4         350  
  4         36  
  4         53  
  4         205  
  4         63  
  19         915  
  19         562  
  19         573173  
  19         200  
  16         304  
  16         9505  
  16         120  
  16         143181  
  16         13092  
  4         66  
  4         165  
  2         20  
  3         2075  
  2         75  
  2         13  
  2         5  
  2         60  
  2         13  
  2         11  
  2         67  
  2         13  
  2         5  
  2         63  
  2         14  
  2         6  
  2         56  
  2         18  
  2         4  
  2         138  
  2         15  
  2         4  
  2         8408  
  2         18  
  2         4  
  2         125  
  2         15  
  2         5  
  2         213  
  2         13  
  2         6  
  2         104  
  73         8223  
309             package HTTP::WebTest::PlayGround;
310              
311             no strict;
312             local \$^W; # aka no warnings in new perls
313              
314             $code
315             CODE
316             }
317              
318             =head2 make_sub_in_playground ($code)
319              
320             Create anonymous subroutine inside playground package.
321              
322             =head3 Returns
323              
324             A reference on anonymous subroutine.
325              
326             =cut
327              
328             sub make_sub_in_playground {
329 23     23 1 39 my $code = shift;
330              
331 23         79 return eval_in_playground("sub { local \$^W; $code }");
332             }
333              
334             =head1 COPYRIGHT
335              
336             Copyright (c) 2001-2003 Ilya Martynov. All rights reserved.
337              
338             This program is free software; you can redistribute it and/or modify
339             it under the same terms as Perl itself.
340              
341             =head1 SEE ALSO
342              
343             L
344              
345             L
346              
347             =cut
348              
349             1;