kraken-mobile 1.0.1 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +251 -77
  3. data/bin/kraken-mobile +64 -67
  4. data/bin/kraken_mobile_calabash_android.rb +39 -0
  5. data/bin/kraken_mobile_helpers.rb +107 -0
  6. data/bin/kraken_mobile_setup.rb +138 -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 +130 -0
  14. data/lib/kraken-mobile/helpers/devices_helper/adb_helper.rb +100 -105
  15. data/lib/kraken-mobile/helpers/kraken_faker.rb +108 -0
  16. data/lib/kraken-mobile/helpers/reporter.rb +3 -0
  17. data/lib/kraken-mobile/hooks/mobile_kraken_hooks.rb +15 -0
  18. data/lib/kraken-mobile/hooks/mobile_operations.rb +36 -0
  19. data/lib/kraken-mobile/hooks/web_operations.rb +33 -0
  20. data/lib/kraken-mobile/mobile/adb.rb +66 -0
  21. data/lib/kraken-mobile/mobile/android_commands.rb +43 -0
  22. data/lib/kraken-mobile/mobile/mobile_process.rb +101 -0
  23. data/lib/kraken-mobile/models/android_device.rb +121 -0
  24. data/lib/kraken-mobile/models/device.rb +113 -31
  25. data/lib/kraken-mobile/models/feature_file.rb +135 -0
  26. data/lib/kraken-mobile/models/feature_scenario.rb +24 -0
  27. data/lib/kraken-mobile/models/web_device.rb +89 -0
  28. data/lib/kraken-mobile/monkeys/mobile/android_monkey.rb +30 -0
  29. data/lib/kraken-mobile/monkeys/mobile/kraken_android_monkey.rb +54 -0
  30. data/lib/kraken-mobile/monkeys/web/web_monkey.rb +63 -0
  31. data/lib/kraken-mobile/runners/calabash/android/monkey_helper.rb +2 -2
  32. data/lib/kraken-mobile/runners/calabash/android/steps/communication_steps.rb +18 -2
  33. data/lib/kraken-mobile/runners/calabash/monkey/monkey_runner.rb +2 -2
  34. data/lib/kraken-mobile/steps/general_steps.rb +83 -0
  35. data/lib/kraken-mobile/steps/mobile/kraken_steps.rb +72 -0
  36. data/lib/kraken-mobile/steps/web/kraken_steps.rb +91 -0
  37. data/lib/kraken-mobile/test_scenario.rb +227 -0
  38. data/lib/kraken-mobile/utils/feature_reader.rb +17 -0
  39. data/lib/kraken-mobile/utils/k.rb +68 -0
  40. data/lib/kraken-mobile/utils/mobile_cucumber.rb +2 -0
  41. data/lib/kraken-mobile/utils/reporter.rb +500 -0
  42. data/lib/kraken-mobile/version.rb +2 -2
  43. data/lib/kraken-mobile/web/web_process.rb +41 -0
  44. data/lib/kraken_mobile.rb +81 -0
  45. data/reporter/assets/css/scenario_index.css +20 -0
  46. data/reporter/assets/images/krakenThumbnail.jpg +0 -0
  47. data/reporter/assets/js/sankey.js +56 -24
  48. data/reporter/feature_report.html.erb +5 -1
  49. data/reporter/index.html.erb +15 -8
  50. data/reporter/scenario_report.html.erb +73 -31
  51. metadata +95 -14
  52. data/bin/kraken-mobile-calabash-android.rb +0 -85
  53. data/bin/kraken-mobile-generate.rb +0 -19
  54. data/bin/kraken-mobile-helpers.rb +0 -48
  55. data/bin/kraken-mobile-setup.rb +0 -50
  56. data/calabash-android-features-skeleton/step_definitions/kraken_steps.rb +0 -1
  57. data/lib/kraken-mobile.rb +0 -29
@@ -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,101 @@
1
+ require 'kraken-mobile/device_process.rb'
2
+ require 'kraken-mobile/utils/k.rb'
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
+ unregister_process_from_directory
15
+ device.delete_inbox
16
+ end
17
+
18
+ def execute
19
+ open(execution_command, 'r') do |output|
20
+ loop do
21
+ $stdout.print output.readline.to_s
22
+ $stdout.flush
23
+ end
24
+ end
25
+ $CHILD_STATUS.exitstatus
26
+ rescue EOFError
27
+ nil
28
+ end
29
+
30
+ #-------------------------------
31
+ # Methods
32
+ #-------------------------------
33
+
34
+ def apk_path
35
+ return config_apk_path if @test_scenario.requires_predefined_devices?
36
+
37
+ path = @test_scenario&.kraken_app&.apk_path
38
+ raise 'ERROR: Invalid APK file path' if path.nil?
39
+
40
+ path
41
+ end
42
+
43
+ private
44
+
45
+ def execution_command
46
+ "|#{environment_variables_command}#{terminal_command_separator}"\
47
+ "#{running_process_command}"
48
+ end
49
+
50
+ def running_process_command
51
+ feature_path = test_scenario.feature_file.file_path
52
+ raise 'ERROR: Invalid feature file path' if feature_path.nil?
53
+
54
+ process_apk_path = apk_path
55
+ raise 'ERROR: Invalid APK file path' if process_apk_path.nil?
56
+
57
+ "calabash-android run #{process_apk_path} \
58
+ #{feature_path} --tags @user#{id} \
59
+ --require features/support/env.rb \
60
+ --require features/support/app_installation_hooks.rb \
61
+ --require features/support/app_life_cycle_hooks.rb \
62
+ --require features/step_definitions/mobile_steps.rb \
63
+ --format pretty --format json -o \
64
+ #{K::REPORT_PATH}/#{@test_scenario.execution_id}/#{device.id}/#{K::FILE_REPORT_NAME}"
65
+ end
66
+
67
+ def environment_variables_command
68
+ variables = {
69
+ ADB_DEVICE_ARG: device.id
70
+ }
71
+ exporting_command_for_environment_variables(variables)
72
+ end
73
+
74
+ #-------------------------------
75
+ # Helpers
76
+ #-------------------------------
77
+
78
+ def config_json
79
+ config_absolute_path = File.expand_path(ENV[K::CONFIG_PATH])
80
+ file = open(config_absolute_path)
81
+ content = file.read
82
+ file.close
83
+ JSON.parse(content)[@id.to_s] || {}
84
+ end
85
+
86
+ def config_apk_path
87
+ device_config_json = config_json
88
+ return if device_config_json['config'].nil?
89
+ return if device_config_json['config']['apk_path'].nil?
90
+
91
+ absolute_config_apk_path = File.expand_path(
92
+ device_config_json['config']['apk_path']
93
+ )
94
+
95
+ raise 'ERROR: Invalid config apk path' unless File.file?(
96
+ absolute_config_apk_path
97
+ )
98
+
99
+ absolute_config_apk_path
100
+ end
101
+ 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