File Coverage

blib/lib/Tapper/Reports/Web/Controller/Tapper/Testruns.pm
Criterion Covered Total %
statement 303 485 62.4
branch 50 136 36.7
condition 1 16 6.2
subroutine 49 63 77.7
pod 7 25 28.0
total 410 725 56.5


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.14';
4 10     10   7507 use parent 'Tapper::Reports::Web::Controller::Base';
  10         31  
  10         114  
5 10     10   944 use Cwd;
  10         36  
  10         807  
6 10     10   75 use Data::DPath 'dpath';
  10         33  
  10         121  
7 10     10   3399 use DateTime::Format::DateParse;
  10         28  
  10         301  
8 10     10   65 use DateTime;
  10         24  
  10         279  
9 10     10   83 use File::Basename;
  10         26  
  10         784  
10 10     10   77 use File::Path;
  10         35  
  10         629  
11 10     10   82 use List::Util 'max';
  10         24  
  10         747  
12 10     10   73 use Template;
  10         32  
  10         389  
13 10     10   77 use YAML::Syck;
  10         25  
  10         704  
14              
15 10     10   5720 use Tapper::Cmd::Testrun;
  10         346195  
  10         406  
16 10     10   99 use Tapper::Cmd::Precondition;
  10         34  
  10         224  
17 10     10   59 use Tapper::Config;
  10         23  
  10         266  
18 10     10   69 use Tapper::Model 'model';
  10         36  
  10         472  
19 10     10   6391 use Tapper::Reports::Web::Util::Testrun;
  10         44  
  10         403  
20 10     10   5029 use Tapper::Reports::Web::Util::Filter::Testrun;
  10         40  
  10         359  
21              
22 10     10   82 use common::sense;
  10         28  
  10         105  
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   2325 }
  10         31  
  10         102  
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 683 my ( $self, $c, $testrun ) = @_;
60              
61 1         4 my $retval = {};
62              
63 1 50       5 return $retval unless $testrun;
64              
65 1         29 $retval->{shortname} = $testrun->shortname;
66              
67 1         42 foreach ($testrun->ordered_preconditions) {
68 2         29559 my $precondition = $_->precondition_as_hash;
69 2 50       217 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         19 return $retval;
110 10     10   149106 }
  10         34  
  10         57  
111              
112 10     10 0 11457 sub base : Chained PathPrefix CaptureArgs(0) { }
  10     9   34  
  10         62  
113              
114             sub id : Chained('base') PathPart('') CaptureArgs(1)
115             {
116 2     2 0 1101 my ( $self, $c, $testrun_id ) = @_;
117 2         14 $c->stash(testrun => $c->model('TestrunDB')->resultset('Testrun')->find($testrun_id));
118 2 50       11442 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   11558 }
  10         28  
  10         73  
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   12255 }
  10         35  
  10         54  
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   11633 }
  10         32  
  10         58  
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   11766 }
  10         35  
  10         59  
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   11844 }
  10         31  
  10         54  
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   12068 }
  10         31  
  10         60  
192              
193             sub preconditions : Chained('id') PathPart('preconditions') CaptureArgs(0)
194             {
195 2     2 0 1341 my ( $self, $c ) = @_;
196 2         12 $c->stash(preconditions => [$c->stash->{testrun}->ordered_preconditions]);
197 2         60573 my @preconditions_as_hash = map { $_->precondition_as_hash } $c->stash->{testrun}->ordered_preconditions;
  4         54561  
198 2         150 $YAML::Syck::SortKeys = 1;
199 2         132 $c->stash->{precondition_string} = YAML::Syck::Dump(@preconditions_as_hash);
200 10     10   11639 }
  10         32  
  10         90  
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   12030 }
  10         39  
  10         57  
