target_cmd_root_status target_cmd_output_root_status
target_cmd_root target_cmd target_cmd_build
- target_cmd_stashed
+ target_cmd_stashed target_subunit_cmd
target_cmd_output_root target_cmd_output
target_cmd_inputfh_root sshuho
target_getfile target_getfile_root
return "$stash/$$leafref";
}
+sub subunit_result_to_osstest_result ($) {
+ my ($ret) = @_;
+ return "pass" if $ret eq "success" or $ret eq "successful";
+ return "fail" if $ret eq "failure";
+ return "skip" if $ret eq "skip";
+ return "fail" if $ret eq "error";
+ # expected failure
+ return "pass" if $ret eq "xfail";
+ # unexpected success
+ return "fail" if $ret eq "uxsuccess";
+ die "subunit_result_to_osstest_result unexpected result $ret";
+}
+sub subunit_sanitize_testname ($) {
+ my ($testname) = @_;
+ $testname =~ s'[^_.()\[\]/~0-9a-zA-Z-]'_'g;
+ return $testname;
+}
+
+# Like target_cmd, but parse the command output as a subunit v1 stream and make
+# a substep out of each subunit test.
+sub target_subunit_cmd ($$;$$) {
+ my ($tho,$tcmd,$timeout,$extrasshopts) = @_;
+ my $filename = "subunit-output";
+ my $path = target_cmd_stashed($tho, \$filename, $tcmd, $timeout,
+ $extrasshopts);
+
+ open my $stdout, "$path" or die "$path: $!";
+
+ my $logfilename = undef;
+ my $fh = undef;
+
+ while (<$stdout>) {
+ if (/^time: \d+-\d+-\d+ \d+:\d+:\d+(?:\.\d+)?Z$/) {
+ # This is the timestamp for the next events
+ } elsif (/^test(?:ing)?:? (.+)\n/) {
+ # Start of a new test.
+ my $testname = subunit_sanitize_testname($1);
+ $logfilename = 'subunit-' . $testname . '.log';
+ $fh = open_unique_stashfile(\$logfilename);
+ substep_start('/' . $testname, $logfilename);
+ } elsif (/^(success(?:ful)?|failure|skip|error|xfail|uxsuccess):
+ \ (.+?)(\ \[(\ multipart)?)?$/x) {
+ # Result of a test, with its output.
+ my ($result, $testname, $have_details, $is_multipart) =
+ ($1,$2,$3,$4);
+
+ if ($have_details) {
+ if ($is_multipart) {
+ # Test output
+ while (<$stdout>) {
+ if (m{^content-type:}i) {
+ print $fh $_ or die $!;
+
+ # part name
+ my $line = <$stdout>;
+ print $fh $line or die $!;
+
+ # Read chunks of a part
+ while (<$stdout>) {
+ if (/^([0-9A-F]+)\r$/i) {
+ # The chunk size is in hex even though this
+ # does not seem to be documented in the
+ # subunit protocol description.
+ my $chunk_size = hex($1);
+ my $chunk;
+
+ last if $chunk_size == 0;
+ read $stdout, $chunk, $chunk_size;
+ print $fh $chunk or die $!;
+ } else {
+ # Unexpected output, was expecting a chunk
+ # size.
+ chomp;
+ logm("*** $_");
+ # Drop back to multipart "test output"
+ # parser, which is more likely to find
+ # a line that match.
+ last;
+ }
+ }
+ } elsif (/^\]$/) {
+ last;
+ } else {
+ # Unexpected output in multipart parser
+ chomp;
+ logm("*** $_");
+ }
+ }
+ } else {
+ # Simple non-multipart test output.
+ while (<$stdout>) {
+ last if (/^\]$/);
+ print $fh $_ or die $!;
+ }
+ }
+ }
+ close $fh or die $!;
+ substep_finish("/" .subunit_sanitize_testname($testname),
+ subunit_result_to_osstest_result($result));
+ } elsif (/^tags: .+/) {
+ # unused
+ } elsif (/^progress: (?:[+-]?\d+|push|pop)$/) {
+ # unused
+ } else {
+ # Unexpected output
+ chomp;
+ logm("*** $_");
+ }
+ }
+
+ close $stdout or die $!;
+}
+
sub poll_loop ($$$&) {
my ($maxwait, $interval, $what, $code) = @_;
# $code should return undef when all is well