File Coverage

blib/lib/PITA/Scheme.pm
Criterion Covered Total %
statement 22 24 91.6
branch n/a
condition n/a
subroutine 8 8 100.0
pod n/a
total 30 32 93.7


line stmt bran cond sub pod time code
1             package PITA::Scheme;
2              
3             =pod
4              
5             =head1 NAME
6              
7             PITA::Scheme - PITA Testing Schemes
8              
9             =head1 SYNOPSIS
10              
11             # Have the scheme load up from the provided config
12             my $scheme = PITA::Scheme->new(
13             injector => $injector,
14             workarea => $workarea,
15             );
16            
17             # Prepare to run the tests
18             $scheme->prepare_all;
19            
20             # Run the tests
21             $scheme->execute_all;
22              
23             =head1 DESCRIPTION
24              
25             While most of the L system exists outside the guest testing images and
26             tries to have as little interaction with them as possible, there is one
27             part that needs to be run from inside it.
28              
29             PITA::Scheme objects live inside the image and does three main tasks.
30              
31             1. Unpack the package and prepare the testing environment
32              
33             2. Run the sequence of commands to execute the tests and capture
34             the results.
35              
36             3. Package the results as a L and send it to the
37             L.
38              
39             This functionality is implemented in a module structure that is highly
40             subclassable. In this way, L can support multiple different
41             testing schemes for multiple different languages and installer types.
42              
43             =head1 Setting up a Testing Image
44              
45             Each image that will be set up will require a bit of customisation,
46             as the entire point of this type of testing is that every environment
47             is different.
48              
49             However, by keeping most of the functionality in the L
50             objects, all you should need to do is to arrange for a simple Perl
51             script to be launched, that feeds some initial configuration to the
52             L object.
53              
54             And it should do the rest. Or die... but we'll cover that later.
55              
56             =head1 METHODS
57              
58             Please excuse the lack of details for now...
59              
60             TO BE COMPLETED
61              
62             =cut
63              
64 4     4   24930 use 5.006;
  4         13  
  4         149  
65 4     4   32 use strict;
  4         8  
  4         138  
66 4     4   73 use Carp ();
  4         23  
  4         64  
67 4     4   4083 use IPC::Run3 ();
  4         55036  
  4         95  
68 4     4   36 use File::Spec ();
  4         7  
  4         60  
69 4     4   2911 use Data::GUID ();
  4         57437  
  4         132  
70 4     4   39 use Params::Util qw{ _INSTANCE _POSINT _STRING _ARRAY _CLASS };
  4         9  
  4         375  
71 4     4   6690 use PITA::XML ();
  0            
  0            
