lib/calabash/android/device.rb in calabash-2.0.0.pre11 vs lib/calabash/android/device.rb in calabash-2.0.0.prelegacy
- old
+ new
@@ -3,14 +3,10 @@
module Calabash
module Android
# A representation of a Calabash Android device.
# @!visibility private
class Device < ::Calabash::Device
- require 'calabash/android/device/helper_application'
-
- include Calabash::Android::Device::HelperApplication
-
attr_reader :adb
def initialize(identifier, server)
super
@adb = ADB.new(identifier)
@@ -68,41 +64,41 @@
end
end
# @!visibility private
def installed_packages
- installed_apps.map{|e| e[:package]}
+ adb.shell('pm list packages').lines.map do |line|
+ line.sub('package:', '').chomp
+ end
end
# @!visibility private
def installed_apps
- @installed_apps_cache ||= lambda do
- adb.shell('pm list packages -f').lines.map do |line|
- # line will be package:<path>=<package>
- # e.g. "package:/system/app/GoogleEars.apk=com.google.android.ears"
- info = line.sub("package:", "")
+ adb.shell('pm list packages -f').lines.map do |line|
+ # line will be package:<path>=<package>
+ # e.g. "package:/system/app/GoogleEars.apk=com.google.android.ears"
+ info = line.sub("package:", "")
- app_path, app_id = info.split('=').map(&:chomp)
+ app_path, app_id = info.split('=').map(&:chomp)
- {package: app_id, path: app_path}
- end
- end.call
+ {package: app_id, path: app_path}
+ end
end
# @!visibility private
def test_server_responding?
begin
- http_client.post(HTTP::Request.new('ping'), retries: 1).body == 'pong'
+ http_client.get(HTTP::Request.new('ping'), retries: 1).body == 'pong'
rescue HTTP::Error => _
false
end
end
# @!visibility private
def test_server_ready?
begin
- http_client.post(HTTP::Request.new('ready')).body == 'true'
+ http_client.get(HTTP::Request.new('ready')).body == 'true'
rescue HTTP::Error => _
false
end
end
@@ -168,13 +164,13 @@
parameters = make_map_parameters(query, method_name, *method_args)
request = HTTP::Request.new('map', params_for_request(parameters))
http_result = if method_name == :flash
- http_client.post(request, timeout: 30)
+ http_client.get(request, timeout: 30)
else
- http_client.post(request)
+ http_client.get(request)
end
result = JSON.parse(http_result.body)
if result['outcome'] != 'SUCCESS'
@@ -187,13 +183,13 @@
# @!visibility private
def perform_action(action, *arguments)
@logger.log "Action: #{action} - Arguments: #{arguments.join(', ')}"
parameters = {command: action, arguments: arguments}
- request = HTTP::Request.new('', params_for_request(parameters))
+ request = HTTP::Request.new('/', params_for_request(parameters))
- result = JSON.parse(http_client.post(request).body)
+ result = JSON.parse(http_client.get(request).body)
unless result['success']
message = result['message'] || result['bonusInformation']
if message.is_a?(Array)
@@ -214,21 +210,10 @@
def enter_text(text)
perform_action('keyboard_enter_text', text)
end
# @!visibility private
- def md5_checksum_for_app_package(package)
- app = installed_apps.find{|app| app[:package] == package}
-
- unless app
- raise "Application with package '#{app}' not installed"
- end
-
- md5_checksum(app[:path])
- end
-
- # @!visibility private
def md5_checksum(file_path)
result = adb.shell("#{md5_binary} '#{file_path}'")
captures = result.match(/(\w+)/).captures
if captures.length != 1
@@ -242,11 +227,11 @@
def backdoor(method, *arguments)
parameters = {method_name: method, arguments: arguments}
json = parameters.to_json
request = HTTP::Request.new('/backdoor', json: json)
- body = http_client.post(request).body
+ body = http_client.get(request).body
result = JSON.parse(body)
if result['outcome'] != 'SUCCESS'
details = if result['detail'].nil? || result['detail'].empty?
''
@@ -379,11 +364,11 @@
}
json = parameters.to_json
request = HTTP::Request.new('/map', json: json)
- body = http_client.post(request).body
+ body = http_client.get(request).body
result = JSON.parse(body)
if result['outcome'] != 'SUCCESS'
if result['results']
parsed_result = result['results'].map {|r| "\"#{r}\","}.join("\n")
@@ -422,79 +407,29 @@
def adb_file_exists?(file)
cmd = "ls #{file}"
adb.shell(cmd, no_exit_code_check: true).chomp == file
end
- def file_exists?(file)
- ensure_helper_application_started
-
- request = HTTP::Request.new('file-exists', params_for_request(fileName: file))
- response = helper_application_http_client.post(request)
-
- if response.status != 200
- result = JSON.parse(response.body)
- raise "Failed to find out if file exists #{result['reason']}"
- end
-
- case response.body
- when 'true'
- return true
- when 'false'
- return false
- else
- raise "Invalid resposne '#{response.body}'"
- end
- end
-
- def read_file(file)
- ensure_helper_application_started
-
- request = HTTP::Request.new('read-file', params_for_request(fileName: file))
- response = helper_application_http_client.post(request)
-
- if response.status != 200
- result = JSON.parse(response.body)
- raise "Failed to read file. Reason: #{result['reason']}"
- end
-
- response.body
- end
-
def calabash_server_failure_exists?(application)
- file_exists?(calabash_server_failure_file_path(application))
+ adb_file_exists?(calabash_server_failure_file_path(application))
end
def calabash_server_finished_exists?(application)
- file_exists?(calabash_server_finished_file_path(application))
+ adb_file_exists?(calabash_server_finished_file_path(application))
end
def read_calabash_sever_failure(application)
- read_file(calabash_server_failure_file_path(application))
+ adb.shell("cat #{calabash_server_failure_file_path(application)}")
end
def read_calabash_sever_finished(application)
- read_file(calabash_server_finished_file_path(application))
+ adb.shell("cat #{calabash_server_finished_file_path(application)}")
end
def clear_calabash_server_report(application)
if installed_packages.include?(application.test_server.identifier)
- parameters =
- {
- intent: {
- flags: 0x10000000,
- component: {
- packageName: application.test_server.identifier,
- className: 'sh.calaba.instrumentationbackend.StatusReporterActivity',
- },
- extras: {
- method: 'clear'
- }
- }
- }
-
- ensure_helper_application_started
- start_activity(parameters)
+ adb.shell("am start -e method clear -n #{application.test_server.identifier}/sh.calaba.instrumentationbackend.StatusReporterActivity")
end
end
def _start_app(application, options={})
env_options = {}
@@ -502,17 +437,16 @@
options.fetch(:extras, {}).each do |k, v|
env_options[k] = v
end
env_options[:test_server_port] = server.test_server_port
+ env_options[:target_package] = application.identifier
env_options[:class] = options.fetch(:class, 'sh.calaba.instrumentationbackend.InstrumentationBackend')
if options[:activity]
env_options[:main_activity] = options[:activity]
- else
- env_options[:main_activity] = 'null'
end
if application.test_server.nil?
raise 'Invalid application. No test-server set.'
end
@@ -523,24 +457,29 @@
unless app_installed?(application.test_server.identifier)
raise "The test-server '#{application.test_server.identifier}' is not installed"
end
- installed_app_md5_checksum = md5_checksum_for_app_package(application.identifier)
+ installed_app = installed_apps.find{|app| app[:package] == application.identifier}
+ installed_app_md5_checksum = md5_checksum(installed_app[:path])
if application.md5_checksum != installed_app_md5_checksum
raise "The specified app is not the same as the installed app (#{application.md5_checksum} != #{installed_app_md5_checksum})."
end
- installed_test_server_md5_checksum = md5_checksum_for_app_package(application.test_server.identifier)
+ installed_test_server = installed_apps.find{|app| app[:package] == application.test_server.identifier}
+ installed_test_server_md5_checksum = md5_checksum(installed_test_server[:path])
if application.test_server.md5_checksum != installed_test_server_md5_checksum
raise "The specified test-server is not the same as the installed test-server (#{application.test_server.md5_checksum} != #{installed_test_server_md5_checksum})."
end
ensure_screen_on
+ # Clear any old error reports
+ clear_calabash_server_report(application)
+
# We have to forward the port ourselves, as an old test-server could be
# running on the old port. If the retriable client was able to
# determine if the port had been forwarded, we would not need this.
port_forward(server.endpoint.port, server.test_server_port)
@@ -556,29 +495,26 @@
rescue => _
raise 'Failed to stop old running test-server'
end
end
- # Clear any old error reports
- clear_calabash_server_report(application)
-
extras = ''
env_options.each_pair do |key, val|
- extras = "#{extras} -e #{key.to_s} #{val.to_s}"
+ extras = "#{extras} -e \"#{key.to_s}\" \"#{val.to_s}\""
end
begin
- adb_instrument(application,
+ instrument(application,
'sh.calaba.instrumentationbackend.CalabashInstrumentationTestRunner',
extras)
rescue ADB::ADBCallError => e
raise "Failed to start the application: '#{e.stderr.lines.first.chomp}'"
end
begin
- Calabash::Retry.retry(retries: 30, interval: 1, timeout: 30, on_errors: [RetryError]) do
+ Retriable.retriable(tries: 30, interval: 1, timeout: 30, on: RetryError) do
unless test_server_responding?
# Read any message the test-server might have
if calabash_server_failure_exists?(application)
failure_message = read_calabash_sever_failure(application)
@@ -593,46 +529,30 @@
@logger.log('For information, see the adb logcat', :error)
raise 'Could not contact test-server'
end
begin
- Calabash::Retry.retry(retries: 10, interval: 1, timeout: 10, on_errors: [RetryError]) do
+ Retriable.retriable(tries: 10, interval: 1, timeout: 10) do
unless test_server_ready?
raise RetryError
end
end
rescue RetryError => _
@logger.log('Test-server was never ready', :error)
@logger.log('For information, see the adb logcat', :error)
raise 'Test-server was never ready'
end
- start_application(options[:intent])
-
# Return true to avoid cluttering the console
true
end
# @!visibility private
- def start_application(intent)
- request = HTTP::Request.new('start-application', params_for_request(intent: intent))
- body = http_client.post(request).body
-
- result = JSON.parse(body)
-
- if result['outcome'] != 'SUCCESS'
- raise "Failed to start application. Reason: #{result['reason']}"
- end
-
- result['result']
- end
-
- # @!visibility private
def _stop_app
- Calabash::Retry.retry(retries: 5, interval: 1) do
+ Retriable.retriable(tries: 5, interval: 1) do
begin
- http_client.post(HTTP::Request.new('kill'), retries: 1, interval: 0)
+ http_client.get(HTTP::Request.new('kill'), retries: 1, interval: 0)
rescue HTTP::Error => _
# It's fine that we can't contact the test-server, as it might already have been shut down
if test_server_responding?
raise 'Could not kill the test-server'
end
@@ -672,11 +592,11 @@
raise 'Could not turn screen on'
end
# @!visibility private
- def adb_instrument(application, test_server_activity, extras = '')
+ def instrument(application, test_server_activity, extras = '')
unless application.is_a?(Android::Application)
raise ArgumentError, "Invalid application type '#{application.class}'"
end
if application.test_server.nil?
@@ -700,15 +620,15 @@
# @!visibility private
class EnsureInstrumentActionError < RuntimeError; end
# @!visibility private
- def ensure_adb_instrument_action(application, test_server_activity, extras = '')
+ def ensure_instrument_action(application, test_server_activity, extras = '')
clear_calabash_server_report(application)
begin
- adb_instrument(application, test_server_activity, extras)
+ instrument(application, test_server_activity, extras)
rescue ADB::ADBCallError => e
raise EnsureInstrumentActionError, e
end
begin
@@ -733,57 +653,13 @@
raise EnsureInstrumentActionError, 'Timed out waiting for status'
end
end
# @!visibility private
- def ensure_instrument_action(application, parameters)
- ensure_helper_application_started
- clear_calabash_server_report(application)
-
- begin
- instrument(parameters)
- rescue ADB::ADBCallError => e
- raise EnsureInstrumentActionError, e
- end
-
- begin
- Timeout.timeout(10) do
- loop do
- if calabash_server_failure_exists?(application)
- failure_message = read_calabash_sever_failure(application)
-
- raise EnsureInstrumentActionError, parse_failure_message(failure_message)
- end
-
- if calabash_server_finished_exists?(application)
- output = read_calabash_sever_finished(application)
-
- if output == 'SUCCESSFUL'
- break
- end
- end
- end
- end
- rescue Timeout::Error => _
- raise EnsureInstrumentActionError, 'Timed out waiting for status'
- end
- end
-
- # @!visibility private
def ts_clear_app_data(application)
- parameters =
- {
- intent: {
- component: {
- className: 'sh.calaba.instrumentationbackend.ClearAppData2',
- packageName: application.test_server.identifier
- }
- }
- }
-
begin
- ensure_instrument_action(application, parameters)
+ ensure_instrument_action(application, 'sh.calaba.instrumentationbackend.ClearAppData2')
rescue EnsureInstrumentActionError => e
raise "Failed to clear app data: #{e.message}"
end
end
@@ -864,14 +740,15 @@
@logger.log "Ensuring #{application.path} is installed"
if installed_packages.include?(application.identifier)
@logger.log 'Application is already installed. Ensuring right checksum'
- installed_app_md5_checksum = md5_checksum_for_app_package(application.identifier)
+ installed_app = installed_apps.find{|app| app[:package] == application.identifier}
+ installed_app_md5_checksum = md5_checksum(installed_app[:path])
if application.md5_checksum != installed_app_md5_checksum
- @logger.log("The md5 checksum has changed for '#{application.identifier}' (#{application.md5_checksum} != #{installed_app_md5_checksum}).", :info)
+ @logger.log("The md5 checksum has changed (#{application.md5_checksum} != #{installed_app_md5_checksum}).", :info)
_install_app(application)
end
else
adb_install_app(application)
end
@@ -1025,11 +902,10 @@
timeout: options[:timeout]))
end
# @!visibility private
def adb_uninstall_app(package)
- @installed_apps_cache = nil
@logger.log "Uninstalling #{package}"
result = adb.command('uninstall', package, timeout: 60).lines.last
if result.downcase.chomp != 'success'
raise "Could not uninstall app '#{package}': #{result.chomp}"
@@ -1040,11 +916,10 @@
end
end
# @!visibility private
def adb_install_app(application)
- @installed_apps_cache = nil
# Because of a bug in the latest version of ADB
# https://github.com/android/platform_system_core/blob/0f91887868e51de67bdf9aedc97fbcb044dc1969/adb/commandline.cpp#L1466
# ADB now uses rm -f ... to remove the temporary application on the
# device, but not all devices (below a certain OS) supports this flag.
# The user will be unable to install the app and instead receive:
@@ -1111,13 +986,13 @@
end
end
# @!visibility private
def execute_gesture(multi_touch_gesture)
- request = HTTP::Request.new('gesture', params_for_request(multi_touch_gesture))
+ request = HTTP::Request.new('gesture', json: multi_touch_gesture.to_json)
- body = http_client.post(request, timeout: multi_touch_gesture.timeout + 10).body
+ body = http_client.get(request, timeout: multi_touch_gesture.timeout + 10).body
result = JSON.parse(body)
if result['outcome'] != 'SUCCESS'
raise "Failed to perform gesture. #{result['reason']}"
end
@@ -1137,40 +1012,10 @@
else
results
end
end
- class InstrumentationError < RuntimeError; end
-
- def instrument(parameters, http_client = helper_application_http_client)
- request = HTTP::Request.new('instrument', params_for_request(parameters))
-
- body = http_client.post(request).body
- result = JSON.parse(body)
-
- if result['outcome'] != 'SUCCESS'
- raise InstrumentationError, "Failed to instrument. Reason: #{result['reason']}"
- end
-
- true
- end
-
- class StartActivityError < RuntimeError; end
-
- def start_activity(parameters, http_client = helper_application_http_client)
- request = HTTP::Request.new('start-activity', params_for_request(parameters))
-
- body = http_client.post(request).body
- result = JSON.parse(body)
-
- if result['outcome'] != 'SUCCESS'
- raise StartActivityError, "Failed to start activity. Reason: #{result['reason']}"
- end
-
- true
- end
-
# @!visibility private
def params_for_request(parameters)
{json: parameters.to_json}
end
@@ -1179,12 +1024,9 @@
if @md5_binary
@md5_binary
else
if adb.shell('md5', no_exit_code_check: true).chomp == 'md5 file ...'
@md5_binary = 'md5'
- elsif (r = adb.shell('md5sum _cal_no_such_file', no_exit_code_check: true)) && r.chomp.start_with?('md5sum:') &&
- !r.include?('permission denied')
- @md5_binary = 'md5sum'
else
# The device does not have 'md5'
calmd5 = Calabash::Android.binary_location('calmd5', info[:cpu_architecture], can_handle_pie_binaries?)
adb.command('push', calmd5, '/data/local/tmp/calmd5')
@md5_binary = '/data/local/tmp/calmd5'