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,173 @@
1
+ require 'pty'
2
+ # TODO: Removed pending PLAT-6322
3
+ # require 'boring'
4
+
5
+ module Maze
6
+ # Encapsulates a shell session, retaining state and input streams for interactive tests
7
+ class InteractiveCLI
8
+ # @!attribute [r] stdout_lines
9
+ # @return [Array] An array of output strings received from the terminals STDOUT pipe
10
+ attr_reader :stdout_lines
11
+
12
+ # @!attribute [r] stderr_lines
13
+ # @return [Array] An array of error strings received from the terminals STDERR pipe
14
+ attr_reader :stderr_lines
15
+
16
+ # @!attribute [r] pid
17
+ # @return [Number, nil] The PID of the running terminal
18
+ attr_reader :pid
19
+
20
+ # @!attribute [r] current_buffer
21
+ # @return [String] A string representation of the current output present in the terminal
22
+ attr_reader :current_buffer
23
+
24
+ # Creates an InteractiveCLI instance
25
+ #
26
+ # @param shell [String] A path to the shell to run, defaults to `/bin/sh`
27
+ # @param stop_command [String] The stop command, defaults to `exit`
28
+ def initialize(shell = '/bin/sh', stop_command = 'exit')
29
+ @shell = shell
30
+ @stop_command = stop_command
31
+ @stdout_lines = []
32
+ @stderr_lines = []
33
+ @on_exit_blocks = []
34
+ @current_buffer = ''
35
+ # TODO: Removed pending PLAT-6322
36
+ # @boring = Boring.new
37
+
38
+ start_threaded_shell(shell)
39
+ end
40
+
41
+ def start(threaded: true)
42
+ threaded ? start_threaded_shell(@shell) : start_shell(@shell)
43
+ end
44
+
45
+ # Attempts to stop the shell using the preset command and wait for it to exit
46
+ #
47
+ # @return [Boolean] If the shell stopped successfully
48
+ def stop
49
+ run_command(@stop_command)
50
+
51
+ @in_stream.close
52
+
53
+ maybe_thread = @thread.join(15)
54
+
55
+ # The thread did not exit!
56
+ return false if maybe_thread.nil?
57
+
58
+ @pid = nil
59
+ true
60
+ end
61
+
62
+ # @return [Boolean] Whether the shell is currently running
63
+ def running?
64
+ !@pid.nil?
65
+ end
66
+
67
+ # Runs the given command if the shell is running
68
+ #
69
+ # @param command [String] The command to run
70
+ #
71
+ # @return [Boolean] true if the command is executed, false otherwise
72
+ def run_command(command)
73
+ return false unless running?
74
+
75
+ @in_stream.puts(command)
76
+
77
+ true
78
+ rescue ::Errno::EIO => err
79
+ $logger.debug(pid) { "EIO error: #{err}" }
80
+ false
81
+ end
82
+
83
+ def on_exit(&block)
84
+ @on_exit_blocks << block
85
+ end
86
+
87
+ private
88
+
89
+ # Starts a shell on another thread
90
+ #
91
+ # @param shell [String] A path to the shell to run
92
+ def start_threaded_shell(shell)
93
+ @thread = Thread.new do
94
+ start_shell(shell)
95
+ end
96
+ end
97
+
98
+ # Starts a shell
99
+ #
100
+ # @param shell [String] A path to the shell to run
101
+ def start_shell(shell)
102
+ stderr_reader, stderr_writer = IO.pipe
103
+
104
+ PTY.spawn(shell, err: stderr_writer.fileno) do |stdout, stdin, pid|
105
+ # We don't need to write to stderr so close it ASAP
106
+ stderr_writer.close
107
+
108
+ $logger.debug(pid) { 'PTY spawned!' }
109
+ @pid = pid
110
+ @in_stream = stdin
111
+
112
+ stdout_thread = Thread.new do
113
+ stdout.each_char do |char|
114
+ if char == "\n"
115
+ line = format_line(@current_buffer)
116
+
117
+ $logger.debug("#{pid} STDOUT") { line.dump }
118
+ @stdout_lines << line
119
+ @current_buffer.clear
120
+ else
121
+ @current_buffer << char
122
+ end
123
+ end
124
+ rescue ::Errno::EIO => err
125
+ $logger.debug(pid) { "EIO error: #{err}" }
126
+ end
127
+
128
+ stderr_thread = Thread.new do
129
+ buffer = ''
130
+
131
+ stderr_reader.each_char do |char|
132
+ if char == "\n"
133
+ line = format_line(buffer)
134
+
135
+ $logger.debug("#{pid} STDERR") { line.dump }
136
+ @stderr_lines << line
137
+ buffer.clear
138
+ else
139
+ buffer << char
140
+ end
141
+ end
142
+ rescue ::Errno::EIO => err
143
+ $logger.debug(pid) { "EIO error: #{err}" }
144
+ end
145
+
146
+ _, status = Process.wait2(@pid)
147
+ @pid = nil
148
+
149
+ # Stop the thread that's reading from stdout
150
+ failed = stdout_thread.join(5).nil?
151
+ raise 'stdout is blocked!' if failed
152
+
153
+ # Stop the thread that's reading from stderr
154
+ failed = stderr_thread.join(5).nil?
155
+ raise 'stderr is blocked!' if failed
156
+
157
+ $logger.debug(pid) { "PTY exit status: #{status.exitstatus}" }
158
+ @on_exit_blocks.each do |block|
159
+ block.call(status.exitstatus)
160
+ end
161
+ end
162
+ ensure
163
+ stderr_reader.close unless stderr_reader.closed?
164
+ stderr_writer.close unless stderr_writer.closed?
165
+ end
166
+
167
+ def format_line(line)
168
+ # TODO: Removed pending PLAT-6322
169
+ # @boring.scrub(line.strip)
170
+ line.strip
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+ require 'singleton'
5
+
6
+ # Logger classes
7
+ module Maze
8
+ # A logger, with level configured according to the environment
9
+ class Logger < Logger
10
+
11
+ include Singleton
12
+ def initialize
13
+ if ENV['VERBOSE'] || ENV['DEBUG']
14
+ super(STDOUT, level: Logger::DEBUG)
15
+ elsif ENV['QUIET']
16
+ super(STDOUT, level: Logger::ERROR)
17
+ else
18
+ super(STDOUT, level: Logger::INFO)
19
+ end
20
+ self.datetime_format = '%Y-%m-%d %H:%M:%S'
21
+ end
22
+ end
23
+
24
+ $logger = Maze::Logger.instance
25
+
26
+ # A collection of logging utilities
27
+ class LogUtil
28
+ class << self
29
+ # Logs Hash-based data, accounting for things like file upload requests that are too big to log meaningfully.
30
+ #
31
+ # @param severity [Integer] A constant from Logger::Severity
32
+ # @param data [Hash] The data to log (currently needs to be a Hash)
33
+ def log_hash(severity, data)
34
+ return unless data.is_a? Hash
35
+
36
+ # Try to pretty print as JSON, if not too big
37
+ begin
38
+ json = JSON.pretty_generate data
39
+ if json.length < 128 * 1024
40
+ $logger.add severity, json
41
+ else
42
+ log_hash_by_field severity, data
43
+ end
44
+ rescue Encoding::UndefinedConversionError
45
+ log_hash_by_field severity, data
46
+ end
47
+ end
48
+
49
+ # Logs a hash field by field,
50
+ #
51
+ # @param severity [Integer] A Logger::Severity
52
+ # @param hash [Hash] The Hash
53
+ def log_hash_by_field(severity, hash)
54
+ hash.keys.each do |key|
55
+ value = hash[key].to_s
56
+ if value.length < 1024
57
+ $logger.add severity, " #{key}: #{value}"
58
+ else
59
+ $logger.add severity, " #{key} (length): #{value.length}"
60
+ $logger.add severity, " #{key} (start): #{value[0, 1024]}"
61
+ end
62
+ end
63
+ end
64
+
65
+ # Produces a clickable link when logged in Buildkite
66
+ # @param url [String] Link URL
67
+ # @param text [String] Link text
68
+ def linkify(url, text)
69
+ "\033]1339;url='#{url}';content='#{text}'\a"
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Maze
4
+ class MacosUtils
5
+ class << self
6
+ def capture_screen(scenario)
7
+ path = File.join(File.join(Dir.pwd, 'maze_output'), 'failed', Maze::Helper.to_friendly_filename(scenario.name))
8
+ FileUtils.makedirs(path)
9
+
10
+ system("/usr/sbin/screencapture #{path}/#{Maze::Helper.to_friendly_filename(scenario.name)}-screenshot.jpg")
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'socket'
4
+
5
+ module Maze
6
+ # Sets the maximum number of times Maze runner will ping to see if a port is open, defaulting to 100
7
+ MAX_MAZE_CONNECT_ATTEMPTS = ENV.fetch('MAX_MAZE_CONNECT_ATTEMPTS', 100).to_i
8
+
9
+ # Provides network utility functionality
10
+ class Network
11
+ class << self
12
+ # Repeatedly pings a port to see if the host is ready for a connection.
13
+ # The maximum amount of attempts is determined by the MAX_MAZE_CONNECT_ATTEMPTS variable.
14
+ #
15
+ # @param host [String] The name of the host to connect to
16
+ # @param port [String] The port to attempt to connect to
17
+ #
18
+ # @raise [StandardError] When the port is not available for a connection
19
+ def wait_for_port(host, port)
20
+ attempts = 0
21
+ up = false
22
+ until (attempts >= MAX_MAZE_CONNECT_ATTEMPTS) || up
23
+ attempts += 1
24
+ up = port_open?(host, port)
25
+ sleep 0.1 unless up
26
+ end
27
+ raise "Port not ready in time!" unless up
28
+ end
29
+
30
+ # Attempts to connect to a port, timing out after a time.
31
+ #
32
+ # @param host [String] The name of the host to connect to
33
+ # @param port [String] The port to attempt to connect to
34
+ # @param seconds [Float] Optional. The length of time to wait before timing out.
35
+ def port_open?(host, port, seconds=0.1)
36
+ Timeout::timeout(seconds) do
37
+ begin
38
+ TCPSocket.new(host, port).close
39
+ true
40
+ rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH, SocketError
41
+ false
42
+ end
43
+ end
44
+ rescue Timeout::Error
45
+ false
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,245 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cucumber/cli/main'
4
+ require 'optimist'
5
+ require_relative '../option'
6
+ require_relative '../../maze'
7
+
8
+ module Maze
9
+ module Option
10
+ # Parses the command line options
11
+ class Parser
12
+ class << self
13
+ def parse(args)
14
+ parser = Optimist::Parser.new do
15
+ text 'Maze Runner extends the functionality of Cucumber, ' \
16
+ 'providing all of the command line arguments that it provides.'
17
+ text ''
18
+ text 'Usage [OPTIONS] <filenames>'
19
+ text ''
20
+ text 'Overridden Cucumber options:'
21
+ opt :help,
22
+ 'Print this help.'
23
+ opt :version,
24
+ 'Display Maze Runner and Cucumber versions'
25
+
26
+ text ''
27
+ text 'General options:'
28
+
29
+ opt Option::ENABLE_RETRIES,
30
+ 'Enables retrying failed scenarios when tagged',
31
+ type: :boolean,
32
+ default: true
33
+
34
+ opt Option::ENABLE_BUGSNAG,
35
+ 'Enables reporting to Bugsnag on scenario failure (Require MAZE_BUGSNAG_API_KEY)',
36
+ type: :boolean,
37
+ default: true
38
+
39
+ text ''
40
+ text 'Server options:'
41
+
42
+ opt Option::BIND_ADDRESS,
43
+ 'Mock server bind address',
44
+ type: :string
45
+ opt Option::PORT,
46
+ 'Mock server port',
47
+ default: 9339
48
+ opt Option::NULL_PORT,
49
+ 'Terminating connection port',
50
+ default: 9341
51
+
52
+ text ''
53
+ text 'Document server options:'
54
+
55
+ opt Option::DS_ROOT,
56
+ 'Document server root',
57
+ type: :string
58
+ opt Option::DS_BIND_ADDRESS,
59
+ 'Document server bind address',
60
+ type: :string
61
+ opt Option::DS_PORT,
62
+ 'Document server port',
63
+ default: 9340
64
+
65
+ text ''
66
+ text 'Appium options:'
67
+
68
+ opt Option::SEPARATE_SESSIONS,
69
+ 'Start a new Appium session for each scenario',
70
+ type: :boolean,
71
+ default: false
72
+ opt Option::FARM,
73
+ 'Device farm to use: "bs" (BrowserStack) or "local"',
74
+ type: :string
75
+ opt Option::APP,
76
+ 'The app to be installed and run against. Assumed to be contained in a file if prefixed with @.',
77
+ type: :string
78
+ opt Option::A11Y_LOCATOR,
79
+ 'Locate elements by accessibility id rather than id',
80
+ type: :boolean,
81
+ default: false
82
+ opt Option::RESILIENT,
83
+ 'Use the resilient Appium driver',
84
+ default: false
85
+ opt Option::CAPABILITIES,
86
+ 'Additional desired Appium capabilities as a JSON string',
87
+ default: '{}'
88
+
89
+ text ''
90
+ text 'Device farm options:'
91
+
92
+ opt Option::DEVICE,
93
+ 'Device to use. Can be listed multiple times to have a prioritised list of devices',
94
+ short: :none,
95
+ type: :string,
96
+ multi: true
97
+ opt Option::BROWSER,
98
+ 'Browser to use (an entry in browsers_<farm>.yml)',
99
+ short: :none,
100
+ type: :string
101
+ opt Option::USERNAME,
102
+ 'Device farm username. Consumes env var from environment based on farm set',
103
+ type: :string
104
+ opt Option::ACCESS_KEY,
105
+ 'Device farm access key. Consumes env var from environment based on farm set',
106
+ type: :string
107
+ opt Option::APPIUM_VERSION,
108
+ 'The Appium version to use',
109
+ type: :string
110
+ opt Option::LIST_DEVICES,
111
+ 'Lists the devices available for the configured device-farm, or all devices if none are specified',
112
+ default: false
113
+ opt Option::APP_BUNDLE_ID,
114
+ 'The bundle identifier of the test application',
115
+ type: :string
116
+
117
+ # SmartBear-only options
118
+ opt Option::SB_LOCAL,
119
+ '(SB only) Path to the SBSecureTunnel binary. MAZE_SB_LOCAL env var or "/SBSecureTunnel" by default',
120
+ type: :string
121
+
122
+ # Sauce Labs-only options
123
+ opt Option::SL_LOCAL,
124
+ '(SL only) Path to the Sauce Connect binary. MAZE_SL_LOCAL env var or "/sauce-connect/bin/sc" by default',
125
+ type: :string
126
+
127
+ # BrowserStack-only options
128
+ opt Option::BS_LOCAL,
129
+ '(BS only) Path to the BrowserStackLocal binary. MAZE_BS_LOCAL env var or "/BrowserStackLocal" by default',
130
+ type: :string
131
+
132
+ # TMS options
133
+ opt Option::TMS_URI,
134
+ 'URI of the test management server root. MAZE_TMS_URI env var',
135
+ type: :string
136
+
137
+ opt Option::TMS_TOKEN,
138
+ 'Token used to access the test management server. MAZE_TMS_TOKEN env var',
139
+ type: :string
140
+
141
+ text ''
142
+ text 'Local device options:'
143
+
144
+ opt Option::OS,
145
+ 'OS type to use ("ios", "android")',
146
+ type: :string
147
+ opt Option::OS_VERSION,
148
+ 'The intended OS version when running on a local device',
149
+ type: :string
150
+ opt Option::APPIUM_SERVER,
151
+ 'Appium server URL, only used for --farm=local. MAZE_APPIUM_SERVER env var or "http://localhost:4723/wd/hub" by default',
152
+ type: :string
153
+ opt Option::START_APPIUM,
154
+ 'Whether a local Appium server should be start. Only used for --farm=local.',
155
+ default: true
156
+ opt Option::APPIUM_LOGFILE,
157
+ 'The file local appium server output is logged to, defaulting to "appium_server.log"',
158
+ default: 'appium_server.log'
159
+ opt Option::APPLE_TEAM_ID,
160
+ 'Apple Team Id, required for local iOS testing. MAZE_APPLE_TEAM_ID env var by default',
161
+ type: :string
162
+ opt Option::UDID,
163
+ 'Apple UDID, required for local iOS testing. MAZE_UDID env var by default',
164
+ type: :string
165
+
166
+ text ''
167
+ text 'Logging options:'
168
+
169
+ opt Option::FILE_LOG,
170
+ "Writes lists of received requests to the maze_output folder for all scenarios",
171
+ type: :boolean,
172
+ default: true
173
+
174
+ opt Option::LOG_REQUESTS,
175
+ "Log lists of received requests to the console in the event of scenario failure. Defaults to true if the BUILDKITE environment variable is set",
176
+ type: :boolean,
177
+ default: false
178
+
179
+ opt Option::ALWAYS_LOG,
180
+ "Always log all received requests at the end of a scenario, whether is passes or fails",
181
+ type: :boolean,
182
+ default: false
183
+
184
+ version "Maze Runner v#{Maze::VERSION} " \
185
+ "(Cucumber v#{Cucumber::VERSION.strip})"
186
+ text ''
187
+ text 'The Cucumber help follows:'
188
+ text ''
189
+ end
190
+
191
+ # Allow for options destined for Cucumber
192
+ parser.ignore_invalid_options = true
193
+ options = parser.parse args
194
+ populate_environmental_defaults(options)
195
+
196
+ rescue Optimist::HelpNeeded
197
+ parser.educate
198
+ Cucumber::Cli::Main.new(['--help']).execute!
199
+ exit
200
+ rescue Optimist::VersionNeeded
201
+ puts parser.version
202
+ exit
203
+ end
204
+
205
+ # Populates unset options with appropriate environment variables or default values if necessary
206
+ #
207
+ # @param options [Hash] The hash of already-parsed options
208
+ #
209
+ # @returns [Hash] The options hash with environment vars added
210
+ def populate_environmental_defaults(options)
211
+ case options.farm
212
+ when 'cbt'
213
+ options[Option::USERNAME] ||= ENV['CBT_USERNAME']
214
+ options[Option::ACCESS_KEY] ||= ENV['CBT_ACCESS_KEY']
215
+ when 'bs'
216
+ # Allow browser/device credentials to exist in separate accounts
217
+ if options[Option::BROWSER]
218
+ options[Option::USERNAME] ||= ENV['BROWSER_STACK_BROWSERS_USERNAME'] || ENV['BROWSER_STACK_USERNAME']
219
+ options[Option::ACCESS_KEY] ||= ENV['BROWSER_STACK_BROWSERS_ACCESS_KEY'] ||ENV['BROWSER_STACK_ACCESS_KEY']
220
+ else
221
+ options[Option::USERNAME] ||= ENV['BROWSER_STACK_DEVICES_USERNAME'] || ENV['BROWSER_STACK_USERNAME']
222
+ options[Option::ACCESS_KEY] ||= ENV['BROWSER_STACK_DEVICES_ACCESS_KEY'] ||ENV['BROWSER_STACK_ACCESS_KEY']
223
+ end
224
+ when 'sl'
225
+ options[Option::USERNAME] ||= ENV['SAUCE_LABS_USERNAME']
226
+ options[Option::ACCESS_KEY] ||= ENV['SAUCE_LABS_ACCESS_KEY']
227
+ when 'bb'
228
+ options[Option::USERNAME] ||= ENV['BITBAR_USERNAME']
229
+ options[Option::ACCESS_KEY] ||= ENV['BITBAR_ACCESS_KEY']
230
+ options[Option::TMS_URI] ||= ENV['MAZE_TMS_URI']
231
+ end
232
+ options[Option::SB_LOCAL] ||= ENV['MAZE_SB_LOCAL'] || '/SBSecureTunnel'
233
+ options[Option::TMS_URI] ||= ENV['MAZE_TMS_URI']
234
+ options[Option::TMS_TOKEN] ||= ENV['MAZE_TMS_TOKEN']
235
+ options[Option::BS_LOCAL] ||= ENV['MAZE_BS_LOCAL'] || '/BrowserStackLocal'
236
+ options[Option::SL_LOCAL] ||= ENV['MAZE_SL_LOCAL'] || '/sauce-connect/bin/sc'
237
+ options[Option::APPIUM_SERVER] ||= ENV['MAZE_APPIUM_SERVER'] || 'http://localhost:4723/wd/hub'
238
+ options[Option::APPLE_TEAM_ID] ||= ENV['MAZE_APPLE_TEAM_ID']
239
+ options[Option::UDID] ||= ENV['MAZE_UDID']
240
+ options
241
+ end
242
+ end
243
+ end
244
+ end
245
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../option'
4
+ require_relative '../browser_stack_devices'
5
+
6
+ module Maze
7
+ module Option
8
+ # Processes the parsed command line options
9
+ class Processor
10
+ class << self
11
+ # Populates config from the parsed options given
12
+ # @param config [Configuration] MazeRunner configuration to populate
13
+ # @param options [Hash] Parsed command line options
14
+ def populate(config, options)
15
+
16
+ # Server options
17
+ config.bind_address = options[Maze::Option::BIND_ADDRESS]
18
+ config.port = options[Maze::Option::PORT]
19
+ config.null_port = options[Maze::Option::NULL_PORT]
20
+
21
+ # General options
22
+ config.enable_retries = options[Maze::Option::ENABLE_RETRIES]
23
+ config.enable_bugsnag = options[Maze::Option::ENABLE_BUGSNAG]
24
+ config.tms_uri = options[Maze::Option::TMS_URI]
25
+ config.tms_token = options[Maze::Option::TMS_TOKEN]
26
+
27
+ # Document server options
28
+ config.document_server_root = options[Maze::Option::DS_ROOT]
29
+ config.document_server_bind_address = options[Maze::Option::DS_BIND_ADDRESS]
30
+ config.document_server_port = options[Maze::Option::DS_PORT]
31
+
32
+ # Logger options
33
+ config.file_log = options[Maze::Option::FILE_LOG]
34
+ config.log_requests = options[Maze::Option::LOG_REQUESTS] || !ENV['BUILDKITE'].nil?
35
+ config.always_log = options[Maze::Option::ALWAYS_LOG]
36
+
37
+ # General appium options
38
+ config.appium_session_isolation = options[Maze::Option::SEPARATE_SESSIONS]
39
+ config.app = Maze::Helper.read_at_arg_file options[Maze::Option::APP]
40
+ config.resilient = options[Maze::Option::RESILIENT]
41
+ farm = options[Maze::Option::FARM]
42
+ config.farm = case farm
43
+ when nil then :none
44
+ when 'cbt' then :cbt
45
+ when 'bs' then :bs
46
+ when 'sl' then :sl
47
+ when 'bb' then :bb
48
+ when 'local' then :local
49
+ else
50
+ raise "Unknown farm '#{farm}'"
51
+ end
52
+ config.locator = options[Maze::Option::A11Y_LOCATOR] ? :accessibility_id : :id
53
+ config.capabilities_option = options[Maze::Option::CAPABILITIES]
54
+
55
+ # Farm specific options
56
+ case config.farm
57
+ when :cbt
58
+ config.browser = options[Maze::Option::BROWSER]
59
+ config.sb_local = Maze::Helper.expand_path(options[Maze::Option::SB_LOCAL])
60
+ username = config.username = options[Maze::Option::USERNAME]
61
+ access_key = config.access_key = options[Maze::Option::ACCESS_KEY]
62
+ when :bs
63
+ device_option = options[Maze::Option::DEVICE]
64
+ if device_option.nil? || device_option.empty?
65
+ config.browser = options[Maze::Option::BROWSER]
66
+ else
67
+ if device_option.is_a?(Array)
68
+ config.device = device_option.first
69
+ config.device_list = device_option.drop(1)
70
+ else
71
+ config.device = device_option
72
+ config.device_list = []
73
+ end
74
+ config.os_version = Maze::BrowserStackDevices::DEVICE_HASH[config.device]['os_version'].to_f
75
+ end
76
+ config.bs_local = Maze::Helper.expand_path(options[Maze::Option::BS_LOCAL])
77
+ config.appium_version = options[Maze::Option::APPIUM_VERSION]
78
+ username = config.username = options[Maze::Option::USERNAME]
79
+ access_key = config.access_key = options[Maze::Option::ACCESS_KEY]
80
+ config.appium_server_url = "http://#{username}:#{access_key}@hub-cloud.browserstack.com/wd/hub"
81
+ when :sl
82
+ device_option = options[Maze::Option::DEVICE]
83
+ if device_option.is_a?(Array)
84
+ config.device = device_option.first
85
+ config.device_list = device_option.drop(1)
86
+ else
87
+ config.device = device_option
88
+ config.device_list = []
89
+ end
90
+ config.browser = options[Maze::Option::BROWSER]
91
+ config.os = options[Maze::Option::OS]
92
+ config.os_version = options[Maze::Option::OS_VERSION].to_f
93
+ config.sl_local = Maze::Helper.expand_path(options[Maze::Option::SL_LOCAL])
94
+ config.appium_version = options[Maze::Option::APPIUM_VERSION]
95
+ username = config.username = options[Maze::Option::USERNAME]
96
+ access_key = config.access_key = options[Maze::Option::ACCESS_KEY]
97
+ config.appium_server_url = "https://#{username}:#{access_key}@ondemand.us-west-1.saucelabs.com/wd/hub"
98
+ when :bb then
99
+ config.username = options[Maze::Option::USERNAME]
100
+ config.access_key = options[Maze::Option::ACCESS_KEY]
101
+ config.tms_uri = options[Maze::Option::TMS_URI]
102
+ device_option = options[Maze::Option::DEVICE]
103
+ if device_option.is_a?(Array)
104
+ config.device = device_option.first
105
+ config.device_list = device_option.drop(1)
106
+ else
107
+ config.device = device_option
108
+ config.device_list = []
109
+ end
110
+ config.os = options[Maze::Option::OS]
111
+ config.os_version = options[Maze::Option::OS_VERSION]
112
+ config.sb_local = Maze::Helper.expand_path(options[Maze::Option::SB_LOCAL])
113
+ config.appium_server_url = 'https://appium.bitbar.com/wd/hub'
114
+ config.app_bundle_id = options[Maze::Option::APP_BUNDLE_ID]
115
+ when :local then
116
+ if options[Maze::Option::BROWSER]
117
+ config.browser = options[Maze::Option::BROWSER]
118
+ else
119
+ os = config.os = options[Maze::Option::OS].downcase
120
+ config.os_version = options[Maze::Option::OS_VERSION].to_f unless options[Maze::Option::OS_VERSION].nil?
121
+ config.appium_server_url = options[Maze::Option::APPIUM_SERVER]
122
+ config.start_appium = options[Maze::Option::START_APPIUM]
123
+ config.appium_logfile = options[Maze::Option::APPIUM_LOGFILE]
124
+ if os == 'ios'
125
+ config.apple_team_id = options[Maze::Option::APPLE_TEAM_ID]
126
+ config.device_id = options[Maze::Option::UDID]
127
+ end
128
+ end
129
+ when :none
130
+ if options[Maze::Option::OS]
131
+ config.os = options[Maze::Option::OS].downcase
132
+ end
133
+ if options[Maze::Option::OS_VERSION]
134
+ config.os_version = options[Maze::Option::OS_VERSION].to_f
135
+ end
136
+ else
137
+ raise "Unexpected farm option #{config.farm}"
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end