airbrake-ruby 3.2.2-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.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/lib/airbrake-ruby.rb +554 -0
  3. data/lib/airbrake-ruby/async_sender.rb +119 -0
  4. data/lib/airbrake-ruby/backtrace.rb +194 -0
  5. data/lib/airbrake-ruby/code_hunk.rb +53 -0
  6. data/lib/airbrake-ruby/config.rb +238 -0
  7. data/lib/airbrake-ruby/config/validator.rb +63 -0
  8. data/lib/airbrake-ruby/deploy_notifier.rb +47 -0
  9. data/lib/airbrake-ruby/file_cache.rb +48 -0
  10. data/lib/airbrake-ruby/filter_chain.rb +95 -0
  11. data/lib/airbrake-ruby/filters/context_filter.rb +29 -0
  12. data/lib/airbrake-ruby/filters/dependency_filter.rb +31 -0
  13. data/lib/airbrake-ruby/filters/exception_attributes_filter.rb +45 -0
  14. data/lib/airbrake-ruby/filters/gem_root_filter.rb +33 -0
  15. data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +90 -0
  16. data/lib/airbrake-ruby/filters/git_repository_filter.rb +42 -0
  17. data/lib/airbrake-ruby/filters/git_revision_filter.rb +66 -0
  18. data/lib/airbrake-ruby/filters/keys_blacklist.rb +50 -0
  19. data/lib/airbrake-ruby/filters/keys_filter.rb +140 -0
  20. data/lib/airbrake-ruby/filters/keys_whitelist.rb +49 -0
  21. data/lib/airbrake-ruby/filters/root_directory_filter.rb +28 -0
  22. data/lib/airbrake-ruby/filters/sql_filter.rb +104 -0
  23. data/lib/airbrake-ruby/filters/system_exit_filter.rb +23 -0
  24. data/lib/airbrake-ruby/filters/thread_filter.rb +92 -0
  25. data/lib/airbrake-ruby/hash_keyable.rb +37 -0
  26. data/lib/airbrake-ruby/ignorable.rb +44 -0
  27. data/lib/airbrake-ruby/nested_exception.rb +39 -0
  28. data/lib/airbrake-ruby/notice.rb +165 -0
  29. data/lib/airbrake-ruby/notice_notifier.rb +228 -0
  30. data/lib/airbrake-ruby/performance_notifier.rb +161 -0
  31. data/lib/airbrake-ruby/promise.rb +99 -0
  32. data/lib/airbrake-ruby/response.rb +71 -0
  33. data/lib/airbrake-ruby/stat.rb +56 -0
  34. data/lib/airbrake-ruby/sync_sender.rb +111 -0
  35. data/lib/airbrake-ruby/tdigest.rb +393 -0
  36. data/lib/airbrake-ruby/time_truncate.rb +17 -0
  37. data/lib/airbrake-ruby/truncator.rb +115 -0
  38. data/lib/airbrake-ruby/version.rb +6 -0
  39. data/spec/airbrake_spec.rb +171 -0
  40. data/spec/async_sender_spec.rb +154 -0
  41. data/spec/backtrace_spec.rb +438 -0
  42. data/spec/code_hunk_spec.rb +118 -0
  43. data/spec/config/validator_spec.rb +189 -0
  44. data/spec/config_spec.rb +281 -0
  45. data/spec/deploy_notifier_spec.rb +41 -0
  46. data/spec/file_cache.rb +36 -0
  47. data/spec/filter_chain_spec.rb +83 -0
  48. data/spec/filters/context_filter_spec.rb +25 -0
  49. data/spec/filters/dependency_filter_spec.rb +14 -0
  50. data/spec/filters/exception_attributes_filter_spec.rb +63 -0
  51. data/spec/filters/gem_root_filter_spec.rb +44 -0
  52. data/spec/filters/git_last_checkout_filter_spec.rb +48 -0
  53. data/spec/filters/git_repository_filter.rb +53 -0
  54. data/spec/filters/git_revision_filter_spec.rb +126 -0
  55. data/spec/filters/keys_blacklist_spec.rb +236 -0
  56. data/spec/filters/keys_whitelist_spec.rb +205 -0
  57. data/spec/filters/root_directory_filter_spec.rb +42 -0
  58. data/spec/filters/sql_filter_spec.rb +219 -0
  59. data/spec/filters/system_exit_filter_spec.rb +14 -0
  60. data/spec/filters/thread_filter_spec.rb +279 -0
  61. data/spec/fixtures/notroot.txt +7 -0
  62. data/spec/fixtures/project_root/code.rb +221 -0
  63. data/spec/fixtures/project_root/empty_file.rb +0 -0
  64. data/spec/fixtures/project_root/long_line.txt +1 -0
  65. data/spec/fixtures/project_root/short_file.rb +3 -0
  66. data/spec/fixtures/project_root/vendor/bundle/ignored_file.rb +5 -0
  67. data/spec/helpers.rb +9 -0
  68. data/spec/ignorable_spec.rb +14 -0
  69. data/spec/nested_exception_spec.rb +75 -0
  70. data/spec/notice_notifier_spec.rb +436 -0
  71. data/spec/notice_notifier_spec/options_spec.rb +266 -0
  72. data/spec/notice_spec.rb +297 -0
  73. data/spec/performance_notifier_spec.rb +287 -0
  74. data/spec/promise_spec.rb +165 -0
  75. data/spec/response_spec.rb +82 -0
  76. data/spec/spec_helper.rb +102 -0
  77. data/spec/stat_spec.rb +35 -0
  78. data/spec/sync_sender_spec.rb +140 -0
  79. data/spec/tdigest_spec.rb +230 -0
  80. data/spec/time_truncate_spec.rb +13 -0
  81. data/spec/truncator_spec.rb +238 -0
  82. metadata +278 -0
