airbrake-ruby 4.15.0 → 6.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/lib/airbrake-ruby/async_sender.rb +4 -2
  3. data/lib/airbrake-ruby/backtrace.rb +6 -5
  4. data/lib/airbrake-ruby/config/processor.rb +77 -0
  5. data/lib/airbrake-ruby/config/validator.rb +6 -0
  6. data/lib/airbrake-ruby/config.rb +44 -35
  7. data/lib/airbrake-ruby/context.rb +51 -0
  8. data/lib/airbrake-ruby/file_cache.rb +1 -1
  9. data/lib/airbrake-ruby/filter_chain.rb +3 -0
  10. data/lib/airbrake-ruby/filters/context_filter.rb +4 -5
  11. data/lib/airbrake-ruby/filters/dependency_filter.rb +1 -0
  12. data/lib/airbrake-ruby/filters/exception_attributes_filter.rb +1 -1
  13. data/lib/airbrake-ruby/filters/gem_root_filter.rb +1 -0
  14. data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +3 -4
  15. data/lib/airbrake-ruby/filters/git_repository_filter.rb +11 -2
  16. data/lib/airbrake-ruby/filters/git_revision_filter.rb +3 -1
  17. data/lib/airbrake-ruby/filters/keys_filter.rb +23 -15
  18. data/lib/airbrake-ruby/filters/root_directory_filter.rb +1 -0
  19. data/lib/airbrake-ruby/filters/sql_filter.rb +11 -11
  20. data/lib/airbrake-ruby/filters/system_exit_filter.rb +1 -0
  21. data/lib/airbrake-ruby/filters/thread_filter.rb +4 -3
  22. data/lib/airbrake-ruby/grouppable.rb +1 -1
  23. data/lib/airbrake-ruby/ignorable.rb +1 -2
  24. data/lib/airbrake-ruby/mergeable.rb +1 -1
  25. data/lib/airbrake-ruby/monotonic_time.rb +1 -1
  26. data/lib/airbrake-ruby/notice.rb +1 -8
  27. data/lib/airbrake-ruby/notice_notifier.rb +4 -4
  28. data/lib/airbrake-ruby/performance_breakdown.rb +1 -6
  29. data/lib/airbrake-ruby/performance_notifier.rb +40 -54
  30. data/lib/airbrake-ruby/promise.rb +1 -0
  31. data/lib/airbrake-ruby/query.rb +1 -6
  32. data/lib/airbrake-ruby/queue.rb +1 -8
  33. data/lib/airbrake-ruby/remote_settings/callback.rb +44 -0
  34. data/lib/airbrake-ruby/remote_settings/settings_data.rb +116 -0
  35. data/lib/airbrake-ruby/remote_settings.rb +128 -0
  36. data/lib/airbrake-ruby/request.rb +1 -8
  37. data/lib/airbrake-ruby/stat.rb +2 -13
  38. data/lib/airbrake-ruby/sync_sender.rb +3 -2
  39. data/lib/airbrake-ruby/tdigest.rb +12 -9
  40. data/lib/airbrake-ruby/thread_pool.rb +9 -6
  41. data/lib/airbrake-ruby/time_truncate.rb +2 -2
  42. data/lib/airbrake-ruby/timed_trace.rb +1 -3
  43. data/lib/airbrake-ruby/truncator.rb +8 -2
  44. data/lib/airbrake-ruby/version.rb +11 -1
  45. data/lib/airbrake-ruby.rb +44 -54
  46. data/spec/airbrake_spec.rb +178 -92
  47. data/spec/async_sender_spec.rb +10 -8
  48. data/spec/backtrace_spec.rb +39 -36
  49. data/spec/benchmark_spec.rb +7 -5
  50. data/spec/code_hunk_spec.rb +26 -17
  51. data/spec/config/processor_spec.rb +167 -0
  52. data/spec/config/validator_spec.rb +23 -3
  53. data/spec/config_spec.rb +43 -55
  54. data/spec/context_spec.rb +54 -0
  55. data/spec/deploy_notifier_spec.rb +6 -4
  56. data/spec/file_cache_spec.rb +1 -0
  57. data/spec/filter_chain_spec.rb +29 -24
  58. data/spec/filters/context_filter_spec.rb +14 -5
  59. data/spec/filters/dependency_filter_spec.rb +3 -1
  60. data/spec/filters/exception_attributes_filter_spec.rb +5 -3
  61. data/spec/filters/gem_root_filter_spec.rb +9 -6
  62. data/spec/filters/git_last_checkout_filter_spec.rb +10 -12
  63. data/spec/filters/{git_repository_filter.rb → git_repository_filter_spec.rb} +26 -15
  64. data/spec/filters/git_revision_filter_spec.rb +20 -20
  65. data/spec/filters/keys_allowlist_spec.rb +26 -16
  66. data/spec/filters/keys_blocklist_spec.rb +35 -18
  67. data/spec/filters/root_directory_filter_spec.rb +7 -7
  68. data/spec/filters/sql_filter_spec.rb +28 -28
  69. data/spec/filters/system_exit_filter_spec.rb +4 -2
  70. data/spec/filters/thread_filter_spec.rb +16 -14
  71. data/spec/loggable_spec.rb +2 -2
  72. data/spec/monotonic_time_spec.rb +8 -6
  73. data/spec/nested_exception_spec.rb +46 -46
  74. data/spec/notice_notifier/options_spec.rb +25 -15
  75. data/spec/notice_notifier_spec.rb +54 -49
  76. data/spec/notice_spec.rb +7 -3
  77. data/spec/performance_breakdown_spec.rb +0 -12
  78. data/spec/performance_notifier_spec.rb +69 -87
  79. data/spec/promise_spec.rb +38 -32
  80. data/spec/query_spec.rb +1 -11
  81. data/spec/queue_spec.rb +1 -13
  82. data/spec/remote_settings/callback_spec.rb +162 -0
  83. data/spec/remote_settings/settings_data_spec.rb +348 -0
  84. data/spec/remote_settings_spec.rb +201 -0
  85. data/spec/request_spec.rb +1 -13
  86. data/spec/response_spec.rb +34 -12
  87. data/spec/spec_helper.rb +4 -4
  88. data/spec/stashable_spec.rb +5 -5
  89. data/spec/stat_spec.rb +7 -14
  90. data/spec/sync_sender_spec.rb +52 -17
  91. data/spec/tdigest_spec.rb +61 -56
  92. data/spec/thread_pool_spec.rb +67 -58
  93. data/spec/time_truncate_spec.rb +23 -6
  94. data/spec/timed_trace_spec.rb +32 -30
  95. data/spec/truncator_spec.rb +72 -43
  96. metadata +67 -51
