Module: Sentry::TestHelper
- Defined in:
- lib/sentry/test_helper.rb
Constant Summary collapse
- DUMMY_DSN =
"http://12345:67890@sentry.localdomain/sentry/42"- REAL_DSN =
Not really real, but it will be resolved as a non-local for testing needs
"https://user:pass@getsentry.io/project/42"
Class Method Summary collapse
- .clear_sentry_events ⇒ Object
-
.extract_sentry_exceptions(event) ⇒ Array<Sentry::SingleExceptionInterface>
Extracts SDK’s internal exception container (not actual exception objects) from an given event.
-
.last_sentry_event ⇒ Event?
Returns the last captured event object.
- .reset_sentry_globals! ⇒ Object
-
.sentry_envelopes ⇒ Array<Envelope>
Returns the captured envelope objects.
-
.sentry_events ⇒ Array<Event>
Returns the captured event objects.
- .sentry_logger ⇒ Sentry::StructuredLogger, Sentry::DebugStructuredLogger
- .sentry_logs ⇒ Object
- .sentry_metrics ⇒ Object
-
.sentry_test_transports ⇒ Array<Transport>
Every transport reachable from the current thread’s hub and the main hub, across all stack layers.
- .sentry_transport ⇒ Transport
-
.setup_sentry_test {|config| ... } ⇒ void
Alters the existing SDK configuration with test-suitable options.
-
.teardown_sentry_test ⇒ void
Clears all stored events and envelopes.
Class Method Details
.clear_sentry_events ⇒ Object
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/sentry/test_helper.rb', line 82 def clear_sentry_events return unless Sentry.initialized? # Clear every transport reachable from the current thread's hub and the # main hub (including its base layer). A request-time clone shares the # main hub's base-layer transport, so clearing only the current # transport would let stale events survive into the next test. sentry_test_transports.each do |transport| transport.clear if transport.respond_to?(:clear) end if Sentry.configuration.enable_logs && sentry_logger.respond_to?(:clear) sentry_logger.clear end end |
.extract_sentry_exceptions(event) ⇒ Array<Sentry::SingleExceptionInterface>
Extracts SDK’s internal exception container (not actual exception objects) from an given event.
153 154 155 |
# File 'lib/sentry/test_helper.rb', line 153 def extract_sentry_exceptions(event) event&.exception&.values || [] end |
.last_sentry_event ⇒ Event?
Returns the last captured event object.
147 148 149 |
# File 'lib/sentry/test_helper.rb', line 147 def last_sentry_event sentry_events.last end |
.reset_sentry_globals! ⇒ Object
157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/sentry/test_helper.rb', line 157 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 |
.sentry_envelopes ⇒ Array<Envelope>
Returns the captured envelope objects.
127 128 129 |
# File 'lib/sentry/test_helper.rb', line 127 def sentry_envelopes sentry_transport.envelopes end |
.sentry_events ⇒ Array<Event>
Returns the captured event objects.
121 122 123 |
# File 'lib/sentry/test_helper.rb', line 121 def sentry_events sentry_transport.events end |
.sentry_logger ⇒ Sentry::StructuredLogger, Sentry::DebugStructuredLogger
99 100 101 |
# File 'lib/sentry/test_helper.rb', line 99 def sentry_logger Sentry.logger end |
.sentry_logs ⇒ Object
131 132 133 134 135 136 |
# File 'lib/sentry/test_helper.rb', line 131 def sentry_logs sentry_envelopes .flat_map(&:items) .select { |item| item.headers[:type] == "log" } .flat_map { |item| item.payload[:items] } end |
.sentry_metrics ⇒ Object
138 139 140 141 142 143 |
# File 'lib/sentry/test_helper.rb', line 138 def sentry_metrics sentry_envelopes .flat_map(&:items) .select { |item| item.headers[:type] == "trace_metric" } .flat_map { |item| item.payload[:items] } end |
.sentry_test_transports ⇒ Array<Transport>
Every transport reachable from the current thread’s hub and the main hub, across all stack layers. Used by ‘clear_sentry_events` so a stale DummyTransport (e.g. the main hub’s base layer that a request-time clone shares) cannot carry leftover events into the next test.
113 114 115 116 117 |
# File 'lib/sentry/test_helper.rb', line 113 def sentry_test_transports [Sentry.get_current_hub, Sentry.get_main_hub].compact.uniq.flat_map do |hub| hub.clients.map(&:transport) end.compact.uniq end |
.sentry_transport ⇒ Transport
104 105 106 |
# File 'lib/sentry/test_helper.rb', line 104 def sentry_transport Sentry.get_current_client.transport end |
.setup_sentry_test {|config| ... } ⇒ void
This method returns an undefined value.
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.
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 |
# File 'lib/sentry/test_helper.rb', line 22 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.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) # Install the testing clients on the *main* hub rather than the current # thread's hub. `Sentry.clone_hub_to_current_thread` (used by # Sentry::Rack::CaptureExceptions) always clones the main hub, so if we # only mutated the thread-local hub a request-time clone would observe a # stale transport. main_hub = Sentry.get_main_hub # 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) main_hub.bind_client(base_client) # create a new layer so mutations made to the testing scope or configuration could be simply popped later main_hub.push_scope test_client = Sentry::Client.new(dummy_config.dup) main_hub.bind_client(test_client) # Realign the current thread's hub with the main hub so direct # `sentry_events` reads and any hub the Rack middleware clones from the # main hub all observe the same DummyTransport. Thread.current.thread_variable_set(Sentry::THREAD_LOCAL, main_hub) end |
.teardown_sentry_test ⇒ void
This method returns an undefined value.
Clears all stored events and envelopes. It should be called after every test case.
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/sentry/test_helper.rb', line 64 def teardown_sentry_test return unless Sentry.initialized? clear_sentry_events # pop the testing layer created by `setup_sentry_test` off the *main* # hub (that is where `setup_sentry_test` pushed it), keeping the base # layer to avoid nil-pointer errors. Popping the current thread's hub # would leave the test layer dangling on the main hub, which the next # request-time clone would inherit. # TODO: find a way to notify users if they somehow popped the test layer before calling this method main_hub = Sentry.get_main_hub if main_hub.instance_variable_get(:@stack).size > 1 main_hub.pop_scope end Sentry::Scope.global_event_processors.clear end |