health-reporter 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bec795aa467f18c19a4082de1a606a7f9f85a1f1
4
- data.tar.gz: 6cc065ff3b203db1b5ec80be22c143f98fc2ad70
3
+ metadata.gz: 90f655ef277bd77b6f90e6129976868c5c3f934f
4
+ data.tar.gz: d905978f2768c0472a238e4b5c8c3c0b3831e882
5
5
  SHA512:
6
- metadata.gz: 9efeb9f05cbb9c332e41a742061b771a1e0fd396c93a98faa9dd98ad035e2dfdacf45e818cf5ff068d308bc9d41852bc96023d7aea6f490f5258b4716364a184
7
- data.tar.gz: 6b5048d5c2ef58ae49363915fd62efa39307c13f01f0a05c272c7e1fdb958538190f43dd096de1a8d8e8eecdd6b6bf1d467e660fe3946b377a6b84ce75111363
6
+ metadata.gz: 9ab4e6974bcc5ffad2e8d454e28f21e87d1528c6bd3fbfc4fd13bdcd1850d57a0502df6e7000b9d2fa3d21fa0eabfcca69564b0495f2972f25d256aa8262fd0d
7
+ data.tar.gz: df47ccab910847e661cc3769594344408635bdced26e8c93563bfceb672fa6445ad332010ae94dc05cf0ede58be9fb7bcf80fec1cd13b8afb28a77eae4e935ac
data/.gitignore CHANGED
@@ -50,3 +50,4 @@ build-iPhoneSimulator/
50
50
  .rvmrc
51
51
 
52
52
  Gemfile.lock
