Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CI:DOCS] xref-manpages script: more regression tests #21072

Merged
merged 1 commit into from
Jan 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion hack/xref-helpmsgs-manpages
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use utf8;

use strict;
use warnings;
use Clone qw(clone);
use FindBin;

(our $ME = $0) =~ s|.*/||;
Expand Down Expand Up @@ -460,12 +461,25 @@ sub podman_help {
################
# podman_man # Parse contents of podman-*.1.md
################
our %Man_Seen;
sub podman_man {
my $command = shift;
my $subpath = "$Markdown_Path/$command.1.md";
print "** $subpath \n" if $debug;

my %man = (_path => $subpath);

# We often get called multiple times on the same man page,
# because (e.g.) podman-container-list == podman-ps. It's the
# same man page text, though, and we don't know which subcommand
# we're being called for, so there's nothing to be gained by
# rereading the man page or by dumping yet more warnings
# at the user. So, keep a cache of what we've done.
if (my $seen = $Man_Seen{$subpath}) {
return clone($seen);
}
$Man_Seen{$subpath} = \%man;

open my $fh, '<', $subpath
or die "$ME: Cannot read $subpath: $!\n";
my $section = '';
Expand Down Expand Up @@ -515,7 +529,7 @@ sub podman_man {
if ($line =~ /^\|\s*\[podman-(\S+?)\(\d\)\]/) {
# $1 will be changed by recursion _*BEFORE*_ left-hand assignment
my $subcmd = $1;
$man{$subcmd} = podman_man("podman-$1");
$man{$subcmd} = podman_man("podman-$subcmd");
}

# In podman-<subcommand>.1.md
Expand Down
224 changes: 218 additions & 6 deletions hack/xref-helpmsgs-manpages.t
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use FindBin;
use Test::More;
use Test::Differences;

plan tests => 9;
plan tests => 10;

require_ok "$FindBin::Bin/xref-helpmsgs-manpages";

Expand All @@ -40,9 +40,10 @@ my @warnings_seen;
$SIG{__WARN__} = sub {
my $msg = shift;
chomp $msg;
$msg =~ s/^xref-\S+?:\s+//;
$msg =~ s|\s+$doc_path/| |g;
push @warnings_seen, $msg;
$msg =~ s/^xref-\S+?:\s+//; # strip "$ME: "
$msg =~ s!(^|\s+)$doc_path/!$1!g; # strip "doc/source/markdown"
$msg =~ s!:\d+:!:NNN:!; # file line numbers can change
push @warnings_seen, $msg;
};

# When we get errors (hopefully only when adding new functionality
Expand Down Expand Up @@ -157,10 +158,221 @@ test_xref("xref_by_help() injection", $hclone, $mclone,
# BEGIN fault injection tests on podman_man()
#
# This function has a ton of sanity checks. To test them we need to
# perform minor surgery on lots of .md files.
# perform minor surgery on lots of .md files: reordering lines,
# adding inconsistencies.
#
# FIXME: TBD. This PR has grown big enough as it is.

# Ordered list of the warnings we expect to see
my @expect_warnings;

# Helper function: given a filename and a function, reads filename
# line by line, invoking filter on each line and writing out the
# results.
sub sed {
my $path = shift; # in: filename (something.md)
my $action = shift; # in: filter function

# The rest of our arguments are the warnings introduced into this man page
push @expect_warnings, @_;

open my $fh_in, '<', "$doc_path/$path"
or die "Cannot read $doc_path/$path: $!";
my $tmpfile = "$doc_path/$path.tmp.$$";
open my $fh_out, '>', $tmpfile
or die "Cannot create $doc_path/$tmpfile: $!";

while (my $line = <$fh_in>) {
# This is what does all the magic
print { $fh_out } $action->($line);
}
close $fh_in;
close $fh_out
or die "Error writing $doc_path/$tmpfile: $!";
rename "$tmpfile" => "$doc_path/$path"
or die "Could not rename $doc_path/$tmpfile: $!";
}

# Start filtering.

# podman-attach is a deliberate choice here: it also serves as the man page
# for podman-container-attach. Prior to 2023-12-20 we would read the file
# twice, issuing two warnings, which is anti-helpful. Here we confirm that
# the dup-removing code works.
sed('podman-attach.1.md', sub {
my $line = shift;
$line =~ s/^(%\s+podman)-(attach\s+1)/$1 $2/;
$line;
},

"podman-attach.1.md:NNN: wrong title line '% podman attach 1'; should be '% podman-attach 1'",
);


# Tests for broken command-line options
# IMPORTANT NOTE: podman-exec precedes podman-container (below),
# because podman-exec.1.md is actually read while podman-container.1.md
# is still processing; so these messages are printed earlier:
# podman-container.1.md -> list of subcommands -> exec -> read -exec.1.md
# Sorry for the confusion.
sed('podman-exec.1.md', sub {
my $line = shift;

if ($line =~ /^#### \*\*--env\*\*/) {
$line = $line . "\ndup dup dup\n\n" . $line;
}
elsif ($line =~ /^#### \*\*--privileged/) {
$line = "#### \*\*--put-me-back-in-order\*\*\n\nbogus option\n\n" . $line;
}
elsif ($line =~ /^#### \*\*--tty\*\*/) {
chomp $line;
$line .= " xyz\n";
}
elsif ($line =~ /^#### \*\*--workdir\*\*/) {
$line = <<"END_FOO";
#### **--workdir**=*dir*, **-w**

blah blah bogus description

#### **--yucca**=*cactus*|*starch*|*both*

blah blah

#### **--zydeco**=*true* | *false*

END_FOO
}

return $line;
},

"podman-exec.1.md:NNN: flag '--env' is a dup",
"podman-exec.1.md:NNN: --privileged should precede --put-me-back-in-order",
"podman-exec.1.md:NNN: could not parse ' xyz' in option description",
"podman-exec.1.md:NNN: please rewrite as ', **-w**=*dir*'",
"podman-exec.1.md:NNN: values must be space-separated: '=*cactus*|*starch*|*both*'",
"podman-exec.1.md:NNN: Do not enumerate true/false for boolean-only options",
);


# Tests for subcommands in a table
sed('podman-container.1.md', sub {
my $line = shift;

# "podman container diff": force an out-of-order error
state $diff;
if ($line =~ /^\|\s+diff\s+\|/) {
$diff = $line;
return '';
}
if ($diff) {
$line .= $diff;
$diff = undef;
}

# "podman init": force a duplicate-command error
if ($line =~ /^\|\s+init\s+\|/) {
$line .= $line;
}

# "podman container port": force a wrong-man-page error
if ($line =~ /^\|\s+port\s+\|/) {
$line =~ s/-port\.1\.md/-top.1.md/;
}

return $line;
},

"podman-container.1.md:NNN: 'exec' and 'diff' are out of order",
"podman-container.1.md:NNN: duplicate subcommand 'init'",
# FIXME: this is not technically correct; it could be the other way around.
"podman-container.1.md:NNN: 'podman-port' should be 'podman-top' in '[podman-port(1)](podman-top.1.md)'",
);


# Tests for --format specifiers in a table
sed('podman-image-inspect.1.md', sub {
my $line = shift;

state $digest;
if ($line =~ /^\|\s+\.Digest\s+\|/) {
$digest = $line;
return '';
}
if ($digest) {
$line .= $digest;
$digest = undef;
}

if ($line =~ /^\|\s+\.ID\s+\|/) {
$line = $line . $line;
}

return $line;
},

"podman-image-inspect.1.md:NNN: format specifier '.Digest' should precede '.GraphDriver'",
"podman-image-inspect.1.md:NNN: format specifier '.ID' is a dup",
);


# Tests for SEE ALSO section
sed('podman-version.1.md', sub {
my $line = shift;

if ($line =~ /^## SEE ALSO/) {
$line .= "**foo**,**bar**"
. ", **baz**baz**"
. ", missingstars"
. ", **[podman-info(1)](podman-cp.1.md)**"
. ", **[podman-foo(1)](podman-wait.1.md)**"
. ", **[podman-x](podman-bar.1.md)**"
. ", **podman-logs(1)**"
. ", **podman-image-rm(1)**"
. ", **sdfsdf**"
. "\n";
}

return $line;
},

"podman-version.1.md:NNN: please add space after comma: '**foo**,**bar**'",
"podman-version.1.md:NNN: invalid token 'baz**baz'",
"podman-version.1.md:NNN: 'missingstars' should be bracketed by '**'",
"podman-version.1.md:NNN: inconsistent link podman-info(1) -> podman-cp.1.md, expected podman-info.1.md",
"podman-version.1.md:NNN: invalid link podman-foo(1) -> podman-wait.1.md",
"podman-version.1.md:NNN: could not parse 'podman-x' as 'manpage(N)'",
"podman-version.1.md:NNN: 'podman-logs(1)' should be '[podman-logs(1)](podman-logs.1.md)'",
"podman-version.1.md:NNN: 'podman-image-rm(1)' refers to a command alias; please use the canonical command name instead",
"podman-version.1.md:NNN: invalid token 'sdfsdf'"
);


# Tests for --filter specifiers
sed('podman-volume-prune.1.md', sub {
my $line = shift;

if ($line =~ /^\|\s+driver\s+\|/) {
$line = "| name! | sdfsdf |\n" . $line;
}
if ($line =~ /^\|\s+opt\s+\|/) {
$line .= $line;
}

return $line;
},

"podman-volume-prune.1.md:NNN: filter 'name!' only allowed immediately after its positive",
"podman-volume-prune.1.md:NNN: filter specifier 'opt' is a dup",
);

# DONE with fault injection. Reread man pages and verify warnings.
@warnings_seen = ();
{
no warnings 'once';
%LibPod::CI::XrefHelpmsgsManpages::Man_Seen = ();
}
$man = LibPod::CI::XrefHelpmsgsManpages::podman_man('podman');
eq_or_diff_text \@warnings_seen, \@expect_warnings, "podman_man() with faults";

# END fault injection tests on podman_man()
###############################################################################
Expand Down