-
-
Notifications
You must be signed in to change notification settings - Fork 479
/
session_flusher_spec.rb
203 lines (168 loc) · 5.55 KB
/
session_flusher_spec.rb
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
require "spec_helper"
RSpec.describe Sentry::SessionFlusher do
let(:string_io) { StringIO.new }
let(:configuration) do
Sentry::Configuration.new.tap do |config|
config.dsn = Sentry::TestHelper::DUMMY_DSN
config.release = 'test-release'
config.environment = 'test'
config.transport.transport_class = Sentry::DummyTransport
config.background_worker_threads = 0
config.logger = Logger.new(string_io)
end
end
let(:client) { Sentry::Client.new(configuration) }
let(:transport) { client.transport }
subject { described_class.new(configuration, client) }
before do
Sentry.background_worker = Sentry::BackgroundWorker.new(configuration)
end
describe "#initialize" do
context "when config.release is nil" do
before { configuration.release = nil }
it "logs debug message" do
flusher = described_class.new(configuration, client)
expect(string_io.string).to match(
/Sessions won't be captured without a valid release/
)
end
end
end
describe "#flush" do
it "early returns with no pending_aggregates" do
expect(subject.instance_variable_get(:@pending_aggregates)).to eq({})
expect do
subject.flush
end.not_to change { transport.envelopes.count }
end
context "with pending aggregates" do
let(:now) do
time = Time.now.utc
Time.utc(time.year, time.month, time.day, time.hour, time.min)
end
let(:handled_event) do
exception = Exception.new('test')
mech = Sentry::Mechanism.new(type: 'custom', handled: true)
client.event_from_exception(exception, {}, mech)
end
let(:unhandled_event) do
exception = Exception.new('test')
mech = Sentry::Mechanism.new(type: 'custom', handled: false)
client.event_from_exception(exception, {}, mech)
end
before do
Timecop.freeze(now) do
10.times do
session = Sentry::Session.new
session.close
subject.add_session(session)
end
5.times do
session = Sentry::Session.new
session.update_from_error_event(handled_event)
session.close
subject.add_session(session)
end
2.times do
session = Sentry::Session.new
session.update_from_error_event(unhandled_event)
session.close
subject.add_session(session)
end
end
end
it "captures pending_aggregates in background worker" do
expect do
subject.flush
end.to change { transport.envelopes.count }.by(1)
envelope = transport.envelopes.first
expect(envelope.items.length).to eq(1)
item = envelope.items.first
expect(item.type).to eq('sessions')
expect(item.payload[:attrs]).to eq({ release: 'test-release', environment: 'test' })
expect(item.payload[:aggregates].first).to eq({
started: now.iso8601,
exited: 10,
errored: 5,
crashed: 2
})
end
end
end
describe "#add_session" do
let(:session) do
session = Sentry::Session.new
session.close
session
end
context "when config.release is nil" do
before { configuration.release = nil }
it "noops" do
flusher = described_class.new(configuration, client)
flusher.add_session(session)
expect(flusher.instance_variable_get(:@pending_aggregates)).to eq({})
end
end
it "spawns new thread" do
expect do
subject.add_session(session)
end.to change { Thread.list.count }.by(1)
expect(subject.instance_variable_get(:@thread)).to be_a(Thread)
end
it "spawns only one thread" do
expect do
subject.add_session(session)
end.to change { Thread.list.count }.by(1)
thread = subject.instance_variable_get(:@thread)
expect(thread).to receive(:alive?).and_return(true)
expect do
subject.add_session(session)
end.to change { Thread.list.count }.by(0)
end
it "adds session to pending_aggregates" do
subject.add_session(session)
pending_aggregates = subject.instance_variable_get(:@pending_aggregates)
expect(pending_aggregates.keys.first).to be_a(Time)
expect(pending_aggregates.values.first).to include({ errored: 0, crashed: 0, exited: 1 })
end
context "when thread creation fails" do
before do
expect(Thread).to receive(:new).and_raise(ThreadError)
end
it "doesn't create new thread" do
expect do
subject.add_session(session)
end.to change { Thread.list.count }.by(0)
end
it "noops" do
subject.add_session(session)
expect(subject.instance_variable_get(:@pending_aggregates)).to eq({})
end
it "logs error" do
subject.add_session(session)
expect(string_io.string).to match(/Session flusher thread creation failed/)
end
end
context "when killed" do
before do
subject.kill
end
it "noops" do
subject.add_session(session)
expect(subject.instance_variable_get(:@pending_aggregates)).to eq({})
end
it "doesn't create new thread" do
expect(Thread).not_to receive(:new)
expect do
subject.add_session(session)
end.to change { Thread.list.count }.by(0)
end
end
end
describe "#kill" do
it "logs message when killing the thread" do
subject.kill
expect(string_io.string).to match(/Killing session flusher/)
end
end
end