File Coverage

blib/lib/Test/Nightly.pm
Criterion Covered Total %
statement 62 64 96.8
branch 9 10 90.0
condition n/a
subroutine 13 13 100.0
pod 3 3 100.0
total 87 90 96.6


line stmt bran cond sub pod time code
1             package Test::Nightly;
2              
3 7     7   223769 use strict;
  7         19  
  7         301  
4 7     7   148 use warnings;
  7         13  
  7         377  
5              
6             our $VERSION = '0.03';
7              
8 7     7   39 use Carp;
  7         15  
  7         821  
9 7     7   48 use File::Spec;
  7         15  
  7         183  
10 7     7   14874 use File::Find::Rule;
  7         73544  
  7         75  
11              
12 7     7   4483 use Test::Nightly::Test;
  7         267  
  7         93  
13 7     7   1008 use Test::Nightly::Email;
  7         16  
  7         31  
14 7     7   4458 use Test::Nightly::Report;
  7         26  
  7         76  
15              
16 7     7   271 use base qw(Test::Nightly::Base Class::Accessor::Fast);
  7         16  
  7         5441  
17              
18             my @methods = qw(
19             base_directories
20             email_report
21             build_script
22             build_type
23             modules
24             report_output
25             report_template
26             test
27             test_directory_format
28             test_file_format
29             test_report
30             version_result
31             install_module
32             skip_tests
33             );
34              
35             __PACKAGE__->mk_accessors(@methods);
36             my @run_these = qw(version_control run_tests coverage_report generate_report);
37              
38             =head1 NAME
39              
40             Test::Nightly - Run all your tests and produce a report on the results.
41              
42             =head1 DESCRIPTION
43              
44             The idea behind this module is to have one script, most probably a cron job, to run all your tests once a night (or once a week). This module will then produce a report on the whether those tests passed or failed. From this report you can see at a glance what tests are failing. This is alpha software! Please try it out, email me bugs suggestions etc.
45              
46             =head1 SYNOPSIS
47              
48             # SCENARIO ONE #
49              
50             Pass in all the options direct into the constructor.
51              
52             use Test::Nightly;
53              
54             my $nightly = Test::Nightly->new({
55             base_directories => ['/base/dir/from/which/to/search/for/modules/'],
56             run_tests => {},
57             generate_report => {
58             email_report => {
59             to => 'kirstinbettiol@gmail.com',
60             },
61             report_output => '/report/output/dir/test_report.html',
62             },
63             debug => 1,
64             });
65              
66             # SCENARIO TWO #
67              
68             Call each method individually.
69              
70             use Test::Nightly;
71              
72             my $nightly = Test::Nightly->new({
73             base_directories => ['/base/dir/from/which/to/search/for/modules/'],
74             });
75              
76             $nightly->run_tests();
77              
78             $nightly->generate_report({
79             email_report => {
80             to => 'kirstinbettiol@gmail.com',
81             },
82             report_output => '/report/output/dir/test_report.html',
83             });
84              
85             # SCENARIO THREE
86              
87             Use build instead of make.
88              
89             use Test::Nightly;
90              
91             my $nightly = Test::Nightly->new({
92             base_directories => ['/base/dir/from/which/to/search/for/modules/'],
93             build_script => 'Build.PL',
94             run_tests => {
95             build_type => 'build',
96             },
97             });
98              
99             =cut
100              
101             =head2 new()
102              
103             my $nightly = Test::Nightly->new({
104             base_directories => \@directories, # Required. Array of base directories to search in.
105             build_script => 'Build.PL', # Defaults to 'Makefile.PL'.
106             run_tests => {
107             test_directory_format => ['t/', 'tests/'], # Optional, defaults to 't/'.
108             test_file_format => ['.t', '.pl'], # Optional, defaults to '.t'.
109             build_type => 'make', # || 'build'. Defaults to 'make'.
110             install_module => 'all', # || 'passed'. 'all' is default.
111             skip_tests => 1, # skips the tests.
112             test_order => 'ordered', # || 'random'. 'ordered' is default.
113             },
114             generate_report => {
115             email_report => \%email_config, # Emails the report. See L for config.
116             report_template => '/dir/somewhere/template.txt', # Defaults to internal template.
117             report_output => '/dir/somewhere/output.txt', # File to output the report to.
118             test_report => 'all', # 'failed' || 'passed'. Defaults to all.
119             },
120             });
121              
122             This is the constructor used to create the main object.
123              
124             Does a search for all modules on your system, matching the build script description (C). You can choose to run all your tests and generate your report directly from this module, by supplying C and C. Or you can simply supply C and it call the other methods separately.
125              
126             =cut
127              
128             sub new {
129              
130 8     8 1 123197 my ($class, $conf) = @_;
131            
132 8         32 my $self = bless {}, $class;
133              
134 8         109 $self->_init($conf, \@methods);
135              
136 8 100       36 if (!defined $self->base_directories()) {
137 1         253 croak 'Test::Nightly::new() - "base_directories" must be supplied';
138             } else {
139              
140 7 100       70 $self->build_script('Makefile.PL') unless defined $self->build_script();
141              
142 7         113 $self->_find_modules();
143              
144             # See if any methods should be called from new
145 6         54 foreach my $run (@run_these) {
146              
147 24 100       1760 if(defined $conf->{$run}) {
148             # user wants to run this one
149 5         32 $self->$run($conf->{$run});
150             }
151             }
152              
153 6         227 return $self;
154              
155             }
156              
157             }
158              
159             =head2 run_tests()
160              
161             $nightly->run_tests({
162             build_type => 'make' # || 'build'. 'make' is default.
163             install_module => 'all', # || 'passed'. 'all' is default.
164             skip_tests => 1, # skips the tests.
165             test_directory_format => ['t/', 'tests/'], # Optional, defaults to ['t/'].
166             test_file_format => ['.t', '.pl'], # Optional, defaults to ['.t'].
167             test_order => 'ordered', # || 'random'. 'ordered' is default.
168             });
169              
170             Runs all the tests on the directories that are stored in the object.
171              
172             Results are stored back in the object so they can be reported on.
173              
174             =cut
175              
176             sub run_tests {
177              
178 5     5 1 22 my ($self, $conf) = @_;
179              
180 5         31 $self->_init($conf, \@methods);
181              
182 5         54 my $test = Test::Nightly::Test->new($self);
183              
184 5         30 $test->run();
185              
186 5         1668 $self->test($test);
187            
188             }
189              
190             =head2 generate_report()
191              
192             $nightly->generate_report({
193             email_report => \%email_config, # Emails the report. See L for config options.
194             report_template => '/dir/somewhere/template.txt', # Defaults to internal template.
195             report_output => '/dir/somewhere/output.txt', # File to output the report to.
196             test_report => 'all', # 'failed' || 'passed'. Defaults to all.
197             });
198              
199             Based on the methods that have been run, produces a report on these.
200              
201             Depending on what you pass in, defines what report is generated. If you pass in an email address to L then the report will be
202             emailed. If you specify an output file to C then the report will be outputted to that file.
203             If you specify both, then both will be done.
204              
205             Default behavior is to use the internal template that is in L, however you can overwrite this with your own template (C). Uses Template Toolkit logic.
206              
207             =cut
208              
209             sub generate_report {
210              
211 4     4 1 480 my ($self, $conf) = @_;
212              
213 4         88 $self->_init($conf, \@methods);
214              
215 4         122 my $report = Test::Nightly::Report->new($self);
216              
217 4         57 $report->run();
218              
219             }
220              
221             sub _find_modules {
222              
223 7     7   20 my ($self, $conf) = @_;
224              
225 7 100       78 if ($self->build_script() =~ /\s/) {
226 1         211 croak 'Test::Nightly::_find_modules(): Supplied "build_script" can not contain a space';
227             }
228              
229 6         72 my @modules;
230              
231             # Search through all the base directories supplied.
232 6         17 foreach my $dir (@{$self->base_directories()}) {
  6         34  
233              
234             # Continue if that directory exists
235 6 50       239 if (-d $dir) {
236            
237             # Search for files matching the build script description.
238 6         318 my @found_build_scripts = File::Find::Rule->file()->name( $self->build_script() )->in($dir);
239              
240             # do i need to do this?
241 6         11926 foreach my $found_build_script (@found_build_scripts) {
242              
243 5         117 my ($volume, $directory, $build_script) = File::Spec->splitpath( $found_build_script );
244            
245 5         15 my %module;
246 5         20 $module{'directory'} = $directory;
247 5         16 $module{'build_script'} = $build_script;
248            
249 5         39 push(@modules, \%module);
250              
251             }
252              
253             } else {
254 0         0 carp 'Test::Nightly::_find_modules() - directory: "'.$dir.'" is not a valid directory';
255 0         0 next;
256             }
257              
258             }
259              
260 6         44 $self->modules(\@modules);
261              
262             }
263              
264             =head1 List of methods:
265              
266             =over 4
267              
268             =item base_directories
269              
270             Required. Array ref of base directories to search in.
271              
272             =item build_script
273              
274             Searches for the specified build_script names. Defaults to Makefile.PL
275              
276             =item build_type
277              
278             Pass this in so we know how you build your modules. There are two options: 'build' and 'make'. Defaults to 'make'.
279              
280             =item debug
281              
282             Turns debugging messages on or off.
283              
284             =item email_report
285              
286             If set will email the report. Takes a hash ref of \%email_config, refer to Test::Nightly::Email for the options.
287              
288             =item install_module
289              
290             Pass this in if you wish to have the module installed.
291              
292             =item modules
293              
294             List of modules that have been found, returns an array ref of undef.
295              
296             =item skip_tests
297              
298             Pass this in if you wish to skip running the tests.
299              
300             =item report_output
301              
302             Set this to a file somewhere and the report will be outputted here.
303              
304             =item report_template
305              
306             Pass this in if you wish to use your own customised report template. Otherwise uses the default template is in Test::Nightly::Report::Template
307              
308             =item test
309              
310             Holds the Test::Nightly::Test object.
311              
312             =item test_directory_format
313              
314             An array of what format the test directories can be. By default it searches for the tests in 't/'
315              
316             =item test_file_format
317              
318             An array of the test file formats you have.
319              
320             =item test_report
321              
322             This is where you specify what you wish to report on after the outcome of the test. Specifying 'passed' will only report on tests that passed, specifying 'failed' will only report on tests that failed and specifying 'all' will report on both.
323              
324             =item test_order
325              
326             Pass this in if you wish to influence the way the tests are run. Either 'ordered' or 'random'. Detauls to 'ordered'.
327              
328             =back
329              
330             =head1 DISCLAIMERS
331              
332             This module assumes that you only need installed modules to test your module. So if the module you're testing requires the changes you've made to another module in the tree that you haven't installed, testing will fail.
333              
334             If your module asks interactive questions in the build script or test scripts then this won't work.
335              
336             =head1 TODO
337              
338             Soon I would like to implement a module that will handle version control, so you are able to checkout and update your modules for testing. As well as this it would be nice to incorporate in a wrapper for L.
339              
340             L,
341             L.
342              
343             =head1 AUTHOR
344              
345             Kirstin Bettiol
346              
347             =head1 SEE ALSO
348              
349             L,
350             L,
351             L,
352             L,
353             L.
354              
355             =head1 COPYRIGHT
356              
357             (c) 2005 Kirstin Bettiol
358             This library is free software, you can use it under the same terms as perl itself.
359              
360             =head1 THANKS
361              
362             Thanks to Leo Lapworth for helping me with this and Foxtons for letting me develop this on their time.
363              
364             =cut
365              
366             1;
367