[SCM] Debian package checker branch, master, updated. 2.1.4-5-gf8d6a2a
The following commit has been merged in the master branch:
commit 253ba1d9c0dd5a6457c774b0a4f7e5864b5bb7b9
Author: Russ Allbery <rra@debian.org>
Date: Sat Jan 10 12:54:40 2009 -0800
Add a changes file test suite
* t/runtests:
+ [RA] Add support for running lintian on changes files in t/changes
and checking the tag output.
+ [RA] Fix exit status when a test fails but -k was given.
Also restructure t/runtests to be a bit easier to follow and to make it
easier to add new types of test suites.
diff --git a/debian/changelog b/debian/changelog
index b1de393..ee4d888 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -19,6 +19,11 @@ lintian (2.1.5) UNRELEASED; urgency=low
* lib/Lintian/Check.pm:
+ [RA] New module collecting checks run from multiple places.
+ * t/runtests:
+ + [RA] Add support for running lintian on changes files in t/changes
+ and checking the tag output.
+ + [RA] Fix exit status when a test fails but -k was given.
+
-- Russ Allbery <rra@debian.org> Mon, 05 Jan 2009 10:41:18 -0800
lintian (2.1.4) unstable; urgency=low
diff --git a/private/update-coverage b/private/update-coverage
index 68646b5..7f72f36 100755
--- a/private/update-coverage
+++ b/private/update-coverage
@@ -59,6 +59,18 @@ for my $desc (<t/tests/*.desc>) {
}
}
+# Parse all tags files for the changes test suite.
+for my $tagfile (<t/changes/*.tags>) {
+ open(IN, '<', $tagfile) or die "Cannot open $tagfile: $!\n";
+ local $_;
+ while (<IN>) {
+ if (/^(.): (\S+)(?: (?:source|udeb))?: (\S+)/) {
+ delete $tags{$3};
+ }
+ }
+ close IN;
+}
+
# Now parse all tags files from the old test suite looking for what tags that
# test reveals.
my %legacy;
diff --git a/t/runtests b/t/runtests
index 2c597db..d030aaf 100755
--- a/t/runtests
+++ b/t/runtests
@@ -23,6 +23,8 @@
# The harness for Lintian's new test suite. Normally run through the runtests
# or check-tag targets in debian/rules. For detailed information on the test
# suite layout and naming conventions, see t/tests/README.
+#
+# The build output is directed to build.pkgname in the testing-directory.
use strict;
use warnings;
@@ -31,120 +33,222 @@ use Data::Dumper;
use Getopt::Long qw(GetOptions);
use Text::Template;
-sub usage {
- print <<END;
-Usage: $0 [-dkv] testset-directory testing-directory [test]
- $0 [-dkv] [-t tag] testset-directory testing-directory
+BEGIN {
+ my $LINTIAN_ROOT = $ENV{'LINTIAN_ROOT'};
+ if (not $LINTIAN_ROOT) {
+ use Cwd ();
+ $ENV{'LINTIAN_ROOT'} = $LINTIAN_ROOT = Cwd::cwd();
+ }
+ delete $ENV{'LINTIAN_CFG'};
+ delete $ENV{'LINTIAN_LAB'};
+ delete $ENV{'LINTIAN_DIST'};
+ delete $ENV{'LINTIAN_UNPACK_LEVEL'};
+ $ENV{'LC_COLLATE'} = 'C';
+
+ # Set standard umask because many of the test packages rely on this
+ # when creating files from the debian/rules script.
+ umask(022);
+}
+
+use lib "$ENV{'LINTIAN_ROOT'}/lib";
+use Util;
+use Tags;
-The -k option means do not stop after one failed test, but try
-them all and report all errors.
+# --- Global configuration
-The -v option will also display those tests that have a description, but are
-not tested in any testset-package.
+our $LINTIAN_ROOT = $ENV{'LINTIAN_ROOT'};
-The -d option will display debugging information.
+our $LINTIAN = $LINTIAN_ROOT . '/frontend/lintian -I -E';
+our $DPKG_BUILDPACKAGE = 'dpkg-buildpackage -rfakeroot -us -uc -d'
+ . ' -iNEVER_MATCH_ANYTHING -INEVER_MATCH_ANYTHING';
-The -t tag option will only run tests that test for or against that tag.
+# --- Usage information
-The optional 3rd parameter causes runtests to only run that particular test.
+sub usage {
+ print unquote(<<"END");
+: Usage: $0 [-dkv] <testset-directory> <testing-directory> [<test>]
+: $0 [-dkv] [-t <tag>] <testset-directory> <testing-directory>
+:
+: -d Display additional debugging information
+: -k Do not stop after one failed test
+: -t <tag> Run only tests for or against <tag>
+: -v Be more verbose
+:
+: The optional 3rd parameter causes runtests to only run that particular
+: test.
END
exit 2;
}
-# The build output is directed to build.pkgname in the testing-directory.
-
-# Exit codes:
-# 0 - success
-# 1 - one or more tests failed
-# 2 - an error prevented proper running of the tests
+# --- Parse options and arguments
-my $debug = 0;
-my $run_all_tests = 0;
-my $tag;
-my $verbose = 0;
+our $DEBUG = 0;
+our $VERBOSE = 0;
+our $RUNDIR;
+our $TESTSET;
-# --- Parse options and arguments
+my ($run_all_tests, $tag);
Getopt::Long::Configure('bundling');
-GetOptions('d|debug' => \$debug,
+GetOptions('d|debug' => \$DEBUG,
'k|keep-going' => \$run_all_tests,
't|tag=s' => \$tag,
- 'v|verbose' => \$verbose) or usage;
+ 'v|verbose' => \$VERBOSE) or usage;
if ($#ARGV < 1 || $#ARGV > 2) {
usage;
}
-my ($testset, $rundir, $singletest) = @ARGV;
+my $singletest;
+($TESTSET, $RUNDIR, $singletest) = @ARGV;
if ($tag and $singletest) {
usage;
}
-
-# --- Set and unset environment variables that lintian is sensitive to
-BEGIN {
- my $LINTIAN_ROOT = $ENV{'LINTIAN_ROOT'};
- if (not $LINTIAN_ROOT) {
- use Cwd ();
- $ENV{'LINTIAN_ROOT'} = $LINTIAN_ROOT = Cwd::cwd();
- }
- delete $ENV{'LINTIAN_CFG'};
- delete $ENV{'LINTIAN_LAB'};
- delete $ENV{'LINTIAN_DIST'};
- delete $ENV{'LINTIAN_UNPACK_LEVEL'};
- $ENV{'LC_COLLATE'} = 'C';
-
- # Set standard umask because many of the test packages rely on this
- # when creating files from the debian/rules script.
- umask(022);
+unless (-d $RUNDIR) {
+ fail("test directory $RUNDIR does not exist");
+}
+unless (-d $TESTSET) {
+ fail("test set directory $TESTSET does not exist");
}
-my $LINTIAN_ROOT = $ENV{'LINTIAN_ROOT'};
+# --- Display output immediately
-use lib "$ENV{'LINTIAN_ROOT'}/lib";
-use Util;
-use Tags;
+$| = 1;
-# --- Set the ways to call lintian and dpkg-buildpackage
-my $lintian_options = '-I -E';
-my $dpkg_buildpackage_options = '-rfakeroot -us -uc -d -iNEVER_MATCH_ANYTHING'
- . ' -INEVER_MATCH_ANYTHING';
-my $lintian_path = $LINTIAN_ROOT . "/frontend/lintian";
+# --- Exit status for the test suite driver
-# --- Display output immediately
-$| = 1;
+# Exit codes:
+# 0 - success
+# 1 - one or more tests failed
+# 2 - an error prevented proper running of the tests
+my $status = 0;
-# --- Let's play.
+# If we don't run any tests, we'll want to warn that we couldn't find
+# anything.
+my $tests_run = 0;
--d $rundir
- or fail("test directory $rundir does not exist\n");
+# --- Run all changes tests
-# in temporary labs
my @tests;
if ($singletest) {
- @tests = map { s/\.desc$//; $_ } ( $singletest );
+ my $test = $singletest;
+ $test =~ s/\.changes$//;
+ if (-f "$TESTSET/changes/$test.changes") {
+ @tests = ($test);
+ }
} elsif ($tag) {
- @tests = find_tests_for_tag($tag);
+ @tests = find_changes_for_tag($tag);
} else {
- -d $testset
- or fail("cannot find $testset: $!\n");
-
- @tests = map { s#^\Q$testset/tests/\E## ;s/\.desc$//; $_ } sort(<$testset/tests/*.desc>);
+ unless (-d "$TESTSET/changes") {
+ fail("cannot find $TESTSET/changes: $!");
+ }
+ @tests = map {
+ s,^\Q$TESTSET/changes/\E,,;
+ s/\.changes$//;
+ $_;
+ } sort(<$TESTSET/changes/*.changes>);
+}
+print "Found the following changes tests: @tests\n" if $DEBUG;
+print "Changes tests:\n" if @tests;
+for (@tests) {
+ my $okay = test_changes($_);
+ unless ($okay) {
+ exit 1 unless $run_all_tests;
+ $status = 1;
+ }
+ $tests_run++;
}
-print "Found the following tests: @tests\n" if $debug;
-my $tests_run = 0;
+# --- Run all package tests
+
+@tests = ();
+if ($singletest) {
+ my $test = $singletest;
+ $test =~ s/\.desc$//;
+ if (-f "$TESTSET/tests/$test.desc") {
+ @tests = ($test);
+ }
+} elsif ($tag) {
+ @tests = find_tests_for_tag($tag);
+} else {
+ unless (-d $TESTSET) {
+ fail("cannot find $TESTSET: $!");
+ }
+ @tests = map {
+ s,^\Q$TESTSET/tests/\E,,;
+ s/\.desc$//;
+ $_;
+ } sort(<$TESTSET/tests/*.desc>);
+}
+print "\n" if ($tests_run and @tests);
+print "Found the following tests: @tests\n" if $DEBUG;
+print "Package tests:\n" if @tests;
for (@tests) {
- my $testdesc = "$testset/tests/$_.desc";
+ my $testdesc = "$TESTSET/tests/$_.desc";
next unless -f $testdesc;
+ my $okay = test_package($_, $testdesc);
+ unless ($okay) {
+ exit 1 unless $run_all_tests;
+ $status = 1;
+ }
+ $tests_run++;
+}
+
+# --- Check whether we ran any tests
- print "process $testdesc...\n" if $debug;
+if (!$tests_run) {
+ if ($singletest) {
+ print "W: No tests run, did you specify a valid test name?\n";
+ } elsif ($tag) {
+ print "I: No tests found for that tag.\n";
+ } else {
+ print "E: No tests run, did you specify a valid testset directory?\n";
+ }
+}
+exit $status;
+
+# --- Full package testing
+
+# Find all tests that check a particular tag, either for its presence or
+# absence. Returns a list of names of the *.desc files, without the *.desc at
+# the end.
+sub find_tests_for_tag {
+ my ($tag) = @_;
+ my @tests;
+ for my $test (<$TESTSET/tests/*.desc>) {
+ my ($testname) = ($test =~ m,.*/([^/]+)\.desc$,);
+ my ($data) = read_dpkg_control($test);
+ if ($data->{'test-for'}) {
+ my %for = map { $_ => 1 } split(' ', $data->{'test-for'});
+ if ($for{$tag}) {
+ push (@tests, $testname);
+ next;
+ }
+ }
+ if ($data->{'test-against'}) {
+ my %against = map { $_ => 1 } split(' ', $data->{'test-against'});
+ if ($against{$tag}) {
+ push (@tests, $testname);
+ }
+ }
+ }
+ return @tests;
+}
+
+# Run a package test and show any diffs in the expected tags or any other
+# errors detected. Takes the test name and the description file. Returns
+# true if the test passes and false if it fails.
+sub test_package {
+ my ($test, $testdesc) = @_;
+
+ print "process $testdesc...\n" if $DEBUG;
my $testdata = (read_dpkg_control($testdesc))[0];
- check_test_is_sane($testset, $testdata);
+ check_test_is_sane($TESTSET, $testdata);
print "Running test $testdata->{testname} $testdata->{version}... ";
my $pkg = $testdata->{srcpkg};
my $pkgdir = "$pkg-$testdata->{version}";
- my $origdir = "$testset/tests/$testdata->{testname}";
- my $targetdir = "$rundir/$pkgdir";
- my $tmpldir = "$testset/templates";
+ my $origdir = "$TESTSET/tests/$testdata->{testname}";
+ my $targetdir = "$RUNDIR/$pkgdir";
+ my $tmpldir = "$TESTSET/templates";
my $is_native = ($testdata->{type} eq 'native');
my $orig_version = $testdata->{version};
@@ -159,7 +263,7 @@ for (@tests) {
}
}
- print "Cleaning up and repopulating $targetdir...\n" if $debug;
+ print "Cleaning up and repopulating $targetdir...\n" if $DEBUG;
runsystem_ok("rm", "-rf", $targetdir);
if ($is_native) {
runsystem("cp", "-rp", "$tmpldir/skel", $targetdir);
@@ -170,7 +274,7 @@ for (@tests) {
runsystem("cp", "-rp", "$tmpldir/skel.upstream", $targetdir);
runsystem("rm", "-f", "$targetdir/.dummy");
runsystem("rsync", "-rp", "$origdir/upstream/", "$targetdir/");
- runsystem("cd $rundir && ".
+ runsystem("cd $RUNDIR && ".
"tar czf ${pkg}_${orig_version}.orig.tar.gz $pkgdir");
runsystem("rsync", "-rp", "--exclude=debian/changelog",
"$tmpldir/skel/", "$targetdir/");
@@ -188,47 +292,49 @@ for (@tests) {
runsystem("echo >$targetdir/debian/watch");
}
if (-x "$origdir/pre_build") {
- print "running pre_build hook... " if $verbose;
+ print "running pre_build hook... " if $VERBOSE;
runsystem("$origdir/pre_build", $targetdir);
}
print "building... ";
- runsystem("cd $rundir/$pkgdir && dpkg-buildpackage $dpkg_buildpackage_options >../build.$pkg 2>&1");
+ runsystem("cd $RUNDIR/$pkgdir && $DPKG_BUILDPACKAGE >../build.$pkg 2>&1");
- print "testing... ";
- runsystem_ok("$lintian_path $lintian_options $rundir/$pkg\_$testdata->{version}*.changes".
- " 2>&1 | sort > $rundir/tags.$pkg");
+ print "testing... ";
+ runsystem_ok("$LINTIAN $RUNDIR/$pkg\_$testdata->{version}*.changes".
+ " 2>&1 | sort > $RUNDIR/tags.$pkg");
# Run a sed-script if it exists, for tests that have slightly variable
# output
- runsystem_ok("sed -i -f $origdir/post_test $rundir/tags.$pkg")
+ runsystem_ok("sed -i -f $origdir/post_test $RUNDIR/tags.$pkg")
if -e "$origdir/post_test";
- my $testok = runsystem_ok("cmp", "-s", "$rundir/tags.$pkg", "$origdir/tags");
- $tests_run++;
+ # Compare the output to the expected tags.
+ my $testok = runsystem_ok(qw(cmp -s), "$RUNDIR/tags.$pkg", "$origdir/tags");
if ($testok) {
print "ok.\n";
} else {
print "FAILED:\n";
- runsystem_ok("diff", "-u", "$origdir/tags", "$rundir/tags.$pkg");
- exit 1 unless $run_all_tests;
- next;
+ runsystem_ok("diff", "-u", "$origdir/tags", "$RUNDIR/tags.$pkg");
+ return;
}
# Check the output for invalid lines. Also verify that all Test-For tags
# are seen and all Test-Against tags are not.
my %test_for = map { $_ => 1 } split(' ', $testdata->{'test-for'});
my %test_against = map { $_ => 1 } split(' ', $testdata->{'test-against'});
- open TAGS, "$rundir/tags.$pkg" or fail("Cannot open $rundir/tags.$pkg");
+ my $okay = 1;
+ open TAGS, "$RUNDIR/tags.$pkg" or fail("Cannot open $RUNDIR/tags.$pkg");
while (<TAGS>) {
next if m/^N: /;
if (not /^(.): (\S+)(?: (?:source|udeb))?: (\S+)/) {
print "E: Invalid line:\n$_";
+ $okay = 0;
next;
}
my $tag = $3;
if ($test_against{$tag}) {
print "E: Tag $tag seen but listed in Test-Against\n";
+ $okay = 0;
}
delete $test_for{$tag};
}
@@ -236,29 +342,79 @@ for (@tests) {
if (%test_for) {
for my $tag (sort keys %test_for) {
print "E: Tag $tag listed in Test-For but not found\n";
+ $okay = 0;
}
}
+ return 1 if $okay;
+ return;
}
-if (!$tests_run) {
- if ($singletest) {
- print "W: No tests run, did you specify a valid test name?\n";
- } elsif ($tag) {
- print "I: No tests found for that tag.\n";
+# --- Changes file testing
+
+# Find all changes tests that check a particular tag, either for its presence
+# or absence. Returns a list of check names.
+sub find_changes_for_tag {
+ my ($tag) = @_;
+ my @tests;
+ for my $test (<$TESTSET/*.tags>) {
+ my ($testname) = ($test =~ m,.*/([^/]+)\.tags$,);
+ open(TAGS, '<', $test) or fail("Cannot open $test");
+ local $_;
+ while (<TAGS>) {
+ next if /^N: /;
+ if (not /^.: \S+(?: (?:source|udeb))?: (\S+)/) {
+ next;
+ }
+ }
+ push(@tests, $1);
+ }
+ return @tests;
+}
+
+# Run a test on a changes file and show any diffs in the expected tags or any
+# other errors detected. Takes the test name. Returns true if the test
+# passes and false if it fails.
+sub test_changes {
+ my ($test) = @_;
+ print "Running test $test... ";
+
+ my $testdir = "$TESTSET/changes";
+
+ print "testing... ";
+ runsystem_ok("$LINTIAN $testdir/$test.changes 2>&1".
+ " | sort > $RUNDIR/tags.changes-$test");
+
+ # Compare the output to the expected tags.
+ my $testok = runsystem_ok('cmp', '-s', "$testdir/$test.tags",
+ "$RUNDIR/tags.changes-$test");
+ if ($testok) {
+ print "ok.\n";
+ return 1;
} else {
- print "E: No tests run, did you specify a valid testset directory?\n";
+ print "FAILED:\n";
+ runsystem_ok("diff", "-u", "$testdir/$test.tags",
+ "$RUNDIR/tags.changes-$test");
+ return;
}
}
# --------------
+
+# Unquote a heredoc, used to make them a bit more readable in Perl code.
+sub unquote {
+ my ($string) = @_;
+ $string =~ s/^:( {0,7}|\t)//gm;
+ return $string
+}
+
sub runsystem {
- print "runsystem(@_)\n" if $debug;
+ print "runsystem(@_)\n" if $DEBUG;
system(@_) == 0
or fail("failed: @_\n");
}
sub runsystem_ok {
- print "runsystem_ok(@_)\n" if $debug;
+ print "runsystem_ok(@_)\n" if $DEBUG;
my $errcode = system(@_);
$errcode == 0 or $errcode == (1 << 8)
or fail("failed: @_\n");
@@ -282,7 +438,7 @@ sub fill_in_tmpl {
sub check_test_is_sane {
my ($dir, $data) = @_;
- if ($debug) {
+ if ($DEBUG) {
print "check_test_is_sane <= ".Dumper($data);
}
@@ -301,37 +457,11 @@ sub check_test_is_sane {
$data->{'test-for'} ||= '';
$data->{'test-against'} ||= '';
- if ($debug) {
+ if ($DEBUG) {
print "check_test_is_sane => ".Dumper($data);
}
}
-# Find all tests that check a particular tag, either for its presence or
-# absence. Returns a list of names of the *.desc files, without the *.desc at
-# the end.
-sub find_tests_for_tag {
- my ($tag) = @_;
- my @tests;
- for my $test (<$testset/tests/*.desc>) {
- my ($testname) = ($test =~ m,.*/([^/]+)\.desc$,);
- my ($data) = read_dpkg_control($test);
- if ($data->{'test-for'}) {
- my %for = map { $_ => 1 } split(' ', $data->{'test-for'});
- if ($for{$tag}) {
- push (@tests, $testname);
- next;
- }
- }
- if ($data->{'test-against'}) {
- my %against = map { $_ => 1 } split(' ', $data->{'test-against'});
- if ($against{$tag}) {
- push (@tests, $testname);
- }
- }
- }
- return @tests;
-}
-
# Local Variables:
# indent-tabs-mode: t
# cperl-indent-level: 4
--
Debian package checker
Reply to: