stoplight 3.0.1 → 4.1.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.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +174 -181
  3. data/lib/stoplight/builder.rb +70 -0
  4. data/lib/stoplight/circuit_breaker.rb +102 -0
  5. data/lib/stoplight/configurable.rb +95 -0
  6. data/lib/stoplight/configuration.rb +126 -0
  7. data/lib/stoplight/data_store/memory.rb +20 -5
  8. data/lib/stoplight/data_store/redis.rb +37 -5
  9. data/lib/stoplight/default.rb +2 -0
  10. data/lib/stoplight/error.rb +1 -0
  11. data/lib/stoplight/light/deprecated.rb +44 -0
  12. data/lib/stoplight/light/lockable.rb +45 -0
  13. data/lib/stoplight/light/runnable.rb +31 -13
  14. data/lib/stoplight/light.rb +69 -63
  15. data/lib/stoplight/rspec/generic_notifier.rb +42 -0
  16. data/lib/stoplight/rspec.rb +3 -0
  17. data/lib/stoplight/version.rb +1 -1
  18. data/lib/stoplight.rb +32 -8
  19. data/spec/spec_helper.rb +7 -0
  20. data/spec/stoplight/builder_spec.rb +165 -0
  21. data/spec/stoplight/circuit_breaker_spec.rb +43 -0
  22. data/spec/stoplight/configurable_spec.rb +25 -0
  23. data/spec/stoplight/data_store/memory_spec.rb +12 -149
  24. data/spec/stoplight/data_store/redis_spec.rb +26 -158
  25. data/spec/stoplight/error_spec.rb +10 -0
  26. data/spec/stoplight/light/lockable_spec.rb +93 -0
  27. data/spec/stoplight/light/runnable_spec.rb +14 -265
  28. data/spec/stoplight/light_spec.rb +4 -28
  29. data/spec/stoplight/notifier/generic_spec.rb +35 -35
  30. data/spec/stoplight/notifier/io_spec.rb +1 -0
  31. data/spec/stoplight/notifier/logger_spec.rb +3 -0
  32. data/spec/stoplight_spec.rb +17 -6
  33. data/spec/support/configurable.rb +69 -0
  34. data/spec/support/data_store/base/clear_failures.rb +18 -0
  35. data/spec/support/data_store/base/clear_state.rb +20 -0
  36. data/spec/support/data_store/base/get_all.rb +44 -0
  37. data/spec/support/data_store/base/get_failures.rb +30 -0
  38. data/spec/support/data_store/base/get_state.rb +7 -0
  39. data/spec/support/data_store/base/names.rb +29 -0
  40. data/spec/support/data_store/base/record_failures.rb +70 -0
  41. data/spec/support/data_store/base/set_state.rb +15 -0
  42. data/spec/support/data_store/base/with_notification_lock.rb +27 -0
  43. data/spec/support/data_store/base.rb +21 -0
  44. data/spec/support/database_cleaner.rb +26 -0
  45. data/spec/support/exception_helpers.rb +9 -0
  46. data/spec/support/light/runnable/color.rb +79 -0
  47. data/spec/support/light/runnable/run.rb +247 -0
  48. data/spec/support/light/runnable/state.rb +31 -0
  49. data/spec/support/light/runnable.rb +5 -0
  50. metadata +53 -231
  51. data/lib/stoplight/notifier/bugsnag.rb +0 -37
  52. data/lib/stoplight/notifier/honeybadger.rb +0 -44
  53. data/lib/stoplight/notifier/pagerduty.rb +0 -21
  54. data/lib/stoplight/notifier/raven.rb +0 -40
  55. data/lib/stoplight/notifier/rollbar.rb +0 -39
  56. data/lib/stoplight/notifier/slack.rb +0 -21
  57. data/spec/stoplight/notifier/bugsnag_spec.rb +0 -90
  58. data/spec/stoplight/notifier/honeybadger_spec.rb +0 -88
  59. data/spec/stoplight/notifier/pagerduty_spec.rb +0 -40
  60. data/spec/stoplight/notifier/raven_spec.rb +0 -90
  61. data/spec/stoplight/notifier/rollbar_spec.rb +0 -90
  62. data/spec/stoplight/notifier/slack_spec.rb +0 -46
@@ -3,6 +3,12 @@
3
3
  module Stoplight
4
4
  class Light
