Merge remote-tracking branch 'flapflap/de-network_configuration'
[tails-test.git] / wiki / src / blueprint / test_suite_getting_rid_of_the_jruby_mess.mdwn
blob61558a0ab31114abdcd86491196527482dce0ad7
1 We want to drop the dependency of JRuby from our automated test suite,
2 and move to native Ruby.
4 **Ticket**: [[!tails_ticket 5731]]
6 [[!toc levels=2]]
8 # Why
10 We depend on JRuby only because of the `sikuli-ruby` gem. Since
11 Debian's JRuby is too old this forces us to use RVM to install a more
12 recent JRuby *and* all required Ruby gems from RVM's non-Debian
13 sources, even though most of them are packaged for Debian. For all we
14 know, all of this can break in the future, especially after the Wheezy
15 release. Also, some parts of the RVM/gem mess have none or at best
16 scetchy authentication. Clearly we want all dependencies for the
17 automated test suite to be in Debian, and this mess is a big blocker
18 for that.
20 Also, in JRuby 1.7 the C extension was deprecated, which means that
21 two gems we depend on hsa become unusabe: `ruby-libvirt`, which is
22 highly critical for us, and `system_timer`, which is not so critical.
24 A move to native Ruby would put us in a much better position, since
25 all gems are packaged in Debian, and native Ruby
26 still has a C extension. To be able to do this we need a replacement
27 for the `sikuli-ruby` gem, though.
29 # Ways to replace the sikuli-ruby gem
31 ## Rjb
33 [[rjb|<http://rjb.rubyforge.org/>]] seems maintained, if not actively developed.
34 It is now in Debian Jessie and wheezy-backports.
36 Other projects using it or interesting stuff at:
38 * [rjb-require](https://github.com/svenfuchs/rjb-require)
39 * [rjb-examples](https://github.com/L2G/rjb-example)
40 * [poi_pond](https://github.com/lgleasain/poi_pond) (uses Rjb)
41 * [Antrap](https://github.com/atoulme/Antwrap) (uses rjb)
43 The jruby sikuli gem is quite simple, implementing it in Rjb can be as
44 lightweight, or not.
46 See [[!tails_ticket 6399]], `test/rjb-migration` branch.
48 ## Wrapping Sikuli commands via a stand-alone Sikuli server
50 If the Rjb solution doesn't work out, this fallback is a drop-in
51 replacement for the Sikuli gem, and that we know will work no matter
52 what, and that should be reasonably easy to implement.
54 In short, we create a pure Java program that controls a single
55 `Screen` object, and listens for commands that that it translates into
56 Sikuli API calls for that `Screen` object, and then responds
57 appropriately to the calling client.
59 ### Details
61 1. We write a pure Java program using the Java API for Sikuli, that
62    takes the `$DISPLAY`, image dir etc. as arguments and then sets up
63    all required Sikuli objects: Mouse and Keyboard robots, and a single
64    `Screen` object. Let's call this the "Sikuli server".
66 1. The Sikuli server listens (on a UNIX socket, or whatever) for
67    "Sikuli commands" that it translates to Sikuli calls on the single
68    `Screen` object via the Sikuli API, and then translates the result
69    and sends that as a response.
71 1. We completely re-write `sikuli_helper.rb`, defining a `Screen`
72    class (and possibly `Region`; see below). On `initialize()` it
73    starts a Sikuli server instance (simply via `Popen()` or whatever).
74    We implement simple wrappers for all methods we've used earlier
75    (i.e. `find()`, `wait()`, `type()`, `hover()` and `click()`) that
76    will send an appropriate command to the Sikuli server.
78 ### Example
80 Say `screen` is an instance of `sikuli_helper.rb`'s `Screen`. Then
81 `screen.wait("image.png", 100)` will result in something like
82 `wait,image.png,100` being sent to the Sikuli server, which it
83 translates into the call `screenObject.wait("image.png", 100)`, and
84 responds back with something easily parsable, like
85 `exception=ImageNotFound:Could not find image.png` (or whatever the
86 exact exception name and message are) on failure, otherwise it just
87 sends an ACK so `screen.wait()` can stop blocking execution.
89 > I'd rather not invent a new protocol entirely, and instead
90 > piggy-back e.g. on HTTP or something more appropriate. Also, I'd
91 > rather use a well-known, well-defined serialization format (YAML,
92 > JSON, you name it) instead of inventing a new one.
94 ### Obstacles
96 * There may be some complexity to deal with `Region` objects (returned
97   by e.g. `find()`, which we use in `wait_and_click()`) since we'd
98   need some way (an identifier?) to know which `Region` object in
99   `sikuli_helper.rb` corresponds to which `Region` (Java) object in
100   the Sikuli server; we avoid this issue with `Screen` since each
101   Sikuli server deals with a single `Screen` object, but we can
102   potentially deal with any number of `Region` objects. A simple
103   solution would be to only store the appropriate coordinates and
104   dimensions in `sikuli_helper.rb`'s `Region` object and then whenever
105   it's used we create a new `Region` object in the Sikuli server using
106   those coordinates and dimensions. We could then implement methods
107   via the `Screen` object, like `Region.click()` could use those
108   coordinates and dimensions to `Screen.click()` on the right place.
109   We currently only use `Region` in our `wait_and_click` helper, so
110   a ad-hoc solution would probably be enough.
112 * Getting Sikuli's key constants (e.g. `Sikuli::KEY_CTRL`) into
113   `sikuli_helper.rb` is not completely trivial. Perhaps we could make
114   the Sikuli server send the values of all these so they can be stored
115   into the appropriate constants upon `Screen.initialize()`, when the
116   server is first contacted? Otherwise we can always statically define
117   them with magic values.
119 # Roadmap
121 Complete the move to Rjb in `test/rjb-migration`.