@@ -1,9 +1,5 @@
1
1
  RSpec.describe Airbrake::ThreadPool do
2
- let(:tasks) { [] }
3
- let(:worker_size) { 1 }
4
- let(:queue_size) { 2 }
5
-
6
- subject do
2
+ subject(:thread_pool) do
7
3
  described_class.new(
8
4
  worker_size: worker_size,
9
5
  queue_size: queue_size,
@@ -11,27 +7,27 @@ RSpec.describe Airbrake::ThreadPool do
11
7
  )
12
8
  end
13
9
 
10
+ let(:tasks) { [] }
11
+ let(:worker_size) { 1 }
12
+ let(:queue_size) { 2 }
13
+
14
14
  describe "#<<" do
15
15
  it "returns true" do
16
- retval = subject << 1
17
- subject.close
18
- expect(retval).to eq(true)
16
+ retval = thread_pool << 1
17
+ thread_pool.close
18
+ expect(retval).to be(true)
19
19
  end
20
20
 
21
21
  it "performs work in background" do
22
- subject << 2
23
- subject << 1
24
- subject.close
22
+ thread_pool << 2
23
+ thread_pool << 1
24
+ thread_pool.close
25
25
 
26
26
  expect(tasks).to eq([2, 1])
27
27
  end
28
28
 
29
29
  context "when the queue is full" do
30
- before do
31
- allow(subject).to receive(:backlog).and_return(queue_size)
32
- end
33
-
34
- subject do
30
+ subject(:full_thread_pool) do
35
31
  described_class.new(
36
32
  worker_size: 1,
37
33
  queue_size: 1,
@@ -39,26 +35,33 @@ RSpec.describe Airbrake::ThreadPool do
39
35
  )
