kraken-mobile 1.0.4 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +45 -11
  3. data/bin/kraken-mobile +55 -67
  4. data/bin/kraken_mobile_calabash_android.rb +39 -0
  5. data/bin/kraken_mobile_helpers.rb +91 -0
  6. data/bin/kraken_mobile_setup.rb +134 -0
  7. data/calabash-android-features-skeleton/step_definitions/mobile_steps.rb +1 -0
  8. data/calabash-android-features-skeleton/support/app_installation_hooks.rb +2 -0
  9. data/calabash-android-features-skeleton/support/app_life_cycle_hooks.rb +3 -4
  10. data/calabash-android-features-skeleton/support/env.rb +1 -1
  11. data/calabash-android-features-skeleton/web/step_definitions/web_steps.rb +3 -0
  12. data/calabash-android-features-skeleton/web/support/app_life_cycle_hooks.rb +15 -0
  13. data/lib/kraken-mobile/device_process.rb +94 -0
  14. data/lib/kraken-mobile/helpers/devices_helper/adb_helper.rb +100 -105
  15. data/lib/kraken-mobile/helpers/kraken_faker.rb +107 -0
  16. data/lib/kraken-mobile/hooks/mobile_kraken_hooks.rb +15 -0
  17. data/lib/kraken-mobile/hooks/mobile_operations.rb +36 -0
  18. data/lib/kraken-mobile/hooks/web_operations.rb +33 -0
  19. data/lib/kraken-mobile/mobile/adb.rb +66 -0
  20. data/lib/kraken-mobile/mobile/android_commands.rb +43 -0
  21. data/lib/kraken-mobile/mobile/mobile_process.rb +82 -0
  22. data/lib/kraken-mobile/models/android_device.rb +121 -0
  23. data/lib/kraken-mobile/models/device.rb +113 -31
  24. data/lib/kraken-mobile/models/feature_file.rb +108 -0
  25. data/lib/kraken-mobile/models/feature_scenario.rb +24 -0
  26. data/lib/kraken-mobile/models/web_device.rb +86 -0
  27. data/lib/kraken-mobile/monkeys/mobile/android_monkey.rb +30 -0
  28. data/lib/kraken-mobile/monkeys/mobile/kraken_android_monkey.rb +54 -0
  29. data/lib/kraken-mobile/runners/calabash/android/steps/communication_steps.rb +15 -0
  30. data/lib/kraken-mobile/steps/general_steps.rb +82 -0
  31. data/lib/kraken-mobile/steps/mobile/kraken_steps.rb +72 -0
  32. data/lib/kraken-mobile/steps/web/kraken_steps.rb +81 -0
  33. data/lib/kraken-mobile/test_scenario.rb +193 -0
  34. data/lib/kraken-mobile/utils/feature_reader.rb +17 -0
  35. data/lib/kraken-mobile/utils/k.rb +67 -0
  36. data/lib/kraken-mobile/utils/mobile_cucumber.rb +2 -0
  37. data/lib/kraken-mobile/utils/reporter.rb +453 -0
  38. data/lib/kraken-mobile/version.rb +2 -2
  39. data/lib/kraken-mobile/web/web_process.rb +39 -0
  40. data/lib/kraken_mobile.rb +77 -0
  41. data/reporter/index.html.erb +6 -6
  42. metadata +89 -9
  43. data/bin/kraken-mobile-calabash-android.rb +0 -85
  44. data/bin/kraken-mobile-generate.rb +0 -19
  45. data/bin/kraken-mobile-helpers.rb +0 -48
  46. data/bin/kraken-mobile-setup.rb +0 -50
  47. data/calabash-android-features-skeleton/step_definitions/kraken_steps.rb +0 -1
  48. data/lib/kraken-mobile.rb +0 -29
