#!/usr/bin/env perl
# vim:ts=4:sw=4:expandtab
-# © 2010-2011 Michael Stapelberg and contributors
+# © 2010 Michael Stapelberg and contributors
package complete_run;
use strict;
use warnings;
use v5.10;
+use utf8;
# the following are modules which ship with Perl (>= 5.10):
use Pod::Usage;
-use Cwd qw(abs_path);
use File::Temp qw(tempfile tempdir);
use Getopt::Long;
use POSIX ();
use TAP::Parser::Aggregator;
use Time::HiRes qw(time);
use IO::Handle;
+
+my $dirname;
+
+BEGIN {
+ use File::Basename;
+ use Cwd qw(abs_path);
+
+ # fileparse()[1] contains the directory portion of the specified path.
+ # See File::Basename(3p) for more details.
+ $dirname = (fileparse(abs_path($0)))[1];
+}
+
# these are shipped with the testsuite
-use lib qw(lib);
-use StartXDummy;
+use lib $dirname . 'lib';
+use StartXServer;
use StatusLine;
use TestWorker;
# the following modules are not shipped with Perl
use X11::XCB::Connection;
use JSON::XS; # AnyEvent::I3 depends on it, too.
+binmode STDOUT, ':utf8';
+binmode STDERR, ':utf8';
+
# Close superfluous file descriptors which were passed by running in a VIM
# subshell or situations like that.
AnyEvent::Util::close_all_fds_except(0, 1, 2);
my %timings;
my $help = 0;
-# Number of tests to run in parallel. Important to know how many Xdummy
+# Number of tests to run in parallel. Important to know how many Xephyr
# instances we need to start (unless @displays are given). Defaults to
# num_cores * 2.
my $parallel = undef;
coverage => 0,
restart => 0,
);
-my $keep_xdummy_output = 0;
+my $keep_xserver_output = 0;
my $result = GetOptions(
"coverage-testing" => \$options{coverage},
- "keep-xdummy-output" => \$keep_xdummy_output,
+ "keep-xserver-output" => \$keep_xserver_output,
"valgrind" => \$options{valgrind},
"strace" => \$options{strace},
"xtrace" => \$options{xtrace},
pod2usage(-verbose => 2, -exitcode => 0) if $help;
+chdir $dirname or die "Could not chdir into $dirname";
+
# Check for missing executables
my @binaries = qw(
../i3
);
foreach my $binary (@binaries) {
- die "$binary executable not found" unless -e $binary;
+ die "$binary executable not found, did you run “make”?" unless -e $binary;
die "$binary is not an executable" unless -x $binary;
}
+if ($options{coverage}) {
+ qx(command -v lcov &> /dev/null);
+ die "Cannot find lcov needed for coverage testing." if $?;
+ qx(command -v genhtml &> /dev/null);
+ die "Cannot find genhtml needed for coverage testing." if $?;
+
+ # clean out the counters that may be left over from previous tests.
+ qx(lcov -d ../ --zerocounters &> /dev/null);
+}
+
+qx(Xephyr -help 2>&1);
+die "Xephyr was not found in your path. Please install Xephyr (xserver-xephyr on Debian)." if $?;
+
@displays = split(/,/, join(',', @displays));
@displays = map { s/ //g; $_ } @displays;
my $numtests = scalar @testfiles;
-# No displays specified, let’s start some Xdummy instances.
+# No displays specified, let’s start some Xephyr instances.
if (@displays == 0) {
- @displays = start_xdummy($parallel, $numtests, $keep_xdummy_output);
+ @displays = start_xserver($parallel, $numtests, $keep_xserver_output);
}
# 1: create an output directory for this test-run
$outdir .= `git describe --tags`;
chomp($outdir);
mkdir($outdir) or die "Could not create $outdir";
-unlink("latest") if -e "latest";
+unlink("latest") if -l "latest";
symlink("$outdir", "latest") or die "Could not symlink latest to $outdir";
# connect to all displays for two reasons:
# 1: check if the display actually works
# 2: keep the connection open so that i3 is not the only client. this prevents
-# the X server from exiting (Xdummy will restart it, but not quick enough
-# sometimes)
+# the X server from exiting
my @single_worker;
for my $display (@displays) {
my $screen;
# Read previous timing information, if available. We will be able to roughly
# predict the test duration and schedule a good order for the tests.
-my $timingsjson = StartXDummy::slurp('.last_run_timings.json');
+my $timingsjson = StartXServer::slurp('.last_run_timings.json');
%timings = %{decode_json($timingsjson)} if length($timingsjson) > 0;
# Re-order the files so that those which took the longest time in the previous
sort { $b->[1] <=> $a->[1] }
map { [$_, $timings{$_} // 999] } @testfiles;
+# Run 000-load-deps.t first to bail out early when dependencies are missing.
+my $loadtest = "t/000-load-deps.t";
+if ((scalar grep { $_ eq $loadtest } @testfiles) > 0) {
+ @testfiles = ($loadtest, grep { $_ ne $loadtest } @testfiles);
+}
+
printf("\nRough time estimate for this run: %.2f seconds\n\n", $timings{GLOBAL})
if exists($timings{GLOBAL});
if ($numtests == 1) {
say '';
say 'Test output:';
- say StartXDummy::slurp($logfile);
+ say StartXServer::slurp($logfile);
}
END { cleanup() }
-exit 0;
+if ($options{coverage}) {
+ print("\nGenerating test coverage report...\n");
+ qx(lcov -d ../ -b ../ --capture -o latest/i3-coverage.info);
+ qx(genhtml -o latest/i3-coverage latest/i3-coverage.info);
+ if ($?) {
+ print("Could not generate test coverage html. Did you compile i3 with test coverage support?\n");
+ } else {
+ print("Test coverage report generated in latest/i3-coverage\n");
+ }
+}
+
+exit ($aggregator->failed > 0);
#
# Takes a test from the beginning of @testfiles and runs it.
}
sub cleanup {
+ my $exitcode = $?;
$_->() for our @CLEANUP;
- exit;
+ exit $exitcode;
}
# must be in a begin block because we C<exit 0> above
=head1 EXAMPLE
-To run the whole testsuite on a reasonable number of Xdummy instances (your
+To run the whole testsuite on a reasonable number of Xephyr instances (your
running X11 will not be touched), run:
./complete-run.pl
# Run tests on the second X server
./complete-run.pl -d :1
- # Run four tests in parallel on some Xdummy servers
+ # Run four tests in parallel on some Xephyr servers
./complete-run.pl -d :1,:2,:3,:4
Note that it is not necessary to specify this anymore. If omitted,
-complete-run.pl will start (num_cores * 2) Xdummy instances.
+complete-run.pl will start (num_cores * 2) Xephyr instances.
=item B<--valgrind>
=item B<--coverage-testing>
-Exits i3 cleanly (instead of kill -9) to make coverage testing work properly.
+Generates a test coverage report at C<latest/i3-coverage>. Exits i3 cleanly
+during tests (instead of kill -9) to make coverage testing work properly.
=item B<--parallel>
-Number of Xdummy instances to start (if you don’t want to start num_cores * 2
+Number of Xephyr instances to start (if you don't want to start num_cores * 2
instances for some reason).
- # Run all tests on a single Xdummy instance
+ # Run all tests on a single Xephyr instance
./complete-run.pl -p 1
+
+=back