bugsnag-maze-runner 6.27.0 → 7.23.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/bin/download-logs +14 -16
  3. data/bin/maze-runner +53 -15
  4. data/bin/upload-app +6 -6
  5. data/lib/features/steps/breadcrumb_steps.rb +44 -14
  6. data/lib/features/steps/error_reporting_steps.rb +16 -0
  7. data/lib/features/steps/network_steps.rb +66 -6
  8. data/lib/features/steps/payload_steps.rb +23 -0
  9. data/lib/features/steps/request_assertion_steps.rb +87 -8
  10. data/lib/features/steps/runner_steps.rb +22 -0
  11. data/lib/features/steps/session_tracking_steps.rb +1 -1
  12. data/lib/features/steps/trace_steps.rb +254 -0
  13. data/lib/features/support/internal_hooks.rb +31 -84
  14. data/lib/maze/api/appium/file_manager.rb +29 -0
  15. data/lib/maze/aws_public_ip.rb +53 -0
  16. data/lib/maze/checks/assert_check.rb +9 -31
  17. data/lib/maze/client/appium/base_client.rb +131 -0
  18. data/lib/maze/client/appium/bb_client.rb +102 -0
  19. data/lib/maze/client/appium/bb_devices.rb +127 -0
  20. data/lib/maze/client/appium/bs_client.rb +91 -0
  21. data/lib/maze/client/appium/bs_devices.rb +141 -0
  22. data/lib/maze/client/appium/bs_legacy_client.rb +31 -0
  23. data/lib/maze/client/appium/local_client.rb +67 -0
  24. data/lib/maze/client/appium.rb +23 -0
  25. data/lib/maze/client/bb_api_client.rb +102 -0
  26. data/lib/maze/client/bb_client_utils.rb +181 -0
  27. data/lib/maze/client/bs_client_utils.rb +168 -0
  28. data/lib/maze/client/selenium/base_client.rb +15 -0
  29. data/lib/maze/client/selenium/bb_browsers.yml +188 -0
  30. data/lib/maze/client/selenium/bb_client.rb +38 -0
  31. data/lib/maze/client/selenium/bs_browsers.yml +257 -0
  32. data/lib/maze/client/selenium/bs_client.rb +89 -0
  33. data/lib/maze/client/selenium/local_client.rb +16 -0
  34. data/lib/maze/client/selenium.rb +16 -0
  35. data/lib/maze/configuration.rb +18 -10
  36. data/lib/maze/docker.rb +40 -1
  37. data/lib/maze/driver/appium.rb +5 -24
  38. data/lib/maze/driver/browser.rb +12 -26
  39. data/lib/maze/errors.rb +32 -0
  40. data/lib/maze/generator.rb +55 -0
  41. data/lib/maze/helper.rb +7 -3
  42. data/lib/maze/hooks/appium_hooks.rb +29 -190
  43. data/lib/maze/hooks/browser_hooks.rb +2 -55
  44. data/lib/maze/hooks/error_code_hook.rb +49 -0
  45. data/lib/maze/hooks/hooks.rb +2 -2
  46. data/lib/maze/http_request.rb +21 -0
  47. data/lib/maze/logger.rb +16 -3
  48. data/lib/maze/maze_output.rb +88 -0
  49. data/lib/maze/option/parser.rb +17 -22
  50. data/lib/maze/option/processor.rb +21 -34
  51. data/lib/maze/option/validator.rb +38 -67
  52. data/lib/maze/option.rb +16 -18
  53. data/lib/maze/plugins/cucumber_report_plugin.rb +1 -1
  54. data/lib/maze/plugins/error_code_plugin.rb +21 -0
  55. data/lib/maze/request_list.rb +10 -5
  56. data/lib/maze/request_repeater.rb +49 -0
  57. data/lib/maze/retry_handler.rb +4 -13
  58. data/lib/maze/schemas/OtelTraceSchema.json +390 -0
  59. data/lib/maze/schemas/trace_schema.rb +7 -0
  60. data/lib/maze/schemas/trace_validator.rb +98 -0
  61. data/lib/maze/server.rb +74 -30
  62. data/lib/maze/servlets/base_servlet.rb +10 -5
  63. data/lib/maze/servlets/command_servlet.rb +10 -7
  64. data/lib/maze/servlets/log_servlet.rb +2 -2
  65. data/lib/maze/servlets/reflective_servlet.rb +12 -11
  66. data/lib/maze/servlets/servlet.rb +47 -8
  67. data/lib/maze/servlets/temp.rb +0 -0
  68. data/lib/maze/servlets/trace_servlet.rb +13 -0
  69. data/lib/maze.rb +2 -2
  70. data/lib/utils/deep_merge.rb +17 -0
  71. data/lib/utils/selenium_money_patch.rb +17 -0
  72. metadata +97 -17
  73. data/lib/maze/bitbar_devices.rb +0 -84
  74. data/lib/maze/bitbar_utils.rb +0 -112
  75. data/lib/maze/browser_stack_devices.rb +0 -160
  76. data/lib/maze/browser_stack_utils.rb +0 -164
  77. data/lib/maze/browsers_bs.yml +0 -220
  78. data/lib/maze/browsers_cbt.yml +0 -100
  79. data/lib/maze/capabilities.rb +0 -126
  80. data/lib/maze/driver/resilient_appium.rb +0 -51
  81. data/lib/maze/sauce_labs_utils.rb +0 -96
  82. data/lib/maze/smart_bear_utils.rb +0 -71
