airbrake-ruby 4.13.3-java → 5.0.0.rc.1-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/lib/airbrake-ruby.rb +23 -32
  3. data/lib/airbrake-ruby/async_sender.rb +1 -1
  4. data/lib/airbrake-ruby/config.rb +65 -13
  5. data/lib/airbrake-ruby/config/processor.rb +80 -0
  6. data/lib/airbrake-ruby/config/validator.rb +4 -0
  7. data/lib/airbrake-ruby/filter_chain.rb +15 -1
  8. data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +2 -1
  9. data/lib/airbrake-ruby/filters/{keys_whitelist.rb → keys_allowlist.rb} +3 -3
  10. data/lib/airbrake-ruby/filters/{keys_blacklist.rb → keys_blocklist.rb} +3 -3
  11. data/lib/airbrake-ruby/filters/keys_filter.rb +5 -5
  12. data/lib/airbrake-ruby/notice_notifier.rb +6 -0
  13. data/lib/airbrake-ruby/performance_notifier.rb +1 -1
  14. data/lib/airbrake-ruby/remote_settings.rb +128 -0
  15. data/lib/airbrake-ruby/remote_settings/settings_data.rb +116 -0
  16. data/lib/airbrake-ruby/sync_sender.rb +1 -1
  17. data/lib/airbrake-ruby/thread_pool.rb +1 -0
  18. data/lib/airbrake-ruby/version.rb +1 -1
  19. data/spec/airbrake_spec.rb +71 -36
  20. data/spec/config/processor_spec.rb +223 -0
  21. data/spec/config/validator_spec.rb +18 -1
  22. data/spec/config_spec.rb +38 -6
  23. data/spec/filter_chain_spec.rb +27 -0
  24. data/spec/filters/git_last_checkout_filter_spec.rb +20 -3
  25. data/spec/filters/{keys_whitelist_spec.rb → keys_allowlist_spec.rb} +10 -10
  26. data/spec/filters/{keys_blacklist_spec.rb → keys_blocklist_spec.rb} +10 -10
  27. data/spec/filters/sql_filter_spec.rb +3 -3
  28. data/spec/notice_notifier/options_spec.rb +4 -4
  29. data/spec/performance_notifier_spec.rb +2 -2
  30. data/spec/remote_settings/settings_data_spec.rb +327 -0
  31. data/spec/remote_settings_spec.rb +212 -0
  32. data/spec/sync_sender_spec.rb +3 -1
  33. data/spec/thread_pool_spec.rb +25 -5
  34. metadata +20 -12
