File Coverage

blib/lib/Tapper/Reports/Web/Controller/Tapper/Testruns.pm
Criterion Covered Total %
statement 296 472 62.7
branch 46 128 35.9
condition 0 13 0.0
subroutine 50 63 79.3
pod 7 25 28.0
total 399 701 56.9


line stmt bran cond sub pod time code
1             package Tapper::Reports::Web::Controller::Tapper::Testruns;
2             our $AUTHORITY = 'cpan:TAPPER';
3             $Tapper::Reports::Web::Controller::Tapper::Testruns::VERSION = '5.0.13';
4 10     10   6322 use parent 'Tapper::Reports::Web::Controller::Base';
  10         16  
  10         76  
5 10     10   751 use Cwd;
  10         14  
  10         603  
6 10     10   41 use Data::DPath 'dpath';
  10         13  
  10         98  
7 10     10   2261 use DateTime::Format::DateParse;
  10         13  
  10         199  
8 10     10   34 use DateTime;
  10         17  
  10         164  
9 10     10   34 use File::Basename;
  10         12  
  10         491  
10 10     10   49 use File::Path;
  10         11  
  10         426  
11 10     10   39 use List::Util 'max';
  10         14  
  10         599  
12 10     10   41 use Template;
  10         14  
  10         197  
13 10     10   37 use YAML::Syck;
  10         12  
  10         441  
14              
15 10     10   4574 use Tapper::Cmd::Testrun;
  10         233890  
  10         402  
16 10     10   75 use Tapper::Cmd::Precondition;
  10         13  
  10         192  
17 10     10   40 use Tapper::Config;
  10         15  
  10         189  
18 10     10   37 use Tapper::Model 'model';
  10         15  
  10         462  
19 10     10   4914 use Tapper::Reports::Web::Util::Testrun;
  10         26  
  10         320  
20 10     10   4579 use Tapper::Reports::Web::Util::Filter::Testrun;
  10         42  
  10         317  
21              
22 10     10   51 use common::sense;
  10         12  
  10         64  
23             ## no critic (RequireUseStrict)
24              
25              
26              
27              
28             sub index :Path :Args()
29             {
30 0     0   0 my ( $self, $c, @args ) = @_;
31              
32 0         0 my $filter = Tapper::Reports::Web::Util::Filter::Testrun->new(context => $c);
33 0         0 my $filter_condition = $filter->parse_filters(\@args);
34              
35 0 0       0 if ($filter_condition->{error}) {
36 0         0 $c->flash->{error_msg} = join("; ", @{$filter_condition->{error}});
  0         0  
37 0         0 $c->res->redirect("/tapper/testruns");
38             }
39 0         0 $c->forward('/tapper/testruns/prepare_testrunlists', [ $filter_condition, $filter->requested_day ]);
40 0         0 $c->forward('/tapper/testruns/prepare_navi');
41 0         0 return;
42 10     10   1828 }
  10         16  
  10         86  
