stoplight 1.2.0 → 1.3.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 +4 -107
- data/LICENSE.md +1 -1
- data/README.md +51 -11
- data/lib/stoplight/default.rb +4 -2
- data/lib/stoplight/light.rb +17 -5
- data/lib/stoplight/light/runnable.rb +11 -3
- data/lib/stoplight/notifier/bugsnag.rb +1 -1
- data/lib/stoplight/version.rb +1 -1
- data/spec/stoplight/default_spec.rb +19 -5
- data/spec/stoplight/light/runnable_spec.rb +74 -5
- data/spec/stoplight/light_spec.rb +36 -8
- data/spec/stoplight/notifier/bugsnag_spec.rb +6 -3
- data/spec/stoplight/notifier/hip_chat_spec.rb +8 -1
- data/spec/stoplight/notifier/honeybadger_spec.rb +6 -1
- data/spec/stoplight/notifier/logger_spec.rb +2 -0
- data/spec/stoplight/notifier/slack_spec.rb +8 -1
- metadata +7 -7
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 1129070df15d367423a8be3a21f9bd73bffc2c74
         | 
| 4 | 
            +
              data.tar.gz: c98bfeffa3eddfac90367b7d6d15c308151eccd5
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 52f6543a523f1598c604198831b854e4efa112868417385ec45ba6b628138ea5abc05be0b0a95ee8601e7f01680f8f31a47d66aeb2ead79f588e30b1868ae459
         | 
| 7 | 
            +
              data.tar.gz: 9df784bc02e745c8dd770c3126a34c37c9b283d5c9712b71f4260e8ed49888a28c9c7b8aa19c5a2001d039d2a2fea51c66dc467e6c7212e4fc9d3d286a0ef65e
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,110 +1,7 @@ | |
| 1 1 | 
             
            # Change log
         | 