40
36
  end
41
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
+
42
44
  it "returns false" do
43
- retval = subject << 1
44
- subject.close
45
- expect(retval).to eq(false)
45
+ retval = full_thread_pool << 1
46
+ full_thread_pool.close
47
+ expect(retval).to be(false)
46
48
  end
47
49
 
48
50
  it "discards tasks" do
49
- 200.times { subject << 1 }
50
- subject.close
51
+ 200.times { full_thread_pool << 1 }
52
+ full_thread_pool.close
51
53
 
52
54
  expect(tasks.size).to be_zero
53
55
  end
54
56
 
55
57
  it "logs discarded tasks" do
56
- expect(Airbrake::Loggable.instance).to receive(:error).with(
57
- /reached its capacity/,
58
- ).exactly(15).times
58
+ allow(Airbrake::Loggable.instance).to receive(:info)
59
+
60
+ 15.times { full_thread_pool << 1 }
61
+ full_thread_pool.close
59
62
 
60
- 15.times { subject << 1 }
61
- subject.close
63
+ expect(Airbrake::Loggable.instance)
64
+ .to have_received(:info).exactly(15).times
62
65
  end
63
66
  end
64
67
  end
@@ -67,22 +70,22 @@ RSpec.describe Airbrake::ThreadPool do
67
70
  let(:worker_size) { 0 }
68
71
 
69
72
  it "returns the size of the queue" do
70
- subject << 1
71
- expect(subject.backlog).to eq(1)
73
+ thread_pool << 1
74
+ expect(thread_pool.backlog).to eq(1)
72
75
  end
73
76
  end
74
77
 
75
78
  describe "#has_workers?" do
76
79
  it "returns false when the thread pool is not closed, but has 0 workers" do
77
- subject.workers.list.each do |worker|
80
+ thread_pool.workers.list.each do |worker|
78
81
  worker.kill.join
79
82
  end
80
- expect(subject).not_to have_workers
83
+ expect(thread_pool).not_to have_workers
81
84
  end
82
85
 
83
86
  it "returns false when the thread pool is closed" do
84
- subject.close
85
- expect(subject).not_to have_workers
87
+ thread_pool.close
88
+ expect(thread_pool).not_to have_workers
86
89
  end
87
90
 
88
91
  describe "forking behavior" do
@@ -93,20 +96,22 @@ RSpec.describe Airbrake::ThreadPool do
93
96
  end
94
97
  end
95
98
 
99
+ # rubocop:disable RSpec/MultipleExpectations
96
100
  it "respawns workers on fork()" do
97
- pid = fork { expect(subject).to have_workers }
101
+ pid = fork { expect(thread_pool).to have_workers }
98
102
  Process.wait(pid)
99
- subject.close
103
+ thread_pool.close
100
104
 
101
105
  expect(Process.last_status).to be_success
102
- expect(subject).not_to have_workers
106
+ expect(thread_pool).not_to have_workers
103
107
  end
108
+ # rubocop:enable RSpec/MultipleExpectations
104
109
 
105
110
  it "ensures that a new thread group is created per process" do
106
- subject << 1
107
- pid = fork { subject.has_workers? }
111
+ thread_pool << 1
112
+ pid = fork { thread_pool.has_workers? }
108
113
  Process.wait(pid)
109
- subject.close
114
+ thread_pool.close
110
115
 
111
116
  expect(Process.last_status).to be_success
112
117
  end
@@ -116,27 +121,29 @@ RSpec.describe Airbrake::ThreadPool do
116
121
  describe "#close" do
117
122
  context "when there's no work to do" do
118
123
  it "joins the spawned thread" do
119
- workers = subject.workers.list
124
+ workers = thread_pool.workers.list
120
125
  expect(workers).to all(be_alive)
121
126
 
122
- subject.close
127
+ thread_pool.close
123
128
  expect(workers).to all(be_stop)
124
129
  end
125
130
  end
126
131
 
127
132
  context "when there's some work to do" do
128
133
  it "logs how many tasks are left to process" do
129
- thread_pool = described_class.new(
130
- worker_size: 0, queue_size: 2, block: proc {},
131
- )
134
+ allow(Airbrake::Loggable.instance).to receive(:debug)
132
135
 
