Skip to content

Commit 1974172

Browse files
solnicclaude
andcommitted
test(test_helper): add Rack two-request leak regression spec (#2951)
Drives two consecutive requests through the real Sentry::Rack::CaptureExceptions middleware (which calls clone_hub_to_current_thread) wrapped in setup_sentry_test/ teardown_sentry_test, asserting the first request's event does not leak into the second and that each request's event stays observable via sentry_events. Fails against pre-fix code (second request sees 2 events); passes with the #2951 fix. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 67be7e1 commit 1974172

1 file changed

Lines changed: 42 additions & 8 deletions

File tree

sentry-ruby/spec/sentry/test_helper_spec.rb

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -94,23 +94,17 @@
9494

9595
describe "event leakage across clone_hub_to_current_thread (regression for #2951)" do
9696
it "keeps sentry_events empty after setup_sentry_test even when an earlier request captured events through a cloned hub" do
97-
# Cycle 1: a normal test that uses the test helper.
9897
setup_sentry_test
9998
Sentry.capture_message("event from a previous test")
10099
teardown_sentry_test
101100

102-
# Simulate an unrelated request that runs *without* the test helper:
103-
# Sentry::Rack::CaptureExceptions clones the main hub onto the request
104-
# thread, then an event is captured through that cloned hub.
105101
Sentry.clone_hub_to_current_thread
106102
Sentry.capture_message("event from an unrelated request")
107103

108-
# Cycle 2: the next test sets the helper up again.
109104
setup_sentry_test
110105

111106
expect(sentry_events).to be_empty
112107

113-
# The Rack middleware clones the hub again for *this* test's request.
114108
Sentry.clone_hub_to_current_thread
115109

116110
expect(sentry_events).to be_empty
@@ -125,15 +119,55 @@
125119
it "still exposes events captured through a hub the Rack middleware cloned after setup_sentry_test" do
126120
setup_sentry_test
127121

128-
# Sentry::Rack::CaptureExceptions clones the main hub onto the request
129-
# thread before the request body runs.
130122
Sentry.clone_hub_to_current_thread
131123
Sentry.capture_message("event from the request")
132124

133125
expect(sentry_events.map(&:message)).to include("event from the request")
134126
end
135127
end
136128

129+
describe "Sentry::Rack::CaptureExceptions across consecutive requests (regression for #2951)", when: :rack_available? do
130+
# Drives a single request through the real Rack middleware. The middleware
131+
# calls Sentry.clone_hub_to_current_thread before handing off to the app,
132+
# exactly like a Rails request spec would.
133+
def perform_request(exception_message)
134+
exception = RuntimeError.new(exception_message)
135+
app = lambda do |env|
136+
env["rack.exception"] = exception
137+
[200, {}, ["ok"]]
138+
end
139+
stack = Sentry::Rack::CaptureExceptions.new(app)
140+
stack.call(Rack::MockRequest.env_for("/#{exception_message}"))
141+
end
142+
143+
def captured_exception_messages
144+
sentry_events.map { |event| event.to_h.dig(:exception, :values, 0, :value) }
145+
end
146+
147+
it "isolates each request's events and keeps them observable via sentry_events" do
148+
# First request, wrapped in the test helper just like a request spec.
149+
setup_sentry_test
150+
perform_request("first-request")
151+
messages = captured_exception_messages
152+
expect(messages.size).to eq(1)
153+
expect(messages.first).to include("first-request")
154+
teardown_sentry_test
155+
156+
# Second request: a fresh setup must not see the first request's event,
157+
# even though the Rack middleware clones the main hub on every request.
158+
setup_sentry_test
159+
expect(sentry_events).to be_empty
160+
161+
perform_request("second-request")
162+
messages = captured_exception_messages
163+
expect(messages.size).to eq(1)
164+
expect(messages.first).to include("second-request")
165+
expect(messages).not_to include(a_string_including("first-request"))
166+
167+
teardown_sentry_test
168+
end
169+
end
170+
137171
describe "#teardown_sentry_test" do
138172
before do
139173
setup_sentry_test

0 commit comments

Comments
 (0)