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.
- checksums.yaml +7 -0
- data/bin/bugsnag-print-load-paths +6 -0
- data/bin/download-logs +76 -0
- data/bin/maze-runner +136 -0
- data/bin/upload-app +56 -0
- data/lib/features/scripts/await-android-emulator.sh +11 -0
- data/lib/features/scripts/clear-android-app-data.sh +8 -0
- data/lib/features/scripts/force-stop-android-app.sh +8 -0
- data/lib/features/scripts/install-android-app.sh +15 -0
- data/lib/features/scripts/launch-android-app.sh +38 -0
- data/lib/features/scripts/launch-android-emulator.sh +15 -0
- data/lib/features/steps/android_steps.rb +51 -0
- data/lib/features/steps/app_automator_steps.rb +228 -0
- data/lib/features/steps/aws_sam_steps.rb +212 -0
- data/lib/features/steps/breadcrumb_steps.rb +50 -0
- data/lib/features/steps/browser_steps.rb +93 -0
- data/lib/features/steps/build_api_steps.rb +25 -0
- data/lib/features/steps/document_server_steps.rb +7 -0
- data/lib/features/steps/error_reporting_steps.rb +342 -0
- data/lib/features/steps/feature_flag_steps.rb +190 -0
- data/lib/features/steps/header_steps.rb +72 -0
- data/lib/features/steps/log_steps.rb +29 -0
- data/lib/features/steps/multipart_request_steps.rb +142 -0
- data/lib/features/steps/network_steps.rb +75 -0
- data/lib/features/steps/payload_steps.rb +234 -0
- data/lib/features/steps/proxy_steps.rb +34 -0
- data/lib/features/steps/query_parameter_steps.rb +31 -0
- data/lib/features/steps/request_assertion_steps.rb +107 -0
- data/lib/features/steps/runner_steps.rb +406 -0
- data/lib/features/steps/session_tracking_steps.rb +116 -0
- data/lib/features/steps/value_steps.rb +119 -0
- data/lib/features/support/env.rb +7 -0
- data/lib/features/support/internal_hooks.rb +260 -0
- data/lib/maze/appium_server.rb +112 -0
- data/lib/maze/assertions/request_set_assertions.rb +97 -0
- data/lib/maze/aws/sam.rb +112 -0
- data/lib/maze/bitbar_devices.rb +84 -0
- data/lib/maze/bitbar_utils.rb +112 -0
- data/lib/maze/browser_stack_devices.rb +160 -0
- data/lib/maze/browser_stack_utils.rb +164 -0
- data/lib/maze/browsers_bs.yml +220 -0
- data/lib/maze/browsers_cbt.yml +100 -0
- data/lib/maze/bugsnag_config.rb +42 -0
- data/lib/maze/capabilities.rb +126 -0
- data/lib/maze/checks/assert_check.rb +91 -0
- data/lib/maze/checks/noop_check.rb +34 -0
- data/lib/maze/compare.rb +161 -0
- data/lib/maze/configuration.rb +174 -0
- data/lib/maze/docker.rb +108 -0
- data/lib/maze/document_server.rb +46 -0
- data/lib/maze/driver/appium.rb +217 -0
- data/lib/maze/driver/browser.rb +138 -0
- data/lib/maze/driver/resilient_appium.rb +51 -0
- data/lib/maze/errors.rb +20 -0
- data/lib/maze/helper.rb +118 -0
- data/lib/maze/hooks/appium_hooks.rb +216 -0
- data/lib/maze/hooks/browser_hooks.rb +68 -0
- data/lib/maze/hooks/command_hooks.rb +9 -0
- data/lib/maze/hooks/hooks.rb +61 -0
- data/lib/maze/interactive_cli.rb +173 -0
- data/lib/maze/logger.rb +73 -0
- data/lib/maze/macos_utils.rb +14 -0
- data/lib/maze/network.rb +49 -0
- data/lib/maze/option/parser.rb +245 -0
- data/lib/maze/option/processor.rb +143 -0
- data/lib/maze/option/validator.rb +184 -0
- data/lib/maze/option.rb +64 -0
- data/lib/maze/plugins/bugsnag_reporting_plugin.rb +49 -0
- data/lib/maze/plugins/cucumber_report_plugin.rb +101 -0
- data/lib/maze/plugins/global_retry_plugin.rb +38 -0
- data/lib/maze/proxy.rb +114 -0
- data/lib/maze/request_list.rb +82 -0
- data/lib/maze/retry_handler.rb +76 -0
- data/lib/maze/runner.rb +149 -0
- data/lib/maze/sauce_labs_utils.rb +96 -0
- data/lib/maze/server.rb +207 -0
- data/lib/maze/servlets/base_servlet.rb +22 -0
- data/lib/maze/servlets/command_servlet.rb +44 -0
- data/lib/maze/servlets/log_servlet.rb +64 -0
- data/lib/maze/servlets/reflective_servlet.rb +69 -0
- data/lib/maze/servlets/servlet.rb +160 -0
- data/lib/maze/smart_bear_utils.rb +71 -0
- data/lib/maze/store.rb +15 -0
- data/lib/maze/terminating_server.rb +129 -0
- data/lib/maze/timers.rb +51 -0
- data/lib/maze/wait.rb +35 -0
- data/lib/maze.rb +27 -0
- metadata +371 -0
@@ -0,0 +1,342 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @!group Error reporting steps
|
4
|
+
|
5
|
+
# Verifies that generic elements of an error payload are present.
|
6
|
+
# APIKey fields and headers are tested against the '$api_key' global variable.
|
7
|
+
#
|
8
|
+
# @step_input version [String] The payload version expected
|
9
|
+
# @step_input name [String] The expected name of the notifier
|
10
|
+
Then('the error is valid for the error reporting API version {string} for the {string} notifier') do |version, name|
|
11
|
+
step "the error is valid for the error reporting API version \"#{version}\"" \
|
12
|
+
" for the \"#{name}\" notifier with the apiKey \"#{$api_key}\""
|
13
|
+
end
|
14
|
+
|
15
|
+
# Verifies that generic elements of an error payload are present.
|
16
|
+
#
|
17
|
+
# @step_input version [String] The payload version expected
|
18
|
+
# @step_input name [String] The expected name of the notifier
|
19
|
+
# @step_input api_key [String] The API key expected
|
20
|
+
Then('the error is valid for the error reporting API version {string}' \
|
21
|
+
' for the {string} notifier with the apiKey {string}') do |payload_version, notifier_name, api_key|
|
22
|
+
steps %(
|
23
|
+
Then the error "Bugsnag-Api-Key" header equals "#{api_key}"
|
24
|
+
And the error payload field "apiKey" equals "#{api_key}"
|
25
|
+
And the error "Bugsnag-Payload-Version" header equals "#{payload_version}"
|
26
|
+
And the error payload contains the payloadVersion "#{payload_version}"
|
27
|
+
And the error "Content-Type" header equals "application/json"
|
28
|
+
And the error "Bugsnag-Sent-At" header is a timestamp
|
29
|
+
And the error Bugsnag-Integrity header is valid
|
30
|
+
|
31
|
+
And the error payload field "notifier.name" equals "#{notifier_name}"
|
32
|
+
And the error payload field "notifier.url" is not null
|
33
|
+
And the error payload field "notifier.version" is not null
|
34
|
+
And the error payload field "events" is a non-empty array
|
35
|
+
|
36
|
+
And each element in error payload field "events" has "severity"
|
37
|
+
And each element in error payload field "events" has "severityReason.type"
|
38
|
+
And each element in error payload field "events" has "unhandled"
|
39
|
+
And each element in error payload field "events" has "exceptions"
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
# Verifies that an event is correct for an unhandled error
|
45
|
+
# This checks various elements of the payload matching an unhandled error including:
|
46
|
+
# The unhandled flag
|
47
|
+
# Any attached session information
|
48
|
+
# Severity
|
49
|
+
#
|
50
|
+
# @param event [Integer] The event to verify
|
51
|
+
Then('event {int} is unhandled') do |event|
|
52
|
+
test_unhandled_state(event, true)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Verifies that an event is correct for an unhandled error
|
56
|
+
# This checks various elements of the payload matching an unhandled error including:
|
57
|
+
# The unhandled flag
|
58
|
+
# Any attached session information
|
59
|
+
# Severity
|
60
|
+
#
|
61
|
+
# @param event [Integer] The event to verify
|
62
|
+
# @param severity [String] An expected severity different to the default "error"
|
63
|
+
Then('event {int} is unhandled with the severity {string}') do |event, severity|
|
64
|
+
test_unhandled_state(event, true, severity)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Verifies that an event is correct for an handled error
|
68
|
+
# This checks various elements of the payload matching an unhandled error including:
|
69
|
+
# The unhandled flag
|
70
|
+
# Any attached session information
|
71
|
+
# Severity
|
72
|
+
#
|
73
|
+
# @param event [Integer] The event to verify
|
74
|
+
Then('event {int} is handled') do |event|
|
75
|
+
test_unhandled_state(event, false)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Verifies that an event is correct for an handled error
|
79
|
+
# This checks various elements of the payload matching an unhandled error including:
|
80
|
+
# The unhandled flag
|
81
|
+
# Any attached session information
|
82
|
+
# Severity
|
83
|
+
#
|
84
|
+
# @param event [Integer] The event to verify
|
85
|
+
# @param severity [String] An expected severity different to the default "error"
|
86
|
+
Then('event {int} is handled with the severity {string}') do |event, severity|
|
87
|
+
test_unhandled_state(event, false, severity)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Checks the payloadVersion is set correctly.
|
91
|
+
# For Javascript this should be in the events.
|
92
|
+
# For all other notifiers this should be a top-level key.
|
93
|
+
#
|
94
|
+
# @step_input payload_version [String] The payload version expected
|
95
|
+
Then('the error payload contains the payloadVersion {string}') do |payload_version|
|
96
|
+
body_version = Maze::Helper.read_key_path(Maze::Server.errors.current[:body], 'payloadVersion')
|
97
|
+
body_set = payload_version == body_version
|
98
|
+
event_version = Maze::Helper.read_key_path(Maze::Server.errors.current[:body], 'events.0.payloadVersion')
|
99
|
+
event_set = payload_version == event_version
|
100
|
+
Maze.check.true(
|
101
|
+
body_set || event_set,
|
102
|
+
"The payloadVersion was not the expected value of #{payload_version}. " \
|
103
|
+
"#{body_version} found in body, #{event_version} found in event"
|
104
|
+
)
|
105
|
+
end
|
106
|
+
|
107
|
+
# Tests whether a value in the first event entry matches a literal.
|
108
|
+
#
|
109
|
+
# @step_input field [String] The relative location of the value to test
|
110
|
+
# @step_input literal [Enum] The literal to test against, one of: true, false, null, not null
|
111
|
+
Then(/^the event "(.+)" is (true|false|null|not null)$/) do |field, literal|
|
112
|
+
step "the error payload field \"events.0.#{field}\" is #{literal}"
|
113
|
+
end
|
114
|
+
|
115
|
+
# Tests whether a value in the first event entry matches a string.
|
116
|
+
#
|
117
|
+
# @step_input field [String] The relative location of the value to test
|
118
|
+
# @step_input string_value [String] The string to match against
|
119
|
+
Then('the event {string} equals {string}') do |field, string_value|
|
120
|
+
step "the error payload field \"events.0.#{field}\" equals \"#{string_value}\""
|
121
|
+
end
|
122
|
+
|
123
|
+
# Tests whether a value in the first event entry equals an integer.
|
124
|
+
#
|
125
|
+
# @step_input field [String] The relative location of the value to test
|
126
|
+
# @step_input value [Integer] The integer to test against
|
127
|
+
Then('the event {string} equals {int}') do |field, value|
|
128
|
+
step "the error payload field \"events.0.#{field}\" equals #{value}"
|
129
|
+
end
|
130
|
+
|
131
|
+
# Tests whether a value in the first event entry starts with a string.
|
132
|
+
#
|
133
|
+
# @step_input field [String] The relative location of the value to test
|
134
|
+
# @step_input string_value [String] The string to match against
|
135
|
+
Then('the event {string} starts with {string}') do |field, string_value|
|
136
|
+
step "the error payload field \"events.0.#{field}\" starts with \"#{string_value}\""
|
137
|
+
end
|
138
|
+
|
139
|
+
# Tests whether a value in the first event entry ends with a string.
|
140
|
+
#
|
141
|
+
# @step_input field [String] The relative location of the value to test
|
142
|
+
# @step_input string_value [String] The string to match against
|
143
|
+
Then('the event {string} ends with {string}') do |field, string_value|
|
144
|
+
step "the error payload field \"events.0.#{field}\" ends with \"#{string_value}\""
|
145
|
+
end
|
146
|
+
|
147
|
+
# Tests whether a value in the first event entry matches a regex.
|
148
|
+
#
|
149
|
+
# @step_input field [String] The relative location of the value to test
|
150
|
+
# @step_input pattern [String] The regex to match against
|
151
|
+
Then('the event {string} matches {string}') do |field, pattern|
|
152
|
+
step "the error payload field \"events.0.#{field}\" matches the regex \"#{pattern}\""
|
153
|
+
end
|
154
|
+
|
155
|
+
# Tests whether a value in the first event entry is a timestamp.
|
156
|
+
#
|
157
|
+
# @step_input field [String] The relative location of the value to test
|
158
|
+
Then('the event {string} is a timestamp') do |field|
|
159
|
+
step "the error payload field \"events.0.#{field}\" matches the regex \"#{TIMESTAMP_REGEX}\""
|
160
|
+
end
|
161
|
+
|
162
|
+
# Tests whether a value in the first event entry is a numeric and parsable timestamp.
|
163
|
+
#
|
164
|
+
# @step_input field [String] The relative location of the value to test
|
165
|
+
Then('the event {string} is a parsable timestamp in seconds') do |field|
|
166
|
+
step "the error payload field \"events.0.#{field}\" is a parsable timestamp in seconds"
|
167
|
+
end
|
168
|
+
|
169
|
+
# Tests the Event field value against an environment variable.
|
170
|
+
#
|
171
|
+
# @step_input field [String] The payload element to check
|
172
|
+
# @step_input env_var [String] The environment variable to test against
|
173
|
+
Then('the event {string} equals the environment variable {string}') do |field, env_var|
|
174
|
+
step "the error payload field \"events.0.#{field}\" equals the environment variable \"#{env_var}\""
|
175
|
+
end
|
176
|
+
|
177
|
+
# Tests whether a value in the first event entry matches a JSON fixture.
|
178
|
+
#
|
179
|
+
# @step_input field [String] The relative location of the value to test
|
180
|
+
# @step_input fixture_path [String] The fixture to match against
|
181
|
+
Then('the event {string} matches the JSON fixture in {string}') do |field, fixture_path|
|
182
|
+
step "the error payload field \"events.0.#{field}\" matches the JSON fixture in \"#{fixture_path}\""
|
183
|
+
end
|
184
|
+
|
185
|
+
Then('the event {string} string is empty') do |keypath|
|
186
|
+
value = Maze::Helper.read_key_path(Maze::Server.errors.current[:body], keypath)
|
187
|
+
Maze.check.true(value.nil? || value.empty?, "The #{keypath} is not empty: '#{value}'")
|
188
|
+
end
|
189
|
+
|
190
|
+
Then('the event {string} is greater than {int}') do |keypath, int|
|
191
|
+
value = Maze::Helper.read_key_path(Maze::Server.errors.current[:body], "events.0.#{keypath}")
|
192
|
+
Maze.check.false(value.nil?, "The event #{keypath} is nil")
|
193
|
+
Maze.check.operator(value, :>, int)
|
194
|
+
end
|
195
|
+
|
196
|
+
# Tests whether a value in the first exception of the first event entry starts with a string.
|
197
|
+
#
|
198
|
+
# @step_input field [String] The relative location of the value to test
|
199
|
+
# @step_input string_value [String] The string to match against
|
200
|
+
Then('the exception {string} starts with {string}') do |field, string_value|
|
201
|
+
step "the error payload field \"events.0.exceptions.0.#{field}\" starts with \"#{string_value}\""
|
202
|
+
end
|
203
|
+
|
204
|
+
# Tests whether a value in the first exception of the first event entry ends with a string.
|
205
|
+
#
|
206
|
+
# @step_input field [String] The relative location of the value to test
|
207
|
+
# @step_input string_value [String] The string to match against
|
208
|
+
Then('the exception {string} ends with {string}') do |field, string_value|
|
209
|
+
step "the error payload field \"events.0.exceptions.0.#{field}\" ends with \"#{string_value}\""
|
210
|
+
end
|
211
|
+
|
212
|
+
# Tests whether a value in the first exception of the first event entry equals a string.
|
213
|
+
#
|
214
|
+
# @step_input field [String] The relative location of the value to test
|
215
|
+
# @step_input string_value [String] The string to match against
|
216
|
+
Then('the exception {string} equals {string}') do |field, string_value|
|
217
|
+
step "the error payload field \"events.0.exceptions.0.#{field}\" equals \"#{string_value}\""
|
218
|
+
end
|
219
|
+
|
220
|
+
# Tests whether a value in the first exception of the first event entry matches a regex.
|
221
|
+
#
|
222
|
+
# @step_input field [String] The relative location of the value to test
|
223
|
+
# @step_input pattern [String] The regex to match against
|
224
|
+
Then('the exception {string} matches {string}') do |field, pattern|
|
225
|
+
step "the error payload field \"events.0.exceptions.0.#{field}\" matches the regex \"#{pattern}\""
|
226
|
+
end
|
227
|
+
|
228
|
+
# Tests whether a element of a stack frame in the first exception of the first event equals an integer.
|
229
|
+
#
|
230
|
+
# @step_input key [String] The element of the stack frame to test
|
231
|
+
# @step_input num [Integer] The stack frame where the element is present
|
232
|
+
# @step_input value [Integer] The value to test against
|
233
|
+
Then('the {string} of stack frame {int} equals {int}') do |key, num, value|
|
234
|
+
field = "events.0.exceptions.0.stacktrace.#{num}.#{key}"
|
235
|
+
step "the error payload field \"#{field}\" equals #{value}"
|
236
|
+
end
|
237
|
+
|
238
|
+
# Tests whether an element of a stack frame in the first exception of the first event matches a regex pattern.
|
239
|
+
#
|
240
|
+
# @step_input key [String] The element of the stack frame to test
|
241
|
+
# @step_input num [Integer] The stack frame where the element is present
|
242
|
+
# @step_input pattern [String] The regex to match against
|
243
|
+
Then('the {string} of stack frame {int} matches {string}') do |key, num, pattern|
|
244
|
+
field = "events.0.exceptions.0.stacktrace.#{num}.#{key}"
|
245
|
+
step "the error payload field \"#{field}\" matches the regex \"#{pattern}\""
|
246
|
+
end
|
247
|
+
|
248
|
+
# Tests whether an element of a stack frame in the first exception of the first event equals a string.
|
249
|
+
#
|
250
|
+
# @step_input key [String] The element of the stack frame to test
|
251
|
+
# @step_input num [Integer] The stack frame where the element is present
|
252
|
+
# @step_input value [String] The value to test against
|
253
|
+
Then('the {string} of stack frame {int} equals {string}') do |key, num, value|
|
254
|
+
field = "events.0.exceptions.0.stacktrace.#{num}.#{key}"
|
255
|
+
step "the error payload field \"#{field}\" equals \"#{value}\""
|
256
|
+
end
|
257
|
+
|
258
|
+
# Tests whether an element of a stack frame in the first exception of the first event starts with a string.
|
259
|
+
#
|
260
|
+
# @step_input key [String] The element of the stack frame to test
|
261
|
+
# @step_input num [Integer] The stack frame where the element is present
|
262
|
+
# @step_input value [String] The value to test against
|
263
|
+
Then('the {string} of stack frame {int} starts with {string}') do |key, num, value|
|
264
|
+
field = "events.0.exceptions.0.stacktrace.#{num}.#{key}"
|
265
|
+
step "the error payload field \"#{field}\" starts with \"#{value}\""
|
266
|
+
end
|
267
|
+
|
268
|
+
# Tests whether an element of a stack frame in the first exception of the first event ends with a string.
|
269
|
+
#
|
270
|
+
# @step_input key [String] The element of the stack frame to test
|
271
|
+
# @step_input num [Integer] The stack frame where the element is present
|
272
|
+
# @step_input value [String] The value to test against
|
273
|
+
Then('the {string} of stack frame {int} ends with {string}') do |key, num, value|
|
274
|
+
field = "events.0.exceptions.0.stacktrace.#{num}.#{key}"
|
275
|
+
step "the error payload field \"#{field}\" ends with \"#{value}\""
|
276
|
+
end
|
277
|
+
|
278
|
+
# Tests whether an element of a stack frame in the first exception of the first event matches a literal.
|
279
|
+
#
|
280
|
+
# @step_input key [String] The element of the stack frame to test
|
281
|
+
# @step_input num [Integer] The stack frame where the element is present
|
282
|
+
# @step_input literal [Enum] The literal to test against, one of: true, false, null, not null
|
283
|
+
Then(/^the "(.*)" of stack frame (\d*) is (true|false|null|not null)$/) do |key, num, literal|
|
284
|
+
field = "events.0.exceptions.0.stacktrace.#{num}.#{key}"
|
285
|
+
step "the error payload field \"#{field}\" is #{literal}"
|
286
|
+
end
|
287
|
+
|
288
|
+
# Tests whether a thread from the first event, identified by name, is the error reporting thread.
|
289
|
+
#
|
290
|
+
# @step_input thread_name [String] The name of the thread to test
|
291
|
+
Then('the thread with name {string} contains the error reporting flag') do |thread_name|
|
292
|
+
validate_error_reporting_thread('name', thread_name)
|
293
|
+
end
|
294
|
+
|
295
|
+
# Tests whether a thread from the first event, identified by an id, is the error reporting thread.
|
296
|
+
#
|
297
|
+
# @step_input thread_id [String] The id of the thread to test
|
298
|
+
Then('the thread with id {string} contains the error reporting flag') do |thread_id|
|
299
|
+
validate_error_reporting_thread('id', thread_id)
|
300
|
+
end
|
301
|
+
|
302
|
+
# Tests that a thread from the first event, identified by a particular key-value pair, is the error reporting thread.
|
303
|
+
#
|
304
|
+
# @param payload_key [String] The thread identifier key
|
305
|
+
# @param payload_value [Any] The thread identifier value
|
306
|
+
def validate_error_reporting_thread(payload_key, payload_value)
|
307
|
+
threads = Maze::Server.errors.current[:body]['events'].first['threads']
|
308
|
+
Maze.check.kind_of Array, threads
|
309
|
+
count = 0
|
310
|
+
|
311
|
+
threads.each do |thread|
|
312
|
+
count += 1 if thread[payload_key].to_s == payload_value && thread['errorReportingThread'] == true
|
313
|
+
end
|
314
|
+
Maze.check.equal(1, count)
|
315
|
+
end
|
316
|
+
|
317
|
+
# Tests whether an event has the correct attributes we'd expect for un/handled events
|
318
|
+
#
|
319
|
+
# @param event [Integer] The index of the event
|
320
|
+
# @param unhandled [Boolean] Whether the event is unhandled or handled
|
321
|
+
# @param severity [String] Optional. An overwritten severity to look for
|
322
|
+
def test_unhandled_state(event, unhandled, severity = nil)
|
323
|
+
expected_unhandled_state = unhandled ? 'true' : 'false'
|
324
|
+
expected_severity = if severity
|
325
|
+
severity
|
326
|
+
elsif unhandled
|
327
|
+
'error'
|
328
|
+
else
|
329
|
+
'warning'
|
330
|
+
end
|
331
|
+
steps %(
|
332
|
+
Then the error payload field "events.#{event}.unhandled" is #{expected_unhandled_state}
|
333
|
+
And the error payload field "events.#{event}.severity" equals "#{expected_severity}"
|
334
|
+
)
|
335
|
+
|
336
|
+
return if Maze::Helper.read_key_path(Maze::Server.errors.current[:body], "events.#{event}.session").nil?
|
337
|
+
|
338
|
+
session_field = unhandled ? 'unhandled' : 'handled'
|
339
|
+
steps %(
|
340
|
+
And the error payload field "events.#{event}.session.events.#{session_field}" is greater than 0
|
341
|
+
)
|
342
|
+
end
|
@@ -0,0 +1,190 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @!group Feature flag steps
|
4
|
+
|
5
|
+
# Verifies that there are no feature flags present in a given event
|
6
|
+
#
|
7
|
+
# @step_input event_id [Integer] The id of the event in the payloads array
|
8
|
+
Then('event {int} has no feature flags') do |event_id|
|
9
|
+
event = Maze::Helper.read_key_path(Maze::Server.errors.current[:body], "events.#{event_id}")
|
10
|
+
Maze.check.false(has_feature_flags?(event), "Feature flags expected to be absent or empty, was #{event['featureFlags']}")
|
11
|
+
end
|
12
|
+
|
13
|
+
# Verifies that the are no feature flags present
|
14
|
+
Then('the event has no feature flags') do
|
15
|
+
steps %(
|
16
|
+
Then event 0 has no feature flags
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Verifies a feature flag with a specific variant is uniquely present in a given event
|
21
|
+
#
|
22
|
+
# @step_input event_id [Integer] The id of the event in the payloads array
|
23
|
+
# @step_input flag_name [String] The featureFlag value expected
|
24
|
+
# @step_input variant [String] The variant value expected
|
25
|
+
Then('event {int} contains the feature flag {string} with variant {string}') do |event_id, flag_name, variant|
|
26
|
+
event = Maze::Helper.read_key_path(Maze::Server.errors.current[:body], "events.#{event_id}")
|
27
|
+
Maze.check.true(has_feature_flags?(event), "Expected feature flags were not present in event #{event_id}: #{event}")
|
28
|
+
feature_flags = event['featureFlags']
|
29
|
+
# Test for flag name uniqueness
|
30
|
+
Maze.check.true(
|
31
|
+
feature_flags.one? { |flag| flag['featureFlag'].eql?(flag_name) },
|
32
|
+
"Expected single flag with 'featureFlag' value: #{flag_name}. Present flags: #{feature_flags}"
|
33
|
+
)
|
34
|
+
|
35
|
+
flag = feature_flags.find { |flag| flag['featureFlag'].eql?(flag_name) }
|
36
|
+
# Test the variant value
|
37
|
+
Maze.check.true(
|
38
|
+
flag.has_key?('variant') && flag['variant'].eql?(variant),
|
39
|
+
"Feature flag: #{flag} did not have variant: #{variant}. All flags: #{feature_flags}"
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Verifies a feature flag with a specific variant is uniquely present
|
44
|
+
#
|
45
|
+
# @step_input flag_name [String] The featureFlag value expected
|
46
|
+
# @step_input variant [String] The variant value expected
|
47
|
+
Then('the event contains the feature flag {string} with variant {string}') do |flag_name, variant|
|
48
|
+
steps %(
|
49
|
+
Then event 0 contains the feature flag "#{flag_name}" with variant "#{variant}"
|
50
|
+
)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Verifies a feature flag with no variant (either null or missing) is uniquely present in a given event
|
54
|
+
#
|
55
|
+
# @step_input event_id [Integer] The id of the event in the payloads array
|
56
|
+
# @step_input flag_name [String] The featureFlag value expected
|
57
|
+
Then('event {int} contains the feature flag {string} with no variant') do |event_id, flag_name|
|
58
|
+
event = Maze::Helper.read_key_path(Maze::Server.errors.current[:body], "events.#{event_id}")
|
59
|
+
Maze.check.true(has_feature_flags?(event),
|
60
|
+
"Expected feature flags were not present in event #{event_id}: #{event}")
|
61
|
+
feature_flags = event['featureFlags']
|
62
|
+
# Test for flag name uniqueness
|
63
|
+
Maze.check.true(
|
64
|
+
feature_flags.one? { |flag| flag['featureFlag'].eql?(flag_name) },
|
65
|
+
"Expected single flag with 'featureFlag' value: #{flag_name}. All flags: #{feature_flags}"
|
66
|
+
)
|
67
|
+
|
68
|
+
flag = feature_flags.find { |flag| flag['featureFlag'].eql?(flag_name) }
|
69
|
+
# Test the variant value
|
70
|
+
Maze.check.false(
|
71
|
+
flag.has_key?('variant'),
|
72
|
+
"Feature flag: #{flag} expected to have no variant. All flags: #{feature_flags}"
|
73
|
+
)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Verifies a feature flag with no variant (either null or missing) is uniquely present
|
77
|
+
#
|
78
|
+
# @step_input flag_name [String] The featureFlag value expected
|
79
|
+
Then('the event contains the feature flag {string} with no variant') do |flag_name|
|
80
|
+
steps %(
|
81
|
+
Then event 0 contains the feature flag "#{flag_name}" with no variant
|
82
|
+
)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Verifies that a number of feature flags outlined in a table are all present and unique in the given event
|
86
|
+
#
|
87
|
+
# The DataTable used for this step should have `featureFlag` and `variant` columns, containing the appropriate
|
88
|
+
# values. For flags with a variant leave the `variant` column blank.
|
89
|
+
#
|
90
|
+
# Example:
|
91
|
+
# | featureFlag | variant |
|
92
|
+
# | my_flag_1 | var_1 |
|
93
|
+
# | my_flag_2 | var_2 |
|
94
|
+
# | my_flag_3 | | # Should not have a variant present
|
95
|
+
#
|
96
|
+
# @step_input event_id [Integer] The id of the event in the payloads array
|
97
|
+
# @step_input table [Cucumber::MultilineArgument::DataTable] Table of expected values
|
98
|
+
Then('event {int} contains the following feature flags:') do |event_id, table|
|
99
|
+
event = Maze::Helper.read_key_path(Maze::Server.errors.current[:body], "events.#{event_id}")
|
100
|
+
verify_feature_flags_with_table(event, table)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Verifies that a number of feature flags outlined in a table are all present and unique
|
104
|
+
#
|
105
|
+
# See above for data table details
|
106
|
+
#
|
107
|
+
# @step_input table [Cucumber::MultilineArgument::DataTable] Table of expected values
|
108
|
+
Then('the event contains the following feature flags:') do |table|
|
109
|
+
event = Maze::Helper.read_key_path(Maze::Server.errors.current[:body], 'events.0')
|
110
|
+
verify_feature_flags_with_table(event, table)
|
111
|
+
end
|
112
|
+
|
113
|
+
# Verifies a feature flag a specific name is not present, regardless of variant, for a given event
|
114
|
+
#
|
115
|
+
# @step_input event_id [Integer] The id of the event in the payloads array
|
116
|
+
# @step_input flag_name [String] The featureFlag value not expected
|
117
|
+
Then('event {int} does not contain the feature flag {string}') do |event_id, flag_name|
|
118
|
+
event = Maze::Helper.read_key_path(Maze::Server.errors.current[:body], "events.#{event_id}")
|
119
|
+
Maze.check.true(
|
120
|
+
has_feature_flags?(event),
|
121
|
+
"Expected feature flags were not present in event #{event_id}: #{event}"
|
122
|
+
)
|
123
|
+
feature_flags = event['featureFlags']
|
124
|
+
Maze.check.true(
|
125
|
+
feature_flags.none? { |flag| flag['featureFlag'].eql?(flag_name) },
|
126
|
+
"Expected to not find feature flag #{flag_name}. All flags: #{feature_flags}"
|
127
|
+
)
|
128
|
+
end
|
129
|
+
|
130
|
+
# Verifies a feature flag a specific name is not present, regardless of variant
|
131
|
+
#
|
132
|
+
# @step_input flag_name [String] The featureFlag value not expected
|
133
|
+
Then('the event does not contain the feature flag {string}') do |flag_name|
|
134
|
+
steps %(
|
135
|
+
Then event 0 does not contain the feature flag "#{flag_name}"
|
136
|
+
)
|
137
|
+
end
|
138
|
+
|
139
|
+
def verify_feature_flags_with_table(event, table)
|
140
|
+
Maze.check.true(
|
141
|
+
has_feature_flags?(event),
|
142
|
+
"Expected feature flags were not present in event: #{event}"
|
143
|
+
)
|
144
|
+
feature_flags = event['featureFlags']
|
145
|
+
|
146
|
+
expected_features = table.hashes
|
147
|
+
Maze.check.true(
|
148
|
+
feature_flags.size == expected_features.size,
|
149
|
+
"Expected #{expected_features.size} features,
|
150
|
+
found #{feature_flags}"
|
151
|
+
)
|
152
|
+
expected_features.each do |expected|
|
153
|
+
flag_name = expected['featureFlag']
|
154
|
+
variant = expected['variant']
|
155
|
+
# Test for flag name uniqueness
|
156
|
+
Maze.check.true(
|
157
|
+
feature_flags.one? { |flag| flag['featureFlag'].eql?(flag_name) },
|
158
|
+
"Expected single flag with 'featureFlag' value: #{flag_name}. Present flags: #{feature_flags}"
|
159
|
+
)
|
160
|
+
flag = feature_flags.find { |flag| flag['featureFlag'].eql?(flag_name) }
|
161
|
+
# Test the variant value
|
162
|
+
if variant.nil? || expected['variant'].empty?
|
163
|
+
Maze.check.false(
|
164
|
+
flag.has_key?('variant'),
|
165
|
+
"Feature flag: #{flag} expected to have no variant. All flags: #{feature_flags}"
|
166
|
+
)
|
167
|
+
else
|
168
|
+
Maze.check.true(
|
169
|
+
flag.has_key?('variant') && flag['variant'].eql?(variant),
|
170
|
+
"Feature flag: #{flag} did not have variant: #{variant}. All flags: #{feature_flags}"
|
171
|
+
)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def has_feature_flags?(event)
|
177
|
+
if event.has_key?('featureFlags')
|
178
|
+
Maze.check.false(
|
179
|
+
event['featureFlags'].nil?,
|
180
|
+
'The feature flags key was present, but null'
|
181
|
+
)
|
182
|
+
Maze.check.true(
|
183
|
+
event['featureFlags'].is_a?(Array),
|
184
|
+
"The feature flags key was present, but the value: #{event['featureFlags']} must be an array"
|
185
|
+
)
|
186
|
+
!event['featureFlags'].empty?
|
187
|
+
else
|
188
|
+
false
|
189
|
+
end
|
190
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @!group Header steps
|
4
|
+
|
5
|
+
# Tests that a request header is not null
|
6
|
+
#
|
7
|
+
# @step_input request_type [String] The type of request (error, session, build, etc)
|
8
|
+
# @step_input header_name [String] The header to test
|
9
|
+
Then('the {word} {string} header is not null') do |request_type, header_name|
|
10
|
+
Maze.check.not_nil(Maze::Server.list_for(request_type).current[:request][header_name],
|
11
|
+
"The #{request_type} '#{header_name}' header should not be null")
|
12
|
+
end
|
13
|
+
|
14
|
+
# Tests that a request header is null
|
15
|
+
#
|
16
|
+
# @step_input request_type [String] The type of request (error, session, build, etc)
|
17
|
+
# @step_input header_name [String] The header to test
|
18
|
+
Then('the {word} {string} header is null') do |request_type, header_name|
|
19
|
+
request = Maze::Server.list_for(request_type).current[:request]
|
20
|
+
|
21
|
+
Maze.check.nil(request[header_name],
|
22
|
+
"The #{request_type} '#{header_name}' header should be null")
|
23
|
+
end
|
24
|
+
|
25
|
+
# Tests that request header equals a string
|
26
|
+
#
|
27
|
+
# @step_input request_type [String] The type of request (error, session, build, etc)
|
28
|
+
# @step_input header_name [String] The header to test
|
29
|
+
# @step_input header_value [String] The string it should match
|
30
|
+
Then('the {word} {string} header equals {string}') do |request_type, header_name, header_value|
|
31
|
+
Maze.check.not_nil(Maze::Server.list_for(request_type).current[:request][header_name],
|
32
|
+
"The #{request_type} '#{header_name}' header wasn't present in the request")
|
33
|
+
Maze.check.equal(header_value, Maze::Server.list_for(request_type).current[:request][header_name])
|
34
|
+
end
|
35
|
+
|
36
|
+
# Tests that a request header matches a regex
|
37
|
+
#
|
38
|
+
# @step_input request_type [String] The type of request (error, session, build, etc)
|
39
|
+
# @step_input header_name [String] The header to test
|
40
|
+
# @step_input regex_string [String] The regex to match with
|
41
|
+
Then('the {word} {string} header matches the regex {string}') do |request_type, header_name, regex_string|
|
42
|
+
regex = Regexp.new(regex_string)
|
43
|
+
value = Maze::Server.list_for(request_type).current[:request][header_name]
|
44
|
+
Maze.check.match(regex, value)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Tests that a request header matches one of a list of strings
|
48
|
+
#
|
49
|
+
# @step_input request_type [String] The type of request (error, session, build, etc)
|
50
|
+
# @step_input header_name [String] The header to test
|
51
|
+
# @step_input header_values [DataTable] A parsed data table
|
52
|
+
Then('the {word} {string} header equals one of:') do |request_type, header_name, header_values|
|
53
|
+
Maze.check.include(header_values.raw.flatten, Maze::Server.list_for(request_type).current[:request][header_name])
|
54
|
+
end
|
55
|
+
|
56
|
+
# Tests that a request header is a timestamp.
|
57
|
+
#
|
58
|
+
# @step_input request_type [String] The type of request (error, session, build, etc)
|
59
|
+
# @step_input header_name [String] The header to test
|
60
|
+
Then('the {word} {string} header is a timestamp') do |request_type, header_name|
|
61
|
+
header = Maze::Server.list_for(request_type).current[:request][header_name]
|
62
|
+
Maze.check.match(TIMESTAMP_REGEX, header)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Checks that the Bugsnag-Integrity header is a SHA1 or simple digest
|
66
|
+
#
|
67
|
+
# @step_input request_type [String] The type of request (error, session, build, etc)
|
68
|
+
When('the {word} Bugsnag-Integrity header is valid') do |request_type|
|
69
|
+
Maze.check.true(Maze::Helper.valid_bugsnag_integrity_header(Maze::Server.list_for(request_type).current),
|
70
|
+
'Invalid Bugsnag-Integrity header detected')
|
71
|
+
end
|
72
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @!group Log assertion steps
|
4
|
+
|
5
|
+
# Tests that a log request matches a given level and message.
|
6
|
+
#
|
7
|
+
# @step_input log_level [String] The expected log level
|
8
|
+
# @step_input message [String] The expected message
|
9
|
+
Then('the {string} level log message equals {string}') do |log_level, message|
|
10
|
+
request = Maze::Server.logs.current
|
11
|
+
Maze.check.not_nil(request, 'No log message to check')
|
12
|
+
log = request[:body]
|
13
|
+
Maze.check.equal(log_level, Maze::Helper.read_key_path(log, 'level'))
|
14
|
+
Maze.check.equal(message, Maze::Helper.read_key_path(log, 'message'))
|
15
|
+
end
|
16
|
+
|
17
|
+
# Tests that a log request matches a given level and message regex.
|
18
|
+
#
|
19
|
+
# @step_input log_level [String] The expected log level
|
20
|
+
# @step_input message_regex [String] Regex for the expected message
|
21
|
+
Then('the {string} level log message matches the regex {string}') do |log_level, message_regex|
|
22
|
+
request = Maze::Server.logs.current
|
23
|
+
Maze.check.not_nil(request, 'No log message to check')
|
24
|
+
|
25
|
+
log = request[:body]
|
26
|
+
Maze.check.equal(log_level, Maze::Helper.read_key_path(log, 'level'))
|
27
|
+
regex = Regexp.new(message_regex)
|
28
|
+
Maze.check.match(regex, Maze::Helper.read_key_path(log, 'message'))
|
29
|
+
end
|