@@ -0,0 +1,223 @@
1
+ RSpec.describe Airbrake::Config::Processor do
2
+ let(:notifier) { Airbrake::NoticeNotifier.new }
3
+
4
+ describe "#process_blocklist" do
5
+ let(:config) { Airbrake::Config.new(blocklist_keys: %w[a b c]) }
6
+
7
+ context "when there ARE blocklist keys" do
8
+ it "adds the blocklist filter" do
9
+ described_class.new(config).process_blocklist(notifier)
10
+ expect(notifier.has_filter?(Airbrake::Filters::KeysBlocklist)).to eq(true)
11
+ end
12
+ end
13
+
14
+ context "when there are NO blocklist keys" do
15
+ let(:config) { Airbrake::Config.new(blocklist_keys: %w[]) }
16
+
17
+ it "doesn't add the blocklist filter" do
18
+ described_class.new(config).process_blocklist(notifier)
19
+ expect(notifier.has_filter?(Airbrake::Filters::KeysBlocklist))
20
+ .to eq(false)
21
+ end
22
+ end
23
+ end
24
+
25
+ describe "#process_allowlist" do
26
+ let(:config) { Airbrake::Config.new(allowlist_keys: %w[a b c]) }
27
+
28
+ context "when there ARE allowlist keys" do
29
+ it "adds the allowlist filter" do
30
+ described_class.new(config).process_allowlist(notifier)
31
+ expect(notifier.has_filter?(Airbrake::Filters::KeysAllowlist)).to eq(true)
32
+ end
33
+ end
34
+
35
+ context "when there are NO allowlist keys" do
36
+ let(:config) { Airbrake::Config.new(allowlist_keys: %w[]) }
37
+
38
+ it "doesn't add the allowlist filter" do
39
+ described_class.new(config).process_allowlist(notifier)
40
+ expect(notifier.has_filter?(Airbrake::Filters::KeysAllowlist))
41
+ .to eq(false)
42
+ end
43
+ end
44
+ end
45
+
46
+ describe "#process_remote_configuration" do
47
+ context "when the config doesn't define a project_id" do
48
+ let(:config) { Airbrake::Config.new(project_id: nil) }
49
+
50
+ it "doesn't set remote settings" do
51
+ expect(Airbrake::RemoteSettings).not_to receive(:poll)
52
+ described_class.new(config).process_remote_configuration
53
+ end
54
+ end
55
+
56
+ context "when the config defines a project_id" do
57
+ context "and when remote configuration is false" do
58
+ let(:config) do
59
+ Airbrake::Config.new(project_id: 123, __remote_configuration: false)
60
+ end
61
+
62
+ it "doesn't set remote settings" do
63
+ expect(Airbrake::RemoteSettings).not_to receive(:poll)
64
+ described_class.new(config).process_remote_configuration
65
+ end
66
+ end
67
+
68
+ context "and when remote configuration is true" do
69
+ let(:config) do
70
+ Airbrake::Config.new(project_id: 123, __remote_configuration: true)
71
+ end
72
+
73
+ it "sets remote settings" do
74
+ expect(Airbrake::RemoteSettings).to receive(:poll)
75
+ described_class.new(config).process_remote_configuration
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ describe "#add_filters" do
82
+ context "when there's a root directory" do
83
+ let(:config) { Airbrake::Config.new(root_directory: '/abc') }
84
+
85
+ it "adds RootDirectoryFilter" do
86
+ described_class.new(config).add_filters(notifier)
87
+ expect(notifier.has_filter?(Airbrake::Filters::RootDirectoryFilter))
88
+ .to eq(true)
89
+ end
90
+
91
+ it "adds GitRevisionFilter" do
92
+ described_class.new(config).add_filters(notifier)
93
+ expect(notifier.has_filter?(Airbrake::Filters::GitRevisionFilter))
94
+ .to eq(true)
95
+ end
96
+
97
+ it "adds GitRepositoryFilter" do
98
+ described_class.new(config).add_filters(notifier)
99
+ expect(notifier.has_filter?(Airbrake::Filters::GitRepositoryFilter))
100
+ .to eq(true)
101
+ end
102
+
103
+ it "adds GitLastCheckoutFilter" do
104
+ described_class.new(config).add_filters(notifier)
105
+ expect(notifier.has_filter?(Airbrake::Filters::GitLastCheckoutFilter))
106
+ .to eq(true)
107
+ end
108
+ end
109
+
110
+ context "when there's NO root directory" do
111
+ let(:config) { Airbrake::Config.new(root_directory: nil) }
112
+
113
+ it "doesn't add RootDirectoryFilter" do
114
+ described_class.new(config).add_filters(notifier)
115
+ expect(notifier.has_filter?(Airbrake::Filters::RootDirectoryFilter))
116
+ .to eq(false)
117
+ end
118
+
119
+ it "doesn't add GitRevisionFilter" do
120
+ described_class.new(config).add_filters(notifier)
121
+ expect(notifier.has_filter?(Airbrake::Filters::GitRevisionFilter))
122
+ .to eq(false)
123
+ end
124
+
125
+ it "doesn't add GitRepositoryFilter" do
126
+ described_class.new(config).add_filters(notifier)
127
+ expect(notifier.has_filter?(Airbrake::Filters::GitRepositoryFilter))
128
+ .to eq(false)
129
+ end
130
+
131
+ it "doesn't add GitLastCheckoutFilter" do
132
+ described_class.new(config).add_filters(notifier)
133
+ expect(notifier.has_filter?(Airbrake::Filters::GitLastCheckoutFilter))
134
+ .to eq(false)
135
+ end
136
+ end
137
+ end
138
+
139
+ describe "#poll_callback" do
140
+ let(:logger) { Logger.new(File::NULL) }
141
+
142
+ let(:config) do
143
+ Airbrake::Config.new(
144
+ project_id: 123,
145
+ __remote_configuration: true,
146
+ logger: logger,
147
+ )
148
+ end
149
+
150
+ let(:data) do
151
+ instance_double(Airbrake::RemoteSettings::SettingsData)
152
+ end
153
+
154
+ before do
155
+ allow(data).to receive(:to_h)
156
+ allow(data).to receive(:error_host)
157
+ allow(data).to receive(:apm_host)
158
+ allow(data).to receive(:error_notifications?)
159
+ allow(data).to receive(:performance_stats?)
160
+ end
161
+
162
+ it "logs given data" do
163
+ expect(logger).to receive(:debug).with(/applying remote settings/)
164
+ described_class.new(config).poll_callback(data)
165
+ end
166
+
167
+ it "sets the error_notifications option" do
168
+ config.error_notifications = false
169
+ expect(data).to receive(:error_notifications?).and_return(true)
170
+
171
+ described_class.new(config).poll_callback(data)
172
+ expect(config.error_notifications).to eq(true)
173
+ end
174
+
175
+ it "sets the performance_stats option" do
176
+ config.performance_stats = false
177
+ expect(data).to receive(:performance_stats?).and_return(true)
178
+
179
+ described_class.new(config).poll_callback(data)
180
+ expect(config.performance_stats).to eq(true)
181
+ end
182
+
183
+ context "when error_host returns a value" do
184
+ it "sets the error_host option" do
185
+ config.error_host = 'http://api.airbrake.io'
186
+ allow(data).to receive(:error_host).and_return('https://api.example.com')
187
+
188
+ described_class.new(config).poll_callback(data)
189
+ expect(config.error_host).to eq('https://api.example.com')
190
+ end
191
+ end
192
+
193
+ context "when error_host returns nil" do
194
+ it "doesn't modify the error_host option" do
195
+ config.error_host = 'http://api.airbrake.io'
196
+ allow(data).to receive(:error_host).and_return(nil)
197
+
198
+ described_class.new(config).poll_callback(data)
199
+ expect(config.error_host).to eq('http://api.airbrake.io')
200
+ end
201
+ end
202
+
203
+ context "when apm_host returns a value" do
204
+ it "sets the apm_host option" do
205
+ config.apm_host = 'http://api.airbrake.io'
206
+ allow(data).to receive(:apm_host).and_return('https://api.example.com')
207
+
208
+ described_class.new(config).poll_callback(data)
209
+ expect(config.apm_host).to eq('https://api.example.com')
210
+ end
211
+ end
212
+
213
+ context "when apm_host returns nil" do
214
+ it "doesn't modify the apm_host option" do
215
+ config.apm_host = 'http://api.airbrake.io'
216
+ allow(data).to receive(:apm_host).and_return(nil)
217
+
218
+ described_class.new(config).poll_callback(data)
219
+ expect(config.apm_host).to eq('http://api.airbrake.io')
220
+ end
221
+ end
222
+ end
223
+ end
@@ -169,7 +169,7 @@ RSpec.describe Airbrake::Config::Validator do
169
169
  }
