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.15';
4 11     11   7590 use parent 'Tapper::Reports::Web::Controller::Base';
  11         82  
  11         107  
5 11     11   1005 use Cwd;
  11         30  
  11         795  
6 11     11   82 use Data::DPath 'dpath';
  11         27  
  11         133  
7 11     11   3311 use DateTime::Format::DateParse;
  11         29  
  11         335  
8 11     11   75 use DateTime;
  11         28  
  11         233  
9 11     11   84 use File::Basename;
  11         25  
  11         800  
10 11     11   84 use File::Path;
  11         23  
  11         613  
11 11     11   101 use List::Util 'max';
  11         27  
  11         668  
12 11     11   99 use Template;
  11         35  
  11         373  
13 11     11   69 use YAML::Syck;
  11         26  
  11         728  
14              
15 11     11   6552 use Tapper::Cmd::Testrun;
  11         346578  
  11         390  
16 11     11   116 use Tapper::Cmd::Precondition;
  11         32  
  11         231  
17 11     11   68 use Tapper::Config;
  11         24  
  11         239  
18 11     11   60 use Tapper::Model 'model';
  11         26  
  11         448  
19 11     11   5333 use Tapper::Reports::Web::Util::Testrun;
  11         37  
  11         372  
20 11     11   5144 use Tapper::Reports::Web::Util::Filter::Testrun;
  11         49  
  11         385  
21              
22 11     11   79 use common::sense;
  11         27  
  11         73  
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 11     11   2390 }
  11         23  
  11         99  
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 611 my ( $self, $c, $testrun ) = @_;
60              
61 1         2 my $retval = {};
62              
63 1 50       4 return $retval unless $testrun;
64              
65 1         26 $retval->{shortname} = $testrun->shortname;
66              
67 1         35 foreach ($testrun->ordered_preconditions) {
68 2         29104 my $precondition = $_->precondition_as_hash;
69 2 50       212 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         18 return $retval;
110 11     11   147876 }
  11         37  
  11         61  
111              
112 11     11 0 11315 sub base : Chained PathPrefix CaptureArgs(0) { }
  11     9   29  
  11         53  
113              
114             sub id : Chained('base') PathPart('') CaptureArgs(1)
115             {
116 2     2 0 1139 my ( $self, $c, $testrun_id ) = @_;
117 2         12 $c->stash(testrun => $c->model('TestrunDB')->resultset('Testrun')->find($testrun_id));
118 2 50       10352 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 11     11   12220 }
  11         28  
  11         63  
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 11     11   11646 }
  11         27  
  11         64  
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 11     11   11704 }
  11         28  
  11         55  
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 11     11   11637 }
  11         33  
  11         54  
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 11     11   11891 }
  11         27  
  11         61  
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 11     11   11562 }
  11         29  
  11         55  
192              
193             sub preconditions : Chained('id') PathPart('preconditions') CaptureArgs(0)
194             {
195 2     2 0 1359 my ( $self, $c ) = @_;
196 2         10 $c->stash(preconditions => [$c->stash->{testrun}->ordered_preconditions]);
197 2         58238 my @preconditions_as_hash = map { $_->precondition_as_hash } $c->stash->{testrun}->ordered_preconditions;
  4         54372  
198 2         132 $YAML::Syck::SortKeys = 1;
199 2         119 $c->stash->{precondition_string} = YAML::Syck::Dump(@preconditions_as_hash);
200 11     11   11805 }
  11         29  
  11         64  
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 11     11   11839 }
  11         30  
  11         57  