5
5
  module Runnable # rubocop:disable Style/Documentation
6
+ # @return [String]
7
+ def state
8
+ _, state = failures_and_state
9
+ state
10
+ end
11
+
6
12
  # @return [String]
7
13
  def color
8
14
  failures, state = failures_and_state
@@ -13,37 +19,51 @@ module Stoplight
13
19
  elsif failures.size < threshold then Color::GREEN
14
20
  elsif failure && Time.now - failure.time >= cool_off_time
15
21
  Color::YELLOW
16
- else Color::RED
22
+ else
23
+ Color::RED
17
24
  end
18
25
  end
19
26
 
20
27
  # @raise [Error::RedLight]
21
- def run
28
+ def run(&code)
29
+ code = validate_code(&code)
22
30
  case color
23
- when Color::GREEN then run_green
24
- when Color::YELLOW then run_yellow
31
+ when Color::GREEN then run_green(&code)
32
+ when Color::YELLOW then run_yellow(&code)
25
33
  else run_red
26
34
  end
27
35
  end
28
36
 
29
37
  private
30
38
 
31
- def run_green
39
+ def validate_code(&code)
40
+ raise ArgumentError, <<~ERROR if block_given? && self.code
41
+ passing code block into both `Light.new` and `Light#run` is not allowed
42
+ ERROR
43
+
44
+ raise ArgumentError, <<~ERROR unless block_given? || self.code
45
+ nothing to run. Please, pass a block into `Light#run`
46
+ ERROR
47
+
48
+ code || self.code
49
+ end
50
+
51
+ def run_green(&code)
32
52
  on_failure = lambda do |size, error|
33
53
  notify(Color::GREEN, Color::RED, error) if failures_threshold_breached?(size, threshold)
34
54
  end
35
- run_code(nil, on_failure)
55
+ run_code(nil, on_failure, &code)
36
56
  end
37
57
 
38
58
  def failures_threshold_breached?(current_failures_count, max_errors_threshold)
39
59
  current_failures_count == max_errors_threshold
40
60
  end
41
61
 
42
- def run_yellow
62
+ def run_yellow(&code)
43
63
  on_success = lambda do |failures|
44
64
  notify(Color::RED, Color::GREEN) unless failures.empty?
45
65
  end
46
- run_code(on_success, nil)
66
+ run_code(on_success, nil, &code)
47
67
  end
48
68
 
49
69
  def run_red
@@ -52,7 +72,7 @@ module Stoplight
52
72
  fallback.call(nil)
53
73
  end
54
74
 
55
- def run_code(on_success, on_failure)
75
+ def run_code(on_success, on_failure, &code)
56
76
  result = code.call
57
77
  failures = clear_failures
58
78
  on_success&.call(failures)
@@ -94,15 +114,13 @@ module Stoplight
94
114
  def safely(default = nil, &code)
95
115
  return yield if data_store == Default::DATA_STORE
96
116
 
97
- self
98
- .class
99
- .new("#{name}-safely", &code)
117
+ Stoplight("#{name}-safely")
100
118
  .with_data_store(Default::DATA_STORE)
101
119
  .with_fallback do |error|
102
120
  error_notifier.call(error) if error
103
121
  default
104
122
  end
105
- .run
123
+ .run(&code)
106
124
  end
107
125
  end
108
126
  end
@@ -1,103 +1,109 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'stoplight/light/deprecated'
4
+
3
5
  module Stoplight
4
- class Light # rubocop:disable Style/Documentation
6
+ #
7
+ # @api private use +Stoplight()+ method instead
8
+ class Light
9
+ extend Forwardable
10
+ extend Deprecated
11
+ include CircuitBreaker
12
+ include Lockable
5
13
  include Runnable
6
14
 
15
+ # @!attribute [r] data_store
16
+ # @return [Stoplight::DataStore::Base]
17
+ def_delegator :configuration, :data_store
18
+
19
+ # @!attribute [r] threshold
20
+ # @return [Integer]
21
+ def_delegator :configuration, :threshold
22
+
23
+ # @!attribute [r] cool_off_time
24
+ # @return [Fixnum]
25
+ def_delegator :configuration, :cool_off_time
26
+
27
+ # @!attribute [r] window_size
28
+ # @return [Float]
29
+ def_delegator :configuration, :window_size
30
+
31
+ # @!attribute [r] notifiers
32
+ # # @return [Array<Notifier::Base>]
33
+ def_delegator :configuration, :notifiers
34
+
35
+ # @!attribute [r] error_notifier
36
+ # # @return [Proc]
37
+ def_delegator :configuration, :error_notifier
38
+
39
+ # @return [String]
40
+ attr_reader :name
7
41
  # @return [Proc]
