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.
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 +206 -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 +101 -21
  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
@@ -1,100 +0,0 @@
1
- # Selenium capabilities for browserNames available on CrossbrowserNameTesting
2
- ---
3
- ie_8:
4
- browserName: "Internet Explorer"
5
- version: "8"
6
- platform: "Windows 7"
7
-
8
- ie_9:
9
- browserName: "Internet Explorer"
10
- version: "9"
11
- platform: "Windows 7"
12
-
13
- ie_10:
14
- browserName: "Internet Explorer"
15
- version: "10"
16
- os: "windows"
17
- platform: "Windows 7 64-Bit"
18
-
19
- ie_11:
20
- browserName: "Internet Explorer"
21
- version: "11"
22
- platform: "Windows 7 64-Bit"
23
-
24
- edge_14:
25
- browserName: "MicrosoftEdge"
26
- version: "14"
27
- platform: "Windows 10"
28
-
29
- edge_15:
30
- browserName: "MicrosoftEdge"
31
- version: "15"
32
- platform: "Windows 10"
33
-
34
- safari_8:
35
- browserName: "Safari"
36
- version: "8"
37
- platform: "Mac OSX 10.10"
38
-
39
- safari_10:
40
- browserName: "Safari"
41
- version: "10"
42
- platform: "Mac OSX 10.12"
43
-
44
- safari_13:
45
- browserName: "Safari"
46
- version: "13"
47
- platform: "Mac OSX 10.15"
48
-
49
- safari_14:
50
- browserName: "Safari"
51
- version: "14"
52
- platform: "MacOS 11.0"
53
-
54
- iphone_7_simulator:
55
- browserName: "Safari"
56
- deviceName: "iPhone 7 Simulator"
57
- platformVersion': "10.0"
58
- platformName': "iOS"
59
-
60
- iphone_xr:
61
- browserName: "Safari"
62
- deviceName': "iPhone XR"
63
- platformVersion': "12.1"
64
- platformName': "iOS"
65
-
66
- android_s7:
67
- browserName: "Chrome"
68
- deviceName: "Galaxy S7"
69
- platformVersion: "7.0"
70
- platformName: "Android"
71
-
72
- firefox_30:
73
- browserName: "Firefox"
74
- version: "30"
75
- platform: "Windows 7"
76
-
77
- firefox_56:
78
- browserName: "Firefox"
79
- version: "56"
80
- platform: "Mac OSX 10.13"
81
-
82
- firefox_95:
83
- browserName: "Firefox"
84
- version: "95"
85
- platform: "Windows 10"
86
-
87
- chrome_43:
88
- browserName: "Chrome"
89
- version: "43"
90
- platform: "Windows 7"
91
-
92
- chrome_61:
93
- browserName: "Chrome"
94
- version: "61"
95
- platform: "Windows 10"
96
-
97
- chrome_96:
98
- browserName: "Chrome"
99
- version: "96"
100
- platform: "Windows 10"
@@ -1,126 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Maze
4
- # Appium capabilities for each target farm
5
- class Capabilities
6
- class << self
7
- # @param device_type [String] A key from @see BrowserStackDevices::DEVICE_HASH
8
- # @param local_id [String] unique key for the tunnel instance
9
- # @param capabilities_option [String] extra capabilities provided on the command line
10
- def for_browser_stack_device(device_type, local_id, appium_version, capabilities_option)
11
- capabilities = {
12
- 'browserstack.console' => 'errors',
13
- 'browserstack.localIdentifier' => local_id,
14
- 'browserstack.local' => 'true',
15
- 'noReset' => 'true'
16
- }
17
- capabilities.merge! BrowserStackDevices::DEVICE_HASH[device_type]
18
- capabilities.merge! JSON.parse(capabilities_option)
19
- capabilities['browserstack.appium_version'] = appium_version unless appium_version.nil?
20
- capabilities
21
- end
22
-
23
- # @param browser_type [String] A key from @see browsers_bs.yml
24
- # @param local_id [String] unique key for the tunnel instance
25
- # @param capabilities_option [String] extra capabilities provided on the command line
26
- def for_browser_stack_browser(browser_type, local_id, capabilities_option)
27
- capabilities = Selenium::WebDriver::Remote::Capabilities.new
28
- capabilities['browserstack.local'] = 'true'
29
- capabilities['browserstack.localIdentifier'] = local_id
30
- capabilities['browserstack.console'] = 'errors'
31
- browsers = YAML.safe_load(File.read("#{__dir__}/browsers_bs.yml"))
32
- capabilities.merge! browsers[browser_type]
33
- capabilities.merge! JSON.parse(capabilities_option)
34
- capabilities
35
- end
36
-
37
- # @param browser_type [String] A key from @see browsers_cbt.yml
38
- # @param local_id [String] unique key for the SB tunnel instance
39
- # @param capabilities_option [String] extra capabilities provided on the command line
40
- def for_cbt_browser(browser_type, local_id, capabilities_option)
41
- capabilities = Selenium::WebDriver::Remote::Capabilities.new
42
- capabilities['tunnel_name'] = local_id
43
- browsers = YAML.safe_load(File.read("#{__dir__}/browsers_cbt.yml"))
44
- capabilities.merge! browsers[browser_type]
45
- capabilities.merge! JSON.parse(capabilities_option)
46
- capabilities
47
- end
48
-
49
- # @param device_type [String]
50
- def for_bitbar_device(bitbar_api_key, device_type, platform, platform_version, capabilities_option)
51
- capabilities = {
52
- 'bitbar_apiKey' => bitbar_api_key,
53
- 'bitbar_testrun' => "#{platform} #{platform_version}",
54
- 'bitbar_findDevice' => false,
55
- 'bitbar_testTimeout' => 7200,
56
- 'disabledAnimations' => 'true',
57
- 'noReset' => 'true'
58
- }
59
- capabilities.merge! BitBarDevices.get_device(device_type, platform, platform_version, bitbar_api_key)
60
- capabilities.merge! JSON.parse(capabilities_option)
61
- capabilities
62
- end
63
-
64
- # Constructs Appium capabilities for running on a local Android or iOS device.
65
- # @param platform [String] 'ios' or 'android'
66
- # @param capabilities_option [String] extra capabilities provided on the command line
67
- # @param team_id [String] Apple Team Id, for iOS only
68
- # @param udid [String] device UDID, for iOS only
69
- # noinspection RubyStringKeysInHashInspection
70
- def for_local(platform, capabilities_option, team_id = nil, udid = nil)
71
- capabilities = case platform.downcase
72
- when 'android'
73
- {
74
- 'platformName' => 'Android',
75
- 'automationName' => 'UiAutomator2',
76
- 'autoGrantPermissions' => 'true',
77
- 'noReset' => 'true'
78
- }
79
- when 'ios'
80
- {
81
- 'platformName' => 'iOS',
82
- 'automationName' => 'XCUITest',
83
- 'deviceName' => udid,
84
- 'xcodeOrgId' => team_id,
85
- 'xcodeSigningId' => 'iPhone Developer',
86
- 'udid' => udid,
87
- 'noReset' => 'true',
88
- 'waitForQuiescence' => false,
89
- 'newCommandTimeout' => 0
90
- }
91
- when 'macos'
92
- {
93
- 'platformName' => 'Mac'
94
- }
95
- else
96
- raise "Unsupported platform: #{platform}"
97
- end
98
- common = {
99
- 'os' => platform,
100
- 'autoAcceptAlerts': 'true'
101
- }
102
- capabilities.merge! common
103
- capabilities.merge! JSON.parse(capabilities_option)
104
- end
105
-
106
- def for_sauce_labs_device(device_name, os, os_version, tunnel_id, appium_version, capabilities_option)
107
- capabilities = {
108
- 'noReset' => true,
109
- 'deviceOrientation' => 'portrait',
110
- 'tunnelIdentifier' => tunnel_id,
111
- 'browserName' => '',
112
- 'autoAcceptAlerts' => true,
113
- 'sendKeyStrategy' => 'setValue',
114
- 'waitForQuiescence' => false,
115
- 'newCommandTimeout' => 0
116
- }
117
- capabilities['deviceName'] = device_name unless device_name.nil?
118
- capabilities['platformName'] = os unless os.nil?
119
- capabilities['platformVersion'] = os_version unless os_version.nil?
120
- capabilities.merge! JSON.parse(capabilities_option)
121
- capabilities['appiumVersion'] = appium_version unless appium_version.nil?
122
- capabilities
123
- end
124
- end
125
- end
126
- end
@@ -1,51 +0,0 @@
1
- require 'appium_lib'
2
- require_relative '../logger'
3
-
4
- module Maze
5
- module Driver
6
- # Handles Appium driver restarts and retries in the case of failure. BrowserStack's iOS 10 and 11 iOS devices in
7
- # particular seemed prone to the underlying Appium connection failing.
8
- #
9
- # For methods available on this class, @see AppAutomateDriver.
10
- class ResilientAppium
11
- # Creates the Appium Driver
12
- #
13
- # @param server_url [String] URL of the Appium server
14
- # @param capabilities [Hash] a hash of capabilities to be used in this test run
15
- # @param locator [Symbol] the primary locator strategy Appium should use to find elements
16
- def initialize(server_url, capabilities, locator = :id)
17
- @driver = Appium.new server_url,
18
- capabilities,
19
- locator
20
- end
21
-
22
- def respond_to_missing?(method_name, include_private = false)
23
- @driver.respond_to_missing? method_name, include_private
24
- end
25
-
26
- def method_missing(method, *args, &block)
27
- return super unless @driver.respond_to?(method)
28
-
29
- retries = 0
30
- until retries >= 5
31
- begin
32
- return @driver.send(method, *args, &block)
33
- rescue Selenium::WebDriver::Error::UnknownError, Selenium::WebDriver::Error::WebDriverError => error
34
- retries += 1
35
- $logger.warn 'Appium Error occurred - restarting driver:'
36
- $logger.warn error
37
- sleep 3
38
- restart
39
- end
40
- end
41
-
42
- # Re-raise the last error, although it might be better to re-raise the
43
- # first error instead. Review based on whether we ever hit this.
44
- return if error.nil?
45
-
46
- $logger.error 'Maximum retries exceeded - raising the last error'
47
- raise error
48
- end
49
- end
50
- end
51
- end
@@ -1,96 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Maze
4
- # Utils supporting the SauceLabs device farm integration
5
- class SauceLabsUtils
6
- PID_FILE = 'sc.pid'
7
- READY_FILE = 'sc.ready'
8
-
9
- class << self
10
- attr_accessor :connect_shell
11
-
12
- # Uploads an app to Sauce Labs for later consumption
13
- # @param username [String] the Sauce Labs username
14
- # @param access_key [String] the Sauce Labs access key
15
- def upload_app(username, access_key, app)
16
- uuid_regex = /\A[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}\z/
17
-
18
- if uuid_regex.match? app
19
- $logger.info "Using pre-uploaded app with UUID #{app}"
20
- app_uuid = app
21
- else
22
- expanded_app = Maze::Helper.expand_path(app)
23
- $logger.info "Uploading app: #{expanded_app}"
24
-
25
- # Upload the app tp Sauce Labs
26
- uri = URI('https://api.us-west-1.saucelabs.com/v1/storage/upload')
27
- request = Net::HTTP::Post.new(uri)
28
- request.basic_auth(username, access_key)
29
- request.set_form({ 'payload' => File.new(expanded_app, 'rb') }, 'multipart/form-data')
30
-
31
- res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
32
- http.request(request)
33
- end
34
-
35
- # Pull the UUID from the response
36
- begin
37
- response = JSON.parse res.body
38
-
39
- if response.key?('item') && response['item'].key?('id')
40
- app_uuid = response['item']['id']
41
- $logger.info "Uploaded app UUID: #{app_uuid}"
42
- $logger.info 'You can use this UUID to avoid uploading the same app more than once.'
43
- else
44
- $logger.error "Unexpected response body: #{}"
45
- raise 'App upload failed'
46
- end
47
- rescue JSON::ParserError
48
- $logger.error "Expected JSON response, received: #{body}"
49
- raise
50
- end
51
- end
52
- app_uuid
53
- end
54
-
55
- # Sauce Connect
56
- # @param sc_local [String] path to the Sauce Connect binary
57
- # @param tunnel_id [String] unique key for the tunnel instance
58
- # @param username [String] Sauce Labs username
59
- # @param access_key [String] Sauce Labs access key
60
- def start_sauce_connect(sc_local, tunnel_id, username, access_key)
61
- $logger.info 'Starting Sauce Connect tunnel'
62
- endpoint = 'https://saucelabs.com/rest/v1'
63
- wait = Maze::Wait.new(interval: 0.3, timeout: 3)
64
- connect_shell = Maze::InteractiveCLI.new
65
- success = wait.until { connect_shell.running? }
66
- raise 'Shell session did not start in time!' unless success
67
-
68
- command = "#{sc_local} -u #{username} -k #{access_key} -x #{endpoint} " \
69
- "-i #{tunnel_id} -d #{PID_FILE} -l sc.log -f #{READY_FILE}"
70
-
71
- # TODO Handle the case where the command fails, providing suitable diagnostics
72
- File.delete(READY_FILE) if File.exist?(READY_FILE)
73
- File.delete(PID_FILE) if File.exist?(PID_FILE)
74
- connect_shell.run_command command
75
- success = Maze::Wait.new(timeout: 30).until do
76
- File.exist? READY_FILE
77
- end
78
- unless success
79
- $logger.info "Failed: #{connect_shell.stdout_lines}"
80
- end
81
- end
82
-
83
- def stop_sauce_connect
84
- pid = nil
85
- File.open(PID_FILE, 'r') do |file|
86
- pid = file.read.to_i
87
- end
88
- Process.kill('INT', pid)
89
- Maze::Wait.new(timeout: 30).until do
90
- `ps aux | awk '{print $2 }' | grep #{pid}`.empty?
91
- end
92
- File.delete(PID_FILE) if File.exist?(PID_FILE)
93
- end
94
- end
95
- end
96
- end
@@ -1,71 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Maze
4
- # Utils supporting the BrowserStack device farm integration
5
- class SmartBearUtils
6
- class << self
7
- SB_READY_FILE = 'sb.ready'
8
- SB_KILL_FILE = 'sb.kill'
9
-
10
- # Starts the SmartBear local tunnel
11
- #
12
- # @param sb_local [String] path to the SBSecureTunnel binary
13
- # @param username [String] Username to start the tunnel with
14
- # @param access_key [String] CBT access key
15
- # @param tunnel_name [String] Tunnel name
16
- def start_local_tunnel(sb_local, username, access_key, tunnel_name=nil)
17
- # Make sure the ready/kill files are already deleted
18
- File.delete(SB_READY_FILE) if File.exist?(SB_READY_FILE)
19
- File.delete(SB_KILL_FILE) if File.exist?(SB_KILL_FILE)
20
-
21
- $logger.info 'Starting CBT SBSecureTunnel'
22
- command = "#{sb_local} --username #{username} --authkey #{access_key} --acceptAllCerts " \
23
- "--ready #{SB_READY_FILE} --kill #{SB_KILL_FILE}"
24
- command << " --tunnelname #{tunnel_name}" unless tunnel_name.nil?
25
-
26
- output = start_tunnel_thread(command)
27
-
28
- success = Maze::Wait.new(timeout: 30).until do
29
- File.exist?(SB_READY_FILE)
30
- end
31
- unless success
32
- $logger.error "Failed: #{output}"
33
- end
34
- end
35
-
36
- # Stops the local tunnel
37
- def stop_local_tunnel
38
- FileUtils.touch(SB_KILL_FILE)
39
- Maze::Wait.new(timeout: 30).until do
40
- !File.exist?(SB_READY_FILE)
41
- end
42
- File.delete(SB_READY_FILE) if File.exist?(SB_READY_FILE)
43
- File.delete(SB_KILL_FILE) if File.exist?(SB_KILL_FILE)
44
- end
45
-
46
- private
47
-
48
- def start_tunnel_thread(cmd)
49
- executor = lambda do
50
- Open3.popen2e(Maze::Runner.environment, cmd) do |_stdin, stdout_and_stderr, wait_thr|
51
-
52
- output = []
53
- stdout_and_stderr.each do |line|
54
- output << line
55
- $logger.debug('SBSecureTunnel') {line.chomp}
56
- end
57
-
58
- exit_status = wait_thr.value.to_i
59
- $logger.debug "Exit status: #{exit_status}"
60
-
61
- output.each { |line| $logger.warn('SBSecureTunnel') {line.chomp} } unless exit_status == 0
62
-
63
- return [output, exit_status]
64
- end
65
- end
66
-
67
- Thread.new(&executor)
68
- end
69
- end
70
- end
71
- end