stoplight 4.1.0 → 5.0.1
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/README.md +289 -350
- data/lib/stoplight/admin/actions/action.rb +24 -0
- data/lib/stoplight/admin/actions/lock.rb +23 -0
- data/lib/stoplight/admin/actions/lock_all_green.rb +18 -0
- data/lib/stoplight/admin/actions/lock_green.rb +23 -0
- data/lib/stoplight/admin/actions/lock_red.rb +23 -0
- data/lib/stoplight/admin/actions/stats.rb +27 -0
- data/lib/stoplight/admin/actions/unlock.rb +23 -0
- data/lib/stoplight/admin/dependencies.rb +50 -0
- data/lib/stoplight/admin/helpers.rb +27 -0
- data/lib/stoplight/admin/lights_repository/light.rb +155 -0
- data/lib/stoplight/admin/lights_repository.rb +74 -0
- data/lib/stoplight/admin/lights_stats.rb +77 -0
- data/lib/stoplight/admin/views/_card.erb +120 -0
- data/lib/stoplight/admin/views/index.erb +36 -0
- data/lib/stoplight/admin/views/layout.erb +66 -0
- data/lib/stoplight/admin.rb +68 -0
- data/lib/stoplight/color.rb +3 -3
- data/lib/stoplight/config/config_provider.rb +62 -0
- data/lib/stoplight/config/library_default_config.rb +29 -0
- data/lib/stoplight/config/user_default_config.rb +83 -0
- data/lib/stoplight/data_store/base.rb +59 -33
- data/lib/stoplight/data_store/fail_safe.rb +105 -0
- data/lib/stoplight/data_store/memory.rb +257 -50
- data/lib/stoplight/data_store/redis/get_metadata.lua +38 -0
- data/lib/stoplight/data_store/redis/lua.rb +23 -0
- data/lib/stoplight/data_store/redis/record_failure.lua +36 -0
- data/lib/stoplight/data_store/redis/record_success.lua +35 -0
- data/lib/stoplight/data_store/redis/transition_to_green.lua +10 -0
- data/lib/stoplight/data_store/redis/transition_to_red.lua +10 -0
- data/lib/stoplight/data_store/redis/transition_to_yellow.lua +9 -0
- data/lib/stoplight/data_store/redis.rb +345 -106
- data/lib/stoplight/default.rb +11 -9
- data/lib/stoplight/error.rb +1 -13
- data/lib/stoplight/failure.rb +14 -13
- data/lib/stoplight/light/config.rb +118 -0
- data/lib/stoplight/light/configuration_builder_interface.rb +128 -0
- data/lib/stoplight/light/green_run_strategy.rb +53 -0
- data/lib/stoplight/light/red_run_strategy.rb +26 -0
- data/lib/stoplight/light/run_strategy.rb +30 -0
- data/lib/stoplight/light/yellow_run_strategy.rb +78 -0
- data/lib/stoplight/light.rb +164 -84
- data/lib/stoplight/metadata.rb +71 -0
- data/lib/stoplight/notifier/base.rb +14 -7
- data/lib/stoplight/notifier/fail_safe.rb +67 -0
- data/lib/stoplight/notifier/generic.rb +54 -5
- data/lib/stoplight/rspec/generic_notifier.rb +11 -12
- data/lib/stoplight/rspec.rb +1 -1
- data/lib/stoplight/state.rb +3 -3
- data/lib/stoplight/traffic_control/base.rb +35 -0
- data/lib/stoplight/traffic_control/consecutive_failures.rb +43 -0
- data/lib/stoplight/traffic_recovery/base.rb +51 -0
- data/lib/stoplight/traffic_recovery/single_success.rb +35 -0
- data/lib/stoplight/version.rb +1 -1
- data/lib/stoplight.rb +111 -51
- metadata +49 -98
- data/lib/stoplight/builder.rb +0 -70
- data/lib/stoplight/circuit_breaker.rb +0 -102
- data/lib/stoplight/configurable.rb +0 -95
- data/lib/stoplight/configuration.rb +0 -126
- data/lib/stoplight/light/deprecated.rb +0 -44
- data/lib/stoplight/light/lockable.rb +0 -45
- data/lib/stoplight/light/runnable.rb +0 -127
- data/lib/stoplight/notifier.rb +0 -6
- data/spec/spec_helper.rb +0 -22
- data/spec/stoplight/builder_spec.rb +0 -165
- data/spec/stoplight/circuit_breaker_spec.rb +0 -43
- data/spec/stoplight/color_spec.rb +0 -39
- data/spec/stoplight/configurable_spec.rb +0 -25
- data/spec/stoplight/data_store/base_spec.rb +0 -71
- data/spec/stoplight/data_store/memory_spec.rb +0 -22
- data/spec/stoplight/data_store/redis_spec.rb +0 -45
- data/spec/stoplight/data_store_spec.rb +0 -9
- data/spec/stoplight/default_spec.rb +0 -80
- data/spec/stoplight/error_spec.rb +0 -39
- data/spec/stoplight/failure_spec.rb +0 -108
- data/spec/stoplight/light/lockable_spec.rb +0 -93
- data/spec/stoplight/light/runnable_spec.rb +0 -38
- data/spec/stoplight/light_spec.rb +0 -156
- data/spec/stoplight/notifier/base_spec.rb +0 -18
- data/spec/stoplight/notifier/generic_spec.rb +0 -50
- data/spec/stoplight/notifier/io_spec.rb +0 -41
- data/spec/stoplight/notifier/logger_spec.rb +0 -75
- data/spec/stoplight/notifier_spec.rb +0 -9
- data/spec/stoplight/state_spec.rb +0 -39
- data/spec/stoplight/version_spec.rb +0 -9
- data/spec/stoplight_spec.rb +0 -32
- data/spec/support/configurable.rb +0 -69
- data/spec/support/data_store/base/clear_failures.rb +0 -18
- data/spec/support/data_store/base/clear_state.rb +0 -20
- data/spec/support/data_store/base/get_all.rb +0 -44
- data/spec/support/data_store/base/get_failures.rb +0 -30
- data/spec/support/data_store/base/get_state.rb +0 -7
- data/spec/support/data_store/base/names.rb +0 -29
- data/spec/support/data_store/base/record_failures.rb +0 -70
- data/spec/support/data_store/base/set_state.rb +0 -15
- data/spec/support/data_store/base/with_notification_lock.rb +0 -27
- data/spec/support/data_store/base.rb +0 -21
- data/spec/support/database_cleaner.rb +0 -26
- data/spec/support/exception_helpers.rb +0 -9
- data/spec/support/light/runnable/color.rb +0 -79
- data/spec/support/light/runnable/run.rb +0 -247
- data/spec/support/light/runnable/state.rb +0 -31
- data/spec/support/light/runnable.rb +0 -5
@@ -1,70 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
RSpec.shared_examples 'Stoplight::DataStore::Base#record_failure' do
|
4
|
-
it 'returns the number of failures' do
|
5
|
-
expect(data_store.record_failure(light, failure)).to eql(1)
|
6
|
-
end
|
7
|
-
|
8
|
-
context 'when there is an error' do
|
9
|
-
before do
|
10
|
-
data_store.record_failure(light, failure)
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'persists the failure' do
|
14
|
-
expect(data_store.get_failures(light)).to eq([failure])
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
context 'when there is are several errors' do
|
19
|
-
before do
|
20
|
-
data_store.record_failure(light, failure)
|
21
|
-
data_store.record_failure(light, other)
|
22
|
-
end
|
23
|
-
|
24
|
-
it 'stores more recent failures at the head' do
|
25
|
-
expect(data_store.get_failures(light)).to eq([other, failure])
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
shared_examples 'with_threshold' do
|
30
|
-
context 'when the number of errors is bigger then threshold' do
|
31
|
-
before do
|
32
|
-
light.with_threshold(1)
|
33
|
-
|
34
|
-
data_store.record_failure(light, failure)
|
35
|
-
end
|
36
|
-
|
37
|
-
it 'limits the number of stored failures' do
|
38
|
-
expect do
|
39
|
-
data_store.record_failure(light, other)
|
40
|
-
end.to change { data_store.get_failures(light) }
|
41
|
-
.from([failure])
|
42
|
-
.to([other])
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
it_behaves_like 'with_threshold'
|
48
|
-
|
49
|
-
context 'with window_size' do
|
50
|
-
let(:window_size) { 3600 }
|
51
|
-
|
52
|
-
before do
|
53
|
-
light.with_window_size(window_size)
|
54
|
-
end
|
55
|
-
|
56
|
-
context 'when error is outside of the window' do
|
57
|
-
let(:older_failure) { Stoplight::Failure.new('class', 'message 3', Time.new - window_size - 1) }
|
58
|
-
|
59
|
-
it 'stores failures only withing window length' do
|
60
|
-
data_store.record_failure(light, failure)
|
61
|
-
data_store.record_failure(light, other)
|
62
|
-
data_store.record_failure(light, older_failure)
|
63
|
-
|
64
|
-
expect(data_store.get_failures(light)).to eq([other, failure])
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
it_behaves_like 'with_threshold'
|
69
|
-
end
|
70
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
RSpec.shared_examples 'Stoplight::DataStore::Base#set_state' do
|
4
|
-
let(:state) { 'state' }
|
5
|
-
|
6
|
-
it 'returns the state' do
|
7
|
-
expect(data_store.set_state(light, state)).to eql(state)
|
8
|
-
end
|
9
|
-
|
10
|
-
it 'persists the state' do
|
11
|
-
data_store.set_state(light, state)
|
12
|
-
|
13
|
-
expect(data_store.get_state(light)).to eql(state)
|
14
|
-
end
|
15
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
RSpec.shared_examples 'Stoplight::DataStore::Base#with_notification_lock' do
|
4
|
-
context 'when notification is already sent' do
|
5
|
-
before do
|
6
|
-
data_store.with_notification_lock(light, Stoplight::Color::GREEN, Stoplight::Color::RED) {}
|
7
|
-
end
|
8
|
-
|
9
|
-
it 'does not yield passed block' do
|
10
|
-
expect do |b|
|
11
|
-
data_store.with_notification_lock(light, Stoplight::Color::GREEN, Stoplight::Color::RED, &b)
|
12
|
-
end.not_to yield_control
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
context 'when notification is not already sent' do
|
17
|
-
before do
|
18
|
-
data_store.with_notification_lock(light, Stoplight::Color::GREEN, Stoplight::Color::RED) {}
|
19
|
-
end
|
20
|
-
|
21
|
-
it 'yields passed block' do
|
22
|
-
expect do |b|
|
23
|
-
data_store.with_notification_lock(light, Stoplight::Color::RED, Stoplight::Color::GREEN, &b)
|
24
|
-
end.to yield_control
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'base/names'
|
4
|
-
require_relative 'base/get_failures'
|
5
|
-
require_relative 'base/get_all'
|
6
|
-
require_relative 'base/record_failures'
|
7
|
-
require_relative 'base/clear_failures'
|
8
|
-
require_relative 'base/get_state'
|
9
|
-
require_relative 'base/set_state'
|
10
|
-
require_relative 'base/clear_state'
|
11
|
-
require_relative 'base/with_notification_lock'
|
12
|
-
|
13
|
-
RSpec.shared_examples 'Stoplight::DataStore::Base' do
|
14
|
-
it 'is a class' do
|
15
|
-
expect(described_class).to be_a(Class)
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'is a subclass of Base' do
|
19
|
-
expect(described_class).to be < Stoplight::DataStore::Base
|
20
|
-
end
|
21
|
-
end
|
@@ -1,26 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'redis'
|
4
|
-
require 'database_cleaner/redis'
|
5
|
-
|
6
|
-
cleaning_strategy = DatabaseCleaner::Redis::Deletion.new(only: ["#{Stoplight::DataStore::Redis::KEY_PREFIX}*"])
|
7
|
-
DatabaseCleaner.strategy = cleaning_strategy
|
8
|
-
|
9
|
-
RSpec.shared_context :redis, :redis do
|
10
|
-
let(:redis) { Redis.new(url: ENV.fetch('STOPLIGHT_REDIS_URL', 'redis://127.0.0.1:6379/0')) }
|
11
|
-
|
12
|
-
before(:suite) do
|
13
|
-
DatabaseCleaner[:redis].db = redis
|
14
|
-
DatabaseCleaner.clean_with(:deletion)
|
15
|
-
end
|
16
|
-
|
17
|
-
around(:each) do |example|
|
18
|
-
DatabaseCleaner.cleaning do
|
19
|
-
example.run
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
RSpec.configure do |config|
|
25
|
-
config.include_context :redis, include_shared: true
|
26
|
-
end
|
@@ -1,79 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
RSpec.shared_examples 'Stoplight::Light::Runnable#color' do
|
4
|
-
subject(:light) { Stoplight::Light.new(name) }
|
5
|
-
|
6
|
-
let(:name) { random_string }
|
7
|
-
|
8
|
-
it 'is initially green' do
|
9
|
-
expect(light.color).to eql(Stoplight::Color::GREEN)
|
10
|
-
end
|
11
|
-
|
12
|
-
context 'when its locked green' do
|
13
|
-
before do
|
14
|
-
light.data_store.set_state(light, Stoplight::State::LOCKED_GREEN)
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'is green' do
|
18
|
-
expect(light.color).to eql(Stoplight::Color::GREEN)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
context 'when its locked red' do
|
23
|
-
before do
|
24
|
-
light.data_store.set_state(light, Stoplight::State::LOCKED_RED)
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'is red' do
|
28
|
-
expect(light.color).to eql(Stoplight::Color::RED)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
context 'when there are many failures' do
|
33
|
-
let(:anther) { Stoplight::Failure.new(error.class.name, error.message, time - 10) }
|
34
|
-
|
35
|
-
before do
|
36
|
-
light.with_threshold(2)
|
37
|
-
light.data_store.record_failure(light, failure)
|
38
|
-
end
|
39
|
-
|
40
|
-
it 'turns red' do
|
41
|
-
expect do
|
42
|
-
light.data_store.record_failure(light, anther)
|
43
|
-
end.to change(light, :color).to be(Stoplight::Color::RED)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
context 'when the most recent failure is old' do
|
48
|
-
let(:failure) { Stoplight::Failure.new(error.class.name, error.message, Time.new - light.cool_off_time) }
|
49
|
-
let(:failure2) { Stoplight::Failure.new(error.class.name, error.message, Time.new - light.cool_off_time - 10) }
|
50
|
-
|
51
|
-
before do
|
52
|
-
light.with_threshold(2)
|
53
|
-
light.data_store.record_failure(light, failure2)
|
54
|
-
end
|
55
|
-
|
56
|
-
it 'turns yellow' do
|
57
|
-
expect do
|
58
|
-
light.data_store.record_failure(light, failure)
|
59
|
-
end.to change(light, :color).to be(Stoplight::Color::YELLOW)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
context 'when the least recent failure is old' do
|
64
|
-
let(:other) do
|
65
|
-
Stoplight::Failure.new(error.class.name, error.message, Time.new - light.cool_off_time)
|
66
|
-
end
|
67
|
-
|
68
|
-
before do
|
69
|
-
light.with_threshold(2)
|
70
|
-
light.data_store.record_failure(light, other)
|
71
|
-
end
|
72
|
-
|
73
|
-
it 'is red when the least recent failure is old' do
|
74
|
-
expect do
|
75
|
-
light.data_store.record_failure(light, failure)
|
76
|
-
end.to change(light, :color).to be(Stoplight::Color::RED)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
@@ -1,247 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
RSpec.shared_examples 'Stoplight::Light::Runnable#run' do
|
4
|
-
let(:code) { -> { code_result } }
|
5
|
-
let(:code_result) { random_string }
|
6
|
-
let(:fallback) { ->(_) { fallback_result } }
|
7
|
-
let(:fallback_result) { random_string }
|
8
|
-
let(:name) { random_string }
|
9
|
-
let(:notifiers) { [notifier] }
|
10
|
-
let(:notifier) { Stoplight::Notifier::IO.new(io) }
|
11
|
-
let(:io) { StringIO.new }
|
12
|
-
|
13
|
-
before { light.with_notifiers(notifiers) }
|
14
|
-
|
15
|
-
shared_examples 'when the light is green' do
|
16
|
-
before { light.data_store.clear_failures(light) }
|
17
|
-
|
18
|
-
it 'runs the code' do
|
19
|
-
expect(run).to eql(code_result)
|
20
|
-
end
|
21
|
-
|
22
|
-
context 'with some failures' do
|
23
|
-
before { light.data_store.record_failure(light, failure) }
|
24
|
-
|
25
|
-
it 'clears the failures' do
|
26
|
-
run
|
27
|
-
expect(light.data_store.get_failures(light).size).to eql(0)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
context 'when the code is failing' do
|
32
|
-
let(:code_result) { raise error }
|
33
|
-
|
34
|
-
it 're-raises the error' do
|
35
|
-
expect { run }.to raise_error(error.class)
|
36
|
-
end
|
37
|
-
|
38
|
-
it 'records the failure' do
|
39
|
-
expect(light.data_store.get_failures(light).size).to eql(0)
|
40
|
-
begin
|
41
|
-
run
|
42
|
-
rescue error.class
|
43
|
-
nil
|
44
|
-
end
|
45
|
-
expect(light.data_store.get_failures(light).size).to eql(1)
|
46
|
-
end
|
47
|
-
|
48
|
-
context 'when we did not send notifications yet' do
|
49
|
-
it 'notifies when transitioning to red' do
|
50
|
-
light.threshold.times do
|
51
|
-
expect(io.string).to eql('')
|
52
|
-
begin
|
53
|
-
run
|
54
|
-
rescue error.class
|
55
|
-
nil
|
56
|
-
end
|
57
|
-
end
|
58
|
-
expect(io.string).to_not eql('')
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
context 'when we already sent notifications' do
|
63
|
-
before do
|
64
|
-
light.data_store.with_notification_lock(light, Stoplight::Color::GREEN, Stoplight::Color::RED) {}
|
65
|
-
end
|
66
|
-
|
67
|
-
it 'does not send new notifications' do
|
68
|
-
light.threshold.times do
|
69
|
-
expect(io.string).to eql('')
|
70
|
-
begin
|
71
|
-
run
|
72
|
-
rescue error.class
|
73
|
-
nil
|
74
|
-
end
|
75
|
-
end
|
76
|
-
expect(io.string).to eql('')
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
it 'notifies when transitioning to red' do
|
81
|
-
light.threshold.times do
|
82
|
-
expect(io.string).to eql('')
|
83
|
-
begin
|
84
|
-
run
|
85
|
-
rescue error.class
|
86
|
-
nil
|
87
|
-
end
|
88
|
-
end
|
89
|
-
expect(io.string).to_not eql('')
|
90
|
-
end
|
91
|
-
|
92
|
-
context 'with an error handler' do
|
93
|
-
let(:result) do
|
94
|
-
run
|
95
|
-
expect(false).to be(true)
|
96
|
-
rescue error.class
|
97
|
-
expect(true).to be(true)
|
98
|
-
end
|
99
|
-
|
100
|
-
it 'records the failure when the handler does nothing' do
|
101
|
-
light.with_error_handler { |_error, _handler| }
|
102
|
-
expect { result }
|
103
|
-
.to change { light.data_store.get_failures(light).size }
|
104
|
-
.by(1)
|
105
|
-
end
|
106
|
-
|
107
|
-
it 'records the failure when the handler calls handle' do
|
108
|
-
light.with_error_handler { |error, handle| handle.call(error) }
|
109
|
-
expect { result }
|
110
|
-
.to change { light.data_store.get_failures(light).size }
|
111
|
-
.by(1)
|
112
|
-
end
|
113
|
-
|
114
|
-
it 'does not record the failure when the handler raises' do
|
115
|
-
light.with_error_handler { |error, _handle| raise error }
|
116
|
-
expect { result }
|
117
|
-
.to_not change { light.data_store.get_failures(light).size }
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
context 'with a fallback' do
|
122
|
-
before { light.with_fallback(&fallback) }
|
123
|
-
|
124
|
-
it 'runs the fallback' do
|
125
|
-
expect(run).to eql(fallback_result)
|
126
|
-
end
|
127
|
-
|
128
|
-
it 'passes the error to the fallback' do
|
129
|
-
light.with_fallback do |e|
|
130
|
-
expect(e).to eql(error)
|
131
|
-
fallback_result
|
132
|
-
end
|
133
|
-
expect(run).to eql(fallback_result)
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
context 'when the data store is failing' do
|
139
|
-
let(:error_notifier) { ->(_) {} }
|
140
|
-
let(:error) { StandardError.new('something went wrong') }
|
141
|
-
|
142
|
-
before do
|
143
|
-
expect(data_store).to receive(:clear_failures) { raise error }
|
144
|
-
|
145
|
-
light.with_error_notifier(&error_notifier)
|
146
|
-
end
|
147
|
-
|
148
|
-
it 'runs the code' do
|
149
|
-
expect(run).to eql(code_result)
|
150
|
-
end
|
151
|
-
|
152
|
-
it 'notifies about the error' do
|
153
|
-
has_notified = false
|
154
|
-
light.with_error_notifier do |e|
|
155
|
-
has_notified = true
|
156
|
-
expect(e).to eq(error)
|
157
|
-
end
|
158
|
-
run
|
159
|
-
expect(has_notified).to eql(true)
|
160
|
-
end
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
shared_examples 'when the light is yellow' do
|
165
|
-
let(:failure) { Stoplight::Failure.new(error.class.name, error.message, Time.new - light.cool_off_time) }
|
166
|
-
let(:failure2) { Stoplight::Failure.new(error.class.name, error.message, Time.new - light.cool_off_time - 10) }
|
167
|
-
|
168
|
-
before do
|
169
|
-
light.with_threshold(2)
|
170
|
-
light.data_store.record_failure(light, failure2)
|
171
|
-
light.data_store.record_failure(light, failure)
|
172
|
-
end
|
173
|
-
|
174
|
-
it 'runs the code' do
|
175
|
-
expect(run).to eql(code_result)
|
176
|
-
end
|
177
|
-
|
178
|
-
it 'notifies when transitioning to green' do
|
179
|
-
expect { run }
|
180
|
-
.to change(io, :string)
|
181
|
-
.from(be_empty)
|
182
|
-
.to(/Switching \w+ from red to green/)
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
shared_examples 'when the light is red' do
|
187
|
-
let(:other) do
|
188
|
-
Stoplight::Failure.new(error.class.name, error.message, Time.new - light.cool_off_time)
|
189
|
-
end
|
190
|
-
|
191
|
-
before do
|
192
|
-
light.with_threshold(2)
|
193
|
-
light.data_store.record_failure(light, other)
|
194
|
-
light.data_store.record_failure(light, failure)
|
195
|
-
end
|
196
|
-
|
197
|
-
it 'raises an error' do
|
198
|
-
expect { run }.to raise_error(Stoplight::Error::RedLight)
|
199
|
-
end
|
200
|
-
|
201
|
-
it 'uses the name as the error message' do
|
202
|
-
expect do
|
203
|
-
run
|
204
|
-
end.to raise_error(Stoplight::Error::RedLight, light.name)
|
205
|
-
end
|
206
|
-
|
207
|
-
context 'with a fallback' do
|
208
|
-
before { light.with_fallback(&fallback) }
|
209
|
-
|
210
|
-
it 'runs the fallback' do
|
211
|
-
expect(run).to eql(fallback_result)
|
212
|
-
end
|
213
|
-
|
214
|
-
it 'does not pass anything to the fallback' do
|
215
|
-
light.with_fallback do |e|
|
216
|
-
expect(e).to eql(nil)
|
217
|
-
fallback_result
|
218
|
-
end
|
219
|
-
expect(run).to eql(fallback_result)
|
220
|
-
end
|
221
|
-
end
|
222
|
-
end
|
223
|
-
|
224
|
-
context 'with code block' do
|
225
|
-
subject(:light) { Stoplight::Light.new(name) }
|
226
|
-
|
227
|
-
def run
|
228
|
-
light.run(&code)
|
229
|
-
end
|
230
|
-
|
231
|
-
it_behaves_like 'when the light is green'
|
232
|
-
it_behaves_like 'when the light is yellow'
|
233
|
-
it_behaves_like 'when the light is red'
|
234
|
-
end
|
235
|
-
|
236
|
-
context 'without code block' do
|
237
|
-
subject(:light) { Stoplight::Light.new(name, &code) }
|
238
|
-
|
239
|
-
def run
|
240
|
-
light.run
|
241
|
-
end
|
242
|
-
|
243
|
-
it_behaves_like 'when the light is green'
|
244
|
-
it_behaves_like 'when the light is yellow'
|
245
|
-
it_behaves_like 'when the light is red'
|
246
|
-
end
|
247
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
RSpec.shared_examples 'Stoplight::Light::Runnable#state' do
|
4
|
-
subject(:light) { Stoplight::Light.new(name) }
|
5
|
-
|
6
|
-
let(:name) { random_string }
|
7
|
-
|
8
|
-
it 'is initially unlocked' do
|
9
|
-
expect(light.state).to eql(Stoplight::State::UNLOCKED)
|
10
|
-
end
|
11
|
-
|
12
|
-
context 'when its locked green' do
|
13
|
-
before do
|
14
|
-
light.data_store.set_state(light, Stoplight::State::LOCKED_GREEN)
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'is locked green' do
|
18
|
-
expect(light.state).to eql(Stoplight::State::LOCKED_GREEN)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
context 'when its locked red' do
|
23
|
-
before do
|
24
|
-
light.data_store.set_state(light, Stoplight::State::LOCKED_RED)
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'is locked red' do
|
28
|
-
expect(light.state).to eql(Stoplight::State::LOCKED_RED)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|