bugsnag-maze-runner 6.27.0

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 (88) hide show
  1. checksums.yaml +7 -0
  2. data/bin/bugsnag-print-load-paths +6 -0
  3. data/bin/download-logs +76 -0
  4. data/bin/maze-runner +136 -0
  5. data/bin/upload-app +56 -0
  6. data/lib/features/scripts/await-android-emulator.sh +11 -0
  7. data/lib/features/scripts/clear-android-app-data.sh +8 -0
  8. data/lib/features/scripts/force-stop-android-app.sh +8 -0
  9. data/lib/features/scripts/install-android-app.sh +15 -0
  10. data/lib/features/scripts/launch-android-app.sh +38 -0
  11. data/lib/features/scripts/launch-android-emulator.sh +15 -0
  12. data/lib/features/steps/android_steps.rb +51 -0
  13. data/lib/features/steps/app_automator_steps.rb +228 -0
  14. data/lib/features/steps/aws_sam_steps.rb +212 -0
  15. data/lib/features/steps/breadcrumb_steps.rb +50 -0
  16. data/lib/features/steps/browser_steps.rb +93 -0
  17. data/lib/features/steps/build_api_steps.rb +25 -0
  18. data/lib/features/steps/document_server_steps.rb +7 -0
  19. data/lib/features/steps/error_reporting_steps.rb +342 -0
  20. data/lib/features/steps/feature_flag_steps.rb +190 -0
  21. data/lib/features/steps/header_steps.rb +72 -0
  22. data/lib/features/steps/log_steps.rb +29 -0
  23. data/lib/features/steps/multipart_request_steps.rb +142 -0
  24. data/lib/features/steps/network_steps.rb +75 -0
  25. data/lib/features/steps/payload_steps.rb +234 -0
  26. data/lib/features/steps/proxy_steps.rb +34 -0
  27. data/lib/features/steps/query_parameter_steps.rb +31 -0
  28. data/lib/features/steps/request_assertion_steps.rb +107 -0
  29. data/lib/features/steps/runner_steps.rb +406 -0
  30. data/lib/features/steps/session_tracking_steps.rb +116 -0
  31. data/lib/features/steps/value_steps.rb +119 -0
  32. data/lib/features/support/env.rb +7 -0
  33. data/lib/features/support/internal_hooks.rb +260 -0
  34. data/lib/maze/appium_server.rb +112 -0
  35. data/lib/maze/assertions/request_set_assertions.rb +97 -0
  36. data/lib/maze/aws/sam.rb +112 -0
  37. data/lib/maze/bitbar_devices.rb +84 -0
  38. data/lib/maze/bitbar_utils.rb +112 -0
  39. data/lib/maze/browser_stack_devices.rb +160 -0
  40. data/lib/maze/browser_stack_utils.rb +164 -0
  41. data/lib/maze/browsers_bs.yml +220 -0
  42. data/lib/maze/browsers_cbt.yml +100 -0
  43. data/lib/maze/bugsnag_config.rb +42 -0
  44. data/lib/maze/capabilities.rb +126 -0
  45. data/lib/maze/checks/assert_check.rb +91 -0
  46. data/lib/maze/checks/noop_check.rb +34 -0
  47. data/lib/maze/compare.rb +161 -0
  48. data/lib/maze/configuration.rb +174 -0
  49. data/lib/maze/docker.rb +108 -0
  50. data/lib/maze/document_server.rb +46 -0
  51. data/lib/maze/driver/appium.rb +217 -0
  52. data/lib/maze/driver/browser.rb +138 -0
  53. data/lib/maze/driver/resilient_appium.rb +51 -0
  54. data/lib/maze/errors.rb +20 -0
  55. data/lib/maze/helper.rb +118 -0
  56. data/lib/maze/hooks/appium_hooks.rb +216 -0
  57. data/lib/maze/hooks/browser_hooks.rb +68 -0
  58. data/lib/maze/hooks/command_hooks.rb +9 -0
  59. data/lib/maze/hooks/hooks.rb +61 -0
  60. data/lib/maze/interactive_cli.rb +173 -0
  61. data/lib/maze/logger.rb +73 -0
  62. data/lib/maze/macos_utils.rb +14 -0
  63. data/lib/maze/network.rb +49 -0
  64. data/lib/maze/option/parser.rb +245 -0
  65. data/lib/maze/option/processor.rb +143 -0
  66. data/lib/maze/option/validator.rb +184 -0
  67. data/lib/maze/option.rb +64 -0
  68. data/lib/maze/plugins/bugsnag_reporting_plugin.rb +49 -0
  69. data/lib/maze/plugins/cucumber_report_plugin.rb +101 -0
  70. data/lib/maze/plugins/global_retry_plugin.rb +38 -0
  71. data/lib/maze/proxy.rb +114 -0
  72. data/lib/maze/request_list.rb +82 -0
  73. data/lib/maze/retry_handler.rb +76 -0
  74. data/lib/maze/runner.rb +149 -0
  75. data/lib/maze/sauce_labs_utils.rb +96 -0
  76. data/lib/maze/server.rb +207 -0
  77. data/lib/maze/servlets/base_servlet.rb +22 -0
  78. data/lib/maze/servlets/command_servlet.rb +44 -0
  79. data/lib/maze/servlets/log_servlet.rb +64 -0
  80. data/lib/maze/servlets/reflective_servlet.rb +69 -0
  81. data/lib/maze/servlets/servlet.rb +160 -0
  82. data/lib/maze/smart_bear_utils.rb +71 -0
  83. data/lib/maze/store.rb +15 -0
  84. data/lib/maze/terminating_server.rb +129 -0
  85. data/lib/maze/timers.rb +51 -0
  86. data/lib/maze/wait.rb +35 -0
  87. data/lib/maze.rb +27 -0
  88. metadata +371 -0
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+ require 'open3'
3
+ require 'fileutils'
4
+ require 'json'
5
+
6
+ module Maze
7
+ # Utils supporting the BitBar device farm integration
8
+ class BitBarUtils
9
+ BB_READY_FILE = 'bb.ready'
10
+ BB_KILL_FILE = 'bb.kill'
11
+ BB_USER_PREFIX = 'BB_USER_'
12
+ BB_KEY_PREFIX = 'BB_KEY_'
13
+
14
+ class << self
15
+
16
+ # Uploads an app to BitBar for later consumption
17
+ # @param api_key [String] The BitBar API key
18
+ # @param app [String] A path to the application file
19
+ def upload_app(api_key, app)
20
+ uuid_regex = /\A[0-9]+\z/
21
+
22
+ if uuid_regex.match? app
23
+ $logger.info "Using pre-uploaded app with ID #{app}"
24
+ app_uuid = app
25
+ else
26
+ expanded_app = Maze::Helper.expand_path(app)
27
+ $logger.info "Uploading app: #{expanded_app}"
28
+
29
+ # Upload the app to BitBar
30
+ uri = URI('https://cloud.bitbar.com/api/me/files')
31
+ request = Net::HTTP::Post.new(uri)
32
+ request.basic_auth(api_key, '')
33
+ request.set_form({ 'file' => File.new(expanded_app, 'rb') }, 'multipart/form-data')
34
+
35
+ res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
36
+ http.request(request)
37
+ end
38
+
39
+ # Pull the UUID from the response
40
+ begin
41
+ response = JSON.parse res.body
42
+ if response.key?('id')
43
+ app_uuid = response['id']
44
+ $logger.info "Uploaded app ID: #{app_uuid}"
45
+ $logger.info 'You can use this ID to avoid uploading the same app more than once.'
46
+ else
47
+ $logger.error "Unexpected response body: #{response}"
48
+ raise 'App upload failed'
49
+ end
50
+ rescue JSON::ParserError
51
+ $logger.error "Expected JSON response, received: #{res}"
52
+ raise
53
+ end
54
+ end
55
+ app_uuid
56
+ end
57
+
58
+ # Requests an unused account id from the test-management-service
59
+ # @param tms_uri [String] The URI of the test-management-service
60
+ #
61
+ # @returns
62
+ def account_credentials(tms_uri)
63
+ Maze::Wait.new(interval: 10, timeout: 1800).until do
64
+ output = request_account_index(tms_uri)
65
+ case output.code
66
+ when '200'
67
+ body = JSON.parse(output.body, {symbolize_names: true})
68
+ @account_id = account_id = body[:id]
69
+ $logger.info "Using account #{account_id}, expiring at #{body[:expiry]}"
70
+ {
71
+ username: ENV["#{BB_USER_PREFIX}#{account_id}"],
72
+ access_key: ENV["#{BB_KEY_PREFIX}#{account_id}"]
73
+ }
74
+ when '409'
75
+ # All accounts are in use, wait for one to become available
76
+ $logger.info 'All accounts are currently in use, retrying in 30s'
77
+ false
78
+ else
79
+ # Something has gone wrong, throw an error
80
+ $logger.error "Unexpected status code received from test-management server"
81
+ raise
82
+ end
83
+ end
84
+ end
85
+
86
+ # Makes the HTTP call to acquire an account id
87
+ # @param tms_uri [String] The URI of the test-management-service
88
+ #
89
+ # @returns
90
+ def request_account_index(tms_uri)
91
+ uri = URI("#{tms_uri}/account/request")
92
+ request = Net::HTTP::Get.new(uri)
93
+ request['Authorization'] = Maze.config.tms_token
94
+ res = Net::HTTP.start(uri.hostname, uri.port) do |http|
95
+ http.request(request)
96
+ end
97
+ res
98
+ end
99
+
100
+ # Informs the test-management-service that in-use account id is no longer in use
101
+ # @param tms_uri [String] The URI of the test-management-service
102
+ def release_account(tms_uri)
103
+ uri = URI("#{tms_uri}/account/release?account_id=#{@account_id}")
104
+ request = Net::HTTP::Get.new(uri)
105
+ request['Authorization'] = Maze.config.tms_token
106
+ res = Net::HTTP.start(uri.hostname, uri.port) do |http|
107
+ http.request(request)
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,160 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Maze
4
+ # Provides a source of capabilities used to run tests against specific BrowserStack devices
5
+ # noinspection RubyStringKeysInHashInspection
6
+ class BrowserStackDevices
7
+ APPIUM_1_7_0 = '1.7.0'
8
+ APPIUM_1_9_1 = '1.9.1'
9
+ APPIUM_1_15_0 = '1.15.0'
10
+ APPIUM_1_20_2 = '1.20.2'
11
+ APPIUM_1_21_0 = '1.21.0'
12
+
13
+ class << self
14
+
15
+ def list_devices(os)
16
+ puts "BrowserStack #{os} devices available"
17
+ devices = DEVICE_HASH.dup
18
+ devices.select { |key, device|
19
+ device['os'].eql?(os)
20
+ }.map { |key, device|
21
+ new_device = device.dup
22
+ new_device['key'] = key
23
+ new_device
24
+ }.sort { |dev_1, dev_2|
25
+ dev_1['os_version'].to_f <=> dev_2['os_version'].to_f
26
+ }.each{ |device|
27
+ puts '------------------------------'
28
+ puts "Device key: #{device['key']}"
29
+ puts "Device: #{device['device']}"
30
+ puts "OS: #{device['os']}"
31
+ puts "OS version: #{device['os_version']}"
32
+ }
33
+ end
34
+
35
+ def make_android_hash(device, version, appium_version = APPIUM_1_20_2)
36
+ hash = {
37
+ 'device' => device,
38
+ 'os_version' => version,
39
+ 'autoGrantPermissions' => 'true',
40
+ 'platformName' => 'Android',
41
+ 'os' => 'android',
42
+ 'browserstack.appium_version' => appium_version
43
+ }
44
+ # disableAnimations only allowed > Android 6
45
+ if version.to_i > 6
46
+ hash['disableAnimations'] = 'true'
47
+ end
48
+ hash.freeze
49
+ end
50
+
51
+ def add_android(device, version, hash, appium_version = APPIUM_1_20_2)
52
+ # Key format is "ANDROID_<version>_<device>", with:
53
+ # - dots in versions and all spaces replaced with underscores
54
+ # - device made upper case
55
+ name = device.upcase.gsub ' ', '_'
56
+ new_version = version.gsub '.', '_'
57
+ key = "ANDROID_#{new_version}_#{name}"
58
+ hash[key] = make_android_hash device, version, appium_version
59
+ end
60
+
61
+ def make_ios_hash(device, version, appium_version = APPIUM_1_21_0)
62
+ {
63
+ 'device' => device,
64
+ 'os_version' => version,
65
+ 'platformName' => 'iOS',
66
+ 'os' => 'ios',
67
+ 'disableAnimations' => 'true',
68
+ 'browserstack.appium_version' => appium_version
69
+ }.freeze
70
+ end
71
+
72
+ def add_ios(device, version, hash, appium_version = APPIUM_1_21_0)
73
+ # Key format is "IOS_<version>_<device>", with:
74
+ # - dots in versions and all spaces replaced with underscores
75
+ # - device made upper case
76
+ name = device.upcase.gsub ' ', '_'
77
+ name = name.gsub '.', '_'
78
+ new_version = version.gsub '.', '_'
79
+ key = "IOS_#{new_version}_#{name}"
80
+ hash[key] = make_ios_hash device, version, appium_version
81
+ end
82
+
83
+ def create_hash
84
+ hash = {
85
+ # Classic, non-specific devices for each Android version
86
+ 'ANDROID_13_0' => make_android_hash('Google Pixel 6 Pro', '13.0'),
87
+ 'ANDROID_13_0_BETA' => make_android_hash('Google Pixel 6 Pro', '13 Beta'),
88
+ 'ANDROID_12_0' => make_android_hash('Google Pixel 5', '12.0'),
89
+ 'ANDROID_11_0' => make_android_hash('Google Pixel 4', '11.0'),
90
+ 'ANDROID_10_0' => make_android_hash('Google Pixel 4', '10.0'),
91
+ 'ANDROID_9_0' => make_android_hash('Google Pixel 3', '9.0'),
92
+ 'ANDROID_8_1' => make_android_hash('Samsung Galaxy Note 9', '8.1'),
93
+ 'ANDROID_8_0' => make_android_hash('Google Pixel 2', '8.0'),
94
+ 'ANDROID_7_1' => make_android_hash('Google Pixel', '7.1'),
95
+ 'ANDROID_6_0' => make_android_hash('Google Nexus 6', '6.0'),
96
+ 'ANDROID_5_0' => make_android_hash('Google Nexus 6', '5.0'),
97
+ 'ANDROID_4_4' => make_android_hash('Google Nexus 5', '4.4', APPIUM_1_9_1),
98
+
99
+ # iOS devices
100
+ 'IOS_16' => make_ios_hash('iPhone 14', '16'),
101
+ 'IOS_15' => make_ios_hash('iPhone 11 Pro', '15'),
102
+ 'IOS_14' => make_ios_hash('iPhone 11', '14'),
103
+ 'IOS_13' => make_ios_hash('iPhone 8', '13'),
104
+ 'IOS_12' => make_ios_hash('iPhone 8', '12'),
105
+ 'IOS_11' => make_ios_hash('iPhone 8', '11', APPIUM_1_7_0),
106
+ 'IOS_10' => make_ios_hash('iPhone 7', '10', APPIUM_1_7_0)
107
+ }
108
+
109
+ # Specific Android devices
110
+ add_android 'Google Pixel 4', '11.0', hash # ANDROID_11_0_GOOGLE_PIXEL_4
111
+
112
+ add_android 'Xiaomi Redmi Note 9', '10.0', hash # ANDROID_10_0_XIAOMI_REDMI_NOTE_9
113
+ add_android 'Samsung Galaxy Note 20', '10.0', hash # ANDROID_10_0_SAMSUNG_GALAXY_NOTE_20
114
+ add_android 'Motorola Moto G9 Play', '10.0', hash # ANDROID_10_0_MOTOROLA_MOTO_G9_PLAY
115
+ add_android 'OnePlus 8', '10.0', hash # ANDROID_10_0_ONEPLUS_8
116
+
117
+ add_android 'Google Pixel 2', '9.0', hash # ANDROID_9_0_GOOGLE_PIXEL_2
118
+ add_android 'Samsung Galaxy Note 9', '8.1', hash # ANDROID_8_1_SAMSUNG_GALAXY_NOTE_9
119
+ add_android 'Samsung Galaxy J7 Prime', '8.1', hash # ANDROID_8_1_SAMSUNG_GALAXY_J7_PRIME
120
+ add_android 'Samsung Galaxy Tab S4', '8.1', hash # ANDROID_8_1_SAMSUNG_GALAXY_TAB_S4
121
+ add_android 'Samsung Galaxy Tab S3', '8.0', hash # ANDROID_8_0_SAMSUNG_GALAXY_TAB_S3
122
+ add_android 'Google Pixel', '8.0', hash # ANDROID_8_0_GOOGLE_PIXEL
123
+ add_android 'Google Pixel 2', '8.0', hash # ANDROID_8_0_GOOGLE_PIXEL_2
124
+ add_android 'Samsung Galaxy S9', '8.0', hash # ANDROID_8_0_SAMSUNG_GALAXY_S9
125
+ add_android 'Samsung Galaxy S9 Plus', '8.0', hash # ANDROID_8_0_SAMSUNG_GALAXY_S9_PLUS
126
+
127
+ add_android 'Samsung Galaxy A8', '7.1', hash # ANDROID_7_1_SAMSUNG_GALAXY_A8
128
+ add_android 'Samsung Galaxy Note 8', '7.1', hash # ANDROID_7_1_SAMSUNG_GALAXY_NOTE_8
129
+ add_android 'Samsung Galaxy S8', '7.0', hash # ANDROID_7_0_SAMSUNG_GALAXY_S8
130
+ add_android 'Samsung Galaxy S8 Plus', '7.0', hash # ANDROID_7_0_SAMSUNG_GALAXY_S8_PLUS
131
+
132
+ add_android 'Motorola Moto X 2nd Gen', '6.0', hash # ANDROID_6_0_MOTOROLA_MOTO_X_2ND_GEN
133
+ add_android 'Google Nexus 6', '6.0', hash # ANDROID_6_0_GOOGLE_NEXUS_6
134
+ add_android 'Samsung Galaxy S7', '6.0', hash # ANDROID_6_0_SAMSUNG_GALAXY_S7
135
+ add_android 'Google Nexus 6', '5.0', hash # ANDROID_5_0_GOOGLE_NEXUS_6
136
+ add_android 'Samsung Galaxy S6', '5.0', hash # ANDROID_5_0_SAMSUNG_GALAXY_S6
137
+ add_android 'Samsung Galaxy Note 4', '4.4', hash, APPIUM_1_9_1 # ANDROID_4_4_SAMSUNG_GALAXY_NOTE_4
138
+ add_android 'Samsung Galaxy Tab 4', '4.4', hash, APPIUM_1_9_1 # ANDROID_4_4_SAMSUNG_GALAXY_TAB_4
139
+
140
+ # Specific iOS devices
141
+ add_ios 'iPhone 8 Plus', '11.0', hash, APPIUM_1_7_0 # IOS_11_0_IPHONE_8_PLUS
142
+ add_ios 'iPhone X', '11.0', hash, APPIUM_1_7_0 # IOS_11_0_IPHONE_X
143
+ add_ios 'iPhone SE', '11.0', hash, APPIUM_1_7_0 # IOS_11_0_IPHONE_SE
144
+ add_ios 'iPhone 6', '11.0', hash, APPIUM_1_7_0 # IOS_11_0_IPHONE_6
145
+ add_ios 'iPhone 6S', '11.0', hash, APPIUM_1_7_0 # IOS_11_0_IPHONE_6S
146
+ add_ios 'iPhone 6S Plus', '11.0', hash, APPIUM_1_7_0 # IOS_11_0_IPHONE_6S_PLUS
147
+ add_ios 'iPad 5th', '11.0', hash, APPIUM_1_7_0 # IOS_11_0_IPAD_5TH
148
+ add_ios 'iPad Mini 4', '11.0', hash, APPIUM_1_7_0 # IOS_11_0_IPAD_MINI_4
149
+ add_ios 'iPad Pro 9.7 2016', '11.0', hash, APPIUM_1_7_0 # IOS_11_0_IPAD_PRO_9_7_2016
150
+ add_ios 'iPad 6th', '11.0', hash, APPIUM_1_7_0 # IOS_11_0_IPAD_6TH
151
+ add_ios 'iPad Pro 12.9', '11.0', hash, APPIUM_1_7_0 # IOS_11_0_IPAD_PRO_12_9
152
+
153
+ hash
154
+ end
155
+ end
156
+
157
+ # The hash of device capabilities, accessible by simple names
158
+ DEVICE_HASH = create_hash
159
+ end
160
+ end
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Maze
4
+ # Utils supporting the BrowserStack device farm integration
5
+ class BrowserStackUtils
6
+ class << self
7
+
8
+ # Uploads an app to BrowserStack for later consumption
9
+ # @param username [String] the BrowserStack username
10
+ # @param access_key [String] the BrowserStack access key
11
+ # @param app_id_file [String] the file to write the uploaded app url to BrowserStack
12
+ def upload_app(username, access_key, app, app_id_file=nil)
13
+ if app.start_with? 'bs://'
14
+ app_url = app
15
+ $logger.info "Using pre-uploaded app from #{app}"
16
+ else
17
+ expanded_app = Maze::Helper.expand_path(app)
18
+
19
+ uri = URI('https://api-cloud.browserstack.com/app-automate/upload')
20
+ request = Net::HTTP::Post.new(uri)
21
+ request.basic_auth(username, access_key)
22
+ request.set_form({ 'file' => File.new(expanded_app, 'rb') }, 'multipart/form-data')
23
+
24
+ upload_tries = 0
25
+ allowed_tries = 10
26
+
27
+ while upload_tries < allowed_tries
28
+ $logger.info "Uploading app: #{expanded_app}"
29
+ res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
30
+ http.request(request)
31
+ end
32
+
33
+ begin
34
+ body = res.body
35
+ response = JSON.parse body
36
+ if response.include?('error')
37
+ $logger.error "Upload failed due to error: #{response['error']}"
38
+ elsif !response.include?('app_url')
39
+ $logger.error "Upload failed, response did not include an app_url: #{res}"
40
+ else
41
+ # Successful upload
42
+ break
43
+ end
44
+ rescue JSON::ParserError
45
+ $logger.error "Error: expected JSON response, received: #{body}"
46
+ end
47
+
48
+ upload_tries += 1
49
+ if upload_tries < allowed_tries
50
+ $logger.info 'Retrying upload in 60s'
51
+ Kernel::sleep 60
52
+ end
53
+ end
54
+
55
+ if response.nil? || response.include?('error') || !response.include?('app_url')
56
+ raise "Failed to upload app after #{upload_tries} attempts"
57
+ end
58
+
59
+ app_url = response['app_url']
60
+ $logger.info "app uploaded to: #{app_url}"
61
+ $logger.info 'You can use this url to avoid uploading the same app more than once.'
62
+ end
63
+
64
+ unless app_id_file.nil?
65
+ $logger.info "Writing uploaded app url to #{app_id_file}"
66
+ File.write(Maze::Helper.expand_path(app_id_file), app_url)
67
+ end
68
+
69
+ app_url
70
+ end
71
+
72
+ # Starts the BrowserStack local tunnel
73
+ # @param bs_local [String] path to the BrowserStackLocal binary
74
+ # @param local_id [String] unique key for the tunnel instance
75
+ # @param access_key [String] BrowserStack access key
76
+ def start_local_tunnel(bs_local, local_id, access_key)
77
+ $logger.info 'Starting BrowserStack local tunnel'
78
+ command = "#{bs_local} -d start --key #{access_key} --local-identifier #{local_id} " \
79
+ '--force-local --only-automate --force'
80
+
81
+ # Extract the pid from the output so it gets killed at the end of the run
82
+ output = Runner.run_command(command)[0][0]
83
+ begin
84
+ @pid = JSON.parse(output)['pid']
85
+ $logger.info "BrowserStackLocal daemon running under pid #{@pid}"
86
+ rescue JSON::ParserError
87
+ $logger.warn 'Unable to parse pid from output, BrowserStackLocal will be left to die its own death'
88
+ end
89
+ end
90
+
91
+ # Stops the local tunnel
92
+ def stop_local_tunnel
93
+ if @pid
94
+ $logger.info "Stopping BrowserStack local tunnel"
95
+ Process.kill('TERM', @pid)
96
+ @pid = nil
97
+ end
98
+ rescue Errno::ESRCH
99
+ # ignored
100
+ end
101
+
102
+ # Gets the build/session info from BrowserStack
103
+ # @param username [String] the BrowserStack username
104
+ # @param access_key [String] the BrowserStack access key
105
+ # @param build_name [String] the name of the BrowserStack build
106
+ def build_info(username, access_key, build_name)
107
+ # Get the ID of a build
108
+ uri = URI("https://api.browserstack.com/app-automate/builds.json?name=#{build_name}")
109
+ request = Net::HTTP::Get.new(uri)
110
+ request.basic_auth(username, access_key)
111
+
112
+ res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
113
+ http.request(request)
114
+ end
115
+
116
+ build_info = JSON.parse(res.body)
117
+
118
+ if !build_info.empty?
119
+ build_id = build_info[0]['automation_build']['hashed_id']
120
+
121
+ # Get the build info
122
+ uri = URI("https://api.browserstack.com/app-automate/builds/#{build_id}/sessions")
123
+ request = Net::HTTP::Get.new(uri)
124
+ request.basic_auth(username, access_key)
125
+
126
+ res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
127
+ http.request(request)
128
+ end
129
+
130
+ build_json = JSON.parse(res.body)
131
+ else
132
+ raise "No build found for given ID: #{build_name}"
133
+ end
134
+ build_json
135
+ end
136
+
137
+ # @param username [String] the BrowserStack username
138
+ # @param access_key [String] the BrowserStack access key
139
+ # @param name [String] name of the build the log is being downloaded from
140
+ # @param log_url [String] url to the log
141
+ # @param log_type [Symbol] The type of log we are downloading
142
+ def download_log(username, access_key, name, log_url, log_type)
143
+ begin
144
+ path = File.join(Dir.pwd, 'maze_output', log_type.to_s)
145
+ FileUtils.makedirs(path)
146
+
147
+ uri = URI(log_url)
148
+ request = Net::HTTP::Get.new(uri)
149
+ request.basic_auth(username, access_key)
150
+
151
+ res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
152
+ http.request(request)
153
+ end
154
+
155
+ $logger.info "Saving #{log_type.to_s} log to #{path}/#{name}.log"
156
+ File.open("#{path}/#{name}.log", 'w+') { |file| file.write(res.body) }
157
+ rescue StandardError => e
158
+ $logger.warn "Unable to save log from #{log_url}"
159
+ $logger.warn e
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,220 @@
1
+ # Selenium capabilities for browsers available on BrowserStack
2
+ ---
3
+ ie_8:
4
+ browser: "ie"
5
+ browser_version: "8"
6
+ os: "windows"
7
+ os_version: "7"
8
+
9
+ ie_9:
10
+ browser: "ie"
11
+ browser_version: "9"
12
+ os: "windows"
13
+ os_version: "7"
14
+
15
+ ie_10:
16
+ browser: "ie"
17
+ browser_version: "10"
18
+ os: "windows"
19
+ os_version: "8"
20
+
21
+ ie_11:
22
+ browser: "ie"
23
+ browser_version: "11"
24
+ os: "windows"
25
+ os_version: "10"
26
+
27
+ edge_14:
28
+ browser: "edge"
29
+ browser_version: "14"
30
+ os: "windows"
31
+ os_version: "10"
32
+
33
+ edge_15:
34
+ browser: "edge"
35
+ browser_version: "15"
36
+ os: "windows"
37
+ os_version: "10"
38
+
39
+ edge_17:
40
+ browser: "edge"
41
+ browser_version: "17"
42
+ os: "windows"
43
+ os_version: "10"
44
+
45
+ safari_6:
46
+ browser: "safari"
47
+ browser_version: "6"
48
+ os: "OS X"
49
+ os_version: "lion"
50
+
51
+ safari_10:
52
+ browser: "safari"
53
+ browser_version: "10.0"
54
+ os: "OS X"
55
+ os_version: "sierra"
56
+
57
+ safari_13:
58
+ browser: "Safari"
59
+ browser_version: "13.0"
60
+ os: "OS X"
61
+ os_version: "Catalina"
62
+
63
+ safari_14:
64
+ browser: "Safari"
65
+ browser_version: "14.0"
66
+ os: "OS X"
67
+ os_version: "Big Sur"
68
+
69
+ safari_15:
70
+ browser: "Safari"
71
+ browser_version: "15.0"
72
+ os: "OS X"
73
+ os_version: "Monterey"
74
+
75
+ iphone_6s:
76
+ browser: "iphone"
77
+ device: "iPhone 6S"
78
+ os: "ios"
79
+ os_version: "9.0"
80
+ real_mobile: true
81
+
82
+ iphone_7:
83
+ browser: "iphone"
84
+ device: "iPhone 7"
85
+ os: "ios"
86
+ os_version: "10.3"
87
+ real_mobile: true
88
+
89
+ iphone_13:
90
+ browser: "iphone"
91
+ device: "iPhone 13"
92
+ os: "ios"
93
+ os_version: "15.4"
94
+ real_mobile: true
95
+
96
+ android_nexus5:
97
+ browser: "Android Browser"
98
+ device: "Google Nexus 5"
99
+ os: "android"
100
+ os_version: "4.4"
101
+ real_mobile: true
102
+
103
+ android_s6:
104
+ browser: "Android Browser"
105
+ device: "Samsung Galaxy S6"
106
+ os: "android"
107
+ os_version: "5.0"
108
+ real_mobile: true
109
+
110
+ android_s7:
111
+ browser: "Android Browser"
112
+ device: "Samsung Galaxy S7"
113
+ os: "android"
114
+ os_version: "6.0"
115
+ real_mobile: true
116
+
117
+ android_s8:
118
+ browser: "Android Browser"
119
+ device: "Samsung Galaxy S8 Plus"
120
+ os: "android"
121
+ os_version: "7.0"
122
+ real_mobile: true
123
+
124
+ firefox_30:
125
+ browser: "firefox"
126
+ browser_version: "30"
127
+ os: "windows"
128
+ os_version: "7"
129
+
130
+ firefox_56:
131
+ browser: "firefox"
132
+ browser_version: "56"
133
+ os: "windows"
134
+ os_version: "10"
135
+
136
+ firefox_78:
137
+ browser: "firefox"
138
+ browser_version: "78"
139
+ os: "windows"
140
+ os_version: "10"
141
+
142
+ firefox_latest:
143
+ browser: "firefox"
144
+ browser_version: "latest"
145
+ os: "windows"
146
+ os_version: "10"
147
+ selenium_version: "3.10.0"
148
+
149
+ chrome_30:
150
+ browser: "chrome"
151
+ browser_version: "30.0"
152
+ os: "windows"
153
+ os_version: "7"
154
+
155
+ chrome_32:
156
+ browser: "chrome"
157
+ browser_version: "32.0"
158
+ os: "windows"
159
+ os_version: "7"
160
+
161
+ chrome_34:
162
+ browser: "chrome"
163
+ browser_version: "34.0"
164
+ os: "windows"
165
+ os_version: "7"
166
+
167
+ chrome_36:
168
+ browser: "chrome"
169
+ browser_version: "36.0"
170
+ os: "windows"
171
+ os_version: "7"
172
+
173
+ chrome_38:
174
+ browser: "chrome"
175
+ browser_version: "38.0"
176
+ os: "windows"
177
+ os_version: "7"
178
+
179
+ chrome_40:
180
+ browser: "chrome"
181
+ browser_version: "40.0"
182
+ os: "windows"
183
+ os_version: "7"
184
+
185
+ chrome_42:
186
+ browser: "chrome"
187
+ browser_version: "42.0"
188
+ os: "windows"
189
+ os_version: "7"
190
+
191
+ chrome_43:
192
+ browser: "chrome"
193
+ browser_version: "43.0"
194
+ os: "windows"
195
+ os_version: "7"
196
+
197
+ chrome_53:
198
+ browser: "chrome"
199
+ browser_version: "53.0"
200
+ os: "windows"
201
+ os_version: "10"
202
+
203
+ chrome_61:
204
+ browser: "chrome"
205
+ browser_version: "61.0"
206
+ os: "windows"
207
+ os_version: "10"
208
+
209
+ chrome_72:
210
+ browser: "chrome"
211
+ browser_version: "72.0"
212
+ os: "windows"
213
+ os_version: "10"
214
+
215
+ chrome_latest:
216
+ browser: "chrome"
217
+ browser_version: "latest"
218
+ os: "windows"
219
+ os_version: "10"
220
+ selenium_version: "3.14.0"