bugsnag-maze-runner 8.2.0 → 8.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eac01df378fac543e5aa19a4999e4a2e403de8e7df9860b6463e27899f2f2f0d
4
- data.tar.gz: c59e92d444b2da617bb0ec06c5fdc4355687129b7cc01cd56e5900a48c2fbe2c
3
+ metadata.gz: 02b1bd719cc437d684670a164059b1db11b6b86e10de81348e1027b74b1a138d
4
+ data.tar.gz: f5341e638425082222c5ca8462e4e98cce7a00a084351a91e746ebb07fc0d23e
5
5
  SHA512:
6
- metadata.gz: a7d5e5079dc431e2c33d57f63ce3242cc0eaf12f81de1b043b843598ba15beb6d0610f21fbc2955502c6f35125781c1889b5a92963560e5dfc14d01f230bda90
7
- data.tar.gz: 8551f7d971779b47ec6e65ba0a6402bcbf9110e4b9232b4851c2b37aab1793a89879c1e3946e86c87abea478465ec43a28306f6f1daf42ff5c043415e4b297e9
6
+ metadata.gz: 683441571c5eb37acffc60787acaa1f697b9e20fe5af95ebb45abe52682ac0507b2ee1f4b55bc28ea0de7eb7587c5f829ee12bcde75482a818cee3be34cbafe5
7
+ data.tar.gz: 8832b0b1684e380449cc3aac2fecf6b2ae47195761a07ac6d1fdc469e6bd176ab89a068726e259dd63f3137af80d57b2542120c8e41b779afe211e75ac4c1470
@@ -0,0 +1,8 @@
1
+ # @!group Deprecated steps
2
+
3
+ # Waits for a given number of spans to be received, which may be spread across one or more trace requests.
4
+ #
5
+ # @step_input span_count [Integer] The number of spans to wait for
6
+ When('I wait for {int} span(s)') do |span_count|
7
+ assert_received_spans Maze::Server.list_for('traces'), span_count
8
+ end
@@ -8,7 +8,7 @@ require_relative '../../maze/wait'
8
8
 
9
9
  # @!group Request assertion steps
10
10
 
11
- def assert_received_requests(request_count, list, list_name, precise = true)
11
+ def assert_received_requests(request_count, list, list_name, precise = true, maximum = nil)
12
12
  timeout = Maze.config.receive_requests_wait
13
13
  # Interval set to 0.5s to make it more likely to detect erroneous extra requests,
14
14
  # without impacting overall speed too much
@@ -45,6 +45,7 @@ def assert_received_requests(request_count, list, list_name, precise = true)
45
45
  Maze.check.equal(request_count, list.size_remaining, "#{list.size_remaining} #{list_name} received")
46
46
  else
47
47
  Maze.check.operator(request_count, :<=, list.size_remaining, "#{list.size_remaining} #{list_name} received")
48
+ Maze.check.operator(maximum, :>=, list.size_remaining, "#{list.size_remaining} #{list_name} received") unless maximum.nil?
48
49
  end
49
50
  end
50
51
 
@@ -102,6 +103,16 @@ Then('I have received at least {int} {request_type}') do |min_received, request_
102
103
  Maze.check.operator(list.size_remaining, :>=, min_received, "Actually received #{list.size_remaining} #{request_type} requests")
103
104
  end
104
105
 
106
+ # Verify that an amount of requests within a range have been received
107
+ #
108
+ # @step_input min_received [Integer] The minimum amount of requests required to pass
109
+ # @step_input max_received [Integer] The maximum amount of requests before failure
110
+ # @step_input request_type [String] The type of request (error, session, build, etc)
111
+ Then('I wait to receive between {int} and {int} {request_type}') do |min_received, max_received, request_type|
112
+ list = Maze::Server.list_for(request_type)
113
+ assert_received_requests min_received, list, request_type, false, max_received
114
+ end
115
+
105
116
  # Assert that the test Server hasn't received any requests - of a specific, or any, type.
106
117
  #
107
118
  # @step_input request_type [String] The type of request ('error', 'session', 'trace', sampling request', etc)
