stoplight 1.1.1 → 1.2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +119 -59
- data/lib/stoplight.rb +4 -0
- data/lib/stoplight/notifier/bugsnag.rb +37 -0
- data/lib/stoplight/notifier/honeybadger.rb +43 -0
- data/lib/stoplight/notifier/logger.rb +19 -0
- data/lib/stoplight/version.rb +1 -1
- data/spec/stoplight/notifier/bugsnag_spec.rb +89 -0
- data/spec/stoplight/notifier/honeybadger_spec.rb +74 -0
- data/spec/stoplight/notifier/logger_spec.rb +70 -0
- metadata +49 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d93190b30a8d042b53c5b2cf115a02dc4d2ca890
|
4
|
+
data.tar.gz: 0c4f3b4da7602df759e976eed9d73dfdb87fa7e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: efbc488c2ebea3bca686f190d14a06bf48b563b2d1c4d07fc30692901d5d72aa353dd93b2d422d0dac0affe01d3cd16d2ea293b767c70ead80a571810b787190
|
7
|
+
data.tar.gz: 93bd99e0422058fb537555e872baf50513672f9c0035eb6f717dae6157ae049c94ac8d810045a825b3d364dc0014a307f7705adbabcc36b6fb28b252b27ddf17
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,12 @@
|
|
2
2
|
|
3
3
|
Stoplight uses [Semantic Versioning][1].
|
4
4
|
|
5
|
+
## v1.2.0 (2015-09-11)
|
6
|
+
|
7
|
+
- #78: Added a Bugsnag notifier. Thanks, @bolshakov!
|
8
|
+
- Added a Honeybadger notifier.
|
9
|
+
- #77: Added a logger notifier. Thanks again, @bolshakov!
|
10
|
+
|
5
11
|
## v1.1.1 (2015-07-16)
|
6
12
|
|
7
13
|
- Introduced a generic notifier to reduce duplication between the IO and Slack
|
data/README.md
CHANGED
@@ -12,9 +12,9 @@ breaker pattern in Ruby.
|
|
12
12
|
|
13
13
|
---
|
14
14
|
|
15
|
-
Does your code use unreliable systems, like a flaky database or a
|
16
|
-
|
17
|
-
|
15
|
+
Does your code use unreliable systems, like a flaky database or a spotty web
|
16
|
+
service? Wrap calls to those up in stoplights to prevent them from affecting
|
17
|
+
the rest of your application.
|
18
18
|
|
19
19
|
Check out [stoplight-admin][] for controlling your stoplights.
|
20
20
|
|
@@ -27,8 +27,12 @@ Check out [stoplight-admin][] for controlling your stoplights.
|
|
27
27
|
- [Rails](#rails)
|
28
28
|
- [Setup](#setup)
|
29
29
|
- [Data store](#data-store)
|
30
|
+
- [Redis](#redis)
|
30
31
|
- [Notifiers](#notifiers)
|
32
|
+
- [Bugsnag](#bugsnag)
|
31
33
|
- [HipChat](#hipchat)
|
34
|
+
- [Honeybadger](#honeybadger)
|
35
|
+
- [Logger](#logger)
|
32
36
|
- [Slack](#slack)
|
33
37
|
- [Rails](#rails-1)
|
34
38
|
- [Advanced usage](#advanced-usage)
|
@@ -64,9 +68,9 @@ light = Stoplight('example-1') { 22.0 / 7 }
|
|
64
68
|
# => #<Stoplight::Light:...>
|
65
69
|
```
|
66
70
|
|
67
|
-
Then you can run it and it will return the result of calling the
|
68
|
-
|
69
|
-
|
71
|
+
Then you can run it and it will return the result of calling the block. This is
|
72
|
+
the green state. (The green state corresponds to the closed state for circuit
|
73
|
+
breakers.)
|
70
74
|
|
71
75
|
``` rb
|
72
76
|
light.run
|
@@ -75,19 +79,19 @@ light.color
|
|
75
79
|
# => "green"
|
76
80
|
```
|
77
81
|
|
78
|
-
If everything goes well, you shouldn't even be able to tell that
|
79
|
-
|
80
|
-
|
82
|
+
If everything goes well, you shouldn't even be able to tell that you're using a
|
83
|
+
stoplight. That's not very interesting though, so let's create a failing
|
84
|
+
stoplight:
|
81
85
|
|
82
86
|
``` rb
|
83
87
|
light = Stoplight('example-2') { 1 / 0 }
|
84
88
|
# => #<Stoplight::Light:...>
|
85
89
|
```
|
86
90
|
|
87
|
-
Now when you run it, the error will be recorded and passed through.
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
+
Now when you run it, the error will be recorded and passed through. After
|
92
|
+
running it a few times, the stoplight will stop trying and fail fast. This is
|
93
|
+
the red state. (The red state corresponds to the open state for circuit
|
94
|
+
breakers.)
|
91
95
|
|
92
96
|
``` rb
|
93
97
|
light.run
|
@@ -103,23 +107,21 @@ light.color
|
|
103
107
|
# => "red"
|
104
108
|
```
|
105
109
|
|
106
|
-
When the stoplight changes from green to red, it will notify every
|
107
|
-
|
108
|
-
about notifiers.
|
110
|
+
When the stoplight changes from green to red, it will notify every configured
|
111
|
+
notifier. See [the notifiers section][] to learn more about notifiers.
|
109
112
|
|
110
|
-
The stoplight will move into the yellow state after being in the
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
to green.
|
113
|
+
The stoplight will move into the yellow state after being in the red state for
|
114
|
+
a while. (The yellow state corresponds to the half open state for circuit
|
115
|
+
breakers.) To configure how long it takes to switch into the yellow state,
|
116
|
+
check out [the timeout section][] When stoplights are yellow, they will try
|
117
|
+
to run their code. If it fails, they'll switch back to red. If it succeeds,
|
118
|
+
they'll switch to green.
|
117
119
|
|
118
120
|
### Custom errors
|
119
121
|
|
120
|
-
Some errors shouldn't cause your stoplight to move into the red
|
121
|
-
|
122
|
-
|
122
|
+
Some errors shouldn't cause your stoplight to move into the red state. Usually
|
123
|
+
these are handled elsewhere in your stack and don't represent real failures. A
|
124
|
+
good example is `ActiveRecord::RecordNotFound`.
|
123
125
|
|
124
126
|
``` rb
|
125
127
|
light = Stoplight('example-3') { User.find(123) }
|
@@ -140,10 +142,10 @@ The following errors are always allowed: `NoMemoryError`, `ScriptError`,
|
|
140
142
|
|
141
143
|
### Custom fallback
|
142
144
|
|
143
|
-
By default, stoplights will re-raise errors when they're green.
|
144
|
-
|
145
|
-
|
146
|
-
|
145
|
+
By default, stoplights will re-raise errors when they're green. When they're
|
146
|
+
red, they'll raise a `Stoplight::Error::RedLight` error. You can provide a
|
147
|
+
fallback that will be called in both of these cases. It will be passed the
|
148
|
+
error if the light was green.
|
147
149
|
|
148
150
|
``` rb
|
149
151
|
light = Stoplight('example-4') { 1 / 0 }
|
@@ -166,9 +168,8 @@ light.run
|
|
166
168
|
|
167
169
|
### Custom threshold
|
168
170
|
|
169
|
-
Some bits of code might be allowed to fail more or less frequently
|
170
|
-
|
171
|
-
in seconds.
|
171
|
+
Some bits of code might be allowed to fail more or less frequently than others.
|
172
|
+
You can configure this by setting a custom threshold.
|
172
173
|
|
173
174
|
``` rb
|
174
175
|
light = Stoplight('example-5') { fail }
|
@@ -185,9 +186,9 @@ The default threshold is `3`.
|
|
185
186
|
|
186
187
|
### Custom timeout
|
187
188
|
|
188
|
-
Stoplights will automatically attempt to recover after a certain
|
189
|
-
|
190
|
-
|
189
|
+
Stoplights will automatically attempt to recover after a certain amount of
|
190
|
+
time. A light in the red state for longer than the timeout will transition to
|
191
|
+
the yellow state. This timeout is customizable.
|
191
192
|
|
192
193
|
``` rb
|
193
194
|
light = Stoplight('example-6') { fail }
|
@@ -208,13 +209,15 @@ light.run
|
|
208
209
|
# RuntimeError:
|
209
210
|
```
|
210
211
|
|
211
|
-
The default timeout is `60` seconds.
|
212
|
-
automatic recovery
|
212
|
+
The default timeout is `60` seconds. To disable automatic recovery, set the
|
213
|
+
timeout to `Float::INFINITY`. To make automatic recovery instantaneous, set the
|
214
|
+
timeout to `0` seconds. Note that this is not recommended, as it effectively
|
215
|
+
replaces the red state with yellow.
|
213
216
|
|
214
217
|
### Rails
|
215
218
|
|
216
|
-
Stoplight was designed to wrap Rails actions with minimal effort.
|
217
|
-
|
219
|
+
Stoplight was designed to wrap Rails actions with minimal effort. Here's an
|
220
|
+
example configuration:
|
218
221
|
|
219
222
|
``` rb
|
220
223
|
class ApplicationController < ActionController::Base
|
@@ -247,9 +250,12 @@ Stoplight::Light.default_data_store
|
|
247
250
|
# => #<Stoplight::DataStore::Memory:...>
|
248
251
|
```
|
249
252
|
|
250
|
-
If you want to use a persistent data store, you'll have to set it
|
251
|
-
|
252
|
-
|
253
|
+
If you want to use a persistent data store, you'll have to set it up. Currently
|
254
|
+
the only supported persistent data store is Redis.
|
255
|
+
|
256
|
+
#### Redis
|
257
|
+
|
258
|
+
Make sure you have [the Redis gem][] (`~> 3.2`) installed before configuring
|
253
259
|
Stoplight.
|
254
260
|
|
255
261
|
``` rb
|
@@ -273,11 +279,25 @@ Stoplight::Light.default_notifiers
|
|
273
279
|
```
|
274
280
|
|
275
281
|
If you want to send notifications elsewhere, you'll have to set them up.
|
276
|
-
|
282
|
+
|
283
|
+
#### Bugsnag
|
284
|
+
|
285
|
+
Make sure you have [the Bugsnag gem][] (`~> 2.8`) installed before configuring
|
286
|
+
Stoplight.
|
287
|
+
|
288
|
+
``` rb
|
289
|
+
require 'bugsnag'
|
290
|
+
# => true
|
291
|
+
notifier = Stoplight::Notifier::Bugsnag.new(Bugsnag)
|
292
|
+
# => #<Stoplight::Notifier::Bugsnag:...>
|
293
|
+
Stoplight::Light.default_notifiers += [notifier]
|
294
|
+
# => [#<Stoplight::Notifier::IO:...>, #<Stoplight::Notifier::Bugsnag:...>]
|
295
|
+
```
|
277
296
|
|
278
297
|
#### HipChat
|
279
298
|
|
280
|
-
Make sure you have [the HipChat gem][] installed before configuring
|
299
|
+
Make sure you have [the HipChat gem][] (`~> 1.5`) installed before configuring
|
300
|
+
Stoplight.
|
281
301
|
|
282
302
|
``` rb
|
283
303
|
require 'hipchat'
|
@@ -290,9 +310,40 @@ Stoplight::Light.default_notifiers += [notifier]
|
|
290
310
|
# => [#<Stoplight::Notifier::IO:...>, #<Stoplight::Notifier::HipChat:...>]
|
291
311
|
```
|
292
312
|
|
313
|
+
#### Honeybadger
|
314
|
+
|
315
|
+
Make sure you have [the Honeybadger gem][] (`~> 2.1`) installed before
|
316
|
+
configuring Stoplight.
|
317
|
+
|
318
|
+
``` rb
|
319
|
+
require 'honeybadger'
|
320
|
+
# => true
|
321
|
+
notifier = Stoplight::Notifier::Honeybadger.new('api key')
|
322
|
+
# => #<Stoplight::Notifier::Honeybadger:...>
|
323
|
+
Stoplight::Light.default_notifiers += [notifier]
|
324
|
+
# => [#<Stoplight::Notifier::IO:...>, #<Stoplight::Notifier::Honeybadger:...>]
|
325
|
+
```
|
326
|
+
|
327
|
+
#### Logger
|
328
|
+
|
329
|
+
Stoplight can be configured to use [the Logger class][] from the standard
|
330
|
+
library.
|
331
|
+
|
332
|
+
``` rb
|
333
|
+
require 'logger'
|
334
|
+
# => true
|
335
|
+
logger = Logger.new(STDERR)
|
336
|
+
# => #<Logger:...>
|
337
|
+
notifier = Stoplight::Notifier::Logger.new(logger)
|
338
|
+
# => #<Stoplight::Notifier::Logger:...>
|
339
|
+
Stoplight::Light.default_notifiers += [notifier]
|
340
|
+
# => [#<Stoplight::Notifier::IO:...>, #<Stoplight::Notifier::Logger:...>]
|
341
|
+
```
|
342
|
+
|
293
343
|
#### Slack
|
294
344
|
|
295
|
-
Make sure you have [the Slack gem][] installed before configuring
|
345
|
+
Make sure you have [the Slack gem][] (`~> 1.3`) installed before configuring
|
346
|
+
Stoplight.
|
296
347
|
|
297
348
|
``` rb
|
298
349
|
require 'slack-notifier'
|
@@ -307,25 +358,25 @@ Stoplight::Light.default_notifiers += [notifier]
|
|
307
358
|
|
308
359
|
### Rails
|
309
360
|
|
310
|
-
Stoplight is designed to work seamlessly with Rails. If you want
|
311
|
-
|
312
|
-
|
313
|
-
|
361
|
+
Stoplight is designed to work seamlessly with Rails. If you want to use the
|
362
|
+
in-memory data store, you don't need to do anything special. If you want to use
|
363
|
+
a persistent data store, you'll need to configure it. Create an initializer for
|
364
|
+
Stoplight:
|
314
365
|
|
315
366
|
``` rb
|
316
367
|
# config/initializers/stoplight.rb
|
317
368
|
require 'stoplight'
|
318
369
|
Stoplight::Light.default_data_store = Stoplight::DataStore::Redis.new(...)
|
319
|
-
Stoplight::Light.default_notifiers += [Stoplight::Notifier::
|
370
|
+
Stoplight::Light.default_notifiers += [Stoplight::Notifier::Logger.new(Rails.logger)]
|
320
371
|
```
|
321
372
|
|
322
373
|
## Advanced usage
|
323
374
|
|
324
375
|
### Locking
|
325
376
|
|
326
|
-
Although stoplights can operate on their own, occasionally you may
|
327
|
-
|
328
|
-
|
377
|
+
Although stoplights can operate on their own, occasionally you may want to
|
378
|
+
override the default behavior. You can lock a light in either the green or red
|
379
|
+
state using `set_state`.
|
329
380
|
|
330
381
|
``` rb
|
331
382
|
light = Stoplight('example-7') { true }
|
@@ -338,12 +389,18 @@ light.run
|
|
338
389
|
# Stoplight::Error::RedLight: example-7
|
339
390
|
```
|
340
391
|
|
341
|
-
**Code in locked red lights may still run under certain conditions!**
|
342
|
-
|
343
|
-
|
344
|
-
|
392
|
+
**Code in locked red lights may still run under certain conditions!** If you
|
393
|
+
have configured a custom data store and that data store fails, Stoplight will
|
394
|
+
switch over to using a blank in-memory data store. That means you will lose the
|
395
|
+
locked state of any stoplights.
|
396
|
+
|
397
|
+
You can go back to using the default behavior by unlocking the stoplight.
|
398
|
+
|
399
|
+
``` rb
|
400
|
+
light.data_store.set_state(light, Stoplight::State::UNLOCKED)
|
401
|
+
```
|
345
402
|
|
346
|
-
|
403
|
+
### Testing
|
347
404
|
|
348
405
|
Stoplights typically work as expected without modification in test suites.
|
349
406
|
However there are a few things you can do to make them behave better. If your
|
@@ -393,7 +450,10 @@ Stoplight is licensed under [the MIT License][].
|
|
393
450
|
[the notifiers section]: #notifiers
|
394
451
|
[the timeout section]: #custom-timeout
|
395
452
|
[the redis gem]: https://rubygems.org/gems/redis
|
453
|
+
[the bugsnag gem]: https://rubygems.org/gems/bugsnag
|
396
454
|
[the hipchat gem]: https://rubygems.org/gems/hipchat
|
455
|
+
[the honeybadger gem]: https://rubygems.org/gems/honeybadger
|
456
|
+
[the logger class]: http://ruby-doc.org/stdlib-2.2.3/libdoc/logger/rdoc/Logger.html
|
397
457
|
[the slack gem]: https://rubygems.org/gems/slack-notifier
|
398
458
|
[@camdez]: https://github.com/camdez
|
399
459
|
[@tfausak]: https://github.com/tfausak
|
data/lib/stoplight.rb
CHANGED
@@ -18,8 +18,12 @@ require 'stoplight/data_store/redis'
|
|
18
18
|
require 'stoplight/notifier'
|
19
19
|
require 'stoplight/notifier/base'
|
20
20
|
require 'stoplight/notifier/generic'
|
21
|
+
|
22
|
+
require 'stoplight/notifier/bugsnag'
|
21
23
|
require 'stoplight/notifier/hip_chat'
|
24
|
+
require 'stoplight/notifier/honeybadger'
|
22
25
|
require 'stoplight/notifier/io'
|
26
|
+
require 'stoplight/notifier/logger'
|
23
27
|
require 'stoplight/notifier/slack'
|
24
28
|
|
25
29
|
require 'stoplight/default'
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Stoplight
|
4
|
+
module Notifier
|
5
|
+
# @see Base
|
6
|
+
class Bugsnag < Base
|
7
|
+
DEFAULT_OPTIONS = {
|
8
|
+
severity: 'info'
|
9
|
+
}
|
10
|
+
|
11
|
+
StoplightStatusChange = Class.new(Error::Base)
|
12
|
+
|
13
|
+
# @return [Proc]
|
14
|
+
attr_reader :formatter
|
15
|
+
# @return [::Bugsnag]
|
16
|
+
attr_reader :bugsnag
|
17
|
+
# @return [Hash{Symbol => Object}]
|
18
|
+
attr_reader :options
|
19
|
+
|
20
|
+
# @param bugsnag [::Bugsnag]
|
21
|
+
# @param formatter [Proc, nil]
|
22
|
+
# @param options [Hash{Symbol => Object}]
|
23
|
+
# @option options [String] :severity
|
24
|
+
def initialize(bugsnag, formatter = nil, options = {})
|
25
|
+
@bugsnag = bugsnag
|
26
|
+
@formatter = formatter || Default::FORMATTER
|
27
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
28
|
+
end
|
29
|
+
|
30
|
+
def notify(light, from_color, to_color, error)
|
31
|
+
message = formatter.call(light, from_color, to_color, error)
|
32
|
+
bugsnag.notify(StoplightStatusChange.new(message), options)
|
33
|
+
message
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Stoplight
|
4
|
+
module Notifier
|
5
|
+
# @see Base
|
6
|
+
class Honeybadger < Base
|
7
|
+
DEFAULT_OPTIONS = {
|
8
|
+
parameters: {},
|
9
|
+
session: {},
|
10
|
+
context: {}
|
11
|
+
}.freeze
|
12
|
+
|
13
|
+
# @return [String]
|
14
|
+
attr_reader :api_key
|
15
|
+
# @return [Proc]
|
16
|
+
attr_reader :formatter
|
17
|
+
# @return [Hash{Symbol => Object}]
|
18
|
+
attr_reader :options
|
19
|
+
|
20
|
+
# @param api_key [String]
|
21
|
+
# @param formatter [Proc, nil]
|
22
|
+
# @param options [Hash{Symbol => Object}]
|
23
|
+
# @option options [Hash] :parameters
|
24
|
+
# @option options [Hash] :session
|
25
|
+
# @option options [Hash] :context
|
26
|
+
def initialize(api_key, formatter = nil, options = {})
|
27
|
+
@api_key = api_key
|
28
|
+
@formatter = formatter || Default::FORMATTER
|
29
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
30
|
+
end
|
31
|
+
|
32
|
+
def notify(light, from_color, to_color, error)
|
33
|
+
message = formatter.call(light, from_color, to_color, error)
|
34
|
+
h = options.merge(
|
35
|
+
api_key: api_key,
|
36
|
+
error_message: message,
|
37
|
+
backtrace: (error.backtrace if error))
|
38
|
+
::Honeybadger.notify(h)
|
39
|
+
message
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/stoplight/version.rb
CHANGED
@@ -0,0 +1,89 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'bugsnag'
|
5
|
+
|
6
|
+
RSpec.describe Stoplight::Notifier::Bugsnag do
|
7
|
+
StoplightStatusChange = Stoplight::Notifier::Bugsnag::StoplightStatusChange
|
8
|
+
|
9
|
+
it 'is a class' do
|
10
|
+
expect(described_class).to be_a(Class)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'is a subclass of Base' do
|
14
|
+
expect(described_class).to be < Stoplight::Notifier::Base
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#formatter' do
|
18
|
+
it 'is initially the default' do
|
19
|
+
expect(described_class.new(nil, nil).formatter)
|
20
|
+
.to eql(Stoplight::Default::FORMATTER)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'reads the formatter' do
|
24
|
+
formatter = proc {}
|
25
|
+
expect(described_class.new(nil, formatter).formatter)
|
26
|
+
.to eql(formatter)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#options' do
|
31
|
+
it 'is initially the default' do
|
32
|
+
expect(described_class.new(nil, nil).options)
|
33
|
+
.to eql(Stoplight::Notifier::Bugsnag::DEFAULT_OPTIONS)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'reads the options' do
|
37
|
+
options = { key: :value }
|
38
|
+
expect(described_class.new(nil, nil, options).options)
|
39
|
+
.to eql(Stoplight::Notifier::Bugsnag::DEFAULT_OPTIONS.merge(options))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '#bugsnag' do
|
44
|
+
it 'reads the Bugsnag client' do
|
45
|
+
client = ::Bugsnag
|
46
|
+
expect(described_class.new(client, nil).bugsnag)
|
47
|
+
.to eql(client)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '#notify' do
|
52
|
+
let(:light) { Stoplight::Light.new(name, &code) }
|
53
|
+
let(:name) { ('a'..'z').to_a.shuffle.join }
|
54
|
+
let(:code) { -> {} }
|
55
|
+
let(:from_color) { Stoplight::Color::GREEN }
|
56
|
+
let(:to_color) { Stoplight::Color::RED }
|
57
|
+
let(:notifier) { described_class.new(bugsnag) }
|
58
|
+
let(:bugsnag) { double(Bugsnag) }
|
59
|
+
|
60
|
+
subject(:result) do
|
61
|
+
notifier.notify(light, from_color, to_color, error)
|
62
|
+
end
|
63
|
+
|
64
|
+
before do
|
65
|
+
status_change = StoplightStatusChange.new(message)
|
66
|
+
expect(bugsnag).to receive(:notify).with(status_change, severity: 'info')
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'when no error given' do
|
70
|
+
let(:error) { nil }
|
71
|
+
|
72
|
+
it 'logs message' do
|
73
|
+
expect(result).to eq(message)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'when message with an error given' do
|
78
|
+
let(:error) { ZeroDivisionError.new('divided by 0') }
|
79
|
+
|
80
|
+
it 'logs message' do
|
81
|
+
expect(result).to eq(message)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def message
|
86
|
+
notifier.formatter.call(light, from_color, to_color, error)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'honeybadger'
|
3
|
+
|
4
|
+
RSpec.describe Stoplight::Notifier::Honeybadger do
|
5
|
+
it 'is a class' do
|
6
|
+
expect(described_class).to be_a(Class)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'is a subclass of Base' do
|
10
|
+
expect(described_class).to be < Stoplight::Notifier::Base
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#formatter' do
|
14
|
+
it 'is initially the default' do
|
15
|
+
expect(described_class.new(nil).formatter).to eql(
|
16
|
+
Stoplight::Default::FORMATTER)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'reads the formatter' do
|
20
|
+
formatter = proc {}
|
21
|
+
expect(described_class.new(nil, formatter).formatter).to eql(formatter)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#options' do
|
26
|
+
it 'is initially the default' do
|
27
|
+
expect(described_class.new(nil).options).to eql(
|
28
|
+
Stoplight::Notifier::Honeybadger::DEFAULT_OPTIONS)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'reads the options' do
|
32
|
+
options = { key: :value }
|
33
|
+
expect(described_class.new(nil, nil, options).options).to eql(
|
34
|
+
Stoplight::Notifier::Honeybadger::DEFAULT_OPTIONS.merge(options))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '#notify' do
|
39
|
+
let(:light) { Stoplight::Light.new(name, &code) }
|
40
|
+
let(:name) { ('a'..'z').to_a.shuffle.join }
|
41
|
+
let(:code) { -> {} }
|
42
|
+
let(:from_color) { Stoplight::Color::GREEN }
|
43
|
+
let(:to_color) { Stoplight::Color::RED }
|
44
|
+
let(:notifier) { described_class.new(api_key) }
|
45
|
+
let(:api_key) { ('a'..'z').to_a.shuffle.join }
|
46
|
+
|
47
|
+
before do
|
48
|
+
allow(Honeybadger).to receive(:notify)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'returns the message' do
|
52
|
+
error = nil
|
53
|
+
message = notifier.formatter.call(light, from_color, to_color, error)
|
54
|
+
expect(notifier.notify(light, from_color, to_color, error)).to eql(
|
55
|
+
message)
|
56
|
+
expect(Honeybadger).to have_received(:notify).with(
|
57
|
+
hash_including(
|
58
|
+
api_key: api_key,
|
59
|
+
error_message: message))
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'returns the message with an error' do
|
63
|
+
error = ZeroDivisionError.new('divided by 0')
|
64
|
+
message = notifier.formatter.call(light, from_color, to_color, error)
|
65
|
+
expect(notifier.notify(light, from_color, to_color, error)).to eql(
|
66
|
+
message)
|
67
|
+
expect(Honeybadger).to have_received(:notify).with(
|
68
|
+
hash_including(
|
69
|
+
api_key: api_key,
|
70
|
+
error_message: message,
|
71
|
+
backtrace: error.backtrace))
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe Stoplight::Notifier::Logger do
|
6
|
+
it 'is a class' do
|
7
|
+
expect(described_class).to be_a(Class)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'is a subclass of Base' do
|
11
|
+
expect(described_class).to be < Stoplight::Notifier::Base
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#formatter' do
|
15
|
+
it 'is initially the default' do
|
16
|
+
expect(described_class.new(nil, nil).formatter)
|
17
|
+
.to eql(Stoplight::Default::FORMATTER)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'reads the formatter' do
|
21
|
+
formatter = proc {}
|
22
|
+
expect(described_class.new(nil, formatter).formatter)
|
23
|
+
.to eql(formatter)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#logger' do
|
28
|
+
it 'reads the logger' do
|
29
|
+
logger = Logger.new(StringIO.new)
|
30
|
+
expect(described_class.new(logger, nil).logger)
|
31
|
+
.to eql(logger)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#notify' do
|
36
|
+
let(:light) { Stoplight::Light.new(name, &code) }
|
37
|
+
let(:name) { ('a'..'z').to_a.shuffle.join }
|
38
|
+
let(:code) { -> {} }
|
39
|
+
let(:from_color) { Stoplight::Color::GREEN }
|
40
|
+
let(:to_color) { Stoplight::Color::RED }
|
41
|
+
let(:notifier) { described_class.new(Logger.new(io)) }
|
42
|
+
let(:io) { StringIO.new }
|
43
|
+
|
44
|
+
before do
|
45
|
+
notifier.notify(light, from_color, to_color, error)
|
46
|
+
end
|
47
|
+
|
48
|
+
subject(:result) { io.string }
|
49
|
+
|
50
|
+
context 'when no error given' do
|
51
|
+
let(:error) { nil }
|
52
|
+
|
53
|
+
it 'logs message' do
|
54
|
+
expect(result).to match(/.+#{message}/)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'when message with an error given' do
|
59
|
+
let(:error) { ZeroDivisionError.new('divided by 0') }
|
60
|
+
|
61
|
+
it 'logs message' do
|
62
|
+
expect(result).to match(/.+#{message}/)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def message
|
67
|
+
notifier.formatter.call(light, from_color, to_color, error)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stoplight
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cameron Desautels
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2015-
|
13
|
+
date: 2015-09-11 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: benchmark-ips
|
@@ -18,14 +18,28 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - "~>"
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: '2.
|
21
|
+
version: '2.3'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
requirements:
|
26
26
|
- - "~>"
|
27
27
|
- !ruby/object:Gem::Version
|
28
|
-
version: '2.
|
28
|
+
version: '2.3'
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: bugsnag
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - "~>"
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '2.8'
|
36
|
+
type: :development
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - "~>"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '2.8'
|
29
43
|
- !ruby/object:Gem::Dependency
|
30
44
|
name: coveralls
|
31
45
|
requirement: !ruby/object:Gem::Requirement
|
@@ -60,14 +74,14 @@ dependencies:
|
|
60
74
|
requirements:
|
61
75
|
- - "~>"
|
62
76
|
- !ruby/object:Gem::Version
|
63
|
-
version: '2.
|
77
|
+
version: '2.13'
|
64
78
|
type: :development
|
65
79
|
prerelease: false
|
66
80
|
version_requirements: !ruby/object:Gem::Requirement
|
67
81
|
requirements:
|
68
82
|
- - "~>"
|
69
83
|
- !ruby/object:Gem::Version
|
70
|
-
version: '2.
|
84
|
+
version: '2.13'
|
71
85
|
- !ruby/object:Gem::Dependency
|
72
86
|
name: guard-rspec
|
73
87
|
requirement: !ruby/object:Gem::Requirement
|
@@ -110,6 +124,20 @@ dependencies:
|
|
110
124
|
- - "~>"
|
111
125
|
- !ruby/object:Gem::Version
|
112
126
|
version: '1.5'
|
127
|
+
- !ruby/object:Gem::Dependency
|
128
|
+
name: honeybadger
|
129
|
+
requirement: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - "~>"
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '2.1'
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - "~>"
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '2.1'
|
113
141
|
- !ruby/object:Gem::Dependency
|
114
142
|
name: rake
|
115
143
|
requirement: !ruby/object:Gem::Requirement
|
@@ -158,42 +186,42 @@ dependencies:
|
|
158
186
|
requirements:
|
159
187
|
- - "~>"
|
160
188
|
- !ruby/object:Gem::Version
|
161
|
-
version: '0.
|
189
|
+
version: '0.34'
|
162
190
|
type: :development
|
163
191
|
prerelease: false
|
164
192
|
version_requirements: !ruby/object:Gem::Requirement
|
165
193
|
requirements:
|
166
194
|
- - "~>"
|
167
195
|
- !ruby/object:Gem::Version
|
168
|
-
version: '0.
|
196
|
+
version: '0.34'
|
169
197
|
- !ruby/object:Gem::Dependency
|
170
198
|
name: slack-notifier
|
171
199
|
requirement: !ruby/object:Gem::Requirement
|
172
200
|
requirements:
|
173
201
|
- - "~>"
|
174
202
|
- !ruby/object:Gem::Version
|
175
|
-
version: 1.
|
203
|
+
version: '1.3'
|
176
204
|
type: :development
|
177
205
|
prerelease: false
|
178
206
|
version_requirements: !ruby/object:Gem::Requirement
|
179
207
|
requirements:
|
180
208
|
- - "~>"
|
181
209
|
- !ruby/object:Gem::Version
|
182
|
-
version: 1.
|
210
|
+
version: '1.3'
|
183
211
|
- !ruby/object:Gem::Dependency
|
184
212
|
name: timecop
|
185
213
|
requirement: !ruby/object:Gem::Requirement
|
186
214
|
requirements:
|
187
215
|
- - "~>"
|
188
216
|
- !ruby/object:Gem::Version
|
189
|
-
version: '0.
|
217
|
+
version: '0.8'
|
190
218
|
type: :development
|
191
219
|
prerelease: false
|
192
220
|
version_requirements: !ruby/object:Gem::Requirement
|
193
221
|
requirements:
|
194
222
|
- - "~>"
|
195
223
|
- !ruby/object:Gem::Version
|
196
|
-
version: '0.
|
224
|
+
version: '0.8'
|
197
225
|
- !ruby/object:Gem::Dependency
|
198
226
|
name: yard
|
199
227
|
requirement: !ruby/object:Gem::Requirement
|
@@ -233,9 +261,12 @@ files:
|
|
233
261
|
- lib/stoplight/light/runnable.rb
|
234
262
|
- lib/stoplight/notifier.rb
|
235
263
|
- lib/stoplight/notifier/base.rb
|
264
|
+
- lib/stoplight/notifier/bugsnag.rb
|
236
265
|
- lib/stoplight/notifier/generic.rb
|
237
266
|
- lib/stoplight/notifier/hip_chat.rb
|
267
|
+
- lib/stoplight/notifier/honeybadger.rb
|
238
268
|
- lib/stoplight/notifier/io.rb
|
269
|
+
- lib/stoplight/notifier/logger.rb
|
239
270
|
- lib/stoplight/notifier/slack.rb
|
240
271
|
- lib/stoplight/state.rb
|
241
272
|
- lib/stoplight/version.rb
|
@@ -251,9 +282,12 @@ files:
|
|
251
282
|
- spec/stoplight/light/runnable_spec.rb
|
252
283
|
- spec/stoplight/light_spec.rb
|
253
284
|
- spec/stoplight/notifier/base_spec.rb
|
285
|
+
- spec/stoplight/notifier/bugsnag_spec.rb
|
254
286
|
- spec/stoplight/notifier/generic_spec.rb
|
255
287
|
- spec/stoplight/notifier/hip_chat_spec.rb
|
288
|
+
- spec/stoplight/notifier/honeybadger_spec.rb
|
256
289
|
- spec/stoplight/notifier/io_spec.rb
|
290
|
+
- spec/stoplight/notifier/logger_spec.rb
|
257
291
|
- spec/stoplight/notifier/slack_spec.rb
|
258
292
|
- spec/stoplight/notifier_spec.rb
|
259
293
|
- spec/stoplight/state_spec.rb
|
@@ -296,9 +330,12 @@ test_files:
|
|
296
330
|
- spec/stoplight/light/runnable_spec.rb
|
297
331
|
- spec/stoplight/light_spec.rb
|
298
332
|
- spec/stoplight/notifier/base_spec.rb
|
333
|
+
- spec/stoplight/notifier/bugsnag_spec.rb
|
299
334
|
- spec/stoplight/notifier/generic_spec.rb
|
300
335
|
- spec/stoplight/notifier/hip_chat_spec.rb
|
336
|
+
- spec/stoplight/notifier/honeybadger_spec.rb
|
301
337
|
- spec/stoplight/notifier/io_spec.rb
|
338
|
+
- spec/stoplight/notifier/logger_spec.rb
|
302
339
|
- spec/stoplight/notifier/slack_spec.rb
|
303
340
|
- spec/stoplight/notifier_spec.rb
|
304
341
|
- spec/stoplight/state_spec.rb
|