|
| 1 | +# frozen_string_literal: true |
| 2 | + |
| 3 | +require "spec_helper" |
| 4 | + |
| 5 | +RSpec.describe Sentry::Rails::CaptureContext do |
| 6 | + # Records the current scope's trace_id every time it's called, so specs can |
| 7 | + # compare what a piece of middleware would see at different points in the stack. |
| 8 | + class CaptureContextSpecProbe |
| 9 | + def self.captured_trace_ids |
| 10 | + @captured_trace_ids ||= [] |
| 11 | + end |
| 12 | + |
| 13 | + def initialize(app) |
| 14 | + @app = app |
| 15 | + end |
| 16 | + |
| 17 | + def call(env) |
| 18 | + self.class.captured_trace_ids << Sentry.get_current_scope.get_trace_context[:trace_id] |
| 19 | + @app.call(env) |
| 20 | + end |
| 21 | + end |
| 22 | + |
| 23 | + describe "#call" do |
| 24 | + before do |
| 25 | + make_basic_app |
| 26 | + end |
| 27 | + |
| 28 | + it "establishes a propagation context and flags the env" do |
| 29 | + trace_id_in_app = nil |
| 30 | + |
| 31 | + app = lambda do |env| |
| 32 | + trace_id_in_app = Sentry.get_current_scope.get_trace_context[:trace_id] |
| 33 | + [200, {}, ["ok"]] |
| 34 | + end |
| 35 | + |
| 36 | + env = Rack::MockRequest.env_for("/test") |
| 37 | + described_class.new(app).call(env) |
| 38 | + |
| 39 | + expect(env[Sentry::PropagationContext::ESTABLISHED_ENV_KEY]).to eq(true) |
| 40 | + expect(trace_id_in_app).to be_a(String) |
| 41 | + end |
| 42 | + |
| 43 | + it "is a no-op when Sentry is not initialized" do |
| 44 | + allow(Sentry).to receive(:initialized?).and_return(false) |
| 45 | + |
| 46 | + called = false |
| 47 | + app = lambda do |env| |
| 48 | + called = true |
| 49 | + [200, {}, ["ok"]] |
| 50 | + end |
| 51 | + |
| 52 | + env = Rack::MockRequest.env_for("/test") |
| 53 | + described_class.new(app).call(env) |
| 54 | + |
| 55 | + expect(called).to eq(true) |
| 56 | + expect(env[Sentry::PropagationContext::ESTABLISHED_ENV_KEY]).to be_nil |
| 57 | + end |
| 58 | + end |
| 59 | + |
| 60 | + context "when composed with CaptureExceptions", type: :request do |
| 61 | + before do |
| 62 | + CaptureContextSpecProbe.captured_trace_ids.clear |
| 63 | + end |
| 64 | + |
| 65 | + context "without tracing enabled" do |
| 66 | + before do |
| 67 | + make_basic_app do |config, app| |
| 68 | + app.config.middleware.insert_before(Sentry::Rails::CaptureExceptions, CaptureContextSpecProbe) |
| 69 | + app.config.middleware.insert_after(Sentry::Rails::CaptureExceptions, CaptureContextSpecProbe) |
| 70 | + end |
| 71 | + end |
| 72 | + |
| 73 | + it "keeps the same trace_id before and after CaptureExceptions runs" do |
| 74 | + get "/world" |
| 75 | + |
| 76 | + early_trace_id, late_trace_id = CaptureContextSpecProbe.captured_trace_ids |
| 77 | + |
| 78 | + expect(early_trace_id).to be_a(String) |
| 79 | + expect(late_trace_id).to eq(early_trace_id) |
| 80 | + end |
| 81 | + end |
| 82 | + |
| 83 | + context "with tracing enabled" do |
| 84 | + before do |
| 85 | + make_basic_app do |config, app| |
| 86 | + config.traces_sample_rate = 1.0 |
| 87 | + app.config.middleware.insert_before(Sentry::Rails::CaptureExceptions, CaptureContextSpecProbe) |
| 88 | + app.config.middleware.insert_after(Sentry::Rails::CaptureExceptions, CaptureContextSpecProbe) |
| 89 | + end |
| 90 | + end |
| 91 | + |
| 92 | + it "keeps the same trace_id from before CaptureExceptions through the started transaction" do |
| 93 | + get "/world" |
| 94 | + |
| 95 | + early_trace_id, late_trace_id = CaptureContextSpecProbe.captured_trace_ids |
| 96 | + |
| 97 | + expect(early_trace_id).to be_a(String) |
| 98 | + # the "late" trace_id comes from the actual transaction CaptureExceptions started |
| 99 | + expect(late_trace_id).to eq(early_trace_id) |
| 100 | + end |
| 101 | + end |
| 102 | + end |
| 103 | +end |
0 commit comments