bugsnag-maze-runner 7.29.0 → 7.30.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a557d4bf1f5d2518fef4116fe4bceecc5b28f78d585ab0926296105e5284ff49
4
- data.tar.gz: 6e2c3eed0f98e66d586c64186a77917bb93aa4dbb7f2e0704ab42fa4abb05eb6
3
+ metadata.gz: 50ddc2b8a7d69a3c11f06e1f9984de46bc4fd607178f240fb76c0d47b03e7725
4
+ data.tar.gz: 682fee5deb9bc66d86380ee5017a8ccd0b4f1b0f9809d6a9e36efa9e73510b83
5
5
  SHA512:
6
- metadata.gz: 194edc4175cb7e7d9c2816d749e2b97a56b97885511762345d2ecdce4c07be4bf2a9de82415f26c127f20b8a1fc5fa0256e84ffcedff74eaf5ad4d017c006f19
7
- data.tar.gz: c2a7a1998c8c2fa628165f1961483e0986942be71ad599e72aad19351984a27c6284007037f7779834fd16e43f3905f8b316d2a1742546c90234f999bd734f1e
6
+ metadata.gz: 9a2b800801966259fa5453d00340645e7afeee1626808ffe4b670c2d64e28614f0d5a69093a38dcb70e123e02150034ce768c4368557e11a57d17f119e3ed306
7
+ data.tar.gz: fd5c15d2cede7d05040b0347d5816543eacaf3c1ca5430a33ccd26d2bb7c71e5bdedcb184b9cdc5113133e7a3ca1f23542aabb4325267f0dc4201b0d11463871
data/bin/maze-runner CHANGED
@@ -42,7 +42,9 @@ require_relative '../lib/maze/metrics_processor'
42
42
  require_relative '../lib/maze/network'
43
43
  require_relative '../lib/maze/proxy'
44
44
  require_relative '../lib/maze/retry_handler'
45
- require_relative '../lib/maze/request_repeater'
45
+ require_relative '../lib/maze/repeaters/request_repeater'
46
+ require_relative '../lib/maze/repeaters/aspecto_repeater'
47
+ require_relative '../lib/maze/repeaters/bugsnag_repeater'
46
48
  require_relative '../lib/maze/runner'
47
49
  require_relative '../lib/maze/terminating_server'
48
50
 
@@ -9,24 +9,25 @@ module Maze
9
9
  class BitBarDevices
10
10
  class << self
11
11
  # Uses the BitBar API to find an available device from the group name given, or a device of that name
12
- # @param device_or_group_name [String] Name of the device, or device group for which to find an available device
12
+ # @param device_or_group_names [String] Name of the device, or device group(s) for which to find an available
13
+ # device. Multiple device group names can be separated by a pipe.
13
14
  # @return Capabilities hash for the available device
14
- def get_available_device(device_or_group_name)
15
+ def get_available_device(device_or_group_names)
15
16
  api_client = BitBarApiClient.new(Maze.config.access_key)
16
- device_group_id = api_client.get_device_group_id(device_or_group_name)
17
- if device_group_id
17
+ device_group_ids = api_client.get_device_group_ids(device_or_group_names)
18
+ if device_group_ids
18
19
  # Device group found - find a free device in it
19
- $logger.debug "Got group id #{device_group_id} for #{device_or_group_name}"
20
- group_count, device = api_client.find_device_in_group(device_group_id)
20
+ $logger.debug "Got group ids #{device_group_ids} for #{device_or_group_names}"
21
+ group_count, device = api_client.find_device_in_groups(device_group_ids)
21
22
  if device.nil?
22
23
  # TODO: Retry rather than fail, see PLAT-7377
23
24
  Maze::Helper.error_exit 'There are no devices available'
24
25
  else
25
- $logger.info "#{group_count} device(s) currently available in group '#{device_or_group_name}'"
26
+ $logger.info "#{group_count} device(s) currently available in group(s) '#{device_or_group_names}'"
26
27
  end
27
28
  else
28
29
  # See if there is a device with the given name
29
- device = api_client.find_device device_or_group_name
30
+ device = api_client.find_device device_or_group_names
30
31
  end
31
32
 
32
33
  device_name = device['displayName']
@@ -20,30 +20,38 @@ module Maze
20
20
  query_api(path)
21
21
  end
22
22
 
23
- # Get the id of a device group given its name
24
- def get_device_group_id(device_group_name)
23
+ # Get the id(s) of a one or more device groups given their names. Multiple device group names should be separated
24
+ # by a pipe (which is directly supported by the BitBar API)
25
+ def get_device_group_ids(device_group_names)
25
26
  query = {
26
- 'filter': "displayName_eq_#{device_group_name}"
27
+ 'filter': "displayName_in_#{device_group_names}"
27
28
  }
28
29
  device_groups = query_api('device-groups', query)
29
30
  if device_groups['data'].nil? || device_groups['data'].size == 0
30
31
  nil
31
32
  else
32
- device_groups['data'][0]['id']
33
+ device_groups['data'].map { |group| group['id'] }
33
34
  end
34
35
  end
35
36
 
36
- def find_device_in_group(device_group_id)
37
- path = "device-groups/#{device_group_id}/devices"
38
- query = {
39
- 'filter': "online_eq_true"
40
- }
41
- all_devices = query_api(path, query)
37
+ def find_device_in_groups(device_group_ids)
38
+ all_devices = []
39
+ device_group_ids.each do |group_id|
40
+ path = "device-groups/#{group_id}/devices"
41
+ query = {
42
+ 'filter': "online_eq_true"
43
+ }
44
+ all_devices += query_api(path, query)['data']
45
+ end
46
+
47
+ $logger.debug "All available devices in group(s) #{device_group_ids}: #{JSON.pretty_generate(all_devices)}"
48
+ filtered_devices = all_devices.reject { |device| device['locked'] }
42
49
 
43
- $logger.debug "All available devices in group #{device_group_id}: #{JSON.pretty_generate(all_devices)}"
44
- Maze::Plugins::DatadogMetricsPlugin.send_gauge('bitbar.device.available', all_devices['data'].size, [Maze.config.device])
45
- filtered_devices = all_devices['data'].reject { |device| device['locked'] }
46
- Maze::Plugins::DatadogMetricsPlugin.send_gauge('bitbar.device.unlocked', filtered_devices.size, [Maze.config.device])
50
+ # Only send gauges to DataDog for single device groups
51
+ if device_group_ids.size == 1
52
+ Maze::Plugins::DatadogMetricsPlugin.send_gauge('bitbar.device.available', all_devices.size, [Maze.config.device])
53
+ Maze::Plugins::DatadogMetricsPlugin.send_gauge('bitbar.device.unlocked', filtered_devices.size, [Maze.config.device])
54
+ end
47
55
  return filtered_devices.size, filtered_devices.sample
48
56
  end
49
57
 
@@ -61,8 +61,11 @@ module Maze
61
61
  # The server endpoints for which invalid requests should be captured and cause tests to fail
62
62
  attr_accessor :captured_invalid_requests
63
63
 
64
- # API key to use when repeating requests
65
- attr_accessor :repeater_api_key
64
+ # API key to use when repeating requests to Bugsnag
65
+ attr_accessor :aspecto_repeater_api_key
66
+
67
+ # API key to use when repeating requests to Bugsnag
68
+ attr_accessor :bugsnag_repeater_api_key
66
69
 
67
70
  # Enables awareness of a public IP address on Buildkite with the Elastic CI Stack for AWS.
68
71
  attr_accessor :aws_public_ip
@@ -41,7 +41,11 @@ module Maze
41
41
  type: :boolean,
42
42
  default: true
43
43
 
44
- opt Option::REPEATER_API_KEY,
44
+ opt Option::ASPECTO_REPEATER_API_KEY,
45
+ 'Enables forwarding of all received POST requests to Aspecto, using the API key provided. MAZE_ASPECTO_REPEATER_API_KEY may also be set.',
46
+ type: :string
47
+
48
+ opt Option::BUGSNAG_REPEATER_API_KEY,
45
49
  'Enables forwarding of all received POST requests to Bugsnag, using the API key provided. MAZE_REPEATER_API_KEY may also be set.',
46
50
  type: :string
47
51
 
@@ -232,7 +236,8 @@ module Maze
232
236
  options[Option::SELENIUM_SERVER] ||= ENV['MAZE_SELENIUM_SERVER'] || 'https://us-west-desktop-hub.bitbar.com/wd/hub'
233
237
  end
234
238
 
235
- options[Option::REPEATER_API_KEY] ||= ENV['MAZE_REPEATER_API_KEY']
239
+ options[Option::ASPECTO_REPEATER_API_KEY] ||= ENV['MAZE_ASPECTO_REPEATER_API_KEY']
240
+ options[Option::BUGSNAG_REPEATER_API_KEY] ||= ENV['MAZE_REPEATER_API_KEY']
236
241
  options[Option::SB_LOCAL] ||= ENV['MAZE_SB_LOCAL'] || '/SBSecureTunnel'
237
242
  options[Option::TMS_URI] ||= ENV['MAZE_TMS_URI']
238
243
  options[Option::TMS_TOKEN] ||= ENV['MAZE_TMS_TOKEN']
@@ -23,7 +23,8 @@ module Maze
23
23
  config.enable_bugsnag = options[Maze::Option::ENABLE_BUGSNAG]
24
24
  config.tms_uri = options[Maze::Option::TMS_URI]
25
25
  config.tms_token = options[Maze::Option::TMS_TOKEN]
26
- config.repeater_api_key = options[Maze::Option::REPEATER_API_KEY]
26
+ config.aspecto_repeater_api_key = options[Maze::Option::ASPECTO_REPEATER_API_KEY]
27
+ config.bugsnag_repeater_api_key = options[Maze::Option::BUGSNAG_REPEATER_API_KEY]
27
28
 
28
29
  # Document server options
29
30
  config.document_server_root = options[Maze::Option::DS_ROOT]
@@ -30,10 +30,10 @@ module Maze
30
30
  end
31
31
 
32
32
  # --repeater-api-key
33
- key = options[Option::REPEATER_API_KEY]
33
+ key = options[Option::BUGSNAG_REPEATER_API_KEY]
34
34
  key_regex = /^[0-9a-fA-F]{32}$/
35
35
  if key && !key_regex.match?(key)
36
- errors << "--#{Option::REPEATER_API_KEY} must be set to a 32-character hex value"
36
+ errors << "--#{Option::BUGSNAG_REPEATER_API_KEY} must be set to a 32-character hex value"
37
37
  end
38
38
 
39
39
  # Farm specific options
data/lib/maze/option.rb CHANGED
@@ -56,7 +56,8 @@ module Maze
56
56
 
57
57
  # General options
58
58
  AWS_PUBLIC_IP = 'aws-public-ip'
59
- REPEATER_API_KEY = 'repeater-api-key'
59
+ ASPECTO_REPEATER_API_KEY = 'aspecto-repeater-api-key'
60
+ BUGSNAG_REPEATER_API_KEY = 'repeater-api-key'
60
61
  ENABLE_BUGSNAG = 'enable-bugsnag'
61
62
  ENABLE_RETRIES = 'enable-retries'
62
63
  end
@@ -0,0 +1,34 @@
1
+ module Maze
2
+ module Repeaters
3
+ # Repeats Bugsnag requests
4
+ class AspectoRepeater < RequestRepeater
5
+
6
+ private
7
+
8
+ def set_headers(request)
9
+ request['Authorization'] = Maze.config.aspecto_repeater_api_key
10
+ end
11
+
12
+ def enabled?
13
+ # enabled if the config option is on and this request type should be repeated
14
+ Maze.config.aspecto_repeater_api_key && url_for_request_type
15
+ end
16
+
17
+ def gzip_supported
18
+ false
19
+ end
20
+
21
+ def url_for_request_type
22
+ url = case @request_type
23
+ when :traces then 'https://otelcol.aspecto.io:4318/v1/traces'
24
+ else return nil
25
+ end
26
+ URI.parse(url)
27
+ end
28
+
29
+ def include_header?(key, _value)
30
+ true unless key.start_with? 'bugsnag'
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,35 @@
1
+ module Maze
2
+ module Repeaters
3
+ # Repeats Bugsnag requests
4
+ class BugsnagRepeater < RequestRepeater
5
+
6
+ private
7
+
8
+ def set_headers(request)
9
+ # TODO Also overwrite apiKey in the payload, if present, recalculate the integrity header (handling
10
+ # compressed payloads if the content-encoding header is set accordingly)
11
+ request['bugsnag-api-key'] = Maze.config.bugsnag_repeater_api_key
12
+ end
13
+
14
+ def enabled?
15
+ # enabled if the config option is on and this request type should be repeated
16
+ Maze.config.bugsnag_repeater_api_key && url_for_request_type
17
+ end
18
+
19
+ def url_for_request_type
20
+ url = case @request_type
21
+ when :errors then 'https://notify.bugsnag.com/'
22
+ when :sessions then 'https://sessions.bugsnag.com/'
23
+ when :traces then 'https://otlp.bugsnag.com/v1/traces'
24
+ else return nil
25
+ end
26
+ URI.parse(url)
27
+ end
28
+
29
+ def include_header?(key, value)
30
+ # Include all headers apart from the API key, which is set separately
31
+ key != 'bugsnag-api-key'
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,87 @@
1
+ module Maze
2
+ module Repeaters
3
+ # Repeats POST requests
4
+ class RequestRepeater
5
+
6
+ def initialize(request_type)
7
+ @request_type = request_type
8
+ end
9
+
10
+ # @param request [HTTPRequest] The request to be repeated
11
+ def repeat(request)
12
+
13
+ return unless enabled?
14
+
15
+ # TODO Forwarding of internal errors to be considered later
16
+ return if request.header.keys.any? { |key| key.downcase == 'bugsnag-internal-error' }
17
+
18
+ uri = url_for_request_type
19
+
20
+ Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |https|
21
+ onward_request = Net::HTTP::Post.new(uri.path)
22
+ onward_request.body = decompress(request)
23
+
24
+ # Set all headers that are present, unless Gzip is not supported
25
+ request.header.each do |key,value|
26
+ # Only include content-type header if gip is supported
27
+ next if !gzip_supported && key.downcase == 'content-encoding'
28
+
29
+ # All other headers are opt-in to avoid accidental leakage
30
+ next unless include_header? key.downcase, value
31
+
32
+ onward_request[key] = value
33
+ end
34
+
35
+ # Set headers specific to the repeater
36
+ set_headers onward_request
37
+
38
+ response = https.request(onward_request)
39
+ log_response response
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def gzip_supported
46
+ true
47
+ end
48
+
49
+ def decompress(request)
50
+ if !gzip_supported && %r{^gzip$}.match(request['Content-Encoding'])
51
+
52
+ reader = Zlib::GzipReader.new(StringIO.new(request.body))
53
+ reader.read
54
+ else
55
+ request.body
56
+ end
57
+ end
58
+
59
+ def enabled?
60
+ raise 'Method not implemented by this class'
61
+ end
62
+
63
+ def url_for_request_type
64
+ raise 'Method not implemented by this class'
65
+ end
66
+
67
+ def include_header?(_key, _value)
68
+ raise 'Method not implemented by this class'
69
+ end
70
+
71
+ def log_response(response)
72
+ log "HEADERS:"
73
+ response.header.each_header do |key, value|
74
+ log " #{key}: #{value}"
75
+ end
76
+
77
+ log
78
+ log "BODY:"
79
+ log response.body
80
+ end
81
+
82
+ def log(message = '')
83
+ $logger.debug message
84
+ end
85
+ end
86
+ end
87
+ end
@@ -28,7 +28,6 @@ module Maze
28
28
 
29
29
  # Receives and parses the requests and payloads sent from the test fixture
30
30
  class Servlet < BaseServlet
31
- prepend RequestRepeater
32
31
 
33
32
  # Constructor
34
33
  #
@@ -40,6 +39,8 @@ module Maze
40
39
  @request_type = request_type
41
40
  @requests = Server.list_for request_type
42
41
  @schema = JSONSchemer.schema(schema) unless schema.nil?
42
+ @aspecto_repeater = Maze::Repeaters::AspectoRepeater.new(@request_type)
43
+ @bugsnag_repeater = Maze::Repeaters::BugsnagRepeater.new(@request_type)
43
44
  end
44
45
 
45
46
  # Logs an incoming GET WEBrick request.
@@ -57,6 +58,10 @@ module Maze
57
58
  # @param request [HTTPRequest] The incoming GET request
58
59
  # @param response [HTTPResponse] The response to return
59
60
  def do_POST(request, response)
61
+
62
+ @aspecto_repeater.repeat request
63
+ @bugsnag_repeater.repeat request
64
+
60
65
  # Turn the WEBrick HttpRequest into our internal HttpRequest delegate
61
66
  request = HttpRequest.new(request)
62
67
 
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 = '7.29.0'
10
+ VERSION = '7.30.1'
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: 7.29.0
4
+ version: 7.30.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Kirkland
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-05-09 00:00:00.000000000 Z
11
+ date: 2023-05-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cucumber
@@ -420,8 +420,10 @@ files:
420
420
  - lib/maze/plugins/error_code_plugin.rb
421
421
  - lib/maze/plugins/global_retry_plugin.rb
422
422
  - lib/maze/proxy.rb
423
+ - lib/maze/repeaters/aspecto_repeater.rb
424
+ - lib/maze/repeaters/bugsnag_repeater.rb
425
+ - lib/maze/repeaters/request_repeater.rb
423
426
  - lib/maze/request_list.rb
424
- - lib/maze/request_repeater.rb
425
427
  - lib/maze/retry_handler.rb
426
428
  - lib/maze/runner.rb
427
429
  - lib/maze/schemas/OtelTraceSchema.json
@@ -1,49 +0,0 @@
1
- module Maze
2
- # Repeats POST requests
3
- module RequestRepeater
4
-
5
- def do_POST(request, response)
6
- repeat(request) if enabled?
7
-
8
- super(request, response)
9
- end
10
-
11
- private
12
-
13
- def enabled?
14
- # enabled if the config option is on and this request type should be repeated
15
- Maze.config.repeater_api_key && url_for_request_type
16
- end
17
-
18
- # @param request [HTTPRequest] The request to be repeated
19
- def repeat(request)
20
-
21
- # TODO Forwarding of internal errors to be considered later
22
- return if request.header.keys.any? { |key| key.downcase == 'bugsnag-internal-error' }
23
-
24
- url = url_for_request_type
25
- http = Net::HTTP.new(url.host)
26
- bugsnag_request = Net::HTTP::Post.new(url.path)
27
-
28
- # Set all headers that are present
29
- bugsnag_request.body = request.body
30
- request.header.each {|key,value| bugsnag_request[key] = value }
31
- bugsnag_request['bugsnag-api-key'] = Maze.config.repeater_api_key
32
-
33
- # TODO Also overwrite apiKey in the payload, if present, recalculate the integrity header (handling
34
- # compressed payloads if the content-encoding header is set accordingly)
35
-
36
- http.request(bugsnag_request)
37
- end
38
-
39
- def url_for_request_type
40
- url = case @request_type
41
- when :errors then 'https://notify.bugsnag.com/'
42
- when :sessions then 'https://sessions.bugsnag.com/'
43
- when :traces then 'https://otlp.bugsnag.com/v1/traces'
44
- else return nil
45
- end
46
- URI.parse(url)
47
- end
48
- end
49
- end