216              
217             sub validate_yaml
218             {
219 1     1 0 4 my ($data) = @_;
220 1         4 eval {
221 1         7 YAML::Syck::Load($data);
222             };
223 1         86 return $@;
224             }
225              
226             sub edit : Chained('preconditions') PathPart('edit') Args(0) :FormConfig
227             {
228 2     2 0 1115727 my ($self, $c) = @_;
229 2         10 my ($max_line, $line_count) = (0,0);
230              
231 2         10 my @lines = split "\n", $c->stash->{precondition_string};
232 2         161 foreach my $line (@lines) {
233 18         47 $max_line = max($max_line, length($line));
234             }
235              
236 2         7 my $form = $c->stash->{form};
237              
238 2 100       148 if ($form->submitted_and_valid) {
239 1         547 my $data = $form->input->{preconditions};
240              
241             # check whether user entered valid YAML
242 1         14 my $error = validate_yaml($data);
243 1 50       8 if ($error) {
244 0         0 $c->stash(message => "<emp>Error</emp>: $error");
245             } else {
246 1         3 my @precondition_ids = eval {
247 1         26 my $precond_cmd = Tapper::Cmd::Precondition->new();
248 1         1693 $precond_cmd->add($data);
249             };
250 1 50       31004 if ($@) {
251 0         0 $c->stash(message => "<emp>Error</emp>: $@");
252 0         0 return;
253             }
254              
255 1         11 $c->stash->{testrun}->disassign_preconditions();
256 1         30912 my $retval = $c->stash->{testrun}->assign_preconditions(@precondition_ids);
257 1 50       29479 if ($retval) {
258 0         0 $c->stash(message => "<emp>Error</emp>: $retval");
259             } else {
260 1         10 $c->stash(message => "New precondition assigned to testrun");
261             }
262             }
263             } else {
264 1         53 my $text = $form->get_element({type => 'Textarea',
265             name => 'preconditions'});
266 1         183 $text->rows(int @lines);
267 1         24 $text->cols($max_line);
268 1         16 $text->default($c->stash->{precondition_string});
269             }
270 10     10   15995 }
  10         34  
  10         55  
271              
272             sub update_precondition : Chained('base') PathPart('update_precondition')
273             {
274 0     0 0 0 my ($self, $c) = @_;
275 10     10   10912 }
  10         33  
  10         56  
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   10583 }
  10         31  
  10         63  
283              
284              
285             sub similar : Chained('id') PathPart('similar') Args(0)
286       0 0   {
287 10     10   10509 }
  10         35  
  10         58  
288              
289              
290             sub new_create : Chained('base') :PathPart('create') :Args(0) :FormConfig
291             {
292 5     5 1 3492105 my ($self, $c) = @_;
293 5         27 my $form = $c->stash->{form};
294              
295 5 100       366 if ($form->submitted_and_valid) {
296 1         1180 my $data = $form->input();
297 1         29 $c->session->{testrun_data} = $data;
298 1         6806 $c->session->{valid} = 1;
299 1         149 $c->session->{usecase_file} = $form->input->{use_case};
300 1         133 $c->res->redirect('/tapper/testruns/fill_usecase');
301              
302             } else {
303 4         1400 my $select;
304              
305 4         42 $select = $form->get_element({type => 'Select', name => 'owner'});
306 4         1184 $select->options($self->get_owner_names());
307              
308 4         661 $select = $form->get_element({type => 'Select', name => 'requested_hosts'});
309 4         1037 $select->options($self->get_hostnames());
310              
311 4         655 my @use_cases;
312 4         40 my $path = Tapper::Config->subconfig->{paths}{use_case_path};
313 4         718 foreach my $file (glob "$path/*.mpc") {
314 24 50       976 open my $fh, "<", $file or $c->response->body(qq(Can not open $file: $!)), return;
315 24         80 my $desc;
316             my $hide;
317 24         480 while (my $line = <$fh>) {
318 52         644 ($desc) = $line =~/^#+ *(?:tapper[_-])?description:\s*(.+)/;
319 52 100       179 last if $desc;
320             }
321 24         88 while (my $line = <$fh>) {
322 4908         7458 ($hide) = $line =~/^#+ *(?:tapper[_-])?hide-in-webgui:\s*(.+)/;
323 4908 50       11541 last if $hide;
324             }
325              
326 24         784 my ($shortfile, undef, undef) = File::Basename::fileparse($file, ('.mpc'));
327 24 50       400 push @use_cases, [$file, "$shortfile - $desc"] unless $hide;
328              
329             }
330 4         57 my $select = $form->get_element({type => 'Radiogroup', name => 'use_case'});
331 4         1199 $select->options(\@use_cases);
332             }
333              
334 10     10   15977 }
  10         33  
  10         71  