@@ -3,8 +3,25 @@
3
3
  # Waits for a given number of spans to be received, which may be spread across one or more trace requests.
4
4
  #
5
5
  # @step_input span_count [Integer] The number of spans to wait for
6
- When('I wait for {int} span(s)') do |span_count|
7
- assert_received_spans span_count, Maze::Server.list_for('traces')
6
+ Then('I wait to receive {int} span(s)') do |span_count|
7
+ assert_received_span_count Maze::Server.list_for('traces'), span_count
8
+ end
9
+
10
+ # Waits for a minimum number of spans to be received, which may be spread across one or more trace requests.
11
+ # If more spans than requested are received, this step will still pass.
12
+ #
13
+ # @step_input span_min [Integer] The minimum number of spans to wait for
14
+ Then('I wait to receive at least {int} span(s)') do |span_min|
15
+ assert_received_minimum_span_count Maze::Server.list_for('traces'), span_min
16
+ end
17
+
18
+ # Waits for a minimum number of spans to be received, which may be spread across one or more trace requests.
19
+ # If more spans than the maximum requested number of spans are received, this step will fail.
20
+ #
21
+ # @step_input span_min [Integer] The minimum number of spans to wait for
22
+ # @step_input span_max [Integer] The maximum number of spans to receive before failure
23
+ Then('I wait to receive between {int} and {int} span(s)') do |span_min, span_max|
24
+ assert_received_ranged_span_count Maze::Server.list_for('traces'), span_min, span_max
8
25
  end
9
26
 
10
27
  Then('I should have received no spans') do
@@ -227,16 +244,28 @@ def attribute_value_matches?(attribute_value, expected_type, expected_value)
227
244
  end
228
245
  end
229
246
 
230
- def assert_received_spans(span_count, list)
247
+ def assert_received_span_count(list, count)
248
+ assert_received_spans(list, count, count)
249
+ end
250
+
251
+ def assert_received_minimum_span_count(list, minimum)
252
+ assert_received_spans(list, minimum)
253
+ end
254
+
255
+ def assert_received_ranged_span_count(list, minimum, maximum)
256
+ assert_received_spans(list, minimum, maximum)
257
+ end
258
+
259
+ def assert_received_spans(list, min_received, max_received = nil)
231
260
  timeout = Maze.config.receive_requests_wait
232
261
  wait = Maze::Wait.new(timeout: timeout)
233
262
 
234
- received = wait.until { spans_from_request_list(list).size >= span_count }
263
+ received = wait.until { spans_from_request_list(list).size >= min_received }
235
264
  received_count = spans_from_request_list(list).size
236
265
 
237
266
  unless received
238
267
  raise Test::Unit::AssertionFailedError.new <<-MESSAGE
239
- Expected #{span_count} spans but received #{received_count} within the #{timeout}s timeout.
268
+ Expected #{min_received} spans but received #{received_count} within the #{timeout}s timeout.
240
269
  This could indicate that:
241
270
  - Bugsnag crashed with a fatal error.
242
271
  - Bugsnag did not make the requests that it should have done.
@@ -246,7 +275,7 @@ def assert_received_spans(span_count, list)
246
275
  MESSAGE
247
276
  end
248
277
 
249
- Maze.check.operator(span_count, :<=, received_count, "#{received_count} spans received")
278
+ Maze.check.operator(max_received, :>=, received_count, "#{received_count} spans received") if max_received
250
279
 
251
280
  Maze::Schemas::Validator.verify_against_schema(list, 'trace')
252
281
  Maze::Schemas::Validator.validate_payload_elements(list, 'trace')
@@ -30,12 +30,14 @@ BeforeAll do
30
30
  end
31
31
  $logger.info "Running in #{Maze.mode.to_s} mode"
32
32
 
33
- # Clear out maze_output folder
33
+ # Clear out maze_output folder and zip
34
34
  maze_output = Dir.glob(File.join(Dir.pwd, 'maze_output', '*'))
35
35
  if Maze.config.file_log && !maze_output.empty?
36
36
  maze_output.each { |path| $logger.info "Clearing contents of #{path}" }
37
37
  FileUtils.rm_rf(maze_output)
38
38
  end
