From 20d6ae4110bfec1921b62a185921255ef719e042 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Tue, 4 Oct 2011 19:58:17 +0100 Subject: [PATCH 01/12] tests: make complete-run use POSIX::close(3) instead of reserving a file descriptor when starting This makes it possible to run complete-run.pl with a "tainted" environment in which fd 3 (and possibly others) are already present. --- testcases/complete-run.pl | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/testcases/complete-run.pl b/testcases/complete-run.pl index 52038b33..aa32557d 100755 --- a/testcases/complete-run.pl +++ b/testcases/complete-run.pl @@ -33,15 +33,6 @@ use IO::Socket::UNIX; # core use POSIX; # core use AnyEvent::Handle; -# open a file so that we get file descriptor 3. we will later close it in the -# child and dup() the listening socket file descriptor to 3 to pass it to i3 -open(my $reserved, '<', '/dev/null'); -if (fileno($reserved) != 3) { - warn "Socket file descriptor is not 3."; - warn "Please don't start this script within a subshell of vim or something."; - exit 1; -} - # install a dummy CHLD handler to overwrite the CHLD handler of AnyEvent / EV # XXX: we could maybe also use a different loop than the default loop in EV? $SIG{CHLD} = sub { @@ -165,7 +156,7 @@ sub take_job { $ENV{DISPLAY} = $display; $^F = 3; - close($reserved); + POSIX::close(3); POSIX::dup2(fileno($socket), 3); # now execute i3 From aa65b721b889679f69fab62bfc49387b4da1678f Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Tue, 4 Oct 2011 20:03:08 +0100 Subject: [PATCH 02/12] tests: eliminate dependency on the DateTime module by using POSIX::strftime --- testcases/complete-run.pl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/testcases/complete-run.pl b/testcases/complete-run.pl index aa32557d..04130ec8 100755 --- a/testcases/complete-run.pl +++ b/testcases/complete-run.pl @@ -16,7 +16,6 @@ use AnyEvent; use IO::Scalar; # not in core :\ use File::Temp qw(tempfile tempdir); use v5.10; -use DateTime; use Data::Dumper; use Cwd qw(abs_path); use Proc::Background; @@ -86,7 +85,7 @@ my @testfiles = @ARGV; # 2: create an output directory for this test-run my $outdir = "testsuite-"; -$outdir .= DateTime->now->strftime("%Y-%m-%d-%H-%M-%S-"); +$outdir .= POSIX::strftime("%Y-%m-%d-%H-%M-%S-", localtime()); $outdir .= `git describe --tags`; chomp($outdir); mkdir($outdir) or die "Could not create $outdir"; From 53121c746c8fab42d5fedbca2cc536210730feae Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Tue, 4 Oct 2011 20:05:12 +0100 Subject: [PATCH 03/12] tests: remove unused dependency Proc::Background from complete-run --- testcases/complete-run.pl | 1 - 1 file changed, 1 deletion(-) diff --git a/testcases/complete-run.pl b/testcases/complete-run.pl index 04130ec8..681119d3 100755 --- a/testcases/complete-run.pl +++ b/testcases/complete-run.pl @@ -18,7 +18,6 @@ use File::Temp qw(tempfile tempdir); use v5.10; use Data::Dumper; use Cwd qw(abs_path); -use Proc::Background; use TAP::Harness; use TAP::Parser; use TAP::Parser::Aggregator; From a94ec5ee4e0dd25c403ca854d227bd5df817071e Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Tue, 4 Oct 2011 20:10:11 +0100 Subject: [PATCH 04/12] tests: re-order dependencies in complete-run, make clear which are shipped with Perl --- testcases/complete-run.pl | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/testcases/complete-run.pl b/testcases/complete-run.pl index 681119d3..763a4f92 100755 --- a/testcases/complete-run.pl +++ b/testcases/complete-run.pl @@ -11,25 +11,26 @@ use strict; use warnings; -use EV; -use AnyEvent; -use IO::Scalar; # not in core :\ -use File::Temp qw(tempfile tempdir); use v5.10; -use Data::Dumper; +# the following are modules which ship with Perl (>= 5.10): use Cwd qw(abs_path); +use File::Basename qw(basename); +use File::Temp qw(tempfile tempdir); +use Getopt::Long; +use IO::Socket::UNIX; +use POSIX; +use Time::HiRes qw(sleep gettimeofday tv_interval); use TAP::Harness; use TAP::Parser; use TAP::Parser::Aggregator; -use File::Basename qw(basename); -use AnyEvent::I3 qw(:all); -use Try::Tiny; -use Getopt::Long; -use Time::HiRes qw(sleep gettimeofday tv_interval); -use X11::XCB; -use IO::Socket::UNIX; # core -use POSIX; # core +# the following modules are not shipped with Perl +use EV; +use AnyEvent; use AnyEvent::Handle; +use AnyEvent::I3 qw(:all); +use IO::Scalar; # not in core :\ +use Try::Tiny; # not in core +use X11::XCB; # install a dummy CHLD handler to overwrite the CHLD handler of AnyEvent / EV # XXX: we could maybe also use a different loop than the default loop in EV? From 6c7c4d52d09f1fd4e461f9325cafb3a69554470d Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Tue, 4 Oct 2011 20:55:29 +0100 Subject: [PATCH 05/12] tests: Refactor the socket activation into lib/SocketActivation.pm --- testcases/complete-run.pl | 71 ++++------------------ testcases/lib/SocketActivation.pm | 99 +++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 59 deletions(-) create mode 100644 testcases/lib/SocketActivation.pm diff --git a/testcases/complete-run.pl b/testcases/complete-run.pl index 763a4f92..d427d70a 100755 --- a/testcases/complete-run.pl +++ b/testcases/complete-run.pl @@ -23,6 +23,9 @@ use Time::HiRes qw(sleep gettimeofday tv_interval); use TAP::Harness; use TAP::Parser; use TAP::Parser::Aggregator; +# these are shipped with the testsuite +use lib qw(lib); +use SocketActivation; # the following modules are not shipped with Perl use EV; use AnyEvent; @@ -131,73 +134,23 @@ sub take_job { my $activate_cv = AnyEvent->condvar; my $time_before_start = [gettimeofday]; - my $start_i3 = sub { - # remove the old unix socket - unlink("/tmp/nested-$display-activation"); - # pass all file descriptors up to three to the children. - # we need to set this flag before opening the socket. - open(my $fdtest, '<', '/dev/null'); - $^F = fileno($fdtest); - close($fdtest); - my $socket = IO::Socket::UNIX->new( - Listen => 1, - Local => "/tmp/nested-$display-activation", + my $pid; + if (!$dont_start) { + $pid = activate_i3( + unix_socket_path => "/tmp/nested-$display-activation", + display => $display, + configfile => $tmpfile, + logpath => $logpath, + cv => $activate_cv ); - my $pid = fork; - if (!defined($pid)) { - die "could not fork()"; - } - if ($pid == 0) { - $ENV{LISTEN_PID} = $$; - $ENV{LISTEN_FDS} = 1; - $ENV{DISPLAY} = $display; - $^F = 3; - - POSIX::close(3); - POSIX::dup2(fileno($socket), 3); - - # now execute i3 - my $i3cmd = abs_path("../i3") . " -V -d all --disable-signalhandler"; - my $cmd = "exec $i3cmd -c $tmpfile >$logpath 2>&1"; - exec "/bin/sh", '-c', $cmd; - - # if we are still here, i3 could not be found or exec failed. bail out. - exit 1; - } - my $child_watcher; $child_watcher = AnyEvent->child(pid => $pid, cb => sub { say "child died. pid = $pid"; undef $child_watcher; }); - - # close the socket, the child process should be the only one which keeps a file - # descriptor on the listening socket. - $socket->close; - - # We now connect (will succeed immediately) and send a request afterwards. - # As soon as the reply is there, i3 is considered ready. - my $cl = IO::Socket::UNIX->new(Peer => "/tmp/nested-$display-activation"); - my $hdl; - $hdl = AnyEvent::Handle->new(fh => $cl, on_error => sub { $activate_cv->send(0) }); - - # send a get_tree message without payload - $hdl->push_write('i3-ipc' . pack("LL", 0, 4)); - - # wait for the reply - $hdl->push_read(chunk => 1, => sub { - my ($h, $line) = @_; - $activate_cv->send(1); - undef $hdl; - }); - - return $pid; - }; - - my $pid; - $pid = $start_i3->() unless $dont_start; + } my $kill_i3 = sub { # Don’t bother killing i3 when we haven’t started it diff --git a/testcases/lib/SocketActivation.pm b/testcases/lib/SocketActivation.pm new file mode 100644 index 00000000..92e514d5 --- /dev/null +++ b/testcases/lib/SocketActivation.pm @@ -0,0 +1,99 @@ +package SocketActivation; +# vim:ts=4:sw=4:expandtab + +use IO::Socket::UNIX; # core +use Cwd qw(abs_path); # core +use POSIX; # core +use AnyEvent::Handle; # not core +use Exporter 'import'; +use v5.10; + +our @EXPORT = qw(activate_i3); + +# +# Starts i3 using socket activation. Creates a listening socket (with bind + +# listen) which is then passed to i3, who in turn calls accept and handles the +# requests. +# +# Since the kernel buffers the connect, the parent process can connect to the +# socket immediately after forking. It then sends a request and waits until it +# gets an answer. Obviously, i3 has to be initialized to actually answer the +# request. +# +# This way, we can wait *precisely* the amount of time which i3 waits to get +# ready, which is a *HUGE* speed gain (and a lot more robust) in comparison to +# using sleep() with a fixed amount of time. +# +# unix_socket_path: Location of the socket to use for the activation +# display: X11 $ENV{DISPLAY} +# configfile: path to the configuration file to use +# logpath: path to the logfile to which i3 will append +# cv: an AnyEvent->condvar which will be triggered once i3 is ready +# +sub activate_i3 { + my %args = @_; + + # remove the old unix socket + unlink($args{unix_socket_path}); + + # pass all file descriptors up to three to the children. + # we need to set this flag before opening the socket. + open(my $fdtest, '<', '/dev/null'); + $^F = fileno($fdtest); + close($fdtest); + my $socket = IO::Socket::UNIX->new( + Listen => 1, + Local => $args{unix_socket_path}, + ); + + my $pid = fork; + if (!defined($pid)) { + die "could not fork()"; + } + if ($pid == 0) { + $ENV{LISTEN_PID} = $$; + $ENV{LISTEN_FDS} = 1; + $ENV{DISPLAY} = $args{display}; + $^F = 3; + + POSIX::close(3); + POSIX::dup2(fileno($socket), 3); + + # now execute i3 + my $i3cmd = abs_path("../i3") . " -V -d all --disable-signalhandler"; + my $cmd = "exec $i3cmd -c $args{configfile} >$args{logpath} 2>&1"; + exec "/bin/sh", '-c', $cmd; + + # if we are still here, i3 could not be found or exec failed. bail out. + exit 1; + } + + # close the socket, the child process should be the only one which keeps a file + # descriptor on the listening socket. + $socket->close; + + # We now connect (will succeed immediately) and send a request afterwards. + # As soon as the reply is there, i3 is considered ready. + my $cl = IO::Socket::UNIX->new(Peer => $args{unix_socket_path}); + my $hdl; + $hdl = AnyEvent::Handle->new( + fh => $cl, + on_error => sub { + $hdl->destroy; + $args{cv}->send(0); + }); + + # send a get_tree message without payload + $hdl->push_write('i3-ipc' . pack("LL", 0, 4)); + + # wait for the reply + $hdl->push_read(chunk => 1, => sub { + my ($h, $line) = @_; + $args{cv}->send(1); + undef $hdl; + }); + + return $pid; +} + +1 From c8d42fbabed90f2d416500821b880a733e366705 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Tue, 4 Oct 2011 23:31:06 +0100 Subject: [PATCH 06/12] tests: SocketActivation: only close() and dup2() if fileno(socket) != 3 --- testcases/lib/SocketActivation.pm | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/testcases/lib/SocketActivation.pm b/testcases/lib/SocketActivation.pm index 92e514d5..70bbec05 100644 --- a/testcases/lib/SocketActivation.pm +++ b/testcases/lib/SocketActivation.pm @@ -56,8 +56,12 @@ sub activate_i3 { $ENV{DISPLAY} = $args{display}; $^F = 3; - POSIX::close(3); - POSIX::dup2(fileno($socket), 3); + # If the socket does not use file descriptor 3 by chance already, we + # close fd 3 and dup2() the socket to 3. + if (fileno($socket) != 3) { + POSIX::close(3); + POSIX::dup2(fileno($socket), 3); + } # now execute i3 my $i3cmd = abs_path("../i3") . " -V -d all --disable-signalhandler"; From bf33c8d7c938585edb98ff6ff6715ffb2fa04a58 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Tue, 4 Oct 2011 23:31:33 +0100 Subject: [PATCH 07/12] tests: SocketActivation: append to the logfile, more comments --- testcases/lib/SocketActivation.pm | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/testcases/lib/SocketActivation.pm b/testcases/lib/SocketActivation.pm index 70bbec05..ef182012 100644 --- a/testcases/lib/SocketActivation.pm +++ b/testcases/lib/SocketActivation.pm @@ -54,6 +54,8 @@ sub activate_i3 { $ENV{LISTEN_PID} = $$; $ENV{LISTEN_FDS} = 1; $ENV{DISPLAY} = $args{display}; + # Only pass file descriptors 0 (stdin), 1 (stdout), 2 (stderr) and + # 3 (socket) to the child. $^F = 3; # If the socket does not use file descriptor 3 by chance already, we @@ -63,9 +65,15 @@ sub activate_i3 { POSIX::dup2(fileno($socket), 3); } - # now execute i3 + # Construct the command to launch i3. Use maximum debug level, disable + # the interactive signalhandler to make it crash immediately instead. my $i3cmd = abs_path("../i3") . " -V -d all --disable-signalhandler"; - my $cmd = "exec $i3cmd -c $args{configfile} >$args{logpath} 2>&1"; + + # Append to $args{logpath} instead of overwriting because i3 might be + # run multiple times in one testcase. + my $cmd = "exec $i3cmd -c $args{configfile} >>$args{logpath} 2>&1"; + + # We need to use the shell due to using output redirections. exec "/bin/sh", '-c', $cmd; # if we are still here, i3 could not be found or exec failed. bail out. From 8d9b4c3c04365ffb53fe43a28022651e64dc103b Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Tue, 4 Oct 2011 23:33:38 +0100 Subject: [PATCH 08/12] tests: launch_with_config: use socket activation --- testcases/complete-run.pl | 2 +- testcases/t/lib/i3test.pm | 26 +++++++++++++++++--------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/testcases/complete-run.pl b/testcases/complete-run.pl index d427d70a..322c23f2 100755 --- a/testcases/complete-run.pl +++ b/testcases/complete-run.pl @@ -188,7 +188,7 @@ sub take_job { my $output; my $parser = TAP::Parser->new({ - exec => [ 'sh', '-c', qq|DISPLAY=$display LOGPATH="$logpath" /usr/bin/perl -It/lib $test| ], + exec => [ 'sh', '-c', qq|DISPLAY=$display LOGPATH="$logpath" /usr/bin/perl -It/lib -Ilib $test| ], spool => IO::Scalar->new(\$output), merge => 1, }); diff --git a/testcases/t/lib/i3test.pm b/testcases/t/lib/i3test.pm index c890693c..14ec8d32 100644 --- a/testcases/t/lib/i3test.pm +++ b/testcases/t/lib/i3test.pm @@ -14,6 +14,7 @@ use Time::HiRes qw(sleep); use Try::Tiny; use Cwd qw(abs_path); use Proc::Background; +use SocketActivation; use v5.10; @@ -414,7 +415,9 @@ sub get_socket_path { # complete-run.pl that it should not create an instance of i3 # sub launch_with_config { - my ($config) = @_; + my ($config, $dont_add_socket_path) = @_; + + $dont_add_socket_path //= 0; if (!defined($tmp_socket_path)) { $tmp_socket_path = File::Temp::tempnam('/tmp', 'i3-test-socket-'); @@ -422,20 +425,25 @@ sub launch_with_config { my ($fh, $tmpfile) = tempfile('i3-test-config-XXXXX', UNLINK => 1); say $fh $config; - say $fh "ipc-socket $tmp_socket_path"; + say $fh "ipc-socket $tmp_socket_path" unless $dont_add_socket_path; close($fh); - # Use $ENV{LOGPATH}, gets set in complete-run.pl. We append instead of - # overwrite because there might be multiple instances of i3 running during - # one test case. - my $i3cmd = "exec " . abs_path("../i3") . " -V -d all --disable-signalhandler -c $tmpfile >>$ENV{LOGPATH} 2>&1"; - my $process = Proc::Background->new($i3cmd); - sleep 1.25; + my $cv = AnyEvent->condvar; + my $pid = activate_i3( + unix_socket_path => "$tmp_socket_path-activation", + display => $ENV{DISPLAY}, + configfile => $tmpfile, + logpath => $ENV{LOGPATH}, + cv => $cv, + ); + + # blockingly wait until i3 is ready + $cv->recv; # force update of the cached socket path in lib/i3test get_socket_path(0); - return $process; + return $pid; } 1 From 4e1d50fa3a2abd9b4ed4f295f42dfb0332bbfa72 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Tue, 4 Oct 2011 23:34:23 +0100 Subject: [PATCH 09/12] tests: Convert all testcases to use the new launch_with_config API It now returns a pid directly, not a Proc::Background object. --- testcases/t/59-socketpaths.t | 51 +++++++++++---------------- testcases/t/65-for_window.t | 41 +++++++++++---------- testcases/t/66-assign.t | 28 ++++++++------- testcases/t/67-workspace_layout.t | 8 ++--- testcases/t/70-force_focus_wrapping.t | 8 ++--- testcases/t/72-start-on-named-ws.t | 12 +++---- testcases/t/73-regress-focus-assign.t | 4 +-- testcases/t/74-border-config.t | 16 ++++----- 8 files changed, 83 insertions(+), 85 deletions(-) diff --git a/testcases/t/59-socketpaths.t b/testcases/t/59-socketpaths.t index 36c99087..7587aeab 100644 --- a/testcases/t/59-socketpaths.t +++ b/testcases/t/59-socketpaths.t @@ -18,26 +18,21 @@ my $i3_path = abs_path("../i3"); # default case: socket will be created in /tmp/i3-/ipc-socket. ##################################################################### -my ($fh, $tmpfile) = tempfile('/tmp/i3-test-config.XXXXXX', UNLINK => 1); -say $fh "# i3 config file (v4)"; -say $fh "font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1"; -close($fh); +my $config = </dev/null 2>/dev/null"; -my $process = Proc::Background->new($i3cmd); -sleep 1; - -diag("pid = " . $process->pid); +# ensure XDG_RUNTIME_DIR is not set +delete $ENV{XDG_RUNTIME_DIR}; +my $pid = launch_with_config($config, 1); my $folder = "/tmp/i3-" . getpwuid(getuid()); ok(-d $folder, "folder $folder exists"); -my $socketpath = "$folder/ipc-socket." . $process->pid; +my $socketpath = "$folder/ipc-socket." . $pid; ok(-S $socketpath, "file $socketpath exists and is a socket"); -exit_gracefully($process->pid, $socketpath); - -sleep 0.25; +exit_gracefully($pid); ##################################################################### # XDG_RUNTIME_DIR case: socket gets created in $XDG_RUNTIME_DIR/i3/ipc-socket. @@ -47,17 +42,15 @@ my $rtdir = tempdir(CLEANUP => 1); ok(! -e "$rtdir/i3", "$rtdir/i3 does not exist yet"); -$i3cmd = "export XDG_RUNTIME_DIR=$rtdir; exec " . abs_path("../i3") . " -V -d all --disable-signalhandler -c $tmpfile >/dev/null 2>/dev/null"; -$process = Proc::Background->new($i3cmd); -sleep 1; +$ENV{XDG_RUNTIME_DIR} = $rtdir; + +$pid = launch_with_config($config, 1); ok(-d "$rtdir/i3", "$rtdir/i3 exists and is a directory"); -$socketpath = "$rtdir/i3/ipc-socket." . $process->pid; +$socketpath = "$rtdir/i3/ipc-socket." . $pid; ok(-S $socketpath, "file $socketpath exists and is a socket"); -exit_gracefully($process->pid, $socketpath); - -sleep 0.25; +exit_gracefully($pid); ##################################################################### # configuration file case: socket gets placed whereever we specify @@ -67,18 +60,16 @@ my $tmpdir = tempdir(CLEANUP => 1); $socketpath = $tmpdir . "/config.sock"; ok(! -e $socketpath, "$socketpath does not exist yet"); -($fh, $tmpfile) = tempfile('/tmp/i3-test-config.XXXXXX', UNLINK => 1); -say $fh "# i3 config file (v4)"; -say $fh "font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1"; -say $fh "ipc-socket $socketpath"; -close($fh); +$config = </dev/null 2>/dev/null"; -$process = Proc::Background->new($i3cmd); -sleep 1; +$pid = launch_with_config($config, 1); ok(-S $socketpath, "file $socketpath exists and is a socket"); -exit_gracefully($process->pid, $socketpath); +exit_gracefully($pid); done_testing; diff --git a/testcases/t/65-for_window.t b/testcases/t/65-for_window.t index 36a20ea9..cc100132 100644 --- a/testcases/t/65-for_window.t +++ b/testcases/t/65-for_window.t @@ -24,7 +24,7 @@ for_window [class="borderless"] border none for_window [title="special borderless title"] border none EOT -my $process = launch_with_config($config); +my $pid = launch_with_config($config); my $tmp = fresh_workspace; @@ -93,7 +93,7 @@ wait_for_unmap $x; @content = @{get_ws_content($tmp)}; cmp_ok(@content, '==', 0, 'no more nodes'); -exit_gracefully($process->pid); +exit_gracefully($pid); ############################################################## # 2: match on the title, check if for_window is really executed @@ -107,7 +107,7 @@ for_window [class="borderless"] border none for_window [title="special borderless title"] border none EOT -$process = launch_with_config($config); +$pid = launch_with_config($config); $tmp = fresh_workspace; @@ -152,7 +152,7 @@ wait_for_unmap $x; @content = @{get_ws_content($tmp)}; cmp_ok(@content, '==', 0, 'no more nodes'); -exit_gracefully($process->pid); +exit_gracefully($pid); ############################################################## # 3: match on the title, set border style *and* a mark @@ -167,7 +167,7 @@ for_window [title="special borderless title"] border none for_window [title="special mark title"] border none, mark bleh EOT -$process = launch_with_config($config); +$pid = launch_with_config($config); $tmp = fresh_workspace; @@ -199,7 +199,7 @@ cmd qq|[con_mark="bleh"] focus|; @content = @{get_ws_content($tmp)}; ok($content[0]->{focused}, 'first node focused'); -exit_gracefully($process->pid); +exit_gracefully($pid); ############################################################## # 4: multiple criteria for the for_window command @@ -211,7 +211,7 @@ font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 for_window [class="borderless" title="usethis"] border none EOT -$process = launch_with_config($config); +$pid = launch_with_config($config); $tmp = fresh_workspace; @@ -233,12 +233,15 @@ wait_for_map $x; cmp_ok(@content, '==', 1, 'one node on this workspace now'); is($content[0]->{border}, 'none', 'no border'); -$window->unmap; +cmd 'kill'; wait_for_unmap $x; +$window->destroy; @content = @{get_ws_content($tmp)}; cmp_ok(@content, '==', 0, 'no nodes on this workspace now'); +$window->_create; + set_wm_class($window->id, 'borderless', 'borderless'); $window->name('notthis'); $window->map; @@ -249,7 +252,7 @@ cmp_ok(@content, '==', 1, 'one node on this workspace now'); is($content[0]->{border}, 'normal', 'no border'); -exit_gracefully($process->pid); +exit_gracefully($pid); ############################################################## # 5: check that a class criterion does not match the instance @@ -261,7 +264,7 @@ font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 for_window [class="foo"] border 1pixel EOT -$process = launch_with_config($config); +$pid = launch_with_config($config); $tmp = fresh_workspace; @@ -283,7 +286,7 @@ wait_for_map $x; cmp_ok(@content, '==', 1, 'one node on this workspace now'); is($content[0]->{border}, 'normal', 'normal border, not matched'); -exit_gracefully($process->pid); +exit_gracefully($pid); ############################################################## # 6: check that the 'instance' criterion works @@ -296,7 +299,7 @@ for_window [class="foo"] border 1pixel for_window [instance="foo"] border none EOT -$process = launch_with_config($config); +$pid = launch_with_config($config); $tmp = fresh_workspace; @@ -318,7 +321,7 @@ wait_for_map $x; cmp_ok(@content, '==', 1, 'one node on this workspace now'); is($content[0]->{border}, 'none', 'no border'); -exit_gracefully($process->pid); +exit_gracefully($pid); ############################################################## # 7: check that invalid criteria don’t end up matching all windows @@ -333,7 +336,7 @@ font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 for_window [id="asdf"] border none EOT -$process = launch_with_config($config); +$pid = launch_with_config($config); $tmp = fresh_workspace; @@ -355,7 +358,7 @@ wait_for_map $x; cmp_ok(@content, '==', 1, 'one node on this workspace now'); is($content[0]->{border}, 'normal', 'normal border'); -exit_gracefully($process->pid); +exit_gracefully($pid); ############################################################## # 8: check that the role criterion works properly @@ -370,7 +373,7 @@ font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 for_window [window_role="i3test"] border none EOT -$process = launch_with_config($config); +$pid = launch_with_config($config); $tmp = fresh_workspace; @@ -403,7 +406,7 @@ wait_for_map $x; cmp_ok(@content, '==', 1, 'one node on this workspace now'); is($content[0]->{border}, 'none', 'no border (window_role)'); -exit_gracefully($process->pid); +exit_gracefully($pid); ############################################################## # 9: another test for the window_role, but this time it changes @@ -419,7 +422,7 @@ font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 for_window [window_role="i3test"] border none EOT -$process = launch_with_config($config); +$pid = launch_with_config($config); $tmp = fresh_workspace; @@ -460,7 +463,7 @@ sync_with_i3 $x; cmp_ok(@content, '==', 1, 'one node on this workspace now'); is($content[0]->{border}, 'none', 'no border (window_role 2)'); -exit_gracefully($process->pid); +exit_gracefully($pid); done_testing; diff --git a/testcases/t/66-assign.t b/testcases/t/66-assign.t index cc41b7af..4844f5b5 100644 --- a/testcases/t/66-assign.t +++ b/testcases/t/66-assign.t @@ -40,7 +40,7 @@ my $config = <pid); +exit_gracefully($pid); $window->destroy; @@ -76,7 +76,7 @@ font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 assign "special" → targetws EOT -$process = launch_with_config($config); +$pid = launch_with_config($config); $tmp = fresh_workspace; @@ -102,7 +102,7 @@ ok("targetws" ~~ @{get_workspace_names()}, 'targetws exists'); $window->destroy; -exit_gracefully($process->pid); +exit_gracefully($pid); sleep 0.25; @@ -111,7 +111,7 @@ sleep 0.25; # already, next to the existing node. ##################################################################### -$process = launch_with_config($config); +$pid = launch_with_config($config); # initialize the target workspace, then go to a fresh one ok(!("targetws" ~~ @{get_workspace_names()}), 'targetws does not exist yet'); @@ -144,7 +144,7 @@ sync_with_i3 $x; ok(@{get_ws_content($tmp)} == 0, 'still no containers'); ok(@{get_ws_content('targetws')} == 2, 'two containers on targetws'); -exit_gracefully($process->pid); +exit_gracefully($pid); ##################################################################### # start a window and see that it gets assigned to a workspace which has content @@ -157,7 +157,7 @@ font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 assign "special" → ~ EOT -$process = launch_with_config($config); +$pid = launch_with_config($config); $tmp = fresh_workspace; @@ -184,7 +184,7 @@ ok(@{$content->{floating_nodes}} == 1, 'one floating con'); $window->destroy; -exit_gracefully($process->pid); +exit_gracefully($pid); sleep 0.25; @@ -198,7 +198,7 @@ font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 assign "special" → ~ EOT -$process = launch_with_config($config); +$pid = launch_with_config($config); $tmp = fresh_workspace; @@ -225,7 +225,7 @@ ok(@{$content->{floating_nodes}} == 1, 'one floating con'); $window->destroy; -exit_gracefully($process->pid); +exit_gracefully($pid); sleep 0.25; @@ -241,7 +241,11 @@ font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 assign "special" → ~ EOT -$process = launch_with_config($config); +$pid = launch_with_config($config); + +# TODO: replace this with checking the process hierarchy +# XXX: give i3-nagbar some time to start up +sleep 1; $tmp = fresh_workspace; @@ -275,7 +279,7 @@ $window->destroy; does_i3_live; -exit_gracefully($process->pid); +exit_gracefully($pid); sleep 0.25; diff --git a/testcases/t/67-workspace_layout.t b/testcases/t/67-workspace_layout.t index 6ff3f15b..e4b18adf 100644 --- a/testcases/t/67-workspace_layout.t +++ b/testcases/t/67-workspace_layout.t @@ -21,7 +21,7 @@ my $config = <{layout}, 'stacked', 'layout not stacked'); isnt($content[1]->{layout}, 'stacked', 'layout not stacked'); -exit_gracefully($process->pid); +exit_gracefully($pid); ##################################################################### # 2: set workspace_layout stacked, check that when opening two cons, @@ -50,7 +50,7 @@ font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 workspace_layout stacked EOT -$process = launch_with_config($config); +$pid = launch_with_config($config); $tmp = fresh_workspace; @@ -122,6 +122,6 @@ is($content[1]->{layout}, 'stacked', 'layout stacked'); is(@content, 1, 'one con on target workspace'); is($content[0]->{layout}, 'stacked', 'layout stacked'); -exit_gracefully($process->pid); +exit_gracefully($pid); done_testing; diff --git a/testcases/t/70-force_focus_wrapping.t b/testcases/t/70-force_focus_wrapping.t index 2aa5407d..8a990f23 100644 --- a/testcases/t/70-force_focus_wrapping.t +++ b/testcases/t/70-force_focus_wrapping.t @@ -19,7 +19,7 @@ my $config = <input_focus, $second->id, 'second window focused'); cmd 'focus right'; is($x->input_focus, $third->id, 'third window focused'); -exit_gracefully($process->pid); +exit_gracefully($pid); ##################################################################### # 2: test the wrapping behaviour with force_focus_wrapping @@ -60,7 +60,7 @@ font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 force_focus_wrapping true EOT -$process = launch_with_config($config); +$pid = launch_with_config($config); $tmp = fresh_workspace; @@ -92,6 +92,6 @@ is($x->input_focus, $second->id, 'second window focused'); cmd 'focus right'; is($x->input_focus, $first->id, 'first window focused'); -exit_gracefully($process->pid); +exit_gracefully($pid); done_testing; diff --git a/testcases/t/72-start-on-named-ws.t b/testcases/t/72-start-on-named-ws.t index 12661867..4493bf83 100644 --- a/testcases/t/72-start-on-named-ws.t +++ b/testcases/t/72-start-on-named-ws.t @@ -19,12 +19,12 @@ my $config = <pid); +exit_gracefully($pid); ############################################################## # 2: with named workspaces, i3 should start on the first named one @@ -37,12 +37,12 @@ font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 bindsym Mod1+1 workspace foobar EOT -$process = launch_with_config($config); +$pid = launch_with_config($config); my @names = @{get_workspace_names()}; cmp_deeply(\@names, [ 'foobar' ], 'i3 starts on named workspace foobar'); -exit_gracefully($process->pid); +exit_gracefully($pid); ############################################################## # 3: the same test as 2, but with a quoted workspace name @@ -55,11 +55,11 @@ font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 bindsym Mod1+1 workspace "foobar" EOT -$process = launch_with_config($config); +$pid = launch_with_config($config); my @names = @{get_workspace_names()}; cmp_deeply(\@names, [ 'foobar' ], 'i3 starts on named workspace foobar'); -exit_gracefully($process->pid); +exit_gracefully($pid); done_testing; diff --git a/testcases/t/73-regress-focus-assign.t b/testcases/t/73-regress-focus-assign.t index bab7c9ae..70414af3 100644 --- a/testcases/t/73-regress-focus-assign.t +++ b/testcases/t/73-regress-focus-assign.t @@ -42,7 +42,7 @@ font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 assign "special" → targetws EOT -my $process = launch_with_config($config); +my $pid = launch_with_config($config); my $tmp = fresh_workspace; @@ -88,7 +88,7 @@ ok(@{get_ws_content($tmp)} == 0, 'special window not on current workspace'); ok(@{get_ws_content('targetws')} == 1, 'special window on targetws'); ok(get_ws($tmp)->{focused}, 'current workspace still focused'); -exit_gracefully($process->pid); +exit_gracefully($pid); $window->destroy; diff --git a/testcases/t/74-border-config.t b/testcases/t/74-border-config.t index 617e37b9..cc1f5c90 100644 --- a/testcases/t/74-border-config.t +++ b/testcases/t/74-border-config.t @@ -19,7 +19,7 @@ my $config = <{border}, 'normal', 'border normal by default'); -exit_gracefully($process->pid); +exit_gracefully($pid); ##################################################################### # 2: check that new tiling windows start with '1pixel' border when @@ -45,7 +45,7 @@ font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 new_window 1pixel EOT -$process = launch_with_config($config); +$pid = launch_with_config($config); $tmp = fresh_workspace; @@ -57,7 +57,7 @@ $first = open_window($x); ok(@content == 1, 'one container opened'); is($content[0]->{border}, '1pixel', 'border normal by default'); -exit_gracefully($process->pid); +exit_gracefully($pid); ##################################################################### # 3: check that new floating windows start with 'normal' border unless @@ -69,7 +69,7 @@ $config = <{nodes}->[0]->{border}, 'normal', 'border normal by default'); -exit_gracefully($process->pid); +exit_gracefully($pid); ##################################################################### # 4: check that new floating windows start with '1pixel' border when @@ -97,7 +97,7 @@ font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 new_float 1pixel EOT -$process = launch_with_config($config); +$pid = launch_with_config($config); $tmp = fresh_workspace; @@ -111,6 +111,6 @@ ok(@floating == 1, 'one floating container opened'); $floatingcon = $floating[0]; is($floatingcon->{nodes}->[0]->{border}, '1pixel', 'border normal by default'); -exit_gracefully($process->pid); +exit_gracefully($pid); done_testing; From 359717970da030c1cf9efcb00d17e2c6814f95f5 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Tue, 4 Oct 2011 23:36:43 +0100 Subject: [PATCH 10/12] =?UTF-8?q?tests:=20don=E2=80=99t=20overwrite=20$tim?= =?UTF-8?q?eout,=20kill=20timer=20when=20done?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- testcases/t/lib/i3test.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/testcases/t/lib/i3test.pm b/testcases/t/lib/i3test.pm index 14ec8d32..9230c5ef 100644 --- a/testcases/t/lib/i3test.pm +++ b/testcases/t/lib/i3test.pm @@ -104,9 +104,10 @@ sub wait_for_event { }; # Trigger timeout after $timeout seconds (can be fractional) - my $timeout = AE::timer $timeout, 0, sub { warn "timeout"; $cv->send(0) }; + my $t = AE::timer $timeout, 0, sub { warn "timeout ($timeout secs)"; $cv->send(0) }; my $result = $cv->recv; + undef $t; return $result; } From 57484553e6bd9065443d06d85be28c16224aa501 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Tue, 4 Oct 2011 23:36:57 +0100 Subject: [PATCH 11/12] tests: use a lot higher timeouts This makes the tests more robust on a machine which is loaded. Also, it makes the tests run (significantly) longer if anything goes wrong. --- testcases/t/lib/i3test.pm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/testcases/t/lib/i3test.pm b/testcases/t/lib/i3test.pm index 9230c5ef..cf29d7b9 100644 --- a/testcases/t/lib/i3test.pm +++ b/testcases/t/lib/i3test.pm @@ -115,7 +115,7 @@ sub wait_for_event { # make sure to include 'structure_notify' in the window’s event_mask attribute sub wait_for_map { my ($x) = @_; - wait_for_event $x, 1, sub { $_[0]->{response_type} == MAP_NOTIFY }; + wait_for_event $x, 2, sub { $_[0]->{response_type} == MAP_NOTIFY }; } # Wrapper around wait_for_event which waits for UNMAP_NOTIFY. Also calls @@ -123,7 +123,7 @@ sub wait_for_map { # event. sub wait_for_unmap { my ($x) = @_; - wait_for_event $x, 1, sub { $_[0]->{response_type} == UNMAP_NOTIFY }; + wait_for_event $x, 2, sub { $_[0]->{response_type} == UNMAP_NOTIFY }; sync_with_i3($x); } @@ -325,7 +325,7 @@ sub sync_with_i3 { $_sync_window->map; - wait_for_event $x, 0.5, sub { $_[0]->{response_type} == MAP_NOTIFY }; + wait_for_event $x, 2, sub { $_[0]->{response_type} == MAP_NOTIFY }; } my $root = $x->get_root_window(); @@ -351,7 +351,7 @@ sub sync_with_i3 { $x->send_event(0, $root, EVENT_MASK_SUBSTRUCTURE_REDIRECT, $msg); # now wait until the reply is here - return wait_for_event $x, 1, sub { + return wait_for_event $x, 2, sub { my ($event) = @_; # TODO: const return 0 unless $event->{response_type} == 161; From bd33c09845d2069d11086f42d61efaba15d71f6d Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Tue, 4 Oct 2011 23:39:36 +0100 Subject: [PATCH 12/12] tests: move i3test.pm from t/lib to lib/ --- testcases/complete-run.pl | 2 +- testcases/{t => }/lib/i3test.pm | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename testcases/{t => }/lib/i3test.pm (100%) diff --git a/testcases/complete-run.pl b/testcases/complete-run.pl index 322c23f2..70bcc8c1 100755 --- a/testcases/complete-run.pl +++ b/testcases/complete-run.pl @@ -188,7 +188,7 @@ sub take_job { my $output; my $parser = TAP::Parser->new({ - exec => [ 'sh', '-c', qq|DISPLAY=$display LOGPATH="$logpath" /usr/bin/perl -It/lib -Ilib $test| ], + exec => [ 'sh', '-c', qq|DISPLAY=$display LOGPATH="$logpath" /usr/bin/perl -Ilib $test| ], spool => IO::Scalar->new(\$output), merge => 1, }); diff --git a/testcases/t/lib/i3test.pm b/testcases/lib/i3test.pm similarity index 100% rename from testcases/t/lib/i3test.pm rename to testcases/lib/i3test.pm