335              
336             sub get_topic_names
337             {
338 0     0 0 0 my ($self) = @_;
339 0         0 my @all_topics = model("TestrunDB")->resultset('Topic')->all();
340 0         0 my @topic_names;
341 0         0 foreach my $topic (sort {$a->name cmp $b->name} @all_topics) {
  0         0  
342 0         0 push(@topic_names, [$topic->name, $topic->name." -- ".$topic->description]);
343             }
344 0         0 return \@topic_names;
345             }
346              
347             sub get_owner_names
348             {
349 4     4 0 18 my ($self) = @_;
350 4         28 my @all_owners = model("TestrunDB")->resultset('Owner')->all();
351 4         56637 my @owners;
352 4         214 foreach my $owner (sort {$a->name cmp $b->name} @all_owners) {
  0         0  
353 3 50       100 if ($owner->login eq 'tapper') {
354 0         0 unshift(@owners, [$owner->login, $owner->name." (".$owner->login.")"]);
355             } else {
356 3         179 push(@owners, [$owner->login, $owner->name." (".$owner->login.")"]);
357             }
358             }
359 4         244 return \@owners;
360             }
361              
362              
363             sub get_hostnames
364             {
365 5     5 1 22 my ($self) = @_;
366 5         38 my @all_machines = model("TestrunDB")->resultset('Host')->search({active => 1});
367 5         17685 my @machines;
368             HOST:
369 5         101 foreach my $host (sort {$a->name cmp $b->name} @all_machines) {
  4         119  
370              
371             # if host is bound, is must be bound to
372             # new_testrun_queue (possibly among others)
373 8 50       755 if ($host->queuehosts->count()) {
374 0         0 my $new_testrun_queue = Tapper::Config->subconfig->{new_testrun_queue};
375             next HOST unless
376 0 0       0 grep {$_->queue->name eq $new_testrun_queue} $host->queuehosts->all;
  0         0  
377             }
378              
379 8         43749 push(@machines, [ $host->name, $host->name ]);
380             }
381 5         365 return \@machines;
382              
383             }
384              
385              
386              
387             sub parse_macro_precondition :Private
388             {
389 2     2 1 7 my ($self, $c, $file) = @_;
390 2         5 my $config;
391 2         38 my $home = $c->path_to();
392 2         539 my ($shortfile, undef, undef) = File::Basename::fileparse($file, ('.mpc'));
393              
394 2 50       101 open my $fh, "<", $file or return "Can not open use case description $file:$!";
395 2         19 my ($required, $optional, $mpc_config) = ('', '', '');
396              
397 2         38 while (my $line = <$fh>) {
398 214 100       443 $config->{description_text} .= "$1\n" if $line =~ /^### ?(.*)$/;
399              
400 214 50       402 ($required) = $line =~/^#+ *(?:tapper[_-])?mandatory[_-]fields?:\s*(.+)/ if not $required;
401 214 100       389 ($optional) = $line =~/^#+ *(?:tapper[_-])?optional[_-]fields?:\s*(.+)/ if not $optional;
402 214 100       542 ($mpc_config) = $line =~/^#+ *(?:tapper[_-])?config[_-]file:\s*(.+)/ if not $mpc_config;
403             }
404              
405 2         18 my $delim = qr/,+\s*/;
406 2         20 foreach my $field (split $delim, $required) {
407 0         0 my ($name, $type) = split /\./, $field;
408 0 0       0 $type = 'Text' if not $type;
409 0         0 push @{$config->{required}}, {type => ucfirst($type),
  0         0  
410             name => $name,
411             label => $name,
412             constraints => [ 'Required' ]
413             }
414             }
415              
416 2         17 foreach my $field (split $delim, $optional) {
417 4         17 my ($name, $type) = split /\./, $field;
418 4 100       13 $type = 'Text' if not $type;
419 4         8 push @{$config->{optional}},{type => ucfirst($type),
  4         27  
420             name => $name,
421             label => $name,
422             };
423             }
424              
425 2 50       8 if ($mpc_config) {
426 2         17 my $use_case_path = Tapper::Config->subconfig->{paths}{use_case_path};
427 2 50       25 $mpc_config = "$use_case_path/$mpc_config"
428             unless substr($mpc_config, 0, 1) eq '/';
429              
430             # configs with relative paths are searched in FormFu's
431             # config_file_path which is somewhere in root/forms. We
432             # want our own config_path which starts at cwd when
433             # being a relative path
434 2 50       33 $mpc_config = getcwd()."/$mpc_config" if $mpc_config !~ m'^/'o;
435              
436 2 50       43 if (not -r $mpc_config) {
437 0         0 $c->stash(error => qq(Config file "$mpc_config" does not exists or is not readable));
438 0         0 return;
439             }
440 2         12 $config->{mpc_config} = $mpc_config;
441             }
442              
443             # Default field "testrun_topic" in every form
444 2 50       4 if (not grep { $_->{name} eq "testrun_topic" } @{$config->{required}}) {
  0         0  
  2         11  
445 2   33     4 unshift @{$config->{required}},
  2         30  
446             {
447             type => "Text",
448             name => "testrun_topic",
449             label => "Testrun topic",
450             value => join("-", "usertest", ($shortfile || ())),
451             constraints => [ { type => 'Required', message_xml => '<span style="color:#B40404">Please fill mandatory field</span>' } ],
452             attributes => { size => 50 },
453             }
454             }
455              
456 2         39 return $config;
457 10     10   24994 }
  10         33  
  10         60  
