airbrake-ruby 5.0.0-java → 5.1.0-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.
- checksums.yaml +4 -4
- data/lib/airbrake-ruby.rb +1 -0
- data/lib/airbrake-ruby/config/processor.rb +5 -19
- data/lib/airbrake-ruby/remote_settings.rb +2 -43
- data/lib/airbrake-ruby/remote_settings/callback.rb +44 -0
- data/lib/airbrake-ruby/remote_settings/settings_data.rb +3 -7
- data/lib/airbrake-ruby/version.rb +1 -1
- data/spec/config/processor_spec.rb +10 -85
- data/spec/filters/git_last_checkout_filter_spec.rb +1 -1
- data/spec/remote_settings/callback_spec.rb +143 -0
- data/spec/remote_settings/settings_data_spec.rb +27 -44
- data/spec/remote_settings_spec.rb +4 -70
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b6e38e61b0caa09af3b9a0e0bf2deb678369bfe2c31e5923f9ec64d93f8456a7
|
4
|
+
data.tar.gz: 1936144cbf286ab6e43fbd8874d4093357ee4f7c2a7c43f0d7e507290e081d53
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 565a30fe46379d2da490d164e6d14462cba6bbb7817e8a008e676a396aa117abd6ac416cdc5b6c019204a2ab4b93c7d6cdd257c02c8ac4a335722463414f3933
|
7
|
+
data.tar.gz: 371aea04d52fef881b2b74c9781f0788b536711e1cfeecfd328ee6778f629e7f19eab793a557f42f6fa1603709ae7e20b1ec1abba527f26149acb3581a633f6c
|
data/lib/airbrake-ruby.rb
CHANGED
@@ -13,6 +13,7 @@ require 'airbrake-ruby/grouppable'
|
|
13
13
|
require 'airbrake-ruby/config'
|
14
14
|
require 'airbrake-ruby/config/validator'
|
15
15
|
require 'airbrake-ruby/config/processor'
|
16
|
+
require 'airbrake-ruby/remote_settings/callback'
|
16
17
|
require 'airbrake-ruby/remote_settings/settings_data'
|
17
18
|
require 'airbrake-ruby/remote_settings'
|
18
19
|
require 'airbrake-ruby/promise'
|
@@ -18,6 +18,7 @@ module Airbrake
|
|
18
18
|
@blocklist_keys = @config.blocklist_keys
|
19
19
|
@allowlist_keys = @config.allowlist_keys
|
20
20
|
@project_id = @config.project_id
|
21
|
+
@poll_callback = Airbrake::RemoteSettings::Callback.new(config)
|
21
22
|
end
|
22
23
|
|
23
24
|
# @param [Airbrake::NoticeNotifier] notifier
|
@@ -41,12 +42,11 @@ module Airbrake
|
|
41
42
|
# @return [Airbrake::RemoteSettings]
|
42
43
|
def process_remote_configuration
|
43
44
|
return unless @project_id
|
45
|
+
return if @config.environment == 'test'
|
44
46
|
|
45
|
-
RemoteSettings.poll(
|
46
|
-
@
|
47
|
-
|
48
|
-
&method(:poll_callback)
|
49
|
-
)
|
47
|
+
RemoteSettings.poll(@project_id, @config.remote_config_host) do |data|
|
48
|
+
@poll_callback.call(data)
|
49
|
+
end
|
50
50
|
end
|
51
51
|
|
52
52
|
# @param [Airbrake::NoticeNotifier] notifier
|
@@ -65,20 +65,6 @@ module Airbrake
|
|
65
65
|
notifier.add_filter(filter.new(@config.root_directory))
|
66
66
|
end
|
67
67
|
end
|
68
|
-
|
69
|
-
# @param [Airbrake::RemoteSettings::SettingsData] data
|
70
|
-
# @return [void]
|
71
|
-
def poll_callback(data)
|
72
|
-
@config.logger.debug(
|
73
|
-
"#{LOG_LABEL} applying remote settings: #{data.to_h}",
|
74
|
-
)
|
75
|
-
|
76
|
-
@config.error_host = data.error_host if data.error_host
|
77
|
-
@config.apm_host = data.apm_host if data.apm_host
|
78
|
-
|
79
|
-
@config.error_notifications = data.error_notifications?
|
80
|
-
@config.performance_stats = data.performance_stats?
|
81
|
-
end
|
82
68
|
end
|
83
69
|
end
|
84
70
|
end
|
@@ -8,22 +8,11 @@ module Airbrake
|
|
8
8
|
# config.error_notifications = data.error_notifications?
|
9
9
|
# end
|
10
10
|
#
|
11
|
-
# When {#poll} is called, it will try to load remote settings from disk, so
|
12
|
-
# that it doesn't wait on the result from the API call.
|
13
|
-
#
|
14
|
-
# When {#stop_polling} is called, the current config will be dumped to disk.
|
15
|
-
#
|
16
11
|
# @since 5.0.0
|
17
12
|
# @api private
|
18
13
|
class RemoteSettings
|
19
14
|
include Airbrake::Loggable
|
20
15
|
|
21
|
-
# @return [String] the path to the persistent config
|
22
|
-
CONFIG_DUMP_PATH = File.join(
|
23
|
-
File.expand_path(__dir__),
|
24
|
-
'../../config/config.json',
|
25
|
-
).freeze
|
26
|
-
|
27
16
|
# @return [Hash{Symbol=>String}] metadata to be attached to every GET
|
28
17
|
# request
|
29
18
|
QUERY_PARAMS = URI.encode_www_form(
|
@@ -54,18 +43,11 @@ module Airbrake
|
|
54
43
|
@poll = nil
|
55
44
|
end
|
56
45
|
|
57
|
-
# Polls remote config of the given project in background.
|
58
|
-
# first (if exists).
|
46
|
+
# Polls remote config of the given project in background.
|
59
47
|
#
|
60
48
|
# @return [self]
|
61
49
|
def poll
|
62
50
|
@poll ||= Thread.new do
|
63
|
-
begin
|
64
|
-
load_config
|
65
|
-
rescue StandardError => ex
|
66
|
-
logger.error("#{LOG_LABEL} config loading failed: #{ex}")
|
67
|
-
end
|
68
|
-
|
69
51
|
@block.call(@data)
|
70
52
|
|
71
53
|
loop do
|
@@ -77,17 +59,11 @@ module Airbrake
|
|
77
59
|
self
|
78
60
|
end
|
79
61
|
|
80
|
-
# Stops the background poller thread.
|
62
|
+
# Stops the background poller thread.
|
81
63
|
#
|
82
64
|
# @return [void]
|
83
65
|
def stop_polling
|
84
66
|
@poll.kill if @poll
|
85
|
-
|
86
|
-
begin
|
87
|
-
dump_config
|
88
|
-
rescue StandardError => ex
|
89
|
-
logger.error("#{LOG_LABEL} config dumping failed: #{ex}")
|
90
|
-
end
|
91
67
|
end
|
92
68
|
|
93
69
|
private
|
@@ -124,22 +100,5 @@ module Airbrake
|
|
124
100
|
uri.query = QUERY_PARAMS
|
125
101
|
uri
|
126
102
|
end
|
127
|
-
|
128
|
-
def load_config
|
129
|
-
config_dir = File.dirname(CONFIG_DUMP_PATH)
|
130
|
-
Dir.mkdir(config_dir) unless File.directory?(config_dir)
|
131
|
-
|
132
|
-
return unless File.exist?(CONFIG_DUMP_PATH)
|
133
|
-
|
134
|
-
config = File.read(CONFIG_DUMP_PATH)
|
135
|
-
@data.merge!(JSON.parse(config))
|
136
|
-
end
|
137
|
-
|
138
|
-
def dump_config
|
139
|
-
config_dir = File.dirname(CONFIG_DUMP_PATH)
|
140
|
-
Dir.mkdir(config_dir) unless File.directory?(config_dir)
|
141
|
-
|
142
|
-
File.write(CONFIG_DUMP_PATH, JSON.dump(@data.to_h))
|
143
|
-
end
|
144
103
|
end
|
145
104
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Airbrake
|
2
|
+
class RemoteSettings
|
3
|
+
# Callback is a class that provides a callback for the config poller, which
|
4
|
+
# updates the local config according to the data.
|
5
|
+
#
|
6
|
+
# @api private
|
7
|
+
# @since 5.0.2
|
8
|
+
class Callback
|
9
|
+
def initialize(config)
|
10
|
+
@config = config
|
11
|
+
@orig_error_notifications = config.error_notifications
|
12
|
+
@orig_performance_stats = config.performance_stats
|
13
|
+
end
|
14
|
+
|
15
|
+
# @param [Airbrake::RemoteSettings::SettingsData] data
|
16
|
+
# @return [void]
|
17
|
+
def call(data)
|
18
|
+
@config.logger.debug do
|
19
|
+
"#{LOG_LABEL} applying remote settings: #{data.to_h}"
|
20
|
+
end
|
21
|
+
|
22
|
+
@config.error_host = data.error_host if data.error_host
|
23
|
+
@config.apm_host = data.apm_host if data.apm_host
|
24
|
+
|
25
|
+
process_error_notifications(data)
|
26
|
+
process_performance_stats(data)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def process_error_notifications(data)
|
32
|
+
return unless @orig_error_notifications
|
33
|
+
|
34
|
+
@config.error_notifications = data.error_notifications?
|
35
|
+
end
|
36
|
+
|
37
|
+
def process_performance_stats(data)
|
38
|
+
return unless @orig_performance_stats
|
39
|
+
|
40
|
+
@config.performance_stats = data.performance_stats?
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -58,17 +58,13 @@ module Airbrake
|
|
58
58
|
# @param [String] remote_config_host
|
59
59
|
# @return [String] where the config is stored on S3.
|
60
60
|
def config_route(remote_config_host)
|
61
|
-
if
|
62
|
-
return
|
63
|
-
CONFIG_ROUTE_PATTERN,
|
64
|
-
host: remote_config_host.chomp('/'),
|
65
|
-
project_id: @project_id,
|
66
|
-
)
|
61
|
+
if @data['config_route'] && !@data['config_route'].empty?
|
62
|
+
return remote_config_host.chomp('/') + '/' + @data['config_route']
|
67
63
|
end
|
68
64
|
|
69
65
|
format(
|
70
66
|
CONFIG_ROUTE_PATTERN,
|
71
|
-
host:
|
67
|
+
host: remote_config_host.chomp('/'),
|
72
68
|
project_id: @project_id,
|
73
69
|
)
|
74
70
|
end
|
@@ -53,9 +53,18 @@ RSpec.describe Airbrake::Config::Processor do
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
+
context "when the config sets environment to 'test'" do
|
57
|
+
let(:config) { Airbrake::Config.new(project_id: 123, environment: 'test') }
|
58
|
+
|
59
|
+
it "doesn't set remote settings" do
|
60
|
+
expect(Airbrake::RemoteSettings).not_to receive(:poll)
|
61
|
+
described_class.new(config).process_remote_configuration
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
56
65
|
context "when the config defines a project_id" do
|
57
66
|
let(:config) do
|
58
|
-
Airbrake::Config.new(project_id: 123)
|
67
|
+
Airbrake::Config.new(project_id: 123, environment: 'not-test')
|
59
68
|
end
|
60
69
|
|
61
70
|
it "sets remote settings" do
|
@@ -122,88 +131,4 @@ RSpec.describe Airbrake::Config::Processor do
|
|
122
131
|
end
|
123
132
|
end
|
124
133
|
end
|
125
|
-
|
126
|
-
describe "#poll_callback" do
|
127
|
-
let(:logger) { Logger.new(File::NULL) }
|
128
|
-
|
129
|
-
let(:config) do
|
130
|
-
Airbrake::Config.new(
|
131
|
-
project_id: 123,
|
132
|
-
logger: logger,
|
133
|
-
)
|
134
|
-
end
|
135
|
-
|
136
|
-
let(:data) do
|
137
|
-
instance_double(Airbrake::RemoteSettings::SettingsData)
|
138
|
-
end
|
139
|
-
|
140
|
-
before do
|
141
|
-
allow(data).to receive(:to_h)
|
142
|
-
allow(data).to receive(:error_host)
|
143
|
-
allow(data).to receive(:apm_host)
|
144
|
-
allow(data).to receive(:error_notifications?)
|
145
|
-
allow(data).to receive(:performance_stats?)
|
146
|
-
end
|
147
|
-
|
148
|
-
it "logs given data" do
|
149
|
-
expect(logger).to receive(:debug).with(/applying remote settings/)
|
150
|
-
described_class.new(config).poll_callback(data)
|
151
|
-
end
|
152
|
-
|
153
|
-
it "sets the error_notifications option" do
|
154
|
-
config.error_notifications = false
|
155
|
-
expect(data).to receive(:error_notifications?).and_return(true)
|
156
|
-
|
157
|
-
described_class.new(config).poll_callback(data)
|
158
|
-
expect(config.error_notifications).to eq(true)
|
159
|
-
end
|
160
|
-
|
161
|
-
it "sets the performance_stats option" do
|
162
|
-
config.performance_stats = false
|
163
|
-
expect(data).to receive(:performance_stats?).and_return(true)
|
164
|
-
|
165
|
-
described_class.new(config).poll_callback(data)
|
166
|
-
expect(config.performance_stats).to eq(true)
|
167
|
-
end
|
168
|
-
|
169
|
-
context "when error_host returns a value" do
|
170
|
-
it "sets the error_host option" do
|
171
|
-
config.error_host = 'http://api.airbrake.io'
|
172
|
-
allow(data).to receive(:error_host).and_return('https://api.example.com')
|
173
|
-
|
174
|
-
described_class.new(config).poll_callback(data)
|
175
|
-
expect(config.error_host).to eq('https://api.example.com')
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
context "when error_host returns nil" do
|
180
|
-
it "doesn't modify the error_host option" do
|
181
|
-
config.error_host = 'http://api.airbrake.io'
|
182
|
-
allow(data).to receive(:error_host).and_return(nil)
|
183
|
-
|
184
|
-
described_class.new(config).poll_callback(data)
|
185
|
-
expect(config.error_host).to eq('http://api.airbrake.io')
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
context "when apm_host returns a value" do
|
190
|
-
it "sets the apm_host option" do
|
191
|
-
config.apm_host = 'http://api.airbrake.io'
|
192
|
-
allow(data).to receive(:apm_host).and_return('https://api.example.com')
|
193
|
-
|
194
|
-
described_class.new(config).poll_callback(data)
|
195
|
-
expect(config.apm_host).to eq('https://api.example.com')
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
context "when apm_host returns nil" do
|
200
|
-
it "doesn't modify the apm_host option" do
|
201
|
-
config.apm_host = 'http://api.airbrake.io'
|
202
|
-
allow(data).to receive(:apm_host).and_return(nil)
|
203
|
-
|
204
|
-
described_class.new(config).poll_callback(data)
|
205
|
-
expect(config.apm_host).to eq('http://api.airbrake.io')
|
206
|
-
end
|
207
|
-
end
|
208
|
-
end
|
209
134
|
end
|
@@ -44,7 +44,7 @@ RSpec.describe Airbrake::Filters::GitLastCheckoutFilter do
|
|
44
44
|
it "attaches last checkouted email" do
|
45
45
|
subject.call(notice)
|
46
46
|
expect(notice[:context][:lastCheckout][:email]).to(
|
47
|
-
match(/\A\w+[\w.-]
|
47
|
+
match(/\A\w+[\w.-]*@(\w+\.)*\w+\z/),
|
48
48
|
)
|
49
49
|
end
|
50
50
|
|
@@ -0,0 +1,143 @@
|
|
1
|
+
RSpec.describe Airbrake::RemoteSettings::Callback do
|
2
|
+
describe "#call" do
|
3
|
+
let(:logger) { Logger.new(File::NULL) }
|
4
|
+
|
5
|
+
let(:config) do
|
6
|
+
Airbrake::Config.new(
|
7
|
+
project_id: 123,
|
8
|
+
logger: logger,
|
9
|
+
)
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:data) do
|
13
|
+
instance_double(Airbrake::RemoteSettings::SettingsData)
|
14
|
+
end
|
15
|
+
|
16
|
+
before do
|
17
|
+
allow(data).to receive(:to_h)
|
18
|
+
allow(data).to receive(:error_host)
|
19
|
+
allow(data).to receive(:apm_host)
|
20
|
+
allow(data).to receive(:error_notifications?)
|
21
|
+
allow(data).to receive(:performance_stats?)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "logs given data" do
|
25
|
+
expect(logger).to receive(:debug) do |&block|
|
26
|
+
expect(block.call).to match(/applying remote settings/)
|
27
|
+
end
|
28
|
+
described_class.new(config).call(data)
|
29
|
+
end
|
30
|
+
|
31
|
+
context "when the config disables error notifications" do
|
32
|
+
before do
|
33
|
+
config.error_notifications = false
|
34
|
+
allow(data).to receive(:error_notifications?).and_return(true)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "keeps the option disabled forever" do
|
38
|
+
callback = described_class.new(config)
|
39
|
+
|
40
|
+
callback.call(data)
|
41
|
+
expect(config.error_notifications).to eq(false)
|
42
|
+
|
43
|
+
callback.call(data)
|
44
|
+
expect(config.error_notifications).to eq(false)
|
45
|
+
|
46
|
+
callback.call(data)
|
47
|
+
expect(config.error_notifications).to eq(false)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "when the config enables error notifications" do
|
52
|
+
before { config.error_notifications = true }
|
53
|
+
|
54
|
+
it "can disable and enable error notifications" do
|
55
|
+
expect(data).to receive(:error_notifications?).and_return(false)
|
56
|
+
|
57
|
+
callback = described_class.new(config)
|
58
|
+
callback.call(data)
|
59
|
+
expect(config.error_notifications).to eq(false)
|
60
|
+
|
61
|
+
expect(data).to receive(:error_notifications?).and_return(true)
|
62
|
+
callback.call(data)
|
63
|
+
expect(config.error_notifications).to eq(true)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "when the config disables performance_stats" do
|
68
|
+
before do
|
69
|
+
config.performance_stats = false
|
70
|
+
allow(data).to receive(:performance_stats?).and_return(true)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "keeps the option disabled forever" do
|
74
|
+
callback = described_class.new(config)
|
75
|
+
|
76
|
+
callback.call(data)
|
77
|
+
expect(config.performance_stats).to eq(false)
|
78
|
+
|
79
|
+
callback.call(data)
|
80
|
+
expect(config.performance_stats).to eq(false)
|
81
|
+
|
82
|
+
callback.call(data)
|
83
|
+
expect(config.performance_stats).to eq(false)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context "when the config enables performance stats" do
|
88
|
+
before { config.performance_stats = true }
|
89
|
+
|
90
|
+
it "can disable and enable performance_stats" do
|
91
|
+
expect(data).to receive(:performance_stats?).and_return(false)
|
92
|
+
|
93
|
+
callback = described_class.new(config)
|
94
|
+
callback.call(data)
|
95
|
+
expect(config.performance_stats).to eq(false)
|
96
|
+
|
97
|
+
expect(data).to receive(:performance_stats?).and_return(true)
|
98
|
+
callback.call(data)
|
99
|
+
expect(config.performance_stats).to eq(true)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context "when error_host returns a value" do
|
104
|
+
it "sets the error_host option" do
|
105
|
+
config.error_host = 'http://api.airbrake.io'
|
106
|
+
allow(data).to receive(:error_host).and_return('https://api.example.com')
|
107
|
+
|
108
|
+
described_class.new(config).call(data)
|
109
|
+
expect(config.error_host).to eq('https://api.example.com')
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
context "when error_host returns nil" do
|
114
|
+
it "doesn't modify the error_host option" do
|
115
|
+
config.error_host = 'http://api.airbrake.io'
|
116
|
+
allow(data).to receive(:error_host).and_return(nil)
|
117
|
+
|
118
|
+
described_class.new(config).call(data)
|
119
|
+
expect(config.error_host).to eq('http://api.airbrake.io')
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
context "when apm_host returns a value" do
|
124
|
+
it "sets the apm_host option" do
|
125
|
+
config.apm_host = 'http://api.airbrake.io'
|
126
|
+
allow(data).to receive(:apm_host).and_return('https://api.example.com')
|
127
|
+
|
128
|
+
described_class.new(config).call(data)
|
129
|
+
expect(config.apm_host).to eq('https://api.example.com')
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
context "when apm_host returns nil" do
|
134
|
+
it "doesn't modify the apm_host option" do
|
135
|
+
config.apm_host = 'http://api.airbrake.io'
|
136
|
+
allow(data).to receive(:apm_host).and_return(nil)
|
137
|
+
|
138
|
+
described_class.new(config).call(data)
|
139
|
+
expect(config.apm_host).to eq('http://api.airbrake.io')
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -13,7 +13,7 @@ RSpec.describe Airbrake::RemoteSettings::SettingsData do
|
|
13
13
|
|
14
14
|
expect(settings_data.interval).to eq(123)
|
15
15
|
expect(settings_data.config_route(''))
|
16
|
-
.to eq('abc
|
16
|
+
.to eq('/abc')
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
@@ -60,65 +60,48 @@ RSpec.describe Airbrake::RemoteSettings::SettingsData do
|
|
60
60
|
end
|
61
61
|
|
62
62
|
describe "#config_route" do
|
63
|
-
let(:host) { '
|
63
|
+
let(:host) { 'http://example.com/' }
|
64
64
|
|
65
|
-
context "when
|
66
|
-
|
67
|
-
|
68
|
-
{ 'config_route' => 'http://example.com/' }
|
69
|
-
end
|
70
|
-
|
71
|
-
it "returns the route with the host" do
|
72
|
-
expect(described_class.new(project_id, data).config_route(host)).to eq(
|
73
|
-
"http://example.com/2020-06-18/config/#{project_id}/config.json",
|
74
|
-
)
|
75
|
-
end
|
65
|
+
context "when remote config specifies a config route" do
|
66
|
+
let(:data) do
|
67
|
+
{ 'config_route' => '123/cfg/321/cfg.json' }
|
76
68
|
end
|
77
69
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
it "returns the route with the host" do
|
84
|
-
expect(described_class.new(project_id, data).config_route(host)).to eq(
|
85
|
-
"http://example.com/2020-06-18/config/#{project_id}/config.json",
|
86
|
-
)
|
87
|
-
end
|
70
|
+
it "returns the config route with the provided location" do
|
71
|
+
expect(described_class.new(project_id, data).config_route(host)).to eq(
|
72
|
+
'http://example.com/123/cfg/321/cfg.json',
|
73
|
+
)
|
88
74
|
end
|
89
75
|
end
|
90
76
|
|
91
|
-
context "when
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
expect(described_class.new(project_id, {}).config_route(host)).to eq(
|
97
|
-
"http://example.com/2020-06-18/config/#{project_id}/config.json",
|
98
|
-
)
|
99
|
-
end
|
77
|
+
context "when remote config DOES NOT specify a config route" do
|
78
|
+
it "returns the config route with the default location" do
|
79
|
+
expect(described_class.new(project_id, {}).config_route(host)).to eq(
|
80
|
+
"http://example.com/2020-06-18/config/#{project_id}/config.json",
|
81
|
+
)
|
100
82
|
end
|
83
|
+
end
|
101
84
|
|
102
|
-
|
103
|
-
|
85
|
+
context "when a config route is specified but is set to nil" do
|
86
|
+
let(:data) do
|
87
|
+
{ 'config_route' => nil }
|
88
|
+
end
|
104
89
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
end
|
90
|
+
it "returns the config route with the default location" do
|
91
|
+
expect(described_class.new(project_id, data).config_route(host)).to eq(
|
92
|
+
"http://example.com/2020-06-18/config/#{project_id}/config.json",
|
93
|
+
)
|
110
94
|
end
|
111
95
|
end
|
112
96
|
|
113
|
-
context "when
|
97
|
+
context "when a config route is specified but is set to an empty string" do
|
114
98
|
let(:data) do
|
115
|
-
{ 'config_route' =>
|
99
|
+
{ 'config_route' => '' }
|
116
100
|
end
|
117
101
|
|
118
|
-
it "returns the route with the
|
102
|
+
it "returns the route with the default instead" do
|
119
103
|
expect(described_class.new(project_id, data).config_route(host)).to eq(
|
120
|
-
|
121
|
-
"2020-06-18/config/#{project_id}/config.json",
|
104
|
+
"http://example.com/2020-06-18/config/#{project_id}/config.json",
|
122
105
|
)
|
123
106
|
end
|
124
107
|
end
|
@@ -22,42 +22,19 @@ RSpec.describe Airbrake::RemoteSettings do
|
|
22
22
|
}
|
23
23
|
end
|
24
24
|
|
25
|
-
let(:config_path) { described_class::CONFIG_DUMP_PATH }
|
26
|
-
let(:config_dir) { File.dirname(config_path) }
|
27
|
-
|
28
25
|
let!(:stub) do
|
29
26
|
stub_request(:get, Regexp.new(endpoint))
|
30
27
|
.to_return(status: 200, body: body.to_json)
|
31
28
|
end
|
32
29
|
|
33
|
-
before do
|
34
|
-
# Do not create config dumps on disk.
|
35
|
-
allow(Dir).to receive(:mkdir).with(config_dir)
|
36
|
-
allow(File).to receive(:write).with(config_path, anything)
|
37
|
-
end
|
38
|
-
|
39
30
|
describe ".poll" do
|
40
31
|
describe "config loading" do
|
41
32
|
let(:settings_data) { described_class::SettingsData.new(project_id, body) }
|
42
33
|
|
43
34
|
before do
|
44
|
-
allow(File).to receive(:exist?).with(config_path).and_return(true)
|
45
|
-
allow(File).to receive(:read).with(config_path).and_return(body.to_json)
|
46
|
-
|
47
35
|
allow(described_class::SettingsData).to receive(:new).and_return(settings_data)
|
48
36
|
end
|
49
37
|
|
50
|
-
it "loads the config from disk" do
|
51
|
-
expect(File).to receive(:read).with(config_path)
|
52
|
-
expect(settings_data).to receive(:merge!).with(body).twice
|
53
|
-
|
54
|
-
remote_settings = described_class.poll(project_id, host) {}
|
55
|
-
sleep(0.2)
|
56
|
-
remote_settings.stop_polling
|
57
|
-
|
58
|
-
expect(stub).to have_been_requested.once
|
59
|
-
end
|
60
|
-
|
61
38
|
it "yields the config to the block twice" do
|
62
39
|
block = proc {}
|
63
40
|
expect(block).to receive(:call).twice
|
@@ -68,21 +45,6 @@ RSpec.describe Airbrake::RemoteSettings do
|
|
68
45
|
|
69
46
|
expect(stub).to have_been_requested.once
|
70
47
|
end
|
71
|
-
|
72
|
-
context "when config loading fails" do
|
73
|
-
it "logs an error" do
|
74
|
-
expect(File).to receive(:read).and_raise(StandardError)
|
75
|
-
expect(Airbrake::Loggable.instance).to receive(:error).with(
|
76
|
-
'**Airbrake: config loading failed: StandardError',
|
77
|
-
)
|
78
|
-
|
79
|
-
remote_settings = described_class.poll(project_id, host) {}
|
80
|
-
sleep(0.2)
|
81
|
-
remote_settings.stop_polling
|
82
|
-
|
83
|
-
expect(stub).to have_been_requested.once
|
84
|
-
end
|
85
|
-
end
|
86
48
|
end
|
87
49
|
|
88
50
|
context "when no errors are raised" do
|
@@ -175,16 +137,16 @@ RSpec.describe Airbrake::RemoteSettings do
|
|
175
137
|
end
|
176
138
|
|
177
139
|
context "when a config route is specified in the returned data" do
|
178
|
-
let(:
|
179
|
-
|
140
|
+
let(:new_config_route) do
|
141
|
+
'213/config/111/config.json'
|
180
142
|
end
|
181
143
|
|
182
144
|
let(:body) do
|
183
|
-
{ 'config_route' =>
|
145
|
+
{ 'config_route' => new_config_route, 'poll_sec' => 0.1 }
|
184
146
|
end
|
185
147
|
|
186
148
|
let!(:new_stub) do
|
187
|
-
stub_request(:get, Regexp.new(
|
149
|
+
stub_request(:get, Regexp.new(new_config_route))
|
188
150
|
.to_return(status: 200, body: body.to_json)
|
189
151
|
end
|
190
152
|
|
@@ -199,32 +161,4 @@ RSpec.describe Airbrake::RemoteSettings do
|
|
199
161
|
end
|
200
162
|
end
|
201
163
|
end
|
202
|
-
|
203
|
-
describe "#stop_polling" do
|
204
|
-
it "dumps config data to disk" do
|
205
|
-
expect(Dir).to receive(:mkdir).with(config_dir)
|
206
|
-
expect(File).to receive(:write).with(config_path, body.to_json)
|
207
|
-
|
208
|
-
remote_settings = described_class.poll(project_id, host) {}
|
209
|
-
sleep(0.2)
|
210
|
-
remote_settings.stop_polling
|
211
|
-
|
212
|
-
expect(stub).to have_been_requested.once
|
213
|
-
end
|
214
|
-
|
215
|
-
context "when config dumping fails" do
|
216
|
-
it "logs an error" do
|
217
|
-
expect(File).to receive(:write).and_raise(StandardError)
|
218
|
-
expect(Airbrake::Loggable.instance).to receive(:error).with(
|
219
|
-
'**Airbrake: config dumping failed: StandardError',
|
220
|
-
)
|
221
|
-
|
222
|
-
remote_settings = described_class.poll(project_id, host) {}
|
223
|
-
sleep(0.2)
|
224
|
-
remote_settings.stop_polling
|
225
|
-
|
226
|
-
expect(stub).to have_been_requested.once
|
227
|
-
end
|
228
|
-
end
|
229
|
-
end
|
230
164
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: airbrake-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.1.0
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Airbrake Technologies, Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-10-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rbtree-jruby
|
@@ -79,6 +79,7 @@ files:
|
|
79
79
|
- lib/airbrake-ruby/query.rb
|
80
80
|
- lib/airbrake-ruby/queue.rb
|
81
81
|
- lib/airbrake-ruby/remote_settings.rb
|
82
|
+
- lib/airbrake-ruby/remote_settings/callback.rb
|
82
83
|
- lib/airbrake-ruby/remote_settings/settings_data.rb
|
83
84
|
- lib/airbrake-ruby/request.rb
|
84
85
|
- lib/airbrake-ruby/response.rb
|
@@ -135,6 +136,7 @@ files:
|
|
135
136
|
- spec/promise_spec.rb
|
136
137
|
- spec/query_spec.rb
|
137
138
|
- spec/queue_spec.rb
|
139
|
+
- spec/remote_settings/callback_spec.rb
|
138
140
|
- spec/remote_settings/settings_data_spec.rb
|
139
141
|
- spec/remote_settings_spec.rb
|
140
142
|
- spec/request_spec.rb
|
@@ -215,6 +217,7 @@ test_files:
|
|
215
217
|
- spec/notice_notifier/options_spec.rb
|
216
218
|
- spec/filter_chain_spec.rb
|
217
219
|
- spec/remote_settings/settings_data_spec.rb
|
220
|
+
- spec/remote_settings/callback_spec.rb
|
218
221
|
- spec/response_spec.rb
|
219
222
|
- spec/queue_spec.rb
|
220
223
|
- spec/code_hunk_spec.rb
|