airbrake-ruby 4.1.0 → 5.0.0

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 (94) hide show
  1. checksums.yaml +5 -5
  2. data/lib/airbrake-ruby/async_sender.rb +22 -96
  3. data/lib/airbrake-ruby/backtrace.rb +8 -7
  4. data/lib/airbrake-ruby/benchmark.rb +39 -0
  5. data/lib/airbrake-ruby/code_hunk.rb +1 -1
  6. data/lib/airbrake-ruby/config/processor.rb +84 -0
  7. data/lib/airbrake-ruby/config/validator.rb +9 -3
  8. data/lib/airbrake-ruby/config.rb +76 -20
  9. data/lib/airbrake-ruby/deploy_notifier.rb +1 -1
  10. data/lib/airbrake-ruby/file_cache.rb +6 -0
  11. data/lib/airbrake-ruby/filter_chain.rb +16 -1
  12. data/lib/airbrake-ruby/filters/dependency_filter.rb +1 -0
  13. data/lib/airbrake-ruby/filters/exception_attributes_filter.rb +2 -2
  14. data/lib/airbrake-ruby/filters/gem_root_filter.rb +1 -0
  15. data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +5 -5
  16. data/lib/airbrake-ruby/filters/git_repository_filter.rb +3 -0
  17. data/lib/airbrake-ruby/filters/git_revision_filter.rb +2 -0
  18. data/lib/airbrake-ruby/filters/{keys_whitelist.rb → keys_allowlist.rb} +3 -3
  19. data/lib/airbrake-ruby/filters/{keys_blacklist.rb → keys_blocklist.rb} +3 -3
  20. data/lib/airbrake-ruby/filters/keys_filter.rb +39 -20
  21. data/lib/airbrake-ruby/filters/root_directory_filter.rb +1 -0
  22. data/lib/airbrake-ruby/filters/sql_filter.rb +30 -6
  23. data/lib/airbrake-ruby/filters/system_exit_filter.rb +1 -0
  24. data/lib/airbrake-ruby/filters/thread_filter.rb +4 -2
  25. data/lib/airbrake-ruby/grouppable.rb +12 -0
  26. data/lib/airbrake-ruby/ignorable.rb +1 -0
  27. data/lib/airbrake-ruby/inspectable.rb +2 -2
  28. data/lib/airbrake-ruby/loggable.rb +2 -2
  29. data/lib/airbrake-ruby/mergeable.rb +12 -0
  30. data/lib/airbrake-ruby/monotonic_time.rb +48 -0
  31. data/lib/airbrake-ruby/notice.rb +10 -20
  32. data/lib/airbrake-ruby/notice_notifier.rb +23 -42
  33. data/lib/airbrake-ruby/performance_breakdown.rb +52 -0
  34. data/lib/airbrake-ruby/performance_notifier.rb +126 -49
  35. data/lib/airbrake-ruby/promise.rb +1 -0
  36. data/lib/airbrake-ruby/query.rb +26 -11
  37. data/lib/airbrake-ruby/queue.rb +65 -0
  38. data/lib/airbrake-ruby/remote_settings/settings_data.rb +120 -0
  39. data/lib/airbrake-ruby/remote_settings.rb +145 -0
  40. data/lib/airbrake-ruby/request.rb +20 -6
  41. data/lib/airbrake-ruby/stashable.rb +15 -0
  42. data/lib/airbrake-ruby/stat.rb +34 -24
  43. data/lib/airbrake-ruby/sync_sender.rb +3 -2
  44. data/lib/airbrake-ruby/tdigest.rb +43 -58
  45. data/lib/airbrake-ruby/thread_pool.rb +138 -0
  46. data/lib/airbrake-ruby/timed_trace.rb +58 -0
  47. data/lib/airbrake-ruby/truncator.rb +10 -4
  48. data/lib/airbrake-ruby/version.rb +11 -1
  49. data/lib/airbrake-ruby.rb +219 -53
  50. data/spec/airbrake_spec.rb +428 -9
  51. data/spec/async_sender_spec.rb +26 -110
  52. data/spec/backtrace_spec.rb +44 -44
  53. data/spec/benchmark_spec.rb +33 -0
  54. data/spec/code_hunk_spec.rb +11 -11
  55. data/spec/config/processor_spec.rb +209 -0
  56. data/spec/config/validator_spec.rb +23 -6
  57. data/spec/config_spec.rb +77 -7
  58. data/spec/deploy_notifier_spec.rb +2 -2
  59. data/spec/{file_cache.rb → file_cache_spec.rb} +2 -4
  60. data/spec/filter_chain_spec.rb +28 -1
  61. data/spec/filters/dependency_filter_spec.rb +1 -1
  62. data/spec/filters/gem_root_filter_spec.rb +9 -9
  63. data/spec/filters/git_last_checkout_filter_spec.rb +21 -4
  64. data/spec/filters/git_repository_filter.rb +1 -1
  65. data/spec/filters/git_revision_filter_spec.rb +13 -11
  66. data/spec/filters/{keys_whitelist_spec.rb → keys_allowlist_spec.rb} +29 -28
  67. data/spec/filters/{keys_blacklist_spec.rb → keys_blocklist_spec.rb} +39 -29
  68. data/spec/filters/root_directory_filter_spec.rb +9 -9
  69. data/spec/filters/sql_filter_spec.rb +110 -55
  70. data/spec/filters/system_exit_filter_spec.rb +1 -1
  71. data/spec/filters/thread_filter_spec.rb +33 -31
  72. data/spec/fixtures/project_root/code.rb +9 -9
  73. data/spec/loggable_spec.rb +17 -0
  74. data/spec/monotonic_time_spec.rb +23 -0
  75. data/spec/{notice_notifier_spec → notice_notifier}/options_spec.rb +19 -21
  76. data/spec/notice_notifier_spec.rb +20 -80
  77. data/spec/notice_spec.rb +9 -11
  78. data/spec/performance_breakdown_spec.rb +11 -0
  79. data/spec/performance_notifier_spec.rb +360 -85
  80. data/spec/query_spec.rb +11 -0
  81. data/spec/queue_spec.rb +18 -0
  82. data/spec/remote_settings/settings_data_spec.rb +365 -0
  83. data/spec/remote_settings_spec.rb +230 -0
  84. data/spec/request_spec.rb +9 -0
  85. data/spec/response_spec.rb +8 -8
  86. data/spec/spec_helper.rb +9 -13
  87. data/spec/stashable_spec.rb +23 -0
  88. data/spec/stat_spec.rb +17 -15
  89. data/spec/sync_sender_spec.rb +14 -12
  90. data/spec/tdigest_spec.rb +6 -6
  91. data/spec/thread_pool_spec.rb +187 -0
  92. data/spec/timed_trace_spec.rb +125 -0
  93. data/spec/truncator_spec.rb +12 -12
  94. metadata +55 -18
