lib/calabash/android/device.rb in calabash-1.9.9.pre2 vs lib/calabash/android/device.rb in calabash-1.9.9.pre3
- old
+ new
@@ -1,10 +1,11 @@
require 'json'
module Calabash
module Android
# A representation of a Calabash Android device.
+ # @!visibility private
class Device < ::Calabash::Device
attr_reader :adb
def initialize(identifier, server)
super
@@ -13,10 +14,16 @@
http_client.on_error(Errno::ECONNREFUSED) do |server|
port_forward(server.endpoint.port, server.test_server_port)
end
end
+ # @!visibility private
+ def change_server(new_server)
+ super(new_server)
+ port_forward(new_server.endpoint.port, new_server.test_server_port)
+ end
+
def self.default_serial
serials = list_serials
if Environment::DEVICE_IDENTIFIER
index = serials.index(Environment::DEVICE_IDENTIFIER)
@@ -154,11 +161,11 @@
if result['outcome'] != 'SUCCESS'
raise "mapping \"#{query}\" with \"#{method_name}\" failed because: #{result['reason']}\n#{result['details']}"
end
- result['results']
+ Calabash::QueryResult.create(result['results'], query)
end
def perform_action(action, *arguments)
@logger.log "Action: #{action} - Arguments: #{arguments.join(', ')}"
@@ -348,22 +355,21 @@
def calabash_server_finished_file_path(application)
"/data/data/#{application.test_server.identifier}/files/calabash_finished.out"
end
- def calabash_server_failure_exists?(application)
- cmd = "ls #{calabash_server_failure_file_path(application)}"
+ def adb_file_exists?(file)
+ cmd = "ls #{file}"
+ adb.shell(cmd, no_exit_code_check: true).chomp == file
+ end
- adb.shell(cmd, no_exit_code_check: true).chomp ==
- calabash_server_failure_file_path(application)
+ def calabash_server_failure_exists?(application)
+ adb_file_exists?(calabash_server_failure_file_path(application))
end
def calabash_server_finished_exists?(application)
- cmd = "ls #{calabash_server_finished_file_path(application)}"
-
- adb.shell(cmd, no_exit_code_check: true).chomp ==
- calabash_server_finished_file_path(application)
+ adb_file_exists?(calabash_server_finished_file_path(application))
end
def read_calabash_sever_failure(application)
adb.shell("cat #{calabash_server_failure_file_path(application)}")
end
@@ -404,10 +410,24 @@
unless app_installed?(application.test_server.identifier)
raise "The test-server '#{application.test_server.identifier}' is not installed"
end
+ 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 = 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)
@@ -534,10 +554,14 @@
if application.test_server.nil?
raise ArgumentError, "No test server set for '#{application}'"
end
+ unless app_installed?(application.identifier)
+ raise "The application #{application.identifier}' is not installed"
+ end
+
unless app_installed?(application.test_server.identifier)
raise "The test-server '#{application.test_server.identifier}' is not installed"
end
cmd = "am instrument #{extras} #{application.test_server.identifier}/#{test_server_activity}"
@@ -744,11 +768,11 @@
}
gesture = Gestures::Gesture.double_tap(gesture_options)
execute_gesture(Gestures::Gesture.with_parameters(gesture,
- query_string: query.to_s,
+ query: query,
timeout: options[:timeout]))
end
# @!visibility private
def _long_press(query, options={})
@@ -783,22 +807,22 @@
duration = options[:duration]
gesture = Gestures::Gesture.generate_swipe(from, to, time: duration)
execute_gesture(Gestures::Gesture.with_parameters(gesture,
- query_string: query.to_s,
+ query: query,
timeout: options[:timeout]))
end
# @!visibility private
def _pan_between(query_from, query_to, options={})
gesture = Gestures::Gesture.generate_swipe({x: 50, y: 50}, {x: 50, y: 50}, time: options[:duration])
gesture.gestures.first.touches[0].query = query_from
gesture.gestures.first.touches[1].query = query_to
execute_gesture(Gestures::Gesture.with_parameters(gesture,
- query_string: query_to,
+ query: query_to,
timeout: options[:timeout]))
end
# @!visibility private
def _flick(query, from, to, options={})
@@ -811,20 +835,20 @@
duration = options[:duration]
gesture = Gestures::Gesture.generate_swipe(from, to, time: duration, flick: true)
execute_gesture(Gestures::Gesture.with_parameters(gesture,
- query_string: query.to_s,
+ query: query,
timeout: options[:timeout]))
end
# @!visibility private
def _pinch(direction, query, options={})
gesture = Gestures::Gesture.pinch(direction)
execute_gesture(Gestures::Gesture.with_parameters(gesture,
- query_string: query.to_s,
+ query: query,
timeout: options[:timeout]))
end
# @!visibility private
def adb_uninstall_app(package)
@@ -840,18 +864,59 @@
end
end
# @!visibility private
def adb_install_app(application)
+ # 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:
+ # RuntimeError: Could not install app 'com.xamarin.xtcandroidsample.test': rm failed for -f, No such file or directory
+ # We have rewritten the way adb handles app installation. It's a 3-step
+ # procedure:
+ # - Push the app binary to /data/local/tmp
+ # - Install the app binary using pm
+ # - Remove the temporary apk.
@logger.log "Installing #{application.path}"
- result = adb.command('install' , '-r', application.path, timeout: 60).lines.last
- if result.downcase.chomp != 'success'
- raise "Could not install app '#{application.identifier}': #{result.chomp}"
+ tmp_path = "/data/local/tmp/#{File.basename(application.path)}"
+
+ begin
+ adb.command('push', application.path, tmp_path, timeout: 60)
+ rescue ADB::ADBCallError => e
+ raise "Failed to push the application to the device storage: '#{e.message}'"
end
- unless installed_packages.include?(application.identifier)
- raise "App '#{application.identifier}' was not installed"
+ begin
+ result = nil
+
+ begin
+ result = adb.shell("pm install -r #{tmp_path}", timeout: 60)
+ rescue ADB::ADBCallError => e
+ raise "Failed to install the application on device: '#{e.message}'"
+ end
+
+ if result.lines.last.downcase.chomp != 'success'
+ raise "Could not install app '#{application.identifier}': #{result.chomp}"
+ end
+
+ unless installed_packages.include?(application.identifier)
+ raise "App '#{application.identifier}' was not installed"
+ end
+ rescue => e
+ begin
+ adb.shell("rm #{tmp_path}")
+ rescue ADB::ADBCallError => _
+ end
+
+ raise e
+ end
+
+ begin
+ adb.shell("rm #{tmp_path}")
+ rescue ADB::ADBCallError => e
+ raise "Failed to remove the tmp apk from device: #{e.message}"
end
end
# @!visibility private
def adb_clear_app_data(package)