458              
459              
460              
461             sub handle_precondition
462             {
463 2     2 1 12 my ($self, $c, $config) = @_;
464 2         10 my $form = $c->stash->{form};
465 2         198 my %macros;
466 2         8 my %all_form_elements = %{$c->request->{parameters}};
  2         61  
467              
468 2         46 foreach my $element (@{$config->{required}}, @{$config->{optional}}) {
  2         13  
  2         11  
469 6         20 my $name = $element->{name};
470 6 100       28 next if not defined $all_form_elements{$name};
471              
472 4 50       24 if (lc($element->{type}) eq 'file') {
473 0         0 my $upload = $c->req->upload($name);
474             my $destdir = sprintf("%s/uploads/%s/%s",
475 0         0 Tapper::Config->subconfig->{paths}{package_dir}, $config->{testrun_id}, $name);
476 0         0 my $destfile = $destdir."/".$upload->basename;
477 0         0 my $error;
478              
479 0         0 mkpath( $destdir, {error => \$error} );
480              
481 0         0 foreach my $diag (@$error) {
482 0         0 my ($dir, $message) = each %$diag;
483 0         0 return("Can not create $dir: $message");
484             }
485 0         0 $upload->copy_to($destfile);
486 0         0 $macros{$name} = $destfile;
487 0         0 delete $all_form_elements{$name};
488             }
489              
490 4 50       17 if (defined($all_form_elements{$name})) {
491 4         18 $macros{$name} = $all_form_elements{$name};
492 4         17 delete $all_form_elements{$name};
493             } else {
494             # TODO: handle error
495             }
496              
497             }
498              
499 2         13 foreach my $name (keys %all_form_elements) {
500 2 50       15 next if $name eq 'submit';
501             # checkboxgroups return an array but since you don't
502             # know its order in advance its easier to access a hash
503 0 0       0 if (ref $all_form_elements{$name} =~ /ARRAY/) {
504 0         0 foreach my $element (@{$all_form_elements{$name}}) {
  0         0  
505 0         0 $macros{$name}->{$element} = 1;
506             }
507             } else {
508 0         0 $macros{$name} = $all_form_elements{$name};
509             }
510             }
511              
512 2 50       204 open my $fh, "<", $config->{file} or return(qq(Can not open $config->{file}: $!));
513 2         9 my $mpc = do {local $/; <$fh>};
  2         19  
  2         120  
514              
515 2         9 my $ttapplied;
516              
517 2         49 my $tt = new Template ();
518 2 50       13113 return $tt->error if not $tt->process(\$mpc, \%macros, \$ttapplied);
519              
520 2         76853 my $cmd = Tapper::Cmd::Precondition->new();
521 2         2356 my @preconditions;
522 2         8 eval { @preconditions = $cmd->add($ttapplied)};
  2         12  
523 2 50       153956 return $@ if $@;
524              
525 2         33 $cmd->assign_preconditions($config->{testrun_id}, @preconditions);
526 2         157427 return \@preconditions;
527             }
528              
529              
530             sub fill_usecase : Chained('base') :PathPart('fill_usecase') :Args(0) :FormConfig
531             {
532 2     2 1 29317 my ($self, $c) = @_;
533 2         10 my $form = $c->stash->{form};
534 2         153 my $position = $form->get_element({type => 'Submit'});
535 2         153 my $file = $c->session->{usecase_file};
536 2         11602 my ($shortfile, undef, undef) = File::Basename::fileparse($file, ('.mpc'));
537 2         10 my %macros;
538 2 50       9 $c->res->redirect('/tapper/testruns/create') unless $file;
539              
540 2         13 my $config = $self->parse_macro_precondition($c, $file);
541              
542             # adding these elements to the form has to be done both before
543             # and _after_ submit. Otherwise FormFu won't see the constraint
544             # (required) in the form
545 2         14 $c->stash->{description_text} = $config->{description_text};
546 2         174 foreach my $element (@{$config->{required}}) {
  2         15  
547 2         8 $element->{label} .= '*'; # mark field as required
548 2         15 $form->element($element);
549             }
550              
551 2         264985 foreach my $element (@{$config->{optional}}) {
  2         9  
552 4         264075 $element->{label} .= ' ';
553 4         18 $form->element($element);
554             }
555              
556 2 50       3798 if ($config->{mpc_config}) {
557 2         13 $form->load_config_file( $config->{mpc_config} );
558             }
559              
560 2         43673 $form->elements({type => 'Submit', name => 'submit', value => 'Submit'});
561 2         6337 $form->process();
562              
563 2 100       91442 if ($form->submitted_and_valid) {
564 1         1147 my $testrun_data = $c->session->{testrun_data};
565 1         189 my @testhosts;
566              
567             # allow overwrite testrun topic
568 1         27 my $testrun_topic = $form->input->{testrun_topic};
569 1 50       26 if ($testrun_topic) {
570 1         13 $testrun_data->{topic} = $testrun_topic;
571             } else {
572 0         0 $testrun_data->{topic} = "undefined-topic";
573             }
574              
575             # hosts
576 1 50       6 if ( defined ($testrun_data->{requested_hosts})){
577 0 0       0 if ( ref($testrun_data->{requested_hosts}) eq 'ARRAY') {
578 0         0 @testhosts = @{$testrun_data->{requested_hosts}};
  0         0  
579             } else {
580 0         0 @testhosts = ( $testrun_data->{requested_hosts} );
581             }
582             } else {
583 1         3 @testhosts = map { $_->[0] } @{get_hostnames()};
  2         61  
  1         5  
584             }
585              
586 1         9 $c->stash->{all_testruns} = [];
587             HOST:
588 1         94 for( my $i=0; $i < @testhosts; $i++) {
589 2         271 my $host = $testhosts[$i];
590             # we need a copy since we modify the hash before
591             # giving it to Tapper::Cmd and this
592             # modification would be used when the user clicks reload
593 2         19 my %testrun_settings = %$testrun_data;
594 2         24 $testrun_settings{queue} = Tapper::Config->subconfig->{new_testrun_queue};
595              
596 2         19 $c->stash->{all_testruns}[$i]{host} = $host;
597              
598 2         159 $testrun_settings{requested_hosts} = $host;
599 2         22 my $cmd = Tapper::Cmd::Testrun->new();
600 2         2126 eval { $config->{testrun_id} = $cmd->add(\%testrun_settings)};
  2         14  
601 2 50       113486 if ($@) {
602 0         0 $c->stash->{all_testruns}[$i]{error} = $@;
603 0         0 next HOST;
604             }
605 2         23 $c->stash->{all_testruns}[$i]{id} = $config->{testrun_id};
606              
607 2         309 $config->{file} = $file;
608 2         17 my $preconditions = $self->handle_precondition($c, $config);
609 2 50       536 if (ref($preconditions) eq 'ARRAY') {
610 2         20 $c->stash->{all_testruns}[$i]{ preconditions } = $preconditions;
611             } else {
612 0         0 $c->stash->{all_testruns}[$i]{ error } = $preconditions;
613             }
614              
615             }
616             }
617 10     10   25074 }
  10         34  
  10         57  
