airbrake-ruby 4.1.0 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
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