39
+ maze_output_zip = Dir.glob(File.join(Dir.pwd, 'maze_output.zip'))
40
+ FileUtils.rm_rf(maze_output_zip)
39
41
 
40
42
  # Record the local server starting time
41
43
  Maze.start_time = Time.now.strftime('%Y-%m-%d %H:%M:%S')
@@ -222,6 +224,14 @@ end
222
224
 
223
225
  # After all tests
224
226
  AfterAll do
227
+ maze_output = File.join(Dir.pwd, 'maze_output')
228
+ maze_output_zip = File.join(Dir.pwd, 'maze_output.zip')
229
+ # zip a folder with files and subfolders
230
+ Zip::File.open(maze_output_zip, Zip::File::CREATE) do |zipfile|
231
+ Dir["#{maze_output}/**/**"].each do |file|
232
+ zipfile.add(file.sub(Dir.pwd + '/', ''), file)
233
+ end
234
+ end
225
235
 
226
236
  metrics = Maze::MetricsProcessor.new(Maze::Server.metrics)
227
237
  metrics.process
@@ -108,7 +108,6 @@ module Maze
108
108
  add_android 'Samsung Galaxy A8', '7.1', hash # ANDROID_7_1_SAMSUNG_GALAXY_A8
109
109
  add_android 'Samsung Galaxy Note 8', '7.1', hash # ANDROID_7_1_SAMSUNG_GALAXY_NOTE_8
110
110
  add_android 'Samsung Galaxy S8', '7.0', hash # ANDROID_7_0_SAMSUNG_GALAXY_S8
111
- add_android 'Samsung Galaxy S8 Plus', '7.0', hash # ANDROID_7_0_SAMSUNG_GALAXY_S8_PLUS
112
111
 
113
112
  # Specific iOS devices
114
113
  add_ios 'iPhone 14 Plus', '16.0', hash # IOS_16_0_IPHONE_14_PLUS
@@ -161,7 +161,7 @@ android_6:
161
161
 
162
162
  android_7:
163
163
  browserName: "Android Browser"
164
- device: "Samsung Galaxy S8 Plus"
164
+ device: "Samsung Galaxy S8"
165
165
  os: "android"
166
166
  osVersion: "7.0"
167
167
  realMobile: true
@@ -5,6 +5,11 @@ require_relative '../helper'
5
5
  module Maze
6
6
  module Schemas
7
7
 
8
+ HEX_STRING_16 = '^[A-Fa-f0-9]{16}$'
9
+ HEX_STRING_32 = '^[A-Fa-f0-9]{32}$'
10
+ SAMPLING_HEADER_ENTRY = '((1(.0)?|0(\.[0-9]+)?):[0-9]+)'
11
+ SAMPLING_HEADER = "^#{SAMPLING_HEADER_ENTRY}(;#{SAMPLING_HEADER_ENTRY})*$"
12
+
8
13
  # Contains a set of pre-defined validations for ensuring traces are correct
9
14
  class TraceValidator
10
15
 
@@ -15,9 +20,10 @@ module Maze
15
20
 
16
21
  # Creates the validator
17
22
  #
18
- # @param body [Hash] The body of the trace to validate
19
- def initialize(body)
20
- @body = body
23
+ # @param request [Hash] The trace request to validate
24
+ def initialize(request)
25
+ @headers = request[:request].header
26
+ @body = request[:body]
21
27
  @success = nil
22
28
  @errors = []
23
29
  end
@@ -26,8 +32,9 @@ module Maze
26
32
  def validate
27
33
  @success = true
28
34
 
29
- regex_comparison('resourceSpans.0.scopeSpans.0.spans.0.spanId', '^[A-Fa-f0-9]{16}$')
30
- regex_comparison('resourceSpans.0.scopeSpans.0.spans.0.traceId', '^[A-Fa-f0-9]{32}$')
35
+ validate_headers
36
+ regex_comparison('resourceSpans.0.scopeSpans.0.spans.0.spanId', HEX_STRING_16)
37
+ regex_comparison('resourceSpans.0.scopeSpans.0.spans.0.traceId', HEX_STRING_32)
31
38
  element_int_in_range('resourceSpans.0.scopeSpans.0.spans.0.kind', 0..5)
