bugsnag-maze-runner 9.11.2 → 9.12.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.
- checksums.yaml +4 -4
- data/bin/bb-failed-sessions +94 -0
- data/lib/features/steps/app_automator_steps.rb +0 -159
- data/lib/features/steps/platform_dependent_steps.rb +204 -0
- data/lib/maze/client/bb_client_utils.rb +56 -0
- data/lib/maze/driver/appium.rb +46 -0
- data/lib/maze.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 325db4804e14fcf97c4cb8f53782676a597d29975d1ead996810979e94466207
|
4
|
+
data.tar.gz: 9b63455da005c6e4a1db345c74301801538425573c1fc02737034b0717a81e46
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f7b981946519533317ff0f07782d12cc78cadda9e0f82227a6d7b7bc1d8ed4f0b52009040eab4fb5c399862e0b652583652f25e9921389fa64d996ea886d3c59
|
7
|
+
data.tar.gz: 9e0ee212669d3dbc3d78ef6ee29dd0843a6b0d0ee6ecb9282ed53761c5b6da180be2fe8fc7590db8d6012d2543c121c9cf9f27f3c631cfffc4fa85c5c3ba42e6
|
@@ -0,0 +1,94 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Required libraries and dependencies
|
5
|
+
require_relative '../lib/maze'
|
6
|
+
require_relative '../lib/maze/loggers/logger'
|
7
|
+
require_relative '../lib/maze/client/bb_client_utils'
|
8
|
+
require 'optimist'
|
9
|
+
require 'net/http'
|
10
|
+
require 'json'
|
11
|
+
require 'uri'
|
12
|
+
require 'date'
|
13
|
+
require 'csv'
|
14
|
+
|
15
|
+
class BBFailedSessions
|
16
|
+
def start(args)
|
17
|
+
# Define and parse command-line options
|
18
|
+
p = Optimist::Parser.new do
|
19
|
+
text 'Get unsuccessful runs from BitBar Cloud'
|
20
|
+
text ''
|
21
|
+
text 'Requires BITBAR_API_KEY'
|
22
|
+
text ''
|
23
|
+
text 'Usage [OPTIONS]'
|
24
|
+
text ''
|
25
|
+
opt :help,
|
26
|
+
'Print this help.'
|
27
|
+
opt :date,
|
28
|
+
"Date to filter the runs. Format: 'YYYY-MM-DD'",
|
29
|
+
:type => :string
|
30
|
+
opt :project,
|
31
|
+
"Name of the BitBar project",
|
32
|
+
:type => :string
|
33
|
+
opt :output,
|
34
|
+
"Path to the output CSV file",
|
35
|
+
:type => :string
|
36
|
+
end
|
37
|
+
|
38
|
+
# Parse the command-line arguments
|
39
|
+
opts = Optimist::with_standard_exception_handling p do
|
40
|
+
raise Optimist::HelpNeeded if ARGV.empty? # Show help screen if no arguments
|
41
|
+
p.parse ARGV
|
42
|
+
end
|
43
|
+
|
44
|
+
# Get the API key from environment variable
|
45
|
+
api_key = ENV['BITBAR_API_KEY']
|
46
|
+
|
47
|
+
# Check if BITBAR_API_KEY has been set
|
48
|
+
if api_key.nil?
|
49
|
+
$logger.warn "BITBAR_API_KEY has not been set"
|
50
|
+
Optimist::with_standard_exception_handling p do
|
51
|
+
raise Optimist::HelpNeeded
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# if date is not provided, use today's date
|
56
|
+
opts[:date] ||= DateTime.now.strftime('%Y-%m-%d')
|
57
|
+
|
58
|
+
# Fetch project information from BitBar
|
59
|
+
project_info = Maze::Client::BitBarClientUtils.get_ids api_key, opts[:project]
|
60
|
+
|
61
|
+
# Iterate over each project and fetch unsuccessful runs
|
62
|
+
for id, name in project_info
|
63
|
+
$logger.info "Getting unsuccessful runs #{name} (#{id}) on #{opts[:date]}"
|
64
|
+
runs = Maze::Client::BitBarClientUtils.get_unsuccessful_runs api_key, id, opts[:date]
|
65
|
+
|
66
|
+
# Array to store the data to be written to the CSV
|
67
|
+
data = []
|
68
|
+
|
69
|
+
# Collect the data from each run
|
70
|
+
runs.each do |run|
|
71
|
+
data << [ name, DateTime.strptime(run['createTime'].to_s, '%Q'), run['displayName'], run['uiLink'], run['config']['files'][0]['file']['userEmail'] ]
|
72
|
+
end
|
73
|
+
|
74
|
+
# Define the CSV file path
|
75
|
+
csv_file_path = opts[:output] || "failed_sessions_#{name.gsub('-', '_')}_#{opts[:date].gsub('/', '_')}.csv"
|
76
|
+
|
77
|
+
$logger.info "Saving data to CSV file at #{csv_file_path}"
|
78
|
+
|
79
|
+
# Write the data to a CSV file
|
80
|
+
CSV.open(csv_file_path, 'w') do |csv|
|
81
|
+
# Write the headers
|
82
|
+
csv << ['Project', 'Date', 'Test Name', 'Dashboard Link', 'User Email']
|
83
|
+
|
84
|
+
# Write the data rows
|
85
|
+
data.each do |row|
|
86
|
+
csv << row
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Start the process with command-line arguments
|
94
|
+
BBFailedSessions.new.start(ARGV)
|
@@ -64,104 +64,6 @@ When('I set the device orientation to {orientation}') do |orientation|
|
|
64
64
|
Maze.driver.set_rotation orientation
|
65
65
|
end
|
66
66
|
|
67
|
-
# Tests that the given payload value is correct for the target BrowserStack platform.
|
68
|
-
# This step will assume the expected and payload values are strings.
|
69
|
-
# If the step is invoked when a remote BrowserStack device is not in use this step will fail.
|
70
|
-
#
|
71
|
-
# The DataTable used for this step should have `ios` and `android` in the same row as their expected value:
|
72
|
-
# | android | Java.lang.RuntimeException |
|
73
|
-
# | ios | NSException |
|
74
|
-
#
|
75
|
-
# If the expected value is set to "@skip", the check should be skipped
|
76
|
-
# If the expected value is set to "@null", the check will be for null
|
77
|
-
# If the expected value is set to "@not_null", the check will be for a non-null value
|
78
|
-
#
|
79
|
-
# @step_input request_type [String] The type of request (error, session, build, etc)
|
80
|
-
# @step_input field_path [String] The field to test
|
81
|
-
# @step_input platform_values [DataTable] A table of acceptable values for each platform
|
82
|
-
Then('the {request_type} payload field {string} equals the platform-dependent string:') do |request_type, field_path, platform_values|
|
83
|
-
test_string_platform_values(request_type, field_path, platform_values)
|
84
|
-
end
|
85
|
-
|
86
|
-
# See `the error payload field {string} equals the platform-dependent string:`
|
87
|
-
#
|
88
|
-
# @step_input field_path [String] The field to test, prepended with "events.0"
|
89
|
-
# @step_input platform_values [DataTable] A table of acceptable values for each platform
|
90
|
-
Then('the event {string} equals the platform-dependent string:') do |field_path, platform_values|
|
91
|
-
test_string_platform_values('error', "events.0.#{field_path}", platform_values)
|
92
|
-
end
|
93
|
-
|
94
|
-
# Tests that the given payload value is correct for the target BrowserStack platform.
|
95
|
-
# This step will assume the expected and payload values are numeric.
|
96
|
-
# If the step is invoked when a remote BrowserStack device is not in use this step will fail.
|
97
|
-
#
|
98
|
-
# The DataTable used for this step should have `ios` and `android` in the same row as their expected value:
|
99
|
-
# | android | 1 |
|
100
|
-
# | ios | 5.5 |
|
101
|
-
#
|
102
|
-
# If the expected value is set to "@skip", the check should be skipped
|
103
|
-
# If the expected value is set to "@null", the check will be for null
|
104
|
-
# If the expected value is set to "@not_null", the check will be for a non-null value
|
105
|
-
#
|
106
|
-
# @step_input request_type [String] The type of request (error, session, build, etc)
|
107
|
-
# @step_input field_path [String] The field to test
|
108
|
-
# @step_input platform_values [DataTable] A table of acceptable values for each platform
|
109
|
-
Then('the {request_type} payload field {string} equals the platform-dependent numeric:') do |request_type, field_path, platform_values|
|
110
|
-
test_numeric_platform_values(request_type, field_path, platform_values)
|
111
|
-
end
|
112
|
-
|
113
|
-
# See `the payload field {string} equals the platform-dependent numeric:`
|
114
|
-
#
|
115
|
-
# @step_input field_path [String] The field to test, prepended with "events.0"
|
116
|
-
# @step_input platform_values [DataTable] A table of acceptable values for each platform
|
117
|
-
Then('the event {string} equals the platform-dependent numeric:') do |field_path, platform_values|
|
118
|
-
test_numeric_platform_values('error', "events.0.#{field_path}", platform_values)
|
119
|
-
end
|
120
|
-
|
121
|
-
# Tests that the given payload value is correct for the target BrowserStack platform.
|
122
|
-
# This step will assume the expected and payload values are booleans.
|
123
|
-
# If the step is invoked when a remote BrowserStack device is not in use this step will fail.
|
124
|
-
#
|
125
|
-
# The DataTable used for this step should have `ios` and `android` in the same row as their expected value:
|
126
|
-
# | android | 1 |
|
127
|
-
# | ios | 5 |
|
128
|
-
#
|
129
|
-
# If the expected value is set to "@skip", the check should be skipped
|
130
|
-
# If the expected value is set to "@null", the check will be for null
|
131
|
-
# If the expected value is set to "@not_null", the check will be for a non-null value
|
132
|
-
#
|
133
|
-
# @step_input request_type [String] The type of request (error, session, build, etc)
|
134
|
-
# @step_input field_path [String] The field to test
|
135
|
-
# @step_input platform_values [DataTable] A table of acceptable values for each platform
|
136
|
-
Then('the {request_type} payload field {string} equals the platform-dependent boolean:') do |request_type, field_path, platform_values|
|
137
|
-
test_boolean_platform_values(request_type, field_path, platform_values)
|
138
|
-
end
|
139
|
-
|
140
|
-
# See `the payload field {string} equals the platform-dependent boolean:`
|
141
|
-
#
|
142
|
-
# @step_input field_path [String] The field to test, prepended with "events.0"
|
143
|
-
# @step_input platform_values [DataTable] A table of acceptable values for each platform
|
144
|
-
Then('the event {string} equals the platform-dependent boolean:') do |field_path, platform_values|
|
145
|
-
test_boolean_platform_values('error', "events.0.#{field_path}", platform_values)
|
146
|
-
end
|
147
|
-
|
148
|
-
# See `the payload field {string} equals the platform-dependent string:`
|
149
|
-
#
|
150
|
-
# @step_input field_path [String] The field to test, prepended with "events.0.exceptions.0."
|
151
|
-
# @step_input platform_values [DataTable] A table of acceptable values for each platform
|
152
|
-
Then('the exception {string} equals the platform-dependent string:') do |field_path, platform_values|
|
153
|
-
test_string_platform_values('error', "events.0.exceptions.0.#{field_path}", platform_values)
|
154
|
-
end
|
155
|
-
|
156
|
-
# See `the payload field {string} equals the platform-dependent string:`
|
157
|
-
#
|
158
|
-
# @step_input field_path [String] The field to test, prepended with "events.0.exceptions.0.stacktrace.#!{num}"
|
159
|
-
# @step_input num [Integer] The index of the stack frame to test
|
160
|
-
# @step_input platform_values [DataTable] A table of acceptable values for each platform
|
161
|
-
Then('the {string} of stack frame {int} equals the platform-dependent string:') do |field_path, num, platform_values|
|
162
|
-
test_string_platform_values('error', "events.0.exceptions.0.stacktrace.#{num}.#{field_path}", platform_values)
|
163
|
-
end
|
164
|
-
|
165
67
|
# Sends keys to a given element, clearing it first
|
166
68
|
# Requires a running Appium driver
|
167
69
|
#
|
@@ -171,64 +73,3 @@ When('I clear and send the keys {string} to the element {string}') do |keys, ele
|
|
171
73
|
Maze.driver.clear_and_send_keys_to_element(element_id, keys)
|
172
74
|
end
|
173
75
|
|
174
|
-
def get_expected_platform_value(platform_values)
|
175
|
-
os = Maze::Helper.get_current_platform
|
176
|
-
expected_value = Hash[platform_values.raw][os.downcase]
|
177
|
-
raise("There is no expected value for the current platform \"#{os}\"") if expected_value.nil?
|
178
|
-
|
179
|
-
expected_value
|
180
|
-
end
|
181
|
-
|
182
|
-
def should_skip_platform_check(expected_value)
|
183
|
-
expected_value.eql?('@skip')
|
184
|
-
end
|
185
|
-
|
186
|
-
def test_string_platform_values(request_type, field_path, platform_values)
|
187
|
-
expected_value = get_expected_platform_value(platform_values)
|
188
|
-
return if should_skip_platform_check(expected_value)
|
189
|
-
|
190
|
-
list = Maze::Server.list_for(request_type)
|
191
|
-
payload_value = Maze::Helper.read_key_path(list.current[:body], field_path)
|
192
|
-
assert_equal_with_nullability(expected_value, payload_value)
|
193
|
-
end
|
194
|
-
|
195
|
-
def test_boolean_platform_values(request_type, field_path, platform_values)
|
196
|
-
expected_value = get_expected_platform_value(platform_values)
|
197
|
-
return if should_skip_platform_check(expected_value)
|
198
|
-
|
199
|
-
expected_bool = case expected_value.downcase
|
200
|
-
when 'true'
|
201
|
-
true
|
202
|
-
when 'false'
|
203
|
-
false
|
204
|
-
else
|
205
|
-
expected_value
|
206
|
-
end
|
207
|
-
list = Maze::Server.list_for(request_type)
|
208
|
-
payload_value = Maze::Helper.read_key_path(list.current[:body], field_path)
|
209
|
-
assert_equal_with_nullability(expected_bool, payload_value)
|
210
|
-
end
|
211
|
-
|
212
|
-
def test_numeric_platform_values(request_type, field_path, platform_values)
|
213
|
-
expected_value = get_expected_platform_value(platform_values)
|
214
|
-
return if should_skip_platform_check(expected_value)
|
215
|
-
|
216
|
-
list = Maze::Server.list_for(request_type)
|
217
|
-
payload_value = Maze::Helper.read_key_path(list.current[:body], field_path)
|
218
|
-
|
219
|
-
# Need to do a little more processing here to allow floats
|
220
|
-
special_value = expected_value.eql?('@null') || expected_value.eql?('@not_null')
|
221
|
-
expectation = special_value ? expected_value : expected_value.to_f
|
222
|
-
assert_equal_with_nullability(expectation, payload_value)
|
223
|
-
end
|
224
|
-
|
225
|
-
def assert_equal_with_nullability(expected_value, payload_value)
|
226
|
-
case expected_value
|
227
|
-
when '@null'
|
228
|
-
Maze.check.nil(payload_value)
|
229
|
-
when '@not_null'
|
230
|
-
Maze.check.not_nil(payload_value)
|
231
|
-
else
|
232
|
-
Maze.check.equal(expected_value, payload_value)
|
233
|
-
end
|
234
|
-
end
|
@@ -0,0 +1,204 @@
|
|
1
|
+
# @!group Platform dependent steps
|
2
|
+
|
3
|
+
# Tests that the given payload value is correct for the target BrowserStack platform.
|
4
|
+
# This step will assume the expected and payload values are strings.
|
5
|
+
# If the step is invoked when a remote BrowserStack device is not in use this step will fail.
|
6
|
+
#
|
7
|
+
# The DataTable used for this step should have `ios` and `android` in the same row as their expected value:
|
8
|
+
# | android | Java.lang.RuntimeException |
|
9
|
+
# | ios | NSException |
|
10
|
+
#
|
11
|
+
# If the expected value is set to "@skip", the check should be skipped
|
12
|
+
# If the expected value is set to "@null", the check will be for null
|
13
|
+
# If the expected value is set to "@not_null", the check will be for a non-null value
|
14
|
+
#
|
15
|
+
# @step_input request_type [String] The type of request (error, session, build, etc)
|
16
|
+
# @step_input field_path [String] The field to test
|
17
|
+
# @step_input platform_values [DataTable] A table of acceptable values for each platform
|
18
|
+
Then('the {request_type} payload field {string} equals the platform-dependent string:') do |request_type, field_path, platform_values|
|
19
|
+
test_string_platform_values(request_type, field_path, platform_values)
|
20
|
+
end
|
21
|
+
|
22
|
+
# See `the error payload field {string} equals the platform-dependent string:`
|
23
|
+
#
|
24
|
+
# @step_input field_path [String] The field to test, prepended with "events.0"
|
25
|
+
# @step_input platform_values [DataTable] A table of acceptable values for each platform
|
26
|
+
Then('the event {string} equals the platform-dependent string:') do |field_path, platform_values|
|
27
|
+
test_string_platform_values('error', "events.0.#{field_path}", platform_values)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Tests that the given payload value is correct for the target BrowserStack platform.
|
31
|
+
# This step will assume the expected and payload values are numeric.
|
32
|
+
# If the step is invoked when a remote BrowserStack device is not in use this step will fail.
|
33
|
+
#
|
34
|
+
# The DataTable used for this step should have `ios` and `android` in the same row as their expected value:
|
35
|
+
# | android | 1 |
|
36
|
+
# | ios | 5.5 |
|
37
|
+
#
|
38
|
+
# If the expected value is set to "@skip", the check should be skipped
|
39
|
+
# If the expected value is set to "@null", the check will be for null
|
40
|
+
# If the expected value is set to "@not_null", the check will be for a non-null value
|
41
|
+
#
|
42
|
+
# @step_input request_type [String] The type of request (error, session, build, etc)
|
43
|
+
# @step_input field_path [String] The field to test
|
44
|
+
# @step_input platform_values [DataTable] A table of acceptable values for each platform
|
45
|
+
Then('the {request_type} payload field {string} equals the platform-dependent numeric:') do |request_type, field_path, platform_values|
|
46
|
+
test_numeric_platform_values(request_type, field_path, platform_values)
|
47
|
+
end
|
48
|
+
|
49
|
+
# See `the payload field {string} equals the platform-dependent numeric:`
|
50
|
+
#
|
51
|
+
# @step_input field_path [String] The field to test, prepended with "events.0"
|
52
|
+
# @step_input platform_values [DataTable] A table of acceptable values for each platform
|
53
|
+
Then('the event {string} equals the platform-dependent numeric:') do |field_path, platform_values|
|
54
|
+
test_numeric_platform_values('error', "events.0.#{field_path}", platform_values)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Tests that the given payload value is correct for the target BrowserStack platform.
|
58
|
+
# This step will assume the expected and payload values are booleans.
|
59
|
+
# If the step is invoked when a remote BrowserStack device is not in use this step will fail.
|
60
|
+
#
|
61
|
+
# The DataTable used for this step should have `ios` and `android` in the same row as their expected value:
|
62
|
+
# | android | 1 |
|
63
|
+
# | ios | 5 |
|
64
|
+
#
|
65
|
+
# If the expected value is set to "@skip", the check should be skipped
|
66
|
+
# If the expected value is set to "@null", the check will be for null
|
67
|
+
# If the expected value is set to "@not_null", the check will be for a non-null value
|
68
|
+
#
|
69
|
+
# @step_input request_type [String] The type of request (error, session, build, etc)
|
70
|
+
# @step_input field_path [String] The field to test
|
71
|
+
# @step_input platform_values [DataTable] A table of acceptable values for each platform
|
72
|
+
Then('the {request_type} payload field {string} equals the platform-dependent boolean:') do |request_type, field_path, platform_values|
|
73
|
+
test_boolean_platform_values(request_type, field_path, platform_values)
|
74
|
+
end
|
75
|
+
|
76
|
+
# See `the payload field {string} equals the platform-dependent boolean:`
|
77
|
+
#
|
78
|
+
# @step_input field_path [String] The field to test, prepended with "events.0"
|
79
|
+
# @step_input platform_values [DataTable] A table of acceptable values for each platform
|
80
|
+
Then('the event {string} equals the platform-dependent boolean:') do |field_path, platform_values|
|
81
|
+
test_boolean_platform_values('error', "events.0.#{field_path}", platform_values)
|
82
|
+
end
|
83
|
+
|
84
|
+
# See `the payload field {string} equals the platform-dependent string:`
|
85
|
+
#
|
86
|
+
# @step_input field_path [String] The field to test, prepended with "events.0.exceptions.0."
|
87
|
+
# @step_input platform_values [DataTable] A table of acceptable values for each platform
|
88
|
+
Then('the exception {string} equals the platform-dependent string:') do |field_path, platform_values|
|
89
|
+
test_string_platform_values('error', "events.0.exceptions.0.#{field_path}", platform_values)
|
90
|
+
end
|
91
|
+
|
92
|
+
# See `the payload field {string} equals the platform-dependent string:`
|
93
|
+
#
|
94
|
+
# @step_input field_path [String] The field to test, prepended with "events.0.exceptions.0.stacktrace.#!{num}"
|
95
|
+
# @step_input num [Integer] The index of the stack frame to test
|
96
|
+
# @step_input platform_values [DataTable] A table of acceptable values for each platform
|
97
|
+
Then('the {string} of stack frame {int} equals the platform-dependent string:') do |field_path, num, platform_values|
|
98
|
+
test_string_platform_values('error', "events.0.exceptions.0.stacktrace.#{num}.#{field_path}", platform_values)
|
99
|
+
end
|
100
|
+
|
101
|
+
#
|
102
|
+
# Equality check routines
|
103
|
+
#
|
104
|
+
def test_string_platform_values(request_type, field_path, platform_values)
|
105
|
+
expected_value = get_expected_platform_value(platform_values)
|
106
|
+
return if should_skip_platform_check(expected_value)
|
107
|
+
|
108
|
+
list = Maze::Server.list_for(request_type)
|
109
|
+
payload_value = Maze::Helper.read_key_path(list.current[:body], field_path)
|
110
|
+
assert_equal_with_nullability(expected_value, payload_value)
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_boolean_platform_values(request_type, field_path, platform_values)
|
114
|
+
expected_value = get_expected_platform_value(platform_values)
|
115
|
+
return if should_skip_platform_check(expected_value)
|
116
|
+
|
117
|
+
expected_bool = case expected_value.downcase
|
118
|
+
when 'true'
|
119
|
+
true
|
120
|
+
when 'false'
|
121
|
+
false
|
122
|
+
else
|
123
|
+
expected_value
|
124
|
+
end
|
125
|
+
list = Maze::Server.list_for(request_type)
|
126
|
+
payload_value = Maze::Helper.read_key_path(list.current[:body], field_path)
|
127
|
+
assert_equal_with_nullability(expected_bool, payload_value)
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_numeric_platform_values(request_type, field_path, platform_values)
|
131
|
+
expected_value = get_expected_platform_value(platform_values)
|
132
|
+
return if should_skip_platform_check(expected_value)
|
133
|
+
|
134
|
+
list = Maze::Server.list_for(request_type)
|
135
|
+
payload_value = Maze::Helper.read_key_path(list.current[:body], field_path)
|
136
|
+
|
137
|
+
# Need to do a little more processing here to allow floats
|
138
|
+
special_value = expected_value.eql?('@null') || expected_value.eql?('@not_null')
|
139
|
+
expectation = special_value ? expected_value : expected_value.to_f
|
140
|
+
assert_equal_with_nullability(expectation, payload_value)
|
141
|
+
end
|
142
|
+
|
143
|
+
def assert_equal_with_nullability(expected_value, payload_value)
|
144
|
+
case expected_value
|
145
|
+
when '@null'
|
146
|
+
Maze.check.nil(payload_value)
|
147
|
+
when '@not_null'
|
148
|
+
Maze.check.not_nil(payload_value)
|
149
|
+
else
|
150
|
+
Maze.check.equal(expected_value, payload_value)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def get_expected_platform_value(platform_values)
|
155
|
+
os = Maze::Helper.get_current_platform
|
156
|
+
expected_value = Hash[platform_values.raw][os.downcase]
|
157
|
+
raise("There is no expected value for the current platform \"#{os}\"") if expected_value.nil?
|
158
|
+
|
159
|
+
expected_value
|
160
|
+
end
|
161
|
+
|
162
|
+
def should_skip_platform_check(expected_value)
|
163
|
+
expected_value.eql?('@skip')
|
164
|
+
end
|
165
|
+
|
166
|
+
# @step_input request_type [String] The type of request (error, session, build, etc)
|
167
|
+
# @step_input field_path [String] The field to test
|
168
|
+
# @step_input platform_values [DataTable] A table of acceptable regexes for each platform
|
169
|
+
Then('the {request_type} payload field {string} matches the platform-dependent regex:') do |request_type, field_path, platform_regexes|
|
170
|
+
match_string_platform_regexes(request_type, field_path, platform_regexes)
|
171
|
+
end
|
172
|
+
|
173
|
+
# See `the error payload field {string} equals the platform-dependent string:`
|
174
|
+
#
|
175
|
+
# @step_input field_path [String] The field to test, prepended with "events.0"
|
176
|
+
# @step_input platform_values [DataTable] A table of acceptable values for each platform
|
177
|
+
Then('the event {string} matches the platform-dependent regex:') do |field_path, platform_regexes|
|
178
|
+
match_string_platform_regexes('error', "events.0.#{field_path}", platform_regexes)
|
179
|
+
end
|
180
|
+
|
181
|
+
# @step_input field_path [String] The field to test, prepended with "events.0.exceptions.0."
|
182
|
+
# @step_input platform_values [DataTable] A table of acceptable regexes for each platform
|
183
|
+
Then('the exception {string} matches the platform-dependent regex:') do |field_path, platform_regexes|
|
184
|
+
match_string_platform_regexes('error', "events.0.exceptions.0.#{field_path}", platform_regexes)
|
185
|
+
end
|
186
|
+
|
187
|
+
# @step_input field_path [String] The field to test, prepended with "events.0.exceptions.0.stacktrace.#!{num}"
|
188
|
+
# @step_input num [Integer] The index of the stack frame to test
|
189
|
+
# @step_input platform_values [DataTable] A table of acceptable values for each platform
|
190
|
+
Then('the {string} of stack frame {int} matches the platform-dependent regex:') do |field_path, num, platform_regexes|
|
191
|
+
match_string_platform_regexes('error', "events.0.exceptions.0.stacktrace.#{num}.#{field_path}", platform_regexes)
|
192
|
+
end
|
193
|
+
|
194
|
+
#
|
195
|
+
# Regex match routines
|
196
|
+
#
|
197
|
+
def match_string_platform_regexes(request_type, field_path, platform_values)
|
198
|
+
expected_regex = get_expected_platform_value(platform_values)
|
199
|
+
return if should_skip_platform_check(expected_regex)
|
200
|
+
list = Maze::Server.list_for(request_type)
|
201
|
+
payload_value = Maze::Helper.read_key_path(list.current[:body], field_path)
|
202
|
+
|
203
|
+
Maze.check.match(expected_regex, payload_value)
|
204
|
+
end
|
@@ -175,6 +175,62 @@ module Maze
|
|
175
175
|
}
|
176
176
|
end
|
177
177
|
|
178
|
+
|
179
|
+
def get_ids(api_key, project_name = nil)
|
180
|
+
base_url = 'https://cloud.bitbar.com/api/me/projects?limit=100'
|
181
|
+
url = project_name ? "#{base_url}&filter=name_eq_#{project_name}" : base_url
|
182
|
+
|
183
|
+
uri = URI.parse(url)
|
184
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
185
|
+
http.use_ssl = true
|
186
|
+
|
187
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
188
|
+
request.basic_auth(api_key, '')
|
189
|
+
|
190
|
+
begin
|
191
|
+
response = http.request(request)
|
192
|
+
raise "HTTP request failed with code #{response.code}" unless response.is_a?(Net::HTTPSuccess)
|
193
|
+
json_body_data = JSON.parse(response.body)['data']
|
194
|
+
json_body_data.map { |project| [project['id'], project['name']] }
|
195
|
+
rescue JSON::ParserError
|
196
|
+
raise 'Failed to parse JSON response'
|
197
|
+
rescue StandardError => e
|
198
|
+
raise "An error occurred: #{e.message}"
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def get_unsuccessful_runs(api_key, project_id, date)
|
203
|
+
new_date = date_to_milliseconds(date)
|
204
|
+
url = URI.parse("https://cloud.bitbar.com/api/me/projects/#{project_id}/runs?filter=successRatio_eq_0.0;d_createTime_on_#{new_date}")
|
205
|
+
|
206
|
+
http = Net::HTTP.new(url.host, url.port)
|
207
|
+
http.use_ssl = true
|
208
|
+
|
209
|
+
request = Net::HTTP::Get.new(url.request_uri)
|
210
|
+
request.basic_auth(api_key, '')
|
211
|
+
|
212
|
+
begin
|
213
|
+
response = http.request(request)
|
214
|
+
raise "HTTP request failed with code #{response.code}" unless response.is_a?(Net::HTTPSuccess)
|
215
|
+
JSON.parse(response.body)['data']
|
216
|
+
rescue JSON::ParserError
|
217
|
+
raise 'Failed to parse JSON response'
|
218
|
+
rescue StandardError => e
|
219
|
+
raise "An error occurred: #{e.message}"
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def date_to_milliseconds(date_string)
|
224
|
+
begin
|
225
|
+
date_format = "%Y-%m-%d"
|
226
|
+
parsed_date = DateTime.strptime(date_string, date_format)
|
227
|
+
milliseconds = (parsed_date.to_time.to_f * 1000).to_i
|
228
|
+
milliseconds
|
229
|
+
rescue ArgumentError
|
230
|
+
raise "Invalid date format. Please use YYYY-MM-DD."
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
178
234
|
private
|
179
235
|
|
180
236
|
def start_tunnel_thread(cmd)
|
data/lib/maze/driver/appium.rb
CHANGED
@@ -81,15 +81,41 @@ module Maze
|
|
81
81
|
$logger.warn "StaleElementReferenceError occurred: #{e}"
|
82
82
|
false
|
83
83
|
end
|
84
|
+
rescue Selenium::WebDriver::Error::ServerError => e
|
85
|
+
# Assume the remote appium session has stopped, so crash out of the session
|
86
|
+
Maze.driver = nil
|
87
|
+
raise e
|
84
88
|
else
|
85
89
|
true
|
86
90
|
end
|
87
91
|
|
92
|
+
# A wrapper around launch_app adding extra error handling
|
93
|
+
def launch_app
|
94
|
+
super
|
95
|
+
rescue Selenium::WebDriver::Error::ServerError => e
|
96
|
+
# Assume the remote appium session has stopped, so crash out of the session
|
97
|
+
Maze.driver = nil
|
98
|
+
raise e
|
99
|
+
end
|
100
|
+
|
101
|
+
# A wrapper around close_app adding extra error handling
|
102
|
+
def close_app
|
103
|
+
super
|
104
|
+
rescue Selenium::WebDriver::Error::ServerError => e
|
105
|
+
# Assume the remote appium session has stopped, so crash out of the session
|
106
|
+
Maze.driver = nil
|
107
|
+
raise e
|
108
|
+
end
|
109
|
+
|
88
110
|
# A wrapper around find_element adding timer functionality
|
89
111
|
def find_element_timed(element_id)
|
90
112
|
@find_element_timer.time do
|
91
113
|
find_element(@element_locator, element_id)
|
92
114
|
end
|
115
|
+
rescue Selenium::WebDriver::Error::ServerError => e
|
116
|
+
# Assume the remote appium session has stopped, so crash out of the session
|
117
|
+
Maze.driver = nil
|
118
|
+
raise e
|
93
119
|
end
|
94
120
|
|
95
121
|
# Clicks a given element
|
@@ -100,6 +126,10 @@ module Maze
|
|
100
126
|
@click_element_timer.time do
|
101
127
|
element.click
|
102
128
|
end
|
129
|
+
rescue Selenium::WebDriver::Error::ServerError => e
|
130
|
+
# Assume the remote appium session has stopped, so crash out of the session
|
131
|
+
Maze.driver = nil
|
132
|
+
raise e
|
103
133
|
end
|
104
134
|
|
105
135
|
# Clicks a given element, ignoring any NoSuchElementError
|
@@ -114,6 +144,10 @@ module Maze
|
|
114
144
|
true
|
115
145
|
rescue Selenium::WebDriver::Error::NoSuchElementError
|
116
146
|
false
|
147
|
+
rescue Selenium::WebDriver::Error::ServerError => e
|
148
|
+
# Assume the remote appium session has stopped, so crash out of the session
|
149
|
+
Maze.driver = nil
|
150
|
+
raise e
|
117
151
|
end
|
118
152
|
|
119
153
|
# Clears a given element
|
@@ -124,6 +158,10 @@ module Maze
|
|
124
158
|
@clear_element_timer.time do
|
125
159
|
element.clear
|
126
160
|
end
|
161
|
+
rescue Selenium::WebDriver::Error::ServerError => e
|
162
|
+
# Assume the remote appium session has stopped, so crash out of the session
|
163
|
+
Maze.driver = nil
|
164
|
+
raise e
|
127
165
|
end
|
128
166
|
|
129
167
|
# Gets the application hierarchy XML
|
@@ -145,6 +183,10 @@ module Maze
|
|
145
183
|
@send_keys_timer.time do
|
146
184
|
element.send_keys(text)
|
147
185
|
end
|
186
|
+
rescue Selenium::WebDriver::Error::ServerError => e
|
187
|
+
# Assume the remote appium session has stopped, so crash out of the session
|
188
|
+
Maze.driver = nil
|
189
|
+
raise e
|
148
190
|
end
|
149
191
|
|
150
192
|
# Sets the rotation of the device
|
@@ -178,6 +220,10 @@ module Maze
|
|
178
220
|
@send_keys_timer.time do
|
179
221
|
element.send_keys(text)
|
180
222
|
end
|
223
|
+
rescue Selenium::WebDriver::Error::ServerError => e
|
224
|
+
# Assume the remote appium session has stopped, so crash out of the session
|
225
|
+
Maze.driver = nil
|
226
|
+
raise e
|
181
227
|
end
|
182
228
|
|
183
229
|
# Reset the currently running application after a given timeout
|
data/lib/maze.rb
CHANGED
@@ -7,7 +7,7 @@ require_relative 'maze/timers'
|
|
7
7
|
# Glues the various parts of MazeRunner together that need to be accessed globally,
|
8
8
|
# providing an alternative to the proliferation of global variables or singletons.
|
9
9
|
module Maze
|
10
|
-
VERSION = '9.
|
10
|
+
VERSION = '9.12.0'
|
11
11
|
|
12
12
|
class << self
|
13
13
|
attr_accessor :check, :driver, :internal_hooks, :mode, :start_time, :dynamic_retry, :public_address,
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bugsnag-maze-runner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 9.
|
4
|
+
version: 9.12.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Steve Kirkland
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-07-
|
11
|
+
date: 2024-07-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cucumber
|
@@ -322,6 +322,7 @@ description: Automation steps and mock server to validaterequest payloads respon
|
|
322
322
|
email:
|
323
323
|
- steve@bugsnag.com
|
324
324
|
executables:
|
325
|
+
- bb-failed-sessions
|
325
326
|
- bugsnag-print-load-paths
|
326
327
|
- download-logs
|
327
328
|
- maze-runner
|
@@ -330,6 +331,7 @@ executables:
|
|
330
331
|
extensions: []
|
331
332
|
extra_rdoc_files: []
|
332
333
|
files:
|
334
|
+
- bin/bb-failed-sessions
|
333
335
|
- bin/bugsnag-print-load-paths
|
334
336
|
- bin/download-logs
|
335
337
|
- bin/maze-runner
|
@@ -356,6 +358,7 @@ files:
|
|
356
358
|
- lib/features/steps/multipart_request_steps.rb
|
357
359
|
- lib/features/steps/network_steps.rb
|
358
360
|
- lib/features/steps/payload_steps.rb
|
361
|
+
- lib/features/steps/platform_dependent_steps.rb
|
359
362
|
- lib/features/steps/proxy_steps.rb
|
360
363
|
- lib/features/steps/query_parameter_steps.rb
|
361
364
|
- lib/features/steps/request_assertion_steps.rb
|