@@ -0,0 +1,219 @@
1
+ RSpec.describe Airbrake::Filters::SqlFilter do
2
+ shared_examples "query filtering" do |test|
3
+ test[:dialects].each do |dialect|
4
+ it "correctly filters SQL like `#{test[:input]}' (#{dialect} dialect)" do
5
+ filter = described_class.new(dialect)
6
+ q = OpenStruct.new(query: test[:input])
7
+ filter.call(q)
8
+ expect(q.query).to eq(test[:output])
9
+ end
10
+ end
11
+ end
12
+
13
+ ALL_DIALECTS = %i[mysql postgres sqlite cassandra oracle].freeze
14
+
15
+ # rubocop:disable Metrics/LineLength
16
+ [
17
+ {
18
+ input: 'SELECT * FROM things;',
19
+ output: 'SELECT * FROM things;',
20
+ dialects: ALL_DIALECTS
21
+ }, {
22
+ input: "SELECT `t001`.`c2` FROM `t001` WHERE `t001`.`c2` = 'value' AND c3=\"othervalue\" LIMIT ?",
23
+ output: "SELECT `t001`.`c2` FROM `t001` WHERE `t001`.`c2` = ? AND c3=? LIMIT ?",
24
+ dialects: %i[mysql]
25
+ }, {
26
+ input: "SELECT * FROM t WHERE foo=\"bar/*\" AND baz=\"whatever */qux\"",
27
+ output: "SELECT * FROM t WHERE foo=? AND baz=?",
28
+ dialects: %i[mysql]
29
+ }, {
30
+ input: "SELECT * FROM t WHERE foo='bar/*' AND baz='whatever */qux'",
31
+ output: "SELECT * FROM t WHERE foo=? AND baz=?",
32
+ dialects: ALL_DIALECTS
33
+ }, {
34
+ input: "SELECT \"t001\".\"c2\" FROM \"t001\" WHERE \"t001\".\"c2\" = 'value' AND c3=1234 LIMIT 1",
35
+ output: "SELECT \"t001\".\"c2\" FROM \"t001\" WHERE \"t001\".\"c2\" = ? AND c3=? LIMIT ?",
36
+ dialects: %i[postgres oracle]
37
+ }, {
38
+ input: "SELECT * FROM t WHERE foo=\"bar--\" AND\n baz=\"qux--\"",
39
+ output: "SELECT * FROM t WHERE foo=? AND\n baz=?",
40
+ dialects: %i[mysql]
41
+ }, {
42
+ input: "SELECT * FROM t WHERE foo='bar--' AND\n baz='qux--'",
43
+ output: "SELECT * FROM t WHERE foo=? AND\n baz=?",
44
+ dialects: ALL_DIALECTS
45
+ }, {
46
+ input: "SELECT * FROM foo WHERE bar='baz' /* Hide Me */",
47
+ output: "SELECT * FROM foo WHERE bar=? ?",
48
+ dialects: ALL_DIALECTS
49
+ }, {
50
+ input: "SELECT * FROM foobar WHERE password='hunter2'\n-- No peeking!",
51
+ output: "SELECT * FROM foobar WHERE password=?\n?",
52
+ dialects: ALL_DIALECTS
53
+ }, {
54
+ input: "SELECT foo, bar FROM baz WHERE password='hunter2' # Secret",
55
+ output: "SELECT foo, bar FROM baz WHERE password=? ?",
56
+ dialects: ALL_DIALECTS
57
+ }, {
58
+ input: "SELECT \"col1\", \"col2\" from \"table\" WHERE \"col3\"=E'foo\\'bar\\\\baz' AND country=e'foo\\'bar\\\\baz'",
59
+ output: "SELECT \"col1\", \"col2\" from \"table\" WHERE \"col3\"=E?",
60
+ dialects: %i[postgres]
61
+ }, {
62
+ input: "INSERT INTO `X` values(\"test\",0, 1 , 2, 'test')",
63
+ output: "INSERT INTO `X` values(?,?, ? , ?, ?)",
64
+ dialects: %i[mysql]
65
+ }, {
66
+ input: "SELECT c11.col1, c22.col2 FROM table c11, table c22 WHERE value='nothing'",
67
+ output: "SELECT c11.col1, c22.col2 FROM table c11, table c22 WHERE value=?",
68
+ dialects: ALL_DIALECTS
69
+ }, {
70
+ input: "INSERT INTO X VALUES(1, 23456, 123.456, 99+100)",
71
+ output: "INSERT INTO X VALUES(?, ?, ?, ?+?)",
72
+ dialects: ALL_DIALECTS
73
+ }, {
74
+ input: "SELECT * FROM table WHERE name=\"foo\" AND value=\"don't\"",
75
+ output: "SELECT * FROM table WHERE name=? AND value=?",
76
+ dialects: %i[mysql]
77
+ }, {
78
+ input: "SELECT * FROM table WHERE name='foo' AND value = 'bar'",
79
+ output: "SELECT * FROM table WHERE name=? AND value = ?",
80
+ dialects: ALL_DIALECTS
81
+ }, {
82
+ input: "SELECT * FROM table WHERE col='foo\\''bar'",
83
+ output: "SELECT * FROM table WHERE col=?",
84
+ dialects: ALL_DIALECTS
85
+ }, {
86
+ input: "SELECT * FROM table WHERE col1='foo\"bar' AND col2='what\"ever'",
87
+ output: "SELECT * FROM table WHERE col1=? AND col2=?",
88
+ dialects: ALL_DIALECTS
89
+ }, {
90
+ input: "select * from accounts where accounts.name != 'dude\n newline' order by accounts.name",
91
+ output: "select * from accounts where accounts.name != ? order by accounts.name",
92
+ dialects: ALL_DIALECTS
93
+ }, {
94
+ input: "SELECT * FROM table WHERE col1=\"don't\" AND col2=\"won't\"",
95
+ output: "SELECT * FROM table WHERE col1=? AND col2=?",
96
+ dialects: %i[mysql]
97
+ }, {
98
+ input: "INSERT INTO X values('', 'jim''s ssn',0, 1 , 'jim''s son''s son', \"\"\"jim''s\"\" hat\", \"\\\"jim''s secret\\\"\")",
99
+ output: "INSERT INTO X values(?, ?,?, ? , ?, ?, ?",
100
+ dialects: %i[mysql]
101
+ }, {
102
+ input: "SELECT * FROM table WHERE name='foo\\' AND color='blue'",
103
+ output: "SELECT * FROM table WHERE name=?",
104
+ dialects: ALL_DIALECTS
105
+ }, {
106
+ input: "SELECT * FROM table WHERE foo=\"this string ends with a backslash\\\\\"",
107
+ output: "SELECT * FROM table WHERE foo=?",
108
+ dialects: %i[mysql]
109
+ }, {
110
+ input: "SELECT * FROM table WHERE foo='this string ends with a backslash\\\\'",
111
+ output: "SELECT * FROM table WHERE foo=?",
112
+ dialects: ALL_DIALECTS
113
+ }, {
114
+ # TODO: fix this example.
115
+ input: "SELECT * FROM table WHERE name='foo\'' AND color='blue'",
116
+ output: "Error: Airbrake::Query was not filtered",
117
+ dialects: ALL_DIALECTS
118
+ }, {
119
+ input: "INSERT INTO X values('', 'a''b c',0, 1 , 'd''e f''s h')",
120
+ output: "INSERT INTO X values(?, ?,?, ? , ?)",
121
+ dialects: ALL_DIALECTS
122
+ }, {
123
+ input: "SELECT * FROM t WHERE -- '\n bar='baz' -- '",
124
+ output: "SELECT * FROM t WHERE ?\n bar=? ?",
125
+ dialects: ALL_DIALECTS
126
+ }, {
127
+ input: "SELECT * FROM t WHERE /* ' */\n bar='baz' -- '",
128
+ output: "SELECT * FROM t WHERE ?\n bar=? ?",
129
+ dialects: ALL_DIALECTS
130
+ }, {
131
+ input: "SELECT * FROM t WHERE -- '\n /* ' */ c2='xxx' /* ' */\n c='x\n xx' -- '",
132
+ output: "SELECT * FROM t WHERE ?\n ? c2=? ?\n c=? ?",
133
+ dialects: ALL_DIALECTS
134
+ }, {
135
+ input: "SELECT * FROM t WHERE -- '\n c='x\n xx' -- '",
136
+ output: "SELECT * FROM t WHERE ?\n c=? ?",
137
+ dialects: ALL_DIALECTS
138
+ }, {
139
+ input: "SELECT * FROM foo WHERE col='value1' AND /* don't */ col2='value1' /* won't */",
140
+ output: "SELECT * FROM foo WHERE col=? AND ? col2=? ?",
141
+ dialects: ALL_DIALECTS
142
+ }, {
143
+ input: "SELECT * FROM table WHERE foo='bar' AND baz=\"nothing to see here'",
144
+ output: "Error: Airbrake::Query was not filtered",
145
+ dialects: %i[mysql]
146
+ }, {
147
+ input: "SELECT * FROM table WHERE foo='bar' AND baz='nothing to see here",
148
+ output: "Error: Airbrake::Query was not filtered",
149
+ dialects: ALL_DIALECTS
150
+ }, {
151
+ input: "SELECT * FROM \"foo\" WHERE \"foo\" = $a$dollar quotes can be $b$nested$b$$a$ and bar = 'baz'",
152
+ output: "SELECT * FROM \"foo\" WHERE \"foo\" = ? and bar = ?",
153
+ dialects: %i[postgres]
154
+ }, {
155
+ input: "INSERT INTO \"foo\" (\"bar\", \"baz\", \"qux\") VALUES ($1, $2, $3) RETURNING \"id\"",
156
+ output: "INSERT INTO \"foo\" (\"bar\", \"baz\", \"qux\") VALUES ($?, $?, $?) RETURNING \"id\"",
157
+ dialects: %i[postgres]
158
+ }, {
159
+ input: "select * from foo where bar = 'some\\tthing' and baz = 10",
160
+ output: "select * from foo where bar = ? and baz = ?",
161
+ dialects: ALL_DIALECTS
162
+ }, {
163
+ input: "select * from users where user = 'user1\\' password = 'hunter 2' -- ->don't count this quote",
164
+ output: "select * from users where user = ?",
165
+ dialects: ALL_DIALECTS
166
+ }, {
167
+ input: "select * from foo where bar=q'[baz's]' and x=5",
168
+ output: "select * from foo where bar=? and x=?",
169
+ dialects: %i[oracle]
170
+ }, {
171
+ input: "select * from foo where bar=q'{baz's}' and x=5",
172
+ output: "select * from foo where bar=? and x=?",
173
+ dialects: %i[oracle]
174
+ }, {
175
+ input: "select * from foo where bar=q'<baz's>' and x=5",
176
+ output: "select * from foo where bar=? and x=?",
177
+ dialects: %i[oracle]
178
+ }, {
179
+ input: "select * from foo where bar=q'(baz's)' and x=5",
180
+ output: "select * from foo where bar=? and x=?",
181
+ dialects: %i[oracle]
182
+ }, {
183
+ input: "select * from foo where bar=0xabcdef123 and x=5",
184
+ output: "select * from foo where bar=? and x=?",
185
+ dialects: %i[cassandra sqlite]
186
+ }, {
187
+ input: "select * from foo where bar=0x2F and x=5",
188
+ output: "select * from foo where bar=? and x=?",
189
+ dialects: %i[mysql cassandra sqlite]
190
+ }, {
191
+ input: "select * from foo where bar=1.234e-5 and x=5",
192
+ output: "select * from foo where bar=? and x=?",
193
+ dialects: ALL_DIALECTS
194
+ }, {
195
+ input: "select * from foo where bar=01234567-89ab-cdef-0123-456789abcdef and x=5",
196
+ output: "select * from foo where bar=? and x=?",
197
+ dialects: %i[postgres cassandra]
198
+ }, {
199
+ input: "select * from foo where bar={01234567-89ab-cdef-0123-456789abcdef} and x=5",
200
+ output: "select * from foo where bar=? and x=?",
201
+ dialects: %i[postgres]
202
+ }, {
203
+ input: "select * from foo where bar=0123456789abcdef0123456789abcdef and x=5",
204
+ output: "select * from foo where bar=? and x=?",
205
+ dialects: %i[postgtes]
206
+ }, {
207
+ input: "select * from foo where bar={012-345678-9abc-def012345678-9abcdef} and x=5",
208
+ output: "select * from foo where bar=? and x=?",
209
+ dialects: %i[postgres]
210
+ }, {
211
+ input: "select * from foo where bar=true and x=FALSE",
212
+ output: "select * from foo where bar=? and x=?",
213
+ dialects: %i[mysql postgres cassandra sqlite]
214
+ }
215
+ ].each do |test|
216
+ include_examples 'query filtering', test
217
+ end
218
+ # rubocop:enable Metrics/LineLength
219
+ end
@@ -0,0 +1,14 @@
1
+ RSpec.describe Airbrake::Filters::SystemExitFilter do
2
+ it "marks SystemExit exceptions as ignored" do
3
+ notice = Airbrake::Notice.new(Airbrake::Config.new, SystemExit.new)
4
+ expect { subject.call(notice) }.to(
5
+ change { notice.ignored? }.from(false).to(true)
6
+ )
7
+ end
8
+
9
+ it "doesn't mark non SystemExit exceptions as ignored" do
10
+ notice = Airbrake::Notice.new(Airbrake::Config.new, AirbrakeTestError.new)
11
+ expect(notice).not_to be_ignored
12
+ expect { subject.call(notice) }.not_to(change { notice.ignored? })
13
+ end
14
+ end
@@ -0,0 +1,279 @@
1
+ RSpec.describe Airbrake::Filters::ThreadFilter do
2
+ let(:notice) do
3
+ Airbrake::Notice.new(Airbrake::Config.new, AirbrakeTestError.new)
4
+ end
5
+
6
+ def new_thread
7
+ Thread.new do
8
+ th = Thread.current
9
+
10
+ # Ensure a thread always has some variable to make sure the
11
+ # :fiber_variables Hash is always present.
12
+ th[:random_var] = 42
13
+ yield(th)
14
+ end.join
15
+ end
16
+
17
+ describe "thread variables" do
18
+ shared_examples "expected thread variable" do |var|
19
+ it "attaches the thread variable" do
20
+ new_thread do |th|
21
+ th.thread_variable_set(:bingo, var)
22
+ subject.call(notice)
23
+ end
24
+
25
+ expect(notice[:params][:thread][:thread_variables][:bingo]).to eq(var)
26
+ end
27
+ end
28
+
29
+ context "given nil" do
30
+ include_examples "expected thread variable", nil
31
+ end
32
+
33
+ context "given true" do
34
+ include_examples "expected thread variable", true
35
+ end
36
+
37
+ context "given false" do
38
+ include_examples "expected thread variable", false
39
+ end
40
+
41
+ context "given a String" do
42
+ include_examples "expected thread variable", 'bango'
43
+ end
44
+
45
+ context "given a Symbol" do
46
+ include_examples "expected thread variable", :bango
47
+ end
48
+
49
+ context "given a Regexp" do
50
+ include_examples "expected thread variable", /bango/
51
+ end
52
+
53
+ context "given an Integer" do
54
+ include_examples "expected thread variable", 1
55
+ end
56
+
57
+ context "given a Float" do
58
+ include_examples "expected thread variable", 1.01
59
+ end
60
+
61
+ context "given an Object" do
62
+ it "converts it to a String and attaches" do
63
+ new_thread do |th|
64
+ th.thread_variable_set(:bingo, Object.new)
65
+ subject.call(notice)
66
+ end
67
+
68
+ vars = notice[:params][:thread][:thread_variables]
69
+ expect(vars[:bingo]).to match(/\A#<Object:.+>\z/)
70
+ end
71
+ end
72
+
73
+ context "given an Array of nested Hashes with complex objects" do
74
+ let(:var) do
75
+ [
76
+ {
77
+ bango: {
78
+ bongo: [
79
+ {
80
+ bish: {
81
+ bash: 'foo',
82
+ bosh: Object.new
83
+ }
84
+ }
85
+ ]
86
+ }
87
+ },
88
+ 123
89
+ ]
90
+ end
91
+
92
+ it "converts objects to a safe objects" do
93
+ new_thread do |th|
94
+ th.thread_variable_set(:bingo, var)
95
+ subject.call(notice)
96
+ end
97
+
98
+ vars = notice[:params][:thread][:thread_variables]
99
+ expect(vars[:bingo]).to(
100
+ match(
101
+ [
102
+ {
103
+ bango: {
104
+ bongo: [
105
+ {
106
+ bish: {
107
+ bash: 'foo',
108
+ bosh: /\A#<Object:.+>\z/
109
+ }
110
+ }
111
+ ]
112
+ }
113
+ },
114
+ 123
115
+ ]
116
+ )
117
+ )
118
+ end
119
+ end
120
+
121
+ it "ignores thread variables starting with an underscore" do
122
+ var = :__recursive_key__
123
+
124
+ new_thread do |th|
125
+ th.thread_variable_set(var, :bingo)
126
+ subject.call(notice)
127
+ end
128
+
129
+ thread_variables = notice[:params][:thread][:thread_variables]
130
+ expect(thread_variables).to be_nil
131
+ end
132
+ end
133
+
134
+ describe "fiber variables" do
135
+ shared_examples "expected fiber variable" do |var|
136
+ it "attaches the fiber variable" do
137
+ new_thread do |th|
138
+ th[:bingo] = var
139
+ subject.call(notice)
140
+ end
141
+
142
+ expect(notice[:params][:thread][:fiber_variables][:bingo]).to eq(var)
143
+ end
144
+ end
145
+
146
+ context "given nil" do
147
+ include_examples "expected fiber variable", nil
148
+ end
149
+
150
+ context "given true" do
151
+ include_examples "expected fiber variable", true
152
+ end
153
+
154
+ context "given false" do
155
+ include_examples "expected fiber variable", false
156
+ end
157
+
158
+ context "given a String" do
159
+ include_examples "expected fiber variable", 'bango'
160
+ end
161
+
162
+ context "given a Symbol" do
163
+ include_examples "expected fiber variable", :bango
164
+ end
165
+
166
+ context "given a Regexp" do
167
+ include_examples "expected fiber variable", /bango/
168
+ end
169
+
170
+ context "given an Integer" do
171
+ include_examples "expected fiber variable", 1
172
+ end
173
+
174
+ context "given a Float" do
175
+ include_examples "expected fiber variable", 1.01
176
+ end
177
+
178
+ context "given an Object" do
179
+ it "converts it to a String and attaches" do
180
+ new_thread do |th|
181
+ th[:bingo] = Object.new
182
+ subject.call(notice)
183
+ end
184
+
185
+ vars = notice[:params][:thread][:fiber_variables]
186
+ expect(vars[:bingo]).to match(/\A#<Object:.+>\z/)
187
+ end
188
+ end
189
+
190
+ context "given an Array of nested Hashes with complex objects" do
191
+ let(:var) do
192
+ [
193
+ {
194
+ bango: {
195
+ bongo: [
196
+ {
197
+ bish: {
198
+ bash: 'foo',
199
+ bosh: Object.new
200
+ }
201
+ }
202
+ ]
203
+ }
204
+ },
205
+ 123
206
+ ]
207
+ end
208
+
209
+ it "converts objects to a safe objects" do
210
+ new_thread do |th|
211
+ th[:bingo] = var
212
+ subject.call(notice)
213
+ end
214
+
215
+ vars = notice[:params][:thread][:fiber_variables]
216
+ expect(vars[:bingo]).to(
217
+ match(
218
+ [
219
+ {
220
+ bango: {
221
+ bongo: [
222
+ {
223
+ bish: {
224
+ bash: 'foo',
225
+ bosh: /\A#<Object:.+>\z/
226
+ }
227
+ }
228
+ ]
229
+ }
230
+ },
231
+ 123
232
+ ]
233
+ )
234
+ )
235
+ end
236
+ end
237
+ end
238
+
239
+ it "appends name", skip: !Thread.current.respond_to?(:name) do
240
+ new_thread do |th|
241
+ th.name = 'bingo'
242
+ subject.call(notice)
243
+ end
244
+
245
+ expect(notice[:params][:thread][:name]).to eq('bingo')
246
+ end
247
+
248
+ it "appends thread inspect (self)" do
249
+ subject.call(notice)
250
+ expect(notice[:params][:thread][:self]).to match(/\A#<Thread:.+ run>\z/)
251
+ end
252
+
253
+ it "appends thread group" do
254
+ subject.call(notice)
255
+ expect(notice[:params][:thread][:group][0]).to match(/\A#<Thread:.+ run>\z/)
256
+ end
257
+
258
+ it "appends priority" do
259
+ subject.call(notice)
260
+ expect(notice[:params][:thread][:priority]).to eq(0)
261
+ end
262
+
263
+ it "appends safe_level", skip: Airbrake::JRUBY do
264
+ subject.call(notice)
265
+ expect(notice[:params][:thread][:safe_level]).to eq(0)
266
+ end
267
+
268
+ it "ignores fiber variables starting with an underscore" do
269
+ key = :__recursive_key__
270
+
271
+ new_thread do |th|
272
+ th[key] = :bingo
273
+ subject.call(notice)
274
+ end
275
+
276
+ fiber_variables = notice[:params][:thread][:fiber_variables]
277
+ expect(fiber_variables[key]).to be_nil
278
+ end
279
+ end