4 # Sometimes the first click is lost (presumably it's used to give
5 # focus to virt-viewer or similar) so we do that now rather than
6 # having an important click lost. The point we click should be
7 # somewhere where no clickable elements generally reside.
8 @screen.click(@screen.width, @screen.height/2)
11 def activate_filesystem_shares
12 # XXX-9p: First of all, filesystem shares cannot be mounted while we
13 # do a snapshot save+restore, so unmounting+remounting them seems
14 # like a good idea. However, the 9p modules get into a broken state
15 # during the save+restore, so we also would like to unload+reload
16 # them, but loading of 9pnet_virtio fails after a restore with
17 # "probe of virtio2 failed with error -2" (in dmesg) which makes the
18 # shares unavailable. Hence we leave this code commented for now.
19 #for mod in ["9pnet_virtio", "9p"] do
20 # @vm.execute("modprobe #{mod}")
23 @vm.list_shares.each do |share|
24 @vm.execute("mkdir -p #{share}")
25 @vm.execute("mount -t 9p -o trans=virtio #{share} #{share}")
29 def deactivate_filesystem_shares
30 @vm.list_shares.each do |share|
31 @vm.execute("umount #{share}")
34 # XXX-9p: See XXX-9p above
35 #for mod in ["9p", "9pnet_virtio"] do
36 # @vm.execute("modprobe -r #{mod}")
40 def restore_background
41 @vm.restore_snapshot($background_snapshot)
42 @vm.wait_until_remote_shell_is_up
45 # XXX-9p: See XXX-9p above
46 #activate_filesystem_shares
48 # The guest's Tor's circuits' states are likely to get out of sync
49 # with the other relays, so we ensure that we have fresh circuits.
50 # Time jumps and incorrect clocks also confuses Tor in many ways.
52 if @vm.execute("service tor status").success?
53 @vm.execute("service tor stop")
54 @vm.execute("killall vidalia")
55 @vm.host_to_guest_time_sync
56 @vm.execute("service tor start")
57 wait_until_tor_is_working
58 @vm.spawn("/usr/local/sbin/restart-vidalia")
63 Given /^a computer$/ do
65 @vm = VM.new($vm_xml_path, $x_display)
68 Given /^the computer has (\d+) ([[:alpha:]]+) of RAM$/ do |size, unit|
69 next if @skip_steps_while_restoring_background
70 @vm.set_ram_size(size, unit)
73 Given /^the computer is set to boot from the Tails DVD$/ do
74 next if @skip_steps_while_restoring_background
75 @vm.set_cdrom_boot($tails_iso)
78 Given /^the computer is set to boot from (.+?) drive "(.+?)"$/ do |type, name|
79 next if @skip_steps_while_restoring_background
80 @vm.set_disk_boot(name, type.downcase)
83 Given /^I plug ([[:alpha:]]+) drive "([^"]+)"$/ do |bus, name|
84 next if @skip_steps_while_restoring_background
85 @vm.plug_drive(name, bus.downcase)
87 step "drive \"#{name}\" is detected by Tails"
91 Then /^drive "([^"]+)" is detected by Tails$/ do |name|
92 next if @skip_steps_while_restoring_background
94 try_for(10, :msg => "Drive '#{name}' is not detected by Tails") {
95 @vm.disk_detected?(name)
98 STDERR.puts "Cannot tell if drive '#{name}' is detected by Tails: " +
99 "Tails is not running"
103 Given /^the network is plugged$/ do
104 next if @skip_steps_while_restoring_background
108 Given /^the network is unplugged$/ do
109 next if @skip_steps_while_restoring_background
113 Given /^I capture all network traffic$/ do
114 # Note: We don't want skip this particular stpe if
115 # @skip_steps_while_restoring_background is set since it starts
116 # something external to the VM state.
117 @sniffer = Sniffer.new("TestSniffer", @vm.net.bridge_name, @vm.mac)
121 Given /^I set Tails to boot with options "([^"]*)"$/ do |options|
122 next if @skip_steps_while_restoring_background
123 @boot_options = options
126 When /^I start the computer$/ do
127 next if @skip_steps_while_restoring_background
128 assert(!@vm.is_running?,
129 "Trying to start a VM that is already running")
134 When /^I power off the computer$/ do
135 next if @skip_steps_while_restoring_background
136 assert(@vm.is_running?,
137 "Trying to power off an already powered off VM")
141 When /^I cold reboot the computer$/ do
142 next if @skip_steps_while_restoring_background
143 step "I power off the computer"
144 step "I start the computer"
147 When /^I destroy the computer$/ do
148 next if @skip_steps_while_restoring_background
152 Given /^the computer boots Tails$/ do
153 next if @skip_steps_while_restoring_background
154 @screen.wait('TailsBootSplash.png', 30)
155 @screen.wait('TailsBootSplashTabMsg.png', 10)
157 @screen.waitVanish('TailsBootSplashTabMsg.png', 1)
158 @screen.type(" autotest_never_use_this_option #{@boot_options}" +
160 @screen.wait('TailsGreeter.png', 15*60)
161 @vm.wait_until_remote_shell_is_up
162 activate_filesystem_shares
165 Given /^I log in to a new session$/ do
166 next if @skip_steps_while_restoring_background
167 @screen.wait_and_click('TailsGreeterLoginButton.png', 10)
170 Given /^I enable more Tails Greeter options$/ do
171 next if @skip_steps_while_restoring_background
172 match = @screen.find('TailsGreeterMoreOptions.png')
173 pos_x = match.x + match.width/2
174 # height*2 may seem odd, but we want to click the button below the
175 # match. This may even work accross different screen resolutions.
176 pos_y = match.y + match.height*2
177 @screen.click(pos_x, pos_y)
178 @screen.wait_and_click('TailsGreeterForward.png', 10)
179 @screen.wait('TailsGreeterLoginButton.png', 20)
182 Given /^I set sudo password "([^"]*)"$/ do |password|
183 @sudo_password = password
184 next if @skip_steps_while_restoring_background
185 @screen.wait("TailsGreeterAdminPassword.png", 20)
186 match = @screen.find('TailsGreeterPassword.png')
187 # width*3 may seem odd, but we want to click the field right of the
188 # match. This may even work accross different screen resolutions.
189 pos_x = match.x + match.width*3
190 pos_y = match.y + match.height/2
191 @screen.click(pos_x, pos_y)
192 @screen.type(@sudo_password + "\t" + @sudo_password)
195 Given /^Tails Greeter has dealt with the sudo password$/ do
196 next if @skip_steps_while_restoring_background
197 f1 = "/etc/sudoers.d/tails-greeter"
198 f2 = "#{f1}-no-password-lecture"
200 @vm.execute("test -e '#{f1}' -o -e '#{f2}'").success?
204 Given /^GNOME has started$/ do
205 next if @skip_steps_while_restoring_background
208 desktop_started_picture = 'WinXPStartButton.png'
210 desktop_started_picture = 'GnomeApplicationsMenu.png'
212 @screen.wait(desktop_started_picture, 180)
215 Then /^Tails seems to have booted normally$/ do
216 next if @skip_steps_while_restoring_background
217 step "GNOME has started"
220 Given /^I have a network connection$/ do
221 next if @skip_steps_while_restoring_background
222 try_for(120) { @vm.has_network? }
225 Given /^Tor has built a circuit$/ do
226 next if @skip_steps_while_restoring_background
227 wait_until_tor_is_working
230 Given /^the time has synced$/ do
231 next if @skip_steps_while_restoring_background
232 ["/var/run/tordate/done", "/var/run/htpdate/success"].each do |file|
233 try_for(300) { @vm.execute("test -e #{file}").success? }
237 Given /^Iceweasel has autostarted and is not loading a web page$/ do
238 next if @skip_steps_while_restoring_background
241 iceweasel_picture = "WinXPIceweaselWindow.png"
243 iceweasel_picture = "IceweaselRunning.png"
246 # Stop iceweasel to load its home page. We do this to prevent Tor
247 # from getting confused in case we save and restore a snapshot in
248 # the middle of loading a page.
249 @screen.wait_and_click(iceweasel_picture, 120)
250 @screen.type("l", Sikuli::KEY_CTRL)
251 @screen.type("about:blank" + Sikuli::KEY_RETURN)
254 Given /^I have closed all annoying notifications$/ do
255 next if @skip_steps_while_restoring_background
258 notification_picture = "WinXPNotificationX.png"
260 notification_picture = "GnomeNotificationX.png"
263 # First we wait a short while to give notifications a chance to show
265 @screen.wait(notification_picture, 10)
271 # note that we cannot use find_all as the resulting matches will
272 # have the positions from before we start closing notificatios,
273 # but closing them will change the positions.
274 while match = @screen.find(notification_picture)
275 @screen.click(match.x + match.width/2, match.y + match.height/2)
277 rescue Sikuli::ImageNotFound
282 Given /^I save the state so the background can be restored next scenario$/ do
283 if @skip_steps_while_restoring_background
284 assert(File.size?($background_snapshot),
285 "We have been skipping steps but there is no snapshot to restore")
287 # To be sure we run the feature from scratch we remove any
288 # leftover snapshot that wasn't removed.
289 if File.exist?($background_snapshot)
290 File.delete($background_snapshot)
292 # Workaround: when libvirt takes ownership of the snapshot it may
293 # become unwritable for the user running this script so it cannot
294 # be removed during clean up.
295 FileUtils.touch($background_snapshot)
296 FileUtils.chmod(0666, $background_snapshot)
298 # Snapshots cannot be saved while filesystem shares are mounted
299 # XXX-9p: See XXX-9p above.
300 #deactivate_filesystem_shares
302 @vm.save_snapshot($background_snapshot)
305 # Now we stop skipping steps from the snapshot restore.
306 @skip_steps_while_restoring_background = false
309 Then /^I see "([^"]*)" after at most (\d+) seconds$/ do |image, time|
310 next if @skip_steps_while_restoring_background
311 @screen.wait(image, time.to_i)
314 Then /^all Internet traffic has only flowed through Tor$/ do
315 next if @skip_steps_while_restoring_background
316 leaks = FirewallLeakCheck.new(@sniffer.pcap_file, get_tor_relays)
318 if !leaks.ipv4_tcp_leaks.empty?
319 puts "The following IPv4 TCP non-Tor Internet hosts were contacted:"
320 puts leaks.ipv4_tcp_leaks.join("\n")
323 if !leaks.ipv4_nontcp_leaks.empty?
324 puts "The following IPv4 non-TCP Internet hosts were contacted:"
325 puts leaks.ipv4_nontcp_leaks.join("\n")
328 if !leaks.ipv6_leaks.empty?
329 puts "The following IPv6 Internet hosts were contacted:"
330 puts leaks.ipv6_leaks.join("\n")
333 if !leaks.nonip_leaks.empty?
334 puts "Some non-IP packets were sent\n"
337 raise "There were network leaks!"
341 When /^I open the GNOME run dialog$/ do
342 next if @skip_steps_while_restoring_background
343 @screen.type(Sikuli::KEY_F2, Sikuli::KEY_ALT)
346 run_dialog_picture = 'WinXPRunDialog.png'
348 run_dialog_picture = 'GnomeRunDialog.png'
350 @screen.wait(run_dialog_picture, 10)
353 When /^I run "([^"]*)"$/ do |program|
354 next if @skip_steps_while_restoring_background
355 step "I open the GNOME run dialog"
356 @screen.type(program + Sikuli::KEY_RETURN)
359 Given /^I enter the sudo password in the gksu prompt$/ do
360 next if @skip_steps_while_restoring_background
361 @screen.wait('GksuAuthPrompt.png', 60)
362 sleep 1 # wait for weird fade-in to unblock the "Ok" button
363 @screen.type(@sudo_password)
364 @screen.type(Sikuli::KEY_RETURN)
365 @screen.waitVanish('GksuAuthPrompt.png', 10)
368 Given /^I enter the sudo password in the PolicyKit prompt$/ do
369 next if @skip_steps_while_restoring_background
370 step "I enter the \"#{@sudo_password}\" password in the PolicyKit prompt"
373 Given /^I enter the "([^"]*)" password in the PolicyKit prompt$/ do |password|
374 next if @skip_steps_while_restoring_background
375 @screen.wait('PolicyKitAuthPrompt.png', 60)
376 sleep 1 # wait for weird fade-in to unblock the "Ok" button
377 @screen.type(password)
378 @screen.type(Sikuli::KEY_RETURN)
379 @screen.waitVanish('PolicyKitAuthPrompt.png', 10)
382 Given /^process "([^"]+)" is running$/ do |process|
383 next if @skip_steps_while_restoring_background
384 assert(@vm.has_process?(process),
385 "Process '#{process}' is not running")
388 Given /^process "([^"]+)" is not running$/ do |process|
389 next if @skip_steps_while_restoring_background
390 assert(!@vm.has_process?(process),
391 "Process '#{process}' is running")
394 Given /^I kill the process "([^"]+)"$/ do |process|
395 next if @skip_steps_while_restoring_background
396 @vm.execute("killall #{process}")
397 try_for(10, :msg => "Process '#{process}' could not be killed") {
398 !@vm.has_process?(process)
402 Given /^I completely shutdown Tails$/ do
403 next if @skip_steps_while_restoring_background
405 @screen.wait_and_click('TailsEmergencyShutdownButton.png', 10)
407 @screen.wait_and_click('TailsEmergencyShutdownHalt.png', 10)
408 nr_gibs_of_ram = (detected_ram_in_bytes.to_f/(2**30)).ceil
409 try_for(nr_gibs_of_ram*5*60, :msg => "VM is still running") do
414 Given /^package "([^"]+)" is installed$/ do |package|
415 next if @skip_steps_while_restoring_background
416 assert(@vm.execute("dpkg -s '#{package}' 2>/dev/null | grep -qs '^Status:.*installed$'").success?,
417 "Package '#{package}' is not installed")