@@ -1,4 +1,4 @@
1
- RSpec.describe Airbrake::Filters::KeysBlacklist do
1
+ RSpec.describe Airbrake::Filters::KeysBlocklist do
2
2
  subject { described_class.new(patterns) }
3
3
 
4
4
  let(:notice) { Airbrake::Notice.new(AirbrakeTestError.new) }
@@ -19,8 +19,8 @@ RSpec.describe Airbrake::Filters::KeysBlacklist do
19
19
  [/\Abon/],
20
20
  [
21
21
  { bongo: 'bango' },
22
- { bongo: '[Filtered]' }
23
- ]
22
+ { bongo: '[Filtered]' },
23
+ ],
24
24
  )
25
25
 
26
26
  context "and when a key is a hash" do
@@ -40,8 +40,8 @@ RSpec.describe Airbrake::Filters::KeysBlacklist do
40
40
  [:bingo],
41
41
  [
42
42
  { bingo: 'bango' },
43
- { bingo: '[Filtered]' }
44
- ]
43
+ { bingo: '[Filtered]' },
44
+ ],
45
45
  )
46
46
  end
47
47
 
@@ -51,8 +51,8 @@ RSpec.describe Airbrake::Filters::KeysBlacklist do
51
51
  ['bingo'],
52
52
  [
53
53
  { bingo: 'bango' },
54
- { bingo: '[Filtered]' }
55
- ]
54
+ { bingo: '[Filtered]' },
55
+ ],
56
56
  )
57
57
  end
58
58
 
@@ -62,8 +62,8 @@ RSpec.describe Airbrake::Filters::KeysBlacklist do
62
62
  ['bingo'],
63
63
  [
64
64
  { array: [{ bingo: 'bango' }, []] },
65
- { array: [{ bingo: '[Filtered]' }, []] }
66
- ]
65
+ { array: [{ bingo: '[Filtered]' }, []] },
66
+ ],
67
67
  )
68
68
  end
69
69
 
@@ -74,8 +74,8 @@ RSpec.describe Airbrake::Filters::KeysBlacklist do
74
74
  [proc { 'bongo' }, :bash],
75
75
  [
76
76
  { bingo: 'bango', bongo: 'bish', bash: 'bosh' },
77
- { bingo: 'bango', bongo: '[Filtered]', bash: '[Filtered]' }
78
- ]
77
+ { bingo: 'bango', bongo: '[Filtered]', bash: '[Filtered]' },
78
+ ],
79
79
  )
80
80
  end
81
81
 
@@ -85,16 +85,16 @@ RSpec.describe Airbrake::Filters::KeysBlacklist do
85
85
  [proc { Object.new }],