43              
44              
45             sub get_test_list_from_precondition {
46 0     0 1 0 my ($precond) = @_;
47              
48 0         0 return grep { defined } (
49             $precond->{testprogram}{execname},
50             map {
51 0         0 join( " ", $_->{program}, @{$_->{parameters}} )
  0         0  
52 0         0 } @{$precond->{testprogram_list}},
  0         0  
53             );
54             }
55              
56              
57             sub get_testrun_overview : Private
58             {
59 1     1 1 441 my ( $self, $c, $testrun ) = @_;
60              
61 1         3 my $retval = {};
62              
63 1 50       5 return $retval unless $testrun;
64              
65 1         22 $retval->{shortname} = $testrun->shortname;
66              
67 1         17 foreach ($testrun->ordered_preconditions) {
68 2         18060 my $precondition = $_->precondition_as_hash;
69 2 50       154 if ($precondition->{precondition_type} eq 'virt' ) {
    50          
    50          
70 0   0     0 $retval->{name} = $precondition->{name} || "Virtualisation Test";
71 0         0 $retval->{arch} = $precondition->{host}->{root}{arch};
72 0   0     0 $retval->{image} = $precondition->{host}->{root}{image} || $precondition->{host}->{root}{name}; # can be an image or copyfile or package
73 0         0 ($retval->{xen_package}) = grep { m!repository/packages/xen/builds! } dpath('/host/preconditions//filename')->match($precondition);
  0         0  
74 0         0 push @{$retval->{test}}, get_test_list_from_precondition($precondition->{host});
  0         0  
75              
76 0         0 foreach my $guest (@{$precondition->{guests}}) {
  0         0  
77 0         0 my $guest_summary;
78 0         0 $guest_summary->{arch} = $guest->{root}{arch};
79 0   0     0 $guest_summary->{image} = $guest->{root}{image} || $guest->{root}{name}; # can be an image or copyfile or package
80 0         0 push @{$guest_summary->{test}}, get_test_list_from_precondition($guest);
  0         0  
81 0         0 push @{$retval->{guests}}, $guest_summary;
  0         0  
82             }
83             # can stop here because virt preconditions usually defines everything we need for a summary
84 0         0 return $retval;
85             }
86             elsif ($precondition->{precondition_type} eq 'image' ) {
87 0         0 $retval->{image} = $precondition->{image};
88 0 0       0 if ($retval->{arch}) {
89 0         0 $retval->{arch} = $precondition->{arch};
90             } else {
91 0 0       0 if ($precondition->{image} =~ m/(64b)|(x86_64)/) {
    0          
92 0         0 $retval->{arch} = 'unknown (probably linux64)';
93             } elsif ($precondition->{image} =~ m/(32b)|(i386)/) {
94 0         0 $retval->{arch} = 'unknown (probably linux32)';
95             } else {
96 0         0 $retval->{arch} = 'unknown';
97             }
98             }
99             } elsif ($precondition->{precondition_type} eq 'prc') {
100 0 0       0 if ($precondition->{config}->{testprogram_list}) {
    0          
101 0         0 foreach my $thisprogram (@{$precondition->{config}->{testprogram_list}}) {
  0         0  
102 0         0 push @{$retval->{test}}, $thisprogram->{program};
  0         0  
103             }
104             } elsif ($precondition->{config}->{test_program}) {
105 0         0 push @{$retval->{test}}, $precondition->{config}->{test_program};
  0         0  
106             }
107             }
108             }
109 1         13 return $retval;
110 10     10   91041 }
  10         20  
  10         49  
111              
112 10     10 0 7683 sub base : Chained PathPrefix CaptureArgs(0) { }
  10     9   15  
  10         36  
113              
114             sub id : Chained('base') PathPart('') CaptureArgs(1)
115             {
116 2     2 0 750 my ( $self, $c, $testrun_id ) = @_;
117 2         10 $c->stash(testrun => $c->model('TestrunDB')->resultset('Testrun')->find($testrun_id));
118 2 50       7271 if (not $c->stash->{testrun}) {
119 0         0 $c->response->body(qq(No testrun with id "$testrun_id" found in the database!));
120 0         0 return;
121             }
122              
123 10     10   7636 }
  10         15  
  10         40  
124              
125             sub delete : Chained('id') PathPart('delete')
126             {
127 0     0 0 0 my ( $self, $c, $force) = @_;
128 0         0 $c->stash(force => $force);
129              
130 0 0       0 return if not $force;
131              
132 0         0 my $cmd = Tapper::Cmd::Testrun->new();
133 0         0 my $retval = $cmd->del($c->stash->{testrun}->id);
134 0 0       0 if ($retval) {
135 0         0 $c->response->body(qq(Can not delete testrun: $retval));
136 0         0 return;
137             }
138 0         0 $c->stash(force => 1);
139 10     10   7738 }
  10         15  
  10         41  
140              
141             sub pause : Chained('id') PathPart('pause')
142             {
143 0     0 0 0 my ( $self, $c) = @_;
144              
145 0         0 my $cmd = Tapper::Cmd::Testrun->new();
146 0         0 my $retval = $cmd->pause($c->stash->{testrun}->id);
147 0 0       0 if (not $retval) {
148 0         0 $c->response->body(qq(Can not pause testrun));
149 0         0 return;
150             }
151 0         0 $c->stash(testrun => $c->stash->{testrun}->id);
152 10     10   7534 }
  10         13  
  10         40  
153              
154             sub continue : Chained('id') PathPart('continue')
155             {
156 0     0 0 0 my ( $self, $c) = @_;
157              
158 0         0 my $cmd = Tapper::Cmd::Testrun->new();
159 0         0 my $retval = $cmd->continue($c->stash->{testrun}->id);
160 0 0       0 if (not $retval) {
161 0         0 $c->response->body(qq(Can not continue testrun));
162 0         0 return;
163             }
164 0         0 $c->stash(testrun => $c->stash->{testrun}->id);
165 10     10   7601 }
  10         15  
  10         36  
