airbrake-ruby 6.1.0-java → 6.2.0-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/airbrake-ruby/async_sender.rb +11 -15
- data/lib/airbrake-ruby/backlog.rb +123 -0
- data/lib/airbrake-ruby/config.rb +7 -0
- data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +1 -1
- data/lib/airbrake-ruby/nested_exception.rb +22 -1
- data/lib/airbrake-ruby/notice.rb +5 -3
- data/lib/airbrake-ruby/notice_notifier.rb +1 -0
- data/lib/airbrake-ruby/performance_notifier.rb +1 -0
- data/lib/airbrake-ruby/response.rb +56 -5
- data/lib/airbrake-ruby/sync_sender.rb +41 -10
- data/lib/airbrake-ruby/version.rb +1 -1
- data/lib/airbrake-ruby.rb +2 -1
- metadata +5 -122
- data/spec/airbrake_spec.rb +0 -522
- data/spec/async_sender_spec.rb +0 -65
- data/spec/backtrace_spec.rb +0 -430
- data/spec/benchmark_spec.rb +0 -35
- data/spec/code_hunk_spec.rb +0 -124
- data/spec/config/processor_spec.rb +0 -167
- data/spec/config/validator_spec.rb +0 -204
- data/spec/config_spec.rb +0 -188
- data/spec/context_spec.rb +0 -54
- data/spec/deploy_notifier_spec.rb +0 -50
- data/spec/file_cache_spec.rb +0 -35
- data/spec/filter_chain_spec.rb +0 -124
- data/spec/filters/context_filter_spec.rb +0 -32
- data/spec/filters/dependency_filter_spec.rb +0 -14
- data/spec/filters/exception_attributes_filter_spec.rb +0 -52
- data/spec/filters/gem_root_filter_spec.rb +0 -44
- data/spec/filters/git_last_checkout_filter_spec.rb +0 -61
- data/spec/filters/git_repository_filter_spec.rb +0 -72
- data/spec/filters/git_revision_filter_spec.rb +0 -126
- data/spec/filters/keys_allowlist_spec.rb +0 -204
- data/spec/filters/keys_blocklist_spec.rb +0 -242
- data/spec/filters/root_directory_filter_spec.rb +0 -39
- data/spec/filters/sql_filter_spec.rb +0 -274
- data/spec/filters/system_exit_filter_spec.rb +0 -16
- data/spec/filters/thread_filter_spec.rb +0 -281
- data/spec/fixtures/notroot.txt +0 -7
- data/spec/fixtures/project_root/code.rb +0 -221
- data/spec/fixtures/project_root/empty_file.rb +0 -0
- data/spec/fixtures/project_root/long_line.txt +0 -1
- data/spec/fixtures/project_root/short_file.rb +0 -3
- data/spec/fixtures/project_root/vendor/bundle/ignored_file.rb +0 -5
- data/spec/helpers.rb +0 -9
- data/spec/ignorable_spec.rb +0 -14
- data/spec/inspectable_spec.rb +0 -45
- data/spec/loggable_spec.rb +0 -17
- data/spec/monotonic_time_spec.rb +0 -25
- data/spec/nested_exception_spec.rb +0 -73
- data/spec/notice_notifier/options_spec.rb +0 -269
- data/spec/notice_notifier_spec.rb +0 -361
- data/spec/notice_spec.rb +0 -300
- data/spec/performance_breakdown_spec.rb +0 -11
- data/spec/performance_notifier_spec.rb +0 -645
- data/spec/promise_spec.rb +0 -203
- data/spec/query_spec.rb +0 -11
- data/spec/queue_spec.rb +0 -18
- data/spec/remote_settings/callback_spec.rb +0 -162
- data/spec/remote_settings/settings_data_spec.rb +0 -348
- data/spec/remote_settings_spec.rb +0 -201
- data/spec/request_spec.rb +0 -9
- data/spec/response_spec.rb +0 -110
- data/spec/spec_helper.rb +0 -100
- data/spec/stashable_spec.rb +0 -23
- data/spec/stat_spec.rb +0 -39
- data/spec/sync_sender_spec.rb +0 -168
- data/spec/tdigest_spec.rb +0 -235
- data/spec/thread_pool_spec.rb +0 -196
- data/spec/time_truncate_spec.rb +0 -30
- data/spec/timed_trace_spec.rb +0 -127
- data/spec/truncator_spec.rb +0 -267
data/spec/thread_pool_spec.rb
DELETED
@@ -1,196 +0,0 @@
|
|
1
|
-
RSpec.describe Airbrake::ThreadPool do
|
2
|
-
subject(:thread_pool) do
|
3
|
-
described_class.new(
|
4
|
-
worker_size: worker_size,
|
5
|
-
queue_size: queue_size,
|
6
|
-
block: proc { |message| tasks << message },
|
7
|
-
)
|
8
|
-
end
|
9
|
-
|
10
|
-
let(:tasks) { [] }
|
11
|
-
let(:worker_size) { 1 }
|
12
|
-
let(:queue_size) { 2 }
|
13
|
-
|
14
|
-
describe "#<<" do
|
15
|
-
it "returns true" do
|
16
|
-
retval = thread_pool << 1
|
17
|
-
thread_pool.close
|
18
|
-
expect(retval).to be(true)
|
19
|
-
end
|
20
|
-
|
21
|
-
it "performs work in background" do
|
22
|
-
thread_pool << 2
|
23
|
-
thread_pool << 1
|
24
|
-
thread_pool.close
|
25
|
-
|
26
|
-
expect(tasks).to eq([2, 1])
|
27
|
-
end
|
28
|
-
|
29
|
-
context "when the queue is full" do
|
30
|
-
subject(:full_thread_pool) do
|
31
|
-
described_class.new(
|
32
|
-
worker_size: 1,
|
33
|
-
queue_size: 1,
|
34
|
-
block: proc { |message| tasks << message },
|
35
|
-
)
|
36
|
-
end
|
37
|
-
|
38
|
-
before do
|
39
|
-
# rubocop:disable RSpec/SubjectStub
|
40
|
-
allow(full_thread_pool).to receive(:backlog).and_return(queue_size)
|
41
|
-
# rubocop:enable RSpec/SubjectStub
|
42
|
-
end
|
43
|
-
|
44
|
-
it "returns false" do
|
45
|
-
retval = full_thread_pool << 1
|
46
|
-
full_thread_pool.close
|
47
|
-
expect(retval).to be(false)
|
48
|
-
end
|
49
|
-
|
50
|
-
it "discards tasks" do
|
51
|
-
200.times { full_thread_pool << 1 }
|
52
|
-
full_thread_pool.close
|
53
|
-
|
54
|
-
expect(tasks.size).to be_zero
|
55
|
-
end
|
56
|
-
|
57
|
-
it "logs discarded tasks" do
|
58
|
-
allow(Airbrake::Loggable.instance).to receive(:info)
|
59
|
-
|
60
|
-
15.times { full_thread_pool << 1 }
|
61
|
-
full_thread_pool.close
|
62
|
-
|
63
|
-
expect(Airbrake::Loggable.instance)
|
64
|
-
.to have_received(:info).exactly(15).times
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
describe "#backlog" do
|
70
|
-
let(:worker_size) { 0 }
|
71
|
-
|
72
|
-
it "returns the size of the queue" do
|
73
|
-
thread_pool << 1
|
74
|
-
expect(thread_pool.backlog).to eq(1)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
describe "#has_workers?" do
|
79
|
-
it "returns false when the thread pool is not closed, but has 0 workers" do
|
80
|
-
thread_pool.workers.list.each do |worker|
|
81
|
-
worker.kill.join
|
82
|
-
end
|
83
|
-
expect(thread_pool).not_to have_workers
|
84
|
-
end
|
85
|
-
|
86
|
-
it "returns false when the thread pool is closed" do
|
87
|
-
thread_pool.close
|
88
|
-
expect(thread_pool).not_to have_workers
|
89
|
-
end
|
90
|
-
|
91
|
-
describe "forking behavior" do
|
92
|
-
before do
|
93
|
-
skip('fork() is unsupported on JRuby') if %w[jruby].include?(RUBY_ENGINE)
|
94
|
-
unless Process.respond_to?(:last_status)
|
95
|
-
skip('Process.last_status is unsupported on this Ruby')
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
# rubocop:disable RSpec/MultipleExpectations
|
100
|
-
it "respawns workers on fork()" do
|
101
|
-
pid = fork { expect(thread_pool).to have_workers }
|
102
|
-
Process.wait(pid)
|
103
|
-
thread_pool.close
|
104
|
-
|
105
|
-
expect(Process.last_status).to be_success
|
106
|
-
expect(thread_pool).not_to have_workers
|
107
|
-
end
|
108
|
-
# rubocop:enable RSpec/MultipleExpectations
|
109
|
-
|
110
|
-
it "ensures that a new thread group is created per process" do
|
111
|
-
thread_pool << 1
|
112
|
-
pid = fork { thread_pool.has_workers? }
|
113
|
-
Process.wait(pid)
|
114
|
-
thread_pool.close
|
115
|
-
|
116
|
-
expect(Process.last_status).to be_success
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
describe "#close" do
|
122
|
-
context "when there's no work to do" do
|
123
|
-
it "joins the spawned thread" do
|
124
|
-
workers = thread_pool.workers.list
|
125
|
-
expect(workers).to all(be_alive)
|
126
|
-
|
127
|
-
thread_pool.close
|
128
|
-
expect(workers).to all(be_stop)
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
context "when there's some work to do" do
|
133
|
-
it "logs how many tasks are left to process" do
|
134
|
-
allow(Airbrake::Loggable.instance).to receive(:debug)
|
135
|
-
|
136
|
-
thread_pool = described_class.new(
|
137
|
-
name: 'foo', worker_size: 0, queue_size: 2, block: proc {},
|
138
|
-
)
|
139
|
-
|
140
|
-
2.times { thread_pool << 1 }
|
141
|
-
thread_pool.close
|
142
|
-
|
143
|
-
expect(Airbrake::Loggable.instance).to have_received(:debug).with(
|
144
|
-
/waiting to process \d+ task\(s\)/,
|
145
|
-
)
|
146
|
-
expect(Airbrake::Loggable.instance).to have_received(:debug).with(/foo.+closed/)
|
147
|
-
end
|
148
|
-
|
149
|
-
it "waits until the queue gets empty" do
|
150
|
-
thread_pool = described_class.new(
|
151
|
-
worker_size: 1, queue_size: 2, block: proc {},
|
152
|
-
)
|
153
|
-
|
154
|
-
10.times { thread_pool << 1 }
|
155
|
-
thread_pool.close
|
156
|
-
expect(thread_pool.backlog).to be_zero
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
context "when it was already closed" do
|
161
|
-
it "doesn't increase the queue size" do
|
162
|
-
begin
|
163
|
-
thread_pool.close
|
164
|
-
rescue Airbrake::Error
|
165
|
-
nil
|
166
|
-
end
|
167
|
-
|
168
|
-
expect(thread_pool.backlog).to be_zero
|
169
|
-
end
|
170
|
-
|
171
|
-
it "raises error" do
|
172
|
-
thread_pool.close
|
173
|
-
expect { thread_pool.close }.to raise_error(
|
174
|
-
Airbrake::Error, 'this thread pool is closed already'
|
175
|
-
)
|
176
|
-
end
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
describe "#spawn_workers" do
|
181
|
-
after { thread_pool.close }
|
182
|
-
|
183
|
-
it "spawns an enclosed thread group" do
|
184
|
-
expect(thread_pool.workers).to be_a(ThreadGroup)
|
185
|
-
expect(thread_pool.workers).to be_enclosed
|
186
|
-
end
|
187
|
-
|
188
|
-
it "spawns threads that are alive" do
|
189
|
-
expect(thread_pool.workers.list).to all(be_alive)
|
190
|
-
end
|
191
|
-
|
192
|
-
it "spawns exactly `workers_size` workers" do
|
193
|
-
expect(thread_pool.workers.list.size).to eq(worker_size)
|
194
|
-
end
|
195
|
-
end
|
196
|
-
end
|
data/spec/time_truncate_spec.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
RSpec.describe Airbrake::TimeTruncate do
|
2
|
-
time = Time.new(2018, 1, 1, 0, 0, 20, 0)
|
3
|
-
time_with_zone = Time.new(2018, 1, 1, 0, 0, 20, '-05:00')
|
4
|
-
|
5
|
-
describe "#utc_truncate_minutes" do
|
6
|
-
shared_examples 'time conversion' do |t|
|
7
|
-
it "truncates the time to the floor minute and returns an RFC3339 timestamp" do
|
8
|
-
expect(described_class.utc_truncate_minutes(t))
|
9
|
-
.to eq('2018-01-01T00:00:00+00:00')
|
10
|
-
end
|
11
|
-
|
12
|
-
it "converts time with zone to UTC" do
|
13
|
-
expect(described_class.utc_truncate_minutes(time_with_zone))
|
14
|
-
.to eq('2018-01-01T05:00:00+00:00')
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
context "when the time argument is a Time object" do
|
19
|
-
include_examples 'time conversion', time
|
20
|
-
end
|
21
|
-
|
22
|
-
context "when the time argument is a Float" do
|
23
|
-
include_examples 'time conversion', time.to_f
|
24
|
-
end
|
25
|
-
|
26
|
-
context "when the time argument is an Integer" do
|
27
|
-
include_examples 'time conversion', time.to_i
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
data/spec/timed_trace_spec.rb
DELETED
@@ -1,127 +0,0 @@
|
|
1
|
-
RSpec.describe Airbrake::TimedTrace do
|
2
|
-
subject(:timed_trace) { described_class.new }
|
3
|
-
|
4
|
-
describe ".span" do
|
5
|
-
it "returns a timed trace" do
|
6
|
-
expect(described_class.span('operation') { anything }).to be_a(described_class)
|
7
|
-
end
|
8
|
-
|
9
|
-
it "returns a timed trace with a stopped span" do
|
10
|
-
timed_trace = described_class.span('operation') { anything }
|
11
|
-
expect(timed_trace.spans).to match('operation' => be > 0)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
describe "#span" do
|
16
|
-
it "captures a span" do
|
17
|
-
timed_trace.span('operation') { anything }
|
18
|
-
expect(timed_trace.spans).to match('operation' => be > 0)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
describe "#start_span" do
|
23
|
-
context "when called once" do
|
24
|
-
it "returns true" do
|
25
|
-
expect(timed_trace.start_span('operation')).to be(true)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
context "when called multiple times" do
|
30
|
-
before { timed_trace.start_span('operation') }
|
31
|
-
|
32
|
-
it "returns false" do
|
33
|
-
expect(timed_trace.start_span('operation')).to be(false)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
context "when another span was started" do
|
38
|
-
before { timed_trace.start_span('operation') }
|
39
|
-
|
40
|
-
it "returns true" do
|
41
|
-
expect(timed_trace.start_span('another operation')).to be(true)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
context "when #spans was called" do
|
46
|
-
before { timed_trace.start_span('operation') }
|
47
|
-
|
48
|
-
it "returns spans with zero values" do
|
49
|
-
expect(timed_trace.spans).to eq('operation' => 0.0)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
describe "#stop_span" do
|
55
|
-
context "when #start_span wasn't invoked" do
|
56
|
-
it "returns false" do
|
57
|
-
expect(timed_trace.stop_span('operation')).to be(false)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
context "when #start_span was invoked" do
|
62
|
-
before { timed_trace.start_span('operation') }
|
63
|
-
|
64
|
-
it "returns true" do
|
65
|
-
expect(timed_trace.stop_span('operation')).to be(true)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
context "when multiple spans were started" do
|
70
|
-
before do
|
71
|
-
timed_trace.start_span('operation')
|
72
|
-
timed_trace.start_span('another operation')
|
73
|
-
end
|
74
|
-
|
75
|
-
context "and when stopping in LIFO order" do
|
76
|
-
it "returns true for all spans" do
|
77
|
-
expect(timed_trace.stop_span('another operation')).to be(true)
|
78
|
-
expect(timed_trace.stop_span('operation')).to be(true)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
context "and when stopping in FIFO order" do
|
83
|
-
it "returns true for all spans" do
|
84
|
-
expect(timed_trace.stop_span('operation')).to be(true)
|
85
|
-
expect(timed_trace.stop_span('another operation')).to be(true)
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
describe "#spans" do
|
92
|
-
context "when no spans were captured" do
|
93
|
-
it "returns an empty hash" do
|
94
|
-
expect(timed_trace.spans).to eq({})
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
context "when a span was captured" do
|
99
|
-
before do
|
100
|
-
timed_trace.start_span('operation')
|
101
|
-
timed_trace.stop_span('operation')
|
102
|
-
end
|
103
|
-
|
104
|
-
it "returns a Hash with the corresponding span" do
|
105
|
-
timed_trace.stop_span('operation')
|
106
|
-
expect(timed_trace.spans).to match('operation' => be > 0)
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
context "when multiple spans were captured" do
|
111
|
-
before do
|
112
|
-
timed_trace.start_span('operation')
|
113
|
-
timed_trace.stop_span('operation')
|
114
|
-
|
115
|
-
timed_trace.start_span('another operation')
|
116
|
-
timed_trace.stop_span('another operation')
|
117
|
-
end
|
118
|
-
|
119
|
-
it "returns a Hash with all spans" do
|
120
|
-
expect(timed_trace.spans).to match(
|
121
|
-
'operation' => be > 0,
|
122
|
-
'another operation' => be > 0,
|
123
|
-
)
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
data/spec/truncator_spec.rb
DELETED
@@ -1,267 +0,0 @@
|
|
1
|
-
RSpec.describe Airbrake::Truncator do
|
2
|
-
def multiply_by_2_max_len(chr)
|
3
|
-
chr * 2 * max_len
|
4
|
-
end
|
5
|
-
|
6
|
-
describe "#truncate" do
|
7
|
-
subject(:truncator) { described_class.new(max_size).truncate(object) }
|
8
|
-
|
9
|
-
let(:max_size) { 3 }
|
10
|
-
let(:truncated) { '[Truncated]' }
|
11
|
-
let(:max_len) { max_size + truncated.length }
|
12
|
-
|
13
|
-
context "given a frozen string" do
|
14
|
-
let(:object) { multiply_by_2_max_len('a') }
|
15
|
-
|
16
|
-
it "returns a new truncated frozen string" do
|
17
|
-
expect(truncator.length).to eq(max_len)
|
18
|
-
expect(truncator).to be_frozen
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
context "given a frozen hash of strings" do
|
23
|
-
let(:object) do
|
24
|
-
{
|
25
|
-
banana: multiply_by_2_max_len('a'),
|
26
|
-
kiwi: multiply_by_2_max_len('b'),
|
27
|
-
strawberry: 'c',
|
28
|
-
shrimp: 'd',
|
29
|
-
}.freeze
|
30
|
-
end
|
31
|
-
|
32
|
-
it "returns a hash of the same size" do
|
33
|
-
expect(truncator.size).to eq(max_size)
|
34
|
-
end
|
35
|
-
|
36
|
-
it "returns a frozen hash" do
|
37
|
-
expect(truncator).to be_frozen
|
38
|
-
end
|
39
|
-
|
40
|
-
it "returns a hash with truncated values" do
|
41
|
-
expect(truncator).to eq(
|
42
|
-
banana: 'aaa[Truncated]', kiwi: 'bbb[Truncated]', strawberry: 'c',
|
43
|
-
)
|
44
|
-
end
|
45
|
-
|
46
|
-
it "returns a hash with truncated strings that are frozen" do
|
47
|
-
expect(truncator[:banana]).to be_frozen
|
48
|
-
expect(truncator[:kiwi]).to be_frozen
|
49
|
-
end
|
50
|
-
|
51
|
-
it "returns a hash unfrozen untruncated strings" do
|
52
|
-
expect(truncator[:strawberry]).not_to be_frozen
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
context "given a frozen array of strings" do
|
57
|
-
let(:object) do
|
58
|
-
[
|
59
|
-
multiply_by_2_max_len('a'),
|
60
|
-
'b',
|
61
|
-
multiply_by_2_max_len('c'),
|
62
|
-
'd',
|
63
|
-
].freeze
|
64
|
-
end
|
65
|
-
|
66
|
-
it "returns an array of the same size" do
|
67
|
-
expect(truncator.size).to eq(max_size)
|
68
|
-
end
|
69
|
-
|
70
|
-
it "returns a frozen array" do
|
71
|
-
expect(truncator).to be_frozen
|
72
|
-
end
|
73
|
-
|
74
|
-
it "returns an array with truncated values" do
|
75
|
-
expect(truncator).to eq(['aaa[Truncated]', 'b', 'ccc[Truncated]'])
|
76
|
-
end
|
77
|
-
|
78
|
-
it "returns an array with truncated strings that are frozen" do
|
79
|
-
expect(truncator[0]).to be_frozen
|
80
|
-
expect(truncator[2]).to be_frozen
|
81
|
-
end
|
82
|
-
|
83
|
-
it "returns an array with unfrozen untruncated strings" do
|
84
|
-
expect(truncator[1]).not_to be_frozen
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
context "given a frozen set of strings" do
|
89
|
-
let(:object) do
|
90
|
-
Set.new([
|
91
|
-
multiply_by_2_max_len('a'),
|
92
|
-
'b',
|
93
|
-
multiply_by_2_max_len('c'),
|
94
|
-
'd',
|
95
|
-
]).freeze
|
96
|
-
end
|
97
|
-
|
98
|
-
it "returns a set of the same size" do
|
99
|
-
expect(truncator.size).to eq(max_size)
|
100
|
-
end
|
101
|
-
|
102
|
-
it "returns a frozen set" do
|
103
|
-
expect(truncator).to be_frozen
|
104
|
-
end
|
105
|
-
|
106
|
-
it "returns a set with truncated values" do
|
107
|
-
expect(truncator).to eq(Set.new(['aaa[Truncated]', 'b', 'ccc[Truncated]']))
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
context "given an arbitrary frozen object that responds to #to_json" do
|
112
|
-
let(:object) do
|
113
|
-
obj = Object.new
|
114
|
-
def obj.to_json
|
115
|
-
'{"object":"shrimp"}'
|
116
|
-
end
|
117
|
-
obj.freeze
|
118
|
-
end
|
119
|
-
|
120
|
-
it "returns a string of a max len size" do
|
121
|
-
expect(truncator.length).to eq(max_len)
|
122
|
-
end
|
123
|
-
|
124
|
-
it "returns a frozen object" do
|
125
|
-
expect(truncator).to be_frozen
|
126
|
-
end
|
127
|
-
|
128
|
-
it "converts the object to truncated JSON" do
|
129
|
-
expect(truncator).to eq('{"o[Truncated]')
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
context "given an arbitrary object that doesn't respond to #to_json" do
|
134
|
-
let(:object) do
|
135
|
-
obj = Object.new
|
136
|
-
allow(obj).to receive(:to_json)
|
137
|
-
.and_raise(Airbrake::Notice::JSON_EXCEPTIONS.first)
|
138
|
-
obj
|
139
|
-
end
|
140
|
-
|
141
|
-
it "converts the object to a truncated string" do
|
142
|
-
expect(truncator.length).to eq(max_len)
|
143
|
-
expect(truncator).to eq('#<O[Truncated]')
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
shared_examples 'self returning objects' do |object|
|
148
|
-
it "returns the passed object" do
|
149
|
-
expect(described_class.new(max_size).truncate(object)).to eql(object)
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
[1, true, false, :symbol, nil].each do |object|
|
154
|
-
include_examples 'self returning objects', object
|
155
|
-
end
|
156
|
-
|
157
|
-
context "given a recursive array" do
|
158
|
-
let(:object) do
|
159
|
-
a = %w[aaaaa bb]
|
160
|
-
a << a
|
161
|
-
a << 'c'
|
162
|
-
a
|
163
|
-
end
|
164
|
-
|
165
|
-
it "prevents recursion" do
|
166
|
-
expect(truncator).to eq(['aaa[Truncated]', 'bb', '[Circular]'])
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
context "given a recursive array with recursive hashes" do
|
171
|
-
let(:object) do
|
172
|
-
a = []
|
173
|
-
a << a
|
174
|
-
|
175
|
-
h = {}
|
176
|
-
h[:k] = h
|
177
|
-
a << h << 'aaaa'
|
178
|
-
end
|
179
|
-
|
180
|
-
it "prevents recursion" do
|
181
|
-
expect(truncator).to eq(['[Circular]', { k: '[Circular]' }, 'aaa[Truncated]'])
|
182
|
-
expect(truncator).to be_frozen
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
context "given a recursive set with recursive arrays" do
|
187
|
-
let(:object) do
|
188
|
-
s = Set.new
|
189
|
-
s << s
|
190
|
-
|
191
|
-
h = {}
|
192
|
-
h[:k] = h
|
193
|
-
s << h << 'aaaa'
|
194
|
-
end
|
195
|
-
|
196
|
-
it "prevents recursion" do
|
197
|
-
expect(truncator).to eq(
|
198
|
-
Set.new(['[Circular]', { k: '[Circular]' }, 'aaa[Truncated]']),
|
199
|
-
)
|
200
|
-
expect(truncator).to be_frozen
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
context "given a hash with long strings" do
|
205
|
-
let(:object) do
|
206
|
-
{
|
207
|
-
a: multiply_by_2_max_len('a'),
|
208
|
-
b: multiply_by_2_max_len('b'),
|
209
|
-
c: { d: multiply_by_2_max_len('d'), e: 'e' },
|
210
|
-
}
|
211
|
-
end
|
212
|
-
|
213
|
-
it "truncates the long strings" do
|
214
|
-
expect(truncator).to eq(
|
215
|
-
a: 'aaa[Truncated]', b: 'bbb[Truncated]', c: { d: 'ddd[Truncated]', e: 'e' },
|
216
|
-
)
|
217
|
-
expect(truncator).to be_frozen
|
218
|
-
end
|
219
|
-
end
|
220
|
-
|
221
|
-
context "given a string with valid unicode characters" do
|
222
|
-
let(:object) { "€€€€€" }
|
223
|
-
|
224
|
-
it "truncates the string" do
|
225
|
-
expect(truncator).to eq("€€€[Truncated]")
|
226
|
-
end
|
227
|
-
end
|
228
|
-
|
229
|
-
context "given an ASCII-8BIT string with invalid characters" do
|
230
|
-
let(:object) do
|
231
|
-
# Shenanigans to get a bad ASCII-8BIT string. Direct conversion raises error.
|
232
|
-
encoded = Base64.encode64("\xD3\xE6\xBC\x9D\xBA").encode!('ASCII-8BIT')
|
233
|
-
Base64.decode64(encoded).freeze
|
234
|
-
end
|
235
|
-
|
236
|
-
it "converts and truncates the string to UTF-8" do
|
237
|
-
expect(truncator).to eq("���[Truncated]")
|
238
|
-
expect(truncator).to be_frozen
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
context "given an array with hashes and hash-like objects with identical keys" do
|
243
|
-
let(:hashie) { Class.new(Hash) }
|
244
|
-
|
245
|
-
let(:object) do
|
246
|
-
{
|
247
|
-
errors: [
|
248
|
-
{ file: 'a' },
|
249
|
-
{ file: 'a' },
|
250
|
-
hashie.new.merge(file: 'bcde'),
|
251
|
-
],
|
252
|
-
}
|
253
|
-
end
|
254
|
-
|
255
|
-
it "truncates values" do
|
256
|
-
expect(truncator).to eq(
|
257
|
-
errors: [
|
258
|
-
{ file: 'a' },
|
259
|
-
{ file: 'a' },
|
260
|
-
hashie.new.merge(file: 'bcd[Truncated]'),
|
261
|
-
],
|
262
|
-
)
|
263
|
-
expect(truncator).to be_frozen
|
264
|
-
end
|
265
|
-
end
|
266
|
-
end
|
267
|
-
end
|