litmus_paper 0.0.3

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 (52) hide show
  1. data/.gitignore +17 -0
  2. data/.rake_commit +1 -0
  3. data/.rvmrc +1 -0
  4. data/.travis.yml +5 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE +22 -0
  7. data/README.md +31 -0
  8. data/Rakefile +6 -0
  9. data/bin/litmus +6 -0
  10. data/bin/litmusctl +7 -0
  11. data/config.ru +5 -0
  12. data/lib/facts/loadaverage.rb +6 -0
  13. data/lib/litmus_paper/app.rb +63 -0
  14. data/lib/litmus_paper/cli/admin.rb +97 -0
  15. data/lib/litmus_paper/cli/server.rb +62 -0
  16. data/lib/litmus_paper/configuration.rb +27 -0
  17. data/lib/litmus_paper/dependency/http.rb +40 -0
  18. data/lib/litmus_paper/dependency/tcp.rb +24 -0
  19. data/lib/litmus_paper/forced_health.rb +18 -0
  20. data/lib/litmus_paper/health.rb +35 -0
  21. data/lib/litmus_paper/logger.rb +15 -0
  22. data/lib/litmus_paper/metric/available_memory.rb +36 -0
  23. data/lib/litmus_paper/metric/cpu_load.rb +26 -0
  24. data/lib/litmus_paper/service.rb +51 -0
  25. data/lib/litmus_paper/status_file.rb +26 -0
  26. data/lib/litmus_paper/version.rb +3 -0
  27. data/lib/litmus_paper.rb +51 -0
  28. data/litmus_paper.gemspec +26 -0
  29. data/spec/litmus_paper/app_spec.rb +246 -0
  30. data/spec/litmus_paper/cli/admin_spec.rb +64 -0
  31. data/spec/litmus_paper/cli/server_spec.rb +16 -0
  32. data/spec/litmus_paper/configuration_spec.rb +19 -0
  33. data/spec/litmus_paper/dependency/http_spec.rb +69 -0
  34. data/spec/litmus_paper/dependency/tcp_spec.rb +35 -0
  35. data/spec/litmus_paper/health_spec.rb +71 -0
  36. data/spec/litmus_paper/metric/available_memory_spec.rb +40 -0
  37. data/spec/litmus_paper/metric/cpu_load_spec.rb +46 -0
  38. data/spec/litmus_paper/service_spec.rb +65 -0
  39. data/spec/litmus_paper/status_file_spec.rb +39 -0
  40. data/spec/litmus_paper_spec.rb +39 -0
  41. data/spec/spec_helper.rb +46 -0
  42. data/spec/support/always_available_dependency.rb +9 -0
  43. data/spec/support/config.d/passing_test.config +6 -0
  44. data/spec/support/config.d/test.config +8 -0
  45. data/spec/support/constant_metric.rb +13 -0
  46. data/spec/support/http_test_server.rb +25 -0
  47. data/spec/support/http_test_server_config.ru +3 -0
  48. data/spec/support/never_available_dependency.rb +9 -0
  49. data/spec/support/stub_facter.rb +9 -0
  50. data/spec/support/test.config +13 -0
  51. data/spec/support/test.d.config +3 -0
  52. metadata +249 -0
