require 'net/http' require 'honeydew/device_matchers' require 'honeydew/device_actions' require 'honeydew/device_log_formatter' module Honeydew class Device include Honeydew::DeviceActions include Honeydew::DeviceMatchers include Honeydew::DeviceLogFormatter ServerTimeoutError = Class.new(Timeout::Error) ActionFailedError = Class.new(RuntimeError) attr_reader :serial, :port def initialize(serial) @serial = serial unless Honeydew.attached_devices.include?(@serial) raise ArgumentError, "No device with serial #{@serial} attached" end @port = Honeydew.config.obtain_new_port start_honeydew_server end def using_timeout timeout old_timeout = Honeydew.config.timeout Honeydew.config.timeout = timeout yield ensure Honeydew.config.timeout = old_timeout end private def perform_assertion action, arguments = {}, options = {} perform_action action, arguments, options rescue ActionFailedError false end def perform_action action, arguments = {}, options = {} ensure_device_ready arguments[:timeout] = Honeydew.config.timeout.to_s debug "performing action #{action} with arguments #{arguments}" send_command action, arguments end def send_command action, arguments uri = device_endpoint('/command') request = Net::HTTP::Post.new uri.path request.set_form_data action: action, arguments: arguments.to_json.to_s response = benchmark do Net::HTTP.start(uri.hostname, uri.port) do |http| http.read_timeout = Honeydew.config.server_timeout response = http.request request {response: response, action: action} end end case response when Net::HTTPOK info "action succeeded, response: #{response.body}" response.body when Net::HTTPNoContent info "action failed, response: #{response.body}" raise ActionFailedError.new "Action #{action} called with arguments #{arguments.inspect} failed" else raise "honeydew-server failed to process command, response: #{response.body}" end end def benchmark result = nil realtime = Benchmark.realtime do result = yield end debug "action '#{result[:action]}' completed in #{(realtime * 1000).to_i}ms" result[:response] end def ensure_device_ready @device_ready ||= begin wait_for_honeydew_server true end end def wait_for_honeydew_server info 'waiting for honeydew-server to respond' Timeout.timeout(Honeydew.config.server_timeout.to_i, ServerTimeoutError) do Kernel.sleep 0.1 until honeydew_server_alive? end info 'honeydew-server is alive and awaiting commands' rescue ServerTimeoutError raise 'timed out waiting for honeydew-server to respond' end def honeydew_server_alive? Net::HTTP.get_response(device_endpoint('/status')).is_a?(Net::HTTPSuccess) rescue Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::ETIMEDOUT, Errno::ENETRESET, EOFError end end end