166              
167             sub rerun : Chained('id') PathPart('rerun') Args(0)
168             {
169 0     0 0 0 my ( $self, $c ) = @_;
170              
171 0         0 my $cmd = Tapper::Cmd::Testrun->new();
172 0         0 my $retval = $cmd->rerun($c->stash->{testrun}->id);
173 0 0       0 if (not $retval) {
174 0         0 $c->response->body(qq(Can not rerun testrun));
175 0         0 return;
176             }
177 0         0 $c->stash(testrun => $retval);
178 10     10   7502 }
  10         16  
  10         36  
179              
180             sub cancel : Chained('id') PathPart('cancel') Args(0)
181             {
182 0     0 0 0 my ( $self, $c ) = @_;
183              
184 0         0 my $cmd = Tapper::Cmd::Testrun->new();
185 0         0 my $retval = $cmd->cancel($c->stash->{testrun}->id, "Cancelled in Web GUI");
186 0 0       0 if ($retval) {
187 0         0 $c->response->body(qq(Can not cancel testrun: $retval));
188 0         0 return;
189             }
190 0         0 $c->stash(testrun => $c->stash->{testrun}->id);
191 10     10   7487 }
  10         16  
  10         39  
192              
193             sub preconditions : Chained('id') PathPart('preconditions') CaptureArgs(0)
194             {
195 2     2 0 1124 my ( $self, $c ) = @_;
196 2         9 $c->stash(preconditions => [$c->stash->{testrun}->ordered_preconditions]);
197 2         37629 my @preconditions_as_hash = map { $_->precondition_as_hash } $c->stash->{testrun}->ordered_preconditions;
  4         35968  
198 2         111 $YAML::Syck::SortKeys = 1;
199 2         93 $c->stash->{precondition_string} = YAML::Syck::Dump(@preconditions_as_hash);
200 10     10   7474 }
  10         16  
  10         43  
201              
202             sub as_yaml : Chained('preconditions') PathPart('yaml') Args(0)
203             {
204 0     0 0 0 my ( $self, $c ) = @_;
205              
206 0         0 my $id = $c->stash->{testrun}->id;
207              
208 0 0       0 if (@{$c->stash->{preconditions} || []}) {
  0 0       0  
209 0         0 $c->response->content_type ('text/plain');
210 0         0 $c->response->header ("Content-Disposition" => 'inline; filename="precondition-'.$id.'.yml"');
211 0         0 $c->response->body ( $c->stash->{precondition_string});
212             } else {
213 0         0 $c->response->body ("No preconditions assigned");
214             }
215 10     10   7698 }
  10         17  
  10         35  
216              
217             sub validate_yaml
218             {
219 1     1 0 2 my ($data) = @_;
220 1         3 eval {
221 1         7 YAML::Syck::Load($data);
222             };
223 1         66 return $@;
224             }
225              
226             sub edit : Chained('preconditions') PathPart('edit') Args(0) :FormConfig
227             {
228 2     2 0 730431 my ($self, $c) = @_;
229 2         6 my ($max_line, $line_count) = (0,0);
230              
231 2         6 my @lines = split "\n", $c->stash->{precondition_string};
232 2         103 foreach my $line (@lines) {
233 18         26 $max_line = max($max_line, length($line));
234             }
235              
236 2         5 my $form = $c->stash->{form};
237              
238 2 100       94 if ($form->submitted_and_valid) {
239 1         418 my $data = $form->input->{preconditions};
240              
241             # check whether user entered valid YAML
242 1         10 my $error = validate_yaml($data);
243 1 50       4 if ($error) {
244 0         0 $c->stash(message => "<emp>Error</emp>: $error");
245             } else {
246 1         1 my @precondition_ids = eval {
247 1         23 my $precond_cmd = Tapper::Cmd::Precondition->new();
248 1         1057 $precond_cmd->add($data);
249             };
250 1 50       32811 if ($@) {
251 0         0 $c->stash(message => "<emp>Error</emp>: $@");
252 0         0 return;
253             }
254              
255 1         8 $c->stash->{testrun}->disassign_preconditions();
256 1         11693 my $retval = $c->stash->{testrun}->assign_preconditions(@precondition_ids);
257 1 50       12487 if ($retval) {
258 0         0 $c->stash(message => "<emp>Error</emp>: $retval");
259             } else {
260 1         8 $c->stash(message => "New precondition assigned to testrun");
261             }
262             }
263             } else {
264 1         30 my $text = $form->get_element({type => 'Textarea',
265             name => 'preconditions'});
266 1         116 $text->rows(int @lines);
267 1         13 $text->cols($max_line);
268 1         51 $text->default($c->stash->{precondition_string});
269             }
270 10     10   11065 }
  10         16  
  10         42  
