common_steps.rb 14.4 KB
Newer Older
1
2
require 'fileutils'

3
4
5
6
7
def post_vm_start_hook
  # Sometimes the first click is lost (presumably it's used to give
  # focus to virt-viewer or similar) so we do that now rather than
  # having an important click lost. The point we click should be
  # somewhere where no clickable elements generally reside.
8
  @screen.click_point(@screen.w, @screen.h/2)
9
10
end

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
def activate_filesystem_shares
  # XXX-9p: First of all, filesystem shares cannot be mounted while we
  # do a snapshot save+restore, so unmounting+remounting them seems
  # like a good idea. However, the 9p modules get into a broken state
  # during the save+restore, so we also would like to unload+reload
  # them, but loading of 9pnet_virtio fails after a restore with
  # "probe of virtio2 failed with error -2" (in dmesg) which makes the
  # shares unavailable. Hence we leave this code commented for now.
  #for mod in ["9pnet_virtio", "9p"] do
  #  @vm.execute("modprobe #{mod}")
  #end

  @vm.list_shares.each do |share|
    @vm.execute("mkdir -p #{share}")
    @vm.execute("mount -t 9p -o trans=virtio #{share} #{share}")
  end
end

def deactivate_filesystem_shares
  @vm.list_shares.each do |share|
    @vm.execute("umount #{share}")
  end

  # XXX-9p: See XXX-9p above
  #for mod in ["9p", "9pnet_virtio"] do
  #  @vm.execute("modprobe -r #{mod}")
  #end
end

40
def restore_background
41
  @vm.restore_snapshot($background_snapshot)
42
  @vm.wait_until_remote_shell_is_up
43
  post_vm_start_hook
44
45
46
47

  # XXX-9p: See XXX-9p above
  #activate_filesystem_shares

48
49
50
  # The guest's Tor's circuits' states are likely to get out of sync
  # with the other relays, so we ensure that we have fresh circuits.
  # Time jumps and incorrect clocks also confuses Tor in many ways.
51
  if @vm.has_network?
52
53
    if @vm.execute("service tor status").success?
      @vm.execute("service tor stop")
54
55
      @vm.execute("killall vidalia")
      @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")
59
    end
60
61
62
  end
end

63
64
def run_dialog_picture
  case @theme
65
66
  when "windows"
    return 'WindowsRunDialog.png'
67
68
69
70
71
  else
    return 'GnomeRunDialog.png'
  end
end

72
73
Given /^a computer$/ do
  @vm.destroy if @vm
74
  @vm = VM.new($vm_xml_path, $x_display)
75
76
end

77
78
79
80
81
Given /^the computer has (\d+) ([[:alpha:]]+) of RAM$/ do |size, unit|
  next if @skip_steps_while_restoring_background
  @vm.set_ram_size(size, unit)
end

82
Given /^the computer is set to boot from the Tails DVD$/ do
83
  next if @skip_steps_while_restoring_background
84
  @vm.set_cdrom_boot($tails_iso)
85
86
end

87
88
89
90
91
Given /^the computer is set to boot from (.+?) drive "(.+?)"$/ do |type, name|
  next if @skip_steps_while_restoring_background
  @vm.set_disk_boot(name, type.downcase)
end

92
93
94
95
96
97
98
99
100
Given /^I plug ([[:alpha:]]+) drive "([^"]+)"$/ do |bus, name|
  next if @skip_steps_while_restoring_background
  @vm.plug_drive(name, bus.downcase)
  if @vm.is_running?
    step "drive \"#{name}\" is detected by Tails"
  end
end

Then /^drive "([^"]+)" is detected by Tails$/ do |name|
101
  next if @skip_steps_while_restoring_background
102
103
104
105
106
107
108
109
110
111
  if @vm.is_running?
    try_for(10, :msg => "Drive '#{name}' is not detected by Tails") {
      @vm.disk_detected?(name)
    }
  else
    STDERR.puts "Cannot tell if drive '#{name}' is detected by Tails: " +
                "Tails is not running"
  end
end

112
113
114
115
116
117
118
119
120
121
122
123
124
125
Given /^the network is plugged$/ do
  next if @skip_steps_while_restoring_background
  @vm.plug_network
end

Given /^the network is unplugged$/ do
  next if @skip_steps_while_restoring_background
  @vm.unplug_network
end

Given /^I capture all network traffic$/ do
  # Note: We don't want skip this particular stpe if
  # @skip_steps_while_restoring_background is set since it starts
  # something external to the VM state.
126
  @sniffer = Sniffer.new("TestSniffer", @vm.net.bridge_name)
127
128
129
130
131
132
133
134
135
136
  @sniffer.capture
end

Given /^I set Tails to boot with options "([^"]*)"$/ do |options|
  next if @skip_steps_while_restoring_background
  @boot_options = options
end

When /^I start the computer$/ do
  next if @skip_steps_while_restoring_background
137
138
  assert(!@vm.is_running?,
         "Trying to start a VM that is already running")
139
  @vm.start
140
  post_vm_start_hook
141
142
143
144
end

When /^I power off the computer$/ do
  next if @skip_steps_while_restoring_background
145
146
  assert(@vm.is_running?,
         "Trying to power off an already powered off VM")
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
  @vm.power_off
end

When /^I cold reboot the computer$/ do
  next if @skip_steps_while_restoring_background
  step "I power off the computer"
  step "I start the computer"
end

When /^I destroy the computer$/ do
  next if @skip_steps_while_restoring_background
  @vm.destroy
end

Given /^the computer boots Tails$/ do
  next if @skip_steps_while_restoring_background
163
  @screen.wait('TailsBootSplash.png', 30)
164
  @screen.wait('TailsBootSplashTabMsg.png', 10)
165
  @screen.type(Sikuli::Key.TAB)
166
167
  @screen.waitVanish('TailsBootSplashTabMsg.png', 1)
  @screen.type(" autotest_never_use_this_option #{@boot_options}" +
168
               Sikuli::Key.ENTER)
Tails developers's avatar
Tails developers committed
169
  @screen.wait('TailsGreeter.png', 30*60)
170
  @vm.wait_until_remote_shell_is_up
171
  activate_filesystem_shares
172
173
end

174
Given /^I log in to a new session$/ do
175
  next if @skip_steps_while_restoring_background
176
  @screen.wait_and_click('TailsGreeterLoginButton.png', 10)
177
178
end

179
Given /^I enable more Tails Greeter options$/ do
180
  next if @skip_steps_while_restoring_background
181
  match = @screen.find('TailsGreeterMoreOptions.png')
182
  @screen.click(match.getCenter.offset(match.w/2, match.h*2))
183
  @screen.wait_and_click('TailsGreeterForward.png', 10)
184
185
186
187
188
189
190
  @screen.wait('TailsGreeterLoginButton.png', 20)
end

Given /^I set sudo password "([^"]*)"$/ do |password|
  @sudo_password = password
  next if @skip_steps_while_restoring_background
  @screen.wait("TailsGreeterAdminPassword.png", 20)
191
192
193
  @screen.type(@sudo_password)
  @screen.type(Sikuli::Key.TAB)
  @screen.type(@sudo_password)
194
195
196
end

Given /^Tails Greeter has dealt with the sudo password$/ do
197
  next if @skip_steps_while_restoring_background
198
199
200
201
202
  f1 = "/etc/sudoers.d/tails-greeter"
  f2 = "#{f1}-no-password-lecture"
  try_for(20) {
    @vm.execute("test -e '#{f1}' -o -e '#{f2}'").success?
  }
203
204
205
206
end

Given /^GNOME has started$/ do
  next if @skip_steps_while_restoring_background
207
  case @theme
208
209
  when "windows"
    desktop_started_picture = 'WindowsStartButton.png'
210
  else
Tails developers's avatar
Tails developers committed
211
    desktop_started_picture = 'GnomeApplicationsMenu.png'
212
  end
Tails developers's avatar
Tails developers committed
213
  @screen.wait(desktop_started_picture, 180)
214
215
end

216
217
218
219
220
Then /^Tails seems to have booted normally$/ do
  next if @skip_steps_while_restoring_background
  step "GNOME has started"
end

221
Given /^Tor is ready$/ do
222
  next if @skip_steps_while_restoring_background
223
224
  @screen.wait("GnomeTorIsReady.png", 300)
  @screen.waitVanish("GnomeTorIsReady.png", 15)
225

226
227
  # Having seen the "Tor is ready" notification implies that Tor has
  # built a circuit, but let's check it directly to be on the safe side.
228
  step "Tor has built a circuit"
229

230
  step "the time has synced"
231
232
233
end

Given /^Tor has built a circuit$/ do
234
  next if @skip_steps_while_restoring_background
235
236
237
238
  wait_until_tor_is_working
end

Given /^the time has synced$/ do
239
  next if @skip_steps_while_restoring_background
240
241
242
243
244
  ["/var/run/tordate/done", "/var/run/htpdate/success"].each do |file|
    try_for(300) { @vm.execute("test -e #{file}").success? }
  end
end

245
246
247
248
249
250
251
Given /^available upgrades have been checked$/ do
  next if @skip_steps_while_restoring_background
  try_for(300) {
    @vm.execute("test -e '/var/run/tails-upgrader/checked_upgrades'").success?
  }
end

252
Given /^Iceweasel has started and is not loading a web page$/ do
253
  next if @skip_steps_while_restoring_background
254
  case @theme
255
256
  when "windows"
    iceweasel_picture = "WindowsIceweaselWindow.png"
257
  else
258
    iceweasel_picture = "IceweaselWindow.png"
259
  end
260
261

  # Stop iceweasel to load its home page. We do this to prevent Tor
Tails developers's avatar
Tails developers committed
262
  # from getting confused in case we save and restore a snapshot in
263
  # the middle of loading a page.
264
  @screen.wait_and_click(iceweasel_picture, 120)
265
266
  @screen.type("l", Sikuli::KeyModifier.CTRL)
  @screen.type("about:blank" + Sikuli::Key.ENTER)
267
268
end

269
Given /^all notifications have disappeared$/ do
270
  next if @skip_steps_while_restoring_background
271
  case @theme
272
273
  when "windows"
    notification_picture = "WindowsNotificationX.png"
274
275
276
  else
    notification_picture = "GnomeNotificationX.png"
  end
277
  @screen.waitVanish(notification_picture, 60)
Tails developers's avatar
Tails developers committed
278
279
end

280
281
282
283
284
285
286
287
288
289
Given /^I save the state so the background can be restored next scenario$/ do
  if @skip_steps_while_restoring_background
    assert(File.size?($background_snapshot),
           "We have been skipping steps but there is no snapshot to restore")
  else
    # To be sure we run the feature from scratch we remove any
    # leftover snapshot that wasn't removed.
    if File.exist?($background_snapshot)
      File.delete($background_snapshot)
    end
Tails developers's avatar
Tails developers committed
290
291
292
    # Workaround: when libvirt takes ownership of the snapshot it may
    # become unwritable for the user running this script so it cannot
    # be removed during clean up.
293
294
    FileUtils.touch($background_snapshot)
    FileUtils.chmod(0666, $background_snapshot)
295
296
297
298
299

    # Snapshots cannot be saved while filesystem shares are mounted
    # XXX-9p: See XXX-9p above.
    #deactivate_filesystem_shares

300
    @vm.save_snapshot($background_snapshot)
301
  end
302
  restore_background
303
304
  # Now we stop skipping steps from the snapshot restore.
  @skip_steps_while_restoring_background = false
305
306
307
end

Then /^I see "([^"]*)" after at most (\d+) seconds$/ do |image, time|
308
  next if @skip_steps_while_restoring_background
309
310
311
312
  @screen.wait(image, time.to_i)
end

Then /^all Internet traffic has only flowed through Tor$/ do
313
  next if @skip_steps_while_restoring_background
314
  leaks = FirewallLeakCheck.new(@sniffer.pcap_file, get_tor_relays)
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
  if !leaks.empty?
    if !leaks.ipv4_tcp_leaks.empty?
      puts "The following IPv4 TCP non-Tor Internet hosts were contacted:"
      puts leaks.ipv4_tcp_leaks.join("\n")
      puts
    end
    if !leaks.ipv4_nontcp_leaks.empty?
      puts "The following IPv4 non-TCP Internet hosts were contacted:"
      puts leaks.ipv4_nontcp_leaks.join("\n")
      puts
    end
    if !leaks.ipv6_leaks.empty?
      puts "The following IPv6 Internet hosts were contacted:"
      puts leaks.ipv6_leaks.join("\n")
      puts
    end
331
332
333
    if !leaks.nonip_leaks.empty?
      puts "Some non-IP packets were sent\n"
    end
334
    save_pcap_file
335
336
337
    raise "There were network leaks!"
  end
end
338
339

When /^I open the GNOME run dialog$/ do
340
  next if @skip_steps_while_restoring_background
341
  @screen.type(Sikuli::Key.F2, Sikuli::KeyModifier.ALT)
342
  @screen.wait(run_dialog_picture, 10)
343
344
345
end

When /^I run "([^"]*)"$/ do |program|
346
  next if @skip_steps_while_restoring_background
347
  step "I open the GNOME run dialog"
348
  @screen.type(program)
349
350
  sleep 0.5
  @screen.type(Sikuli::Key.ENTER)
351
end
352

353
354
355
356
357
Given /^I enter the sudo password in the gksu prompt$/ do
  next if @skip_steps_while_restoring_background
  @screen.wait('GksuAuthPrompt.png', 60)
  sleep 1 # wait for weird fade-in to unblock the "Ok" button
  @screen.type(@sudo_password)
358
  @screen.type(Sikuli::Key.ENTER)
359
360
361
  @screen.waitVanish('GksuAuthPrompt.png', 10)
end

362
Given /^I enter the sudo password in the pkexec prompt$/ do
363
  next if @skip_steps_while_restoring_background
364
  step "I enter the \"#{@sudo_password}\" password in the pkexec prompt"
365
366
end

367
368
def deal_with_polkit_prompt (image, password)
  @screen.wait(image, 60)
369
  sleep 1 # wait for weird fade-in to unblock the "Ok" button
370
  @screen.type(password)
371
  @screen.type(Sikuli::Key.ENTER)
372
373
374
375
376
377
  @screen.waitVanish(image, 10)
end

Given /^I enter the "([^"]*)" password in the pkexec prompt$/ do |password|
  next if @skip_steps_while_restoring_background
  deal_with_polkit_prompt('PolicyKitAuthPrompt.png', password)
378
379
380
381
end

Given /^process "([^"]+)" is running$/ do |process|
  next if @skip_steps_while_restoring_background
382
383
  assert(@vm.has_process?(process),
         "Process '#{process}' is not running")
384
385
end

386
387
Given /^process "([^"]+)" is running within (\d+) seconds$/ do |process, time|
  next if @skip_steps_while_restoring_background
Tails developers's avatar
Tails developers committed
388
389
  try_for(time.to_i, :msg => "Process '#{process}' is not running after " +
                             "waiting for #{time} seconds") do
390
391
392
393
    @vm.has_process?(process)
  end
end

394
395
396
397
398
399
Given /^process "([^"]+)" is not running$/ do |process|
  next if @skip_steps_while_restoring_background
  assert(!@vm.has_process?(process),
         "Process '#{process}' is running")
end

400
Given /^I kill the process "([^"]+)"$/ do |process|
401
  next if @skip_steps_while_restoring_background
402
  @vm.execute("killall #{process}")
403
  try_for(10, :msg => "Process '#{process}' could not be killed") {
404
405
    !@vm.has_process?(process)
  }
406
407
end

408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
Then /^Tails eventually shuts down$/ do
  next if @skip_steps_while_restoring_background
  nr_gibs_of_ram = (detected_ram_in_MiB.to_f/(2**10)).ceil
  timeout = nr_gibs_of_ram*5*60
  try_for(timeout, :msg => "VM is still running after #{timeout} seconds") do
    ! @vm.is_running?
  end
end

Then /^Tails eventually restarts$/ do
  next if @skip_steps_while_restoring_background
  nr_gibs_of_ram = (detected_ram_in_MiB.to_f/(2**10)).ceil
  @screen.wait('TailsBootSplashPostReset.png', nr_gibs_of_ram*5*60)
end

Given /^I shutdown Tails and wait for the computer to power off$/ do
  next if @skip_steps_while_restoring_background
425
  @vm.execute("poweroff")
426
427
428
429
  step 'Tails eventually shuts down'
end

When /^I request a shutdown using the emergency shutdown applet$/ do
430
  next if @skip_steps_while_restoring_background
431
  @screen.hide_cursor
432
  @screen.wait_and_click('TailsEmergencyShutdownButton.png', 10)
433
  @screen.hide_cursor
434
  @screen.wait_and_click('TailsEmergencyShutdownHalt.png', 10)
435
436
437
438
439
440
441
442
end

When /^I request a reboot using the emergency shutdown applet$/ do
  next if @skip_steps_while_restoring_background
  @screen.hide_cursor
  @screen.wait_and_click('TailsEmergencyShutdownButton.png', 10)
  @screen.hide_cursor
  @screen.wait_and_click('TailsEmergencyShutdownReboot.png', 10)
443
444
445
446
end

Given /^package "([^"]+)" is installed$/ do |package|
  next if @skip_steps_while_restoring_background
447
  assert(@vm.execute("dpkg -s '#{package}' 2>/dev/null | grep -qs '^Status:.*installed$'").success?,
448
         "Package '#{package}' is not installed")
449
end
450
451
452
453
454
455
456
457
458
459
460
461
462
463

When /^I start Iceweasel$/ do
  next if @skip_steps_while_restoring_background
  case @theme
  when "windows"
    step 'I click the start menu'
    @screen.wait_and_click("WindowsApplicationsInternet.png", 10)
    @screen.wait_and_click("WindowsApplicationsIceweasel.png", 10)
  else
    @screen.wait_and_click("GnomeApplicationsMenu.png", 10)
    @screen.wait_and_click("GnomeApplicationsInternet.png", 10)
    @screen.wait_and_click("GnomeApplicationsIceweasel.png", 10)
  end
end