@@ -0,0 +1,15 @@
1
+ require 'calabash-android/management/adb'
2
+ require 'calabash-android/operations'
3
+
4
+ Before do |scenario|
5
+ # install_app_with_calabash
6
+ @scenario_tags = scenario.source_tag_names
7
+ end
8
+
9
+ After do |scenario|
10
+ @scenario_tags = scenario.source_tag_names
11
+ end
12
+
13
+ AfterStep do |_scenario|
14
+ screenshot_embed
15
+ end
@@ -0,0 +1,36 @@
1
+ require 'calabash-android/management/adb'
2
+ require 'calabash-android/operations'
3
+ require 'kraken-mobile/test_scenario'
4
+
5
+ def start_test_kraken_server_in_background
6
+ start_test_server_in_background
7
+
8
+ DeviceProcess.notify_process_state(
9
+ process_id: process_id,
10
+ state: K::PROCESS_STATES[:ready_to_start]
11
+ )
12
+
13
+ Timeout.timeout(K::DEFAULT_START_TIMEOUT_SECONDS, RuntimeError) do
14
+ sleep(1) until TestScenario.ready_to_start?
15
+ end
16
+ end
17
+
18
+ def shutdown_test_kraken_server
19
+ DeviceProcess.notify_process_state(
20
+ process_id: process_id,
21
+ state: K::PROCESS_STATES[:ready_to_finish]
22
+ )
23
+
24
+ Timeout.timeout(K::DEFAULT_FINISH_TIMEOUT_SECONDS, RuntimeError) do
25
+ sleep(1) until TestScenario.ready_to_finish?
26
+ end
27
+
28
+ shutdown_test_server
29
+ end
30
+
31
+ private
32
+
33
+ def process_id
34
+ tag_process_id = @scenario_tags.grep(/@user/).first
35
+ tag_process_id.delete_prefix('@user')
36
+ end
@@ -0,0 +1,33 @@
1
+ require 'kraken-mobile/test_scenario'
2
+
3
+ def start_test_kraken_server_in_background(scenario:)
4
+ @scenario_tags = scenario.source_tag_names
5
+ DeviceProcess.notify_process_state(
6
+ process_id: process_id(scenario: scenario),
7
+ state: K::PROCESS_STATES[:ready_to_start]
8
+ )
9
+
10
+ Timeout.timeout(K::DEFAULT_START_TIMEOUT_SECONDS, RuntimeError) do
11
+ sleep(1) until TestScenario.ready_to_start?
12
+ end
13
+ end
14
+
15
+ def shutdown_test_kraken_server(scenario:)
16
+ @scenario_tags = scenario.source_tag_names
17
+ DeviceProcess.notify_process_state(
18
+ process_id: process_id(scenario: scenario),
19
+ state: K::PROCESS_STATES[:ready_to_finish]
20
+ )
21
+
22
+ Timeout.timeout(K::DEFAULT_FINISH_TIMEOUT_SECONDS, RuntimeError) do
23
+ sleep(1) until TestScenario.ready_to_finish?
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def process_id(scenario:)
30
+ scenario_tags = scenario.source_tag_names
31
+ tag_process_id = scenario_tags.grep(/@user/).first
32
+ tag_process_id.delete_prefix('@user')
33
+ end
@@ -0,0 +1,66 @@
1
+ require 'kraken-mobile/models/android_device'
2
+ require 'kraken-mobile/constants'
3
+ require 'kraken-mobile/mobile/android_commands.rb'
4
+
5
+ class ADB
6
+ class << self
7
+ include Android::Commands
8
+
9
+ def connected_devices
10
+ devices = []
11
+ adb_devices_l.split("\n").each do |line|
12
+ id = extract_device_id(line)
13
+ model = extract_device_model(line)
14
+ next if id.nil? || model.nil?
15
+
16
+ devices << AndroidDevice.new(id: id, model: model)
17
+ end
18
+ devices
19
+ rescue StandardError => _e
20
+ raise 'ERROR: Can\'t read Android devices connected.'
21
+ end
22
+
23
+ def device_screen_size(device_id:)
24
+ adb_size = screen_size_for_device_with_id(device_id: device_id)
25
+ extract_device_screen_size_info(adb_size)
26
+ rescue StandardError => _e
27
+ raise "ERROR: Can\'t read Android device #{device_id} screen size."
28
+ end
29
+
30
+ def save_snapshot_for_device_with_id_in_file_path(device_id:, file_path:)
31
+ save_snapshot_for_device_with_id_in_path(
32
+ device_id: device_id,
33
+ file_path: file_path
34
+ )
35
+ rescue StandardError => _e
36
+ raise "ERROR: Can\'t save snapshot for device #{device_id}."
37
+ end
38
+
39
+ def device_sdk_version(device_id:)
40
+ version = sdk_version_for_device_with_id(device_id: device_id)
41
+ version.strip
42
+ rescue StandardError => _e
43
+ raise "ERROR: Can\'t get SDK version for device #{device_id}."
44
+ end
45
+
46
+ private
47
+
48
+ def extract_device_id(line)
49
+ return line.split(' ').first if line.match(/device(?!s)/)
50
+ end
51
+
52
+ def extract_device_model(line)
53
+ return unless line.match(/device(?!s)/)
54
+
55
+ line.scan(/model:(.*) device/).flatten.first
56
+ end
57
+
58
+ def extract_device_screen_size_info(line)
59
+ parts = line.strip!.split(' ')
60
+ size = parts[parts.count - 1]
61
+ return [0, 0] unless size.include?('x')
62
+
63
+ size.split('x').map(&:to_i)
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,43 @@
1
+ module Android
2
+ module Commands
3
+ # List of connected devices/emulators
4
+ def adb_devices_l
5
+ `adb devices -l`
6
+ end
7
+
8
+ def file_content(device_id:, file_name:)
9
+ `adb -s #{device_id} shell "cat /sdcard/#{file_name} 2> /dev/null"`
10
+ end
11
+
12
+ def write_content_to_file_with_name_in_device(
13
+ content:, device_id:, file_name:
14
+ )
15
+ `adb -s #{device_id} shell "echo "#{content}" > /sdcard/#{file_name}"`
16
+ end
17
+
18
+ def create_file_with_name_in_device(device_id:, file_name:)
19
+ `adb -s #{device_id} shell "> /sdcard/#{file_name}"`
20
+ end
21
+
22
+ def delete_file_with_name_in_device(device_id:, file_name:)
23
+ `adb -s #{device_id} shell "rm -rf /sdcard/#{file_name}"`
24
+ end
25
+
26
+ def device_orientation(device_id:)
27
+ `adb -s #{device_id} shell dumpsys input | grep 'SurfaceOrientation' \
28
+ | awk '{ print $2 }'`
29
+ end
30
+
31
+ def screen_size_for_device_with_id(device_id:)
32
+ `adb -s #{device_id} shell wm size`
33
+ end
34
+
35
+ def save_snapshot_for_device_with_id_in_path(device_id:, file_path:)
36
+ `adb -s #{device_id} shell cat /sdcard/window_dump.xml > #{file_path}`
37
+ end
38
+
39
+ def sdk_version_for_device_with_id(device_id:)
40
+ `adb -s #{device_id} shell getprop ro.build.version.sdk`
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,82 @@
1
+ require 'kraken-mobile/device_process.rb'
2
+ require 'kraken-mobile/utils/k'
3
+
4
+ class MobileProcess < DeviceProcess
5
+ #-------------------------------
6
+ # Required methods
7
+ #-------------------------------
8
+ def before_execute
9
+ register_process_to_directory
10
+ device.create_inbox
11
+ end
12
+
13
+ def after_execute
14
+ device.delete_inbox
15
+ end
16
+
17
+ def execute
18
+ open(execution_command, 'r') do |output|
19
+ loop do
20
+ $stdout.print output.readline.to_s
21
+ $stdout.flush
22
+ end
23
+ end
24
+ $CHILD_STATUS.exitstatus
25
+ rescue EOFError
26
+ nil
27
+ end
28
+
29
+ #-------------------------------
30
+ # Methods
31
+ #-------------------------------
32
+
33
+ def apk_path
34
+ return config_apk_path if @test_scenario.requires_predefined_devices?
35
+
36
+ path = @test_scenario&.kraken_app&.apk_path
37
+ raise 'ERROR: Invalid APK file path' if path.nil?
38
+
39
+ path
40
+ end
41
+
42
+ private
43
+
44
+ def execution_command
45
+ feature_path = test_scenario.feature_file.file_path
46
+ raise 'ERROR: Invalid feature file path' if feature_path.nil?
47
+
48
+ process_apk_path = apk_path
49
+ raise 'ERROR: Invalid APK file path' if process_apk_path.nil?
50
+
51
+ "|ADB_DEVICE_ARG=#{device.id} calabash-android run #{process_apk_path} "\
52
+ "#{feature_path} --tags @user#{id} --format pretty --format json -o "\
53
+ "#{K::REPORT_PATH}/#{@test_scenario.execution_id}/#{device.id}/#{K::FILE_REPORT_NAME}" # TODO, folder to save all things
54
+ end
55
+
56
+ #-------------------------------
57
+ # Helpers
58
+ #-------------------------------
59
+
60
+ def config_json
61
+ config_absolute_path = File.expand_path(ENV[K::CONFIG_PATH])
62
+ file = open(config_absolute_path)
63
+ content = file.read
64
+ JSON.parse(content)[@id.to_s] || {}
65
+ end
66
+
67
+ def config_apk_path
68
+ device_config_json = config_json
69
+ return if device_config_json['config'].nil?
70
+ return if device_config_json['config']['apk_path'].nil?
71
+
72
+ absolute_config_apk_path = File.expand_path(
73
+ device_config_json['config']['apk_path']
74
+ )
75
+
76
+ raise 'ERROR: Invalid config apk path' unless File.file?(
77
+ absolute_config_apk_path
78
+ )
79
+
80
+ absolute_config_apk_path
81
+ end
82
+ end
@@ -0,0 +1,121 @@
1
+ require 'kraken-mobile/models/device'
2
+ require 'kraken-mobile/mobile/adb'
3
+ require 'kraken-mobile/monkeys/mobile/kraken_android_monkey'
4
+ require 'kraken-mobile/monkeys/mobile/android_monkey'
5
+
6
+ class AndroidDevice < Device
7
+ include KrakenAndroidMonkey
8
+ include AndroidMonkey
9
+
10
+ #-------------------------------
11
+ # Signaling
12
+ #-------------------------------
13
+ def create_inbox
14
+ raise 'ERROR: Device is disconnected.' unless connected?
15
+
16
+ ADB.create_file_with_name_in_device(
17
+ device_id: @id,
18
+ file_name: K::INBOX_FILE_NAME
19
+ )
20
+ end
21
+
22
+ def delete_inbox
23
+ raise 'ERROR: Device is disconnected.' unless connected?
24
+
25
+ ADB.delete_file_with_name_in_device(
26
+ device_id: @id,
27
+ file_name: K::INBOX_FILE_NAME
28
+ )
29
+ end
30
+
31
+ def write_signal(signal)
32
+ ADB.write_content_to_file_with_name_in_device(
33
+ content: signal,
34
+ device_id: @id,
35
+ file_name: K::INBOX_FILE_NAME
36
+ )
37
+ end
38
+
39
+ def read_signal(signal, timeout = K::DEFAULT_TIMEOUT_SECONDS)
40
+ Timeout.timeout(timeout, RuntimeError) do
41
+ sleep(1) until inbox_last_signal == signal
42
+ end
43
+ end
44
+
45
+ #-------------------------------
46
+ # More interface methods
47
+ #-------------------------------
48
+ def connected?
49
+ ADB.connected_devices.any? do |device|
50
+ device.id == @id
51
+ end
52
+ end
53
+
54
+ def orientation
55
+ ADB.device_orientation(
56
+ device_id: @id
57
+ ).strip!.to_i
58
+ rescue StandardError => _e
59
+ K::ANDROID_PORTRAIT
60
+ end
61
+
62
+ def screen_size
63
+ size = ADB.device_screen_size(device_id: @id)
64
+
65
+ height = orientation == K::ANDROID_PORTRAIT ? size[1] : size[0]
66
+ width = orientation == K::ANDROID_PORTRAIT ? size[0] : size[1]
67
+
68
+ [height, width]
69
+ end
70
+
71
+ def sdk_version
72
+ ADB.device_sdk_version(device_id: @id)
73
+ end
74
+
75
+ def type
76
+ K::ANDROID_DEVICE
77
+ end
78
+
79
+ def save_snapshot_in_file_path(file_path)
80
+ raise 'ERROR: Invalid snapshot file path' if file_path.nil?
81
+
82
+ absolute_path = File.expand_path(file_path)
83
+ raise 'ERROR: File already exists' if File.file?(absolute_path)
84
+
85
+ ADB.save_snapshot_for_device_with_id_in_file_path(
86
+ device_id: @id,
87
+ file_path: absolute_path
88
+ )
89
+ end
90
+
91
+ #-------------------------------
92
+ # Random testing
93
+ #-------------------------------
94
+ def run_monkey_with_number_of_events(number_of_events)
95
+ execute_monkey(number_of_events)
96
+ end
97
+
98
+ def run_kraken_monkey_with_number_of_events(number_of_events)
99
+ execute_kraken_monkey(number_of_events)
100
+ end
101
+
102
+ #-------------------------------
103
+ # Helprs
104
+ #-------------------------------
105
+ def calabash_default_device
106
+ operations_module = Calabash::Android::Operations
107
+ operations_module::Device.new(
108
+ operations_module,
109
+ ENV['ADB_DEVICE_ARG'],
110
+ ENV['TEST_SERVER_PORT'],
111
+ ENV['APP_PATH'],
112
+ ENV['TEST_APP_PATH']
113
+ )
114
+ end
115
+
116
+ private
117
+
118
+ def inbox_last_signal
119
+ ADB.file_content(device_id: @id, file_name: K::INBOX_FILE_NAME).strip
120
+ end
121
+ end
@@ -1,32 +1,114 @@
1
- module KrakenMobile
2
- module Models
3
- class Device
4
-
5
- #-------------------------------
6
- # Fields
7
- #-------------------------------
8
- attr_accessor :id
9
- attr_accessor :model
10
- attr_accessor :position
11
- attr_accessor :config
12
-
13
- #-------------------------------
14
- # Constructors
15
- #-------------------------------
16
- def initialize(id, model, position, config = {})
17
- @id = id
18
- @model = model
19
- @position = position
20
- @config = config
21
- end
22
-
23
- #-------------------------------
24
- # Helpers
25
- #-------------------------------
26
- def screenshot_prefix
27
- @id.gsub('.', '_').gsub(/:(.*)/, '').to_s + '_'
28
- end
29
-
30
- end
31
- end
1
+ require 'kraken-mobile/device_process'
2
+
3
+ class Device
4
+ #-------------------------------
5
+ # Fields
6
+ #-------------------------------
7
+ attr_accessor :id
8
+ attr_accessor :model
9
+
10
+ #-------------------------------
11
+ # Constructors
12
+ #-------------------------------
13
+ def initialize(id:, model:)
14
+ @id = id
15
+ @model = model
16
+ end
17
+
18
+ #-------------------------------
19
+ # Signaling
20
+ #-------------------------------
21
+ def create_inbox
22
+ raise 'ERROR: create_inbox not implemented.'
23
+ end
24
+
25
+ def delete_inbox
26
+ raise 'ERROR: delete_inbox not implemented.'
27
+ end
28
+
29
+ def write_signal(_signal)
30
+ raise 'ERROR: write_signal not implemented.'
31
+ end
32
+
33
+ def read_signal(_signal, _timeout = K::DEFAULT_TIMEOUT_SECONDS)
34
+ raise 'ERROR: read_signal not implemented.'
35
+ end
36
+
37
+ #-------------------------------
38
+ # Random testing
39
+ #-------------------------------
40
+ def run_monkey_with_number_of_events(_number_of_events)
41
+ raise 'ERROR: run_monkey_with_number_of_events not implemented.'
42
+ end
43
+
44
+ def run_kraken_monkey_with_number_of_events(_number_of_events)
45
+ raise 'ERROR: run_kraken_monkey_with_number_of_events not implemented.'
46
+ end
47
+
48
+ #-------------------------------
49
+ # More interface methods
50
+ #-------------------------------
51
+ def connected?
52
+ raise 'ERROR: connected? not implemented.'
53
+ end
54
+
55
+ def orientation
56
+ raise 'ERROR: orientation not implemented.'
57
+ end
58
+
59
+ def screen_size
60
+ raise 'ERROR: screen_size not implemented.'
61
+ end
62
+
63
+ def sdk_version
64
+ raise 'ERROR: sdk_version not implemented.'
65
+ end
66
+
67
+ def type
68
+ raise 'ERROR: Unsupported device'
69
+ end
70
+
71
+ def save_snapshot_in_path(_file_path)
72
+ raise 'ERROR: save_snapshot_in_path not implemented.'
73
+ end
74
+
75
+ #-------------------------------
76
+ # Helpers
77
+ #-------------------------------
78
+ def to_s
79
+ @id + K::SEPARATOR + @model + K::SEPARATOR + type
80
+ end
81
+
82
+ def screenshot_prefix
83
+ @id.gsub('.', '_').gsub(/:(.*)/, '').to_s + '_'
84
+ end
85
+
86
+ def self.find_by_process_id(id)
87
+ DeviceProcess.directory.each do |process_info|
88
+ info = process_info.strip.split(K::SEPARATOR)
89
+ process_id = info[0]
90
+ next unless process_id.to_s == id.to_s
91
+
92
+ return device_from_type(
93
+ id: info[1], model: info[2],
94
+ device_type: info[3]
95
+ )
96
+ end
97
+
98
+ nil
99
+ end
100
+
101
+ def self.device_from_type(id:, model:, device_type:)
102
+ device_class = nil
103
+ if device_type == K::ANDROID_DEVICE
104
+ device_class = AndroidDevice
105
+ elsif device_type == K::WEB_DEVICE
106
+ device_class = WebDevice
107
+ end
108
+ raise 'ERROR: Unsupported device' if device_class.nil?
109
+
110
+ device_class.new(
111
+ id: id, model: model
112
+ )
113
+ end
32
114
  end