170
170
  end
171
171
 
172
- it "returns a rejected promise" do
172
+ it "returns a resolved promise" do
173
173
  promise = described_class.check_notify_ability(config)
174
174
  expect(promise).to be_resolved
175
175
  end
@@ -180,5 +180,22 @@ RSpec.describe Airbrake::Config::Validator do
180
180
  described_class.check_notify_ability(config)
181
181
  end
182
182
  end
183
+
184
+ context "when the error_notifications option is false" do
185
+ let(:config_params) do
186
+ {
187
+ project_id: valid_id,
188
+ project_key: valid_key,
189
+ error_notifications: false,
190
+ }
191
+ end
192
+
193
+ it "returns a rejected promise" do
194
+ promise = described_class.check_notify_ability(config)
195
+ expect(promise.value).to eq(
196
+ 'error' => "error notifications are disabled",
197
+ )
198
+ end
199
+ end
183
200
  end
184
201
  end
@@ -10,19 +10,23 @@ RSpec.describe Airbrake::Config do
10
10
  its(:app_version) { is_expected.to be_nil }
11
11
  its(:versions) { is_expected.to be_empty }
12
12
  its(:host) { is_expected.to eq('https://api.airbrake.io') }
13
- its(:endpoint) { is_expected.not_to be_nil }
13
+ its(:error_host) { is_expected.to eq('https://api.airbrake.io') }
14
+ its(:apm_host) { is_expected.to eq('https://api.airbrake.io') }
15
+ its(:error_endpoint) { is_expected.not_to be_nil }
14
16
  its(:workers) { is_expected.to eq(1) }
15
17
  its(:queue_size) { is_expected.to eq(100) }
16
18
  its(:root_directory) { is_expected.to eq(Bundler.root.realpath.to_s) }
17
19
  its(:environment) { is_expected.to be_nil }
18
20
  its(:ignore_environments) { is_expected.to be_empty }
19
21
  its(:timeout) { is_expected.to be_nil }