271              
272             sub update_precondition : Chained('base') PathPart('update_precondition')
273             {
274 0     0 0 0 my ($self, $c) = @_;
275 10     10   6983 }
  10         18  
  10         36  
276              
277              
278             sub show_precondition : Chained('preconditions') PathPart('show') Args(0)
279             {
280 0     0 0 0 my ( $self, $c ) = @_;
281              
282 10     10   6730 }
  10         17  
  10         33  
283              
284              
285             sub similar : Chained('id') PathPart('similar') Args(0)
286       0 0   {
287 10     10   6670 }
  10         22  
  10         35  
288              
289              
290             sub new_create : Chained('base') :PathPart('create') :Args(0) :FormConfig
291             {
292 5     5 1 2722937 my ($self, $c) = @_;
293 5         21 my $form = $c->stash->{form};
294              
295 5 100       239 if ($form->submitted_and_valid) {
296 1         984 my $data = $form->input();
297 1         27 $c->session->{testrun_data} = $data;
298 1         4657 $c->session->{valid} = 1;
299 1         99 $c->session->{usecase_file} = $form->input->{use_case};
300 1         85 $c->res->redirect('/tapper/testruns/fill_usecase');
301              
302             } else {
303 4         1179 my $select = $form->get_element({type => 'Select', name => 'topic'});
304 4         653 $select->options($self->get_topic_names());
305              
306 4         418 $select = $form->get_element({type => 'Select', name => 'owner'});
307 4         691 $select->options($self->get_owner_names());
308              
309 4         332 $select = $form->get_element({type => 'Select', name => 'requested_hosts'});
310 4         890 $select->options($self->get_hostnames());
311              
312 4         415 my @use_cases;
313 4         29 my $path = Tapper::Config->subconfig->{paths}{use_case_path};
314 4         667 foreach my $file (glob "$path/*.mpc") {
315 24 50       635 open my $fh, "<", $file or $c->response->body(qq(Can not open $file: $!)), return;
316 24         24 my $desc;
317 24         255 while (my $line = <$fh>) {
318 52         159 ($desc) = $line =~/^#+ *(?:tapper[_-])?description:\s*(.+)/;
319 52 100       118 last if $desc;
320             }
321              
322 24         545 my ($shortfile, undef, undef) = File::Basename::fileparse($file, ('.mpc'));
323 24         221 push @use_cases, [$file, "$shortfile - $desc"];
324              
325             }
326 4         32 my $select = $form->get_element({type => 'Radiogroup', name => 'use_case'});
327 4         674 $select->options(\@use_cases);
328             }
329              
330 10     10   10668 }
  10         17  
  10         52  