86
86
  [
87
87
  { bingo: 'bango', bongo: 'bish' },
88
- { bingo: 'bango', bongo: 'bish' }
89
- ]
88
+ { bingo: 'bango', bongo: 'bish' },
89
+ ],
90
90
  )
91
91
 
92
92
  it "logs an error" do
93
93
  expect(Airbrake::Loggable.instance).to receive(:error).with(
94
- /KeysBlacklist is invalid.+patterns: \[#<Object:.+>\]/
94
+ /KeysBlocklist is invalid.+patterns: \[#<Object:.+>\]/,
95
95
  )
96
- keys_blacklist = described_class.new(patterns)
97
- keys_blacklist.call(notice)
96
+ keys_blocklist = described_class.new(patterns)
97
+ keys_blocklist.call(notice)
98
98
  end
99
99
  end
100
100
 
@@ -104,10 +104,10 @@ RSpec.describe Airbrake::Filters::KeysBlacklist do
104
104
  context "and when the filter is called once" do
105
105
  it "logs an error" do
106
106
  expect(Airbrake::Loggable.instance).to receive(:error).with(
107
- /KeysBlacklist is invalid.+patterns: \[#<Proc:.+>\]/
107
+ /KeysBlocklist is invalid.+patterns: \[#<Proc:.+>\]/,
108
108
  )
109
- keys_blacklist = described_class.new(patterns)
110
- keys_blacklist.call(notice)
109
+ keys_blocklist = described_class.new(patterns)
110
+ keys_blocklist.call(notice)
111
111
  end
112
112
  end
113
113
 
@@ -127,16 +127,16 @@ RSpec.describe Airbrake::Filters::KeysBlacklist do
127
127
  [Object.new],
128
128
  [
129
129
  { bingo: 'bango', bongo: 'bish' },
130
- { bingo: 'bango', bongo: 'bish' }
131
- ]
130
+ { bingo: 'bango', bongo: 'bish' },
131
+ ],
132
132
  )
133
133
 
134
134
  it "logs an error" do
135
135
  expect(Airbrake::Loggable.instance).to receive(:error).with(
136
- /KeysBlacklist is invalid.+patterns: \[#<Object:.+>\]/
136
+ /KeysBlocklist is invalid.+patterns: \[#<Object:.+>\]/,
137
137
  )
138
- keys_blacklist = described_class.new(patterns)
139
- keys_blacklist.call(notice)
138
+ keys_blocklist = described_class.new(patterns)
139
+ keys_blocklist.call(notice)
140
140
  end
141
141
  end
142
142
 
@@ -147,9 +147,19 @@ RSpec.describe Airbrake::Filters::KeysBlacklist do
147
147
  ['bish'],
148
148
  [
149
149
  { bongo: { bish: 'bash' } },
150
- { bongo: { bish: '[Filtered]' } }
151
- ]
150
+ { bongo: { bish: '[Filtered]' } },
151
+ ],
152
152
  )
153
+
154
+ it "doesn't mutate the original hash" do
155
+ params = { bongo: { bish: 'bash' } }
156
+ notice[:params] = params
157
+
158
+ blocklist = described_class.new([:bish])
159
+ blocklist.call(notice)
160
+
161
+ expect(params[:bongo][:bish]).to eq('bash')
162
+ end
153
163
  end
154
164
 
155
165
  context "and it is recursive" do
@@ -161,8 +171,8 @@ RSpec.describe Airbrake::Filters::KeysBlacklist do
161
171
  ['bango'],
162
172
  [
163
173
  bongo,
164
- { bingo: { bango: '[Filtered]' } }
165
- ]
174
+ { bingo: { bango: '[Filtered]' } },
175
+ ],
166
176
  )
167
177
  end
168
178
  end
@@ -177,7 +187,7 @@ RSpec.describe Airbrake::Filters::KeysBlacklist do
177
187
 
178
188
  subject.call(notice)
179
189
  expect(notice[:context][:url]).to(
180
- eq 'http://localhost:3000/crash?foo=bar&baz=bongo&bish=[Filtered]&color=%23FFAAFF'
190
+ eq('http://localhost:3000/crash?foo=bar&baz=bongo&bish=[Filtered]&color=%23FFAAFF'),
181
191
  )
182
192
  end
183
193
  end
@@ -5,35 +5,35 @@ RSpec.describe Airbrake::Filters::RootDirectoryFilter do
5
5
  let(:notice) { Airbrake::Notice.new(AirbrakeTestError.new) }
6
6
 
7
7
  it "replaces root directory in the backtrace with a label" do