133
- expect(Airbrake::Loggable.instance).to receive(:debug).with(
134
- /waiting to process \d+ task\(s\)/,
136
+ thread_pool = described_class.new(
137
+ name: 'foo', worker_size: 0, queue_size: 2, block: proc {},
135
138
  )
136
- expect(Airbrake::Loggable.instance).to receive(:debug).with(/closed/)
137
139
 
138
140
  2.times { thread_pool << 1 }
139
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/)
140
147
  end
141
148
 
142
149
  it "waits until the queue gets empty" do
@@ -144,7 +151,7 @@ RSpec.describe Airbrake::ThreadPool do
144
151
  worker_size: 1, queue_size: 2, block: proc {},
145
152
  )
146
153
 
147
- 10.times { subject << 1 }
154
+ 10.times { thread_pool << 1 }
148
155
  thread_pool.close
149
156
  expect(thread_pool.backlog).to be_zero
150
157
  end
@@ -153,17 +160,17 @@ RSpec.describe Airbrake::ThreadPool do
153
160
  context "when it was already closed" do
154
161
  it "doesn't increase the queue size" do
155
162
  begin
156
- subject.close
163
+ thread_pool.close
157
164
  rescue Airbrake::Error
158
165
  nil
159
166
  end
160
167
 
161
- expect(subject.backlog).to be_zero
168
+ expect(thread_pool.backlog).to be_zero
162
169
  end
163
170
 
164
171
  it "raises error" do
