Skip to content

Commit 68ac728

Browse files
committed
tests(rails): add integration tests for Sequel/Rails tracing
1 parent cad74d8 commit 68ac728

File tree

4 files changed

+253
-0
lines changed

4 files changed

+253
-0
lines changed

sentry-rails/Gemfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,5 @@ gem "benchmark-ips"
6262
gem "benchmark_driver"
6363
gem "benchmark-ipsa"
6464
gem "benchmark-memory"
65+
66+
gem "sequel"
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# frozen_string_literal: true
2+
3+
require "sequel"
4+
require "sentry/sequel"
5+
6+
class SequelUsersController < ActionController::Base
7+
def index
8+
users = SEQUEL_DB[:users].all
9+
render json: users
10+
end
11+
12+
def create
13+
id = SEQUEL_DB[:users].insert(name: params[:name], email: params[:email])
14+
render json: { id: id, name: params[:name], email: params[:email] }, status: :created
15+
end
16+
17+
def show
18+
user = SEQUEL_DB[:users].where(id: params[:id]).first
19+
if user
20+
render json: user
21+
else
22+
render json: { error: "Not found" }, status: :not_found
23+
end
24+
end
25+
26+
def update
27+
SEQUEL_DB[:users].where(id: params[:id]).update(name: params[:name])
28+
user = SEQUEL_DB[:users].where(id: params[:id]).first
29+
render json: user
30+
end
31+
32+
def destroy
33+
SEQUEL_DB[:users].where(id: params[:id]).delete
34+
head :no_content
35+
end
36+
37+
def exception
38+
SEQUEL_DB[:users].all
39+
raise "Something went wrong!"
40+
end
41+
end

sentry-rails/spec/dummy/test_rails_app/config/application.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,16 @@ def configure
122122
end
123123
end
124124

125+
# Sequel-specific routes for testing Sequel tracing
126+
scope "/sequel" do
127+
get "/users", to: "sequel_users#index"
128+
post "/users", to: "sequel_users#create"
129+
get "/users/:id", to: "sequel_users#show"
130+
put "/users/:id", to: "sequel_users#update"
131+
delete "/users/:id", to: "sequel_users#destroy"
132+
get "/exception", to: "sequel_users#exception"
133+
end
134+
125135
get "500", to: "hello#reporting"
126136