618              
619              
620             sub prepare_testrunlists : Private {
621              
622 0     0 0 0 my ( $or_self, $or_c, $hr_filter_condition ) = @_;
623              
624 0         0 my $b_view_pager = 0;
625 0         0 my $hr_params = $or_c->req->params;
626             my $hr_query_vals = {
627             testrun_id => $hr_filter_condition->{testrun_id},
628             host => $hr_filter_condition->{host},
629             topic => $hr_filter_condition->{topic},
630             state => $hr_filter_condition->{state},
631             success => $hr_filter_condition->{success},
632             owner => $hr_filter_condition->{owner},
633 0         0 };
634              
635 0         0 require DateTime;
636 0 0       0 if ( $hr_params->{testrun_date} ) {
    0          
637             $hr_filter_condition->{testrun_date} = DateTime::Format::Strptime->new(
638             pattern => '%F',
639 0         0 )->parse_datetime( $hr_params->{testrun_date} );
640             }
641             elsif (! $hr_filter_condition->{testrun_id} ) {
642 0         0 $hr_filter_condition->{testrun_date} = DateTime->now();
643             }
644 0 0 0     0 if ( $hr_params->{pager_sign} && $hr_params->{pager_value} ) {
645 0 0       0 if ( $hr_params->{pager_sign} eq 'negative' ) {
    0          
646             $hr_filter_condition->{testrun_date}->subtract(
647 0         0 $hr_params->{pager_value} => 1
648             );
649             }
650             elsif ( $hr_params->{pager_sign} eq 'positive' ) {
651             $hr_filter_condition->{testrun_date}->add(
652 0         0 $hr_params->{pager_value} => 1
653             );
654             }
655             }
656              
657 0 0       0 if ( $hr_filter_condition->{testrun_date} ) {
658              
659 0   0     0 $or_c->stash->{pager_interval} = $hr_params->{pager_interval} || 1;
660 0         0 $or_c->stash->{testrun_date} = $hr_filter_condition->{testrun_date};
661              
662             # set testrun date
663 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');
664 0         0 my $d_testrun_date_to = $hr_filter_condition->{testrun_date}->strftime('%d %b %Y');
665              
666 0 0       0 if ( $d_testrun_date_from ne $d_testrun_date_to ) {
667 0         0 $or_c->stash->{head_overview} = "Testruns ($d_testrun_date_to - $d_testrun_date_from)";
668             }
669             else {
670 0         0 $or_c->stash->{head_overview} = "Testruns ($d_testrun_date_from)";
671             }
672              
673 0         0 $hr_query_vals->{testrun_date_from} = $hr_filter_condition->{testrun_date}->clone->subtract( days => $or_c->stash->{pager_interval} - 1 )->strftime('%F');
674 0         0 $hr_query_vals->{testrun_date_to} = $hr_filter_condition->{testrun_date}->strftime('%F');
675              
676 0         0 $or_c->stash->{view_pager} = 1;
677              
678             }
679             else {
680 0         0 $or_c->stash->{head_overview} = 'Testruns';
681             }
682              
683 0         0 $or_c->stash->{testruns} = $or_c->model('TestrunDB')->fetch_raw_sql({
684             query_name => 'testruns::web_list',
685             fetch_type => '@%',
686             query_vals => $hr_query_vals,
687             });
688              
689 0         0 return 1;
690              
691 10     10   16629 }
  10         31  
  10         61  
