stoplight 0.4.1 → 0.5.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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/LICENSE.md +1 -1
  4. data/README.md +66 -63
  5. data/lib/stoplight.rb +10 -15
  6. data/lib/stoplight/color.rb +9 -0
  7. data/lib/stoplight/data_store.rb +0 -146
  8. data/lib/stoplight/data_store/base.rb +7 -130
  9. data/lib/stoplight/data_store/memory.rb +25 -100
  10. data/lib/stoplight/data_store/redis.rb +61 -119
  11. data/lib/stoplight/default.rb +34 -0
  12. data/lib/stoplight/error.rb +0 -42
  13. data/lib/stoplight/failure.rb +21 -25
  14. data/lib/stoplight/light.rb +42 -127
  15. data/lib/stoplight/light/runnable.rb +97 -0
  16. data/lib/stoplight/notifier/base.rb +1 -4
  17. data/lib/stoplight/notifier/hip_chat.rb +17 -32
  18. data/lib/stoplight/notifier/io.rb +9 -9
  19. data/lib/stoplight/state.rb +9 -0
  20. data/spec/spec_helper.rb +2 -3
  21. data/spec/stoplight/color_spec.rb +39 -0
  22. data/spec/stoplight/data_store/base_spec.rb +56 -36
  23. data/spec/stoplight/data_store/memory_spec.rb +120 -2
  24. data/spec/stoplight/data_store/redis_spec.rb +123 -24
  25. data/spec/stoplight/data_store_spec.rb +2 -69
  26. data/spec/stoplight/default_spec.rb +86 -0
  27. data/spec/stoplight/error_spec.rb +29 -0
  28. data/spec/stoplight/failure_spec.rb +61 -51
  29. data/spec/stoplight/light/runnable_spec.rb +234 -0
  30. data/spec/stoplight/light_spec.rb +143 -191
  31. data/spec/stoplight/notifier/base_spec.rb +8 -11
  32. data/spec/stoplight/notifier/hip_chat_spec.rb +66 -55
  33. data/spec/stoplight/notifier/io_spec.rb +49 -21
  34. data/spec/stoplight/notifier_spec.rb +3 -0
  35. data/spec/stoplight/state_spec.rb +39 -0
  36. data/spec/stoplight_spec.rb +2 -65
  37. metadata +55 -19
  38. data/spec/support/data_store.rb +0 -36
  39. data/spec/support/fakeredis.rb +0 -3
  40. data/spec/support/hipchat.rb +0 -3
@@ -3,32 +3,60 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Stoplight::Notifier::IO do
6
- subject(:notifier) { described_class.new(io, formatter) }
7
- let(:io) { StringIO.new }
8
- let(:formatter) { nil }
6
+ it 'is a class' do
7
+ expect(described_class).to be_a(Module)
8
+ end
9
+
10
+ it 'is a subclass of Base' do
11
+ expect(described_class).to be < Stoplight::Notifier::Base
12
+ end
13
+
14
+ describe '#formatter' do
15
+ it 'is initially the default' do
16
+ expect(described_class.new(nil).formatter)
17
+ .to eql(Stoplight::Default::FORMATTER)
18
+ end
19
+
20
+ it 'reads the formatter' do
21
+ formatter = proc {}
22
+ expect(described_class.new(nil, formatter).formatter)
23
+ .to eql(formatter)
24
+ end
25
+ end
26
+
27
+ describe '#io' do
28
+ it 'reads the IO' do
29
+ io = StringIO.new
30
+ expect(described_class.new(io).io).to eql(io)
31
+ end
32
+ end
9
33
 
10
34
  describe '#notify' do
11
- subject(:result) { notifier.notify(light, from_color, to_color) }
12
- let(:light) { Stoplight::Light.new(light_name, &light_code) }
13
- let(:light_name) { SecureRandom.hex }
14
- let(:light_code) { -> {} }
15
- let(:from_color) { Stoplight::DataStore::COLOR_GREEN }
16
- let(:to_color) { Stoplight::DataStore::COLOR_RED }
17
-
18
- it 'emits the message as a warning' do
19
- result
20
- expect(io.string)
21
- .to eql("Switching #{light.name} from #{from_color} to #{to_color}\n")
35
+ let(:light) { Stoplight::Light.new(name, &code) }
36
+ let(:name) { ('a'..'z').to_a.shuffle.join }
37
+ let(:code) { -> {} }
38
+ let(:from_color) { Stoplight::Color::GREEN }
39
+ let(:to_color) { Stoplight::Color::RED }
40
+ let(:notifier) { described_class.new(io) }
41
+ let(:io) { StringIO.new }
42
+
43
+ it 'returns the message' do
44
+ error = nil
45
+ expect(notifier.notify(light, from_color, to_color, error))
46
+ .to eql(notifier.formatter.call(light, from_color, to_color, error))
22
47
  end
23
48
 
24
- context 'with a formatter' do
25
- let(:formatter) { ->(l, f, t) { "#{l.name} #{f} #{t}" } }
49
+ it 'returns the message with an error' do
50
+ error = ZeroDivisionError.new('divided by 0')
51
+ expect(notifier.notify(light, from_color, to_color, error))
52
+ .to eql(notifier.formatter.call(light, from_color, to_color, error))
53
+ end
26
54
 
27
- it 'formats the message' do
28
- result
29
- expect(io.string)
30
- .to eql("#{light.name} #{from_color} #{to_color}\n")
31
- end
55
+ it 'writes the message' do
56
+ error = nil
57
+ notifier.notify(light, from_color, to_color, error)
58
+ message = notifier.formatter.call(light, from_color, to_color, error)
59
+ expect(io.string).to eql("#{message}\n")
32
60
  end
33
61
  end
34
62
  end
@@ -3,4 +3,7 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Stoplight::Notifier do
6
+ it 'is a module' do
7
+ expect(described_class).to be_a(Module)
8
+ end
6
9
  end
@@ -0,0 +1,39 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Stoplight::State do
6
+ it 'is a module' do
7
+ expect(described_class).to be_a(Module)
8
+ end
9
+
10
+ describe '::UNLOCKED' do
11
+ it 'is a string' do
12
+ expect(Stoplight::State::UNLOCKED).to be_a(String)
13
+ end
14
+
15
+ it 'is frozen' do
16
+ expect(Stoplight::State::UNLOCKED).to be_frozen
17
+ end
18
+ end
19
+
20
+ describe '::LOCKED_GREEN' do
21
+ it 'is a string' do
22
+ expect(Stoplight::State::LOCKED_GREEN).to be_a(String)
23
+ end
24
+
25
+ it 'is frozen' do
26
+ expect(Stoplight::State::LOCKED_GREEN).to be_frozen
27
+ end
28
+ end
29
+
30
+ describe '::LOCKED_RED' do
31
+ it 'is a string' do
32
+ expect(Stoplight::State::LOCKED_RED).to be_a(String)
33
+ end
34
+
35
+ it 'is frozen' do
36
+ expect(Stoplight::State::LOCKED_RED).to be_frozen
37
+ end
38
+ end
39
+ end
@@ -3,70 +3,7 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Stoplight do
6
- let(:name) { SecureRandom.hex }
7
-
8
- describe '::VERSION' do
9
- subject(:result) { described_class.const_get(:VERSION) }
10
-
11
- it 'is a Gem::Version' do
12
- expect(result).to be_a(Gem::Version)
13
- end
14
- end
15
-
16
- describe '.data_store' do
17
- subject(:result) { described_class.data_store }
18
-
19
- it 'uses the default data store' do
20
- expect(result).to be_a(Stoplight::DataStore::Memory)
21
- end
22
-
23
- it 'memoizes the result' do
24
- expect(result).to be described_class.data_store
25
- end
26
-
27
- context 'with a custom data store' do
28
- let(:data_store) { double }
29
-
30
- before do
31
- @data_store = described_class.data_store
32
- described_class.data_store = data_store
33
- end
34
-
35
- after { described_class.data_store = @data_store }
36
-
37
- it 'returns the data store' do
38
- expect(result).to eql(data_store)
39
- end
40
- end
41
- end
42
-
43
- describe '.notifiers' do
44
- subject(:result) { described_class.notifiers }
45
-
46
- it 'uses the default notifier' do
47
- expect(result).to be_an(Array)
48
- expect(result.size).to eql(1)
49
- expect(result.first).to be_a(Stoplight::Notifier::IO)
50
- end
51
-
52
- it 'memoizes the result' do
53
- expect(result).to be described_class.notifiers
54
- end
55
-
56
- context 'with custom notifiers' do
57
- let(:notifiers) { [notifier] }
58
- let(:notifier) { double }
59
-
60
- before do
61
- @notifiers = described_class.notifiers
62
- described_class.notifiers = notifiers
63
- end
64
-
65
- after { described_class.notifiers = @notifiers }
66
-
67
- it 'returns the notifiers' do
68
- expect(result).to eql(notifiers)
69
- end
70
- end
6
+ it 'is a module' do
7
+ expect(described_class).to be_a(Module)
71
8
  end
72
9
  end
metadata CHANGED
@@ -1,15 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stoplight
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cameron Desautels
8
8
  - Taylor Fausak
9
+ - Justin Steffy
9
10
  autorequire:
10
11
  bindir: bin
11
12
  cert_chain: []
12
- date: 2014-10-03 00:00:00.000000000 Z
13
+ date: 2014-11-19 00:00:00.000000000 Z
13
14
  dependencies:
14
15
  - !ruby/object:Gem::Dependency
15
16
  name: benchmark-ips
@@ -17,14 +18,14 @@ dependencies:
17
18
  requirements:
18
19
  - - ~>
19
20
  - !ruby/object:Gem::Version
20
- version: '2.0'
21
+ version: '2.1'
21
22
  type: :development
22
23
  prerelease: false
23
24
  version_requirements: !ruby/object:Gem::Requirement
24
25
  requirements:
25
26
  - - ~>
26
27
  - !ruby/object:Gem::Version
27
- version: '2.0'
28
+ version: '2.1'
28
29
  - !ruby/object:Gem::Dependency
29
30
  name: coveralls
30
31
  requirement: !ruby/object:Gem::Requirement
@@ -59,14 +60,14 @@ dependencies:
59
60
  requirements:
60
61
  - - ~>
61
62
  - !ruby/object:Gem::Version
62
- version: '1.3'
63
+ version: '1.4'
63
64
  type: :development
64
65
  prerelease: false
65
66
  version_requirements: !ruby/object:Gem::Requirement
66
67
  requirements:
67
68
  - - ~>
68
69
  - !ruby/object:Gem::Version
69
- version: '1.3'
70
+ version: '1.4'
70
71
  - !ruby/object:Gem::Dependency
71
72
  name: rake
72
73
  requirement: !ruby/object:Gem::Requirement
@@ -81,6 +82,20 @@ dependencies:
81
82
  - - ~>
82
83
  - !ruby/object:Gem::Version
83
84
  version: '10.3'
85
+ - !ruby/object:Gem::Dependency
86
+ name: redis
87
+ requirement: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ~>
90
+ - !ruby/object:Gem::Version
91
+ version: '3.1'
92
+ type: :development
93
+ prerelease: false
94
+ version_requirements: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ~>
97
+ - !ruby/object:Gem::Version
98
+ version: '3.1'
84
99
  - !ruby/object:Gem::Dependency
85
100
  name: rspec
86
101
  requirement: !ruby/object:Gem::Requirement
@@ -101,14 +116,28 @@ dependencies:
101
116
  requirements:
102
117
  - - ~>
103
118
  - !ruby/object:Gem::Version
104
- version: '0.26'
119
+ version: '0.27'
105
120
  type: :development
106
121
  prerelease: false
107
122
  version_requirements: !ruby/object:Gem::Requirement
108
123
  requirements:
109
124
  - - ~>
110
125
  - !ruby/object:Gem::Version
111
- version: '0.26'
126
+ version: '0.27'
127
+ - !ruby/object:Gem::Dependency
128
+ name: timecop
129
+ requirement: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ~>
132
+ - !ruby/object:Gem::Version
133
+ version: '0.7'
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ~>
139
+ - !ruby/object:Gem::Version
140
+ version: '0.7'
112
141
  - !ruby/object:Gem::Dependency
113
142
  name: yard
114
143
  requirement: !ruby/object:Gem::Requirement
@@ -123,12 +152,11 @@ dependencies:
123
152
  - - ~>
124
153
  - !ruby/object:Gem::Version
125
154
  version: '0.8'
126
- description: |
127
- Traffic control for code. An implementation of the circuit breaker pattern
128
- in Ruby.
155
+ description: An implementation of the circuit breaker pattern.
129
156
  email:
130
157
  - camdez@gmail.com
131
158
  - taylor@fausak.me
159
+ - steffy@orgsync.com
132
160
  executables: []
133
161
  extensions: []
134
162
  extra_rdoc_files: []
@@ -138,33 +166,39 @@ files:
138
166
  - LICENSE.md
139
167
  - README.md
140
168
  - lib/stoplight.rb
169
+ - lib/stoplight/color.rb
141
170
  - lib/stoplight/data_store.rb
142
171
  - lib/stoplight/data_store/base.rb
143
172
  - lib/stoplight/data_store/memory.rb
144
173
  - lib/stoplight/data_store/redis.rb
174
+ - lib/stoplight/default.rb
145
175
  - lib/stoplight/error.rb
146
176
  - lib/stoplight/failure.rb
147
177
  - lib/stoplight/light.rb
178
+ - lib/stoplight/light/runnable.rb
148
179
  - lib/stoplight/notifier.rb
149
180
  - lib/stoplight/notifier/base.rb
150
181
  - lib/stoplight/notifier/hip_chat.rb
151
182
  - lib/stoplight/notifier/io.rb
183
+ - lib/stoplight/state.rb
152
184
  - spec/spec_helper.rb
185
+ - spec/stoplight/color_spec.rb
153
186
  - spec/stoplight/data_store/base_spec.rb
154
187
  - spec/stoplight/data_store/memory_spec.rb
155
188
  - spec/stoplight/data_store/redis_spec.rb
156
189
  - spec/stoplight/data_store_spec.rb
190
+ - spec/stoplight/default_spec.rb
191
+ - spec/stoplight/error_spec.rb
157
192
  - spec/stoplight/failure_spec.rb
193
+ - spec/stoplight/light/runnable_spec.rb
158
194
  - spec/stoplight/light_spec.rb
159
195
  - spec/stoplight/notifier/base_spec.rb
160
196
  - spec/stoplight/notifier/hip_chat_spec.rb
161
197
  - spec/stoplight/notifier/io_spec.rb
162
198
  - spec/stoplight/notifier_spec.rb
199
+ - spec/stoplight/state_spec.rb
163
200
  - spec/stoplight_spec.rb
164
- - spec/support/data_store.rb
165
- - spec/support/fakeredis.rb
166
- - spec/support/hipchat.rb
167
- homepage: http://orgsync.github.io/stoplight
201
+ homepage: https://github.com/orgsync/stoplight
168
202
  licenses:
169
203
  - MIT
170
204
  metadata: {}
@@ -184,24 +218,26 @@ required_rubygems_version: !ruby/object:Gem::Requirement
184
218
  version: '0'
185
219
  requirements: []
186
220
  rubyforge_project:
187
- rubygems_version: 2.4.1
221
+ rubygems_version: 2.4.3
188
222
  signing_key:
189
223
  specification_version: 4
190
224
  summary: Traffic control for code.
191
225
  test_files:
192
226
  - spec/spec_helper.rb
227
+ - spec/stoplight/color_spec.rb
193
228
  - spec/stoplight/data_store/base_spec.rb
194
229
  - spec/stoplight/data_store/memory_spec.rb
195
230
  - spec/stoplight/data_store/redis_spec.rb
196
231
  - spec/stoplight/data_store_spec.rb
232
+ - spec/stoplight/default_spec.rb
233
+ - spec/stoplight/error_spec.rb
197
234
  - spec/stoplight/failure_spec.rb
235
+ - spec/stoplight/light/runnable_spec.rb
198
236
  - spec/stoplight/light_spec.rb
199
237
  - spec/stoplight/notifier/base_spec.rb
200
238
  - spec/stoplight/notifier/hip_chat_spec.rb
201
239
  - spec/stoplight/notifier/io_spec.rb
202
240
  - spec/stoplight/notifier_spec.rb
241
+ - spec/stoplight/state_spec.rb
203
242
  - spec/stoplight_spec.rb
204
- - spec/support/data_store.rb
205
- - spec/support/fakeredis.rb
206
- - spec/support/hipchat.rb
207
243
  has_rdoc:
@@ -1,36 +0,0 @@
1
- # coding: utf-8
2
- # rubocop:disable Metrics/LineLength
3
-
4
- shared_examples_for 'a data store' do
5
- let(:name) { SecureRandom.hex }
6
- let(:failure) { Stoplight::Failure.new(error, time) }
7
- let(:error) { error_class.new }
8
- let(:error_class) { Class.new(StandardError) }
9
- let(:time) { Time.now }
10
- let(:state) { Stoplight::DataStore::STATES.to_a.sample }
11
- let(:threshold) { 1 + rand(100) }
12
- let(:timeout) { rand(100) }
13
-
14
- it { expect(data_store.names).to eql([]) }
15
- it { expect(data_store.get_color(name)).to eql(Stoplight::DataStore::COLOR_GREEN) }
16
- it { expect(data_store.green?(name)).to eql(true) }
17
- it { expect(data_store.yellow?(name)).to eql(false) }
18
- it { expect(data_store.red?(name)).to eql(false) }
19
- it { expect(data_store.get_attempts(name)).to eql(Stoplight::DataStore::DEFAULT_ATTEMPTS) }
20
- it { expect(data_store.record_attempt(name)).to eql(1) }
21
- it { expect(data_store.get_failures(name)).to eql(Stoplight::DataStore::DEFAULT_FAILURES) }
22
- it { expect(data_store.record_failure(name, failure)).to eql(failure) }
23
- it { expect(data_store.get_state(name)).to eql(Stoplight::DataStore::DEFAULT_STATE) }
24
- it { expect(data_store.set_state(name, state)).to eql(state) }
25
- it { expect(data_store.get_threshold(name)).to eql(Stoplight::DataStore::DEFAULT_THRESHOLD) }
26
- it { expect(data_store.set_threshold(name, threshold)).to eql(threshold) }
27
- it { expect(data_store.get_timeout(name)).to eql(Stoplight::DataStore::DEFAULT_TIMEOUT) }
28
- it { expect(data_store.set_timeout(name, timeout)).to eql(timeout) }
29
-
30
- it 'clears stale lights' do
31
- data_store.sync(name)
32
- expect(data_store.names).to include(name)
33
- data_store.clear_stale
34
- expect(data_store.names).to_not include(name)
35
- end
36
- end
@@ -1,3 +0,0 @@
1
- # coding: utf-8
2
-
3
- require 'fakeredis/rspec'
@@ -1,3 +0,0 @@
1
- # coding: utf-8
2
-
3
- require 'hipchat'