1 package WWW
::Mechanize
::Script
;
6 use File
::Basename
qw(fileparse);
7 use File
::Path
qw(make_path);
10 use Module
::Pluggable
::Object
();
11 use Params
::Util
qw(_HASH);
13 use WWW
::Mechanize
();
14 use WWW
::Mechanize
::Timed
();
16 # ABSTRACT: fetch websites and executes tests on the results
20 use WWW::Mechanize::Script;
22 my $wms = WWW::Mechanize::Script->new();
23 $wms->run_script(@script);
25 foreach my $test (@script) {
26 $wms->run_test(%{$test});
31 our $VERSION = '0.001_003';
35 Instantiates new WWW
::Mechanize
::Script object
.
37 Configuration hash looks like
:
40 check
=> { # check defaults
45 request
=> { # request defaults
46 agent
=> { # LWP::UserAgent defaults
47 agent
=> "Agent Adderly",
48 accept_cookies
=> 'yes', # check LWP::UA param
49 show_cookie
=> 'yes', # check LWP::UA param
50 show_headers
=> 'yes', # check LWP::UA param
51 send_cookie
=> 'yes', # check LWP::UA param
55 script_dirs
=> [qw(/old/wtscripts /new/json_scripts)],
57 template
=> "[% CODE_NAME; IF MESSAGES.size > 0 %] - [% MESSAGES.join(', '); END %]\n",
61 template
=> "[% USE Dumper; Dumper.dump(RESPONSE) %]",
62 target
=> "/tmp/@OPTS_FILE@.log",
70 my ( $class, $cfg ) = @_;
72 my $self = bless( { cfg
=> { %{$cfg} } }, $class );
77 =method _gen_code_compute
79 Interpretes one of following config hash parameters
82 check
=> { # check defaults
84 code_func
=> 'my ($cur,$new) = @_; return $cur > $new ? $cur : $new;'
88 When none of them are there
, the sample
in defaults
->check->code_func is used
.
94 my $check_cfg = $_[0];
97 if ( defined( $check_cfg->{code_func
} ) )
99 my $compute_str = "sub { " . $check_cfg->{code_func
} . " };";
100 $compute_code = eval $compute_str;
104 if ( !defined($compute_code) and defined( $check_cfg->{code_cmp
} ) )
107 "sub { my (\$cur,\$new) = \@_; \$cur "
108 . $check_cfg->{code_cmp
}
109 . " \$new ? \$cur : \$new; };";
110 $compute_code = eval $compute_str;
114 if ( !defined($compute_code) )
116 my $compute_str = "sub { my (\$cur,\$new) = \@_; \$cur > \$new ? \$cur : \$new; };";
117 $compute_code = eval $compute_str;
121 return $compute_code;
124 =method test_plugins
( )
126 The C
<plugins
()> classmethod returns the names of configuration loading plugins as
127 found by L
<Module
::Pluggable
::Object
|Module
::Pluggable
::Object
>.
133 my ( $self, $test ) = @_;
135 unless ( defined( $self->{all_plugins
} ) )
137 my $plugin_base = join( "::", __PACKAGE__
, "Plugin" );
139 Module
::Pluggable
::Object
->new(
141 search_path
=> [$plugin_base],
142 except
=> [$plugin_base],
144 only
=> qr/^${plugin_base}::\p{Word}+$/,
147 # filter out things that don't look like our plugins
149 map { $_->new( $self->{cfg
}->{defaults
} ) }
150 grep { $_->isa($plugin_base) } $finder->plugins();
151 $self->{all_plugins
} = \
@ap;
154 my @tp = grep { $_->can_check($test) } @
{ $self->{all_plugins
} };
158 =method get_request_value
($request,$value_name)
160 Returns the value
for creating the request
- either from current script
161 or from defaults
(C
<< defaults
->request->$value_name >>).
165 sub get_request_value
167 my ( $self, $request, $value_name ) = @_;
169 $value_name or return;
171 return $request->{$value_name} // $self->{cfg
}->{default}->{request
}->{$value_name};
178 my $target = $def->{target
};
181 if ( $target ne "-" and $def->{append
} )
183 my ( $name, $path, $suffix ) = fileparse
($target);
184 -d
$path or make_path
($path);
185 my $fh = IO
::File
->new( $target, ">>" );
186 $fh->seek( 0, SEEK_END
);
193 =method summarize
($code,@msgs)
195 Generates the summary passing the template
in the configuration of
196 C
<< config
->summary >> into L
<Template
::Toolkit
>.
198 Following variables are provided
for the template processing
:
204 The accumulated return code of all executed checks computed via
205 L</_gen_code_compute>.
209 Collected messages returned of all executed checks.
213 Plus all constants named in the C<< config->templating->vars >> hash and
214 those in C<< config->summary->vars >> hash.
216 The output target is guessed from C<< config->summary->target >> whereby
217 the special target I<-> is interpreted as C<stdout>.
223 my ( $self, $code, @msgs ) = @_;
226 %{ _HASH
( $self->{cfg
}->{templating
}->{vars
} ) // {} },
227 %{ _HASH
( $self->{cfg
}->{report
}->{vars
} ) // {} },
232 my $input = $self->{cfg
}->{summary
}->{source
} // \
$self->{cfg
}->{summary
}->{template
};
233 my $output = _get_target
( $self->{cfg
}->{summary
} );
234 my $template = Template
->new();
235 $template->process( $input, \
%vars, $output )
236 or die $template->error();
241 =method gen_report
($full_test, $mech, $code, @msgs)
243 Generates a report
for a test within a script by passing the template
244 in the configuration of C
<< config
->report >> into L
<Template
::Toolkit
>.
246 Following variables are provided
for the template processing
:
252 The accumulated return code of all executed checks computed via
253 L</_gen_code_compute>.
257 Collected messages returned of all executed checks.
261 Hash containing the following L<HTTP::Response|response> items:
271 Content of the response
275 The base URI for this response
279 Header keys/values as perl hash
285 Plus all constants named in the C<< config->templating->vars >> hash and
286 those in C<< config->report->vars >> hash.
288 The output target is guessed from C<< config->summary->target >> whereby
289 the special target I<-> is interpreted as C<stdout>.
291 When the C<< config->summary->append >> flag is set and contains a true
292 value, the output is appended to an existing target.
298 my ( $self, $full_test, $mech, $code, @msgs ) = @_;
299 my $response = $mech->response();
301 %{ _HASH
( $self->{cfg
}->{templating
}->{vars
} ) // {} },
302 %{ _HASH
( $self->{cfg
}->{report
}->{vars
} ) // {} },
306 CODE
=> $response->code(),
307 CONTENT
=> $response->content(),
308 BASE
=> $response->base(),
310 map { $_ => $response->headers()->header($_) }
311 $response->headers()->header_field_names()
316 my $input = $self->{cfg
}->{report
}->{source
} // \
$self->{cfg
}->{report
}->{template
};
317 my $output = _get_target
( $self->{cfg
}->{report
} );
318 my $template = Template
->new();
319 $template->process( $input, \
%vars, $output )
320 or die $template->error();
325 =method run_script
(@script)
327 Runs a script consisting of at least one test
and generates a summary
if
328 configured
. The code to accumulate the
return codes from
each test is taken
329 from C
<< config
->defaults->check >> as described
in L
</_gen_code_compute
>.
331 Returns the accumulated
return codes from all tests
in the
given script
.
337 my ( $self, @script ) = @_;
340 my $compute_code = _gen_code_compute
( $self->{cfg
}->{defaults
}->{check
} );
342 foreach my $test (@script)
344 my ( $test_code, @test_msgs ) = $self->run_test($test);
345 $code = &{$compute_code}( $code, $test_code );
346 push( @msgs, @test_msgs );
349 if ( $self->{cfg
}->{summary
} )
351 my $summary = $self->summarize( $code, @msgs );
354 return ( $code, @msgs );
357 =method run_test
(\
%test)
359 Runs one test
and generates a report
if configured
(C
<< config
->report >>).
361 The request is constructed from C
<< test
->request >> whereby the part
362 below C
<< test
->request->agent >> is used to parametrize a new instance
363 of L
<WWW
::Mechanize
::Timed
>.
365 All
keys defined below C
<< test
->request->agent >> are taken as
366 setter of WWW
::Mechanize
::Timed
or a inherited
class.
368 If there is a hash
defined at C
<< test
->request->http_headers >>, those
369 headers are passed along with the URI specified at C
<< test
->request->uri >>
370 to GET
/POST
or whatever you want to
do (C
<< test
->request->method >>).
372 Which checks are executed is
defined below C
<< test
->check >>. Each valid
373 plugin below the I
<WWW
::Mechanize
::Script
::Plugin
> namespace is approved
374 for relevance
for the test
(see L
<WWW
::Mechanize
::Script
::Plugin
/can_check
>).
376 The code to accumulate the
return codes from
each test is taken
377 from C
<< test
->check >> as described
in L
</_gen_code_compute
>.
379 Returns the accumulated
return codes from all checks
in the
given tests
.
385 my ( $self, $test ) = @_;
387 my $merger = Hash
::Merge
->new('LEFT_PRECEDENT');
388 my $full_test = $merger->merge( $test, $self->{cfg
}->{defaults
} );
390 my $mech = WWW
::Mechanize
::Timed
->new();
391 foreach my $akey ( keys %{ $full_test->{request
}->{agent
} } )
393 # XXX clone and delete array args before
394 $mech->$akey( $full_test->{request
}->{agent
}->{$akey} );
397 my $method = $full_test->{request
}->{method
};
398 defined( $test->{request
}->{http_headers
} )
399 ?
$mech->$method( $full_test->{request
}->{uri
}, %{ $full_test->{request
}->{http_headers
} } )
400 : $mech->$method( $full_test->{request
}->{uri
} );
402 $full_test->{compute_code
} = _gen_code_compute
( $full_test->{check
} );
406 foreach my $tp ( $self->test_plugins($full_test) )
408 my ( $plug_code, @plug_msgs ) = $tp->check_response( $full_test, $mech );
409 $code = &{ $full_test->{compute_code
} }( $code, $plug_code );
410 push( @msgs, @plug_msgs );
413 if ( $self->{cfg
}->{report
} )
415 $self->gen_report( $full_test, $mech, $code, @msgs );
418 return ( $code, @msgs );