8
- # rubocop:disable Metrics/LineLength
8
+ # rubocop:disable Layout/LineLength
9
9
  notice[:errors].first[:backtrace] = [
10
10
  { file: "/home/kyrylo/code/airbrake/ruby/spec/spec_helper.rb" },
11
11
  { file: "#{root_directory}/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb " },
12
12
  { file: "/opt/rubies/ruby-2.2.2/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb" },
13
- { file: "#{root_directory}/gems/rspec-core-3.3.2/exe/rspec" }
13
+ { file: "#{root_directory}/gems/rspec-core-3.3.2/exe/rspec" },
14
14
  ]
15
- # rubocop:enable Metrics/LineLength
15
+ # rubocop:enable Layout/LineLength
16
16
 
17
17
  subject.call(notice)
18
18
 
19
- # rubocop:disable Metrics/LineLength
19
+ # rubocop:disable Layout/LineLength
20
20
  expect(notice[:errors].first[:backtrace]).to(
21
21
  eq(
22
22
  [
23
23
  { file: "/home/kyrylo/code/airbrake/ruby/spec/spec_helper.rb" },
24
24
  { file: "/PROJECT_ROOT/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb " },
25
25
  { file: "/opt/rubies/ruby-2.2.2/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb" },
26
- { file: "/PROJECT_ROOT/gems/rspec-core-3.3.2/exe/rspec" }
27
- ]
28
- )
26
+ { file: "/PROJECT_ROOT/gems/rspec-core-3.3.2/exe/rspec" },
27
+ ],
28
+ ),
29
29
  )
30
- # rubocop:enable Metrics/LineLength
30
+ # rubocop:enable Layout/LineLength
31
31
  end
32
32
 
33
33
  it "does not filter file when it is nil" do
34
34
  expect(notice[:errors].first[:file]).to be_nil
35
35
  expect { subject.call(notice) }.not_to(
36
- change { notice[:errors].first[:file] }
36
+ change { notice[:errors].first[:file] },
37
37
  )
38
38
  end
39
39
  end
@@ -10,210 +10,265 @@ RSpec.describe Airbrake::Filters::SqlFilter do
10
10
  end
11
11
  end
12
12
 
13
+ shared_examples "query blocklisting" do |query, opts|
14
+ it "ignores '#{query}'" do
15
+ filter = described_class.new('postgres')
16
+ q = Airbrake::Query.new(query: query, method: 'GET', route: '/', timing: 1)
17
+ filter.call(q)
18
+
19
+ expect(q.ignored?).to eq(opts[:should_ignore])
20
+ end
21
+ end
22
+
13
23
  ALL_DIALECTS = %i[mysql postgres sqlite cassandra oracle].freeze
14
24
 