8
42
  attr_reader :code
9
- # @return [Float]
10
- attr_reader :cool_off_time
11
- # @return [DataStore::Base]
12
- attr_reader :data_store
13
43
  # @return [Proc]
14
44
  attr_reader :error_handler
15
- # @return [Proc]
16
- attr_reader :error_notifier
17
45
  # @return [Proc, nil]
18
46
  attr_reader :fallback
19
- # @return [String]
20
- attr_reader :name
21
- # @return [Array<Notifier::Base>]
22
- attr_reader :notifiers
23
- # @return [Fixnum]
24
- attr_reader :threshold
47
+ # @return [Stoplight::Configuration]
48
+ # @api private
49
+ attr_reader :configuration
25
50
 
26
51
  class << self
27
- # @return [DataStore::Base]
28
- attr_accessor :default_data_store
29
- # @return [Proc]
30
- attr_accessor :default_error_notifier
31
- # @return [Array<Notifier::Base>]
32
- attr_accessor :default_notifiers
33
- end
52
+ alias __new_with_configuration__ new
34
53
 
35
- @default_data_store = Default::DATA_STORE
36
- @default_error_notifier = Default::ERROR_NOTIFIER
37
- @default_notifiers = Default::NOTIFIERS
54
+ # It overrides the +Light.new+ method to support an old and a new
55
+ # way of instantiation.
56
+ #
57
+ # @overload new(name, &code)
58
+ # @param name [String]
59
+ # @return [Stoplight::Light]
60
+ #
61
+ # @overload new(name, configuration)
62
+ # @param name [String]
63
+ # @param configuration [Stoplight::Configuration]
64
+ # @return [Stoplight::Light]
65
+ #
66
+ def new(name, configuration = nil, &code)
67
+ if configuration
68
+ __new_with_configuration__(name, configuration, &code)
69
+ else
70
+ warn '[DEPRECATED] Instantiating `Stoplight::Light` is deprecated. ' \
71
+ 'Please use `Stoplight()` method instead.'
72
+ Builder.with(name: name).build(&code)
73
+ end
74
+ end
75
+ end
38
76
 
39
77
  # @param name [String]
78
+ # @param configuration [Stoplight::Configuration]
40
79
  # @yield []
41
- def initialize(name, &code)
80
+ def initialize(name, configuration, &code)
81
+ @configuration = configuration
42
82
  @name = name
43
83
  @code = code
44
-
45
- @cool_off_time = Default::COOL_OFF_TIME
46
- @data_store = self.class.default_data_store
47
84
  @error_handler = Default::ERROR_HANDLER
48
- @error_notifier = self.class.default_error_notifier
49
85
  @fallback = Default::FALLBACK
50
- @notifiers = self.class.default_notifiers
51
- @threshold = Default::THRESHOLD
52
- end
53
-
54
- # @param cool_off_time [Float]
55
- # @return [self]
56
- def with_cool_off_time(cool_off_time)
57
- @cool_off_time = cool_off_time
58
- self
59
- end
60
-
61
- # @param data_store [DataStore::Base]
62
- # @return [self]
63
- def with_data_store(data_store)
64
- @data_store = data_store
65
- self
66
86
  end
67
87
 
68
88
  # @yieldparam error [Exception]
69
89
  # @yieldparam handle [Proc]
70
- # @return [self]
90
+ # @return [Stoplight::CircuitBreaker]
71
91
  def with_error_handler(&error_handler)
72
92
  @error_handler = error_handler
73
93
  self
74
94
  end
75
95
 
76
- # @yieldparam error [Exception]
77
- # @return [self]
78
- def with_error_notifier(&error_notifier)
79
- @error_notifier = error_notifier
80
- self
81
- end
82
-
83
96
  # @yieldparam error [Exception, nil]
84
- # @return [self]
97
+ # @return [Stoplight::CircuitBreaker]
85
98
  def with_fallback(&fallback)
86
99
  @fallback = fallback
87
100
  self
88
101
  end
89
102
 
