9 local $SIG{__WARN__
} = \
&Carp
::cluck
;
12 use List
::MoreUtils qw
/any uniq/;
14 my $runtest_dir="/usr/lib/ltp/tests/linux/runtest";
15 #my $runtest_dir="runtest";
17 LTPRESULTS
=> "/var/cache/ltp/results",
18 LTPROOT
=> "/usr/lib/ltp/tests/linux",
19 TOOLSDIR
=> "/usr/lib/ltp/tools",
20 LTPTOOLS
=> "/usr/lib/ltp/tools",
21 PATH
=> "$ENV{PATH}:/usr/lib/ltp/tests/linux/testcases/bin",
22 TMP
=> $ENV{TMP
} // $ENV{TMPDIR
} // "/tmp",
37 return $arg if $arg =~ /^\d+$/;
43 my ($used_tests, $environment, $setup, $teardown) = @_;
45 for(keys %$environment) {
47 my $value=$environment->{$_};
52 for(keys %static_env) {
53 my $value=$static_env{$_};
56 if(($environment->{output
} // "") ne "") {
57 $panopts.=" -o ".shell_quote
($environment->{output
});
60 if(($environment->{failfile
} // "") ne "") {
61 my $ff=$environment->{failfile
};
62 my $out=$environment->{output
}//"";
65 $panopts.=" -C ".shell_quote
($ff);
68 if(($environment->{logfile
} // "") ne "") {
69 my $ff=$environment->{logfile
};
70 my $out=$environment->{output
}//"";
75 $panopts.=" -l ".shell_quote
($ff);
79 if(($environment->{count
} // "") ne "") {
80 $count=$environment->{count
};
81 if($count =~ /^(\d)l$/) {
82 $count=$1*@
$used_tests;
84 $count=to_number
($count);
86 if($environment->{random
}) {
87 $count = $count // scalar @
$used_tests;
90 if(!($environment->{random
})) {
95 $panopts.=" -s ".$count;
98 if(($environment->{time} // "") ne "") {
99 return if !$environment->{time} =~ /[0-9]+[hmsd]?/;
100 $panopts.=" -t ".$environment->{time};
103 if(($environment->{parallel
} // "") ne "") {
104 $panopts.=" -x ".to_number
($environment->{parallel
} // 0);
107 my $ft=new File
::Temp
(TEMPLATE
=> "/tmp/runtestXXXXXXXXX");
109 print $ft map { "$_->{id} $_->{command}" } @
$used_tests;
112 system '${LTPTOOLS}/pan -q -p -n $$ -a '.$zoo->filename.' -f '.$ft->filename.$panopts;
122 open(FILE
, "<$file");
124 my $ts_desc={ selected
=> 0, tests
=> [] };
130 if($1 =~ /DESCRIPTION:(.*)/) {
131 $ts_desc->{description
}=$1;
132 $last=\
$ts_desc->{description
};
133 } elsif ($1 =~ /ALL:(.*)/) {
134 push @
$allvars, grep m/./, (split qr/ +/, $1);
135 } elsif ($1 =~ /SETUP:(.*)/) {
136 push @
$allsetup, grep m/./, (split qr/ +/, $1);
139 } elsif(defined $last) {
149 next unless /^([^[:space:]]+)[[:space:]]+(.*)/;
151 if(exists($test_hash{"$1 $2"})) {
152 next if exists $test_hash{"$1 $2"}->{files
}->{$name};
153 push @
{$ts_desc->{tests
}}, $test_hash{"$1 $2"};
154 $test_hash{"$1 $2"}->{files
}->{$name}=undef;
155 $ts_desc->{selected
}++ if($test_hash{"$1 $2"}->{selected
});
157 push(@test_data, { id
=> $1, command
=> $2,
158 files
=> {$name => undef}});
160 $test_data[$#test_data]->{vars
}=[(grep { /^\$(.*)/; !exists($static_env{$1}) } ( @
$allvars, $2 =~ /\$[[:alpha:]][[:alnum:]_]*/g ))];
161 $test_data[$#test_data]->{setup
}=$allsetup;
162 push @
{$ts_desc->{tests
}}, \
%{$test_data[$#test_data]};
163 $test_hash{$id}=\
%{$test_data[$#test_data]};
164 $testsuites{"<ALL>"}->{count
}++;
169 $ts_desc->{count
}=$num;
170 $testsuites{$name}=$ts_desc;
175 $testsuites{"<ALL>"}={selected
=> 0, count
=> 0, tests
=> \
@test_data};
178 opendir(DIR
, $runtest_dir) || die("Couldn't open directory $runtest_dir");
184 load_file
("$runtest_dir/$_");
191 return map { (ref($_) eq "ARRAY") ? flatten
(@
$_) : $_ } @_;
197 return uniq
(flatten
(map $_->{vars
}, @
$ts_list));
203 return uniq
(flatten
(map $_->{setup
}, @
$ts_list));
206 sub tests_needing_vars
208 my ($tests, @vars)=@_;
209 my %vars_hash=(map { ($_ => undef) } @vars);
210 return grep { any
{ exists($vars_hash{$_}) } @
{$_->{vars
}} } @
$tests;
215 package Layout
::Proportional
;
217 use Curses
::UI
::Container
;
219 our @ISA=qw
/Curses::UI::Container/;
223 my $self = $class->SUPER::new
( @_, -layoutorder
=> [] );
229 my $ret=$self->SUPER::add
(@_);
230 push @
{$self->{-layoutorder
}}, $self->{-object2id
}->{$ret};
236 $self->Curses::UI
::Widget
::layout
();
238 my $size=($self->{-vertical
} ?
"height" : "width");
239 my $coord=($self->{-vertical
} ?
"y" : "x");
240 my $ot_size=($self->{-vertical
} ?
"width" : "height");
241 my $ot_coord=($self->{-vertical
} ?
"x" : "y");
242 my $padding=($self->{-vertical
} ?
243 sub { my $obj=shift; return ($obj->{-padtop
}//0)+($obj->{-padbottom
}//0); } :
244 sub { my $obj=shift; return ($obj->{-padleft
}//0)+($obj->{-padright
}//0); });
247 my %sizes= ( height
=> $self->canvasheight(), width
=> $self->canvaswidth() );
248 foreach(@
{$self->{-layoutorder
}}) {
249 my $obj=$self->{-id2object
}->{$_};
250 $total_min += $obj->{"-min-$size"} if $obj->{"-min-$size"};
251 $total_mult += $obj->{"-mult-$size"} if $obj->{"-mult-$size"};
253 my $excess = $sizes{$size}-$total_min;
254 my $ratio=($total_mult==0 ?
0 : $excess/$total_mult);
257 foreach(@
{$self->{-layoutorder
}}) {
258 my $obj=$self->{-id2object
}->{$_};
259 $obj->{-$coord}=$cur;
260 $obj->{-$ot_coord}=0;
261 $obj->{-$size}=int (($obj->{"-min-$size"} // 0) + ($obj->{"-mult-$size"} // 0)*$ratio);
262 $cur += $obj->{-$size};
263 $obj->{-$size} = 0 if $obj->{-$size} < 0;
264 delete $obj->{-$ot_size};
265 $obj->{-parent
}=$self;
272 $INC{"Layout/Proportional.pm"}="";
274 package ListBox
::MultiColumn
;
276 use Curses
::UI
::Listbox
;
278 our @ISA=qw
/Curses::UI::Listbox/;
282 my $self = $class->SUPER::new
(
284 "-col-designator" => [],
292 my ($self, $col) = @_;
293 return $self->{-colwidth
}->[$col] if $self->{-colwidth
}->[$col];
299 my $val = $self->values()->[$i];
301 if(ref($val) eq "ARRAY") {
302 for my $idx (0..$#$val-1) {
303 my $len=$self->getcolwidth($idx);
304 push (@disp, $$val[$idx]);
306 push (@disp, $$val[$#$val]);
307 } elsif(ref($val) eq "HASH") {
308 my $cd=$self->{"-col-designator"};
309 return "" unless $cd;
310 for my $idx (0..$#$cd-1) {
311 my $len=$self->getcolwidth($idx);
312 push (@disp, $val->{$cd->[$idx]});
314 push (@disp, $val->{$cd->[$#$cd]});
316 @disp=($self->SUPER::getlabel
($i));
318 @disp=($self->{"-col-formatter"} ?
319 $self->{"-col-formatter"}->(@disp) :
322 my $len=$self->getcolwidth($_);
323 $disp[$_] = sprintf("%-${len}.${len}s", $disp[$_]);
325 return join("|", @disp);
329 use List
::MoreUtils qw
/any/;
335 $INC{"ListBox/MultiColumn.pm"}="";
337 my $cui = new Curses
::UI
(
345 simple_text
(label
=> "Output file", name
=> "output"),
346 simple_text
(label
=> "Log file", name
=> "logfile"),
347 simple_text
(label
=> "Failed command file", name
=> "failfile"),
348 simple_text
(label
=> "Running time", name
=> "time", validator
=> '/^\d*[hdms]?$/'),
349 simple_text
(label
=> "Parallel tests", name
=> "parallel", validator
=> '/^\d*$/'),
350 simple_check
(label
=> "Random tests", name
=> "random"),
351 simple_text
(label
=> "Test count", name
=> "count", validator
=> '/^\d*l?$/'),
354 my %options =( failfile
=> "/var/tmp/LTP_RUN_ON_%d.failed",
355 logfile
=> "/var/tmp/LTP_RUN_ON_%d.log" );
359 return { label
=> $params{label
}, name
=> $params{name
},
361 my ($parent, $data, @params) = @_;
362 @params=(@params, -regexp
=> $params{validator
}) if exists $params{validator
};
363 my $lab=$parent->add(undef, "TextEntry", @params);
364 $lab->text($data) if defined $data;
367 get
=> sub { return shift()->get(); }
374 return { label
=> $params{label
}, name
=> $params{name
},
376 my ($parent, $data, @params) = @_;
377 my $lab=$parent->add(undef, "Checkbox", @params);
378 $lab->check() if $data;
381 get
=> sub { return shift()->get(); }
388 options_dialog
([@opt_template, map {
390 label
=> $_, name
=> $_,
392 my ($parent, $data, @params) = @_;
393 my $lab=$parent->add(undef, "TextEntry", @params);
394 $lab->text($data) if defined $data;
397 get
=> sub { return shift()->get(); }
399 } LTPTests
::needed_vars
[grep { $_->{selected
} } @test_data]], \
%options);
404 my $selected_tests=[grep { $_->{selected
} } @test_data];
405 my @needed_vars=LTPTests
::needed_vars
$selected_tests;
406 my @unsatisfied_tests=LTPTests
::tests_needing_vars
$selected_tests, (grep !$options{$_}, @needed_vars);
407 if(@unsatisfied_tests) {
408 my $response=$cui->dialog(
409 -message
=> "You have sellected tests that need setting some variables. Would you like to set them now?",
411 {-label
=> "Show the options dialog", -value
=> 0},
412 {-label
=> "Don't run those tests", -value
=> 1},
413 {-label
=> "Cancel", -value
=> 2}
415 -title
=> "Unset variables"
417 return if($response == 2);
420 } else { # filter tests
421 $selected_tests=[grep { !any
{ !$options{$_} } LTPTests
::needed_vars
[$_] } @
$selected_tests ];
424 my @setups = LTPTests
::setup_scripts
$selected_tests;
425 $cui->leave_curses();
426 LTPTests
::execute_tests
($selected_tests, \
%options, ["clear; echo Running LTP Tests; ", map { "$_ setup;" } @setups], [map { "$_ teardown;" } @setups]);
427 $cui->reset_curses();
431 { -label
=> "Load", -value
=> sub {
432 my $file=$cui->loadfilebrowser();
433 LTPTests
::load_file
$file if defined $file;
434 $ts_list->values([sort keys (%testsuites)]);
436 { -label
=> "Execute", -value
=> \
&execute_tests
},
437 { -label
=> "Options", -value
=> \
&show_opt_dialog
},
438 { -label
=> "Exit", -value
=> sub { exit(0) } }
443 my $v=$ts_list->get_active_value();
444 $tc_list->values($testsuites{$v}->{tests
} );
445 my $seh=$tc_list->{-onchange
};
446 $tc_list->onChange(undef);
447 $tc_list->set_selection(grep { $tc_list->{-values}->[$_]->{selected
} } (0..$#{$tc_list->{-values}}));
448 $tc_list->onChange($seh);
449 $tc_list->intellidraw();
452 sub update_tc_selection
454 my @sel=$tc_list->get();
455 for(@
{$tc_list->{-values}}){
458 for(keys %{$_->{files
}}) {
459 $testsuites{$_}->{selected
}--;
461 $testsuites{"<ALL>"}->{selected
}--;
465 if(!$_->{selected
}) {
467 for(keys %{$_->{files
}}) {
468 $testsuites{$_}->{selected
}++;
470 $testsuites{"<ALL>"}->{selected
}++;
473 $ts_list->intellidraw();
479 my $seh=$tc_list->{-onchange
};
480 $tc_list->onChange(undef);
481 $tc_list->set_selection((0..$#{$tc_list->{-values}}));
482 $tc_list->onChange($seh);
484 $tc_list->intellidraw();
490 $tc_list->clear_selection();
491 update_tc_selection
(); # clear_selection doesn't call -onchange callback
492 $tc_list->intellidraw();
497 my $ts=$testsuites{$ts_list->get_active_value()};
498 if($ts->{count
}>$ts->{selected
}) {
516 my ($template, $options)=@_;
518 my $dialog=$cui->add(undef, "Window");
519 my $dialogid=$cui->{-object2id
}->{$dialog};
526 my $label=$dialog->add(undef, "Label", -text
=> $_->{label
},
527 -x
=> 0, -width
=> $labelwidth, -y
=> $line);
528 push @widgets, $_->{create
}->($dialog, $options->{$_->{name
}}, -x
=> $labelwidth+2, -y
=> $line);
531 $line+=max
($label->{-h
}, $widgets[$#widgets]->{-h
});
534 $dialog->add(undef, "Buttonbox", -y
=> $line+1, -buttons
=>[
535 { -label
=> "Ok", -onpress
=> sub { $dialog->loose_focus; } }
541 $options->{$_->{name
}}=$_->{get
}->(shift(@widgets));
544 $cui->delete($dialogid);
545 $cui->root->focus(undef, 1);
548 $win = $cui->add("win", "Window", -padtop
=> 1);
552 -menu
=> [ { -label
=> "File", -submenu
=>$main_menu } ]
556 "layout", "Layout::Proportional", -vertical
=> 0, -border
=> 1
559 $ts_list=$cont->add (
560 "lb", "ListBox::MultiColumn",
561 -values => [sort keys (%testsuites)],
562 -vscrollbar
=> "right",
563 # -padtop => 2, -padleft => 2,
564 # -padright => 2, -padbottom => 2,
565 "-mult-width" => 1, -border
=> 1,
566 -onselchange
=> \
&update_tc_list
,
567 "-col-formatter" => sub {
568 my $tmp=$testsuites{$_[0]} // { selected
=> 0, count
=> 1 };
570 if($tmp->{selected
}==0) {
572 } elsif($tmp->{selected
}<$tmp->{count
}) {
582 $tc_list=$cont->add (
583 "lb2", "ListBox::MultiColumn",
584 -values => \
@test_data,
585 "-col-designator" => ["id", "command"],
586 -vscrollbar
=> "right",
587 # -padtop => 2, -padleft => 2,
588 # -padright => 2, -padbottom => 2,
589 "-mult-width" => 2, -border
=> 1,
591 -onchange
=> \
&update_tc_selection
594 $ts_list->set_routine('option-check', \
&check_ts
);
595 $ts_list->set_routine('option-uncheck', \
&uncheck_ts
);
596 $ts_list->set_routine('option-select', \
&toggle_ts
);
598 $cui->set_binding( sub{ $cui->focus('menu') }, Curses
::KEY_F
(10) );