692              
693             sub prepare_navi : Private
694             {
695 0     0 0 0 my ( $self, $c ) = @_;
696              
697 0         0 my @a_args = @{$c->req->arguments};
  0         0  
698              
699             $c->stash->{navi} = [
700             {
701 0         0 title => 'Control',
702             href => q##,
703             active => 0,
704             subnavi => [
705             {
706             title => 'Create new Testrun',
707             href => '/tapper/testruns/create/',
708             },
709             ],
710             },
711             ];
712              
713 0         0 my @a_subnavi;
714 0         0 OUTER: for ( my $i = 0; $i < @a_args; $i+=2 ) {
715 0         0 my $s_reduced_filter_path = q##;
716 0         0 for ( my $j = 0; $j < @a_args; $j+=2 ) {
717 0 0       0 next if $i == $j;
718 0         0 $s_reduced_filter_path .= "/$a_args[$j]/".$a_args[$j+1];
719             }
720             push @a_subnavi, {
721             title => "$a_args[$i]: ".$a_args[$i+1],
722             image => '/tapper/static/images/minus.png',
723             href => '/tapper/testruns'
724             . $s_reduced_filter_path
725             . (
726             $c->stash->{view_pager}
727             ? '?testrun_date='
728             . $c->stash->{testrun_date}->strftime('%F')
729             . '&amp;pager_interval='
730             . $c->stash->{pager_interval}
731 0 0       0 : ''
732             )
733             };
734             } # OUTER
735              
736 0         0 push @{$c->stash->{navi}},
  0         0  
737             { title => 'Active Filters', subnavi => \@a_subnavi, },
738             { title => 'New Filters', id => 'idx_new_filter' },
739             { title => 'Help', id => 'idx_help', subnavi => [{ title => 'Press Shift for multiple Filters' }] },
740             ;
741              
742 10     10   13992 }
  10         46  
  10         68  
