File Coverage

blib/lib/PITA/XML/Guest.pm
Criterion Covered Total %
statement 87 100 87.0
branch 18 28 64.2
condition 10 11 90.9
subroutine 23 25 92.0
pod 13 14 92.8
total 151 178 84.8


line stmt bran cond sub pod time code
1             package PITA::XML::Guest;
2              
3             =pod
4              
5             =head1 NAME
6              
7             PITA::XML::Guest - A testing environment, typically a system image
8              
9             =head1 SYNOPSIS
10              
11             # A simple guest using the local Perl
12             # (mostly used for test purposes)
13             my $dist = PITA::XML::Guest->new(
14             driver => 'Local',
15             params => {},
16             );
17              
18             =head1 DESCRIPTION
19              
20             C is an object for holding information about
21             a testing guest environment. A PITA Guest is a container with specific
22             operating system and hardware that contains one or more testing contexts,
23             represented in L by L objects.
24              
25             =head1 METHODS
26              
27             =cut
28              
29 10     10   205 use 5.006;
  10         32  
  10         403  
30 10     10   56 use strict;
  10         17  
  10         307  
31 10     10   55 use Carp ();
  10         20  
  10         153  
32 10     10   52 use File::Spec ();
  10         22  
  10         638  
33 10     10   53 use File::Basename ();
  10         27  
  10         187  
34 10     10   52 use Class::Inspector ();
  10         18  
  10         225  
35 10     10   47 use Params::Util qw{ _INSTANCE _STRING _CLASS _HASH0 _SET0 };
  10         21  
  10         704  
36 10     10   59 use PITA::XML::Storable ();
  10         20  
  10         500  
37              
38 10     10   48 use vars qw{$VERSION @ISA};
  10         18  
  10         671  