331              
332             sub get_topic_names
333             {
334 4     4 0 7 my ($self) = @_;
335 4         24 my @all_topics = model("TestrunDB")->resultset('Topic')->all();
336 4         36456 my @topic_names;
337 4         157 foreach my $topic (sort {$a->name cmp $b->name} @all_topics) {
  0         0  
338 3         77 push(@topic_names, [$topic->name, $topic->name." -- ".$topic->description]);
339             }
340 4         231 return \@topic_names;
341             }
342              
343             sub get_owner_names
344             {
345 4     4 0 9 my ($self) = @_;
346 4         18 my @all_owners = model("TestrunDB")->resultset('Owner')->all();
347 4         4513 my @owners;
348 4         121 foreach my $owner (sort {$a->name cmp $b->name} @all_owners) {
  0         0  
349 3 50       72 if ($owner->login eq 'tapper') {
350 0         0 unshift(@owners, [$owner->login, $owner->name." (".$owner->login.")"]);
351             } else {
352 3         101 push(@owners, [$owner->login, $owner->name." (".$owner->login.")"]);
353             }
354             }
355 4         151 return \@owners;
356             }
357              
358              
359             sub get_hostnames
360             {
361 5     5 1 10 my ($self) = @_;
362 5         21 my @all_machines = model("TestrunDB")->resultset('Host')->search({active => 1});
363 5         10684 my @machines;
364             HOST:
365 5         71 foreach my $host (sort {$a->name cmp $b->name} @all_machines) {
  4         97  
366              
367             # if host is bound, is must be bound to
368             # new_testrun_queue (possibly among others)
369 8 50       452 if ($host->queuehosts->count()) {
370 0         0 my $new_testrun_queue = Tapper::Config->subconfig->{new_testrun_queue};
371             next HOST unless
372 0 0       0 grep {$_->queue->name eq $new_testrun_queue} $host->queuehosts->all;
  0         0  
373             }
374              
375 8         25020 push(@machines, [ $host->name, $host->name ]);
376             }
377 5         264 return \@machines;
378              
379             }
380              
381              
382              
383             sub parse_macro_precondition :Private
384             {
385 2     2 1 4 my ($self, $c, $file) = @_;
386 2         3 my $config;
387 2         26 my $home = $c->path_to();
388              
389              
390 2 50       344 open my $fh, "<", $file or return "Can not open use case description $file:$!";
391 2         8 my ($required, $optional, $mpc_config) = ('', '', '');
392              
393 2         20 while (my $line = <$fh>) {
394 214 100       259 $config->{description_text} .= "$1\n" if $line =~ /^### ?(.*)$/;
395              
396 214 50       249 ($required) = $line =~/^#+ *(?:tapper[_-])?mandatory[_-]fields?:\s*(.+)/ if not $required;
397 214 100       234 ($optional) = $line =~/^#+ *(?:tapper[_-])?optional[_-]fields?:\s*(.+)/ if not $optional;
398 214 100       391 ($mpc_config) = $line =~/^#+ *(?:tapper[_-])?config[_-]file:\s*(.+)/ if not $mpc_config;
399             }
400              
401 2         10 my $delim = qr/,+\s*/;
402 2         12 foreach my $field (split $delim, $required) {
403 0         0 my ($name, $type) = split /\./, $field;
404 0 0       0 $type = 'Text' if not $type;
405 0         0 push @{$config->{required}}, {type => ucfirst($type),
  0         0  
406             name => $name,
407             label => $name,
408             constraints => [ 'Required' ]
409             }
410             }
411              
412 2         11 foreach my $field (split $delim, $optional) {
413 4         9 my ($name, $type) = split /\./, $field;
414 4 100       9 $type = 'Text' if not $type;
415 4         3 push @{$config->{optional}},{type => ucfirst($type),
  4         27  
416             name => $name,
417             label => $name,
418             };
419             }
420              
421 2 50       6 if ($mpc_config) {
422 2         13 my $use_case_path = Tapper::Config->subconfig->{paths}{use_case_path};
423 2 50       17 $mpc_config = "$use_case_path/$mpc_config"
424             unless substr($mpc_config, 0, 1) eq '/';
425              
426             # configs with relative paths are searched in FormFu's
427             # config_file_path which is somewhere in root/forms. We
428             # want our own config_path which starts at cwd when
429             # being a relative path
430 2 50       17 $mpc_config = getcwd()."/$mpc_config" if $mpc_config !~ m'^/'o;
431              
432 2 50       35 if (not -r $mpc_config) {
433 0         0 $c->stash(error => qq(Config file "$mpc_config" does not exists or is not readable));
434 0         0 return;
435             }
436 2         6 $config->{mpc_config} = $mpc_config;
437             }
438 2         22 return $config;
439 10     10   16929 }
  10         19  
  10         43  