20
- its(:blacklist_keys) { is_expected.to be_empty }
21
- its(:whitelist_keys) { is_expected.to be_empty }
22
+ its(:blocklist_keys) { is_expected.to be_empty }
23
+ its(:allowlist_keys) { is_expected.to be_empty }
22
24
  its(:performance_stats) { is_expected.to eq(true) }
23
25
  its(:performance_stats_flush_period) { is_expected.to eq(15) }
24
26
  its(:query_stats) { is_expected.to eq(true) }
25
27
  its(:job_stats) { is_expected.to eq(true) }
28
+ its(:error_notifications) { is_expected.to eq(true) }
29
+ its(:__remote_configuration) { is_expected.to eq(false) }
26
30
 
27
31
  describe "#new" do
28
32
  context "when user config is passed" do
@@ -63,13 +67,13 @@ RSpec.describe Airbrake::Config do
63
67
  end
64
68
  end
65
69
 
66
- describe "#endpoint" do
70
+ describe "#error_endpoint" do
67
71
  subject { described_class.new(valid_params.merge(user_config)) }
68
72
 
69
73
  context "when host ends with a URL with a slug with a trailing slash" do
70
74
  let(:user_config) { { host: 'https://localhost/bingo/' } }
71
75
 
72
- its(:endpoint) do
76
+ its(:error_endpoint) do
73
77
  is_expected.to eq(URI('https://localhost/bingo/api/v3/projects/1/notices'))
74
78
  end
75
79
  end
@@ -77,7 +81,7 @@ RSpec.describe Airbrake::Config do
77
81
  context "when host ends with a URL with a slug without a trailing slash" do
78
82
  let(:user_config) { { host: 'https://localhost/bingo' } }
79
83
 
80
- its(:endpoint) do
84
+ its(:error_endpoint) do
81
85
  is_expected.to eq(URI('https://localhost/api/v3/projects/1/notices'))
82
86
  end
83
87
  end
@@ -169,4 +173,32 @@ RSpec.describe Airbrake::Config do
169
173
  expect(subject.logger.level).to eq(Logger::WARN)
170
174
  end
171
175
  end
176
+
177
+ describe "#blacklist_keys=" do
178
+ before { allow(Kernel).to receive(:warn) }
179
+
180
+ it "sets blocklist_keys instead" do
181
+ subject.blacklist_keys = [1, 2, 3]
182
+ expect(subject.blocklist_keys).to eq([1, 2, 3])
183
+ end
184
+
185
+ it "prints a warning" do
186
+ expect(Kernel).to receive(:warn).with(/use blocklist_keys= instead/)
187
+ subject.blacklist_keys = [1, 2, 3]
188
+ end
189
+ end
190
+
191
+ describe "#whitelist_keys=" do
192
+ before { allow(Kernel).to receive(:warn) }
193
+
194
+ it "sets allowlist_keys instead" do
195
+ subject.whitelist_keys = [1, 2, 3]
196
+ expect(subject.allowlist_keys).to eq([1, 2, 3])
197
+ end
198
+
199
+ it "prints a warning" do
200
+ expect(Kernel).to receive(:warn).with(/use allowlist_keys= instead/)
201
+ subject.whitelist_keys = [1, 2, 3]
202
+ end
203
+ end
172
204
  end
@@ -89,4 +89,31 @@ RSpec.describe Airbrake::FilterChain do
89
89
  expect(subject.inspect).to eq('[Proc]')
90
90
  end
91
91
  end
92
+
93
+ describe "#includes?" do
94
+ context "when a custom filter class is included in the filter chain" do
95
+ it "returns true" do
96
+ klass = Class.new {}
97
+
98
+ subject.add_filter(klass.new)
99
+ expect(subject.includes?(klass)).to eq(true)
100
+ end
101
+ end
102
+
103
+ context "when Proc filter class is included in the filter chain" do
104
+ it "returns true" do
105
+ subject.add_filter(proc {})
106
+ expect(subject.includes?(Proc)).to eq(true)
107
+ end
108
+ end
109
+
110
+ context "when filter class is NOT included in the filter chain" do
111
+ it "returns false" do
112
+ klass = Class.new {}
113
+
114
+ subject.add_filter(proc {})
115
+ expect(subject.includes?(klass)).to eq(false)
116
+ end
117
+ end
118
+ end
92
119
  end
@@ -21,24 +21,41 @@ RSpec.describe Airbrake::Filters::GitLastCheckoutFilter do
21
21
  end