39             BEGIN {
40 10     10   59 $VERSION = '0.52';
41 10         11200 @ISA = 'PITA::XML::Storable';
42             }
43              
44 4     4 0 32 sub xml_entity { 'guest' }
45              
46              
47              
48              
49              
50             #####################################################################
51             # Constructor and Accessors
52              
53             my %ALLOWED = (
54             id => 1,
55             driver => 1,
56             config => 1,
57             base => 1,
58             );
59              
60             =pod
61              
62             =head2 new
63              
64             # The most correct way to specify a guest
65             my $guest1 = PITA::XML::Guest->new(
66             driver => 'Qemu',
67             config => {
68             memory => 256,
69             snapshot => 1,
70             }
71             );
72            
73             # Equivalent, using shorthand.
74             # Anything other that 'driver' is considered a config entry.
75             my $guest = PITA::XML::Guest->new(
76             driver => 'Qemu',
77             memory => 256,
78             snapshot => 1,
79             );
80              
81             The C constructor creates a new EguestE element.
82              
83             It has a single compulsory parameter of the guest driver name, and takes
84             optionally a set of named params to provide as creation params for the
85             guest driver object.
86              
87             Returns a new L or throw an exception on error.
88              
89             =cut
90              
91             sub new {
92 4     4 1 1049 my $class = shift;
93 4         31 my $self = bless { base => undef, @_ }, $class;
94              
95             # Move the non-core options into the config hash
96 4 50       46 unless ( _HASH0($self->{config}) ) {
97 4         13 $self->{config} = {};
98             }
99 4         35 foreach my $k ( sort keys %$self ) {
100 19 100       47 next if $ALLOWED{$k};
101 6         21 $self->{config}->{$k} = delete $self->{$k};
102             }
103              
104             # Check the object
105 4         19 $self->_init;
106              
107 4         10 $self;
108             }
109              
110             =pod
111              
112             =head2 read
113              
114             $guest = PITA::XML::Guest->new( 'guest.xml' );
115              
116             The C constructor loads a guest from an existing L file.
117              
118             Returns a new L object, or throws an exception on error.
119              
120             =cut
121              
122             sub read {
123 4     4 1 1468 my $class = shift;
124 4         8 my $file = shift;
125 4 50 66     53 if ( defined _STRING($file) and not -f $file ) {
126 0         0 Carp::croak("XML Guest file '$file' does not exist");
127             }
128              
129             # What is the directory context for the XML guest file
130 4 100       430 my $base = File::Basename::dirname(
131             File::Spec->rel2abs(
132             defined(_STRING($file)) ? $file : File::Spec->curdir
133             ),
134             );
135              
136             # Create the basic object
137 4         30 my $self = bless {
138             config => {},
139             base => $base,
140             @_,
141             }, $class;
142              
143             ### NOTE: DISABLED TILL WE FINALIZE THE SCHEMA
144             # Validate the document and reset the handle
145             # $class->validate( $fh );
146             # $fh->seek( 0, 0 ) or Carp::croak(
147             # 'Failed to reset file after validation (seek to 0)'
148             # );
149              
150             # Build the object from the file and validate
151 4         35 my $fh = PITA::XML->_FH($file);
152 4         43 my $parser = XML::SAX::ParserFactory->parser(
153             Handler => PITA::XML::SAXParser->new($self),
154             );
155 4         71411 $parser->parse_file($fh);
156              
157 4         1033 $self;
158             }
159              
160             # Format-check the parameters
161             sub _init {
162 8     8   17 my $self = shift;
163              
164             # Check the id, if it has one
165 8 100       33 if ( defined $self->id ) {
166 3 50       8 unless ( PITA::XML->_GUID($self->id) ) {
167 0         0 Carp::croak('The id value is not a valid 8-4-4-4-12 GUID');
168             }
169             }
170              
171             # Requires a driver
172 8 50       34 unless ( _CLASS($self->driver) ) {
173 0         0 Carp::croak('Missing or invalid driver');
174             }
175              
176             # Check the configuration hash
177 8 50       131 unless ( _HASH0($self->config) ) {
178 0         0 Carp::croak('Invalid, missing, or empty config');
179             }
180              
181             # Optional files
182 8   100     68 $self->{files} ||= [];
183 8 50       239 unless ( _SET0($self->{files}, 'PITA::XML::File') ) {
184 0         0 Carp::croak('Invalid files');
185             }
186              
187             # Optional platforms
188 8   100     172 $self->{platforms} ||= [];
189 8 50       206 unless ( _SET0($self->{platforms}, 'PITA::XML::Platform') ) {
190 0         0 Carp::croak('Invalid platforms');
191             }
192              
193 8         75 $self;
194             }
195              
196              
197             =pod
198              
199             =head2 id
200              
201             The C accessor returns the unique identifier of the request, if
202             it has one. This will generally be some form of L string.
203              
204             Returns the identifier as a string, or C if the request has not
205             been assigned an id.
206              
207             =cut
208              
209             sub id {
210 21     21 1 3234 $_[0]->{id};
211             }
212              
213             =pod
214              
215             =head2 set_id
216              
217             If an object does not already have an C property, the C method
218             will let you assign one to the guest. Takes a valid GUID "8-4-4-4-12" string
219             and sets the object with it, or croaks on error.
220              
221             =cut
222              
223             sub set_id {
224 1     1 1 3 my $self = shift;
225 1         8 my $guid = PITA::XML->_GUID(shift);
226 1 50       7 unless ( $guid ) {
227 0         0 Carp::croak("Invalid GUID format");
228             }
229 1 50       8 if ( $self->id ) {
230 0         0 Carp::croak("The guest already has an id value");
231             }
232 1         18 $self->{id} = $guid;
233 1         9 return 1;
234             }
235              
236             =pod
237              
238             =head2 driver
239              
240             The C accessor returns the shorthand name of the driver, as it
241             is stored in the PITA-XML xml file.
242              
243             For example, if the guest uses the L driver,
244             the C method return C<'Qemu'>.
245              
246             =cut
247              
248             sub driver {
249 14     14 1 311 $_[0]->{driver};
250             }
251              
252             =pod
253              
254             =head2 driver_available
255              
256             The C method will check your local system to see if the
257             driver for this guest is available in the current Perl environment.
258              
259             Returns true if the driver is available, or false if not.
260              
261             =cut
262              
263             sub driver_available {
264 0     0 1 0 my $self = shift;
265 0         0 my $driver = 'PITA::Guest::Driver::' . $self->driver;
266 0         0 Class::Inspector->installed( $driver );
267             }
268              
269             =pod
270              
271             =head2 config
272              
273             The C accessor returns the configuration for the driver.
274              
275             This configuration is entirely driver-specific, and although conventions
276             may exist, you should not rely on the contents of the configuration to
277             have any specific meaning.
278              
279             Returns a reference to a C containing plain scalar keys and values.
280              
281             =cut
282              
283             sub config {
284 14     14 1 1186 $_[0]->{config};
285             }
286              
287             =pod
288              
289             =head2 base
290              
291             If the guest XML was loaded from a file via C the C method
292             will return the directory that the XML file was loaded from.
293              
294             This base directory identifies where any relative file paths should be
295             mapped from.
296              
297             =cut
298              
299             sub base {
300 2     2 1 17 $_[0]->{base};
301             }
302              
303             =pod
304              
305             =head2 files
306              
307             Each guest will require zero or more file resources. In most cases, this
308             consists of drive images or emulator configuration files.
309              
310             The C method returns all existing files for this guest.
311              
312             Returns a list of L objects
313              
314             =cut
315              
316             sub files {
317 10     10 1 19 @{ $_[0]->{files} };
  10         88  
318             }
319              
320             =pod
321              
322             =head2 platforms
323              
324             Each guest should contain one or more testing contexts, where packages
325             of some specific type can be automatically tested. In PITA parlance, a
326             scheme-specific testing context is known as a I.
327              
328             The C method returns all existing known platforms for this
329             guest.
330              
331             Returns a list of one of more L objects.
332              
333             If this method returns a zero-length list, then the guest may be
334             unprocessed, and has not been 'discovered' yet.
335              
336             =cut
337              
338             sub platforms {
339 5     5 1 10 @{ $_[0]->{platforms} };
  5         26  
340             }
341              
342             =pod
343              
344             =head2 add_file
345              
346             The C method adds a new driver-specific file to
347             the guest.
348              
349             It takes as it's only parameter a L object.
350              
351             Returns true if added, or throws an exception if not passed a valid
352             L object.
353              
354             =cut
355              
356             sub add_file {
357 7     7 1 434 my $self = shift;
358 7         58 my $file = _INSTANCE(shift, 'PITA::XML::File');
359 7 50       61 unless ( $file ) {
360 0         0 Carp::croak('Did not provide a PITA::XML::File object');
361             }
362              
363             # Add it to the array
364 7   100     42 $self->{files} ||= [];
365 7         12 push @{$self->{files}}, $file;
  7         20  
366              
367 7         30 1;
368             }
369              
370             =pod
371              
372             =head2 add_platform
373              
374             The C method adds a new testing context to the guest.
375              
376             In general, you should B be manually adding platform definitions
377             to the guest unless you are implementing a driver auto-discovery
378             mechanism for your new or custom L class.
379              
380             That is, the PITA driver system itself will take you unprocessed guest,
381             load it, query the guest for its platform list, and update the XML file
382             independantly, without the help of any external system.
383              
384             It takes as it's only parameter a L object.
385              
386             Returns true if added, or throws an exception if not passed a valid
387             L object.
388              
389             =cut
390              
391             sub add_platform {
392 3     3 1 3356 my $self = shift;
393 3         19 my $platform = _INSTANCE(shift, 'PITA::XML::Platform');
394 3 100       10 unless ( $platform ) {
395 1         203 Carp::croak('Did not provide a PITA::XML::Platform object');
396             }
397              
398             # Add it to the array
399 2   100     12 $self->{platforms} ||= [];
400 2         4 push @{$self->{platforms}}, $platform;
  2         7  
401              
402 2         8 1;
403             }
404              
405              
406              
407              
408              
409             #####################################################################
410             # Main Methods
411              
412             =pod
413              
414             =head2 discovered
415              
416             The C method is a convenience method, and checks to see if
417             platform discovery has been done on the guest, or if it is unprocessed.
418              
419             Returns true if the platforms have been discovered, or false if not.
420              
421             =cut
422              
423             sub discovered {
424 0     0 1   !! $_[0]->platforms;
425             }
426              
427             1;
428              
429             =pod
430              
431             =head1 SUPPORT
432              
433             Bugs should be reported via the CPAN bug tracker at
434              
435             L
436              
437             For other issues, contact the author.
438              
439             =head1 AUTHOR
440              
441             Adam Kennedy Eadamk@cpan.orgE, L
442              
443             =head1 SEE ALSO
444              
445             L
446              
447             The Perl Image Testing Architecture (L)
448              
449             =head1 COPYRIGHT
450              
451             Copyright 2005 - 2013 Adam Kennedy.
452              
453             This program is free software; you can redistribute
454             it and/or modify it under the same terms as Perl itself.
455              
456             The full text of the license can be found in the
457             LICENSE file included with this module.
458              
459             =cut