@@ -0,0 +1,67 @@
1
+ module Maze
2
+ module Client
3
+ module Appium
4
+ class LocalClient < BaseClient
5
+ def prepare_session
6
+ # Attempt to start the local appium server
7
+ appium_uri = URI(Maze.config.appium_server_url)
8
+ Maze::AppiumServer.start(address: appium_uri.host, port: appium_uri.port.to_s) if Maze.config.start_appium
9
+ end
10
+
11
+ def device_capabilities
12
+ config = Maze.config
13
+ platform = Maze::Helper.get_current_platform
14
+ capabilities = case platform
15
+ when 'android'
16
+ {
17
+ 'platformName' => 'Android',
18
+ 'automationName' => 'UiAutomator2',
19
+ 'autoGrantPermissions' => 'true',
20
+ 'noReset' => 'true'
21
+ }
22
+ when 'ios'
23
+ {
24
+ 'platformName' => 'iOS',
25
+ 'automationName' => 'XCUITest',
26
+ 'deviceName' => config.device_id,
27
+ 'xcodeOrgId' => config.apple_team_id,
28
+ 'xcodeSigningId' => 'iPhone Developer',
29
+ 'udid' => config.device_id,
30
+ 'noReset' => 'true',
31
+ 'waitForQuiescence' => false,
32
+ 'newCommandTimeout' => 0
33
+ }
34
+ when 'macos'
35
+ {
36
+ 'platformName' => 'Mac'
37
+ }
38
+ else
39
+ raise "Unsupported platform: #{config.os}"
40
+ end
41
+ common = {
42
+ 'app' => config.app,
43
+ 'os' => platform,
44
+ 'autoAcceptAlerts': 'true'
45
+ }
46
+ capabilities.merge! common
47
+ capabilities.merge! JSON.parse(config.capabilities_option)
48
+ capabilities
49
+ end
50
+
51
+ def log_run_intro
52
+ # Nothing to do
53
+ end
54
+
55
+ def log_run_outro
56
+ # Nothing to do
57
+ end
58
+
59
+ def stop_session
60
+ super
61
+ # Acquire and output the logs for the current session
62
+ Maze::Runner.run_command("log show --predicate '(process == \"#{Maze.config.app}\")' --style syslog --start '#{Maze.start_time}' > #{Maze.config.app}.log")
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,23 @@
1
+ module Maze
2
+ module Client
3
+ module Appium
4
+ def self.start
5
+ client_class =
6
+ case Maze.config.farm
7
+ when :bb then BitBarClient
8
+ when :bs
9
+ if Maze.config.legacy_driver?
10
+ $logger.info 'Using the Legacy (JWP) Appium client'
11
+ BrowserStackLegacyClient
12
+ else
13
+ $logger.info 'Using the W3C Appium client'
14
+ BrowserStackClient
15
+ end
16
+ when :local then LocalClient
17
+ end
18
+
19
+ client_class.new.tap(&:start_session)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -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,15 @@
1
+ module Maze
2
+ module Client
3
+ module Selenium
4
+ class BaseClient
5
+ def start_session
6
+ raise 'Method not implemented by this class'
7
+ end
8
+
9
+ def stop_session
10
+ Maze.driver&.driver_quit
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end