216              
217             sub validate_yaml
218             {
219 1     1 0 4 my ($data) = @_;
220 1         2 eval {
221 1         6 YAML::Syck::Load($data);
222             };
223 1         54 return $@;
224             }
225              
226             sub edit : Chained('preconditions') PathPart('edit') Args(0) :FormConfig
227             {
228 2     2 0 1103758 my ($self, $c) = @_;
229 2         9 my ($max_line, $line_count) = (0,0);
230              
231 2         9 my @lines = split "\n", $c->stash->{precondition_string};
232 2         179 foreach my $line (@lines) {
233 18         43 $max_line = max($max_line, length($line));
234             }
235              
236 2         10 my $form = $c->stash->{form};
237              
238 2 100       152 if ($form->submitted_and_valid) {
239 1         568 my $data = $form->input->{preconditions};
240              
241             # check whether user entered valid YAML
242 1         12 my $error = validate_yaml($data);
243 1 50       5 if ($error) {
244 0         0 $c->stash(message => "<emp>Error</emp>: $error");
245             } else {
246 1         3 my @precondition_ids = eval {
247 1         20 my $precond_cmd = Tapper::Cmd::Precondition->new();
248 1         1232 $precond_cmd->add($data);
249             };
250 1 50       32157 if ($@) {
251 0         0 $c->stash(message => "<emp>Error</emp>: $@");
252 0         0 return;
253             }
254              
255 1         9 $c->stash->{testrun}->disassign_preconditions();
256 1         31615 my $retval = $c->stash->{testrun}->assign_preconditions(@precondition_ids);
257 1 50       27375 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         145 $text->rows(int @lines);
267 1         23 $text->cols($max_line);
268 1         17 $text->default($c->stash->{precondition_string});
269             }
270 11     11   16021 }
  11         26  
  11         64  
271              
272             sub update_precondition : Chained('base') PathPart('update_precondition')
273             {
274 0     0 0 0 my ($self, $c) = @_;
275 11     11   10865 }
  11         33  
  11         57  
276              
277              
278             sub show_precondition : Chained('preconditions') PathPart('show') Args(0)
279             {
280 0     0 0 0 my ( $self, $c ) = @_;
281              
282 11     11   10560 }
  11         34  
  11         64  
283              
284              
285             sub similar : Chained('id') PathPart('similar') Args(0)
286       0 0   {
287 11     11   10282 }
  11         30  
  11         63  
288              
289              
290             sub new_create : Chained('base') :PathPart('create') :Args(0) :FormConfig
291             {
292 5     5 1 3109656 my ($self, $c) = @_;
293 5         22 my $form = $c->stash->{form};
294              
295 5 100       299 if ($form->submitted_and_valid) {
296 1         965 my $data = $form->input();
297 1         24 $c->session->{testrun_data} = $data;
298 1         5590 $c->session->{valid} = 1;
299 1         113 $c->session->{usecase_file} = $form->input->{use_case};
300 1         101 $c->res->redirect('/tapper/testruns/fill_usecase');
301              
302             } else {
303 4         1088 my $select;
304              
305 4         29 $select = $form->get_element({type => 'Select', name => 'owner'});
306 4         962 $select->options($self->get_owner_names());
307              
308 4         537 $select = $form->get_element({type => 'Select', name => 'requested_hosts'});
309 4         1124 $select->options($self->get_hostnames());
310              
311 4         518 my @use_cases;
312 4         50 my $path = Tapper::Config->subconfig->{paths}{use_case_path};
313 4         592 foreach my $file (glob "$path/*.mpc") {
314 24 50       845 open my $fh, "<", $file or $c->response->body(qq(Can not open $file: $!)), return;
315 24         91 my $desc;
316             my $hide;
317 24         409 while (my $line = <$fh>) {
318 52         290 ($desc) = $line =~/^#+ *(?:tapper[_-])?description:\s*(.+)/;
319 52 100       170 last if $desc;
320             }
321 24         71 while (my $line = <$fh>) {
322 4908         6664 ($hide) = $line =~/^#+ *(?:tapper[_-])?hide-in-webgui:\s*(.+)/;
323 4908 50       10677 last if $hide;
324             }
325              
326 24         666 my ($shortfile, undef, undef) = File::Basename::fileparse($file, ('.mpc'));
327 24 50       380 push @use_cases, [$file, "$shortfile - $desc"] unless $hide;
328              
329             }
330 4         44 my $select = $form->get_element({type => 'Radiogroup', name => 'use_case'});
331 4         910 $select->options(\@use_cases);
332             }
333              
334 11     11   16075 }
  11         29  
  11         69  
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 17 my ($self) = @_;
350 4         27 my @all_owners = model("TestrunDB")->resultset('Owner')->all();
351 4         51577 my @owners;
352 4         183 foreach my $owner (sort {$a->name cmp $b->name} @all_owners) {
  0         0  
353 3 50       76 if ($owner->login eq 'tapper') {
354 0         0 unshift(@owners, [$owner->login, $owner->name." (".$owner->login.")"]);
355             } else {
356 3         168 push(@owners, [$owner->login, $owner->name." (".$owner->login.")"]);
357             }
358             }
359 4         207 return \@owners;
360             }
361              
362              
363             sub get_hostnames
364             {
365 5     5 1 17 my ($self) = @_;
366 5         46 my @all_machines = model("TestrunDB")->resultset('Host')->search({active => 1});
367 5         15195 my @machines;
368             HOST:
369 5         84 foreach my $host (sort {$a->name cmp $b->name} @all_machines) {
  4         105  
370              
371             # if host is bound, is must be bound to
372             # new_testrun_queue (possibly among others)
373 8 50       523 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         35185 push(@machines, [ $host->name, $host->name ]);
380             }
381 5         299 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         4 my $config;
391 2         20 my $home = $c->path_to();
392 2         440 my ($shortfile, undef, undef) = File::Basename::fileparse($file, ('.mpc'));
393              
394 2 50       89 open my $fh, "<", $file or return "Can not open use case description $file:$!";
395 2         14 my ($required, $optional, $mpc_config) = ('', '', '');
396              
397 2         30 while (my $line = <$fh>) {
398 214 100       374 $config->{description_text} .= "$1\n" if $line =~ /^### ?(.*)$/;
399              
400 214 50       333 ($required) = $line =~/^#+ *(?:tapper[_-])?mandatory[_-]fields?:\s*(.+)/ if not $required;
401 214 100       323 ($optional) = $line =~/^#+ *(?:tapper[_-])?optional[_-]fields?:\s*(.+)/ if not $optional;
402 214 100       487 ($mpc_config) = $line =~/^#+ *(?:tapper[_-])?config[_-]file:\s*(.+)/ if not $mpc_config;
403             }
404              
405 2         15 my $delim = qr/,+\s*/;
406 2         24 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         13 foreach my $field (split $delim, $optional) {
417 4         15 my ($name, $type) = split /\./, $field;
418 4 100       11 $type = 'Text' if not $type;
419 4         9 push @{$config->{optional}},{type => ucfirst($type),
  4         21  
420             name => $name,
421             label => $name,
422             };
423             }
424              
425 2 50       6 if ($mpc_config) {
426 2         15 my $use_case_path = Tapper::Config->subconfig->{paths}{use_case_path};
427 2 50       20 $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       22 $mpc_config = getcwd()."/$mpc_config" if $mpc_config !~ m'^/'o;
435              
436 2 50       33 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         9 $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         10  
445 2   33     3 unshift @{$config->{required}},
  2         24  
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         32 return $config;
457 11     11   25205 }
  11         27  
  11         59  
458              
459              
460              
461             sub handle_precondition
462             {
463 2     2 1 8 my ($self, $c, $config) = @_;
464 2         8 my $form = $c->stash->{form};
465 2         118 my %macros;
466 2         5 my %all_form_elements = %{$c->request->{parameters}};
  2         38  
467              
468 2         30 foreach my $element (@{$config->{required}}, @{$config->{optional}}) {
  2         7  
  2         8  
469 6         15 my $name = $element->{name};
470 6 100       18 next if not defined $all_form_elements{$name};
471              
472 4 50       15 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       11 if (defined($all_form_elements{$name})) {
491 4         9 $macros{$name} = $all_form_elements{$name};
492 4         11 delete $all_form_elements{$name};
493             } else {
494             # TODO: handle error
495             }
496              
497             }
498              
499 2         8 foreach my $name (keys %all_form_elements) {
500 2 50       8 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       145 open my $fh, "<", $config->{file} or return(qq(Can not open $config->{file}: $!));
513 2         7 my $mpc = do {local $/; <$fh>};
  2         12  
  2         76  
514              
515 2         7 my $ttapplied;
516              
517 2         30 my $tt = new Template ();
518 2 50       8840 return $tt->error if not $tt->process(\$mpc, \%macros, \$ttapplied);
519              
520 2         62421 my $cmd = Tapper::Cmd::Precondition->new();
521 2         1842 my @preconditions;
522 2         6 eval { @preconditions = $cmd->add($ttapplied)};
  2         11  
523 2 50       135565 return $@ if $@;
524              
525 2         31 $cmd->assign_preconditions($config->{testrun_id}, @preconditions);
526 2         120100 return \@preconditions;
527             }
528              
529              
530             sub fill_usecase : Chained('base') :PathPart('fill_usecase') :Args(0) :FormConfig
531             {
532 2     2 1 23687 my ($self, $c) = @_;
533 2         9 my $form = $c->stash->{form};
534 2         130 my $position = $form->get_element({type => 'Submit'});
535 2         134 my $file = $c->session->{usecase_file};
536 2         8866 my ($shortfile, undef, undef) = File::Basename::fileparse($file, ('.mpc'));
537 2         6 my %macros;
538 2 50       11 $c->res->redirect('/tapper/testruns/create') unless $file;
539              
540 2         10 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         12 $c->stash->{description_text} = $config->{description_text};
546 2         137 foreach my $element (@{$config->{required}}) {
  2         7  
547 2         6 $element->{label} .= '*'; # mark field as required
548 2         30 $form->element($element);
549             }
550              
551 2         211352 foreach my $element (@{$config->{optional}}) {
  2         10  
552 4         211772 $element->{label} .= ' ';
553 4         13 $form->element($element);
554             }
555              
556 2 50       2934 if ($config->{mpc_config}) {
557 2         10 $form->load_config_file( $config->{mpc_config} );
558             }
559              
560 2         36133 $form->elements({type => 'Submit', name => 'submit', value => 'Submit'});
561 2         4826 $form->process();
562              
563 2 100       72444 if ($form->submitted_and_valid) {
564 1         948 my $testrun_data = $c->session->{testrun_data};
565 1         128 my @testhosts;
566              
567             # allow overwrite testrun topic
568 1         21 my $testrun_topic = $form->input->{testrun_topic};
569 1 50       26 if ($testrun_topic) {
570 1         5 $testrun_data->{topic} = $testrun_topic;
571             } else {
572 0         0 $testrun_data->{topic} = "undefined-topic";
573             }
574              
575             # hosts
576 1 50       4 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         50  
  1         4  
584             }
585              
586 1         8 $c->stash->{all_testruns} = [];
587             HOST:
588 1         83 for( my $i=0; $i < @testhosts; $i++) {
589 2         194 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         16 my %testrun_settings = %$testrun_data;
594 2         20 $testrun_settings{queue} = Tapper::Config->subconfig->{new_testrun_queue};
595              
596 2         15 $c->stash->{all_testruns}[$i]{host} = $host;
597              
598 2         120 $testrun_settings{requested_hosts} = $host;
599 2         23 my $cmd = Tapper::Cmd::Testrun->new();
600 2         1730 eval { $config->{testrun_id} = $cmd->add(\%testrun_settings)};
  2         15  
601 2 50       79931 if ($@) {
602 0         0 $c->stash->{all_testruns}[$i]{error} = $@;
603 0         0 next HOST;
604             }
605 2         12 $c->stash->{all_testruns}[$i]{id} = $config->{testrun_id};
606              
607 2         194 $config->{file} = $file;
608 2         15 my $preconditions = $self->handle_precondition($c, $config);
609 2 50       465 if (ref($preconditions) eq 'ARRAY') {
610 2         16 $c->stash->{all_testruns}[$i]{ preconditions } = $preconditions;
611             } else {
612 0         0 $c->stash->{all_testruns}[$i]{ error } = $preconditions;
613             }
614              
615             }
616             }
617 11     11   25443 }
  11         34  
  11         59  
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 11     11   16375 }
  11         29  
  11         58  
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 11     11   13745 }
  11         32  
  11         57  
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) 2020 by Advanced Micro Devices, Inc..
862              
863             This is free software, licensed under:
864              
865             The (two-clause) FreeBSD License
866              
867             =cut