743              
744              
745             1;
746              
747             __END__
748              
749             =pod
750              
751             =encoding UTF-8
752              
753             =head1 NAME
754              
755             Tapper::Reports::Web::Controller::Tapper::Testruns
756              
757             =head1 DESCRIPTION
758              
759             Catalyst Controller.
760              
761             =head2 index
762              
763             Prints a list of a testruns together with their state, start time and
764             end time. No options, not return values.
765              
766             TODO: Too many testruns, takes too long to display. Thus, we need to add
767             filter facility.
768              
769             =head2 get_test_list_from_precondition
770              
771             Utility function to extract testprograms from a given (sub-) precondition.
772              
773             =head2 get_testrun_overview
774              
775             This function reads and parses all precondition of a testrun to generate
776             a summary of the testrun which will then be shown as an overview. It
777             returns a hash reference containing:
778             * name
779             * arch
780             * image
781             * test
782              
783             @param testrun result object
784              
785             @return hash reference
786              
787             =head2 new_create
788              
789             This function handles the form for the first step of creating a new
790             testrun.
791              
792             =head2 get_hostnames
793              
794             Get an array of all hostnames that can be used for a new testrun. Note:
795             The array contains array that contain the hostname twice (i.e. (['host',
796             'host'], ...) because that is what the template expects.
797              
798             @return success - ref to array of [ hostname, hostname ]
799              
800             =head2 parse_macro_precondition
801              
802             Parse the given file as macro precondition and return a has ref
803             containing required, optional and mcp_config fields.
804              
805             @param catalyst context
806             @param string - file name
807              
808             @return success - hash ref
809             @return error - string
810              
811             =head2 handle_precondition
812              
813             Check whether each required precondition has a value, uploads files and
814             so on.
815              
816             @param Catalyst context
817             @param config hash
818              
819             @return success - list of precondition ids
820             @return error - error message
821              
822             =head2 fill_usecase
823              
824             Creates the form for the last step of creating a testrun. When this form
825             is submitted and valid the testrun is created based on the gathered
826             data. The function is used directly by Catalyst which therefore cares
827             for params and returns.
828              
829             =head1 NAME
830              
831             Tapper::Reports::Web::Controller::Tapper::Testruns - Catalyst Controller
832              
833             =head1 METHODS
834              
835             =head2 index
836              
837             =head1 AUTHOR
838              
839             Steffen Schwigon,,,
840              
841             =head1 LICENSE
842              
843             This program is released under the following license: freebsd
844              
845             =head1 AUTHORS
846              
847             =over 4
848              
849             =item *
850              
851             AMD OSRC Tapper Team <tapper@amd64.org>
852              
853             =item *
854              
855             Tapper Team <tapper-ops@amazon.com>
856              
857             =back
858              
859             =head1 COPYRIGHT AND LICENSE
860              
861             This software is Copyright (c) 2019 by Advanced Micro Devices, Inc..
862              
863             This is free software, licensed under:
864              
865             The (two-clause) FreeBSD License
866              
867             =cut