22
22
 
23
23
  context "when .git directory exists" do
24
- before { subject.call(notice) }
24
+ context "when AIRBRAKE_DEPLOY_USERNAME env variable is set" do
25
+ before { ENV['AIRBRAKE_DEPLOY_USERNAME'] = 'deployer' }
25
26
 
26
- it "attaches last checkouted username" do
27
- expect(notice[:context][:lastCheckout][:username]).not_to be_empty
27
+ it "attaches username from the environment" do
28
+ subject.call(notice)
29
+ expect(notice[:context][:lastCheckout][:username]).to eq('deployer')
30
+ end
31
+ end
32
+
33
+ context "when AIRBRAKE_DEPLOY_USERNAME env variable is NOT set" do
34
+ before { ENV['AIRBRAKE_DEPLOY_USERNAME'] = nil }
35
+
36
+ it "attaches last checkouted username" do
37
+ subject.call(notice)
38
+ username = notice[:context][:lastCheckout][:username]
39
+ expect(username).not_to be_empty
40
+ expect(username).not_to be_nil
41
+ end
28
42
  end
29
43
 
30
44
  it "attaches last checkouted email" do
45
+ subject.call(notice)
31
46
  expect(notice[:context][:lastCheckout][:email]).to(
32
47
  match(/\A\w+[\w.-]*@\w+\.?\w+?\z/),
33
48
  )
34
49
  end
35
50
 
36
51
  it "attaches last checkouted revision" do
52
+ subject.call(notice)
37
53
  expect(notice[:context][:lastCheckout][:revision]).not_to be_empty
38
54
  expect(notice[:context][:lastCheckout][:revision].size).to eq(40)
39
55
  end
40
56
 
41
57
  it "attaches last checkouted time" do
58
+ subject.call(notice)
42
59
  expect(notice[:context][:lastCheckout][:time]).not_to be_empty
43
60
  expect(notice[:context][:lastCheckout][:time].size).to eq(25)
44
61
  end
@@ -1,4 +1,4 @@
1
- RSpec.describe Airbrake::Filters::KeysWhitelist do
1
+ RSpec.describe Airbrake::Filters::KeysAllowlist do
2
2
  subject { described_class.new(patterns) }
3
3
 
4
4
  let(:notice) { Airbrake::Notice.new(AirbrakeTestError.new) }
@@ -70,10 +70,10 @@ RSpec.describe Airbrake::Filters::KeysWhitelist do
70
70
 
71
71
  it "logs an error" do
72
72
  expect(Airbrake::Loggable.instance).to receive(:error).with(
73
- /KeysWhitelist is invalid.+patterns: \[#<Object:.+>\]/,
73
+ /KeysAllowlist is invalid.+patterns: \[#<Object:.+>\]/,
74
74
  )
75
- keys_whitelist = described_class.new(patterns)
76
- keys_whitelist.call(notice)
75
+ keys_allowlist = described_class.new(patterns)
76
+ keys_allowlist.call(notice)
77
77
  end
78
78
  end
79
79
 
@@ -83,10 +83,10 @@ RSpec.describe Airbrake::Filters::KeysWhitelist do
83
83
  context "and when the filter is called once" do
84
84
  it "logs an error" do
85
85
  expect(Airbrake::Loggable.instance).to receive(:error).with(
86
- /KeysWhitelist is invalid.+patterns: \[#<Proc:.+>\]/,
86
+ /KeysAllowlist is invalid.+patterns: \[#<Proc:.+>\]/,
87
87
  )
88
- keys_whitelist = described_class.new(patterns)
89
- keys_whitelist.call(notice)
88
+ keys_allowlist = described_class.new(patterns)
89
+ keys_allowlist.call(notice)
90
90
  end
91
91
 
92
92
  include_examples(
@@ -113,10 +113,10 @@ RSpec.describe Airbrake::Filters::KeysWhitelist do
113
113
 
114
114
  it "logs an error" do
115
115
  expect(Airbrake::Loggable.instance).to receive(:error).with(
116
- /KeysWhitelist is invalid.+patterns: \[#<Object:.+>\]/,
116
+ /KeysAllowlist is invalid.+patterns: \[#<Object:.+>\]/,
117
117
  )
118
- keys_whitelist = described_class.new(patterns)
119
- keys_whitelist.call(notice)
118
+ keys_allowlist = described_class.new(patterns)
119
+ keys_allowlist.call(notice)
120
120
  end
121
121
  end
122
122