165
- subject.close
166
- expect { subject.close }.to raise_error(
172
+ thread_pool.close
173
+ expect { thread_pool.close }.to raise_error(
167
174
  Airbrake::Error, 'this thread pool is closed already'
168
175
  )
169
176
  end
@@ -171,17 +178,19 @@ RSpec.describe Airbrake::ThreadPool do
171
178
  end
172
179
 
173
180
  describe "#spawn_workers" do
174
- it "spawns alive threads in an enclosed ThreadGroup" do
175
- expect(subject.workers).to be_a(ThreadGroup)
176
- expect(subject.workers.list).to all(be_alive)
177
- expect(subject.workers).to be_enclosed
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
178
187
 
179
- subject.close
188
+ it "spawns threads that are alive" do
189
+ expect(thread_pool.workers.list).to all(be_alive)
180
190
  end
181
191
 
182
192
  it "spawns exactly `workers_size` workers" do
183
- expect(subject.workers.list.size).to eq(worker_size)
184
- subject.close
193
+ expect(thread_pool.workers.list.size).to eq(worker_size)
185
194
  end
186
195
  end
187
196
  end
@@ -1,13 +1,30 @@
1
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
+
2
5
  describe "#utc_truncate_minutes" do
3
- it "truncates time to the floor minute and returns an RFC3339 timestamp" do
4
- time = Time.new(2018, 1, 1, 0, 0, 20, 0)
5
- expect(subject.utc_truncate_minutes(time)).to eq('2018-01-01T00:00:00+00:00')
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
6
24
  end
7
25
 
8
- it "converts time with zone to UTC" do
9
- time = Time.new(2018, 1, 1, 0, 0, 20, '-05:00')
10
- expect(subject.utc_truncate_minutes(time)).to eq('2018-01-01T05:00:00+00:00')
26
+ context "when the time argument is an Integer" do
27
+ include_examples 'time conversion', time.to_i
11
28
  end
12
29
  end
13
30
  end
@@ -1,50 +1,52 @@
1
1
  RSpec.describe Airbrake::TimedTrace do
2
+ subject(:timed_trace) { described_class.new }
3
+
2
4
  describe ".span" do
3
5
  it "returns a timed trace" do
4
- expect(described_class.span('operation') {}).to be_a(described_class)
6
+ expect(described_class.span('operation') { anything }).to be_a(described_class)
5
7
  end
6
8
 
7
9
  it "returns a timed trace with a stopped span" do
8
- timed_trace = described_class.span('operation') {}
10
+ timed_trace = described_class.span('operation') { anything }
9
11
  expect(timed_trace.spans).to match('operation' => be > 0)
10
12
  end
11
13
  end
12
14
 
13
15
  describe "#span" do
14
16
  it "captures a span" do
15
- subject.span('operation') {}
16
- expect(subject.spans).to match('operation' => be > 0)
17
+ timed_trace.span('operation') { anything }
18
+ expect(timed_trace.spans).to match('operation' => be > 0)
17
19
  end
18
20
  end
19
21
 
20
22
  describe "#start_span" do
21
23
  context "when called once" do
22
24
  it "returns true" do
23
- expect(subject.start_span('operation')).to eq(true)
25
+ expect(timed_trace.start_span('operation')).to be(true)
24
26
  end
25
27
  end
26
28
 
27
29
  context "when called multiple times" do
28
- before { subject.start_span('operation') }
30
+ before { timed_trace.start_span('operation') }
29
31
 
30
32
  it "returns false" do
31
- expect(subject.start_span('operation')).to eq(false)
33
+ expect(timed_trace.start_span('operation')).to be(false)
32
34
  end
33
35
  end
34
36
 
35
37
  context "when another span was started" do
36
- before { subject.start_span('operation') }
38
+ before { timed_trace.start_span('operation') }
37
39
 
38
40
  it "returns true" do
39
- expect(subject.start_span('another operation')).to eq(true)
41
+ expect(timed_trace.start_span('another operation')).to be(true)
40
42
  end
41
43
  end
42
44
 
43
45
  context "when #spans was called" do
44
- before { subject.start_span('operation') }
46
+ before { timed_trace.start_span('operation') }
45
47
 
46
48
  it "returns spans with zero values" do
47
- expect(subject.spans).to eq('operation' => 0.0)
49
+ expect(timed_trace.spans).to eq('operation' => 0.0)
48
50
  end
49
51
  end
50
52
  end
@@ -52,35 +54,35 @@ RSpec.describe Airbrake::TimedTrace do
52
54
  describe "#stop_span" do
53
55
  context "when #start_span wasn't invoked" do
54
56
  it "returns false" do
55
- expect(subject.stop_span('operation')).to eq(false)
57
+ expect(timed_trace.stop_span('operation')).to be(false)
56
58
  end
57
59
  end
58
60
 
59
61
  context "when #start_span was invoked" do
60
- before { subject.start_span('operation') }
62
+ before { timed_trace.start_span('operation') }
61
63
 
62
64
  it "returns true" do
63
- expect(subject.stop_span('operation')).to eq(true)
65
+ expect(timed_trace.stop_span('operation')).to be(true)
64
66
  end
65
67
  end
66
68
 
67
69
  context "when multiple spans were started" do
68
70
  before do
69
- subject.start_span('operation')
70
- subject.start_span('another operation')
71
+ timed_trace.start_span('operation')
72
+ timed_trace.start_span('another operation')
71
73
  end
72
74
 
73
75
  context "and when stopping in LIFO order" do
74
76
  it "returns true for all spans" do
75
- expect(subject.stop_span('another operation')).to eq(true)
76
- expect(subject.stop_span('operation')).to eq(true)
77
+ expect(timed_trace.stop_span('another operation')).to be(true)
78
+ expect(timed_trace.stop_span('operation')).to be(true)
77
79
  end
78
80
  end
79
81
 
80
82
  context "and when stopping in FIFO order" do
81
83
  it "returns true for all spans" do
82
- expect(subject.stop_span('operation')).to eq(true)
83
- expect(subject.stop_span('another operation')).to eq(true)
84
+ expect(timed_trace.stop_span('operation')).to be(true)
85
+ expect(timed_trace.stop_span('another operation')).to be(true)
84
86
  end
85
87
  end
86
88
  end
@@ -89,33 +91,33 @@ RSpec.describe Airbrake::TimedTrace do
89
91
  describe "#spans" do
90
92
  context "when no spans were captured" do
91
93
  it "returns an empty hash" do
92
- expect(subject.spans).to eq({})
94
+ expect(timed_trace.spans).to eq({})
93
95
  end
94
96
  end
95
97
 
96
98
  context "when a span was captured" do
97
99
  before do
98
- subject.start_span('operation')
99
- subject.stop_span('operation')
100
+ timed_trace.start_span('operation')
101
+ timed_trace.stop_span('operation')
100
102
  end
101
103
 
102
104
  it "returns a Hash with the corresponding span" do
103
- subject.stop_span('operation')
104
- expect(subject.spans).to match('operation' => be > 0)
105
+ timed_trace.stop_span('operation')
106
+ expect(timed_trace.spans).to match('operation' => be > 0)
105
107
  end
106
108
  end
107
109
 
108
110
  context "when multiple spans were captured" do
109
111
  before do
110
- subject.start_span('operation')
111
- subject.stop_span('operation')
112
+ timed_trace.start_span('operation')
113
+ timed_trace.stop_span('operation')
112
114
 
113
- subject.start_span('another operation')
114
- subject.stop_span('another operation')
115
+ timed_trace.start_span('another operation')
116
+ timed_trace.stop_span('another operation')
115
117
  end
116
118
 
117
119
  it "returns a Hash with all spans" do
118
- expect(subject.spans).to match(
120
+ expect(timed_trace.spans).to match(
119
121
  'operation' => be > 0,
120
122
  'another operation' => be > 0,
121
123
  )
@@ -4,18 +4,18 @@ RSpec.describe Airbrake::Truncator do
4
4
  end
5
5
 
6
6
  describe "#truncate" do
7
+ subject(:truncator) { described_class.new(max_size).truncate(object) }
8
+
7
9
  let(:max_size) { 3 }
8
10
  let(:truncated) { '[Truncated]' }
9
11
  let(:max_len) { max_size + truncated.length }
10
12
 
11
- subject { described_class.new(max_size).truncate(object) }
12
-
13
13
  context "given a frozen string" do
14
14
  let(:object) { multiply_by_2_max_len('a') }
15
15
 
16
16
  it "returns a new truncated frozen string" do
17
- expect(subject.length).to eq(max_len)
18
- expect(subject).to be_frozen
17
+ expect(truncator.length).to eq(max_len)
18
+ expect(truncator).to be_frozen
19
19
  end
20
20
  end
21
21
 
@@ -29,16 +29,27 @@ RSpec.describe Airbrake::Truncator do
29
29
  }.freeze
30
30
  end
31
31
 
32
- it "returns a new truncated frozen hash" do
33
- expect(subject.size).to eq(max_size)
34
- expect(subject).to be_frozen
32
+ it "returns a hash of the same size" do
33
+ expect(truncator.size).to eq(max_size)
34
+ end
35
35
 
36
- expect(subject).to eq(
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(
37
42
  banana: 'aaa[Truncated]', kiwi: 'bbb[Truncated]', strawberry: 'c',
38
43
  )
39
- expect(subject[:banana]).to be_frozen
40
- expect(subject[:kiwi]).to be_frozen
41
- expect(subject[:strawberry]).not_to be_frozen
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
42
53
  end
43
54
  end
44
55
 
@@ -52,14 +63,25 @@ RSpec.describe Airbrake::Truncator do
52
63
  ].freeze
53
64
  end
54
65
 
55
- it "returns a new truncated frozen array" do
56
- expect(subject.size).to eq(max_size)
57
- expect(subject).to be_frozen
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
58
73
 
59
- expect(subject).to eq(['aaa[Truncated]', 'b', 'ccc[Truncated]'])
60
- expect(subject[0]).to be_frozen
61
- expect(subject[1]).not_to be_frozen
62
- expect(subject[2]).to be_frozen
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
63
85
  end
64
86
  end
65
87
 
@@ -73,14 +95,16 @@ RSpec.describe Airbrake::Truncator do
73
95
  ]).freeze
74
96
  end
75
97
 
76
- it "returns a new truncated frozen array" do
77
- expect(subject.size).to eq(max_size)
78
- expect(subject).to be_frozen
98
+ it "returns a set of the same size" do
99
+ expect(truncator.size).to eq(max_size)
100
+ end
79
101
 
80
- expect(subject).to eq(
81
- Set.new(['aaa[Truncated]', 'b', 'ccc[Truncated]']),
82
- )
83
- expect(subject).to be_frozen
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]']))
84
108
  end
85
109
  end
86
110
 
@@ -93,11 +117,16 @@ RSpec.describe Airbrake::Truncator do
93
117
  obj.freeze
94
118
  end
95
119
 
96
- it "converts the object to truncated JSON" do
97
- expect(subject.length).to eq(max_len)
98
- expect(subject).to be_frozen
120
+ it "returns a string of a max len size" do
121
+ expect(truncator.length).to eq(max_len)
122
+ end
99
123
 
100
- expect(subject).to eq('{"o[Truncated]')
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]')
101
130
  end
102
131
  end
103
132
 
@@ -110,8 +139,8 @@ RSpec.describe Airbrake::Truncator do
110
139
  end
111
140
 
112
141
  it "converts the object to a truncated string" do
113
- expect(subject.length).to eq(max_len)
114
- expect(subject).to eq('#<O[Truncated]')
142
+ expect(truncator.length).to eq(max_len)
143
+ expect(truncator).to eq('#<O[Truncated]')
115
144
  end