15
- # rubocop:disable Metrics/LineLength
25
+ # rubocop:disable Layout/LineLength
16
26
  [
17
27
  {
18
28
  input: 'SELECT * FROM things;',
19
29
  output: 'SELECT * FROM things;',
20
- dialects: ALL_DIALECTS
30
+ dialects: ALL_DIALECTS,
21
31
  }, {
22
32
  input: "SELECT `t001`.`c2` FROM `t001` WHERE `t001`.`c2` = 'value' AND c3=\"othervalue\" LIMIT ?",
23
33
  output: "SELECT `t001`.`c2` FROM `t001` WHERE `t001`.`c2` = ? AND c3=? LIMIT ?",
24
- dialects: %i[mysql]
34
+ dialects: %i[mysql],
25
35
  }, {
26
36
  input: "SELECT * FROM t WHERE foo=\"bar/*\" AND baz=\"whatever */qux\"",
27
37
  output: "SELECT * FROM t WHERE foo=? AND baz=?",
28
- dialects: %i[mysql]
38
+ dialects: %i[mysql],
29
39
  }, {
30
40
  input: "SELECT * FROM t WHERE foo='bar/*' AND baz='whatever */qux'",
31
41
  output: "SELECT * FROM t WHERE foo=? AND baz=?",
32
- dialects: ALL_DIALECTS
42
+ dialects: ALL_DIALECTS,
33
43
  }, {
34
44
  input: "SELECT \"t001\".\"c2\" FROM \"t001\" WHERE \"t001\".\"c2\" = 'value' AND c3=1234 LIMIT 1",
35
45
  output: "SELECT \"t001\".\"c2\" FROM \"t001\" WHERE \"t001\".\"c2\" = ? AND c3=? LIMIT ?",
36
- dialects: %i[postgres oracle]
46
+ dialects: %i[postgres oracle],
37
47
  }, {
38
48
  input: "SELECT * FROM t WHERE foo=\"bar--\" AND\n baz=\"qux--\"",
39
49
  output: "SELECT * FROM t WHERE foo=? AND\n baz=?",
40
- dialects: %i[mysql]
50
+ dialects: %i[mysql],
41
51
  }, {
42
52
  input: "SELECT * FROM t WHERE foo='bar--' AND\n baz='qux--'",
43
53
  output: "SELECT * FROM t WHERE foo=? AND\n baz=?",
44
- dialects: ALL_DIALECTS
54
+ dialects: ALL_DIALECTS,
45
55
  }, {
46
56
  input: "SELECT * FROM foo WHERE bar='baz' /* Hide Me */",
47
57
  output: "SELECT * FROM foo WHERE bar=? ?",
48
- dialects: ALL_DIALECTS
58
+ dialects: ALL_DIALECTS,
49
59
  }, {
50
60
  input: "SELECT * FROM foobar WHERE password='hunter2'\n-- No peeking!",
51
61
  output: "SELECT * FROM foobar WHERE password=?\n?",
52
- dialects: ALL_DIALECTS
62
+ dialects: ALL_DIALECTS,
53
63
  }, {
54
64
  input: "SELECT foo, bar FROM baz WHERE password='hunter2' # Secret",
55
65
  output: "SELECT foo, bar FROM baz WHERE password=? ?",
56
- dialects: ALL_DIALECTS
66
+ dialects: ALL_DIALECTS,
57
67
  }, {
58
68
  input: "SELECT \"col1\", \"col2\" from \"table\" WHERE \"col3\"=E'foo\\'bar\\\\baz' AND country=e'foo\\'bar\\\\baz'",
59
69
  output: "SELECT \"col1\", \"col2\" from \"table\" WHERE \"col3\"=E?",
60
- dialects: %i[postgres]
70
+ dialects: %i[postgres],
61
71
  }, {
62
72
  input: "INSERT INTO `X` values(\"test\",0, 1 , 2, 'test')",
63
- output: "INSERT INTO `X` values(?,?, ? , ?, ?)",
64
- dialects: %i[mysql]
73
+ output: "INSERT INTO `X` values(?)",
74
+ dialects: %i[mysql],
75
+ }, {
76
+ input: "INSERT INTO `X` values(\"test\",0, 1 , 2, 'test')",
77
+ output: "INSERT INTO `X` values(?)",
78
+ dialects: %i[mysql],
65
79
  }, {
66
80
  input: "SELECT c11.col1, c22.col2 FROM table c11, table c22 WHERE value='nothing'",
67
81
  output: "SELECT c11.col1, c22.col2 FROM table c11, table c22 WHERE value=?",
68
- dialects: ALL_DIALECTS
82
+ dialects: ALL_DIALECTS,
69
83
  }, {
70
84
  input: "INSERT INTO X VALUES(1, 23456, 123.456, 99+100)",
71
- output: "INSERT INTO X VALUES(?, ?, ?, ?+?)",
72
- dialects: ALL_DIALECTS
85
+ output: "INSERT INTO X VALUES(?)",
86
+ dialects: ALL_DIALECTS,
73
87
  }, {
74
88
  input: "SELECT * FROM table WHERE name=\"foo\" AND value=\"don't\"",
75
89
  output: "SELECT * FROM table WHERE name=? AND value=?",
76
- dialects: %i[mysql]
90
+ dialects: %i[mysql],
77
91
  }, {
78
92
  input: "SELECT * FROM table WHERE name='foo' AND value = 'bar'",
79
93
  output: "SELECT * FROM table WHERE name=? AND value = ?",
80
- dialects: ALL_DIALECTS
94
+ dialects: ALL_DIALECTS,
81
95
  }, {
82
96
  input: "SELECT * FROM table WHERE col='foo\\''bar'",
83
97
  output: "SELECT * FROM table WHERE col=?",
84
- dialects: ALL_DIALECTS
98
+ dialects: ALL_DIALECTS,
85
99
  }, {
86
100
  input: "SELECT * FROM table WHERE col1='foo\"bar' AND col2='what\"ever'",
87
101
  output: "SELECT * FROM table WHERE col1=? AND col2=?",
88
- dialects: ALL_DIALECTS
102
+ dialects: ALL_DIALECTS,
89
103
  }, {
90
104
  input: "select * from accounts where accounts.name != 'dude\n newline' order by accounts.name",
91
105
  output: "select * from accounts where accounts.name != ? order by accounts.name",
92
- dialects: ALL_DIALECTS
106
+ dialects: ALL_DIALECTS,
93
107
  }, {
94
108
  input: "SELECT * FROM table WHERE col1=\"don't\" AND col2=\"won't\"",
95
109
  output: "SELECT * FROM table WHERE col1=? AND col2=?",
96
- dialects: %i[mysql]
110
+ dialects: %i[mysql],
97
111
  }, {
98
112
  input: "INSERT INTO X values('', 'jim''s ssn',0, 1 , 'jim''s son''s son', \"\"\"jim''s\"\" hat\", \"\\\"jim''s secret\\\"\")",
99
113
  output: "INSERT INTO X values(?, ?,?, ? , ?, ?, ?",
100
- dialects: %i[mysql]
114
+ dialects: %i[mysql],
101
115
  }, {
102
116
  input: "SELECT * FROM table WHERE name='foo\\' AND color='blue'",
103
117
  output: "SELECT * FROM table WHERE name=?",
104
- dialects: ALL_DIALECTS
118
+ dialects: ALL_DIALECTS,
105
119
  }, {
106
120
  input: "SELECT * FROM table WHERE foo=\"this string ends with a backslash\\\\\"",
107
121
  output: "SELECT * FROM table WHERE foo=?",
108
- dialects: %i[mysql]
122
+ dialects: %i[mysql],
109
123
  }, {
110
124
  input: "SELECT * FROM table WHERE foo='this string ends with a backslash\\\\'",
111
125
  output: "SELECT * FROM table WHERE foo=?",
112
- dialects: ALL_DIALECTS
126
+ dialects: ALL_DIALECTS,
113
127
  }, {
114
128
  # TODO: fix this example.
115
129
  input: "SELECT * FROM table WHERE name='foo\'' AND color='blue'",
116
130
  output: "Error: Airbrake::Query was not filtered",
117
- dialects: ALL_DIALECTS
131
+ dialects: ALL_DIALECTS,
118
132
  }, {
119
133
  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
134
+ output: "INSERT INTO X values(?)",
135
+ dialects: ALL_DIALECTS,
122
136
  }, {
123
137
  input: "SELECT * FROM t WHERE -- '\n bar='baz' -- '",
124
138
  output: "SELECT * FROM t WHERE ?\n bar=? ?",
125
- dialects: ALL_DIALECTS
139
+ dialects: ALL_DIALECTS,
126
140
  }, {
127
141
  input: "SELECT * FROM t WHERE /* ' */\n bar='baz' -- '",
128
142
  output: "SELECT * FROM t WHERE ?\n bar=? ?",
129
- dialects: ALL_DIALECTS
143
+ dialects: ALL_DIALECTS,
130
144
  }, {
131
145
  input: "SELECT * FROM t WHERE -- '\n /* ' */ c2='xxx' /* ' */\n c='x\n xx' -- '",
132
146
  output: "SELECT * FROM t WHERE ?\n ? c2=? ?\n c=? ?",
133
- dialects: ALL_DIALECTS
147
+ dialects: ALL_DIALECTS,
134
148
  }, {
135
149
  input: "SELECT * FROM t WHERE -- '\n c='x\n xx' -- '",
136
150
  output: "SELECT * FROM t WHERE ?\n c=? ?",
137
- dialects: ALL_DIALECTS
151
+ dialects: ALL_DIALECTS,
138
152
  }, {
139
153
  input: "SELECT * FROM foo WHERE col='value1' AND /* don't */ col2='value1' /* won't */",
140
154
  output: "SELECT * FROM foo WHERE col=? AND ? col2=? ?",
141
- dialects: ALL_DIALECTS
155
+ dialects: ALL_DIALECTS,
142
156
  }, {
143
157
  input: "SELECT * FROM table WHERE foo='bar' AND baz=\"nothing to see here'",
144
158
  output: "Error: Airbrake::Query was not filtered",
145
- dialects: %i[mysql]
159
+ dialects: %i[mysql],
146
160
  }, {
147
161
  input: "SELECT * FROM table WHERE foo='bar' AND baz='nothing to see here",
148
162
  output: "Error: Airbrake::Query was not filtered",
149
- dialects: ALL_DIALECTS
163
+ dialects: ALL_DIALECTS,
150
164
  }, {
151
165
  input: "SELECT * FROM \"foo\" WHERE \"foo\" = $a$dollar quotes can be $b$nested$b$$a$ and bar = 'baz'",
152
166
  output: "SELECT * FROM \"foo\" WHERE \"foo\" = ? and bar = ?",
153
- dialects: %i[postgres]
167
+ dialects: %i[postgres],
154
168
  }, {
155
169
  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]
170
+ output: "INSERT INTO \"foo\" (?) RETURNING \"id\"",
171
+ dialects: %i[postgres],
158
172
  }, {
159
173
  input: "select * from foo where bar = 'some\\tthing' and baz = 10",
160
174
  output: "select * from foo where bar = ? and baz = ?",
161
- dialects: ALL_DIALECTS
175
+ dialects: ALL_DIALECTS,
162
176
  }, {
163
177
  input: "select * from users where user = 'user1\\' password = 'hunter 2' -- ->don't count this quote",
164
178
  output: "select * from users where user = ?",
165
- dialects: ALL_DIALECTS
179
+ dialects: ALL_DIALECTS,
166
180
  }, {
167
181
  input: "select * from foo where bar=q'[baz's]' and x=5",
168
182
  output: "select * from foo where bar=? and x=?",
169
- dialects: %i[oracle]
183
+ dialects: %i[oracle],
170
184
  }, {
171
185
  input: "select * from foo where bar=q'{baz's}' and x=5",
172
186
  output: "select * from foo where bar=? and x=?",
173
- dialects: %i[oracle]
187
+ dialects: %i[oracle],
174
188
  }, {
175
189
  input: "select * from foo where bar=q'<baz's>' and x=5",
176
190
  output: "select * from foo where bar=? and x=?",
177
- dialects: %i[oracle]
191
+ dialects: %i[oracle],
178
192
  }, {
179
193
  input: "select * from foo where bar=q'(baz's)' and x=5",
180
194
  output: "select * from foo where bar=? and x=?",
181
- dialects: %i[oracle]
195
+ dialects: %i[oracle],
182
196
  }, {
183
197
  input: "select * from foo where bar=0xabcdef123 and x=5",
184
198
  output: "select * from foo where bar=? and x=?",
185
- dialects: %i[cassandra sqlite]
199
+ dialects: %i[cassandra sqlite],
186
200
  }, {
187
201
  input: "select * from foo where bar=0x2F and x=5",
188
202
  output: "select * from foo where bar=? and x=?",
189
- dialects: %i[mysql cassandra sqlite]
203
+ dialects: %i[mysql cassandra sqlite],
190
204
  }, {
191
205
  input: "select * from foo where bar=1.234e-5 and x=5",
192
206
  output: "select * from foo where bar=? and x=?",
193
- dialects: ALL_DIALECTS
207
+ dialects: ALL_DIALECTS,
194
208
  }, {
195
209
  input: "select * from foo where bar=01234567-89ab-cdef-0123-456789abcdef and x=5",
196
210
  output: "select * from foo where bar=? and x=?",
197
- dialects: %i[postgres cassandra]
211
+ dialects: %i[postgres cassandra],
198
212
  }, {
199
213
  input: "select * from foo where bar={01234567-89ab-cdef-0123-456789abcdef} and x=5",
200
214
  output: "select * from foo where bar=? and x=?",
201
- dialects: %i[postgres]
215
+ dialects: %i[postgres],
202
216
  }, {
203
217
  input: "select * from foo where bar=0123456789abcdef0123456789abcdef and x=5",
204
218
  output: "select * from foo where bar=? and x=?",
205
- dialects: %i[postgtes]
219
+ dialects: %i[postgtes],
206
220
  }, {
207
221
  input: "select * from foo where bar={012-345678-9abc-def012345678-9abcdef} and x=5",
208
222
  output: "select * from foo where bar=? and x=?",
209
- dialects: %i[postgres]
223
+ dialects: %i[postgres],
210
224
  }, {
211
225
  input: "select * from foo where bar=true and x=FALSE",
212
226
  output: "select * from foo where bar=? and x=?",
213
- dialects: %i[mysql postgres cassandra sqlite]
227
+ dialects: %i[mysql postgres cassandra sqlite],
214
228
  }