440              
441              
442              
443             sub handle_precondition
444             {
445 2     2 1 6 my ($self, $c, $config) = @_;
446 2         7 my $form = $c->stash->{form};
447 2         93 my %macros;
448 2         3 my %all_form_elements = %{$c->request->{parameters}};
  2         35  
449              
450 2         22 foreach my $element (@{$config->{required}}, @{$config->{optional}}) {
  2         6  
  2         11  
451 4         10 my $name = $element->{name};
452 4 100       26 next if not defined $all_form_elements{$name};
453              
454 2 50       11 if (lc($element->{type}) eq 'file') {
455 0         0 my $upload = $c->req->upload($name);
456             my $destdir = sprintf("%s/uploads/%s/%s",
457 0         0 Tapper::Config->subconfig->{paths}{package_dir}, $config->{testrun_id}, $name);
458 0         0 my $destfile = $destdir."/".$upload->basename;
459 0         0 my $error;
460              
461 0         0 mkpath( $destdir, {error => \$error} );
462              
463 0         0 foreach my $diag (@$error) {
464 0         0 my ($dir, $message) = each %$diag;
465 0         0 return("Can not create $dir: $message");
466             }
467 0         0 $upload->copy_to($destfile);
468 0         0 $macros{$name} = $destfile;
469 0         0 delete $all_form_elements{$name};
470             }
471              
472 2 50       8 if (defined($all_form_elements{$name})) {
473 2         6 $macros{$name} = $all_form_elements{$name};
474 2         8 delete $all_form_elements{$name};
475             } else {
476             # TODO: handle error
477             }
478              
479             }
480              
481 2         7 foreach my $name (keys %all_form_elements) {
482 2 50       9 next if $name eq 'submit';
483             # checkboxgroups return an array but since you don't
484             # know its order in advance its easier to access a hash
485 0 0       0 if (ref $all_form_elements{$name} =~ /ARRAY/) {
486 0         0 foreach my $element (@{$all_form_elements{$name}}) {
  0         0  
487 0         0 $macros{$name}->{$element} = 1;
488             }
489             } else {
490 0         0 $macros{$name} = $all_form_elements{$name};
491             }
492             }
493              
494 2 50       138 open my $fh, "<", $config->{file} or return(qq(Can not open $config->{file}: $!));
495 2         3 my $mpc = do {local $/; <$fh>};
  2         10  
  2         47  
496              
497 2         3 my $ttapplied;
498              
499 2         26 my $tt = new Template ();
500 2 50       7720 return $tt->error if not $tt->process(\$mpc, \%macros, \$ttapplied);
501              
502 2         44534 my $cmd = Tapper::Cmd::Precondition->new();
503 2         1863 my @preconditions;
504 2         4 eval { @preconditions = $cmd->add($ttapplied)};
  2         19  
505 2 50       73641 return $@ if $@;
506              
507 2         42 $cmd->assign_preconditions($config->{testrun_id}, @preconditions);
508 2         84304 return \@preconditions;
509             }
510              
511              
512             sub fill_usecase : Chained('base') :PathPart('fill_usecase') :Args(0) :FormConfig
513             {
514 2     2 1 18238 my ($self, $c) = @_;
515 2         7 my $form = $c->stash->{form};
516 2         97 my $position = $form->get_element({type => 'Submit'});
517 2         94 my $file = $c->session->{usecase_file};
518 2         7154 my %macros;
519 2 50       7 $c->res->redirect('/tapper/testruns/create') unless $file;
520              
521 2         10 my $config = $self->parse_macro_precondition($c, $file);
522              
523             # adding these elements to the form has to be done both before
524             # and _after_ submit. Otherwise FormFu won't see the constraint
525             # (required) in the form
526 2         11 $c->stash->{description_text} = $config->{description_text};
527 2         118 foreach my $element (@{$config->{required}}) {
  2         9  
528 0         0 $element->{label} .= '*'; # mark field as required
529 0         0 $form->element($element);
530             }
531              
532 2         3 foreach my $element (@{$config->{optional}}) {
  2         5  
533 4         154341 $element->{label} .= ' ';
534 4         19 $form->element($element);
535             }
536              
537 2 50       2530 if ($config->{mpc_config}) {
538 2         12 $form->load_config_file( $config->{mpc_config} );
539             }
540              
541 2         26828 $form->elements({type => 'Submit', name => 'submit', value => 'Submit'});
542 2         3582 $form->process();
543              
544              
545 2 100       51707 if ($form->submitted_and_valid) {
546 1         642 my $testrun_data = $c->session->{testrun_data};
547 1         111 my @testhosts;
548 1 50       4 if ( defined ($testrun_data->{requested_hosts})){
549 0 0       0 if ( ref($testrun_data->{requested_hosts}) eq 'ARRAY') {
550 0         0 @testhosts = @{$testrun_data->{requested_hosts}};
  0         0  
551             } else {
552 0         0 @testhosts = ( $testrun_data->{requested_hosts} );
553             }
554             } else {
555 1         2 @testhosts = map { $_->[0] } @{get_hostnames()};
  2         39  
  1         5  
556             }
557              
558 1         7 $c->stash->{all_testruns} = [];
559             HOST:
560 1         75 for( my $i=0; $i < @testhosts; $i++) {
561 2         162 my $host = $testhosts[$i];
562             # we need a copy since we modify the hash before
563             # giving it to Tapper::Cmd and this
564             # modification would be used when the user clicks reload
565 2         15 my %testrun_settings = %$testrun_data;
566 2         16 $testrun_settings{queue} = Tapper::Config->subconfig->{new_testrun_queue};
567              
568 2         14 $c->stash->{all_testruns}[$i]{host} = $host;
569              
570 2         145 $testrun_settings{requested_hosts} = $host;
571 2         21 my $cmd = Tapper::Cmd::Testrun->new();
572 2         1387 eval { $config->{testrun_id} = $cmd->add(\%testrun_settings)};
  2         11  
573 2 50       52519 if ($@) {
574 0         0 $c->stash->{all_testruns}[$i]{error} = $@;
575 0         0 next HOST;
576             }
577 2         17 $c->stash->{all_testruns}[$i]{id} = $config->{testrun_id};
578              
579 2         168 $config->{file} = $file;
580 2         12 my $preconditions = $self->handle_precondition($c, $config);
581 2 50       416 if (ref($preconditions) eq 'ARRAY') {
582 2         17 $c->stash->{all_testruns}[$i]{ preconditions } = $preconditions;
583             } else {
584 0         0 $c->stash->{all_testruns}[$i]{ error } = $preconditions;
585             }
586              
587             }
588             }
589 10     10   17622 }
  10         20  
  10         48  