72              
73             use vars qw{$VERSION};
74             BEGIN {
75             $VERSION = '0.43';
76             }
77              
78              
79              
80              
81              
82             #####################################################################
83             # Constructor
84              
85             sub new {
86             my $class = shift;
87             my $self = bless { @_ }, $class;
88              
89             # Apply the default path if needed
90             unless ( $self->path ) {
91             $self->{path} = $self->default_path;
92             }
93              
94             # Cursory checking for compulsory params
95             foreach my $param ( qw{ injector workarea scheme path } ) {
96             next if $self->$param();
97             Carp::croak("Missing compulsory param '$param'");
98             }
99              
100             # Load the request from a file if needed
101             unless ( $self->request ) {
102             $self->{request_xml} = File::Spec->catfile( $self->injector, $self->request_xml );
103             unless ( -f $self->request_xml and -r _ ) {
104             Carp::croak('Missing request file, or no permissions');
105             }
106             $self->{request} = PITA::XML::Request->read( $self->request_xml );
107             }
108             unless ( _INSTANCE($self->request, 'PITA::XML::Request') ) {
109             Carp::croak(
110             "Bad report Request or failed to load one from "
111             . $self->request_xml
112             );
113             }
114             unless ( $self->request->scheme eq $self->scheme ) {
115             Carp::croak("Test scheme in image.conf does not match Request scheme");
116             }
117              
118             # Check the request identifier
119             unless ( _GUID($self->request_id) ) {
120             Carp::croak("Missing or bad request_id for this test instance");
121             }
122              
123             $self;
124             }
125              
126              
127              
128              
129              
130             #####################################################################
131             # Accessors and convience methods
132              
133             sub injector {
134             $_[0]->{injector};
135             }
136              
137             sub workarea {
138             $_[0]->{workarea};
139             }
140              
141             sub scheme {
142             $_[0]->{scheme};
143             }
144              
145             sub path {
146             $_[0]->{path};
147             }
148              
149             sub request_xml {
150             $_[0]->{request_xml};
151             }
152              
153             sub request {
154             $_[0]->{request};
155             }
156              
157             sub request_id {
158             my $self = shift;
159             if ( $self->request and $self->request->id ) {
160             # New style request with an id
161             return $self->request->id;
162             } else {
163             # Manually passed request_id
164             return $self->{request_id};
165             }
166              
167             undef;
168             }
169              
170             sub platform {
171             $_[0]->{platform};
172             }
173              
174             sub install {
175             $_[0]->{install};
176             }
177              
178             sub report {
179             $_[0]->{report};
180             }
181              
182              
183              
184              
185              
186             #####################################################################
187             # PITA::Scheme Methods
188              
189             sub load_config {
190             my $self = shift;
191              
192             # Load the config file
193             $self->{config} = Config::Tiny->new( $self->{config_file} );
194             unless ( $self->{config} ) {
195             Carp::croak("Failed to load config file: " . Config::Tiny->errstr);
196             }
197              
198             # Validate some basics
199              
200             1;
201             }
202              
203             # Do the various preparations
204             sub prepare_all {
205             my $self = shift;
206             return 1 if $self->install;
207              
208             # Prepare the package
209             $self->prepare_package;
210              
211             # Prepare the environment
212             $self->prepare_environment;
213              
214             # Prepare the report
215             $self->prepare_report;
216              
217             1;
218             }
219              
220             # Nothing, yet
221             sub prepare_package {
222             my $self = shift;
223             1;
224             }
225              
226             sub prepare_report {
227             my $self = shift;
228             return 1 if $self->install;
229              
230             # Create the install object
231             $self->{install} = PITA::XML::Install->new(
232             request => $self->request,
233             platform => $self->platform,
234             );
235              
236             # Create the main report object
237             $self->{report} ||= PITA::XML::Report->new;
238             $self->report->add_install( $self->install );
239              
240             1;
241             }
242              
243             sub execute_command {
244             my $self = shift;
245             my $cmd = _ARRAY( [ @_ ] ) or Carp::croak(
246             "execute_command not passed an ARRAY ref as command"
247             );
248              
249             # Execute the command
250             my $stdout = '';
251             my $stderr = '';
252             my $success = IPC::Run3::run3( $cmd, \undef, \$stdout, \$stderr );
253              
254             # Turn the results into a Command object
255             my $command = PITA::XML::Command->new(
256             cmd => join( ' ', @$cmd ),
257             stdout => \$stdout,
258             stderr => \$stderr,
259             );
260             unless ( _INSTANCE($command, 'PITA::XML::Command') ) {
261             Carp::croak("Error creating ::Command");
262             }
263              
264             # If we have a PITA::XML::Install object available,
265             # automatically add to it.
266             if ( $self->install ) {
267             $self->install->add_command( $command );
268             }
269              
270             $command;
271             }
272              
273              
274              
275              
276              
277             #####################################################################
278             # Support Methods
279              
280             # Validate a usable scheme, returning a (loaded) driver class
281             sub _DRIVER {
282             my $class = shift;
283              
284             # Resolve the specific testing scheme class for this run
285             my $scheme = shift;
286             unless ( _STRING($scheme) ) {
287             Carp::croak("Missing or invalid scheme");
288             }
289             my $driver = join( '::', 'PITA', 'Scheme', map { ucfirst $_ } split /\./, lc($scheme || '') );
290             unless ( _CLASS($driver) ) {
291             Carp::croak("Invalid scheme '$scheme'");
292             }
293              
294             # Load the scheme class
295             eval "require $driver;";
296             if ( $@ =~ /^Can\'t locate PITA/ ) {
297             Carp::croak("Scheme '$scheme' is unsupported on this Guest");
298             } elsif ( $@ ) {
299             Carp::croak("Error loading scheme '$scheme' driver $driver: $@");
300             }
301              
302             $driver;
303             }
304              
305             sub _GUID {
306             my $guid = eval {
307             Data::GUID->from_any_string(shift);
308             };
309             $@ ? undef : $guid;
310             }
311              
312             1;
313              
314             =pod
315              
316             =head1 SUPPORT
317              
318             Bugs should be reported via the CPAN bug tracker at
319              
320             L
321              
322             For other issues, contact the author.
323              
324             =head1 AUTHOR
325              
326             Adam Kennedy Eadamk@cpan.orgE, L
327              
328             =head1 SEE ALSO
329              
330             The Perl Image Testing Architecture (L)
331              
332             L, L, L
333              
334             =head1 COPYRIGHT
335              
336             Copyright 2005 - 2011 Adam Kennedy.
337              
338             This program is free software; you can redistribute
339             it and/or modify it under the same terms as Perl itself.
340              
341             The full text of the license can be found in the
342             LICENSE file included with this module.
343              
344             =cut