90
- # @param notifiers [Array<Notifier::Base>]
91
- # @return [self]
92
- def with_notifiers(notifiers)
93
- @notifiers = notifiers
94
- self
95
- end
103
+ private
96
104
 
97
- # @param threshold [Fixnum]
98
- # @return [self]
99
- def with_threshold(threshold)
100
- @threshold = threshold
105
+ def reconfigure(configuration)
106
+ @configuration = configuration
101
107
  self
102
108
  end
103
109
  end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.shared_examples 'a generic notifier' do
4
+ it 'includes Generic' do
5
+ expect(described_class).to include(Stoplight::Notifier::Generic)
6
+ end
7
+
8
+ describe '#formatter' do
9
+ it 'is initially the default' do
10
+ formatter = nil
11
+ expect(described_class.new(nil, formatter).formatter)
12
+ .to eql(Stoplight::Default::FORMATTER)
13
+ end
14
+
15
+ it 'reads the formatter' do
16
+ formatter = proc {}
17
+ expect(described_class.new(nil, formatter).formatter)
18
+ .to eql(formatter)
19
+ end
20
+ end
21
+
22
+ describe '#notify' do
23
+ let(:light) { Stoplight::Light.new(name, &code) }
24
+ let(:name) { ('a'..'z').to_a.shuffle.join }
25
+ let(:code) { -> {} }
26
+ let(:from_color) { Stoplight::Color::GREEN }
27
+ let(:to_color) { Stoplight::Color::RED }
28
+ let(:notifier) { described_class.new(double.as_null_object) }
29
+
30
+ it 'returns the message' do
31
+ error = nil
32
+ expect(notifier.notify(light, from_color, to_color, error))
33
+ .to eql(notifier.formatter.call(light, from_color, to_color, error))
34
+ end
35
+
36
+ it 'returns the message with an error' do
37
+ error = ZeroDivisionError.new('divided by 0')
38
+ expect(notifier.notify(light, from_color, to_color, error))
39
+ .to eql(notifier.formatter.call(light, from_color, to_color, error))
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'stoplight/rspec/generic_notifier'
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Stoplight
4
- VERSION = Gem::Version.new('3.0.1')
4
+ VERSION = Gem::Version.new('4.1.0')
5
5
  end
data/lib/stoplight.rb CHANGED
@@ -1,6 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Stoplight # rubocop:disable Style/Documentation
4
+ class << self
5
+ # @!attribute default_data_store
6
+ # @return [DataStore::Base]
7
+ attr_accessor :default_data_store
8
+
9
+ # @!attribute default_notifiers
10
+ # @return [Array<Notifier::Base>]
11
+ attr_accessor :default_notifiers
12
+
13
+ # @!attribute default_error_notifier
14
+ # @return [Proc]
15
+ attr_accessor :default_error_notifier
16
+ end
4
17
  end
5
18
 
6
19
  require 'stoplight/version'
@@ -19,21 +32,32 @@ require 'stoplight/notifier'
19
32
  require 'stoplight/notifier/base'
20
33
  require 'stoplight/notifier/generic'
21
34
 
22
- require 'stoplight/notifier/bugsnag'
23
- require 'stoplight/notifier/honeybadger'
24
35
  require 'stoplight/notifier/io'
25
36
  require 'stoplight/notifier/logger'
26
- require 'stoplight/notifier/pagerduty'
27
- require 'stoplight/notifier/raven'
28
- require 'stoplight/notifier/rollbar'
29
- require 'stoplight/notifier/slack'
30
37
 
31
38
  require 'stoplight/default'
32
39
 
40
+ module Stoplight # rubocop:disable Style/Documentation
41
+ @default_data_store = Default::DATA_STORE
42
+ @default_notifiers = Default::NOTIFIERS
43
+ @default_error_notifier = Default::ERROR_NOTIFIER
44
+ end
45
+
46
+ require 'stoplight/configurable'
47
+ require 'stoplight/circuit_breaker'
48
+ require 'stoplight/builder'
49
+ require 'stoplight/configuration'
50
+ require 'stoplight/light/lockable'
33
51
  require 'stoplight/light/runnable'
34
52
  require 'stoplight/light'
35
53
 
36
- # @see Stoplight::Light#initialize
54
+ # @return [Stoplight::CircuitBreaker]
37
55
  def Stoplight(name, &code) # rubocop:disable Naming/MethodName