127137
root to: "hello#world"
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
# frozen_string_literal: true
2+
3+
begin
4+
require "simplecov"
5+
SimpleCov.command_name "SequelTracing"
6+
rescue LoadError
7+
end
8+
9+
require "sequel"
10+
require "sentry/sequel"
11+
12+
require_relative "../dummy/test_rails_app/app/controllers/sequel_users_controller"
13+
14+
RSpec.describe "Sequel Tracing with Rails", type: :request do
15+
before(:all) do
16+
if RUBY_ENGINE == "jruby"
17+
SEQUEL_DB = Sequel.connect("jdbc:sqlite::memory:")
18+
else
19+
SEQUEL_DB = Sequel.sqlite
20+
end
21+
22+
SEQUEL_DB.create_table :users do
23+
primary_key :id
24+
String :name
25+
String :email
26+
end
27+
28+
SEQUEL_DB[:users].count
29+
SEQUEL_DB.extension(:sentry)
30+
end
31+
32+
after(:all) do
33+
SEQUEL_DB.drop_table?(:users)
34+
Object.send(:remove_const, :SEQUEL_DB)
35+
end
36+
37+
before do
38+
make_basic_app do |config, app|
39+
config.traces_sample_rate = 1.0
40+
config.enabled_patches << :sequel
41+
end
42+
end
43+
44+
let(:transport) { Sentry.get_current_client.transport }
45+
46+
describe "SELECT queries" do
47+
it "creates a transaction with Sequel span for index action" do
48+
get "/sequel/users"
49+
50+
expect(response).to have_http_status(:ok)
51+
expect(transport.events.count).to eq(1)
52+
53+
transaction = transport.events.last.to_h
54+
55+
expect(transaction[:type]).to eq("transaction")
56+
expect(transaction.dig(:contexts, :trace, :op)).to eq("http.server")
57+
58+
sequel_span = transaction[:spans].find { |span| span[:op] == "db.sql.sequel" }
59+
60+
expect(sequel_span).not_to be_nil
61+
expect(sequel_span[:description]).to include("SELECT")
62+
expect(sequel_span[:description]).to include("users")
63+
expect(sequel_span[:origin]).to eq("auto.db.sequel")
64+
expect(sequel_span[:data]["db.system"]).to eq("sqlite")
65+
end
66+
end
67+
68+
describe "INSERT queries" do
69+
it "creates a transaction with Sequel span for create action" do
70+
post "/sequel/users", params: { name: "John Doe", email: "[email protected]" }
71+
72+
expect(response).to have_http_status(:created)
73+
74+
transaction = transport.events.last.to_h
75+
expect(transaction[:type]).to eq("transaction")
76+
77+
insert_span = transaction[:spans].find do |span|
78+
span[:op] == "db.sql.sequel" && span[:description]&.include?("INSERT")
79+
end
80+
81+
expect(insert_span).not_to be_nil
82+
expect(insert_span[:description]).to include("INSERT")
83+
expect(insert_span[:description]).to include("users")
84+
expect(insert_span[:origin]).to eq("auto.db.sequel")
85+
end
86+
end
87+
88+
describe "UPDATE queries" do
89+
it "creates a transaction with Sequel span for update action" do
90+
SEQUEL_DB[:users].insert(name: "Jane Doe", email: "[email protected]")
91+
92+
put "/sequel/users/1", params: { name: "Jane Smith" }
93+
94+
expect(response).to have_http_status(:ok)
95+
96+
transaction = transport.events.last.to_h
97+
98+
update_span = transaction[:spans].find do |span|
99+
span[:op] == "db.sql.sequel" && span[:description]&.include?("UPDATE")
100+
end
101+
102+
expect(update_span).not_to be_nil
103+
expect(update_span[:description]).to include("UPDATE")
104+
expect(update_span[:description]).to include("users")
105+
end
106+
end
107+
108+
describe "DELETE queries" do
109+
it "creates a transaction with Sequel span for delete action" do
110+
SEQUEL_DB[:users].insert(name: "Delete Me", email: "[email protected]")
111+
112+
delete "/sequel/users/1"
113+
114+
expect(response).to have_http_status(:no_content)
115+
116+
transaction = transport.events.last.to_h
117+
118+
delete_span = transaction[:spans].find do |span|
119+
span[:op] == "db.sql.sequel" && span[:description]&.include?("DELETE")
120+
end
121+
122+
expect(delete_span).not_to be_nil
123+
expect(delete_span[:description]).to include("DELETE")
124+
expect(delete_span[:description]).to include("users")
125+
end
126+
end
127+
128+
describe "exception handling" do
129+
it "creates both error event and transaction with Sequel span" do
130+
get "/sequel/exception"
131+
132+
expect(response).to have_http_status(:internal_server_error)
133+
134+
expect(transport.events.count).to eq(2)
135+
136+
error_event = transport.events.first.to_h
137+
transaction = transport.events.last.to_h
138+
139+
expect(error_event[:exception][:values].first[:type]).to eq("RuntimeError")
140+
expect(error_event[:exception][:values].first[:value]).to include("Something went wrong!")
141+
142+
sequel_span = transaction[:spans].find { |span| span[:op] == "db.sql.sequel" }
143+
expect(sequel_span).not_to be_nil
144+
expect(sequel_span[:description]).to include("SELECT")
145+
146+
expect(error_event.dig(:contexts, :trace, :trace_id)).to eq(
147+
transaction.dig(:contexts, :trace, :trace_id)
148+
)
149+
end
150+
end
151+
152+
describe "span timing" do
153+
it "records proper start and end timestamps" do
154+
get "/sequel/users"
155+
156+
transaction = transport.events.last.to_h
157+
sequel_span = transaction[:spans].find { |span| span[:op] == "db.sql.sequel" }
158+
159+
expect(sequel_span[:start_timestamp]).not_to be_nil
160+
expect(sequel_span[:timestamp]).not_to be_nil
161+
expect(sequel_span[:start_timestamp]).to be < sequel_span[:timestamp]
162+
end
163+
end
164+
165+
describe "Sequel and ActiveRecord coexistence" do
166+
it "records spans for both database systems in the same application" do
167+
Post.create!(title: "Test Post")
168+
169+
SEQUEL_DB[:users].insert(name: "Sequel User", email: "[email protected]")
170+
171+
transport.events.clear
172+
173+
get "/sequel/users"
174+
175+
expect(response).to have_http_status(:ok)
176+
177+
transaction = transport.events.last.to_h
178+
sequel_spans = transaction[:spans].select { |span| span[:op] == "db.sql.sequel" }
179+
180+
expect(sequel_spans.length).to be >= 1
181+
expect(sequel_spans.first[:data]["db.system"]).to eq("sqlite")
182+
end
183+
184+
it "records ActiveRecord spans separately from Sequel spans" do
185+
transport.events.clear
186+
187+
get "/posts"
188+
189+
expect(response).to have_http_status(:internal_server_error) # raises "foo" in PostsController#index
190+
191+
transaction = transport.events.last.to_h
192+
193+
ar_spans = transaction[:spans].select { |span| span[:op] == "db.sql.active_record" }
194+
sequel_spans = transaction[:spans].select { |span| span[:op] == "db.sql.sequel" }
195+
196+
expect(ar_spans.length).to be >= 1
197+
expect(sequel_spans.length).to eq(0)
198+
end
199+
end
200+
end

0 commit comments

Comments
 (0)