215
229
  ].each do |test|
216
230
  include_examples 'query filtering', test
217
231
  end
218
- # rubocop:enable Metrics/LineLength
232
+ # rubocop:enable Layout/LineLength
233
+
234
+ [
235
+ 'COMMIT',
236
+ 'commit',
237
+ 'BEGIN',
238
+ 'begin',
239
+ 'SET time zone ?',
240
+ 'set time zone ?',
241
+ 'SHOW max_identifier_length',
242
+ 'show max_identifier_length',
243
+
244
+ 'WITH pk_constraint AS ( SELECT conrelid, unnest(conkey) AS connum ' \
245
+ 'FROM pg_constraint WHERE contype = ? AND conrelid = ?::regclass ), ' \
246
+ 'cons AS ( SELECT conrelid, connum, row_number() OVER() AS rownum FROM ' \
247
+ 'pk_constraint ) SELECT attr.attname FROM pg_attribute attr INNER JOIN ' \
248
+ 'cons ON attr.attrelid = cons.conrelid AND attr.attnum = cons.connum ' \
249
+ 'ORDER BY cons.rownum',
250
+
251
+ 'SELECT c.relname FROM pg_class c LEFT JOIN pg_namespace n ON ' \
252
+ 'n.oid = c.relnamespace WHERE n.nspname = ANY (?)',
253
+
254
+ 'SELECT a.attname FROM ( SELECT indrelid, indkey, generate_subscripts(?) ' \
255
+ 'idx FROM pg_index WHERE indrelid = ?::regclass AND indisprimary ) i ' \
256
+ 'JOIN pg_attribute a ON a.attrelid = i.indrelid AND ' \
257
+ 'a.attnum = i.indkey[i.idx] ORDER BY i.idx',
258
+
259
+ 'SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, ' \
260
+ 't.typtype, t.typbasetype FROM pg_type as t LEFT JOIN pg_range as r ON ' \
261
+ 'oid = rngtypid WHERE t.typname IN (?) OR t.typtype IN (?) OR t.typinput ' \
262
+ '= ?::regprocedure OR t.typelem != ?',
263
+
264
+ 'SELECT t.oid, t.typname FROM pg_type as t WHERE t.typname IN (?)',
265
+ ].each do |query|
266
+ include_examples 'query blocklisting', query, should_ignore: true
267
+ end
268
+
269
+ [
270
+ 'UPDATE "users" SET "last_sign_in_at" = ? WHERE "users"."id" = ?',
271
+ ].each do |query|
272
+ include_examples 'query blocklisting', query, should_ignore: false
273
+ end
219
274
  end