38
- Stoplight::Light.new(name, &code)
56
+ if block_given?
57
+ warn '[DEPRECATED] Calling `Stoplight("name") { ... }` with a code block is deprecated. ' \
58
+ 'Please pass code block to the run method `Stoplight("name").run { ... }` method instead.'
59
+ Stoplight::Builder.with(name: name).build(&code)
60
+ else
61
+ Stoplight::Builder.with(name: name)
62
+ end
39
63
  end
data/spec/spec_helper.rb CHANGED
@@ -4,10 +4,17 @@ require 'simplecov'
4
4
 
5
5
  require 'stoplight'
6
6
  require 'timecop'
7
+ require_relative 'support/data_store/base'
8
+ require_relative 'support/light/runnable'
9
+ require_relative 'support/configurable'
10
+ require_relative 'support/database_cleaner'
11
+ require_relative 'support/exception_helpers'
7
12
 
8
13
  Timecop.safe_mode = true
9
14
 
10
15
  RSpec.configure do |rspec|
16
+ rspec.include ExceptionHelpers
17
+
11
18
  rspec.color = true
12
19
  rspec.disable_monkey_patching!
13
20
  rspec.order = :random
@@ -0,0 +1,165 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'securerandom'
5
+
6
+ RSpec.describe Stoplight::Builder do
7
+ let(:name) { SecureRandom.uuid }
8
+
9
+ describe '.with' do
10
+ context 'with only name' do
11
+ subject(:configuration) { builder.configuration }
12
+
13
+ let(:builder) { described_class.with(name: name) }
14
+
15
+ it 'sets configuration to default values' do
16
+ expect(configuration).to have_attributes(
17
+ name: name,
18
+ data_store: Stoplight.default_data_store,
19
+ notifiers: Stoplight.default_notifiers,
20
+ cool_off_time: Stoplight::Default::COOL_OFF_TIME,
21
+ threshold: Stoplight::Default::THRESHOLD,
22
+ window_size: Stoplight::Default::WINDOW_SIZE
23
+ )
24
+ end
25
+ end
26
+
27
+ context 'with configured parameters' do
28
+ subject(:configuration) { builder.configuration }
29
+
30
+ let(:builder) { described_class.with(**configured_parameters) }
31
+ let(:configured_parameters) do
32
+ {
33
+ name: name,
34
+ data_store: 42,
35
+ notifiers: [43],
36
+ cool_off_time: 44,
37
+ threshold: 45,
38
+ window_size: 46
39
+ }
40
+ end
41
+
42
+ it 'sets configuration parameters' do
43
+ expect(configuration).to have_attributes(**configured_parameters)
44
+ end
45
+ end
46
+ end
47
+
48
+ describe '.build' do
49
+ let(:builder) { described_class.new(configuration) }
50
+ let(:configuration) { instance_double(Stoplight::Configuration, name: name) }
51
+
52
+ context 'with code' do
53
+ subject(:light) { builder.build(&code) }
54
+
55
+ let(:code) { -> { 42 } }
56
+
57
+ it 'builds new light' do
58
+ expect(light.configuration).to eq(configuration)
59
+ expect(light.code).to eq(code)
60
+ end
61
+ end
62
+
63
+ context 'without code' do
64
+ subject(:light) { builder.build }
65
+
66
+ it 'builds new light' do
67
+ expect(light.configuration).to eq(configuration)
68
+ expect(light.code).to eq(nil)
69
+ end
70
+ end
71
+ end
72
+
73
+ context 'methods building an instance of light' do
74
+ let(:builder) { described_class.new(configuration) }
75
+ let(:configuration) do
76
+ Stoplight::Configuration.new(
77
+ name: name,
78
+ data_store: Stoplight.default_data_store,
79
+ notifiers: Stoplight.default_notifiers,
80
+ cool_off_time: Stoplight::Default::COOL_OFF_TIME,
81
+ threshold: Stoplight::Default::THRESHOLD,
82
+ window_size: Stoplight::Default::WINDOW_SIZE,
83
+ error_notifier: Stoplight.default_error_notifier
84
+ )
85
+ end
86
+
87
+ describe '#with_error_handler' do
88
+ subject(:light) { builder.with_error_handler(&error_handler) }
89
+
90
+ let(:error_handler) { ->(error, handle) {} }
91
+
92
+ it 'returns an instance of the Light class with this configuration set' do
93
+ expect(light.configuration).to be(configuration)
94
+ expect(light.error_handler).to eq(error_handler)
95
+ end
96
+ end
97
+
98
+ describe '#with_fallback' do
99
+ subject(:light) { builder.with_fallback(&fallback) }
100
+
101
+ let(:fallback) { ->(error) {} }
102
+
103
+ it 'returns an instance of the Light class with this configuration set' do
104
+ expect(light.configuration).to be(configuration)
105
+ expect(light.fallback).to eq(fallback)
106
+ end
107
+ end
108
+
109
+ describe '#run' do
110
+ it 'yields the block' do
111
+ expect do |code|
112
+ builder.run(&code)
113
+ end.to yield_control
114
+ end
115
+ end
116
+
117
+ describe '#lock' do
118
+ context 'when the light is not locked' do
119
+ it 'locks the light' do
120
+ expect { builder.lock(Stoplight::Color::RED) }
121
+ .to change(builder, :color)
122
+ .from(Stoplight::Color::GREEN)
123
+ .to(Stoplight::Color::RED)
124
+ end
125
+ end
126
+
127
+ context 'when the light is locked' do
128
+ before do
129
+ builder.lock(Stoplight::Color::RED)
130
+ end
131
+
132
+ it 'does not change the light' do
133
+ expect { builder.lock(Stoplight::Color::RED) }
134
+ .not_to change(builder, :color)
135
+ .from(Stoplight::Color::RED)
136
+ end
137
+ end
138
+ end
139
+
140
+ describe '#unlock' do
141
+ context 'when the light is not locked' do
142
+ it 'does nothing' do
143
+ expect { builder.unlock }
144
+ .not_to change(builder, :color)
145
+ .from(Stoplight::Color::GREEN)
146
+ end
147
+ end
148
+
149
+ context 'when the light is locked' do
150
+ before do
151
+ builder.lock(Stoplight::Color::RED)
152
+ end
153
+
154
+ it 'unlocks the light' do
155
+ expect { builder.unlock }
156
+ .to change(builder, :color)
157
+ .from(Stoplight::Color::RED)
158
+ .to(Stoplight::Color::GREEN)
159
+ end
160
+ end
161
+ end
162
+ end
163
+
164
+ it_behaves_like Stoplight::Configurable
165
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Stoplight::CircuitBreaker do
6
+ subject(:circuit_breaker) { klass.new }
7
+
8
+ let(:klass) do
9
+ Class.new { include Stoplight::CircuitBreaker }
10
+ end
11
+
12
+ specify '#with_error_handler' do
13
+ expect { circuit_breaker.with_error_handler {} }.to raise_error(NotImplementedError)
14
+ end
15
+
16
+ specify '#with_fallback' do
17
+ expect { circuit_breaker.with_fallback {} }.to raise_error(NotImplementedError)
18
+ end
19
+
20
+ specify '#color' do
21
+ expect { circuit_breaker.color }.to raise_error(NotImplementedError)
22
+ end
23
+
24
+ specify '#state' do
25
+ expect { circuit_breaker.state }.to raise_error(NotImplementedError)
26
+ end
27
+
28
+ specify '#name' do
29
+ expect { circuit_breaker.name }.to raise_error(NotImplementedError)
30
+ end
31
+
32
+ specify '#run' do
33
+ expect { circuit_breaker.run {} }.to raise_error(NotImplementedError)
34
+ end
35
+
36
+ specify '#lock' do
37
+ expect { circuit_breaker.lock('red') }.to raise_error(NotImplementedError)
38
+ end
39
+
40
+ specify '#unlock' do
41
+ expect { circuit_breaker.unlock }.to raise_error(NotImplementedError)
42
+ end
43
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Stoplight::Configurable do
6
+ describe '#with' do
7
+ subject(:configurable) { configurable_class.new }
8
+
9
+ let(:configurable_class) do
10
+ Class.new do
11
+ include Stoplight::Configurable
12
+
13
+ def configuration
14
+ Stoplight::Configuration.new(name: 'foo')
15
+ end
16
+ end
17
+ end
18
+
19
+ it 'raises NotImplementedError' do
20
+ expect do
21
+ configurable.with_data_store(nil)
22
+ end.to raise_error(NotImplementedError)
23
+ end
24
+ end
25
+ end