590              
591              
592             sub prepare_testrunlists : Private {
593              
594 0     0 0 0 my ( $or_self, $or_c, $hr_filter_condition ) = @_;
595              
596 0         0 my $b_view_pager = 0;
597 0         0 my $hr_params = $or_c->req->params;
598             my $hr_query_vals = {
599             testrun_id => $hr_filter_condition->{testrun_id},
600             host => $hr_filter_condition->{host},
601             topic => $hr_filter_condition->{topic},
602             state => $hr_filter_condition->{state},
603             success => $hr_filter_condition->{success},
604             owner => $hr_filter_condition->{owner},
605 0         0 };
606              
607 0         0 require DateTime;
608 0 0       0 if ( $hr_params->{testrun_date} ) {
    0          
609             $hr_filter_condition->{testrun_date} = DateTime::Format::Strptime->new(
610             pattern => '%F',
611 0         0 )->parse_datetime( $hr_params->{testrun_date} );
612             }
613             elsif (! $hr_filter_condition->{testrun_id} ) {
614 0         0 $hr_filter_condition->{testrun_date} = DateTime->now();
615             }
616 0 0 0     0 if ( $hr_params->{pager_sign} && $hr_params->{pager_value} ) {
617 0 0       0 if ( $hr_params->{pager_sign} eq 'negative' ) {
    0          
618             $hr_filter_condition->{testrun_date}->subtract(
619 0         0 $hr_params->{pager_value} => 1
620             );
621             }
622             elsif ( $hr_params->{pager_sign} eq 'positive' ) {
623             $hr_filter_condition->{testrun_date}->add(
624 0         0 $hr_params->{pager_value} => 1
625             );
626             }
627             }
628              
629 0 0       0 if ( $hr_filter_condition->{testrun_date} ) {
630              
631 0   0     0 $or_c->stash->{pager_interval} = $hr_params->{pager_interval} || 1;
632 0         0 $or_c->stash->{testrun_date} = $hr_filter_condition->{testrun_date};
633              
634             # set testrun date
635 0         0 my $d_testrun_date_from = $hr_filter_condition->{testrun_date}->clone->subtract( days => $or_c->stash->{pager_interval} - 1 )->strftime('%d %b %Y');
636 0         0 my $d_testrun_date_to = $hr_filter_condition->{testrun_date}->strftime('%d %b %Y');
637              
638 0 0       0 if ( $d_testrun_date_from ne $d_testrun_date_to ) {
639 0         0 $or_c->stash->{head_overview} = "Testruns ($d_testrun_date_to - $d_testrun_date_from)";
640             }
641             else {
642 0         0 $or_c->stash->{head_overview} = "Testruns ($d_testrun_date_from)";
643             }
644              
645 0         0 $hr_query_vals->{testrun_date_from} = $hr_filter_condition->{testrun_date}->clone->subtract( days => $or_c->stash->{pager_interval} - 1 )->strftime('%F');
646 0         0 $hr_query_vals->{testrun_date_to} = $hr_filter_condition->{testrun_date}->strftime('%F');
647              
648 0         0 $or_c->stash->{view_pager} = 1;
649              
650             }
651             else {
652 0         0 $or_c->stash->{head_overview} = 'Testruns';
653             }
654              
655 0         0 $or_c->stash->{testruns} = $or_c->model('TestrunDB')->fetch_raw_sql({
656             query_name => 'testruns::web_list',
657             fetch_type => '@%',
658             query_vals => $hr_query_vals,
659             });
660              
661 0         0 return 1;
662              
663 10     10   11036 }
  10         15  
  10         41  