@@ -2,7 +2,7 @@ RSpec.describe Airbrake::Filters::SystemExitFilter do
2
2
  it "marks SystemExit exceptions as ignored" do
3
3
  notice = Airbrake::Notice.new(SystemExit.new)
4
4
  expect { subject.call(notice) }.to(
5
- change { notice.ignored? }.from(false).to(true)
5
+ change { notice.ignored? }.from(false).to(true),
6
6
  )
7
7
  end
8
8
 
@@ -77,13 +77,13 @@ RSpec.describe Airbrake::Filters::ThreadFilter do
77
77
  {
78
78
  bish: {
79
79
  bash: 'foo',
80
- bosh: Object.new
81
- }
82
- }
83
- ]
84
- }
80
+ bosh: Object.new,
81
+ },
82
+ },
83
+ ],
84
+ },
85
85
  },
86
- 123
86
+ 123,
87
87
  ]
88
88
  end
89
89
 
@@ -103,15 +103,15 @@ RSpec.describe Airbrake::Filters::ThreadFilter do
103
103
  {
104
104
  bish: {
105
105
  bash: 'foo',
106
- bosh: /\A#<Object:.+>\z/
107
- }
108
- }
109
- ]
110
- }
106
+ bosh: /\A#<Object:.+>\z/,
107
+ },
108
+ },
109
+ ],
110
+ },
111
111
  },