53
+ .byebug_history
data/README.md CHANGED
@@ -33,6 +33,7 @@ docker-compose run --rm health-reporter bundle exec rspec -cfd spec/*
33
33
 
34
34
  ## Usage
35
35
 
36
+ #TODO add dependency registration and calling
36
37
 
37
38
  ## Contributing
38
39
 
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
20
  spec.require_paths = ["lib"]
21
21
 
22
+ spec.add_development_dependency 'timecop', '~> 0.8.0'
22
23
  spec.add_development_dependency 'bundler', '~> 1.3'
23
24
  spec.add_development_dependency 'rake', '~> 10.0'
24
25
  spec.add_development_dependency 'rspec', '~> 2.13'
@@ -1,4 +1,4 @@
1
- module HealthReporter
1
+ class HealthReporter
2
2
  end
3
3
 
4
4
  require 'health_reporter/reporter'
@@ -1,15 +1,74 @@
1
- require 'json'
1
+ require 'singleton'
2
2
 
3
- module HealthReporter
4
- class Reporter
5
- def initialize(healthy: true)
6
- @healthy = healthy
7
- end
3
+ class HealthReporter
4
+ include Singleton
5
+
6
+ def self.self_test
7
+ @@self_test
8
+ end
9
+
10
+ def self.self_test=(self_test)
11
+ @@self_test = self_test
12
+ end
13
+
14
+ def self.unhealthy_cache_ttl
15
+ @@unhealthy_cache_ttl
16
+ end
17
+
18
+ def self.unhealthy_cache_ttl=(unhealthy_cache_ttl)
19
+ @@unhealthy_cache_ttl = unhealthy_cache_ttl
20
+ end
21
+
22
+ def self.healthy_cache_ttl
23
+ @@healthy_cache_ttl
24
+ end
8
25
 
26
+ def self.healthy_cache_ttl=(healthy_cache_ttl)
27
+ @@healthy_cache_ttl = healthy_cache_ttl
28
+ end
29
+
30
+ @@self_test = lambda{ true }
31
+ @@unhealthy_cache_ttl = 30
32
+ @@healthy_cache_ttl = 60
33
+ @@last_check_time = nil
34
+ @@healthy = nil #Initialized as nil so that first call will set it
35
+ @@semaphore = Mutex.new
36
+
37
+ # TODO
38
+ # def register_dependency_check(url:, code: 200)
39
+ # raise "Configured URL #{url} is invalid" unless url =~ URI::regexp
40
+ #
41
+ # dependencies[]
42
+ # end
9
43
 
44
+ def self.healthy?
45
+ @@semaphore.synchronize {
46
+ perform_health_check if @@healthy.nil? or cache_ttl_expired
47
+ @@healthy
48
+ }
49
+ end
50
+
51
+ private
10
52
 
11
- def healthy
12
- @healthy
53
+ def self.perform_health_check
54
+ @@healthy = sanitize(@@self_test.call)
55
+ @@last_check_time = Time.now
56
+ end
57
+
58
+ def self.sanitize(result)
59
+ unless [true, false].include?(result)
60
+ raise "Invalid non-boolean response from registered self-check lambda: #{result.to_s}"
13
61
  end
62
+ result
63
+ end
64
+
65
+ def self.cache_ttl_expired
66
+ return true if @@last_check_time.nil?
67
+ Time.now > (@@last_check_time + ttl)
68
+ end
69
+
70
+ def self.ttl
71
+ return @@healthy_cache_ttl if @@healthy
72
+ @@unhealthy_cache_ttl
14
73
  end
15
74
  end
@@ -1,3 +1,3 @@
1
- module HealthReporter
2
- VERSION = '0.0.1'
1
+ class HealthReporter
2
+ VERSION = '0.0.2'
3
3
  end
data/spec/reporter.rb CHANGED
@@ -1,12 +1,199 @@
1
1
  require 'spec_helper'
2
- require 'yaml'
3
2
 
4
- describe HealthReporter::Reporter do
5
- subject { HealthReporter::Reporter }
3
+ describe HealthReporter do
4
+ subject { HealthReporter }
6
5
 
7
6
  it 'has a version number' do
8
7
  expect(HealthReporter::VERSION).not_to be nil
9
8
  end
10
9
 
10
+ before(:each) do
11
+ subject.healthy_cache_ttl = 60
12
+ subject.unhealthy_cache_ttl = 30
13
+ subject.self_test = lambda{ true }
14
+ subject.class_variable_set(:@@last_check_time, nil)
15
+ subject.class_variable_set(:@@healthy, nil)
16
+ Timecop.return
17
+ reset_lambda_runner_spy
18
+ end
19
+
20
+ context 'when configuring' do
21
+ it 'remembers the self-test lambda passed to it' do
22
+ test_lambda = lambda{ 'ab' == 'cd' }
23
+ subject.self_test = test_lambda
24
+ expect(subject.self_test).to be test_lambda
25
+ end
26
+
27
+ it 'uses the self-test lambda passed to it' do
28
+ test_lambda = spy_lambda_returning_false
29
+ subject.self_test = test_lambda
30
+ expect(subject.self_test).to be test_lambda
31
+ expect(subject.healthy?).to be false
32
+ expect(spy_lambda_was_run?).to eq true
33
+ end
34
+
35
+ it 'remembers the cache ttl when healthy' do
36
+ subject.healthy_cache_ttl = 10
37
+ expect(subject.healthy_cache_ttl).to eq 10
38
+ end
39
+
40
+ it 'remembers the cache ttl when not healthy' do
41
+ subject.unhealthy_cache_ttl = 5
42
+ expect(subject.unhealthy_cache_ttl).to eq 5
43
+ end
44
+ end
45
+
46
+ context 'when exercising self-test lambda' do
47
+ it 'allows true to be returned by self-test lambda' do
48
+ test_lambda = lambda{ true }
49
+ subject.self_test = test_lambda
50
+ expect(subject.healthy?).to be true
51
+ end
52
+
53
+ it 'allows false to be returned by self-test lambda' do
54
+ test_lambda = lambda{ false }
55
+ subject.self_test = test_lambda
56
+ expect(subject.healthy?).to be false
57
+ end
58
+
59
+ it 'raises an exception when non-boolean values are returned by self-test lambda' do
60
+ test_lambda = lambda{ "I don't feel well..." }
61
+ subject.self_test = test_lambda
62
+ expect{subject.healthy?}.to raise_error RuntimeError, "Invalid non-boolean response from registered self-check lambda: I don't feel well..."
63
+ end
64
+ end
65
+
66
+ context 'when initialized without any parameters' do
67
+ it 'sets the default self-test lambda to { true }' do
68
+ expect(subject.healthy?).to eq true
69
+ end
70
+
71
+ it 'sets the default healthy state cache ttl to 60 seconds' do
72
+ expect(subject.healthy_cache_ttl).to eq 60
73
+ end
74
+
75
+ it 'sets the default unhealthy state cache ttl to 30 seconds' do
76
+ expect(subject.unhealthy_cache_ttl).to eq 30
77
+ end
78
+ end
79
+
80
+ context 'when calling health check for first time (no cached health state)' do
81
+ it 'calls the configured self-test lambda and returns health' do
82
+ subject.self_test = spy_lambda_returning_false
83
+ expect(subject.healthy?).to be false
84
+ expect(spy_lambda_was_run?).to eq true
85
+ end
86
+ end
11
87
 
88
+ context 'when current state is healty' do
89
+ before(:each) do
90
+ subject.self_test = spy_lambda_returning_true
91
+ subject.healthy? #force the self-test
92
+ reset_lambda_runner_spy #reset the spy so that we can see if it was run or not
93
+ end
94
+
95
+ context 'when neither healty-cache-ttl nor unhealty-cache-ttl has expired' do
96
+ before(:each) do
97
+ subject.unhealthy_cache_ttl = 10
98
+ subject.healthy_cache_ttl = 10
99
+ Timecop.freeze(Time.now + 5)
100
+ end
101
+
102
+ it 'does not call the registered self-test lambda' do
103
+ subject.healthy? #request here and test if it was run in expect below
104
+ expect(spy_lambda_was_run?).to eq false
105
+ end
106
+ it 'returns the current healthy state' do
107
+ expect(subject.healthy?).to be true
108
+ end
109
+ end
110
+
111
+ context 'when healty-cache-ttl has expired' do
112
+ before do
113
+ subject.unhealthy_cache_ttl = 10
114
+ subject.healthy_cache_ttl = 3
115
+ Timecop.freeze(Time.now + 5)
116
+ end
117
+
118
+ it 'calls the registered self-test lambda' do
119
+ subject.healthy? #request here and test if it was run in expect below
120
+ expect(spy_lambda_was_run?).to eq true
121
+ end
122
+ it 'returns the current healthy state' do
123
+ expect(subject.healthy?).to be true
124
+ end
125
+ end
126
+
127
+ context 'when unhealty-cache-ttl has expired' do
128
+ before(:each) do
129
+ subject.unhealthy_cache_ttl = 3
130
+ subject.healthy_cache_ttl = 10
131
+ Timecop.freeze(Time.now + 5)
132
+ end
133
+
134
+ it 'does not call the registered self-test lambda' do
135
+ subject.healthy? #request here and test if it was run in expect below
136
+ expect(spy_lambda_was_run?).to eq false
137
+ end
138
+ it 'returns the current healthy state' do
139
+ expect(subject.healthy?).to be true
140
+ end
141
+ end
142
+ end
143
+
144
+ context 'when current state is unhealty' do
145
+ before(:each) do
146
+ subject.self_test = spy_lambda_returning_false
147
+ subject.healthy? #force the self-test
148
+ reset_lambda_runner_spy #reset the spy so that we can see if it was run or not
149
+ end
150
+
151
+ context 'when neither healty-cache-ttl nor unhealty-cache-ttl has expired' do
152
+ before(:each) do
153
+ subject.unhealthy_cache_ttl = 10
154
+ subject.healthy_cache_ttl = 10
155
+ Timecop.freeze(Time.now + 5)
156
+ end
157
+
158
+ it 'does not call the registered self-test lambda' do
159
+ subject.healthy? #request here and test if it was run in expect below
160
+ expect(spy_lambda_was_run?).to eq false
161
+ end
162
+ it 'returns the current unhealthy state' do
163
+ expect(subject.healthy?).to be false
164
+ end
165
+ end
166
+
167
+ context 'when healty-cache-ttl has expired' do
168
+ before(:each) do
169
+ subject.unhealthy_cache_ttl = 10
170
+ subject.healthy_cache_ttl = 3
171
+ Timecop.freeze(Time.now + 5)
172
+ end
173
+
174
+ it 'does not call the registered self-test lambda' do
175
+ subject.healthy? #request here and test if it was run in expect below
176
+ expect(spy_lambda_was_run?).to eq false
177
+ end
178
+ it 'returns the current unhealthy state' do
179
+ expect(subject.healthy?).to be false
180
+ end
181
+ end
182
+
183
+ context 'when unhealty-cache-ttl has expired' do
184
+ before(:each) do
185
+ subject.unhealthy_cache_ttl = 3
186
+ subject.healthy_cache_ttl = 10
187
+ Timecop.freeze(Time.now + 5)
188
+ end
189
+
190
+ it 'calls the registered self-test lambda' do
191
+ subject.healthy? #request here and test if it was run in expect below
192
+ expect(spy_lambda_was_run?).to eq true
193
+ end
194
+ it 'returns the current unhealthy state' do
195
+ expect(subject.healthy?).to be false
196
+ end
197
+ end
198
+ end
12
199
  end
data/spec/spec_helper.rb CHANGED
@@ -1,11 +1,36 @@
1
1
  require 'simplecov'
2
2
  require 'simplecov-rcov'
3
+ require 'timecop'
3
4
 
4
5
  SimpleCov.formatter = SimpleCov::Formatter::RcovFormatter
5
6
  SimpleCov.start do
6
- add_filter "/spec/"
7
+ add_filter "./spec/"
7
8
  end
8
9
 
9
10
  $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
10
11
 
11
12
  require 'health_reporter'
13
+
14
+
15
+ def reset_lambda_runner_spy
16
+ @test_variable_from_sender = Random.new.rand(1...100000000000)
17
+ @test_variable_from_receiver = 0
18
+ end
19
+
20
+ def spy_lambda_was_run?
21
+ @test_variable_from_receiver == @test_variable_from_sender
22
+ end
23
+
24
+ def spy_lambda_returning_false
25
+ lambda{
26
+ @test_variable_from_receiver = @test_variable_from_sender
27
+ return false
28
+ }
29
+ end
30
+
31
+ def spy_lambda_returning_true
32
+ lambda{
33
+ @test_variable_from_receiver = @test_variable_from_sender
34
+ return true
35
+ }
36
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: health-reporter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Barney de Villiers
@@ -10,6 +10,20 @@ bindir: bin
10
10
  cert_chain: []
11
11
  date: 2018-04-06 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: timecop
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 0.8.0
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 0.8.0
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement