1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
|
# frozen_string_literal: true
module Sentry
module TestHelper
module_function
DUMMY_DSN = "http://12345:67890@sentry.localdomain/sentry/42"
# Not really real, but it will be resolved as a non-local for testing needs
REAL_DSN = "https://user:pass@getsentry.io/project/42"
# Alters the existing SDK configuration with test-suitable options. Mainly:
# - Sets a dummy DSN instead of `nil` or an actual DSN.
# - Sets the transport to DummyTransport, which allows easy access to the captured events.
# - Disables background worker.
# - Makes sure the SDK is enabled under the current environment ("test" in most cases).
#
# It should be called **before** every test case.
#
# @yieldparam config [Configuration]
# @return [void]
def setup_sentry_test(&block)
raise "please make sure the SDK is initialized for testing" unless Sentry.initialized?
dummy_config = Sentry.configuration.dup
# configure dummy DSN, so the events will not be sent to the actual service
dummy_config.dsn = DUMMY_DSN
# set transport to DummyTransport, so we can easily intercept the captured events
dummy_config.transport.transport_class = Sentry::DummyTransport
# make sure SDK allows sending under the current environment
dummy_config.enabled_environments += [dummy_config.environment] unless dummy_config.enabled_environments.include?(dummy_config.environment)
# disble async event sending
dummy_config.background_worker_threads = 0
# user can overwrite some of the configs, with a few exceptions like:
# - include_local_variables
# - auto_session_tracking
block&.call(dummy_config)
# the base layer's client should already use the dummy config so nothing will be sent by accident
base_client = Sentry::Client.new(dummy_config)
Sentry.get_current_hub.bind_client(base_client)
# create a new layer so mutations made to the testing scope or configuration could be simply popped later
Sentry.get_current_hub.push_scope
test_client = Sentry::Client.new(dummy_config.dup)
Sentry.get_current_hub.bind_client(test_client)
end
# Clears all stored events and envelopes.
# It should be called **after** every test case.
# @return [void]
def teardown_sentry_test
return unless Sentry.initialized?
clear_sentry_events
# pop testing layer created by `setup_sentry_test`
# but keep the base layer to avoid nil-pointer errors
# TODO: find a way to notify users if they somehow popped the test layer before calling this method
if Sentry.get_current_hub.instance_variable_get(:@stack).size > 1
Sentry.get_current_hub.pop_scope
end
Sentry::Scope.global_event_processors.clear
end
def clear_sentry_events
return unless Sentry.initialized?
sentry_transport.clear if sentry_transport.respond_to?(:clear)
if Sentry.configuration.enable_logs && sentry_logger.respond_to?(:clear)
sentry_logger.clear
end
end
# @return [Sentry::StructuredLogger, Sentry::DebugStructuredLogger]
def sentry_logger
Sentry.logger
end
# @return [Transport]
def sentry_transport
Sentry.get_current_client.transport
end
# Returns the captured event objects.
# @return [Array<Event>]
def sentry_events
sentry_transport.events
end
# Returns the captured envelope objects.
# @return [Array<Envelope>]
def sentry_envelopes
sentry_transport.envelopes
end
def sentry_logs
sentry_envelopes
.flat_map(&:items)
.select { |item| item.headers[:type] == "log" }
.flat_map { |item| item.payload[:items] }
end
# Returns the last captured event object.
# @return [Event, nil]
def last_sentry_event
sentry_events.last
end
# Extracts SDK's internal exception container (not actual exception objects) from an given event.
# @return [Array<Sentry::SingleExceptionInterface>]
def extract_sentry_exceptions(event)
event&.exception&.values || []
end
def reset_sentry_globals!
Sentry::MUTEX.synchronize do
# Don't check initialized? because sometimes we stub it in tests
if Sentry.instance_variable_defined?(:@main_hub)
Sentry::GLOBALS.each do |var|
Sentry.instance_variable_set(:"@#{var}", nil)
end
Thread.current.thread_variable_set(Sentry::THREAD_LOCAL, nil)
end
end
end
end
end
|