bugsnag-maze-runner 6.27.0 → 7.22.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/download-logs +14 -16
- data/bin/maze-runner +53 -15
- data/bin/upload-app +6 -6
- data/lib/features/steps/breadcrumb_steps.rb +44 -14
- data/lib/features/steps/error_reporting_steps.rb +16 -0
- data/lib/features/steps/network_steps.rb +66 -6
- data/lib/features/steps/payload_steps.rb +23 -0
- data/lib/features/steps/request_assertion_steps.rb +87 -8
- data/lib/features/steps/runner_steps.rb +22 -0
- data/lib/features/steps/session_tracking_steps.rb +1 -1
- data/lib/features/steps/trace_steps.rb +206 -0
- data/lib/features/support/internal_hooks.rb +31 -84
- data/lib/maze/api/appium/file_manager.rb +29 -0
- data/lib/maze/aws_public_ip.rb +53 -0
- data/lib/maze/checks/assert_check.rb +9 -31
- data/lib/maze/client/appium/base_client.rb +131 -0
- data/lib/maze/client/appium/bb_client.rb +102 -0
- data/lib/maze/client/appium/bb_devices.rb +127 -0
- data/lib/maze/client/appium/bs_client.rb +91 -0
- data/lib/maze/client/appium/bs_devices.rb +141 -0
- data/lib/maze/client/appium/bs_legacy_client.rb +31 -0
- data/lib/maze/client/appium/local_client.rb +67 -0
- data/lib/maze/client/appium.rb +23 -0
- data/lib/maze/client/bb_api_client.rb +102 -0
- data/lib/maze/client/bb_client_utils.rb +181 -0
- data/lib/maze/client/bs_client_utils.rb +168 -0
- data/lib/maze/client/selenium/base_client.rb +15 -0
- data/lib/maze/client/selenium/bb_browsers.yml +188 -0
- data/lib/maze/client/selenium/bb_client.rb +38 -0
- data/lib/maze/client/selenium/bs_browsers.yml +257 -0
- data/lib/maze/client/selenium/bs_client.rb +89 -0
- data/lib/maze/client/selenium/local_client.rb +16 -0
- data/lib/maze/client/selenium.rb +16 -0
- data/lib/maze/configuration.rb +18 -10
- data/lib/maze/docker.rb +40 -1
- data/lib/maze/driver/appium.rb +5 -24
- data/lib/maze/driver/browser.rb +12 -26
- data/lib/maze/errors.rb +32 -0
- data/lib/maze/generator.rb +55 -0
- data/lib/maze/helper.rb +7 -3
- data/lib/maze/hooks/appium_hooks.rb +29 -190
- data/lib/maze/hooks/browser_hooks.rb +2 -55
- data/lib/maze/hooks/error_code_hook.rb +49 -0
- data/lib/maze/hooks/hooks.rb +2 -2
- data/lib/maze/http_request.rb +21 -0
- data/lib/maze/logger.rb +16 -3
- data/lib/maze/maze_output.rb +88 -0
- data/lib/maze/option/parser.rb +17 -22
- data/lib/maze/option/processor.rb +21 -34
- data/lib/maze/option/validator.rb +38 -67
- data/lib/maze/option.rb +16 -18
- data/lib/maze/plugins/cucumber_report_plugin.rb +1 -1
- data/lib/maze/plugins/error_code_plugin.rb +21 -0
- data/lib/maze/request_list.rb +10 -5
- data/lib/maze/request_repeater.rb +49 -0
- data/lib/maze/retry_handler.rb +4 -13
- data/lib/maze/schemas/OtelTraceSchema.json +390 -0
- data/lib/maze/schemas/trace_schema.rb +7 -0
- data/lib/maze/schemas/trace_validator.rb +98 -0
- data/lib/maze/server.rb +74 -30
- data/lib/maze/servlets/base_servlet.rb +10 -5
- data/lib/maze/servlets/command_servlet.rb +10 -7
- data/lib/maze/servlets/log_servlet.rb +2 -2
- data/lib/maze/servlets/reflective_servlet.rb +12 -11
- data/lib/maze/servlets/servlet.rb +47 -8
- data/lib/maze/servlets/temp.rb +0 -0
- data/lib/maze/servlets/trace_servlet.rb +13 -0
- data/lib/maze.rb +2 -2
- data/lib/utils/deep_merge.rb +17 -0
- data/lib/utils/selenium_money_patch.rb +17 -0
- metadata +101 -21
- data/lib/maze/bitbar_devices.rb +0 -84
- data/lib/maze/bitbar_utils.rb +0 -112
- data/lib/maze/browser_stack_devices.rb +0 -160
- data/lib/maze/browser_stack_utils.rb +0 -164
- data/lib/maze/browsers_bs.yml +0 -220
- data/lib/maze/browsers_cbt.yml +0 -100
- data/lib/maze/capabilities.rb +0 -126
- data/lib/maze/driver/resilient_appium.rb +0 -51
- data/lib/maze/sauce_labs_utils.rb +0 -96
- data/lib/maze/smart_bear_utils.rb +0 -71
@@ -0,0 +1,102 @@
|
|
1
|
+
module Maze
|
2
|
+
# Utils supporting the BitBar device farm integration
|
3
|
+
module Client
|
4
|
+
class BitBarApiClient
|
5
|
+
BASE_URI = 'https://cloud.bitbar.com/api'
|
6
|
+
USER_SPECIFIC_URI = "#{BASE_URI}/v2/me"
|
7
|
+
|
8
|
+
def initialize(access_key)
|
9
|
+
@access_key = access_key
|
10
|
+
end
|
11
|
+
|
12
|
+
# Get a list of all available device groups
|
13
|
+
def get_device_group_list
|
14
|
+
query_api('device-groups')
|
15
|
+
end
|
16
|
+
|
17
|
+
# Get a list of all available devices in a device group
|
18
|
+
def get_device_list_for_group(device_group_id)
|
19
|
+
path = "device-groups/#{device_group_id}/devices"
|
20
|
+
query_api(path)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Get the id of a device group given its name
|
24
|
+
def get_device_group_id(device_group_name)
|
25
|
+
query = {
|
26
|
+
'filter': "displayName_eq_#{device_group_name}"
|
27
|
+
}
|
28
|
+
device_groups = query_api('device-groups', query)
|
29
|
+
if device_groups['data'].nil? || device_groups['data'].size == 0
|
30
|
+
nil
|
31
|
+
else
|
32
|
+
device_groups['data'][0]['id']
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def find_device_in_group(device_group_id)
|
37
|
+
path = "device-groups/#{device_group_id}/devices"
|
38
|
+
query = {
|
39
|
+
'filter': "online_eq_true"
|
40
|
+
}
|
41
|
+
all_devices = query_api(path, query)
|
42
|
+
|
43
|
+
$logger.debug "All available devices in group #{device_group_id}: #{JSON.pretty_generate(all_devices)}"
|
44
|
+
filtered_devices = all_devices['data'].reject { |device| device['locked'] }
|
45
|
+
return filtered_devices.size, filtered_devices.sample
|
46
|
+
end
|
47
|
+
|
48
|
+
def find_device(device_name)
|
49
|
+
path = "devices"
|
50
|
+
query = {
|
51
|
+
'filter': "displayName_eq_#{device_name};online_eq_true",
|
52
|
+
}
|
53
|
+
all_devices = query_api(path, query, BASE_URI)['data']
|
54
|
+
if all_devices.size == 0
|
55
|
+
Maze::Helper.error_exit "No devices found with name '#{device_name}'"
|
56
|
+
else
|
57
|
+
$logger.debug "All available devices with name #{device_name}: #{JSON.pretty_generate(all_devices)}"
|
58
|
+
filtered_devices = all_devices.reject { |device| device['locked'] }
|
59
|
+
if filtered_devices.size == 0
|
60
|
+
Maze::Helper.error_exit "None of the #{all_devices.size} devices with name '#{device_name}' are currently available"
|
61
|
+
else
|
62
|
+
$logger.info "#{filtered_devices.size} of #{all_devices.size} devices with name '#{device_name}' are available"
|
63
|
+
end
|
64
|
+
|
65
|
+
return filtered_devices.sample
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def get_device_session_ui_link(session_id)
|
70
|
+
query = {
|
71
|
+
'filter': "clientSideId_eq_#{session_id}"
|
72
|
+
}
|
73
|
+
data = query_api('device-sessions', query)['data']
|
74
|
+
if data.size == 1
|
75
|
+
data[0]['uiLink']
|
76
|
+
else
|
77
|
+
$logger.warn "Failed to get UI link for session #{session_id}. Expected exactly 1 device-session, found #{data.size}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
# Queries the BitBar REST API
|
84
|
+
def query_api(path, query=nil, uri=USER_SPECIFIC_URI)
|
85
|
+
if query
|
86
|
+
encoded_query = URI.encode_www_form(query)
|
87
|
+
uri = URI("#{uri}/#{path}?#{encoded_query}")
|
88
|
+
else
|
89
|
+
uri = URI("#{uri}/#{path}")
|
90
|
+
end
|
91
|
+
request = Net::HTTP::Get.new(uri)
|
92
|
+
request.basic_auth(@access_key, '')
|
93
|
+
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
|
94
|
+
http.request(request)
|
95
|
+
end
|
96
|
+
|
97
|
+
JSON.parse(res.body)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
@@ -0,0 +1,181 @@
|
|
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
|
+
module Client
|
9
|
+
class BitBarClientUtils
|
10
|
+
BB_READY_FILE = 'bb.ready'
|
11
|
+
BB_KILL_FILE = 'bb.kill'
|
12
|
+
BB_USER_PREFIX = 'BB_USER_'
|
13
|
+
BB_KEY_PREFIX = 'BB_KEY_'
|
14
|
+
|
15
|
+
class << self
|
16
|
+
|
17
|
+
# Uploads an app to BitBar for later consumption
|
18
|
+
# @param api_key [String] The BitBar API key
|
19
|
+
# @param app [String] A path to the application file
|
20
|
+
def upload_app(api_key, app)
|
21
|
+
uuid_regex = /\A[0-9]+\z/
|
22
|
+
|
23
|
+
if uuid_regex.match? app
|
24
|
+
$logger.info "Using pre-uploaded app with ID #{app}"
|
25
|
+
app_uuid = app
|
26
|
+
else
|
27
|
+
expanded_app = Maze::Helper.expand_path(app)
|
28
|
+
$logger.info "Uploading app: #{expanded_app}"
|
29
|
+
|
30
|
+
# Upload the app to BitBar
|
31
|
+
uri = URI('https://cloud.bitbar.com/api/me/files')
|
32
|
+
request = Net::HTTP::Post.new(uri)
|
33
|
+
request.basic_auth(api_key, '')
|
34
|
+
request.set_form({ 'file' => File.new(expanded_app, 'rb') }, 'multipart/form-data')
|
35
|
+
|
36
|
+
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
|
37
|
+
http.request(request)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Pull the UUID from the response
|
41
|
+
begin
|
42
|
+
response = JSON.parse res.body
|
43
|
+
if response.key?('id')
|
44
|
+
app_uuid = response['id'].to_s
|
45
|
+
$logger.info "Uploaded app ID: #{app_uuid}"
|
46
|
+
$logger.info 'You can use this ID to avoid uploading the same app more than once.'
|
47
|
+
else
|
48
|
+
$logger.error "Unexpected response body: #{response}"
|
49
|
+
raise 'App upload failed'
|
50
|
+
end
|
51
|
+
rescue JSON::ParserError
|
52
|
+
$logger.error "Expected JSON response, received: #{res}"
|
53
|
+
raise
|
54
|
+
end
|
55
|
+
end
|
56
|
+
app_uuid
|
57
|
+
end
|
58
|
+
|
59
|
+
# Requests an unused account id from the test-management-service
|
60
|
+
# @param tms_uri [String] The URI of the test-management-service
|
61
|
+
#
|
62
|
+
# @returns
|
63
|
+
def account_credentials(tms_uri)
|
64
|
+
Maze::Wait.new(interval: 10, timeout: 1800).until do
|
65
|
+
output = request_account_index(tms_uri)
|
66
|
+
case output.code
|
67
|
+
when '200'
|
68
|
+
body = JSON.parse(output.body, {symbolize_names: true})
|
69
|
+
@account_id = account_id = body[:id]
|
70
|
+
$logger.info "Using account #{account_id}, expiring at #{body[:expiry]}"
|
71
|
+
{
|
72
|
+
username: ENV["#{BB_USER_PREFIX}#{account_id}"],
|
73
|
+
access_key: ENV["#{BB_KEY_PREFIX}#{account_id}"]
|
74
|
+
}
|
75
|
+
when '409'
|
76
|
+
# All accounts are in use, wait for one to become available
|
77
|
+
$logger.info 'All accounts are currently in use, retrying in 30s'
|
78
|
+
false
|
79
|
+
else
|
80
|
+
# Something has gone wrong, throw an error
|
81
|
+
$logger.error "Unexpected status code (#{output.code}) received from test-management server: #{output.body}"
|
82
|
+
raise
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Makes the HTTP call to acquire an account id
|
88
|
+
# @param tms_uri [String] The URI of the test-management-service
|
89
|
+
#
|
90
|
+
# @returns
|
91
|
+
def request_account_index(tms_uri)
|
92
|
+
uri = URI("#{tms_uri}/account/request")
|
93
|
+
request = Net::HTTP::Get.new(uri)
|
94
|
+
request['Authorization'] = Maze.config.tms_token
|
95
|
+
res = Net::HTTP.start(uri.hostname, uri.port) do |http|
|
96
|
+
http.request(request)
|
97
|
+
end
|
98
|
+
res
|
99
|
+
end
|
100
|
+
|
101
|
+
# Informs the test-management-service that in-use account id is no longer in use
|
102
|
+
# @param tms_uri [String] The URI of the test-management-service
|
103
|
+
def release_account(tms_uri)
|
104
|
+
$logger.info "Release account #{@account_id}"
|
105
|
+
uri = URI("#{tms_uri}/account/release?account_id=#{@account_id}")
|
106
|
+
request = Net::HTTP::Get.new(uri)
|
107
|
+
request['Authorization'] = Maze.config.tms_token
|
108
|
+
res = Net::HTTP.start(uri.hostname, uri.port) do |http|
|
109
|
+
http.request(request)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Starts the BitBar local tunnel
|
114
|
+
#
|
115
|
+
# @param sb_local [String] path to the SBSecureTunnel binary
|
116
|
+
# @param username [String] Username to start the tunnel with
|
117
|
+
# @param access_key [String] access key
|
118
|
+
def start_local_tunnel(sb_local, username, access_key)
|
119
|
+
# Make sure the ready/kill files are already deleted
|
120
|
+
File.delete(BB_READY_FILE) if File.exist?(BB_READY_FILE)
|
121
|
+
File.delete(BB_KILL_FILE) if File.exist?(BB_KILL_FILE)
|
122
|
+
|
123
|
+
$logger.info 'Starting SBSecureTunnel'
|
124
|
+
command = "#{sb_local} --username #{username} --authkey #{access_key} --acceptAllCerts " \
|
125
|
+
"--ready #{BB_READY_FILE} --kill #{BB_KILL_FILE}"
|
126
|
+
|
127
|
+
output = start_tunnel_thread(command)
|
128
|
+
|
129
|
+
success = Maze::Wait.new(timeout: 30).until do
|
130
|
+
File.exist?(BB_READY_FILE)
|
131
|
+
end
|
132
|
+
unless success
|
133
|
+
$logger.error "Failed: #{output}"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Stops the local tunnel
|
138
|
+
def stop_local_tunnel
|
139
|
+
FileUtils.touch(BB_KILL_FILE)
|
140
|
+
|
141
|
+
success = Maze::Wait.new(timeout: 30).until do
|
142
|
+
@tunnel_thread.nil? || !@tunnel_thread.alive?
|
143
|
+
end
|
144
|
+
|
145
|
+
if success
|
146
|
+
$logger.info("Shutdown SBSecureTunnel")
|
147
|
+
else
|
148
|
+
$logger.error("Failed to shutdown SBSecureTunnel!")
|
149
|
+
end
|
150
|
+
|
151
|
+
@tunnel_thread = nil
|
152
|
+
File.delete(BB_READY_FILE) if File.exist?(BB_READY_FILE)
|
153
|
+
File.delete(BB_KILL_FILE) if File.exist?(BB_KILL_FILE)
|
154
|
+
end
|
155
|
+
|
156
|
+
private
|
157
|
+
|
158
|
+
def start_tunnel_thread(cmd)
|
159
|
+
executor = lambda do
|
160
|
+
Open3.popen2e(Maze::Runner.environment, cmd) do |_stdin, stdout_and_stderr, wait_thr|
|
161
|
+
|
162
|
+
output = []
|
163
|
+
stdout_and_stderr.each do |line|
|
164
|
+
output << line
|
165
|
+
end
|
166
|
+
|
167
|
+
exit_status = wait_thr.value.to_i
|
168
|
+
$logger.debug "Exit status: #{exit_status}"
|
169
|
+
|
170
|
+
output.each { |line| $logger.warn('SBSecureTunnel') {line.chomp} } unless exit_status == 0
|
171
|
+
|
172
|
+
return [output, exit_status]
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
@tunnel_thread = Thread.new(&executor)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Maze
|
4
|
+
module Client
|
5
|
+
# Utils supporting the BrowserStack device farm integration
|
6
|
+
class BrowserStackClientUtils
|
7
|
+
class << self
|
8
|
+
|
9
|
+
# Uploads an app to BrowserStack for later consumption
|
10
|
+
# @param username [String] the BrowserStack username
|
11
|
+
# @param access_key [String] the BrowserStack access key
|
12
|
+
# @param app_id_file [String] the file to write the uploaded app url to BrowserStack
|
13
|
+
def upload_app(username, access_key, app, app_id_file=nil)
|
14
|
+
if app.start_with? 'bs://'
|
15
|
+
app_url = app
|
16
|
+
$logger.info "Using pre-uploaded app from #{app}"
|
17
|
+
else
|
18
|
+
expanded_app = Maze::Helper.expand_path(app)
|
19
|
+
|
20
|
+
uri = URI('https://api-cloud.browserstack.com/app-automate/upload')
|
21
|
+
request = Net::HTTP::Post.new(uri)
|
22
|
+
request.basic_auth(username, access_key)
|
23
|
+
request.set_form({ 'file' => File.new(expanded_app, 'rb') }, 'multipart/form-data')
|
24
|
+
|
25
|
+
upload_tries = 0
|
26
|
+
allowed_tries = 10
|
27
|
+
|
28
|
+
while upload_tries < allowed_tries
|
29
|
+
begin
|
30
|
+
$logger.info "Uploading app: #{expanded_app}"
|
31
|
+
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
|
32
|
+
http.request(request)
|
33
|
+
end
|
34
|
+
|
35
|
+
body = res.body
|
36
|
+
response = JSON.parse body
|
37
|
+
if response.include?('error')
|
38
|
+
$logger.error "Upload failed due to error: #{response['error']}"
|
39
|
+
elsif !response.include?('app_url')
|
40
|
+
$logger.error "Upload failed, response did not include an app_url: #{res}"
|
41
|
+
else
|
42
|
+
# Successful upload
|
43
|
+
break
|
44
|
+
end
|
45
|
+
rescue Net::ReadTimeout
|
46
|
+
$logger.error "Upload failed due to ReadTimeout"
|
47
|
+
rescue JSON::ParserError
|
48
|
+
$logger.error "Unexpected JSON response, received: #{body}"
|
49
|
+
end
|
50
|
+
|
51
|
+
upload_tries += 1
|
52
|
+
if upload_tries < allowed_tries
|
53
|
+
$logger.info 'Retrying upload in 60s'
|
54
|
+
Kernel::sleep 60
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
if response.nil? || response.include?('error') || !response.include?('app_url')
|
59
|
+
raise "Failed to upload app after #{upload_tries} attempts"
|
60
|
+
end
|
61
|
+
|
62
|
+
app_url = response['app_url']
|
63
|
+
$logger.info "App uploaded to: #{app_url}"
|
64
|
+
$logger.info 'You can use this url to avoid uploading the same app more than once.'
|
65
|
+
end
|
66
|
+
|
67
|
+
unless app_id_file.nil?
|
68
|
+
$logger.info "Writing uploaded app url to #{app_id_file}"
|
69
|
+
File.write(Maze::Helper.expand_path(app_id_file), app_url)
|
70
|
+
end
|
71
|
+
|
72
|
+
app_url
|
73
|
+
end
|
74
|
+
|
75
|
+
# Starts the BrowserStack local tunnel
|
76
|
+
# @param bs_local [String] path to the BrowserStackLocal binary
|
77
|
+
# @param local_id [String] unique key for the tunnel instance
|
78
|
+
# @param access_key [String] BrowserStack access key
|
79
|
+
def start_local_tunnel(bs_local, local_id, access_key)
|
80
|
+
$logger.info 'Starting BrowserStack local tunnel'
|
81
|
+
command = "#{bs_local} -d start --key #{access_key} --local-identifier #{local_id} " \
|
82
|
+
'--force-local --only-automate --force'
|
83
|
+
|
84
|
+
# Extract the pid from the output so it gets killed at the end of the run
|
85
|
+
output = Runner.run_command(command)[0][0]
|
86
|
+
begin
|
87
|
+
@pid = JSON.parse(output)['pid']
|
88
|
+
$logger.info "BrowserStackLocal daemon running under pid #{@pid}"
|
89
|
+
rescue JSON::ParserError
|
90
|
+
$logger.warn 'Unable to parse pid from output, BrowserStackLocal will be left to die its own death'
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Stops the local tunnel
|
95
|
+
def stop_local_tunnel
|
96
|
+
if @pid
|
97
|
+
$logger.info "Stopping BrowserStack local tunnel"
|
98
|
+
Process.kill('TERM', @pid)
|
99
|
+
@pid = nil
|
100
|
+
end
|
101
|
+
rescue Errno::ESRCH
|
102
|
+
# ignored
|
103
|
+
end
|
104
|
+
|
105
|
+
# Gets the build/session info from BrowserStack
|
106
|
+
# @param username [String] the BrowserStack username
|
107
|
+
# @param access_key [String] the BrowserStack access key
|
108
|
+
# @param build_name [String] the name of the BrowserStack build
|
109
|
+
def build_info(username, access_key, build_name)
|
110
|
+
# Get the ID of a build
|
111
|
+
uri = URI("https://api.browserstack.com/app-automate/builds.json?name=#{build_name}")
|
112
|
+
request = Net::HTTP::Get.new(uri)
|
113
|
+
request.basic_auth(username, access_key)
|
114
|
+
|
115
|
+
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
|
116
|
+
http.request(request)
|
117
|
+
end
|
118
|
+
|
119
|
+
build_info = JSON.parse(res.body)
|
120
|
+
|
121
|
+
if !build_info.empty?
|
122
|
+
build_id = build_info[0]['automation_build']['hashed_id']
|
123
|
+
|
124
|
+
# Get the build info
|
125
|
+
uri = URI("https://api.browserstack.com/app-automate/builds/#{build_id}/sessions")
|
126
|
+
request = Net::HTTP::Get.new(uri)
|
127
|
+
request.basic_auth(username, access_key)
|
128
|
+
|
129
|
+
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
|
130
|
+
http.request(request)
|
131
|
+
end
|
132
|
+
|
133
|
+
build_json = JSON.parse(res.body)
|
134
|
+
else
|
135
|
+
raise "No build found for given ID: #{build_name}"
|
136
|
+
end
|
137
|
+
build_json
|
138
|
+
end
|
139
|
+
|
140
|
+
# @param username [String] the BrowserStack username
|
141
|
+
# @param access_key [String] the BrowserStack access key
|
142
|
+
# @param name [String] name of the build the log is being downloaded from
|
143
|
+
# @param log_url [String] url to the log
|
144
|
+
# @param log_type [Symbol] The type of log we are downloading
|
145
|
+
def download_log(username, access_key, name, log_url, log_type)
|
146
|
+
begin
|
147
|
+
path = File.join(Dir.pwd, 'maze_output', log_type.to_s)
|
148
|
+
FileUtils.makedirs(path)
|
149
|
+
|
150
|
+
uri = URI(log_url)
|
151
|
+
request = Net::HTTP::Get.new(uri)
|
152
|
+
request.basic_auth(username, access_key)
|
153
|
+
|
154
|
+
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
|
155
|
+
http.request(request)
|
156
|
+
end
|
157
|
+
|
158
|
+
$logger.info "Saving #{log_type.to_s} log to #{path}/#{name}.log"
|
159
|
+
File.open("#{path}/#{name}.log", 'w+') { |file| file.write(res.body) }
|
160
|
+
rescue StandardError => e
|
161
|
+
$logger.warn "Unable to save log from #{log_url}"
|
162
|
+
$logger.warn e
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
chrome_latest:
|
2
|
+
platform: 'Windows'
|
3
|
+
osVersion: '11'
|
4
|
+
browserName: 'chrome'
|
5
|
+
version: 'latest'
|
6
|
+
resolution: '1920x1080'
|
7
|
+
|
8
|
+
chrome_108:
|
9
|
+
platform: 'Windows'
|
10
|
+
osVersion: '11'
|
11
|
+
browserName: 'chrome'
|
12
|
+
version: '108'
|
13
|
+
resolution: '1920x1080'
|
14
|
+
|
15
|
+
chrome_107:
|
16
|
+
platform: 'Windows'
|
17
|
+
osVersion: '11'
|
18
|
+
browserName: 'chrome'
|
19
|
+
version: '107'
|
20
|
+
resolution: '1920x1080'
|
21
|
+
|
22
|
+
chrome_106:
|
23
|
+
platform: 'Windows'
|
24
|
+
osVersion: '11'
|
25
|
+
browserName: 'chrome'
|
26
|
+
version: '106'
|
27
|
+
resolution: '1920x1080'
|
28
|
+
|
29
|
+
chrome_105:
|
30
|
+
platform: 'Windows'
|
31
|
+
osVersion: '11'
|
32
|
+
browserName: 'chrome'
|
33
|
+
version: '105'
|
34
|
+
resolution: '1920x1080'
|
35
|
+
|
36
|
+
chrome_104:
|
37
|
+
platform: 'Windows'
|
38
|
+
osVersion: '11'
|
39
|
+
browserName: 'chrome'
|
40
|
+
version: '104'
|
41
|
+
resolution: '1920x1080'
|
42
|
+
|
43
|
+
chrome_103:
|
44
|
+
platform: 'Windows'
|
45
|
+
osVersion: '11'
|
46
|
+
browserName: 'chrome'
|
47
|
+
version: '103'
|
48
|
+
resolution: '1920x1080'
|
49
|
+
|
50
|
+
chrome_72:
|
51
|
+
platform: 'Windows'
|
52
|
+
osVersion: '10'
|
53
|
+
browserName: 'chrome'
|
54
|
+
version: '72'
|
55
|
+
resolution: '1920x1080'
|
56
|
+
|
57
|
+
chrome_43:
|
58
|
+
platform': 'Windows'
|
59
|
+
osVersion: '10'
|
60
|
+
browserName: 'chrome'
|
61
|
+
version: '43'
|
62
|
+
resolution: '1920x1080'
|
63
|
+
|
64
|
+
firefox_latest:
|
65
|
+
platform: 'Windows'
|
66
|
+
osVersion: '11'
|
67
|
+
browserName: 'firefox'
|
68
|
+
version: 'latest'
|
69
|
+
resolution: '1920x1080'
|
70
|
+
|
71
|
+
firefox_107:
|
72
|
+
platform: 'Windows'
|
73
|
+
osVersion: '11'
|
74
|
+
browserName: 'firefox'
|
75
|
+
version: '107'
|
76
|
+
resolution: '1920x1080'
|
77
|
+
|
78
|
+
firefox_106:
|
79
|
+
platform: 'Windows'
|
80
|
+
osVersion: '11'
|
81
|
+
browserName: 'firefox'
|
82
|
+
version: '106'
|
83
|
+
resolution: '1920x1080'
|
84
|
+
|
85
|
+
firefox_105:
|
86
|
+
platform: 'Windows'
|
87
|
+
osVersion: '11'
|
88
|
+
browserName: 'firefox'
|
89
|
+
version: '105'
|
90
|
+
resolution: '1920x1080'
|
91
|
+
|
92
|
+
firefox_104:
|
93
|
+
platform: 'Windows'
|
94
|
+
osVersion: '11'
|
95
|
+
browserName: 'firefox'
|
96
|
+
version: '104'
|
97
|
+
resolution: '1920x1080'
|
98
|
+
|
99
|
+
firefox_103:
|
100
|
+
platform: 'Windows'
|
101
|
+
osVersion: '11'
|
102
|
+
browserName: 'firefox'
|
103
|
+
version: '103'
|
104
|
+
resolution: '1920x1080'
|
105
|
+
|
106
|
+
firefox_102:
|
107
|
+
platform: 'Windows'
|
108
|
+
osVersion: '11'
|
109
|
+
browserName: 'firefox'
|
110
|
+
version: '102'
|
111
|
+
resolution: '1920x1080'
|
112
|
+
|
113
|
+
firefox_78:
|
114
|
+
platform: 'Windows'
|
115
|
+
osVersion: '10'
|
116
|
+
browserName: 'firefox'
|
117
|
+
version: '78'
|
118
|
+
resolution: '1920x1080'
|
119
|
+
|
120
|
+
ie_11:
|
121
|
+
platform: 'Windows'
|
122
|
+
osVersion: '10'
|
123
|
+
browserName: 'internet explorer'
|
124
|
+
version: '11'
|
125
|
+
resolution: '1920x1080'
|
126
|
+
|
127
|
+
edge_latest:
|
128
|
+
platform: 'Windows'
|
129
|
+
osVersion: '11'
|
130
|
+
browserName: 'MicrosoftEdge'
|
131
|
+
version: 'latest'
|
132
|
+
resolution: '1920x1080'
|
133
|
+
|
134
|
+
edge_106:
|
135
|
+
platform: 'Windows'
|
136
|
+
osVersion: '11'
|
137
|
+
browserName: 'MicrosoftEdge'
|
138
|
+
version: '106'
|
139
|
+
resolution: '1920x1080'
|
140
|
+
|
141
|
+
edge_105:
|
142
|
+
platform: 'Windows'
|
143
|
+
osVersion: '11'
|
144
|
+
browserName: 'MicrosoftEdge'
|
145
|
+
version: '105'
|
146
|
+
resolution: '1920x1080'
|
147
|
+
|
148
|
+
edge_104:
|
149
|
+
platform: 'Windows'
|
150
|
+
osVersion: '11'
|
151
|
+
browserName: 'MicrosoftEdge'
|
152
|
+
version: '104'
|
153
|
+
resolution: '1920x1080'
|
154
|
+
|
155
|
+
edge_103:
|
156
|
+
platform: 'Windows'
|
157
|
+
osVersion: '11'
|
158
|
+
browserName: 'MicrosoftEdge'
|
159
|
+
version: '103'
|
160
|
+
resolution: '1920x1080'
|
161
|
+
|
162
|
+
edge_102:
|
163
|
+
platform: 'Windows'
|
164
|
+
osVersion: '11'
|
165
|
+
browserName: 'MicrosoftEdge'
|
166
|
+
version: '102'
|
167
|
+
resolution: '1920x1080'
|
168
|
+
|
169
|
+
edge_101:
|
170
|
+
platform: 'Windows'
|
171
|
+
osVersion: '11'
|
172
|
+
browserName: 'MicrosoftEdge'
|
173
|
+
version: '101'
|
174
|
+
resolution: '1920x1080'
|
175
|
+
|
176
|
+
safari_16:
|
177
|
+
platform: 'macOS'
|
178
|
+
osVersion: '13'
|
179
|
+
browserName: 'safari'
|
180
|
+
version: '16'
|
181
|
+
resolution: '2560x1920'
|
182
|
+
|
183
|
+
safari_15:
|
184
|
+
platform: 'macOS'
|
185
|
+
osVersion: '12'
|
186
|
+
browserName: 'safari'
|
187
|
+
version: '15'
|
188
|
+
resolution: '2560x1920'
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Maze
|
2
|
+
module Client
|
3
|
+
module Selenium
|
4
|
+
class BitBarClient < BaseClient
|
5
|
+
def start_session
|
6
|
+
config = Maze.config
|
7
|
+
if ENV['BUILDKITE']
|
8
|
+
credentials = Maze::Client::BitBarClientUtils.account_credentials config.tms_uri
|
9
|
+
config.username = credentials[:username]
|
10
|
+
config.access_key = credentials[:access_key]
|
11
|
+
end
|
12
|
+
capabilities = ::Selenium::WebDriver::Remote::Capabilities.new
|
13
|
+
capabilities['bitbar_apiKey'] = config.access_key
|
14
|
+
browsers = YAML.safe_load(File.read("#{__dir__}/bb_browsers.yml"))
|
15
|
+
capabilities.merge! browsers[config.browser]
|
16
|
+
capabilities.merge! JSON.parse(config.capabilities_option)
|
17
|
+
config.capabilities = capabilities
|
18
|
+
|
19
|
+
Maze::Client::BitBarClientUtils.start_local_tunnel config.sb_local,
|
20
|
+
config.username,
|
21
|
+
config.access_key
|
22
|
+
|
23
|
+
# TODO This probably needs to be settable via an environment variable
|
24
|
+
# selenium_url = 'https://us-west-desktop-hub.bitbar.com/wd/hub'
|
25
|
+
selenium_url = 'https://eu-desktop-hub.bitbar.com/wd/hub'
|
26
|
+
Maze.driver = Maze::Driver::Browser.new :remote, selenium_url, config.capabilities
|
27
|
+
Maze.driver.start_driver
|
28
|
+
end
|
29
|
+
|
30
|
+
def stop_session
|
31
|
+
super
|
32
|
+
Maze::Client::BitBarClientUtils.stop_local_tunnel
|
33
|
+
Maze::Client::BitBarClientUtils.release_account(Maze.config.tms_uri) if ENV['BUILDKITE']
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|