airbrake-ruby 6.1.0-java → 6.1.1-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +1 -1
- data/lib/airbrake-ruby/nested_exception.rb +10 -1
- data/lib/airbrake-ruby/notice.rb +5 -3
- data/lib/airbrake-ruby/version.rb +1 -1
- metadata +4 -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
|