@@ -0,0 +1,51 @@
1
+ require 'pathname'
2
+ require 'net/http'
3
+ require 'uri'
4
+ require 'forwardable'
5
+
6
+ require 'sinatra/base'
7
+ require 'facter'
8
+ require 'syslog_logger'
9
+
10
+ require 'facts/loadaverage'
11
+
12
+ require 'litmus_paper/app'
13
+ require 'litmus_paper/configuration'
14
+ require 'litmus_paper/dependency/http'
15
+ require 'litmus_paper/dependency/tcp'
16
+ require 'litmus_paper/health'
17
+ require 'litmus_paper/forced_health'
18
+ require 'litmus_paper/logger'
19
+ require 'litmus_paper/metric/available_memory'
20
+ require 'litmus_paper/metric/cpu_load'
21
+ require 'litmus_paper/service'
22
+ require 'litmus_paper/status_file'
23
+
24
+ module LitmusPaper
25
+ class << self
26
+ attr_reader :services, :config_dir
27
+ end
28
+
29
+ def self.configure(filename)
30
+ @config_file = filename
31
+
32
+ begin
33
+ @services = LitmusPaper::Configuration.new(filename).evaluate
34
+ rescue Exception
35
+ end
36
+ end
37
+
38
+ def self.config_dir=(path)
39
+ @config_dir = Pathname.new(path)
40
+ end
41
+
42
+ def self.reload
43
+ configure(@config_file)
44
+ end
45
+
46
+ def self.reset
47
+ @services = {}
48
+ end
49
+ end
50
+
51
+ Signal.trap("HUP") { LitmusPaper.reload }
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/litmus_paper/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Braintreeps"]
6
+ gem.email = ["code@getbraintree.com"]
7
+ gem.description = %q{Backend health tester for HA Services}
8
+ gem.summary = %q{Backend health tester for HA Services}
9
+ gem.homepage = ""
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "litmus_paper"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = LitmusPaper::VERSION
17
+
18
+ gem.add_dependency "sinatra", "~> 1.3.2"
19
+ gem.add_dependency "facter", "~> 1.6.7"
20
+ gem.add_dependency "SyslogLogger", "1.4.1"
21
+
22
+ gem.add_development_dependency "rspec", "2.9.0"
23
+ gem.add_development_dependency "rack-test", "0.6.1"
24
+ gem.add_development_dependency "rake"
25
+ gem.add_development_dependency "rake_commit", "0.13"
26
+ end
@@ -0,0 +1,246 @@
1
+ require 'spec_helper'
2
+
3
+ describe LitmusPaper::App do
4
+ def app
5
+ LitmusPaper::App
6
+ end
7
+
8
+ describe "GET /" do
9
+ it "returns the list of services litmus monitors" do
10
+ LitmusPaper.services['test'] = LitmusPaper::Service.new('test')
11
+ LitmusPaper.services['another'] = LitmusPaper::Service.new('another')
12
+
13
+ get "/"
14
+
15
+ last_response.status.should == 200
16
+ last_response.body.should include('test')
17
+ last_response.body.should include('another')
18
+ end
19
+ end
20
+
21
+ describe "POST /force/*" do
22
+ it "creates a global upfile" do
23
+ test_service = LitmusPaper::Service.new('test', [NeverAvailableDependency.new], [ConstantMetric.new(100)])
24
+ LitmusPaper.services['test'] = test_service
25
+
26
+ post "/force/up", :reason => "up for testing"
27
+ last_response.status.should == 201
28
+
29
+ get "/test/status"
30
+ last_response.status.should == 200
31
+ last_response.body.should match(/up for testing/)
32
+ end
33
+
34
+ it "creates a global downfile" do
35
+ test_service = LitmusPaper::Service.new('test', [AlwaysAvailableDependency.new], [ConstantMetric.new(100)])
36
+ LitmusPaper.services['test'] = test_service
37
+
38
+ post "/force/down", :reason => "down for testing"
39
+ last_response.status.should == 201
40
+
41
+ get "/test/status"
42
+ last_response.status.should == 503
43
+ last_response.body.should match(/down for testing/)
44
+ end
45
+
46
+ it "creates a service specific upfile" do
47
+ test_service = LitmusPaper::Service.new('test', [NeverAvailableDependency.new], [ConstantMetric.new(100)])
48
+ LitmusPaper.services['test'] = test_service
49
+
50
+ post "/force/up/test", :reason => "up for testing"
51
+ last_response.status.should == 201
52
+
53
+ get "/test/status"
54
+ last_response.status.should == 200
55
+ last_response.body.should match(/up for testing/)
56
+ end
57
+ end
58
+
59
+ describe "DELETE /force/*" do
60
+ it "removes the global upfile" do
61
+ test_service = LitmusPaper::Service.new('test', [NeverAvailableDependency.new], [ConstantMetric.new(100)])
62
+ LitmusPaper.services['test'] = test_service
63
+
64
+ post "/force/up", :reason => "up for testing"
65
+ last_response.status.should == 201
66
+
67
+ get "/test/status"
68
+ last_response.status.should == 200
69
+
70
+ delete "/force/up"
71
+ last_response.status.should == 200
72
+
73
+ get "/test/status"
74
+ last_response.status.should == 503
75
+ last_response.body.should_not match(/up for testing/)
76
+ end
77
+
78
+ it "removes the global downfile" do
79
+ test_service = LitmusPaper::Service.new('test', [AlwaysAvailableDependency.new], [ConstantMetric.new(100)])
80
+ LitmusPaper.services['test'] = test_service
81
+
82
+ post "/force/down", :reason => "down for testing"
83
+ last_response.status.should == 201
84
+
85
+ get "/test/status"
86
+ last_response.status.should == 503
87
+
88
+ delete "/force/down"
89
+ last_response.status.should == 200
90
+
91
+ get "/test/status"
92
+ last_response.should be_ok
93
+ last_response.body.should_not match(/down for testing/)
94
+ end
95
+
96
+ it "removes a service specific upfile" do
97
+ test_service = LitmusPaper::Service.new('test', [NeverAvailableDependency.new], [ConstantMetric.new(100)])
98
+ LitmusPaper.services['test'] = test_service
99
+
100
+ post "/force/up/test", :reason => "up for testing"
101
+ last_response.status.should == 201
102
+
103
+ get "/test/status"
104
+ last_response.status.should == 200
105
+ last_response.body.should match(/up for testing/)
106
+
107
+ delete "/force/up/test"
108
+ last_response.status.should == 200
109
+
110
+ get "/test/status"
111
+ last_response.status.should == 503
112
+ end
113
+
114
+ it "404s if there is no upfile" do
115
+ test_service = LitmusPaper::Service.new('test', [NeverAvailableDependency.new], [ConstantMetric.new(100)])
116
+
117
+ delete "/up"
118
+
119
+ last_response.status.should == 404
120
+ end
121
+ end
122
+
123
+ describe "GET /:service/status" do
124
+ it "is successful when the service is passing" do
125
+ test_service = LitmusPaper::Service.new('test', [AlwaysAvailableDependency.new], [ConstantMetric.new(100)])
126
+ LitmusPaper.services['test'] = test_service
127
+
128
+ get "/test/status"
129
+
130
+ last_response.should be_ok
131
+ last_response.header["Content-Type"].should == "text/plain"
132
+ last_response.header["X-Health"].should == "100"
133
+ last_response.body.should match(/Health: 100/)
134
+ last_response.body.should match(/AlwaysAvailableDependency: OK/)
135
+ last_response.body.should include("ConstantMetric(100): 100")
136
+ end
137
+
138
+ it "is 'service unavailable' when the check fails" do
139
+ test_service = LitmusPaper::Service.new('test', [NeverAvailableDependency.new], [ConstantMetric.new(100)])
140
+ LitmusPaper.services['test'] = test_service
141
+
142
+ get "/test/status"
143
+
144
+ last_response.status.should == 503
145
+ last_response.header["Content-Type"].should == "text/plain"
146
+ last_response.header["X-Health"].should == "0"
147
+ last_response.body.should match(/Health: 0/)
148
+ end
149
+
150
+ it "is 'not found' when the service is unknown" do
151
+ get "/unknown/status"
152
+
153
+ last_response.status.should == 404
154
+ last_response.header["Content-Type"].should == "text/plain"
155
+ end
156
+
157
+ it "is 'service unavailable' when an up file and down file exists" do
158
+ test_service = LitmusPaper::Service.new('test', [AlwaysAvailableDependency.new], [ConstantMetric.new(100)])
159
+ LitmusPaper.services['test'] = test_service
160
+
161
+ LitmusPaper::StatusFile.new("up", "test").create("Up for testing")
162
+ LitmusPaper::StatusFile.new("down", "test").create("Down for testing")
163
+
164
+ get "/test/status"
165
+
166
+ last_response.status.should == 503
167
+ last_response.body.should match(/Down for testing/)
168
+ end
169
+
170
+ it "is 'service available' when an up file exists" do
171
+ test_service = LitmusPaper::Service.new('test', [NeverAvailableDependency.new], [ConstantMetric.new(100)])
172
+ LitmusPaper.services['test'] = test_service
173
+
174
+ LitmusPaper::StatusFile.new("up", "test").create("Up for testing")
175
+
176
+ get "/test/status"
177
+
178
+ last_response.status.should == 200
179
+ last_response.body.should match(/Up for testing/)
180
+ end
181
+
182
+ it "is 'service available' when an up file exists" do
183
+ test_service = LitmusPaper::Service.new('test', [NeverAvailableDependency.new], [ConstantMetric.new(100)])
184
+ LitmusPaper.services['test'] = test_service
185
+
186
+ LitmusPaper::StatusFile.new("up", "test").create("Up for testing")
187
+
188
+ get "/test/status"
189
+
190
+ last_response.status.should == 200
191
+ last_response.body.should match(/Up for testing/)
192
+ end
193
+
194
+ it "is 'service unavailable' when a global down file and up file exists" do
195
+ test_service = LitmusPaper::Service.new('test', [AlwaysAvailableDependency.new], [ConstantMetric.new(100)])
196
+ LitmusPaper.services['test'] = test_service
197
+
198
+ LitmusPaper::StatusFile.new("global_down").create("Down for testing")
199
+ LitmusPaper::StatusFile.new("global_up").create("Up for testing")
200
+
201
+ get "/test/status"
202
+
203
+ last_response.status.should == 503
204
+ last_response.body.should match(/Down for testing/)
205
+ end
206
+
207
+ it "is 'service unavailable' when a global down file exists" do
208
+ test_service = LitmusPaper::Service.new('test', [AlwaysAvailableDependency.new], [ConstantMetric.new(100)])
209
+ LitmusPaper.services['test'] = test_service
210
+
211
+ LitmusPaper::StatusFile.new("global_down").create("Down for testing")
212
+
213
+ get "/test/status"
214
+
215
+ last_response.status.should == 503
216
+ last_response.body.should match(/Down for testing/)
217
+ end
218
+
219
+ it "is successful when a global up file exists" do
220
+ test_service = LitmusPaper::Service.new('test', [NeverAvailableDependency.new], [ConstantMetric.new(100)])
221
+ LitmusPaper.services['test'] = test_service
222
+
223
+ LitmusPaper::StatusFile.new("global_up").create("Up for testing")
224
+
225
+ get "/test/status"
226
+
227
+ last_response.status.should == 200
228
+ last_response.body.should match(/Up for testing/)
229
+ end
230
+ end
231
+
232
+ describe "server errors" do
233
+ it "responds with a text/plain 500 response" do
234
+ old_environment = :test
235
+ begin
236
+ app.environment = :production
237
+ get "/test/error"
238
+ last_response.status.should == 500
239
+ last_response.headers["Content-Type"].should == "text/plain"
240
+ last_response.body.should == "Server Error"
241
+ ensure
242
+ app.environment = old_environment
243
+ end
244
+ end
245
+ end
246
+ end
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+
3
+
4
+ describe 'litmusctl' do
5
+ def _litmusctl(args)
6
+ `bundle exec ruby -I lib bin/litmusctl #{args} -p 9293`
7
+ end
8
+
9
+ before(:all) do
10
+ system "bundle exec ruby -I lib bin/litmus -p 9293 -d -D /tmp/litmus_paper -c #{TEST_CONFIG} -P /tmp/litmus.pid"
11
+ end
12
+
13
+ after(:all) do
14
+ system "kill -9 `cat /tmp/litmus.pid`"
15
+ end
16
+
17
+ describe 'list' do
18
+ it "returns the list of services running" do
19
+ _litmusctl('list').should match("test")
20
+ end
21
+ end
22
+
23
+ describe 'status' do
24
+ it 'returns the status of a service' do
25
+ _litmusctl('status test').should match("Health: 0")
26
+ _litmusctl('status passing_test').should match(/Health: \d\d/)
27
+ end
28
+
29
+ it "returns 'NOT FOUND' for a service that doesn't exist" do
30
+ _litmusctl('status unknown').should match('NOT FOUND')
31
+ end
32
+ end
33
+
34
+ describe "force" do
35
+ it "can create a global downfile" do
36
+ _litmusctl('force down -r "for testing"').should match("File created")
37
+
38
+ status = _litmusctl('status test')
39
+ status.should match(/Health: 0/)
40
+ status.should match(/for testing/)
41
+ end
42
+
43
+ it "creates a downfile" do
44
+ _litmusctl('force down test -r "for testing"').should match("File created")
45
+
46
+ status = _litmusctl('status test')
47
+ status.should match(/Health: 0/)
48
+ status.should match(/for testing/)
49
+ end
50
+
51
+ it 'removes an upfile for the service' do
52
+ _litmusctl('force up test -r "for testing"').should match("File created")
53
+ _litmusctl('force up test -d').should match("File deleted")
54
+
55
+ status = _litmusctl('status passing_test')
56
+ status.should match(/Health: \d\d/)
57
+ status.should_not match(/for testing/)
58
+ end
59
+
60
+ it "returns not found if downfile doesn't exist" do
61
+ _litmusctl('force down test -d').should match("NOT FOUND")
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+ require 'litmus_paper/cli/server'
3
+
4
+ describe LitmusPaper::CLI::Server do
5
+ describe 'parse!' do
6
+ it 'parses litmus config file options' do
7
+ options = LitmusPaper::CLI::Server::Options.new.parse!(['-c', 'foo.conf'])
8
+ options[:litmus_config].should == 'foo.conf'
9
+ end
10
+
11
+ it 'parses the config dir options' do
12
+ options = LitmusPaper::CLI::Server::Options.new.parse!(['-D', '/tmp/foo'])
13
+ options[:config_dir].should == '/tmp/foo'
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe LitmusPaper::Configuration do
4
+ describe "evaluate" do
5
+ it "configures a service" do
6
+ config = LitmusPaper::Configuration.new(TEST_CONFIG)
7
+ services = config.evaluate
8
+ services.has_key?('test').should == true
9
+ end
10
+ end
11
+
12
+ describe "include_files" do
13
+ it "configures a dir glob of services" do
14
+ config = LitmusPaper::Configuration.new(TEST_D_CONFIG)
15
+ services = config.evaluate
16
+ services.has_key?('test').should == true
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,69 @@
1
+ require 'spec_helper'
2
+
3
+ describe LitmusPaper::Dependency::HTTP do
4
+ before(:all) do
5
+ server_start = system "bundle exec rackup spec/support/http_test_server_config.ru --port 9294 --pid /tmp/http-test-server.pid --daemonize"
6
+ SpecHelper.wait_for_service :host => '127.0.0.1', :port => 9294
7
+ @url = "http://127.0.0.1:9294"
8
+ end
9
+
10
+ after(:all) do
11
+ system "kill -9 `cat /tmp/http-test-server.pid`"
12
+ end
13
+
14
+ describe "#available?" do
15
+ context "http method" do
16
+ it "uses the given http method when making the request" do
17
+ check = LitmusPaper::Dependency::HTTP.new("#{@url}/method", :method => "GET", :content => "POST")
18
+ check.should_not be_available
19
+
20
+ check = LitmusPaper::Dependency::HTTP.new("#{@url}/method", :method => "POST", :content => "POST")
21
+ check.should be_available
22
+ end
23
+ end
24
+
25
+ it "is true when response is 200" do
26
+ check = LitmusPaper::Dependency::HTTP.new("#{@url}/status/200")
27
+ check.should be_available
28
+ end
29
+
30
+ it "is true when response is 200 and expected content matches" do
31
+ check = LitmusPaper::Dependency::HTTP.new("#{@url}/status/200", :content => "200 OK")
32
+ check.should be_available
33
+ end
34
+
35
+ it "is false when response is 200, but does not match content" do
36
+ check = LitmusPaper::Dependency::HTTP.new("#{@url}/status/200", :content => "some text not in the response")
37
+ check.should_not be_available
38
+ end
39
+
40
+ it "is true when response is any 200 level response" do
41
+ check = LitmusPaper::Dependency::HTTP.new("#{@url}/status/201")
42
+ check.should be_available
43
+ check = LitmusPaper::Dependency::HTTP.new("#{@url}/status/202")
44
+ check.should be_available
45
+ end
46
+
47
+ it "is false when response is 500 " do
48
+ check = LitmusPaper::Dependency::HTTP.new("#{@url}/status/500")
49
+ check.should_not be_available
50
+ end
51
+
52
+ it "is false when the response is 404" do
53
+ check = LitmusPaper::Dependency::HTTP.new("#{@url}/status/404")
54
+ check.should_not be_available
55
+ end
56
+
57
+ it "is false when the dependency is not available" do
58
+ check = LitmusPaper::Dependency::HTTP.new('http://127.0.0.1:7777')
59
+ check.should_not be_available
60
+ end
61
+ end
62
+
63
+ describe "to_s" do
64
+ it "is the name of the class and the url" do
65
+ check = LitmusPaper::Dependency::HTTP.new("#{@url}/status/500")
66
+ check.to_s.should == "Dependency::HTTP(http://127.0.0.1:9294/status/500)"
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ describe LitmusPaper::Dependency::TCP do
4
+ before(:all) do
5
+ @server = TCPServer.new 3333
6
+ end
7
+
8
+ after(:all) do
9
+ @server.close
10
+ end
11
+
12
+ describe "#available?" do
13
+ it "is true when it's able to reach the ip and port" do
14
+ check = LitmusPaper::Dependency::TCP.new("127.0.0.1", 3333)
15
+ check.should be_available
16
+ end
17
+
18
+ it "is false when the ip is not available" do
19
+ check = LitmusPaper::Dependency::TCP.new("10.254.254.254", 3333)
20
+ check.should_not be_available
21
+ end
22
+
23
+ it "is false when the port is not available" do
24
+ check = LitmusPaper::Dependency::TCP.new("127.0.0.1", 3334)
25
+ check.should_not be_available
26
+ end
27
+ end
28
+
29
+ describe "to_s" do
30
+ it "is the name of the class and the ip and port" do
31
+ check = LitmusPaper::Dependency::TCP.new("127.0.0.1", 3333)
32
+ check.to_s.should == "Dependency::TCP(tcp://127.0.0.1:3333)"
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+
3
+ describe LitmusPaper::Health do
4
+ describe "ok?" do
5
+ it "is true when health is greater than 0" do
6
+ health = LitmusPaper::Health.new
7
+ health.perform(ConstantMetric.new(50))
8
+ health.should be_ok
9
+ end
10
+
11
+ it "is false when health is 0" do
12
+ health = LitmusPaper::Health.new
13
+ health.perform(ConstantMetric.new(0))
14
+ health.should_not be_ok
15
+ end
16
+ end
17
+
18
+ describe "perform" do
19
+ it "executes the check and adds its value to its health" do
20
+ health = LitmusPaper::Health.new
21
+ health.perform(ConstantMetric.new(50))
22
+ health.perform(ConstantMetric.new(25))
23
+ health.value.should == 75
24
+ end
25
+ end
26
+
27
+ describe "ensure" do
28
+ it "checks the dependency and modifies the value accordingly" do
29
+ health = LitmusPaper::Health.new
30
+ health.ensure(NeverAvailableDependency.new)
31
+ health.perform(ConstantMetric.new(50))
32
+ health.value.should == 0
33
+ end
34
+ end
35
+
36
+ describe "summary" do
37
+ it "includes the availablilty of dependencies" do
38
+ health = LitmusPaper::Health.new
39
+ health.ensure(NeverAvailableDependency.new)
40
+ health.ensure(AlwaysAvailableDependency.new)
41
+
42
+ health.summary.should match(/NeverAvailableDependency: FAIL/)
43
+ health.summary.should match(/AlwaysAvailableDependency: OK/)
44
+ end
45
+
46
+ it "includes the health of individual metrics" do
47
+ health = LitmusPaper::Health.new
48
+ health.perform(ConstantMetric.new(12))
49
+ health.perform(ConstantMetric.new(34))
50
+
51
+ health.summary.should include("ConstantMetric(12): 12")
52
+ health.summary.should include("ConstantMetric(34): 34")
53
+ end
54
+
55
+ it "only runs each metric once" do
56
+ health = LitmusPaper::Health.new
57
+ metric = ConstantMetric.new(12)
58
+ metric.should_receive(:current_health).once.and_return(12)
59
+
60
+ health.perform(metric)
61
+ end
62
+
63
+ it "only runs each dependency once" do
64
+ health = LitmusPaper::Health.new
65
+ dependency = AlwaysAvailableDependency.new
66
+ dependency.should_receive(:available?).once.and_return(true)
67
+
68
+ health.ensure(dependency)
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ describe LitmusPaper::Metric::AvailableMemory do
4
+ describe "#current_health" do
5
+ it "multiplies weight by memory available" do
6
+ facter = StubFacter.new({"memorytotal" => "10 GB", "memoryfree" => "5 GB"})
7
+ memory = LitmusPaper::Metric::AvailableMemory.new(50, facter)
8
+ memory.current_health.should == 25
9
+ end
10
+
11
+ describe "#memory_total" do
12
+ it "is a positive integer" do
13
+ metric = LitmusPaper::Metric::AvailableMemory.new(50)
14
+ metric.memory_total.should > 1_000
15
+ end
16
+
17
+ it "is cached" do
18
+ Facter.should_receive(:value).once.and_return("10 MB")
19
+ metric = LitmusPaper::Metric::AvailableMemory.new(50)
20
+ metric.memory_total
21
+ metric.memory_total
22
+ metric.memory_total
23
+ end
24
+ end
25
+
26
+ describe "#memory_free" do
27
+ it "is a positive integer" do
28
+ metric = LitmusPaper::Metric::AvailableMemory.new(50)
29
+ metric.memory_free.should > 100
30
+ end
31
+ end
32
+
33
+ describe "#to_s" do
34
+ it "is the name of the check and the max weight" do
35
+ metric = LitmusPaper::Metric::AvailableMemory.new(50)
36
+ metric.to_s.should == "Metric::AvailableMemory(50)"
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ describe LitmusPaper::Metric::CPULoad do
4
+ describe "#current_health" do
5
+ it "is the percent of available cpu capacity" do
6
+ facter = StubFacter.new({"processorcount" => "4", "loadaverage" => "1.00 0.40 0.10"})
7
+ cpu_load = LitmusPaper::Metric::CPULoad.new(40, facter)
8
+ cpu_load.current_health.should == 30
9
+ end
10
+
11
+ it "is zero when the load is above one per core" do
12
+ facter = StubFacter.new({"processorcount" => "4", "loadaverage" => "20.00 11.40 10.00"})
13
+ cpu_load = LitmusPaper::Metric::CPULoad.new(50, facter)
14
+ cpu_load.current_health.should == 0
15
+ end
16
+ end
17
+
18
+ describe "#processor_count" do
19
+ it "is a positive integer" do
20
+ cpu_load = LitmusPaper::Metric::CPULoad.new(50)
21
+ cpu_load.processor_count.should > 0
22
+ end
23
+
24
+ it "is cached" do
25
+ Facter.should_receive(:value).once.and_return("10")
26
+ cpu_load = LitmusPaper::Metric::CPULoad.new(50)
27
+ cpu_load.processor_count
28
+ cpu_load.processor_count
29
+ cpu_load.processor_count
30
+ end
31
+ end
32
+
33
+ describe "#load_average" do
34
+ it "is a floating point" do
35
+ cpu_load = LitmusPaper::Metric::CPULoad.new(50)
36
+ cpu_load.load_average.should > 0.0
37
+ end
38
+ end
39
+
40
+ describe "#to_s" do
41
+ it "is the check name and the maximum weight" do
42
+ cpu_load = LitmusPaper::Metric::CPULoad.new(50)
43
+ cpu_load.to_s.should == "Metric::CPULoad(50)"
44
+ end
45
+ end
46
+ end