summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoranonym <anonym@riseup.net>2017-12-05 19:02:12 +0100
committeranonym <anonym@riseup.net>2019-05-14 16:51:14 +0200
commit706cde463d845cd5202295fa06f9712f7f5aea76 (patch)
treea4f565aa1371cf29eb6215df0b51670e84cb6f6d
parentff0d38c13e04d3536a00f9b11637dfcf265aa9e7 (diff)
Test suite: reinvent try_for()/retry_action as try().
Interface-wise we have: * try_for(t, ...) => try(timeout: t, ...) * retry_action(n, ...) => try(attempts: n, ...) * + a few minor changes (e.g. 'msg' => 'message') The other important change is that we fix #9223, i.e. the code block no longer must return `true` to pass; instead we provide a `try_for_success()` for the cases where we actually want that. Will-fix: #9223
-rw-r--r--features/step_definitions/additional_software_packages.rb14
-rw-r--r--features/step_definitions/apt.rb36
-rw-r--r--features/step_definitions/browser.rb22
-rw-r--r--features/step_definitions/common_steps.rb115
-rw-r--r--features/step_definitions/electrum.rb6
-rw-r--r--features/step_definitions/encryption.rb3
-rw-r--r--features/step_definitions/erase_memory.rb11
-rw-r--r--features/step_definitions/evince.rb7
-rw-r--r--features/step_definitions/git.rb8
-rw-r--r--features/step_definitions/gnome.rb7
-rw-r--r--features/step_definitions/mac_spoofing.rb2
-rw-r--r--features/step_definitions/pidgin.rb14
-rw-r--r--features/step_definitions/root_access_control.rb6
-rw-r--r--features/step_definitions/ssh.rb12
-rw-r--r--features/step_definitions/thunderbird.rb25
-rw-r--r--features/step_definitions/tor.rb2
-rw-r--r--features/step_definitions/torified_gnupg.rb48
-rw-r--r--features/step_definitions/torified_misc.rb4
-rw-r--r--features/step_definitions/totem.rb2
-rw-r--r--features/step_definitions/unsafe_browser.rb2
-rw-r--r--features/step_definitions/usb.rb15
-rw-r--r--features/step_definitions/veracrypt.rb57
-rw-r--r--features/support/helpers/display.rb8
-rw-r--r--features/support/helpers/misc.rb6
-rw-r--r--features/support/helpers/remote_shell.rb4
-rw-r--r--features/support/helpers/try.rb161
-rw-r--r--features/support/helpers/vm.rb2
27 files changed, 308 insertions, 291 deletions
diff --git a/features/step_definitions/additional_software_packages.rb b/features/step_definitions/additional_software_packages.rb
index 9753e20..741a019 100644
--- a/features/step_definitions/additional_software_packages.rb
+++ b/features/step_definitions/additional_software_packages.rb
@@ -11,7 +11,7 @@ Then /^the Additional Software (upgrade|installation) service has started$/ do |
service = "tails-additional-software-upgrade"
seconds_to_wait = 900
end
- try_for(seconds_to_wait, :delay => 10) do
+ try(timeout: seconds_to_wait, delay: 10) do
$vm.execute("systemctl status #{service}.service").success?
end
if service == "installation"
@@ -52,7 +52,7 @@ Then /^Additional Software is correctly configured for package "([^"]*)"$/ do |p
step 'all persistence configuration files have safe access rights'
$vm.execute_successfully("ls /live/persistence/TailsData_unlocked/apt/cache/#{package}_*.deb")
$vm.execute_successfully("ls /live/persistence/TailsData_unlocked/apt/lists/*_Packages")
- try_for(30) do
+ try(timeout: 30) do
$vm.execute("grep --line-regexp --fixed-strings #{package} #{ASP_CONF}").success?
end
end
@@ -60,7 +60,7 @@ end
Then /^"([^"]*)" is not in the list of Additional Software$/ do |package|
assert($vm.file_exist?(ASP_CONF), "ASP configuration file not found")
step 'all persistence configuration files have safe access rights'
- try_for(30) do
+ try(timeout: 30) do
$vm.execute("grep \"#{package}\" #{ASP_CONF}").stdout.empty?
end
end
@@ -117,15 +117,15 @@ end
Then /^I can open the Additional Software documentation from the notification$/ do
gnome_shell = Dogtail::Application.new('gnome-shell')
gnome_shell.child('Documentation', roleName: 'push button').click
- try_for(60) { @torbrowser = Dogtail::Application.new('Firefox') }
+ try(timeout: 60) { @torbrowser = Dogtail::Application.new('Firefox') }
step '"Tails - Install from another Tails" has loaded in the Tor Browser'
end
Then /^the Additional Software dpkg hook has been run for package "([^"]*)" and notices the persistence is locked$/ do |package|
asp_logs = "#{ASP_STATE_DIR}/log"
assert(!$vm.file_empty?(asp_logs))
- try_for(60) { $vm.execute("grep -E '^.*New\spackages\smanually\sinstalled:\s.*#{package}.*$' #{asp_logs}").success? }
- try_for(60) { $vm.file_content(asp_logs).include?('Warning: persistence storage is locked') }
+ try(timeout: 60) { $vm.execute("grep -E '^.*New\spackages\smanually\sinstalled:\s.*#{package}.*$' #{asp_logs}").success? }
+ try(timeout: 60) { $vm.file_content(asp_logs).include?('Warning: persistence storage is locked') }
end
When /^I can open the Additional Software configuration window from the notification$/ do
@@ -137,5 +137,5 @@ end
Then /^I can open the Additional Software log file from the notification$/ do
gnome_shell = Dogtail::Application.new('gnome-shell')
gnome_shell.child('Show Log', roleName: 'push button').click
- try_for(60) { Dogtail::Application.new('gedit').child("log [Read-Only] (#{ASP_STATE_DIR}) - gedit", roleName: 'frame') }
+ try(timeout: 60) { Dogtail::Application.new('gedit').child("log [Read-Only] (#{ASP_STATE_DIR}) - gedit", roleName: 'frame') }
end
diff --git a/features/step_definitions/apt.rb b/features/step_definitions/apt.rb
index 15007ba..0b8d26f 100644
--- a/features/step_definitions/apt.rb
+++ b/features/step_definitions/apt.rb
@@ -43,7 +43,7 @@ When /^I update APT using apt$/ do
step 'I kill the process "apt"'
$vm.execute('rm -rf /var/lib/apt/lists/*')
end
- retry_tor(recovery_proc) do
+ try_tor(recovery_proc) do
Timeout::timeout(15*60) do
$vm.execute_successfully("echo #{@sudo_password} | " +
"sudo -S apt update", :user => LIVE_USER)
@@ -52,7 +52,7 @@ When /^I update APT using apt$/ do
end
def wait_for_package_installation(package)
- try_for(2*60) do
+ try(timeout: 2*60) do
$vm.execute_successfully("dpkg -s '#{package}' 2>/dev/null | grep -qs '^Status:.*installed$'")
end
end
@@ -64,19 +64,17 @@ Then /^I install "(.+)" using apt$/ do |package|
# installed at this point, and then "apt purge" would return non-zero.
$vm.execute("apt purge #{package}")
end
- retry_tor(recovery_proc) do
- Timeout::timeout(3*60) do
- $vm.execute("echo #{@sudo_password} | " +
- "sudo -S DEBIAN_PRIORITY=critical apt -y install #{package}",
- :user => LIVE_USER,
- :spawn => true)
- wait_for_package_installation(package)
- end
+ try_tor(recovery_proc, timeout: 3*60) do
+ $vm.execute_successfully("echo #{@sudo_password} | " +
+ "sudo -S DEBIAN_PRIORITY=critical apt -y install #{package}",
+ :user => LIVE_USER,
+ :spawn => true)
+ wait_for_package_installation(package)
end
end
def wait_for_package_removal(package)
- try_for(3*60) do
+ try_for_success(timeout: 3*60) do
# Once purged, a package is removed from the installed package status database
# and "dpkg -s" returns a non-zero exit code
! $vm.execute("dpkg -s #{package}").success?
@@ -140,12 +138,15 @@ When /^I update APT using Synaptic$/ do
step 'I kill the process "synaptic"'
step "I start Synaptic"
end
- retry_tor(recovery_proc) do
+ try_tor(recovery_proc) do
@synaptic.button('Reload').click
sleep 10 # It might take some time before APT starts downloading
- try_for(15*60, :msg => "Took too much time to download the APT data") {
+ try_for_success(
+ timeout: 15*60,
+ message: "Took too much time to download the APT data"
+ ) do
!$vm.has_process?("/usr/lib/apt/methods/tor+http")
- }
+ end
assert_raise(RuntimeError) do
@synaptic.child(roleName: 'dialog', recursive: false)
.child('Error', roleName: 'icon', retry: false)
@@ -164,7 +165,7 @@ Then /^I install "(.+)" using Synaptic$/ do |package_name|
$vm.execute("apt -y purge #{package_name}")
step "I start Synaptic"
end
- retry_tor(recovery_proc) do
+ try_tor(recovery_proc) do
@synaptic.button('Search').click
find_dialog = @synaptic.dialog('Find')
find_dialog.child(roleName: 'text').typeText(package_name)
@@ -175,11 +176,10 @@ Then /^I install "(.+)" using Synaptic$/ do |package_name|
package_entry.doubleClick
@synaptic.button('Apply').click
apply_prompt = nil
- try_for(60) { apply_prompt = @synaptic.dialog('Summary'); true }
+ try(timeout: 60) { apply_prompt = @synaptic.dialog('Summary') }
apply_prompt.button('Apply').click
- try_for(4*60) do
+ try(timeout: 4*60) do
@synaptic.child('Changes applied', roleName: 'frame', recursive: false)
- true
end
step 'I kill the process "synaptic"'
end
diff --git a/features/step_definitions/browser.rb b/features/step_definitions/browser.rb
index 78c11ff..89a264c 100644
--- a/features/step_definitions/browser.rb
+++ b/features/step_definitions/browser.rb
@@ -98,9 +98,9 @@ When /^I open the address "([^"]*)" in the (.*)$/ do |address, browser|
open_address.call
end
if browser == "Tor Browser"
- retry_method = method(:retry_tor)
+ retry_method = method(:try_tor)
else
- retry_method = Proc.new { |p, &b| retry_action(10, recovery_proc: p, &b) }
+ retry_method = Proc.new { |p, &b| try(attempts: 10, recovery_proc: p, &b) }
end
open_address.call
retry_method.call(recovery_on_failure) do
@@ -120,12 +120,12 @@ Then /^"([^"]+)" has loaded in the Tor Browser$/ do |title|
reload_action = 'Reload'
end
expected_title = "#{title} - #{browser_name}"
- try_for(60) { @torbrowser.child(expected_title, roleName: 'frame') }
+ try(timeout: 60) { @torbrowser.child(expected_title, roleName: 'frame') }
# The 'Reload' button (graphically shown as a looping arrow)
# is only shown when a page has loaded, so once we see the
# expected title *and* this button has appeared, then we can be sure
# that the page has fully loaded.
- try_for(60) { @torbrowser.child(reload_action, roleName: 'push button') }
+ try(timeout: 60) { @torbrowser.child(reload_action, roleName: 'push button') }
end
Then /^the (.*) has no plugins installed$/ do |browser|
@@ -170,9 +170,11 @@ end
Then /^the (.*) chroot is torn down$/ do |browser|
info = xul_application_info(browser)
- try_for(30, :msg => "The #{browser} chroot '#{info[:chroot]}' was " \
- "not removed") do
- !$vm.execute("test -d '#{info[:chroot]}'").success?
+ try_for_success(
+ timeout: 30,
+ message: "The #{browser} chroot '#{info[:chroot]}' was not removed"
+ ) do
+ $vm.execute("test -d '#{info[:chroot]}'").failure?
end
end
@@ -206,7 +208,7 @@ end
Then /^the file is saved to the default Tor Browser download directory$/ do
assert_not_nil(@some_file)
expected_path = "/home/#{LIVE_USER}/Tor Browser/#{@some_file}"
- try_for(10) { $vm.file_exist?(expected_path) }
+ try_for_success(timeout: 10) { $vm.file_exist?(expected_path) }
end
When /^I open Tails homepage in the (.+)$/ do |browser|
@@ -237,7 +239,7 @@ Then /^I can listen to an Ogg audio track in Tor Browser$/ do
end
step "no application is playing audio"
open_test_url.call
- retry_tor(recovery_on_failure) do
+ try_tor(recovery_on_failure) do
step "1 application is playing audio after 30 seconds"
end
end
@@ -254,7 +256,7 @@ Then /^I can watch a WebM video in Tor Browser$/ do
open_test_url.call
end
open_test_url.call
- retry_tor(recovery_on_failure) do
+ try_tor(recovery_on_failure) do
@screen.wait("TorBrowserSampleRemoteWebMVideoFrame.png", 30)
end
end
diff --git a/features/step_definitions/common_steps.rb b/features/step_definitions/common_steps.rb
index 4f5601a..eec0dbe 100644
--- a/features/step_definitions/common_steps.rb
+++ b/features/step_definitions/common_steps.rb
@@ -9,7 +9,7 @@ def post_vm_start_hook
end
def context_menu_helper(top, bottom, menu_item)
- try_for(60) do
+ try(timeout: 60) do
t = @screen.wait(top, 10)
b = @screen.wait(bottom, 10)
# In Sikuli, lower x == closer to the left, lower y == closer to the top
@@ -19,7 +19,6 @@ def context_menu_helper(top, bottom, menu_item)
@screen.right_click(center)
@screen.hide_cursor
@screen.wait_and_click(menu_item, 10)
- return
end
end
@@ -73,7 +72,10 @@ end
Then /^drive "([^"]+)" is detected by Tails$/ do |name|
raise "Tails is not running" unless $vm.is_running?
- try_for(20, :msg => "Drive '#{name}' is not detected by Tails") do
+ try_for_success(
+ timeout: 20,
+ message: "Drive '#{name}' is not detected by Tails"
+ ) do
$vm.disk_detected?(name)
end
end
@@ -88,7 +90,7 @@ end
Given /^the network connection is ready(?: within (\d+) seconds)?$/ do |timeout|
timeout ||= 30
- try_for(timeout.to_i) { $vm.has_network? }
+ try(timeout: timeout.to_i) { assert($vm.has_network?) }
end
Given /^the hardware clock is set to "([^"]*)"$/ do |time|
@@ -238,7 +240,7 @@ Given /^Tails is at the boot menu's cmdline( after rebooting)?$/ do |reboot|
dealt_with_uefi_setup = false
# The below code is not completely reliable, so we might have to
# retry by rebooting.
- try_for(boot_timeout) do
+ try(timeout: boot_timeout) do
begin
tab_spammer = IO.popen(['ruby', '-e', tab_spammer_code])
if not(dealt_with_uefi_setup) && @os_loader == 'UEFI'
@@ -259,7 +261,6 @@ Given /^Tails is at the boot menu's cmdline( after rebooting)?$/ do |reboot|
Process.kill("TERM", tab_spammer.pid)
tab_spammer.close
end
- true
end
end
@@ -322,7 +323,7 @@ end
Given /^Tails Greeter has applied all settings$/ do
# I.e. it is done with PostLogin, which is ensured to happen before
# a logind session is opened for LIVE_USER.
- try_for(120) {
+ try_for_success(timeout: 120) {
$vm.execute_successfully("loginctl").stdout
.match(/^\s*\S+\s+\d+\s+#{LIVE_USER}\s+seat\d+\s+\S+\s*$/) != nil
}
@@ -360,8 +361,8 @@ When /^I see the "(.+)" notification(?: after at most (\d+) seconds)?$/ do |titl
notification_list = gnome_shell.child(
'No Notifications', roleName: 'label', showingOnly: false
).parent.parent
- try_for(timeout) do
- notification_list.child?(title, roleName: 'label', showingOnly: false)
+ try(timeout: timeout) do
+ notification_list.child(title, roleName: 'label', showingOnly: false)
end
end
@@ -373,8 +374,10 @@ Given /^Tor is ready$/ do
if !$vm.file_exist?('/run/live-additional-software/doomed_to_fail')
step "the Additional Software upgrade service has started"
begin
- try_for(30) { $vm.execute('systemctl is-system-running').success? }
- rescue Timeout::Error
+ try_for_success(timeout: 30) do
+ $vm.execute('systemctl is-system-running').success?
+ end
+ rescue TryFailed
jobs = $vm.execute('systemctl list-jobs').stdout
units_status = $vm.execute('systemctl').stdout
raise "The system is not fully running yet:\n#{jobs}\n#{units_status}"
@@ -392,7 +395,9 @@ end
Given /^the time has synced$/ do
begin
["/run/tordate/done", "/run/htpdate/success"].each do |file|
- try_for(300) { $vm.execute("test -e #{file}").success? }
+ try_for_success(timeout: 300) do
+ $vm.execute("test -e #{file}").success?
+ end
end
rescue
File.open("#{$config["TMPDIR"]}/log.htpdate", 'w') do |file|
@@ -403,9 +408,9 @@ Given /^the time has synced$/ do
end
Given /^available upgrades have been checked$/ do
- try_for(300) {
+ try_for_success(timeout: 300) do
$vm.execute("test -e '/run/tails-upgrader/checked_upgrades'").success?
- }
+ end
end
When /^I start the Tor Browser( in offline mode)?$/ do |offline|
@@ -424,9 +429,9 @@ When /^I start the Tor Browser( in offline mode)?$/ do |offline|
end
Given /^the Tor Browser (?:has started|starts)( in offline mode)?$/ do |offline|
- try_for(60) do
+ try(timeout: 60) do
@torbrowser = Dogtail::Application.new('Firefox')
- @torbrowser.child?(roleName: 'frame', recursive: false)
+ @torbrowser.child(roleName: 'frame', recursive: false)
end
end
@@ -473,12 +478,12 @@ Given /^all notifications have disappeared$/ do
# bar, which when clicked opens the calendar.
x, y = 512, 10
gnome_shell = Dogtail::Application.new('gnome-shell')
- retry_action(10, recovery_proc: Proc.new { @screen.type(Sikuli::Key.ESC) }) do
+ try(attempts: 10, recovery_proc: Proc.new { @screen.type(Sikuli::Key.ESC) }) do
@screen.click_point(x, y)
unless gnome_shell.child?('No Notifications', roleName: 'label')
@screen.click('GnomeCloseAllNotificationsButton.png')
end
- gnome_shell.child?('No Notifications', roleName: 'label')
+ gnome_shell.child('No Notifications', roleName: 'label')
end
@screen.type(Sikuli::Key.ESC)
end
@@ -528,33 +533,34 @@ Given /^process "([^"]+)" is (not )?running$/ do |process, not_running|
end
Given /^process "([^"]+)" is running within (\d+) seconds$/ do |process, time|
- try_for(time.to_i, :msg => "Process '#{process}' is not running after " +
- "waiting for #{time} seconds") do
+ try_for_success(
+ timeout: time.to_i,
+ message: "Process '#{process}' is not running after waiting for #{time} seconds"
+ ) do
$vm.has_process?(process)
end
end
Given /^process "([^"]+)" has stopped running after at most (\d+) seconds$/ do |process, time|
- try_for(time.to_i, :msg => "Process '#{process}' is still running after " +
- "waiting for #{time} seconds") do
+ try_for_success(
+ timeout: time.to_i,
+ message: "Process '#{process}' is still running after waiting for #{time} seconds"
+ ) do
not $vm.has_process?(process)
end
end
Given /^I kill the process "([^"]+)"$/ do |process|
$vm.execute("killall #{process}")
- try_for(10, :msg => "Process '#{process}' could not be killed") {
- !$vm.has_process?(process)
- }
+ step "process \"#{process}\" has stopped running after at most 10 seconds"
end
Then /^Tails eventually (shuts down|restarts)$/ do |mode|
- try_for(3*60) do
+ try(timeout: 3*60) do
if mode == 'restarts'
@screen.find('TailsGreeter.png')
- true
else
- ! $vm.is_running?
+ assert(! $vm.is_running?)
end
end
end
@@ -620,7 +626,7 @@ EOF
"type ethernet autoconnect yes ifname eth0"
)
end
- try_for(10) {
+ try_for_success(timeout: 10) {
nm_con_list = $vm.execute("nmcli --terse --fields NAME connection show").stdout
nm_con_list.split("\n").include? "#{con_name}"
}
@@ -628,7 +634,7 @@ end
Given /^I switch to the "([^"]+)" NetworkManager connection$/ do |con_name|
$vm.execute("nmcli connection up id #{con_name}")
- try_for(60) do
+ try_for_success(timeout: 60) do
$vm.execute("nmcli --terse --fields NAME,STATE connection show").stdout.chomp.split("\n").include?("#{con_name}:activated")
end
end
@@ -649,12 +655,12 @@ end
When /^the file "([^"]+)" exists(?:| after at most (\d+) seconds)$/ do |file, timeout|
timeout = 0 if timeout.nil?
- try_for(
- timeout.to_i,
- :msg => "The file #{file} does not exist after #{timeout} seconds"
- ) {
+ try_for_success(
+ timeout: timeout.to_i,
+ message: "The file #{file} does not exist after #{timeout} seconds"
+ ) do
$vm.file_exist?(file)
- }
+ end
end
When /^the file "([^"]+)" does not exist$/ do |file|
@@ -750,7 +756,7 @@ Then /^there is a GNOME bookmark for the (amnesiac|persistent) Tor Browser direc
end
Then /^there is no GNOME bookmark for the persistent Tor Browser directory$/ do
- try_for(65) do
+ try(timeout: 65) do
@screen.wait_and_click('GnomePlaces.png', 10)
@screen.wait("GnomePlacesWithoutTorBrowserPersistent.png", 10)
@screen.type(Sikuli::Key.ESC)
@@ -773,7 +779,7 @@ When /^I double-click on the (Tails documentation|Report an Error) launcher on t
image = 'Desktop' + launcher.split.map { |s| s.capitalize } .join + '.png'
info = xul_application_info('Tor Browser')
# Sometimes the double-click is lost (#12131).
- retry_action(10) do
+ try(attempts: 10) do
@screen.wait_and_double_click(image, 10) if $vm.execute("pgrep --uid #{info[:user]} --full --exact '#{info[:cmd_regex]}'").failure?
step 'the Tor Browser has started'
end
@@ -801,9 +807,12 @@ When /^I (can|cannot) save the current page as "([^"]+[.]html)" to the (.*) dire
@screen.type(output_file.sub(/[.]html$/, ''))
@screen.type(Sikuli::Key.ENTER)
if should_work
- try_for(20, :msg => "The page was not saved to #{output_dir}/#{output_file}") {
+ try_for_success(
+ timeout: 20,
+ message: "The page was not saved to #{output_dir}/#{output_file}"
+ ) do
$vm.file_exist?("#{output_dir}/#{output_file}")
- }
+ end
else
@screen.wait("TorBrowserCannotSavePage.png", 10)
end
@@ -826,9 +835,12 @@ When /^I can print the current page as "([^"]+[.]pdf)" to the (default downloads
@screen.type('v', Sikuli::KeyModifier.CTRL)
@screen.type(Sikuli::Key.ENTER)
@screen.wait_and_click("Gtk3PrintButton.png", 10)
- try_for(30, :msg => "The page was not printed to #{output_dir}/#{output_file}") {
+ try_for_success(
+ timeout: 30,
+ message: "The page was not printed to #{output_dir}/#{output_file}"
+ ) do
$vm.file_exist?("#{output_dir}/#{output_file}")
- }
+ end
end
Given /^a web server is running on the LAN$/ do
@@ -859,7 +871,10 @@ Given /^a web server is running on the LAN$/ do
EOF
add_lan_host(@web_server_ip_addr, @web_server_port)
proc = IO.popen(['ruby', '-e', code])
- try_for(10, :msg => "It seems the LAN web server failed to start") do
+ try_for_success(
+ timeout: 10,
+ message: "It seems the LAN web server failed to start"
+ ) do
Process.kill(0, proc.pid) == 1
end
@@ -873,10 +888,13 @@ EOF
# more consistent result, so let's rely on that instead. Note that
# this forces us to capture traffic *after* this step in case
# accessing this server matters, like when testing the Tor Browser..
- try_for(30, :msg => "Something is wrong with the LAN web server") do
- msg = $vm.execute_successfully("curl #{@web_server_url}",
- :user => LIVE_USER).stdout.chomp
- web_server_hello_msg == msg
+ try_for_success(
+ timeout: 30,
+ message: "Something is wrong with the LAN web server"
+ ) do
+ content = $vm.execute_successfully("curl #{@web_server_url}",
+ :user => LIVE_USER).stdout.chomp
+ web_server_hello_msg == content
end
end
@@ -913,16 +931,15 @@ When /^AppArmor has (not )?denied "([^"]+)" from opening "([^"]+)"$/ do |anti_te
"'I monitor the AppArmor log of ...' step")
audit_line_regex = 'apparmor="DENIED" operation="open" profile="%s" name="%s"' % [profile, file]
begin
- try_for(10, { :delay => 1 }) {
+ try(timeout: 10, delay: 1 ) {
audit_log = $vm.execute(
"journalctl --full --no-pager " +
"--since='#{@apparmor_profile_monitoring_start[profile]}' " +
"SYSLOG_IDENTIFIER=kernel | grep -w '#{audit_line_regex}'"
).stdout.chomp
assert(audit_log.empty? == (anti_test ? true : false))
- true
}
- rescue Timeout::Error, Test::Unit::AssertionFailedError => e
+ rescue TryFailed, Test::Unit::AssertionFailedError => e
raise e, "AppArmor has #{anti_test ? "" : "not "}denied the operation"
end
end
diff --git a/features/step_definitions/electrum.rb b/features/step_definitions/electrum.rb
index 7188d4a..9263d98 100644
--- a/features/step_definitions/electrum.rb
+++ b/features/step_definitions/electrum.rb
@@ -15,7 +15,7 @@ Then /^I start Electrum through the GNOME menu$/ do
end
Then /^Electrum (?:has started|starts)$/ do
- try_for(60) do
+ try(timeout: 60) do
electrum_app
end
end
@@ -33,7 +33,7 @@ When /^a bitcoin wallet is (|not )present$/ do |existing|
end
Then /^I am prompted to (configure Electrum|enter my Electrum wallet password)$/ do |mode|
- try_for(30) do
+ try(timeout: 30) do
electrum_wizard.child('Electrum wallet', roleName: 'label')
end
case mode
@@ -92,7 +92,7 @@ end
Then /^Electrum successfully connects to the network$/ do
electrum_statusbar = electrum_main.child(roleName: 'status bar')
- try_for(180) do
+ try_for_success(timeout: 180) do
electrum_statusbar.children(roleName: 'label').any? do |n|
# The balance is shown iff we are connected.
n.name.start_with?('Balance: ')
diff --git a/features/step_definitions/encryption.rb b/features/step_definitions/encryption.rb
index 3b20a5b..a0b60c7 100644
--- a/features/step_definitions/encryption.rb
+++ b/features/step_definitions/encryption.rb
@@ -1,10 +1,9 @@
def seahorse_menu_click_helper(main, sub, verify = nil)
- try_for(60) do
+ try(timeout: 60) do
step "process \"#{verify}\" is running" if verify
@screen.hide_cursor
@screen.wait_and_click(main, 10)
@screen.wait_and_click(sub, 10)
- return
end
end
diff --git a/features/step_definitions/erase_memory.rb b/features/step_definitions/erase_memory.rb
index 5ba9487..b65bfd6 100644
--- a/features/step_definitions/erase_memory.rb
+++ b/features/step_definitions/erase_memory.rb
@@ -118,13 +118,20 @@ Given /^I fill the guest's memory with a known pattern and the allocating proces
:user => LIVE_USER)
end
# We make sure that all fillram processes have started...
- try_for(10, :msg => "all fillram processes didn't start", :delay => 0.1) do
+ try_for_success(
+ timeout: 10,
+ message: "all fillram processes didn't start",
+ :delay => 0.1
+ ) do
nr_fillram_procs = $vm.pidof("fillram").size
nr_instances == nr_fillram_procs
end
prev_used_ram_ratio = -1
# ... and that it finishes
- try_for(nr_instances*2*60, { :msg => "fillram didn't complete, probably the VM crashed" }) do
+ try_for_success(
+ timeout: nr_instances*2*60,
+ message: "fillram didn't complete, probably the VM crashed"
+ ) do
used_ram_ratio = (used_ram_in_MiB.to_f/@detected_ram_m)*100
# Round down to closest multiple of 10 to limit the logging a bit.
used_ram_ratio = (used_ram_ratio/10).round*10
diff --git a/features/step_definitions/evince.rb b/features/step_definitions/evince.rb
index 2baaebe..060ef9e 100644
--- a/features/step_definitions/evince.rb
+++ b/features/step_definitions/evince.rb
@@ -14,9 +14,12 @@ Then /^I can print the current document to "([^"]+)"$/ do |output_file|
@screen.type('v', Sikuli::KeyModifier.CTRL)
@screen.type(Sikuli::Key.ENTER)
@screen.wait_and_click("Gtk3PrintButton.png", 10)
- try_for(10, :msg => "The document was not printed to #{output_file}") {
+ try_for_success(
+ timeout: 10,
+ message: "The document was not printed to #{output_file}"
+ ) do
$vm.file_exist?(output_file)
- }
+ end
end
When /^I close Evince$/ do
diff --git a/features/step_definitions/git.rb b/features/step_definitions/git.rb
index bd8fcf7..e7137ca 100644
--- a/features/step_definitions/git.rb
+++ b/features/step_definitions/git.rb
@@ -9,15 +9,15 @@ When /^I clone the Git repository "([\S]+)" in GNOME Terminal$/ do |repo|
@screen.type('clear' + Sikuli::Key.ENTER)
end
- retry_tor(recovery_proc) do
+ try_tor(recovery_proc) do
step "I run \"git clone #{repo}\" in GNOME Terminal"
m = /^(https?|git):\/\//.match(repo)
unless m
step 'I verify the SSH fingerprint for the Git repository'
end
- try_for(180, :msg => 'Git process took too long') {
- !$vm.has_process?('/usr/bin/git')
- }
+ try_for_success(timeout: 180, message: 'Git process took too long') do
+ ! $vm.has_process?('/usr/bin/git')
+ end
Dogtail::Application.new('gnome-terminal-server')
.child('Terminal', roleName: 'terminal')
.text['Unpacking objects: 100%']
diff --git a/features/step_definitions/gnome.rb b/features/step_definitions/gnome.rb
index 40e84e9..a04774c 100644
--- a/features/step_definitions/gnome.rb
+++ b/features/step_definitions/gnome.rb
@@ -8,8 +8,11 @@ end
Then /^a screenshot is saved to the live user's Pictures directory$/ do
pictures_directory = "/home/#{LIVE_USER}/Pictures"
- try_for(10, :msg=> "No screenshot was created in #{pictures_directory}") do
- !$vm.execute(
+ try_for_success(
+ timeout: 10,
+ message: "No screenshot was created in #{pictures_directory}"
+ ) do
+ ! $vm.execute(
"find '#{pictures_directory}' -name 'Screenshot*.png' -maxdepth 1"
).stdout.empty?
end
diff --git a/features/step_definitions/mac_spoofing.rb b/features/step_definitions/mac_spoofing.rb
index c4d3372..55307c5 100644
--- a/features/step_definitions/mac_spoofing.rb
+++ b/features/step_definitions/mac_spoofing.rb
@@ -121,7 +121,7 @@ When /^I hotplug a network device( and wait for it to be initialized)?$/ do |wai
EOF
$vm.plug_device(xml)
if wait
- try_for(30) do
+ try_for_success(timeout: 30) do
all_ethernet_nics.size >= initial_nr_nics + 1
end
end
diff --git a/features/step_definitions/pidgin.rb b/features/step_definitions/pidgin.rb
index 37f42ab..72a5029 100644
--- a/features/step_definitions/pidgin.rb
+++ b/features/step_definitions/pidgin.rb
@@ -29,7 +29,7 @@ end
def focus_pidgin_irc_conversation_window(account)
account = account.sub(/^irc\./, '')
- try_for(20) do
+ try(timeout: 20) do
$vm.focus_window(".*#{Regexp.escape(account)}$")
end
end
@@ -101,7 +101,7 @@ end
Then /^Pidgin automatically enables my XMPP account$/ do
account = xmpp_account("Tails_account")
jid = account["username"] + '@' + account["domain"]
- try_for(3*60) do
+ try_for_success(timeout: 3*60) do
pidgin_account_connected?(jid, 'prpl-jabber')
end
$vm.focus_window('Buddy List')
@@ -157,7 +157,7 @@ Then /^I receive a response from my friend( in the multi-user chat)?$/ do |multi
else
$vm.focus_window(@friend_name)
end
- try_for(60) do
+ try(timeout: 60) do
if @screen.exists('PidginServerMessage.png')
@screen.click('PidginDialogCloseButton.png')
end
@@ -371,7 +371,7 @@ Then /^Pidgin successfully connects to the "([^"]+)" account$/ do |account|
deactivate_and_activate_pidgin_account(account)
end
end
- retry_tor(recovery_on_failure) do
+ try_tor(recovery_on_failure) do
begin
$vm.focus_window('Buddy List')
rescue ExecutionFailedInVM
@@ -418,7 +418,7 @@ Then /^I can join the( pre-configured)? "([^"]+)" channel on "([^"]+)"$/ do |pre
$vm.focus_window(@chat_room_jid)
end
@screen.hide_cursor
- try_for(60) do
+ try(timeout: 60) do
begin
@screen.wait_and_click(chan_image(account, channel, 'conversation_tab'), 5)
rescue FindFailed => e
@@ -503,7 +503,7 @@ When /^I close Pidgin's certificate import failure dialog$/ do
end
When /^I see the Tails roadmap URL$/ do
- try_for(60) do
+ try(timeout: 60) do
if @screen.exists('PidginServerMessage.png')
@screen.click('PidginDialogCloseButton.png')
end
@@ -518,7 +518,7 @@ end
When /^I click on the Tails roadmap URL$/ do
@screen.click('PidginTailsRoadmapUrl.png')
- try_for(60) { @torbrowser = Dogtail::Application.new('Firefox') }
+ try(timeout: 60) { @torbrowser = Dogtail::Application.new('Firefox') }
end
Then /^Pidgin's D-Bus interface is not available$/ do
diff --git a/features/step_definitions/root_access_control.rb b/features/step_definitions/root_access_control.rb
index 8362342..ba0ed59 100644
--- a/features/step_definitions/root_access_control.rb
+++ b/features/step_definitions/root_access_control.rb
@@ -26,9 +26,9 @@ end
Then /^I should be able to run a command as root with pkexec$/ do
step "I run \"pkexec touch /root/pkexec-test\" in GNOME Terminal"
step 'I enter the sudo password in the pkexec prompt'
- try_for(10, :msg => 'The /root/pkexec-test file was not created.') {
- $vm.execute('ls /root/pkexec-test').success?
- }
+ try(timeout: 10, message: 'The /root/pkexec-test file was not created.') do
+ $vm.execute_successfully('ls /root/pkexec-test').success?
+ end
end
Then /^I should not be able to run a command as root with pkexec and the standard passwords$/ do
diff --git a/features/step_definitions/ssh.rb b/features/step_definitions/ssh.rb
index 1fd0efa..b95984c 100644
--- a/features/step_definitions/ssh.rb
+++ b/features/step_definitions/ssh.rb
@@ -102,7 +102,7 @@ When /^I connect to an SSH server on the (Internet|LAN)$/ do |location|
step 'I run "clear" in GNOME Terminal'
end
- retry_tor(recovery_proc) do
+ try_tor(recovery_proc) do
step "I run \"#{cmd}\" in GNOME Terminal"
step 'process "ssh" is running within 10 seconds'
step 'I verify the SSH fingerprint for the SSH server'
@@ -124,7 +124,7 @@ Then /^I connect to an SFTP server on the Internet$/ do
step 'I kill the process "nautilus"'
end
- retry_tor(recovery_proc) do
+ try_tor(recovery_proc) do
step 'I start "Nautilus" via GNOME Activities Overview'
nautilus = Dogtail::Application.new('nautilus')
nautilus.child(roleName: 'frame')
@@ -140,8 +140,8 @@ Then /^I connect to an SFTP server on the Internet$/ do
end
Then /^I verify the SSH fingerprint for the SFTP server$/ do
- try_for(30) do
- Dogtail::Application.new('gnome-shell').child?('Log In Anyway')
+ try(timeout: 30) do
+ Dogtail::Application.new('gnome-shell').child('Log In Anyway')
end
# Here we'd like to click on the button using Dogtail, but something
# is buggy so let's just use the keyboard.
@@ -149,8 +149,8 @@ Then /^I verify the SSH fingerprint for the SFTP server$/ do
end
Then /^I successfully connect to the SFTP server$/ do
- try_for(60) do
+ try(timeout: 60) do
Dogtail::Application.new('nautilus')
- .child?("#{@sftp_username} on #{@sftp_host}")
+ .child("#{@sftp_username} on #{@sftp_host}")
end
end
diff --git a/features/step_definitions/thunderbird.rb b/features/step_definitions/thunderbird.rb
index 420dac4..489c2e4 100644
--- a/features/step_definitions/thunderbird.rb
+++ b/features/step_definitions/thunderbird.rb
@@ -33,7 +33,7 @@ When /^I start Thunderbird$/ do
$vm.file_append('/etc/thunderbird/pref/thunderbird.js', line)
end
step 'I start "Thunderbird" via GNOME Activities Overview'
- try_for(60) { thunderbird_main }
+ try(timeout: 60) { thunderbird_main }
end
When /^I have not configured an email account$/ do
@@ -98,7 +98,7 @@ When /^I enter my email credentials into the autoconfiguration wizard$/ do
thunderbird_wizard.child('Password:', roleName: 'entry').typeText(password)
thunderbird_wizard.button('Continue').click
# This button is shown if and only if a configuration has been found
- try_for(120) { thunderbird_wizard.button('Done') }
+ try(timeout: 120) { thunderbird_wizard.button('Done') }
end
Then /^the autoconfiguration wizard's choice for the (incoming|outgoing) server is secure (.+)$/ do |type, protocol|
@@ -117,31 +117,24 @@ When /^I fetch my email$/ do
thunderbird_main.child('Mail Toolbar', roleName: 'tool bar')
.button('Get Messages').click
- try_for(120) do
- begin
+ try(timeout: 120) do
+ assert_raise do
thunderbird_main.child(roleName: 'status bar', retry: false)
.child(roleName: 'progress bar', retry: false)
- false
- rescue
- true
end
end
end
When /^I accept the (?:autoconfiguration wizard's|manual) configuration$/ do
# The password check can fail due to bad Tor circuits.
- retry_tor do
- try_for(120) do
- begin
+ try_tor do
+ try(timeout: 120) do
+ assert_raise do
# Spam the button, even if it is disabled (while it is still
# testing the password).
thunderbird_wizard.button('Done').click
- false
- rescue
- true
end
end
- true
end
# The account isn't fully created before we fetch our mail. For
# instance, if we'd try to send an email before this, yet another
@@ -193,14 +186,14 @@ When /^I send an email to myself$/ do
.typeText('test')
compose_window.child('Composition Toolbar', roleName: 'tool bar')
.button('Send').click
- try_for(120) do
+ try_for_success(timeout: 120) do
not compose_window.exist?
end
end
Then /^I can find the email I sent to myself in my inbox$/ do
recovery_proc = Proc.new { step 'I fetch my email' }
- retry_tor(recovery_proc) do
+ try_tor(recovery_proc) do
thunderbird_inbox.click
filter = thunderbird_main.child('Filter these messages <Ctrl+Shift+K>',
roleName: 'entry')
diff --git a/features/step_definitions/tor.rb b/features/step_definitions/tor.rb
index 1e3a6b5..5566ff3 100644
--- a/features/step_definitions/tor.rb
+++ b/features/step_definitions/tor.rb
@@ -341,7 +341,7 @@ When /^I connect Gobby to "([^"]+)"$/ do |host|
connect_dialog.button('Connect').click
# This looks for the live user's presence entry in the chat, which
# will only be shown if the connection succeeded.
- try_for(60) { gobby.child(LIVE_USER, roleName: 'table cell'); true }
+ try(timeout: 60) { gobby.child(LIVE_USER, roleName: 'table cell') }
end
When /^the Tor Launcher autostarts$/ do
diff --git a/features/step_definitions/torified_gnupg.rb b/features/step_definitions/torified_gnupg.rb
index c762f71..1a3d1b8 100644
--- a/features/step_definitions/torified_gnupg.rb
+++ b/features/step_definitions/torified_gnupg.rb
@@ -66,7 +66,7 @@ When /^I fetch the "([^"]+)" OpenPGP key using the GnuPG CLI( without any signat
else
importopts = ''
end
- retry_tor(Proc.new { setup_onion_keyserver }) do
+ try_tor(Proc.new { setup_onion_keyserver }) do
@gnupg_recv_key_res = $vm.execute_successfully(
"timeout 120 gpg --batch #{importopts} --recv-key '#{@fetched_openpgp_keyid}'",
:user => LIVE_USER)
@@ -90,10 +90,14 @@ end
When /^the "([^"]+)" key is in the live user's public keyring(?: after at most (\d) seconds)?$/ do |keyid, delay|
delay = 10 unless delay
- try_for(delay.to_i, :msg => "The '#{keyid}' key is not in the live user's public keyring") {
- $vm.execute("gpg --batch --list-keys '#{keyid}'",
- :user => LIVE_USER).success?
- }
+ try(
+ timeout: delay.to_i,
+ message: "The '#{keyid}' key is not in the live user's public keyring"
+ ) do
+ $vm.execute_successfully(
+ "gpg --batch --list-keys '#{keyid}'", :user => LIVE_USER
+ )
+ end
end
When /^I start Seahorse( via the OpenPGP Applet)?$/ do |withgpgapplet|
@@ -144,7 +148,7 @@ Then /^I synchronize keys in Seahorse$/ do
end
end
- retry_tor(recovery_proc) do
+ try_tor(recovery_proc) do
@screen.wait_and_click("SeahorseWindow.png", 10)
seahorse_menu_click_helper('SeahorseRemoteMenu.png',
'SeahorseRemoteMenuSync.png',
@@ -152,9 +156,13 @@ Then /^I synchronize keys in Seahorse$/ do
@screen.wait('SeahorseSyncKeys.png', 20)
@screen.type("s", Sikuli::KeyModifier.ALT) # Button: Sync
# There's no visual feedback of Seahorse in Tails/Jessie, except on error.
- try_for(120) {
- change_of_status?
- }
+ try(timeout: 120) do
+ assert(
+ count_gpg_signatures(@fetched_openpgp_keyid) > 2 ||
+ @screen.exists('GnomeCloseButton.png') ||
+ !$vm.has_process?('seahorse')
+ )
+ end
check_for_seahorse_error
raise OpenPGPKeyserverCommunicationError.new(
'Seahorse crashed with a segfault.') unless $vm.has_process?('seahorse')
@@ -163,24 +171,12 @@ end
When /^I fetch the "([^"]+)" OpenPGP key using Seahorse( via the OpenPGP Applet)?$/ do |keyid, withgpgapplet|
step "I start Seahorse#{withgpgapplet}"
-
- def change_of_status?(keyid)
- # Due to a lack of visual feedback in Seahorse we'll break out of the
- # try_for loop below by returning "true" when there's something we can act
- # upon.
- if $vm.execute_successfully(
- "gpg --batch --list-keys '#{keyid}'", :user => LIVE_USER) ||
- @screen.exists('GnomeCloseButton.png')
- true
- end
- end
-
recovery_proc = Proc.new do
setup_onion_keyserver
@screen.click('GnomeCloseButton.png') if @screen.exists('GnomeCloseButton.png')
@screen.type("w", Sikuli::KeyModifier.CTRL)
end
- retry_tor(recovery_proc) do
+ try_tor(recovery_proc) do
@screen.wait_and_click("SeahorseWindow.png", 10)
seahorse_menu_click_helper('SeahorseRemoteMenu.png',
'SeahorseRemoteMenuFind.png',
@@ -203,10 +199,12 @@ When /^I fetch the "([^"]+)" OpenPGP key using Seahorse( via the OpenPGP Applet)
@screen.click("SeahorseKeyResultWindow.png")
@screen.click("SeahorseFoundKeyResult.png")
@screen.click("SeahorseImport.png")
- try_for(120) do
- change_of_status?(keyid)
+ try_for_success(timeout: 120) do
+ $vm.execute_successfully(
+ "gpg --batch --list-keys '#{keyid}'", :user => LIVE_USER
+ ) ||
+ @screen.exists('GnomeCloseButton.png')
end
- check_for_seahorse_error
end
end
diff --git a/features/step_definitions/torified_misc.rb b/features/step_definitions/torified_misc.rb
index 7ccdb22..ce01a59 100644
--- a/features/step_definitions/torified_misc.rb
+++ b/features/step_definitions/torified_misc.rb
@@ -1,7 +1,7 @@
require 'resolv'
When /^I query the whois directory service for "([^"]+)"$/ do |domain|
- retry_tor do
+ try_tor do
@vm_execute_res = $vm.execute("whois '#{domain}'", :user => LIVE_USER)
if @vm_execute_res.failure? || @vm_execute_res.stdout['LIMIT EXCEEDED']
raise "Looking up whois info for #{domain} failed with:\n" +
@@ -12,7 +12,7 @@ When /^I query the whois directory service for "([^"]+)"$/ do |domain|
end
When /^I wget "([^"]+)" to stdout(?:| with the '([^']+)' options)$/ do |target, options|
- retry_tor do
+ try_tor do
if target == "some Tails mirror"
host = 'dl.amnesia.boum.org'
address = Resolv.new.getaddresses(host).sample
diff --git a/features/step_definitions/totem.rb b/features/step_definitions/totem.rb
index a5b88d1..39ff509 100644
--- a/features/step_definitions/totem.rb
+++ b/features/step_definitions/totem.rb
@@ -37,7 +37,7 @@ Then /^I can watch a WebM video over HTTPs$/ do
recovery_on_failure = Proc.new do
step 'I close Totem'
end
- retry_tor(recovery_on_failure) do
+ try_tor(recovery_on_failure) do
step "I open \"#{test_url}\" with Totem"
@screen.wait("SampleRemoteWebMVideoFrame.png", 120)
end
diff --git a/features/step_definitions/unsafe_browser.rb b/features/step_definitions/unsafe_browser.rb
index 3f9f1b5..434c0c4 100644
--- a/features/step_definitions/unsafe_browser.rb
+++ b/features/step_definitions/unsafe_browser.rb
@@ -54,7 +54,7 @@ Then /^the Unsafe Browser has only Firefox's default bookmarks configured$/ do
path = "/home/#{info[:user]}/bookmarks"
@screen.type(path + Sikuli::Key.ENTER)
chroot_path = "#{info[:chroot]}/#{path}.json"
- try_for(10) { $vm.file_exist?(chroot_path) }
+ try_for_success(timeout: 10) { $vm.file_exist?(chroot_path) }
dump = JSON.load($vm.file_content(chroot_path))
def check_bookmarks_helper(a)
diff --git a/features/step_definitions/usb.rb b/features/step_definitions/usb.rb
index 7a8306d..4e93c27 100644
--- a/features/step_definitions/usb.rb
+++ b/features/step_definitions/usb.rb
@@ -150,7 +150,7 @@ When /^I start Tails Installer$/ do
end
When /^I am told by Tails Installer that.*"([^"]+)".*$/ do |status|
- try_for(10) do
+ try_for_success(timeout: 10) do
tails_installer_match_status(status)
end
end
@@ -162,7 +162,7 @@ Then /^a suitable USB device is (?:still )?not found$/ do
end
Then /^(no|the "([^"]+)") USB drive is selected$/ do |mode, name|
- try_for(30) do
+ try_for_success(timeout: 30) do
if mode == 'no'
tails_installer_selected_device == ''
else
@@ -175,7 +175,7 @@ When /^I (install|reinstall|upgrade) Tails (?:to|on) USB drive "([^"]+)" (by clo
step "I start Tails Installer"
# If the device was plugged *just* before this step, it might not be
# completely ready (so it's shown) at this stage.
- try_for(10) { tails_installer_is_device_selected?(name) }
+ try_for_success(timeout: 10) { tails_installer_is_device_selected?(name) }
if source == 'from an ISO'
iso_radio = @installer.child('Use a downloaded Tails ISO image',
roleName: 'radio button')
@@ -200,11 +200,10 @@ When /^I (install|reinstall|upgrade) Tails (?:to|on) USB drive "([^"]+)" (by clo
confirmation_label = 'Install'
end
@installer.child('Question', roleName: 'alert').button(confirmation_label).click
- try_for(15*60, { :delay => 10 }) do
+ try(timeout: 15*60, delay: 10) do
@installer
.child('Information', roleName: 'alert')
.child('Installation complete!', roleName: 'label')
- true
end
rescue Exception => e
debug_log("Tails Installer debug log:\n" +
@@ -412,7 +411,7 @@ end
Given /^all persistence presets(| from the old Tails version)(| but the first one) are enabled$/ do |old_tails, except_first|
assert(old_tails.empty? || except_first.empty?, "Unsupported case.")
- try_for(120, :msg => "Persistence is disabled") do
+ try_for_success(timeout: 120, message: "Persistence is disabled") do
tails_persistence_enabled?
end
unexpected_mounts = Array.new
@@ -804,7 +803,7 @@ Then /^I am proposed to install an incremental upgrade to version (.+)$/ do |ver
end
failure_pic = 'TailsUpgraderFailure.png'
success_pic = "TailsUpgraderUpgradeTo#{version}.png"
- retry_tor(recovery_proc) do
+ try_tor(recovery_proc) do
match, _ = @screen.waitAny([success_pic, failure_pic], 2*60)
assert_equal(success_pic, match)
end
@@ -823,7 +822,7 @@ Then /^I can successfully install the incremental upgrade to version (.+)$/ do |
end
failure_pic = 'TailsUpgraderFailure.png'
success_pic = 'TailsUpgraderDownloadComplete.png'
- retry_tor(recovery_proc) do
+ try_tor(recovery_proc) do
match, _ = @screen.waitAny([success_pic, failure_pic], 2*60)
assert_equal(success_pic, match)
end
diff --git a/features/step_definitions/veracrypt.rb b/features/step_definitions/veracrypt.rb
index 25b673d..03b4b89 100644
--- a/features/step_definitions/veracrypt.rb
+++ b/features/step_definitions/veracrypt.rb
@@ -116,8 +116,8 @@ When /^I unlock and mount this VeraCrypt (volume|file container) with Unlock Ver
@screen.click('VeraCryptUnlockDialogHiddenVolumeLabel.png') if @veracrypt_is_hidden
@screen.type(Sikuli::Key.ENTER)
@screen.waitVanish('VeraCryptUnlockDialog.png', 10)
- try_for(30) do
- $vm.execute_successfully('ls /media/amnesia/*/SecretFile')
+ try(timeout: 30) do
+ $vm.execute_successfully('ls /media/amnesia/*/SecretFile')
end
end
@@ -143,28 +143,16 @@ When /^I unlock and mount this VeraCrypt (volume|file container) with GNOME Disk
attach_dialog.child('Set up read-only loop device', roleName: 'check box').click
filter = attach_dialog.child('Disk Images (*.img, *.iso)', roleName: 'combo box')
filter.click
- try_for(5) do
- begin
- filter.child('All Files', roleName: 'menu item').click
- true
- rescue RuntimeError
- # we probably clicked too early, which triggered an "Attempting
- # to generate a mouse event at negative coordinates" Dogtail error
- false
- end
+ try(timeout: 5) do
+ filter.child('All Files', roleName: 'menu item').click
end
@screen.type(@veracrypt_shared_dir_in_guest + '/' + $veracrypt_volume_name)
sleep 2 # avoid ENTER being eaten by the auto-completion system
@screen.type(Sikuli::Key.ENTER)
- try_for(15) do
- begin
- disks.children(roleName: 'table cell').find { |row|
- /^105 MB Loop Device/.match(row.name)
- }.grabFocus
- true
- rescue NoMethodError
- false
- end
+ try(timeout: 15) do
+ disks.children(roleName: 'table cell').find do |row|
+ /^105 MB Loop Device/.match(row.name)
+ end.grabFocus
end
end
disks.child('', roleName: 'panel', description: 'Unlock selected encrypted partition').click
@@ -187,25 +175,18 @@ When /^I unlock and mount this VeraCrypt (volume|file container) with GNOME Disk
# (that sometimes clicks just a little bit outside of the button)
@screen.wait('Gtk3UnlockButton.png', 10)
@screen.type('u', Sikuli::KeyModifier.ALT) # "Unlock" button
- try_for(10, :msg => "Failed to mount the unlocked volume") do
- begin
- unlocked_volume = disks.child('105 MB VeraCrypt/TrueCrypt', roleName: 'panel', showingOnly: true)
- unlocked_volume.click
- # Move the focus down to the "Filesystem\n107 MB FAT" item (that Dogtail
- # is not able to find) using the 'Down' arrow, in order to display
- # the "Mount selected partition" button.
- unlocked_volume.grabFocus()
- sleep 0.5 # otherwise the following key press is sometimes lost
- disks.pressKey('Down')
- disks.child('', roleName: 'panel', description: 'Mount selected partition', showingOnly: true).click
- true
- rescue RuntimeError
- # we probably did something too early, which triggered a Dogtail error
- # such as "Attempting to generate a mouse event at negative coordinates"
- false
- end
+ try(timeout: 10, message: "Failed to mount the unlocked volume") do
+ unlocked_volume = disks.child('105 MB VeraCrypt/TrueCrypt', roleName: 'panel', showingOnly: true)
+ unlocked_volume.click
+ # Move the focus down to the "Filesystem\n107 MB FAT" item (that Dogtail
+ # is not able to find) using the 'Down' arrow, in order to display
+ # the "Mount selected partition" button.
+ unlocked_volume.grabFocus()
+ sleep 0.5 # otherwise the following key press is sometimes lost
+ disks.pressKey('Down')
+ disks.child('', roleName: 'panel', description: 'Mount selected partition', showingOnly: true).click
end
- try_for(10, :msg => "/media/amnesia/*/SecretFile does not exist") do
+ try(timeout: 10, message: "/media/amnesia/*/SecretFile does not exist") do
$vm.execute_successfully('ls /media/amnesia/*/SecretFile')
end
end
diff --git a/features/support/helpers/display.rb b/features/support/helpers/display.rb
index b4dce73..219970f 100644
--- a/features/support/helpers/display.rb
+++ b/features/support/helpers/display.rb
@@ -25,9 +25,13 @@ class Display
# We wait for the display to be active to not lose actions
# (e.g. key presses via sikuli) that come immediately after
# starting (or restoring) a vm
- try_for(20, { :delay => 0.1, :msg => "virt-viewer failed to start"}) {
+ try_for_success(
+ timeout: 20,
+ message: "virt-viewer failed to start",
+ delay: 0.1
+ ) do
active?
- }
+ end
end
def stop
diff --git a/features/support/helpers/misc.rb b/features/support/helpers/misc.rb
index 8052c63..53e697b 100644
--- a/features/support/helpers/misc.rb
+++ b/features/support/helpers/misc.rb
@@ -8,8 +8,10 @@ class TorBootstrapFailure < StandardError
end
def wait_until_tor_is_working
- try_for(270) { $vm.execute('/usr/local/sbin/tor-has-bootstrapped').success? }
-rescue Timeout::Error
+ try(timeout: 270) do
+ $vm.execute_successfully('/usr/local/sbin/tor-has-bootstrapped')
+ end
+rescue TryFailed
# Save Tor logs before erroring out
File.open("#{$config["TMPDIR"]}/log.tor", 'w') { |file|
file.write("#{$vm.execute('journalctl --no-pager -u tor@default.service').stdout}")
diff --git a/features/support/helpers/remote_shell.rb b/features/support/helpers/remote_shell.rb
index aea20dc..9f5ceba 100644
--- a/features/support/helpers/remote_shell.rb
+++ b/features/support/helpers/remote_shell.rb
@@ -7,10 +7,6 @@ module RemoteShell
class ServerFailure < StandardError
end
- # Used to differentiate vs Timeout::Error, which is thrown by
- # try_for() (by default) and often wraps around remote shell usage
- # -- in that case we don't want to catch that "outer" exception in
- # our handling of remote shell timeouts below.
class Timeout < ServerFailure
end
diff --git a/features/support/helpers/try.rb b/features/support/helpers/try.rb
index bec33c4..4d4dea7 100644
--- a/features/support/helpers/try.rb
+++ b/features/support/helpers/try.rb
@@ -1,30 +1,55 @@
require 'timeout'
+class TryFailed < StandardError
+end
+
# It's forbidden to throw this exception (or subclasses) in anything
-# but try_for() below. Just don't use it anywhere else!
-class UniqueTryForTimeoutError < Exception
+# but try() below. Just don't use it anywhere else!
+class UniqueTryTimeoutError < Exception
end
-# Call block (ignoring any exceptions it may throw) repeatedly with
-# one second breaks until it returns true, or until `timeout` seconds have
-# passed when we throw a Timeout::Error exception. If `timeout` is `nil`,
-# then we just run the code block with no timeout.
-def try_for(timeout, options = {})
- if block_given? && timeout.nil?
- return yield
+# Attempt to execute `block` without it throwing any exceptions,
+# retrying whenever one is encountered. Stop this attempt as soon as
+# one of the conditions `timeout` (in seconds) or `attempts` (maximum
+# number of attempts) are reached, by throwing a TryFailed exception.
+# Return the result of the block whenever it manages to return.
+# Flags:
+# - timeout: abort after this many seconds
+# - attempts: abort after this many attempts
+# - delay: wait this long between each attempt (default: 1 second)
+# - exception: which exception class to throw on failure
+# (default: TryFailed)
+# - message: custom message for the exception thrown on failure
+# (default message indicates which condition failed)
+# - operation_name: used to improve the default exception message on
+# an "attempts failure".
+# - recovery_proc: run this method after each failure (used to revert
+# back to the initial conditions before running the code block)
+def try(options, &block)
+ if options[:timeout].nil? && options[:attempts].nil?
+ raise "at least one of the 'timeout' and 'attempts' options must be set"
end
+ # Passing 0 to Timeout::timeout() means "no timeout, just execute
+ # the block"
+ options[:timeout] ||= 0
+ options[:attempts] ||= nil
options[:delay] ||= 1
+ options[:exception] ||= TryFailed
+ options[:operation_name] ||= 'Operation'
+ options[:recovery_proc] ||= nil
+
+ attempt = 1
last_exception = nil
- # Create a unique exception used only for this particular try_for
- # call's Timeout to allow nested try_for:s. If we used the same one,
- # the innermost try_for would catch all outer ones', creating a
+ # Create a unique exception used only for this particular try()
+ # call's Timeout to allow nested try():s. If we used the same one,
+ # the innermost try() would catch all outer ones', creating a
# really strange situation.
- unique_timeout_exception = Class.new(UniqueTryForTimeoutError)
- Timeout::timeout(timeout, unique_timeout_exception) do
+ unique_timeout_exception = Class.new(UniqueTryTimeoutError)
+ Timeout::timeout(options[:timeout], unique_timeout_exception) do
loop do
begin
- return if yield
- rescue NameError, UniqueTryForTimeoutError => e
+ return block.call
+ rescue NameError, UniqueTryTimeoutError => e
# NameError most likely means typos, and hiding that is rarely
# (never?) a good idea, so we rethrow them. See below why we
# also rethrow *all* the unique exceptions.
@@ -35,42 +60,59 @@ def try_for(timeout, options = {})
# case of a timeout.
last_exception = e
end
+ # The block must have thrown an exception, otherwise we would
+ # have returned by now.
+ if not(options[:attempts].nil?)
+ if attempt <= options[:attempts]
+ debug_log("#{options[:operation_name]} failed (Try #{attempt} of " +
+ "#{options[:attempts]}) with:\n" +
+ "#{last_exception.class}: #{last_exception.message}")
+ attempt += 1
+ else
+ options[:messasge] ||=
+ "#{options[:operation_name]} failed (despite retrying " +
+ "#{options[:attempts]} times) with\n" +
+ "#{last_exception.class}: #{last_exception.message}"
+ raise options[:exception].new(options[:messasge])
+ end
+ end
sleep options[:delay]
+ options[:recovery_proc].call if options[:recovery_proc]
end
end
# At this point the block above either succeeded and we'll return,
# or we are throwing an exception. If the latter, we either have a
- # NameError that we'll not catch (and will any try_for below us in
- # the stack), or we have a unique exception. That can mean one of
- # two things:
- # 1. it's the one unique to this try_for, and in that case we'll
+ # NameError that we'll not catch (and neither will any try() below
+ # us in the stack), or we have a unique exception. That can mean one
+ # of two things:
+ # 1. it's the one unique to this try(), and in that case we'll
# catch it, rethrowing it as something that will be ignored by
- # inside the blocks of all try_for:s below us in the stack.
- # 2. it's an exception unique to another try_for. Assuming that we
+ # the blocks of all try():s below us in the stack.
+ # 2. it's an exception unique to another try(). Assuming that we
# do not throw the unique exceptions in any other place or way
# than we do it in this function, this means that there is a
- # try_for below us in the stack to which this exception must be
+ # try() below us in the stack to which this exception must be
# unique to.
# Let 1 be the base step, and 2 the inductive step, and we sort of
- # an inductive proof for the correctness of try_for when it's
- # nested. It shows that for an infinite stack of try_for:s, any of
- # the unique exceptions will be caught only by the try_for instance
- # it is unique to, and all try_for:s in between will ignore it so it
+ # have an inductive proof for the correctness of try() when it's
+ # nested. It shows that for an infinite stack of try():s, any of
+ # the unique exceptions will be caught only by the try() instance
+ # it is unique to, and all try():s in between will ignore it so it
# ends up there immediately.
-rescue unique_timeout_exception => e
- msg = options[:msg] || 'try_for() timeout expired'
- exc_class = options[:exception] || Timeout::Error
- if last_exception
- msg += "\nLast ignored exception was: " +
- "#{last_exception.class}: #{last_exception}"
- end
- raise exc_class.new(msg)
+rescue unique_timeout_exception
+ options[:message] ||= "timeout expired! Last ignored exception was: " +
+ "#{last_exception.class}: #{last_exception}"
+ raise options[:exception].new(options[:message])
end
-class TorFailure < StandardError
+# Analog to try(), where we the block *also* has to evaluate as
+# something Ruby interprets as "true" (i.e. anything except false and
+# nil).
+def try_for_success(options, &block)
+ try(options) { assert(block.call) }
end
-class MaxRetriesFailure < StandardError
+class TorFailure < StandardError
end
def force_new_tor_circuit()
@@ -91,45 +133,16 @@ end
# as a failure. After a failure recovery_proc will be called (if
# given) and the intention with it is to bring us back to the state
# expected by the block, so it can be retried.
-def retry_tor(recovery_proc = nil, &block)
+def try_tor(recovery_proc = nil, options = {}, &block)
tor_recovery_proc = Proc.new do
force_new_tor_circuit
recovery_proc.call if recovery_proc
end
-
- retry_action($config['MAX_NEW_TOR_CIRCUIT_RETRIES'],
- :recovery_proc => tor_recovery_proc,
- :operation_name => 'Tor operation', &block)
+ try(
+ attempts: $config['MAX_NEW_TOR_CIRCUIT_RETRIES'],
+ recovery_proc: tor_recovery_proc,
+ operation_name: 'Tor operation',
+# **options,
+ &block
+ )
end
-
-def retry_action(max_retries, options = {}, &block)
- assert(max_retries.is_a?(Integer), "max_retries must be an integer")
- options[:recovery_proc] ||= nil
- options[:operation_name] ||= 'Operation'
-
- retries = 1
- loop do
- begin
- block.call
- return
- rescue NameError => e
- # NameError most likely means typos, and hiding that is rarely
- # (never?) a good idea, so we rethrow them.
- raise e
- rescue Exception => e
- if retries <= max_retries
- debug_log("#{options[:operation_name]} failed (Try #{retries} of " +
- "#{max_retries}) with:\n" +
- "#{e.class}: #{e.message}")
- options[:recovery_proc].call if options[:recovery_proc]
- retries += 1
- else
- raise MaxRetriesFailure.new("#{options[:operation_name]} failed (despite retrying " +
- "#{max_retries} times) with\n" +
- "#{e.class}: #{e.message}")
- end
- end
- end
-end
-
-alias :retry_times :retry_action
diff --git a/features/support/helpers/vm.rb b/features/support/helpers/vm.rb
index 13ad4e2..7e2dc07 100644
--- a/features/support/helpers/vm.rb
+++ b/features/support/helpers/vm.rb
@@ -458,7 +458,7 @@ class VM
end
def wait_until_remote_shell_is_up(timeout = 90)
- try_for(timeout, :msg => "Remote shell seems to be down") do
+ try_for_success(timeout: timeout, message: "Remote shell seems to be down") do
remote_shell_is_up?
end
end