32
39
  regex_comparison('resourceSpans.0.scopeSpans.0.spans.0.startTimeUnixNano', '^[0-9]+$')
33
40
  regex_comparison('resourceSpans.0.scopeSpans.0.spans.0.endTimeUnixNano', '^[0-9]+$')
@@ -40,6 +47,49 @@ module Maze
40
47
  )
41
48
  end
42
49
 
50
+ def validate_header(name)
51
+ value = @headers[name]
52
+ if value.nil? || value.size > 1
53
+ @errors << "Expected exactly one value for header #{name}, received #{value || 'nil'}"
54
+ else
55
+ yield value[0]
56
+ end
57
+ end
58
+
59
+ # Checks that the required headers are present and correct
60
+ def validate_headers
61
+ # API key
62
+ validate_header('bugsnag-api-key') do |api_key|
63
+ expected = Regexp.new(HEX_STRING_32)
64
+ unless expected.match(api_key)
65
+ @success = false
66
+ @errors << "bugsnag-api-key header was expected to match the regex '#{HEX_STRING_32}', but was '#{api_key}'"
67
+ end
68
+ end
69
+
70
+ # Bugsnag-Sent-at
71
+ validate_header('bugsnag-sent-at') do |date|
72
+ begin
73
+ Date.iso8601(date)
74
+ rescue Date::Error
75
+ @success = false
76
+ @errors << "bugsnag-sent-at header was expected to be an IOS 8601 date, but was '#{date}'"
77
+ end
78
+ end
79
+
80
+ # Bugsnag-Span-Sampling
81
+ # of the format x:y where x is a decimal between 0 and 1 (inclusive) and y is the number of spans in the batch (if possible at this stage - we could weaken this if necessary)
82
+ validate_header('bugsnag-span-sampling') do |sampling|
83
+ begin
84
+ expected = Regexp.new(SAMPLING_HEADER)
85
+ unless expected.match(sampling)
86
+ @success = false
87
+ @errors << "bugsnag-span-sampling header was expected to match the regex '#{SAMPLING_HEADER}', but was '#{sampling}'"
88
+ end
89
+ end
90
+ end
91
+ end
92
+
43
93
  def regex_comparison(path, regex)
44
94
  element_value = Maze::Helper.read_key_path(@body, path)
45
95
  expected = Regexp.new(regex)
@@ -49,7 +49,7 @@ module Maze
49
49
 
50
50
  if validator_class
51
51
  validators = list.all.map do |request|
52
- validator = validator_class.new(request[:body])
52
+ validator = validator_class.new(request)
53
53
  validator.validate
54
54
  validator
55
55
  end
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 = '8.2.0'
10
+ VERSION = '8.3.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: 8.2.0
4
+ version: 8.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Kirkland
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-07-19 00:00:00.000000000 Z
11
+ date: 2023-08-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cucumber
@@ -347,6 +347,7 @@ files:
347
347
  - lib/features/steps/breadcrumb_steps.rb
348
348
  - lib/features/steps/browser_steps.rb
349
349
  - lib/features/steps/build_api_steps.rb
350
+ - lib/features/steps/deprecated_steps.rb
350
351
  - lib/features/steps/document_server_steps.rb
351
352
  - lib/features/steps/error_reporting_steps.rb
352
353
  - lib/features/steps/feature_flag_steps.rb
@@ -446,11 +447,11 @@ files:
446
447
  - lib/maze/wait.rb
447
448
  - lib/utils/deep_merge.rb
448
449
  - lib/utils/selenium_money_patch.rb
449
- homepage:
450
+ homepage:
450
451
  licenses:
451
452
  - MIT
452
453
  metadata: {}
453
- post_install_message:
454
+ post_install_message:
454
455
  rdoc_options: []
455
456
  require_paths:
456
457
  - lib
@@ -466,7 +467,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
466
467
  version: '0'
467
468
  requirements: []
468
469
  rubygems_version: 3.1.6
469
- signing_key:
470
+ signing_key:
470
471
  specification_version: 4
471
472
  summary: Bugsnag API request validation harness
472
473
  test_files: []