116
145
  end
117
146
 
@@ -134,7 +163,7 @@ RSpec.describe Airbrake::Truncator do
134
163
  end
135
164
 
136
165
  it "prevents recursion" do
137
- expect(subject).to eq(['aaa[Truncated]', 'bb', '[Circular]'])
166
+ expect(truncator).to eq(['aaa[Truncated]', 'bb', '[Circular]'])
138
167
  end
139
168
  end
140
169
 
@@ -149,8 +178,8 @@ RSpec.describe Airbrake::Truncator do
149
178
  end
150
179
 
151
180
  it "prevents recursion" do
152
- expect(subject).to eq(['[Circular]', { k: '[Circular]' }, 'aaa[Truncated]'])
153
- expect(subject).to be_frozen
181
+ expect(truncator).to eq(['[Circular]', { k: '[Circular]' }, 'aaa[Truncated]'])
182
+ expect(truncator).to be_frozen
154
183
  end
155
184
  end
156
185
 
@@ -165,10 +194,10 @@ RSpec.describe Airbrake::Truncator do
165
194
  end
166
195
 
167
196
  it "prevents recursion" do
168
- expect(subject).to eq(
197
+ expect(truncator).to eq(
169
198
  Set.new(['[Circular]', { k: '[Circular]' }, 'aaa[Truncated]']),
170
199
  )
171
- expect(subject).to be_frozen
200
+ expect(truncator).to be_frozen
172
201
  end
173
202
  end
174
203
 
@@ -182,10 +211,10 @@ RSpec.describe Airbrake::Truncator do
182
211
  end
183
212
 
184
213
  it "truncates the long strings" do
185
- expect(subject).to eq(
214
+ expect(truncator).to eq(
186
215
  a: 'aaa[Truncated]', b: 'bbb[Truncated]', c: { d: 'ddd[Truncated]', e: 'e' },
187
216
  )
188
- expect(subject).to be_frozen
217
+ expect(truncator).to be_frozen
189
218
  end
190
219
  end
191
220
 
@@ -193,7 +222,7 @@ RSpec.describe Airbrake::Truncator do
193
222
  let(:object) { "€€€€€" }
194
223
 
195
224
  it "truncates the string" do
196
- expect(subject).to eq("€€€[Truncated]")
225
+ expect(truncator).to eq("€€€[Truncated]")
197
226
  end
198
227
  end
199
228
 
@@ -205,8 +234,8 @@ RSpec.describe Airbrake::Truncator do
205
234
  end
206
235
 
207
236
  it "converts and truncates the string to UTF-8" do
208
- expect(subject).to eq("���[Truncated]")
209
- expect(subject).to be_frozen
237
+ expect(truncator).to eq("���[Truncated]")
238
+ expect(truncator).to be_frozen
210
239
  end
211
240
  end
212
241
 
@@ -224,14 +253,14 @@ RSpec.describe Airbrake::Truncator do
224
253
  end
225
254
 
226
255
  it "truncates values" do
227
- expect(subject).to eq(
256
+ expect(truncator).to eq(
228
257
  errors: [
229
258
  { file: 'a' },
230
259
  { file: 'a' },
231
260
  hashie.new.merge(file: 'bcd[Truncated]'),
232
261
  ],
233
262
  )
234
- expect(subject).to be_frozen
263
+ expect(truncator).to be_frozen
235
264
  end
236
265
  end
237
266
  end