summaryrefslogtreecommitdiffstats
path: root/cucumber/features/support/helpers/misc_helpers.rb
diff options
context:
space:
mode:
Diffstat (limited to 'cucumber/features/support/helpers/misc_helpers.rb')
-rw-r--r--cucumber/features/support/helpers/misc_helpers.rb344
1 files changed, 0 insertions, 344 deletions
diff --git a/cucumber/features/support/helpers/misc_helpers.rb b/cucumber/features/support/helpers/misc_helpers.rb
deleted file mode 100644
index 865d2978..00000000
--- a/cucumber/features/support/helpers/misc_helpers.rb
+++ /dev/null
@@ -1,344 +0,0 @@
-require 'date'
-require 'io/console'
-require 'pry'
-require 'timeout'
-require 'test/unit'
-
-# Test::Unit adds an at_exit hook which, among other things, consumes
-# the command-line arguments that were intended for cucumber. If
-# e.g. `--format` was passed it will throw an error since it's not a
-# valid option for Test::Unit, and it throwing an error at this time
-# (at_exit) will make Cucumber think it failed and consequently exit
-# with an error. Fooling Test::Unit that this hook has already run
-# works around this craziness.
-Test::Unit.run = true
-
-# Make all the assert_* methods easily accessible in any context.
-include Test::Unit::Assertions
-
-def assert_vmcommand_success(p, msg = nil)
- assert(p.success?, msg.nil? ? "Command failed: #{p.cmd}\n" + \
- "error code: #{p.returncode}\n" \
- "stderr: #{p.stderr}" : \
- msg)
-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
-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
- end
- options[:delay] ||= 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
- # really strange situation.
- unique_timeout_exception = Class.new(UniqueTryForTimeoutError)
- Timeout::timeout(timeout, unique_timeout_exception) do
- loop do
- begin
- return if yield
- rescue NameError, UniqueTryForTimeoutError => 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.
- raise e
- rescue Exception => e
- # All other exceptions are ignored while trying the
- # block. Well we save the last exception so we can print it in
- # case of a timeout.
- last_exception = e
- end
- sleep options[:delay]
- 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
- # 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
- # 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
- # 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
- # 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)
-end
-
-class TorFailure < StandardError
-end
-
-class MaxRetriesFailure < StandardError
-end
-
-def force_new_tor_circuit()
- debug_log("Forcing new Tor circuit...")
- # Tor rate limits NEWNYM to at most one per 10 second period.
- interval = 10
- if $__last_newnym
- elapsed = Time.now - $__last_newnym
- # We sleep an extra second to avoid tight timings.
- sleep interval - elapsed + 1 if 0 < elapsed && elapsed < interval
- end
- $vm.execute_successfully('tor_control_send "signal NEWNYM"', :libs => 'tor')
- $__last_newnym = Time.now
-end
-
-# This will retry the block up to MAX_NEW_TOR_CIRCUIT_RETRIES
-# times. The block must raise an exception for a run to be considered
-# 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)
- 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)
-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
-
-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
- raise TorBootstrapFailure.new('Tor failed to bootstrap')
-end
-
-def convert_bytes_mod(unit)
- case unit
- when "bytes", "b" then mod = 1
- when "KB" then mod = 10**3
- when "k", "KiB" then mod = 2**10
- when "MB" then mod = 10**6
- when "M", "MiB" then mod = 2**20
- when "GB" then mod = 10**9
- when "G", "GiB" then mod = 2**30
- when "TB" then mod = 10**12
- when "T", "TiB" then mod = 2**40
- else
- raise "invalid memory unit '#{unit}'"
- end
- return mod
-end
-
-def convert_to_bytes(size, unit)
- return (size*convert_bytes_mod(unit)).to_i
-end
-
-def convert_to_MiB(size, unit)
- return (size*convert_bytes_mod(unit) / (2**20)).to_i
-end
-
-def convert_from_bytes(size, unit)
- return size.to_f/convert_bytes_mod(unit).to_f
-end
-
-def cmd_helper(cmd, env = {})
- if cmd.instance_of?(Array)
- cmd << {:err => [:child, :out]}
- elsif cmd.instance_of?(String)
- cmd += " 2>&1"
- end
- env = ENV.to_h.merge(env)
- IO.popen(env, cmd) do |p|
- out = p.readlines.join("\n")
- p.close
- ret = $?
- assert_equal(0, ret, "Command failed (returned #{ret}): #{cmd}:\n#{out}")
- return out
- end
-end
-
-def all_tor_hosts
- nodes = Array.new
- chutney_torrcs = Dir.glob(
- "#{$config['TMPDIR']}/chutney-data/nodes/*/torrc"
- )
- chutney_torrcs.each do |torrc|
- open(torrc) do |f|
- nodes += f.grep(/^(Or|Dir)Port\b/).map do |line|
- { address: $vmnet.bridge_ip_addr, port: line.split.last.to_i }
- end
- end
- end
- return nodes
-end
-
-def allowed_hosts_under_tor_enforcement
- all_tor_hosts + @lan_hosts
-end
-
-def get_free_space(machine, path)
- case machine
- when 'host'
- assert(File.exists?(path), "Path '#{path}' not found on #{machine}.")
- free = cmd_helper(["df", path])
- when 'guest'
- assert($vm.file_exist?(path), "Path '#{path}' not found on #{machine}.")
- free = $vm.execute_successfully("df '#{path}'")
- else
- raise 'Unsupported machine type #{machine} passed.'
- end
- output = free.split("\n").last
- return output.match(/[^\s]\s+[0-9]+\s+[0-9]+\s+([0-9]+)\s+.*/)[1].chomp.to_i
-end
-
-def random_string_from_set(set, min_len, max_len)
- len = (min_len..max_len).to_a.sample
- len ||= min_len
- (0..len-1).map { |n| set.sample }.join
-end
-
-def random_alpha_string(min_len, max_len = 0)
- alpha_set = ('A'..'Z').to_a + ('a'..'z').to_a
- random_string_from_set(alpha_set, min_len, max_len)
-end
-
-def random_alnum_string(min_len, max_len = 0)
- alnum_set = ('A'..'Z').to_a + ('a'..'z').to_a + (0..9).to_a.map { |n| n.to_s }
- random_string_from_set(alnum_set, min_len, max_len)
-end
-
-# Sanitize the filename from unix-hostile filename characters
-def sanitize_filename(filename, options = {})
- options[:replacement] ||= '_'
- bad_unix_filename_chars = Regexp.new("[^A-Za-z0-9_\\-.,+:]")
- filename.gsub(bad_unix_filename_chars, options[:replacement])
-end
-
-def info_log_artifact_location(type, path)
- if $config['ARTIFACTS_BASE_URI']
- # Remove any trailing slashes, we'll add one ourselves
- base_url = $config['ARTIFACTS_BASE_URI'].gsub(/\/*$/, "")
- path = "#{base_url}/#{File.basename(path)}"
- end
- info_log("#{type.capitalize}: #{path}")
-end
-
-def notify_user(message)
- alarm_script = $config['NOTIFY_USER_COMMAND']
- return if alarm_script.nil? || alarm_script.empty?
- cmd_helper(alarm_script.gsub('%m', message))
-end
-
-def pause(message = "Paused")
- notify_user(message)
- STDERR.puts
- STDERR.puts message
- # Ring the ASCII bell for a helpful notification in most terminal
- # emulators.
- STDOUT.write "\a"
- STDERR.puts
- loop do
- STDERR.puts "Return: Continue; d: Debugging REPL"
- c = STDIN.getch
- case c
- when "\r"
- return
- when "d"
- binding.pry(quiet: true)
- end
- end
-end
-
-def dbus_send(service, object_path, method, *args, **opts)
- opts ||= {}
- ruby_type_to_dbus_type = {
- String => 'string',
- Fixnum => 'int32',
- }
- typed_args = args.map do |arg|
- type = ruby_type_to_dbus_type[arg.class]
- assert_not_nil(type, "No DBus type conversion for Ruby type '#{arg.class}'")
- "#{type}:#{arg}"
- end
- ret = $vm.execute_successfully(
- "dbus-send --print-reply --dest=#{service} #{object_path} " +
- " #{method} #{typed_args.join(' ')}",
- **opts
- ).stdout.lines
- # The first line written is about timings and other stuff we don't
- # care about; we only care about the return values.
- ret.shift
- ret.map! do |s|
- type, val = /^\s*(\S+)\s+(\S+)$/.match(s)[1,2]
- case type
- when 'string'
- # Unquote
- val[1, val.length - 2]
- when 'int32'
- val.to_i
- else
- raise "No Ruby type conversion for DBus type '#{type}'"
- end
- end
- if ret.size == 0
- return nil
- elsif ret.size == 1
- return ret.first
- else
- return ret
- end
-end