112
- 123
113
- ]
114
- )
112
+ 123,
113
+ ],
114
+ ),
115
115
  )
116
116
  end
117
117
  end
@@ -194,13 +194,13 @@ RSpec.describe Airbrake::Filters::ThreadFilter do
194
194
  {
195
195
  bish: {
196
196
  bash: 'foo',
197
- bosh: Object.new
198
- }
199
- }
200
- ]
201
- }
197
+ bosh: Object.new,
198
+ },
199
+ },
200
+ ],
201
+ },
202
202
  },
203
- 123
203
+ 123,
204
204
  ]
205
205
  end
206
206
 
@@ -220,15 +220,15 @@ RSpec.describe Airbrake::Filters::ThreadFilter do
220
220
  {
221
221
  bish: {
222
222
  bash: 'foo',
223
- bosh: /\A#<Object:.+>\z/
224
- }
225
- }
226
- ]
227
- }
223
+ bosh: /\A#<Object:.+>\z/,
224
+ },
225
+ },
226
+ ],
227
+ },
228
228
  },
229
- 123
230
- ]
231
- )
229
+ 123,
230
+ ],
231
+ ),
232
232
  )
233
233
  end
234
234
  end
@@ -245,12 +245,12 @@ RSpec.describe Airbrake::Filters::ThreadFilter do
245
245
 
246
246
  it "appends thread inspect (self)" do
247
247
  subject.call(notice)
248
- expect(notice[:params][:thread][:self]).to match(/\A#<Thread:.+ run>\z/)
248
+ expect(notice[:params][:thread][:self]).to match(/\A#<Thread:.+>\z/)
249
249
  end
250
250
 
251
251
  it "appends thread group" do
252
252
  subject.call(notice)
253
- expect(notice[:params][:thread][:group][0]).to match(/\A#<Thread:.+ run>\z/)
253
+ expect(notice[:params][:thread][:group][0]).to match(/\A#<Thread:.+>\z/)
254
254
  end
255
255
 
256
256
  it "appends priority" do
@@ -258,7 +258,9 @@ RSpec.describe Airbrake::Filters::ThreadFilter do
258
258
  expect(notice[:params][:thread][:priority]).to eq(0)
259
259
  end
260
260
 
261
- it "appends safe_level", skip: Airbrake::JRUBY do
261
+ it "appends safe_level", skip: (
262
+ "Not supported on this version of Ruby." unless Airbrake::HAS_SAFE_LEVEL
263
+ ) do
262
264
  subject.call(notice)
263
265
  expect(notice[:params][:thread][:safe_level]).to eq(0)
264
266
  end