| 2 2 |  | 
| 3 | 
            -
            Stoplight uses [Semantic Versioning][ | 
| 3 | 
            +
            Stoplight uses [Semantic Versioning][].
         | 
| 4 | 
            +
            The change log is available [on GitHub][].
         | 
| 4 5 |  | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
            - #78: Added a Bugsnag notifier. Thanks, @bolshakov!
         | 
| 8 | 
            -
            - Added a Honeybadger notifier.
         | 
| 9 | 
            -
            - #77: Added a logger notifier. Thanks again, @bolshakov!
         | 
| 10 | 
            -
             | 
| 11 | 
            -
            ## v1.1.1 (2015-07-16)
         | 
| 12 | 
            -
             | 
| 13 | 
            -
            - Introduced a generic notifier to reduce duplication between the IO and Slack
         | 
| 14 | 
            -
              notifiers.
         | 
| 15 | 
            -
             | 
| 16 | 
            -
            ## v1.1.0 (2015-07-04)
         | 
| 17 | 
            -
             | 
| 18 | 
            -
            - #71: Added Slack notifier. Thanks, @s1mplex!
         | 
| 19 | 
            -
             | 
| 20 | 
            -
            ## v1.0.0 (2015-02-19)
         | 
| 21 | 
            -
             | 
| 22 | 
            -
            - Didn't change anything.
         | 
| 23 | 
            -
             | 
| 24 | 
            -
            ## v0.5.2 (2015-02-13)
         | 
| 25 | 
            -
             | 
| 26 | 
            -
            - Created a convenience function for creating stoplights.
         | 
| 27 | 
            -
            - Created a `VERSION` constant.
         | 
| 28 | 
            -
            - Added YARD type documentation for public methods.
         | 
| 29 | 
            -
             | 
| 30 | 
            -
            ## v0.5.1 (2014-11-19)
         | 
| 31 | 
            -
             | 
| 32 | 
            -
            - Fixed a logic bug that incorrectly determined red lights to be yellow.
         | 
| 33 | 
            -
             | 
| 34 | 
            -
            ## v0.5.0 (2014-11-19)
         | 
| 35 | 
            -
             | 
| 36 | 
            -
            - Data stores and notifiers can be configured on a per-stoplight basis. This
         | 
| 37 | 
            -
              allows stoplights to use stoplights internally.
         | 
| 38 | 
            -
            - Stoplights use stoplights internally to wrap calls to data stores and
         | 
| 39 | 
            -
              notifiers. This means they gracefully handle either going down.
         | 
| 40 | 
            -
            - Data stores only store failures and states. Also failures are stored in a ring
         | 
| 41 | 
            -
              buffer. This drastically reduces the amount of data stored.
         | 
| 42 | 
            -
            - Stoplights will use the fallback (if it's given) when they fail while they're
         | 
| 43 | 
            -
              green. This means they won't re-raise exceptions if you provide a fallback.
         | 
| 44 | 
            -
            - Stoplights pass the error to their notifiers when transitioning from green to
         | 
| 45 | 
            -
              red.
         | 
| 46 | 
            -
             | 
| 47 | 
            -
            ## v0.4.1 (2014-10-03)
         | 
| 48 | 
            -
             | 
| 49 | 
            -
            - Fixed a bug that caused green to red notifications to sometimes not be sent.
         | 
| 50 | 
            -
             | 
| 51 | 
            -
            ## v0.4.0 (2014-09-17)
         | 
| 52 | 
            -
             | 
| 53 | 
            -
            - Made stoplights handle failing notifiers by logging the failure to standard
         | 
| 54 | 
            -
              error.
         | 
| 55 | 
            -
            - Made stoplights automatically fall back to a fresh in-memory data store if the
         | 
| 56 | 
            -
              primary store is unavailable.
         | 
| 57 | 
            -
            - Generalized `Stoplight::Notifier::StandardError` into
         | 
| 58 | 
            -
              `Stoplight::Notifier::IO`.
         | 
| 59 | 
            -
            - Changed notification format from a string to a lambda. It accepts the same
         | 
| 60 | 
            -
              parameters that the format string accepted.
         | 
| 61 | 
            -
            - Updated `Stoplight::Notifier::Base#notify` to accept three parameters (the
         | 
| 62 | 
            -
              light, the before color, and the after color) instead of just one parameter
         | 
| 63 | 
            -
              (the message).
         | 
| 64 | 
            -
            - Prevented setting non-positive thresholds.
         | 
| 65 | 
            -
            - Removed `Stoplight::Mixin`.
         | 
| 66 | 
            -
             | 
| 67 | 
            -
            ## v0.3.1 (2014-09-12)
         | 
| 68 | 
            -
             | 
| 69 | 
            -
            - Replaced `Stoplight::Failure#error` with `#error_class` and `#error_message`.
         | 
| 70 | 
            -
              Also changed the constructor to take the class and the message instead of the
         | 
| 71 | 
            -
              error.
         | 
| 72 | 
            -
             | 
| 73 | 
            -
            ## v0.3.0 (2014-09-11)
         | 
| 74 | 
            -
             | 
| 75 | 
            -
            - Allowed formatting notifications.
         | 
| 76 | 
            -
            - Added automatic recovery from red lights.
         | 
| 77 | 
            -
            - Added `Stoplight::DataStore#clear_stale` for clearing stale lights.
         | 
| 78 | 
            -
            - Removed forwarded methods on `Stoplight` module.
         | 
| 79 | 
            -
            - Moved some methods from `Stoplight::DataStore::Base` to
         | 
| 80 | 
            -
              `Stoplight::DataStore`.
         | 
| 81 | 
            -
            - Renamed `Stoplight::DataStore::Base#purge` to `#clear_stale`.
         | 
| 82 | 
            -
            - Renamed `Stoplight::DataStore::Base#delete` to `#clear`.
         | 
| 83 | 
            -
            - Prefixed data store getters with `get_`.
         | 
| 84 | 
            -
            - Added `Stoplight::DataStore::Base#sync`.
         | 
| 85 | 
            -
            - Changed `Stoplight::DataStore::Base#get_failures` to return actual failures
         | 
| 86 | 
            -
              (`Stoplight::Failure`) instead of strings.
         | 
| 87 | 
            -
             | 
| 88 | 
            -
            ## v0.2.1 (2014-08-20)
         | 
| 89 | 
            -
             | 
| 90 | 
            -
            - Forced times to be serialized as strings.
         | 
| 91 | 
            -
             | 
| 92 | 
            -
            ## v0.2.0 (2014-08-18)
         | 
| 93 | 
            -
             | 
| 94 | 
            -
            - Switched `Stoplight.data_store` and `Stoplight.notifiers` over to using
         | 
| 95 | 
            -
              simple accessors.
         | 
| 96 | 
            -
            - Modified `Stoplight::DataStore::Redis` to accept an instance of `Redis`.
         | 
| 97 | 
            -
            - Refactored `Stoplight::DataStore::Redis` to use fewer keys.
         | 
| 98 | 
            -
            - Created `Stoplight::Notifier` and subclasses.
         | 
| 99 | 
            -
            - Sent notifications when moving from green to red.
         | 
| 100 | 
            -
            - Renamed `Stoplight::Light::DEFAULT_THRESHOLD` to
         | 
| 101 | 
            -
              `Stoplight::DEFAULT_THRESHOLD`.
         | 
| 102 | 
            -
            - Renamed `Stoplight::Error::NoFallback` to `Stoplight::Error::RedLight`.
         | 
| 103 | 
            -
            - Created `Stoplight::Mixin#stoplight` for easily creating and running simple
         | 
| 104 | 
            -
              stoplights.
         | 
| 105 | 
            -
             | 
| 106 | 
            -
            ## v0.1.0 (2014-08-12)
         | 
| 107 | 
            -
             | 
| 108 | 
            -
            - Initial release.
         | 
| 109 | 
            -
             | 
| 110 | 
            -
            [1]: http://semver.org/spec/v2.0.0.html
         | 
| 6 | 
            +
            [semantic versioning]: http://semver.org/spec/v2.0.0.html
         | 
| 7 | 
            +
            [on github]: https://github.com/orgsync/stoplight/releases
         | 
    
        data/LICENSE.md
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            The MIT License (MIT)
         | 
| 2 2 |  | 
| 3 | 
            -
            Copyright (c) 2015 Cameron Desautels, Taylor Fausak & Justin Steffy
         | 
| 3 | 
            +
            Copyright (c) 2015-2016 Cameron Desautels, Taylor Fausak & Justin Steffy
         | 
| 4 4 |  | 
| 5 5 | 
             
            Permission is hereby granted, free of charge, to any person obtaining a copy
         | 
| 6 6 | 
             
            of this software and associated documentation files (the "Software"), to deal
         | 
    
        data/README.md
    CHANGED
    
    | @@ -45,19 +45,19 @@ Check out [stoplight-admin][] for controlling your stoplights. | |
| 45 45 | 
             
            Add it to your Gemfile:
         | 
| 46 46 |  | 
| 47 47 | 
             
            ``` rb
         | 
| 48 | 
            -
            gem 'stoplight' | 
| 48 | 
            +
            gem 'stoplight'
         | 
| 49 49 | 
             
            ```
         | 
| 50 50 |  | 
| 51 51 | 
             
            Or install it manually:
         | 
| 52 52 |  | 
| 53 53 | 
             
            ``` sh
         | 
| 54 | 
            -
            $ gem install stoplight | 
| 54 | 
            +
            $ gem install stoplight
         | 
| 55 55 | 
             
            ```
         | 
| 56 56 |  | 
| 57 57 | 
             
            Stoplight uses [Semantic Versioning][]. Check out [the change log][] for a
         | 
| 58 58 | 
             
            detailed list of changes.
         | 
| 59 59 |  | 
| 60 | 
            -
            Stoplight works with all supported versions of Ruby (2.0 through 2. | 
| 60 | 
            +
            Stoplight works with all supported versions of Ruby (2.0 through 2.3).
         | 
| 61 61 |  | 
| 62 62 | 
             
            ## Basic usage
         | 
| 63 63 |  | 
| @@ -119,13 +119,15 @@ a while. (The yellow state corresponds to the half open state for circuit | |
| 119 119 |  | 
| 120 120 | 
             
            ### Custom errors
         | 
| 121 121 |  | 
| 122 | 
            +
            ##### Whitelisted errors
         | 
| 123 | 
            +
             | 
| 122 124 | 
             
            Some errors shouldn't cause your stoplight to move into the red state. Usually
         | 
| 123 125 | 
             
            these are handled elsewhere in your stack and don't represent real failures. A
         | 
| 124 126 | 
             
            good example is `ActiveRecord::RecordNotFound`.
         | 
| 125 127 |  | 
| 126 128 | 
             
            ``` rb
         | 
| 127 129 | 
             
            light = Stoplight('example-3') { User.find(123) }
         | 
| 128 | 
            -
              . | 
| 130 | 
            +
              .with_whitelisted_errors([ActiveRecord::RecordNotFound])
         | 
| 129 131 | 
             
            # => #<Stoplight::Light:...>
         | 
| 130 132 | 
             
            light.run
         | 
| 131 133 | 
             
            # ActiveRecord::RecordNotFound: Couldn't find User with ID=123
         | 
| @@ -137,9 +139,47 @@ light.color | |
| 137 139 | 
             
            # => "green"
         | 
| 138 140 | 
             
            ```
         | 
| 139 141 |  | 
| 140 | 
            -
            The following errors are always  | 
| 142 | 
            +
            The following errors are always whitelisted: `NoMemoryError`, `ScriptError`,
         | 
| 141 143 | 
             
            `SecurityError`, `SignalException`, `SystemExit`, and `SystemStackError`.
         | 
| 142 144 |  | 
| 145 | 
            +
            Whitelisted errors take precedence over [blacklisted errors](#blacklisted-errors).
         | 
| 146 | 
            +
             | 
| 147 | 
            +
            ##### Blacklisted errors
         | 
| 148 | 
            +
             | 
| 149 | 
            +
            You may want only certain errors to cause your stoplight to move into the red
         | 
| 150 | 
            +
            state.
         | 
| 151 | 
            +
             | 
| 152 | 
            +
            ``` rb
         | 
| 153 | 
            +
            light = Stoplight('example-4') { 1 / 0 }
         | 
| 154 | 
            +
              .with_blacklisted_errors([ZeroDivisionError])
         | 
| 155 | 
            +
            # => #<Stoplight::Light:...>
         | 
| 156 | 
            +
            light.run
         | 
| 157 | 
            +
            # ZeroDivisionError: divided by 0
         | 
| 158 | 
            +
            light.run
         | 
| 159 | 
            +
            # ZeroDivisionError: divided by 0
         | 
| 160 | 
            +
            light.run
         | 
| 161 | 
            +
            # ZeroDivisionError: divided by 0
         | 
| 162 | 
            +
            light.color
         | 
| 163 | 
            +
            # => "red"
         | 
| 164 | 
            +
            ```
         | 
| 165 | 
            +
             | 
| 166 | 
            +
            This will cause all other errors to be raised normally. They won't affect the
         | 
| 167 | 
            +
            state of your stoplight.
         | 
| 168 | 
            +
             | 
| 169 | 
            +
            ``` rb
         | 
| 170 | 
            +
            light = Stoplight('example-5') { fail }
         | 
| 171 | 
            +
              .with_blacklisted_errors([ZeroDivisionError])
         | 
| 172 | 
            +
            # => #<Stoplight::Light:...>
         | 
| 173 | 
            +
            light.run
         | 
| 174 | 
            +
            # RuntimeError:
         | 
| 175 | 
            +
            light.run
         | 
| 176 | 
            +
            # RuntimeError:
         | 
| 177 | 
            +
            light.run
         | 
| 178 | 
            +
            # RuntimeError:
         | 
| 179 | 
            +
            light.color
         | 
| 180 | 
            +
            # => "green"
         | 
| 181 | 
            +
            ```
         | 
| 182 | 
            +
             | 
| 143 183 | 
             
            ### Custom fallback
         | 
| 144 184 |  | 
| 145 185 | 
             
            By default, stoplights will re-raise errors when they're green. When they're
         | 
| @@ -148,7 +188,7 @@ fallback that will be called in both of these cases. It will be passed the | |
| 148 188 | 
             
            error if the light was green.
         | 
| 149 189 |  | 
| 150 190 | 
             
            ``` rb
         | 
| 151 | 
            -
            light = Stoplight('example- | 
| 191 | 
            +
            light = Stoplight('example-6') { 1 / 0 }
         | 
| 152 192 | 
             
              .with_fallback { |e| p e; 'default' }
         | 
| 153 193 | 
             
            # => #<Stoplight::Light:..>
         | 
| 154 194 | 
             
            light.run
         | 
| @@ -172,7 +212,7 @@ Some bits of code might be allowed to fail more or less frequently than others. | |
| 172 212 | 
             
            You can configure this by setting a custom threshold.
         | 
| 173 213 |  | 
| 174 214 | 
             
            ``` rb
         | 
| 175 | 
            -
            light = Stoplight('example- | 
| 215 | 
            +
            light = Stoplight('example-7') { fail }
         | 
| 176 216 | 
             
              .with_threshold(1)
         | 
| 177 217 | 
             
            # => #<Stoplight::Light:...>
         | 
| 178 218 | 
             
            light.run
         | 
| @@ -191,7 +231,7 @@ time. A light in the red state for longer than the timeout will transition to | |
| 191 231 | 
             
            the yellow state. This timeout is customizable.
         | 
| 192 232 |  | 
| 193 233 | 
             
            ``` rb
         | 
| 194 | 
            -
            light = Stoplight('example- | 
| 234 | 
            +
            light = Stoplight('example-8') { fail }
         | 
| 195 235 | 
             
              .with_timeout(1)
         | 
| 196 236 | 
             
            # => #<Stoplight::Light:...>
         | 
| 197 237 | 
             
            light.run
         | 
| @@ -227,7 +267,7 @@ class ApplicationController < ActionController::Base | |
| 227 267 |  | 
| 228 268 | 
             
              def stoplight(&block)
         | 
| 229 269 | 
             
                Stoplight("#{params[:controller]}##{params[:action]}", &block)
         | 
| 230 | 
            -
                  . | 
| 270 | 
            +
                  .with_whitelisted_errors([ActiveRecord::RecordNotFound])
         | 
| 231 271 | 
             
                  .with_fallback do |error|
         | 
| 232 272 | 
             
                    Rails.logger.error(error)
         | 
| 233 273 | 
             
                    render(nothing: true, status: :service_unavailable)
         | 
| @@ -379,7 +419,7 @@ override the default behavior. You can lock a light in either the green or red | |
| 379 419 | 
             
            state using `set_state`.
         | 
| 380 420 |  | 
| 381 421 | 
             
            ``` rb
         | 
| 382 | 
            -
            light = Stoplight('example- | 
| 422 | 
            +
            light = Stoplight('example-9') { true }
         | 
| 383 423 | 
             
            # => #<Stoplight::Light:..>
         | 
| 384 424 | 
             
            light.run
         | 
| 385 425 | 
             
            # => true
         | 
| @@ -418,7 +458,7 @@ give each test case a fresh data store with RSpec. | |
| 418 458 |  | 
| 419 459 | 
             
            ``` rb
         | 
| 420 460 | 
             
            before(:each) do
         | 
| 421 | 
            -
              Stoplight::Light. | 
| 461 | 
            +
              Stoplight::Light.default_data_store = Stoplight::DataStore::Memory.new
         | 
| 422 462 | 
             
            end
         | 
| 423 463 | 
             
            ```
         | 
| 424 464 |  | 
    
        data/lib/stoplight/default.rb
    CHANGED
    
    | @@ -2,7 +2,7 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            module Stoplight
         | 
| 4 4 | 
             
              module Default
         | 
| 5 | 
            -
                 | 
| 5 | 
            +
                WHITELISTED_ERRORS = [
         | 
| 6 6 | 
             
                  NoMemoryError,
         | 
| 7 7 | 
             
                  ScriptError,
         | 
| 8 8 | 
             
                  SecurityError,
         | 
| @@ -11,9 +11,11 @@ module Stoplight | |
| 11 11 | 
             
                  SystemStackError
         | 
| 12 12 | 
             
                ].freeze
         | 
| 13 13 |  | 
| 14 | 
            +
                BLACKLISTED_ERRORS = [].freeze
         | 
| 15 | 
            +
             | 
| 14 16 | 
             
                DATA_STORE = DataStore::Memory.new
         | 
| 15 17 |  | 
| 16 | 
            -
                ERROR_NOTIFIER = -> error { warn error }
         | 
| 18 | 
            +
                ERROR_NOTIFIER = -> (error) { warn error }
         | 
| 17 19 |  | 
| 18 20 | 
             
                FALLBACK = nil
         | 
| 19 21 |  | 
    
        data/lib/stoplight/light.rb
    CHANGED
    
    | @@ -5,7 +5,9 @@ module Stoplight | |
| 5 5 | 
             
                include Runnable
         | 
| 6 6 |  | 
| 7 7 | 
             
                # @return [Array<Exception>]
         | 
| 8 | 
            -
                attr_reader : | 
| 8 | 
            +
                attr_reader :whitelisted_errors
         | 
| 9 | 
            +
                # @return [Array<Exception>]
         | 
| 10 | 
            +
                attr_reader :blacklisted_errors
         | 
| 9 11 | 
             
                # @return [Proc]
         | 
| 10 12 | 
             
                attr_reader :code
         | 
| 11 13 | 
             
                # @return [DataStore::Base]
         | 
| @@ -42,7 +44,8 @@ module Stoplight | |
| 42 44 | 
             
                  @name = name
         | 
| 43 45 | 
             
                  @code = code
         | 
| 44 46 |  | 
| 45 | 
            -
                  @ | 
| 47 | 
            +
                  @whitelisted_errors = Default::WHITELISTED_ERRORS
         | 
| 48 | 
            +
                  @blacklisted_errors = Default::BLACKLISTED_ERRORS
         | 
| 46 49 | 
             
                  @data_store = self.class.default_data_store
         | 
| 47 50 | 
             
                  @error_notifier = self.class.default_error_notifier
         | 
| 48 51 | 
             
                  @fallback = Default::FALLBACK
         | 
| @@ -51,10 +54,19 @@ module Stoplight | |
| 51 54 | 
             
                  @timeout = Default::TIMEOUT
         | 
| 52 55 | 
             
                end
         | 
| 53 56 |  | 
| 54 | 
            -
                # @param  | 
| 57 | 
            +
                # @param whitelisted_errors [Array<Exception>]
         | 
| 58 | 
            +
                # @return [self]
         | 
| 59 | 
            +
                def with_whitelisted_errors(whitelisted_errors)
         | 
| 60 | 
            +
                  @whitelisted_errors = Default::WHITELISTED_ERRORS + whitelisted_errors
         | 
| 61 | 
            +
                  self
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                alias with_allowed_errors with_whitelisted_errors
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                # @param blacklisted_errors [Array<Exception>]
         | 
| 55 67 | 
             
                # @return [self]
         | 
| 56 | 
            -
                def  | 
| 57 | 
            -
                  @ | 
| 68 | 
            +
                def with_blacklisted_errors(blacklisted_errors)
         | 
| 69 | 
            +
                  @blacklisted_errors = Default::BLACKLISTED_ERRORS + blacklisted_errors
         | 
| 58 70 | 
             
                  self
         | 
| 59 71 | 
             
                end
         | 
| 60 72 |  | 
| @@ -56,8 +56,14 @@ module Stoplight | |
| 56 56 | 
             
                    handle_error(error, on_failure)
         | 
| 57 57 | 
             
                  end
         | 
| 58 58 |  | 
| 59 | 
            +
                  def not_blacklisted_error?(error)
         | 
| 60 | 
            +
                    blacklisted_errors.length > 0 &&
         | 
| 61 | 
            +
                      blacklisted_errors.none? { |klass| error.is_a?(klass) }
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
             | 
| 59 64 | 
             
                  def handle_error(error, on_failure)
         | 
| 60 | 
            -
                    fail error if  | 
| 65 | 
            +
                    fail error if whitelisted_errors.any? { |klass| error.is_a?(klass) }
         | 
| 66 | 
            +
                    fail error if not_blacklisted_error?(error)
         | 
| 61 67 | 
             
                    size = record_failure(error)
         | 
| 62 68 | 
             
                    on_failure.call(size, error) if on_failure
         | 
| 63 69 | 
             
                    fail error unless fallback
         | 
| @@ -84,9 +90,11 @@ module Stoplight | |
| 84 90 | 
             
                  end
         | 
| 85 91 |  | 
| 86 92 | 
             
                  def safely(default = nil, &code)
         | 
| 87 | 
            -
                    return  | 
| 93 | 
            +
                    return yield if data_store == Default::DATA_STORE
         | 
| 88 94 |  | 
| 89 | 
            -
                    self | 
| 95 | 
            +
                    self
         | 
| 96 | 
            +
                      .class
         | 
| 97 | 
            +
                      .new("#{name}-safely", &code)
         | 
| 90 98 | 
             
                      .with_data_store(Default::DATA_STORE)
         | 
| 91 99 | 
             
                      .with_fallback do |error|
         | 
| 92 100 | 
             
                        error_notifier.call(error) if error
         | 
    
        data/lib/stoplight/version.rb
    CHANGED
    
    
| @@ -7,19 +7,33 @@ RSpec.describe Stoplight::Default do | |
| 7 7 | 
             
                expect(described_class).to be_a(Module)
         | 
| 8 8 | 
             
              end
         | 
| 9 9 |  | 
| 10 | 
            -
              describe ':: | 
| 10 | 
            +
              describe '::WHITELISTED_ERRORS' do
         | 
| 11 11 | 
             
                it 'is an array' do
         | 
| 12 | 
            -
                  expect(Stoplight::Default:: | 
| 12 | 
            +
                  expect(Stoplight::Default::WHITELISTED_ERRORS).to be_an(Array)
         | 
| 13 13 | 
             
                end
         | 
| 14 14 |  | 
| 15 15 | 
             
                it 'contains exception classes' do
         | 
| 16 | 
            -
                  Stoplight::Default:: | 
| 17 | 
            -
                    expect( | 
| 16 | 
            +
                  Stoplight::Default::WHITELISTED_ERRORS.each do |whitelisted_error|
         | 
| 17 | 
            +
                    expect(whitelisted_error).to be < Exception
         | 
| 18 18 | 
             
                  end
         | 
| 19 19 | 
             
                end
         | 
| 20 20 |  | 
| 21 21 | 
             
                it 'is frozen' do
         | 
| 22 | 
            -
                  expect(Stoplight::Default:: | 
| 22 | 
            +
                  expect(Stoplight::Default::WHITELISTED_ERRORS).to be_frozen
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              describe '::BLACKLISTED_ERRORS' do
         | 
| 27 | 
            +
                it 'is an array' do
         | 
| 28 | 
            +
                  expect(Stoplight::Default::BLACKLISTED_ERRORS).to be_an(Array)
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                it 'is empty' do
         | 
| 32 | 
            +
                  expect(Stoplight::Default::BLACKLISTED_ERRORS).to be_empty
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                it 'is frozen' do
         | 
| 36 | 
            +
                  expect(Stoplight::Default::BLACKLISTED_ERRORS).to be_frozen
         | 
| 23 37 | 
             
                end
         | 
| 24 38 | 
             
              end
         | 
| 25 39 |  | 
| @@ -8,7 +8,7 @@ RSpec.describe Stoplight::Light::Runnable do | |
| 8 8 |  | 
| 9 9 | 
             
              let(:code) { -> { code_result } }
         | 
| 10 10 | 
             
              let(:code_result) { random_string }
         | 
| 11 | 
            -
              let(:fallback) { -> _ { fallback_result } }
         | 
| 11 | 
            +
              let(:fallback) { -> (_) { fallback_result } }
         | 
| 12 12 | 
             
              let(:fallback_result) { random_string }
         | 
| 13 13 | 
             
              let(:name) { random_string }
         | 
| 14 14 |  | 
| @@ -119,10 +119,79 @@ RSpec.describe Stoplight::Light::Runnable do | |
| 119 119 | 
             
                      expect(io.string).to_not eql('')
         | 
| 120 120 | 
             
                    end
         | 
| 121 121 |  | 
| 122 | 
            -
                    context 'when the error is  | 
| 123 | 
            -
                      let(: | 
| 122 | 
            +
                    context 'when the error is whitelisted' do
         | 
| 123 | 
            +
                      let(:whitelisted_errors) { [error.class] }
         | 
| 124 124 |  | 
| 125 | 
            -
                      before { subject. | 
| 125 | 
            +
                      before { subject.with_whitelisted_errors(whitelisted_errors) }
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                      it 'does not record the failure' do
         | 
| 128 | 
            +
                        expect(subject.data_store.get_failures(subject).size).to eql(0)
         | 
| 129 | 
            +
                        begin
         | 
| 130 | 
            +
                          subject.run
         | 
| 131 | 
            +
                        rescue error.class
         | 
| 132 | 
            +
                          nil
         | 
| 133 | 
            +
                        end
         | 
| 134 | 
            +
                        expect(subject.data_store.get_failures(subject).size).to eql(0)
         | 
| 135 | 
            +
                      end
         | 
| 136 | 
            +
                    end
         | 
| 137 | 
            +
             | 
| 138 | 
            +
                    context 'when the error is blacklisted' do
         | 
| 139 | 
            +
                      let(:blacklisted_errors) { [error.class] }
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                      before { subject.with_blacklisted_errors(blacklisted_errors) }
         | 
| 142 | 
            +
             | 
| 143 | 
            +
                      it 'records the failure' do
         | 
| 144 | 
            +
                        expect(subject.data_store.get_failures(subject).size).to eql(0)
         | 
| 145 | 
            +
                        begin
         | 
| 146 | 
            +
                          subject.run
         | 
| 147 | 
            +
                        rescue error.class
         | 
| 148 | 
            +
                          nil
         | 
| 149 | 
            +
                        end
         | 
| 150 | 
            +
                        expect(subject.data_store.get_failures(subject).size).to eql(1)
         | 
| 151 | 
            +
                      end
         | 
| 152 | 
            +
                    end
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                    context 'when the error is not blacklisted' do
         | 
| 155 | 
            +
                      let(:blacklisted_errors) { [RuntimeError] }
         | 
| 156 | 
            +
             | 
| 157 | 
            +
                      before { subject.with_blacklisted_errors(blacklisted_errors) }
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                      it 'does not record the failure' do
         | 
| 160 | 
            +
                        expect(subject.data_store.get_failures(subject).size).to eql(0)
         | 
| 161 | 
            +
                        begin
         | 
| 162 | 
            +
                          subject.run
         | 
| 163 | 
            +
                        rescue error.class
         | 
| 164 | 
            +
                          nil
         | 
| 165 | 
            +
                        end
         | 
| 166 | 
            +
                        expect(subject.data_store.get_failures(subject).size).to eql(0)
         | 
| 167 | 
            +
                      end
         | 
| 168 | 
            +
                    end
         | 
| 169 | 
            +
             | 
| 170 | 
            +
                    context 'when the list of blacklisted errors is empty' do
         | 
| 171 | 
            +
                      let(:blacklisted_errors) { [] }
         | 
| 172 | 
            +
             | 
| 173 | 
            +
                      before { subject.with_blacklisted_errors(blacklisted_errors) }
         | 
| 174 | 
            +
             | 
| 175 | 
            +
                      it 'records the failure' do
         | 
| 176 | 
            +
                        expect(subject.data_store.get_failures(subject).size).to eql(0)
         | 
| 177 | 
            +
                        begin
         | 
| 178 | 
            +
                          subject.run
         | 
| 179 | 
            +
                        rescue error.class
         | 
| 180 | 
            +
                          nil
         | 
| 181 | 
            +
                        end
         | 
| 182 | 
            +
                        expect(subject.data_store.get_failures(subject).size).to eql(1)
         | 
| 183 | 
            +
                      end
         | 
| 184 | 
            +
                    end
         | 
| 185 | 
            +
             | 
| 186 | 
            +
                    context 'when the error is both whitelisted and blacklisted' do
         | 
| 187 | 
            +
                      let(:whitelisted_errors) { [error.class] }
         | 
| 188 | 
            +
                      let(:blacklisted_errors) { [error.class] }
         | 
| 189 | 
            +
             | 
| 190 | 
            +
                      before do
         | 
| 191 | 
            +
                        subject
         | 
| 192 | 
            +
                          .with_whitelisted_errors(whitelisted_errors)
         | 
| 193 | 
            +
                          .with_blacklisted_errors(blacklisted_errors)
         | 
| 194 | 
            +
                      end
         | 
| 126 195 |  | 
| 127 196 | 
             
                      it 'does not record the failure' do
         | 
| 128 197 | 
             
                        expect(subject.data_store.get_failures(subject).size).to eql(0)
         | 
| @@ -154,7 +223,7 @@ RSpec.describe Stoplight::Light::Runnable do | |
| 154 223 |  | 
| 155 224 | 
             
                  context 'when the data store is failing' do
         | 
| 156 225 | 
             
                    let(:data_store) { Object.new }
         | 
| 157 | 
            -
                    let(:error_notifier) { -> _ {} }
         | 
| 226 | 
            +
                    let(:error_notifier) { -> (_) {} }
         | 
| 158 227 |  | 
| 159 228 | 
             
                    before do
         | 
| 160 229 | 
             
                      subject
         | 
| @@ -42,7 +42,7 @@ RSpec.describe Stoplight::Light do | |
| 42 42 | 
             
                after { described_class.default_error_notifier = @default_error_notifier }
         | 
| 43 43 |  | 
| 44 44 | 
             
                it 'sets the error notifier' do
         | 
| 45 | 
            -
                  default_error_notifier = -> _ {}
         | 
| 45 | 
            +
                  default_error_notifier = -> (_) {}
         | 
| 46 46 | 
             
                  described_class.default_error_notifier = default_error_notifier
         | 
| 47 47 | 
             
                  expect(described_class.default_error_notifier)
         | 
| 48 48 | 
             
                    .to eql(default_error_notifier)
         | 
| @@ -67,9 +67,19 @@ RSpec.describe Stoplight::Light do | |
| 67 67 | 
             
                end
         | 
| 68 68 | 
             
              end
         | 
| 69 69 |  | 
| 70 | 
            -
              describe '# | 
| 70 | 
            +
              describe '#whitelisted_errors' do
         | 
| 71 71 | 
             
                it 'is initially the default' do
         | 
| 72 | 
            -
                  expect(light. | 
| 72 | 
            +
                  expect(light.whitelisted_errors).to eql(
         | 
| 73 | 
            +
                    Stoplight::Default::WHITELISTED_ERRORS
         | 
| 74 | 
            +
                  )
         | 
| 75 | 
            +
                end
         | 
| 76 | 
            +
              end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
              describe '#blacklisted_errors' do
         | 
| 79 | 
            +
                it 'is initially the default' do
         | 
| 80 | 
            +
                  expect(light.blacklisted_errors).to eql(
         | 
| 81 | 
            +
                    Stoplight::Default::BLACKLISTED_ERRORS
         | 
| 82 | 
            +
                  )
         | 
| 73 83 | 
             
                end
         | 
| 74 84 | 
             
              end
         | 
| 75 85 |  | 
| @@ -122,12 +132,30 @@ RSpec.describe Stoplight::Light do | |
| 122 132 | 
             
                end
         | 
| 123 133 | 
             
              end
         | 
| 124 134 |  | 
| 135 | 
            +
              describe '#with_whitelisted_errors' do
         | 
| 136 | 
            +
                it 'adds the whitelisted errors to the default' do
         | 
| 137 | 
            +
                  whitelisted_errors = [StandardError]
         | 
| 138 | 
            +
                  light.with_whitelisted_errors(whitelisted_errors)
         | 
| 139 | 
            +
                  expect(light.whitelisted_errors)
         | 
| 140 | 
            +
                    .to eql(Stoplight::Default::WHITELISTED_ERRORS + whitelisted_errors)
         | 
| 141 | 
            +
                end
         | 
| 142 | 
            +
              end
         | 
| 143 | 
            +
             | 
| 125 144 | 
             
              describe '#with_allowed_errors' do
         | 
| 126 | 
            -
                it ' | 
| 145 | 
            +
                it 'sets whitelisted_errors' do
         | 
| 127 146 | 
             
                  allowed_errors = [StandardError]
         | 
| 128 147 | 
             
                  light.with_allowed_errors(allowed_errors)
         | 
| 129 | 
            -
                  expect(light. | 
| 130 | 
            -
                    .to eql(Stoplight::Default:: | 
| 148 | 
            +
                  expect(light.whitelisted_errors)
         | 
| 149 | 
            +
                    .to eql(Stoplight::Default::WHITELISTED_ERRORS + allowed_errors)
         | 
| 150 | 
            +
                end
         | 
| 151 | 
            +
              end
         | 
| 152 | 
            +
             | 
| 153 | 
            +
              describe '#with_blacklisted_errors' do
         | 
| 154 | 
            +
                it 'adds the blacklisted errors to the default' do
         | 
| 155 | 
            +
                  blacklisted_errors = [StandardError]
         | 
| 156 | 
            +
                  light.with_blacklisted_errors(blacklisted_errors)
         | 
| 157 | 
            +
                  expect(light.blacklisted_errors)
         | 
| 158 | 
            +
                    .to eql(Stoplight::Default::BLACKLISTED_ERRORS + blacklisted_errors)
         | 
| 131 159 | 
             
                end
         | 
| 132 160 | 
             
              end
         | 
| 133 161 |  | 
| @@ -141,7 +169,7 @@ RSpec.describe Stoplight::Light do | |
| 141 169 |  | 
| 142 170 | 
             
              describe '#with_error_notifier' do
         | 
| 143 171 | 
             
                it 'sets the error notifier' do
         | 
| 144 | 
            -
                  error_notifier = -> _ {}
         | 
| 172 | 
            +
                  error_notifier = -> (_) {}
         | 
| 145 173 | 
             
                  light.with_error_notifier(&error_notifier)
         | 
| 146 174 | 
             
                  expect(light.error_notifier).to eql(error_notifier)
         | 
| 147 175 | 
             
                end
         | 
| @@ -149,7 +177,7 @@ RSpec.describe Stoplight::Light do | |
| 149 177 |  | 
| 150 178 | 
             
              describe '#with_fallback' do
         | 
| 151 179 | 
             
                it 'sets the fallback' do
         | 
| 152 | 
            -
                  fallback = -> _ {}
         | 
| 180 | 
            +
                  fallback = -> (_) {}
         | 
| 153 181 | 
             
                  light.with_fallback(&fallback)
         | 
| 154 182 | 
             
                  expect(light.fallback).to eql(fallback)
         | 
| 155 183 | 
             
                end
         | 
| @@ -1,7 +1,10 @@ | |
| 1 1 | 
             
            # coding: utf-8
         | 
| 2 2 |  | 
| 3 3 | 
             
            require 'spec_helper'
         | 
| 4 | 
            -
             | 
| 4 | 
            +
             | 
| 5 | 
            +
            # require 'bugsnag'
         | 
| 6 | 
            +
            module Bugsnag
         | 
| 7 | 
            +
            end
         | 
| 5 8 |  | 
| 6 9 | 
             
            RSpec.describe Stoplight::Notifier::Bugsnag do
         | 
| 7 10 | 
             
              StoplightStatusChange = Stoplight::Notifier::Bugsnag::StoplightStatusChange
         | 
| @@ -42,7 +45,7 @@ RSpec.describe Stoplight::Notifier::Bugsnag do | |
| 42 45 |  | 
| 43 46 | 
             
              describe '#bugsnag' do
         | 
| 44 47 | 
             
                it 'reads the Bugsnag client' do
         | 
| 45 | 
            -
                  client =  | 
| 48 | 
            +
                  client = Bugsnag
         | 
| 46 49 | 
             
                  expect(described_class.new(client, nil).bugsnag)
         | 
| 47 50 | 
             
                    .to eql(client)
         | 
| 48 51 | 
             
                end
         | 
| @@ -55,7 +58,7 @@ RSpec.describe Stoplight::Notifier::Bugsnag do | |
| 55 58 | 
             
                let(:from_color) { Stoplight::Color::GREEN }
         | 
| 56 59 | 
             
                let(:to_color) { Stoplight::Color::RED }
         | 
| 57 60 | 
             
                let(:notifier) { described_class.new(bugsnag) }
         | 
| 58 | 
            -
                let(:bugsnag) {  | 
| 61 | 
            +
                let(:bugsnag) { Bugsnag }
         | 
| 59 62 |  | 
| 60 63 | 
             
                subject(:result) do
         | 
| 61 64 | 
             
                  notifier.notify(light, from_color, to_color, error)
         | 
| @@ -1,7 +1,14 @@ | |
| 1 1 | 
             
            # coding: utf-8
         | 
| 2 2 |  | 
| 3 3 | 
             
            require 'spec_helper'
         | 
| 4 | 
            -
             | 
| 4 | 
            +
             | 
| 5 | 
            +
            # require 'slack-notifier'
         | 
| 6 | 
            +
            module Slack
         | 
| 7 | 
            +
              class Notifier
         | 
| 8 | 
            +
                def initialize(*)
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
            end
         | 
| 5 12 |  | 
| 6 13 | 
             
            RSpec.describe Stoplight::Notifier::Slack do
         | 
| 7 14 | 
             
              it_behaves_like 'a generic notifier'
         | 
    
        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.3.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:  | 
| 13 | 
            +
            date: 2016-01-28 00:00:00.000000000 Z
         | 
| 14 14 | 
             
            dependencies:
         | 
| 15 15 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 16 16 | 
             
              name: benchmark-ips
         | 
| @@ -32,14 +32,14 @@ dependencies: | |
| 32 32 | 
             
                requirements:
         | 
| 33 33 | 
             
                - - "~>"
         | 
| 34 34 | 
             
                  - !ruby/object:Gem::Version
         | 
| 35 | 
            -
                    version: ' | 
| 35 | 
            +
                    version: '3.0'
         | 
| 36 36 | 
             
              type: :development
         | 
| 37 37 | 
             
              prerelease: false
         | 
| 38 38 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 39 39 | 
             
                requirements:
         | 
| 40 40 | 
             
                - - "~>"
         | 
| 41 41 | 
             
                  - !ruby/object:Gem::Version
         | 
| 42 | 
            -
                    version: ' | 
| 42 | 
            +
                    version: '3.0'
         | 
| 43 43 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 44 44 | 
             
              name: coveralls
         | 
| 45 45 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -186,14 +186,14 @@ dependencies: | |
| 186 186 | 
             
                requirements:
         | 
| 187 187 | 
             
                - - "~>"
         | 
| 188 188 | 
             
                  - !ruby/object:Gem::Version
         | 
| 189 | 
            -
                    version:  | 
| 189 | 
            +
                    version: 0.36.0
         | 
| 190 190 | 
             
              type: :development
         | 
| 191 191 | 
             
              prerelease: false
         | 
| 192 192 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 193 193 | 
             
                requirements:
         | 
| 194 194 | 
             
                - - "~>"
         | 
| 195 195 | 
             
                  - !ruby/object:Gem::Version
         | 
| 196 | 
            -
                    version:  | 
| 196 | 
            +
                    version: 0.36.0
         | 
| 197 197 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 198 198 | 
             
              name: slack-notifier
         | 
| 199 199 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -305,7 +305,7 @@ required_ruby_version: !ruby/object:Gem::Requirement | |
| 305 305 | 
             
              requirements:
         | 
| 306 306 | 
             
              - - ">="
         | 
| 307 307 | 
             
                - !ruby/object:Gem::Version
         | 
| 308 | 
            -
                  version:  | 
| 308 | 
            +
                  version: '2'
         | 
| 309 309 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 310 310 | 
             
              requirements:
         | 
| 311 311 | 
             
              - - ">="
         |