From d174ff16edc462a7fc44cb1372789bb06ddaa543 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sat, 24 Sep 2011 17:20:36 +0100 Subject: [PATCH] Add docs/testsuite --- docs/Makefile | 5 +- docs/i3-sync-working.dia | Bin 0 -> 2762 bytes docs/i3-sync-working.png | Bin 0 -> 25072 bytes docs/i3-sync.dia | Bin 0 -> 2208 bytes docs/i3-sync.png | Bin 0 -> 17308 bytes docs/testsuite | 446 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 450 insertions(+), 1 deletion(-) create mode 100644 docs/i3-sync-working.dia create mode 100644 docs/i3-sync-working.png create mode 100644 docs/i3-sync.dia create mode 100644 docs/i3-sync.png create mode 100644 docs/testsuite diff --git a/docs/Makefile b/docs/Makefile index 9d70243d..990bba87 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -1,5 +1,5 @@ -all: hacking-howto.html debugging.html userguide.html ipc.html multi-monitor.html wsbar.html refcard.pdf +all: hacking-howto.html debugging.html userguide.html ipc.html multi-monitor.html wsbar.html refcard.pdf testsuite.html hacking-howto.html: hacking-howto asciidoc -a toc -n $< @@ -10,6 +10,9 @@ debugging.html: debugging userguide.html: userguide asciidoc -a toc -n $< +testsuite.html: testsuite + asciidoc -a toc -n $< + ipc.html: ipc asciidoc -a toc -n $< diff --git a/docs/i3-sync-working.dia b/docs/i3-sync-working.dia new file mode 100644 index 0000000000000000000000000000000000000000..9f1c3bc8cae13895ca87b89239036f7f14c4718b GIT binary patch literal 2762 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 QXOB1k2e*BCJ%PCZ0H|wW!2kdN literal 0 HcmV?d00001 diff --git a/docs/i3-sync-working.png b/docs/i3-sync-working.png new file mode 100644 index 0000000000000000000000000000000000000000..dce44ac5ac4d2efe4d1d1751b499586613eca33f GIT binary patch literal 25072 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 literal 0 HcmV?d00001 diff --git a/docs/i3-sync.png b/docs/i3-sync.png new file mode 100644 index 0000000000000000000000000000000000000000..b64cce25959b1620084fc2214e35c2b7f9fb8a10 GIT binary patch literal 17308 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 literal 0 HcmV?d00001 diff --git a/docs/testsuite b/docs/testsuite new file mode 100644 index 00000000..7611499d --- /dev/null +++ b/docs/testsuite @@ -0,0 +1,446 @@ +i3 testsuite +============ +Michael Stapelberg +September 2011 + +This document explains how the i3 testsuite works, how to use it and how to +extend it. It is targeted at developers who not necessarily have been doing +testing before or have not been testing in Perl before. In general, the +testsuite is not of interest for end users. + + +== Introduction + +The i3 testsuite is a collection of files which contain testcases for various +i3 features. Some of them test if a certain workflow works correctly (moving +windows, focus behaviour, …). Others are regression tests and contain code +which previously made i3 crash or lead to unexpected behaviour. They then check +if i3 still runs (meaning it did not crash) and if it handled everything +correctly. + +The goal of having these tests is to automatically find problems and to +automatically get a feel for whether a change in the source code breaks any +existing feature. After every modification of the i3 sourcecode, the developer +should run the full testsuite. If one of the tests does not pass (but fails), +the corresponding problem should be fixed (or, in some cases, the testcase has +to be modified). For every bugreport, a testcase should be written to test the +correct behaviour. Initially, it will fail, but after fixing the bug, it will +pass. This ensures (or increases the chance) that bugs which have been fixed +once will never be found again. + +Also, when implementing a new feature, a testcase might be a good way to be +able to easily test if the feature is working correctly. Many developers will +test manually if everything works. Having a testcase not only helps you with +that, but it will also be useful for every future change. + +== Implementation + +For several reasons, the i3 testsuite has been implemented in Perl: + +1. Perl has a long tradition of testing. Every popular/bigger Perl module which + you can find on CPAN will not only come with documentation, but also with + tests. Therefore, the available infrastructure for tests is comprehensive. + See for example the excellent http://search.cpan.org/perldoc?Test::More + and the referenced http://search.cpan.org/perldoc?Test::Tutorial. + +2. Perl is widely available and has a well-working package infrastructure. +3. The author is familiar with Perl :). + +Please do not start programming language flamewars at this point. + +=== Mechanisms + +==== Script: complete-run + +The testcases are run by a script called +complete-run.pl+. It runs all +testcases by default, but you can be more specific and let it only run one or +more testcases. Also, it takes care of starting up a separate instance of i3 +with an appropriate configuration file and creates a folder for each run +containing the appropriate i3 logfile for each testcase. The latest folder can +always be found under the symlink +latest/+. It is recommended that you run the +tests on one or more separate X server instances (you can only start one window +manager per X session), for example using the provided Xdummy script. ++complete-run.pl+ takes one or more X11 display specifications and parallelizes +the testcases appropriately: + +.Example invocation of complete-run.pl+ +--------------------------------------- +$ cd ~/i3/testcases + +# start two dummy X11 instances in the background +$ ./Xdummy :1 & +$ ./Xdummy :2 & + +$ ./complete-run.pl -d :1,:2 +# output omitted because it is very long +All tests successful. +Files=78, Tests=734, 27 wallclock secs ( 0.38 usr 0.48 sys + 17.65 cusr 3.21 csys = 21.72 CPU) +Result: PASS + +$ ./complete-run.pl -d :1 t/04-floating.t +[:3] i3 startup: took 0.07s, status = 1 +[:3] Running t/04-floating.t with logfile testsuite-2011-09-24-16-06-04-4.0.2-226-g1eb011a/i3-log-for-04-floating.t +[:3] t/04-floating.t finished +[:3] killing i3 +output for t/04-floating.t: +ok 1 - use X11::XCB::Window; +ok 2 - The object isa X11::XCB::Window +ok 3 - Window is mapped +ok 4 - i3 raised the width to 75 +ok 5 - i3 raised the height to 50 +ok 6 - i3 did not map it to (0x0) +ok 7 - The object isa X11::XCB::Window +ok 8 - i3 let the width at 80 +ok 9 - i3 let the height at 90 +ok 10 - i3 mapped it to x=1 +ok 11 - i3 mapped it to y=18 +ok 12 - The object isa X11::XCB::Window +ok 13 - i3 let the width at 80 +ok 14 - i3 let the height at 90 +1..14 + +All tests successful. +Files=1, Tests=14, 0 wallclock secs ( 0.01 usr 0.00 sys + 0.19 cusr 0.03 csys = 0.23 CPU) +Result: PASS + +$ less latest/i3-log-for-04-floating.t +---------------------------------------- + +==== IPC interface + +The testsuite makes extensive use of the IPC (Inter-Process Communication) +interface which i3 provides. It is used for the startup process of i3, for +terminating it cleanly and (most importantly) for modifying and getting the +current state (layout tree). + +See [http://i3wm.org/docs/ipc.html] for documentation on the IPC interface. + +==== X11::XCB + +In order to open new windows, change attributes, get events, etc., the +testsuite uses X11::XCB, a new (and quite specific to i3 at the moment) Perl +module which uses the XCB protocol description to generate Perl bindings to +X11. They work in a very similar way to libxcb (which i3 uses) and provide +relatively high-level interfaces (objects such as +X11::XCB::Window+) aswell as +access to the low-level interface, which is very useful when testing a window +manager. + +=== Filesystem structure + +In the git root of i3, the testcases live in the folder +testcases+. This +folder contains the +complete-run.pl+ and +Xdummy+ scripts and a base +configuration file which will be used for the tests. The different testcases +themselve can be found in the conventionally named subfolder +t+: + +.Filesystem structure +-------------------------------------------- +├── testcases +│   ├── complete-run.pl +│   ├── i3-test.config +│   ├── t +│   │   ├── 00-load.t +│   │   ├── 01-tile.t +│   │   ├── 02-fullscreen.t +│   │   ├── ... +│   │   ├── omitted for brevity +│   │   ├── ... +│   │   ├── 74-regress-focus-toggle.t +│   │   └── lib +│   │   └── i3test.pm +│   └── Xdummy +-------------------------------------------- + +== Anatomy of a testcase + +Learning by example is definitely a good strategy when you are wondering how to +write a testcase. Let's take +t/11-goto.t+ as an easy example and go through it +step by step: + +.t/11-goto.t: Boilerplate +---------------------- +#!perl +# vim:ts=4:sw=4:expandtab + +use i3test; +use File::Temp; + +my $x = X11::XCB::Connection->new; +----------------------- + +This is what we call boilerplate. It exists at the top of every test file (to +some extent). The first line is the shebang, which specifies that this file is +a Perl script. The second line contains VIM specific settings on how to +edit/format this file (use spaces instead of tabs, indent using 4 spaces). +Afterwards, the +i3test+ module is used. This module contains i3 testsuite +specific functions which you are strongly encouraged to use. They make writing +testcases a lot easier and will make it easier for other people to read your +tests. + +The next line uses the +File::Temp+ module. This is specific to this testcase, +because it needs to generate a temporary name during the test. Many testcases +use only the +i3test+ module. + +The last line opens a connection to X11. You might or might not need this in +your testcase, depending on whether you are going to open windows (etc.) or +only use i3 commands. + +.t/11-goto.t: Setup +---------------------- +my $tmp = fresh_workspace; + +cmd 'split h'; +---------------------- + +The first line calls i3test's +fresh_workspace+ function which looks for a +currently unused workspace, switches to it, and returns its name. The variable ++$tmp+ will end up having a value such as +"/tmp/87kBVcHbA9"+. Note that this +is not (necessarily) a valid path, it's just a random workspace name. + +So, now that we are on a new workspace, we ensure that the workspace uses +horizontal orientation by issuing the +split h+ command (see the i3 User's +Guide for a list of commands). This is not strictly necessary, but good style. +In general, the +cmd+ function executes the specified i3 command by using the +IPC interface and returns once i3 acknowledged the command. + +.t/11-goto.t: Setup +---------------------- +##################################################################### +# Create two windows and make sure focus switching works +##################################################################### + +my $top = open_window($x); +my $mid = open_window($x); +my $bottom = open_window($x); +---------------------- + +In every major section of a testcase, you should put a comment like the one +above. This makes it immediately clear how the file is structured. + +The +open_window+ function opens a standard window, which will then be put into +tiling mode by i3. If you want a floating window, use the ++open_floating_window+ function. These functions accept the same parameters as ++X11::XCB::Window->new+, see the i3test documentation at TODO. + +.t/11-goto.t: Helper function +---------------------- +# +# Returns the input focus after sending the given command to i3 via IPC +# end sleeping for half a second to make sure i3 reacted +# +sub focus_after { + my $msg = shift; + + cmd $msg; + sync_with_i3 $x; + return $x->input_focus; +} +---------------------- + +This section defines a helper function which will be used over and over in this +testcase. If you have code which gets executed more than once or twice +(depending on the length of your test, use your best judgement), please put it +in a function. Tests should be short, concise and clear. + +The +focus_after+ function executes a command and returns the X11 focus after +the command was executed. The +sync_with_i3+ command makes sure that i3 could +push its state to X11. See <> to learn how this works exactly. + +.t/11-goto.t: Test assumptions +---------------------- +$focus = $x->input_focus; +is($focus, $bottom->id, "Latest window focused"); + +$focus = focus_after('focus left'); +is($focus, $mid->id, "Middle window focused"); +---------------------- + +Now, we run the first two real tests. They use +Test::More+'s +is+ function, +which compares two values and prints the differences if they are not the same. +After the arguments, we supply a short comment to indicate what we are testing +here. This makes it vastly more easy for the developer to spot which testcase +is the problem in case one fails. + +The first test checks that the most recently opened window is focused. +Afterwards, the command +focus left+ is issued and it is verified that the +middle window now has focus. + +Note that this is not a comprehensive test of the +focus+ command -- we would +have to test wrapping, focus when using a more complex layout, focusing the +parent/child containers, etc. But that is not the point of this testcase. +Instead, we just want to know if +$x->input_focus+ corresponds with what we are +expecting. If not, something is completely wrong with the test environment and +this trivial test will fail. + +.t/11-goto.t: Test that the feature does not work (yet) +---------------------- +##################################################################### +# Now goto a mark which does not exist +##################################################################### + +my $random_mark = mktemp('mark.XXXXXX'); + +$focus = focus_after(qq|[con_mark="$random_mark"] focus|); +is($focus, $mid->id, "focus unchanged"); +---------------------- + +In this new major section, a random mark (mark is an identifier for a window, +see "VIM-like marks" in the i3 User’s Guide) will be generated. Afterwards, we +test that trying to focus that mark will not do anything. This is important: Do +not only test that using a feature has the expected outcome, but also test that +using it without properly initializing it does no harm. This command could for +example have changed focus anyways (a bug) or crash i3 (obviously a bug). + +.t/11-goto.t: Test that the feature does work +---------------------- +cmd "mark $random_mark"; + +$focus = focus_after('focus left'); +is($focus, $top->id, "Top window focused"); + +$focus = focus_after(qq|[con_mark="$random_mark"] focus|); +is($focus, $mid->id, "goto worked"); +---------------------- + +Remember: Focus was on the middle window (we verified that earlier in "Test +assumptions"). We now mark the middle window with our randomly generated mark. +Afterwards, we switch focus away from the middle window to be able to tell if +focusing it via its mark will work. If it does work (next test), the goto +command works. + +.t/11-goto.t: Test corner case +---------------------- +# check that we can specify multiple criteria + +$focus = focus_after('focus left'); +is($focus, $top->id, "Top window focused"); + +$focus = focus_after(qq|[con_mark="$random_mark" con_mark="$random_mark"] focus|); +is($focus, $mid->id, "goto worked"); +---------------------- + +Now we test the same feature, but specifying the mark twice in the command. +This should have no effect, but let’s be sure: test it and see if things go +wrong. + +.t/11-goto.t: Test second code path +---------------------- +##################################################################### +# Check whether the focus command will switch to a different +# workspace if necessary +##################################################################### + +my $tmp2 = fresh_workspace; + +is(focused_ws(), $tmp2, 'tmp2 now focused'); + +cmd qq|[con_mark="$random_mark"] focus|; + +is(focused_ws(), $tmp, 'tmp now focused'); +---------------------- + +This part of the test checks that focusing windows by mark works across +workspaces. It uses i3test's +focused_ws+ function to get the current +workspace. + +.t/11-goto.t: Test second code path +---------------------- +done_testing; +---------------------- + +The end of every testcase has to contain the +done_testing+ line. This tells ++complete-run.pl+ that the test was finished successfully. If it does not +occur, the test might have crashed during execution -- some of the reasons why +that could happen are bugs in the used modules, bugs in the testcase itself or +an i3 crash resulting in the testcase being unable to communicate with i3 via +IPC anymore. + +[[i3_sync]] +== Appendix A: The i3 sync protocol + +Consider the following situation: You open two windows in your testcase, then +you use +focus left+ and want to verify that the X11 focus has been updated +properly. Sounds simple, right? Let’s assume you use this straight-forward +implementation: + +.Racey focus testcase +----------- +my $left = open_window($x); +my $right = open_window($x); +cmd 'focus left'; +is($x->input_focus, $left->id, 'left window focused'); +---------- + +However, the test fails. Sometimes. Apparantly, there is a race condition in +your test. If you think about it, this is because you are using two different +pieces of software: You tell i3 to update focus, i3 confirms that, and then you +ask X11 to give you the current focus. There is a certain time i3 needs to +update the X11 state. If the testcase gets CPU time before X11 processed i3's +requests, the test will fail. + +image::i3-sync.png["Diagram of the race condition", title="Diagram of the race condition"] + +One way to "solve" this would be to add +sleep 0.5;+ after the +cmd+ call. +After 0.5 seconds it should be safe to assume that focus has been updated, +right? + +In practice, this usually works. However, it has several problems: + +1. This is obviously not a clean solution, but a workaround. Ugly. +2. On very slow machines, this might not work. Unlikely, but in different + situations (a delay to wait for i3 to startup) the necessary time is much + harder to guess, even for fast machines. +3. This *wastes a lot of time*. Usually, your computer is much faster than 0.5s + to update the status. However, sometimes, it might take 0.4s, so we can’t + make it +sleep 0.1+. + +To illustrate how grave the problem with wasting time actually is: Before +removing all sleeps from the testsuite, a typical run using 4 separate X +servers took around 50 seconds on my machine. After removing all the sleeps, +we achieved times of about 25 seconds. This is very significant and influences +the way you think about tests -- the faster they are, the more likely you are +to check whether everything still works quite often (which you should). + +What I am trying to say is: This adds up quickly and makes the test suite less +robust. + +The real solution for this problem is a mechanism which I call "the i3 sync +protocol". The idea is to send a request (which does not modify state) via X11 +to i3 which will then be answered. Due to the request's position in the event +queue (*after* all previous events), you can be sure that by the time you +receive the reply, all other events have been dealt with by i3 (and, more +importantly, X11). + +image::i3-sync-working.png["Diagram of the i3 sync solution", title="Diagram of the i3 sync solution"] + +=== Implementation details + +The client which wants to sync with i3 initiates the protocol by sending a +ClientMessage to the X11 root window: + +.Send ClientMessage +------------------- +# Generate a ClientMessage, see xcb_client_message_t +my $msg = pack "CCSLLLLLLL", + CLIENT_MESSAGE, # response_type + 32, # format + 0, # sequence + $root, # destination window + $x->atom(name => 'I3_SYNC')->id, + + $_sync_window->id, # data[0]: our own window id + $myrnd, # data[1]: a random value to identify the request + 0, + 0, + 0; + +# Send it to the root window -- since i3 uses the SubstructureRedirect +# event mask, it will get the ClientMessage. +$x->send_event(0, $root, EVENT_MASK_SUBSTRUCTURE_REDIRECT, $msg); +------------------- + +i3 will then reply with the same ClientMessage, sent to the window specified in ++data[0]+. In the reply, +data[0]+ and +data[1]+ are exactly the same as in the +request. You should use a random value in +data[1]+ and check that you received +the same one when getting the reply. + +== Appendix B: Socket activation