664              
665             sub prepare_navi : Private
666             {
667 0     0 0 0 my ( $self, $c ) = @_;
668              
669 0         0 my @a_args = @{$c->req->arguments};
  0         0  
670              
671             $c->stash->{navi} = [
672             {
673 0         0 title => 'Control',
674             href => q##,
675             active => 0,
676             subnavi => [
677             {
678             title => 'Create new Testrun',
679             href => '/tapper/testruns/create/',
680             },
681             ],
682             },
683             ];
684              
685 0         0 my @a_subnavi;
686 0         0 OUTER: for ( my $i = 0; $i < @a_args; $i+=2 ) {
687 0         0 my $s_reduced_filter_path = q##;
688 0         0 for ( my $j = 0; $j < @a_args; $j+=2 ) {
689 0 0       0 next if $i == $j;
690 0         0 $s_reduced_filter_path .= "/$a_args[$j]/".$a_args[$j+1];
691             }
692             push @a_subnavi, {
693             title => "$a_args[$i]: ".$a_args[$i+1],
694             image => '/tapper/static/images/minus.png',
695             href => '/tapper/testruns'
696             . $s_reduced_filter_path
697             . (
698             $c->stash->{view_pager}
699             ? '?testrun_date='
700             . $c->stash->{testrun_date}->strftime('%F')
701             . '&amp;pager_interval='
702             . $c->stash->{pager_interval}
703 0 0       0 : ''
704             )
705             };
706             } # OUTER
707              
708 0         0 push @{$c->stash->{navi}},
  0         0  
709             { title => 'Active Filters', subnavi => \@a_subnavi, },
710             { title => 'New Filters', id => 'idx_new_filter' },
711             { title => 'Help', id => 'idx_help', subnavi => [{ title => 'Press Shift for multiple Filters' }] },
712             ;
713              
714 10     10   8987 }
  10         18  
  10         39  
715              
716              
717             1;
718              
719             __END__
720              
721             =pod
722              
723             =encoding UTF-8
724              
725             =head1 NAME
726              
727             Tapper::Reports::Web::Controller::Tapper::Testruns
728              
729             =head1 DESCRIPTION
730              
731             Catalyst Controller.
732              
733             =head2 index
734              
735             Prints a list of a testruns together with their state, start time and
736             end time. No options, not return values.
737              
738             TODO: Too many testruns, takes too long to display. Thus, we need to add
739             filter facility.
740              
741             =head2 get_test_list_from_precondition
742              
743             Utility function to extract testprograms from a given (sub-) precondition.
744              
745             =head2 get_testrun_overview
746              
747             This function reads and parses all precondition of a testrun to generate
748             a summary of the testrun which will then be shown as an overview. It
749             returns a hash reference containing:
750             * name
751             * arch
752             * image
753             * test
754              
755             @param testrun result object
756              
757             @return hash reference
758              
759             =head2 new_create
760              
761             This function handles the form for the first step of creating a new
762             testrun.
763              
764             =head2 get_hostnames
765              
766             Get an array of all hostnames that can be used for a new testrun. Note:
767             The array contains array that contain the hostname twice (i.e. (['host',
768             'host'], ...) because that is what the template expects.
769              
770             @return success - ref to array of [ hostname, hostname ]
771              
772             =head2 parse_macro_precondition
773              
774             Parse the given file as macro precondition and return a has ref
775             containing required, optional and mcp_config fields.
776              
777             @param catalyst context
778             @param string - file name
779              
780             @return success - hash ref
781             @return error - string
782              
783             =head2 handle_precondition
784              
785             Check whether each required precondition has a value, uploads files and
786             so on.
787              
788             @param Catalyst context
789             @param config hash
790              
791             @return success - list of precondition ids
792             @return error - error message
793              
794             =head2 fill_usecase
795              
796             Creates the form for the last step of creating a testrun. When this form
797             is submitted and valid the testrun is created based on the gathered
798             data. The function is used directly by Catalyst which therefore cares
799             for params and returns.
800              
801             =head1 NAME
802              
803             Tapper::Reports::Web::Controller::Tapper::Testruns - Catalyst Controller
804              
805             =head1 METHODS
806              
807             =head2 index
808              
809             =head1 AUTHOR
810              
811             Steffen Schwigon,,,
812              
813             =head1 LICENSE
814              
815             This program is released under the following license: freebsd
816              
817             =head1 AUTHORS
818              
819             =over 4
820              
821             =item *
822              
823             AMD OSRC Tapper Team <tapper@amd64.org>
824              
825             =item *
826              
827             Tapper Team <tapper-ops@amazon.com>
828              
829             =back
830              
831             =head1 COPYRIGHT AND LICENSE
832              
833             This software is Copyright (c) 2017 by Advanced Micro Devices, Inc..
834              
835             This is free software, licensed under:
836              
837             The (two-clause) FreeBSD License
838              
839             =cut