#!/usr/bin/env perl
# vim:ts=4:sw=4:expandtab
-#
# © 2010-2011 Michael Stapelberg and contributors
-#
-# syntax: ./complete-run.pl --display :1 --display :2
-# to run the test suite on the X11 displays :1 and :2
-# use 'Xdummy :1' and 'Xdummy :2' before to start two
-# headless X11 servers
-#
use strict;
use warnings;
# these are shipped with the testsuite
use lib qw(lib);
use SocketActivation;
+use StartXDummy;
# the following modules are not shipped with Perl
use AnyEvent;
use AnyEvent::Handle;
# reads in a whole file
sub slurp {
- open my $fh, '<', shift;
+ open(my $fh, '<', shift);
local $/;
<$fh>;
}
my $coverage_testing = 0;
my $valgrind = 0;
my $help = 0;
+# Number of tests to run in parallel. Important to know how many Xdummy
+# instances we need to start (unless @displays are given). Defaults to
+# num_cores * 2.
+my $parallel = undef;
my @displays = ();
+my @childpids = ();
my $result = GetOptions(
"coverage-testing" => \$coverage_testing,
"valgrind" => \$valgrind,
"display=s" => \@displays,
+ "parallel=i" => \$parallel,
"help|?" => \$help,
);
-pod2usage(0) if $help;
+pod2usage(-verbose => 2, -exitcode => 0) if $help;
@displays = split(/,/, join(',', @displays));
@displays = map { s/ //g; $_ } @displays;
-@displays = qw(:1) if @displays == 0;
+# No displays specified, let’s start some Xdummy instances.
+if (@displays == 0) {
+ my ($displays, $pids) = start_xdummy($parallel);
+ @displays = @$displays;
+ @childpids = @$pids;
+}
# connect to all displays for two reasons:
# 1: check if the display actually works
}
}
+die "No usable displays found" if @wdisplays == 0;
+
my $config = slurp('i3-test.config');
# 1: get a list of all testcases
$aggregator->stop();
+# Disable buffering to make sure the output and summary appear before we exit.
+$| = 1;
+
for (@done) {
my ($test, $output) = @$_;
say "output for $test:";
# 4: print summary
$harness->summary($aggregator);
+kill(15, $_) for @childpids;
+
__END__
=head1 NAME
complete-run.pl [files...]
+=head1 EXAMPLE
+
+To run the whole testsuite on a reasonable number of Xdummy instances (your
+running X11 will not be touched), run:
+ ./complete-run.pl
+
+To run only a specific test (useful when developing a new feature), run:
+ ./complete-run t/100-fullscreen.t
+
=head1 OPTIONS
=over 8
# Run four tests in parallel on some Xdummy 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.
+
=item B<--valgrind>
Runs i3 under valgrind to find memory problems. The output will be available in
=item B<--coverage-testing>
Exits i3 cleanly (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
+instances for some reason).
+
+ # Run all tests on a single Xdummy instance
+ ./complete-run.pl -p 1
--- /dev/null
+package StartXDummy;
+# vim:ts=4:sw=4:expandtab
+
+use strict;
+use warnings;
+use POSIX ();
+use Exporter 'import';
+use Time::HiRes qw(sleep);
+use v5.10;
+
+our @EXPORT = qw(start_xdummy);
+
+# reads in a whole file
+sub slurp {
+ open(my $fh, '<', shift) or return '';
+ local $/;
+ <$fh>;
+}
+
+=head2 start_xdummy($parallel)
+
+Starts C<$parallel> (or number of cores * 2 if undef) Xdummy processes (see
+the file ./Xdummy) and returns two arrayrefs: a list of X11 display numbers to
+the Xdummy processes and a list of PIDs of the processes.
+
+=cut
+sub start_xdummy {
+ my ($parallel) = @_;
+
+ my @displays = ();
+ my @childpids = ();
+
+ # Yeah, I know it’s non-standard, but Perl’s POSIX module doesn’t have
+ # _SC_NPROCESSORS_CONF.
+ my $cpuinfo = slurp('/proc/cpuinfo');
+ my $num_cores = scalar grep { /model name/ } split("\n", $cpuinfo);
+ # If /proc/cpuinfo does not exist, we fall back to 2 cores.
+ $num_cores ||= 2;
+
+ $parallel ||= $num_cores * 2;
+
+ # First get the last used display number, then increment it by one.
+ # Effectively falls back to 1 if no X server is running.
+ my ($displaynum) = reverse ('0', sort </tmp/.X11-unix/X*>);
+ $displaynum =~ s/.*(\d)$/$1/;
+ $displaynum++;
+
+ say "Starting $parallel Xdummy instances, starting at :$displaynum...";
+
+ for my $idx (0 .. ($parallel-1)) {
+ my $pid = fork();
+ die "Could not fork: $!" unless defined($pid);
+ if ($pid == 0) {
+ # Child, close stdout/stderr, then start Xdummy.
+ POSIX::close(0);
+ POSIX::close(2);
+ exec './Xdummy', ":$displaynum", '-config', '/dev/null';
+ exit 1;
+ }
+ push(@childpids, $pid);
+ push(@displays, ":$displaynum");
+ $displaynum++;
+ }
+
+ # Wait until the X11 sockets actually appear. Pretty ugly solution, but as
+ # long as we can’t socket-activate X11…
+ my $sockets_ready;
+ do {
+ $sockets_ready = 1;
+ for (@displays) {
+ my $path = "/tmp/.X11-unix/X" . substr($_, 1);
+ $sockets_ready = 0 unless -S $path;
+ }
+ sleep 0.1;
+ } until $sockets_ready;
+
+ return \@displays, \@childpids;
+}
+
+1