Skip to content

Commit f81ae2a

Browse files
authored
Add skip_all option for checks and check collections (#28)
1 parent 9dac630 commit f81ae2a

9 files changed

Lines changed: 190 additions & 26 deletions

File tree

‎CHANGELOG.markdown‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#### Unreleased
2+
* Add a `skip_all` registration option for checks and check collections that
3+
should remain directly accessible without running at `/okcomputer/all`
24
* Don't use a shared closure for each spawned thread
35
> awilfox: https://github.com/okcomputer-ruby/okcomputer/pull/27
46
* ActionMailerCheck: Support :sendmail and :test

‎README.markdown‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,32 @@ end
182182
OkComputer::Registry.register "check_for_odds", MyCustomCheck.new
183183
```
184184

185+
### Grouping Checks
186+
187+
Use a `CheckCollection` to expose several related checks from one endpoint. Register
188+
the collection with `skip_all: true` when the group should not run as part of the
189+
default `/okcomputer/all` endpoint:
190+
191+
```ruby
192+
# config/initializers/okcomputer.rb
193+
versions = OkComputer::CheckCollection.new("Versions")
194+
195+
OkComputer::Registry.register "versions", versions, skip_all: true
196+
OkComputer::Registry.register "ruby_version", OkComputer::RubyVersionCheck.new, "versions"
197+
OkComputer::Registry.register "app_version", OkComputer::AppVersionCheck.new, "versions"
198+
```
199+
200+
The group is available at `/okcomputer/versions` and `/okcomputer/versions.json`.
201+
Its checks remain individually available, but neither the group nor its checks run
202+
at `/okcomputer/all`.
203+
204+
An individual check can also be omitted from `/okcomputer/all` while retaining its
205+
own endpoint:
206+
207+
```ruby
208+
OkComputer::Registry.register "ruby_version", OkComputer::RubyVersionCheck.new, skip_all: true
209+
```
210+
185211
### Registering Optional Checks
186212

187213
Register an optional check like so:

‎lib/ok_computer/check.rb‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
module OkComputer
44
class Check
55
# to be set by Registry upon registration
6-
attr_accessor :registrant_name
6+
attr_accessor :registrant_name, :skip_all
77
# nil by default, only set to true if the check deems itself failed
88
attr_accessor :failure_occurred
99
# nil by default, set by #check to control the output

‎lib/ok_computer/check_collection.rb‎

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
module OkComputer
22
class CheckCollection
3-
attr_accessor :collection, :registrant_name, :display
3+
attr_accessor :collection, :registrant_name, :display, :skip_all
44

55
# Public: Initialize a new CheckCollection
66
#
77
# display - the display name for the Check Collection
8-
def initialize(display)
8+
# exclude_skipped_checks - whether checks marked skip_all should be omitted
9+
def initialize(display, exclude_skipped_checks=false)
910
self.display = display
1011
self.collection = {}
12+
self.skip_all = false
13+
@exclude_skipped_checks = exclude_skipped_checks
1114
end
1215

1316
# Public: Run the collection's checks
@@ -37,7 +40,7 @@ def [](key)
3740
#
3841
# Returns an Array of the collection's values
3942
def checks
40-
collection.values
43+
included_collection.values
4144
end
4245

4346
def <=>(check)
@@ -51,13 +54,13 @@ def <=>(check)
5154
alias_method :values, :checks
5255

5356
def check_names
54-
collection.keys
57+
included_collection.keys
5558
end
5659

5760
alias_method :keys, :check_names
5861

5962
def sub_collections
60-
checks.select{ |c| c.is_a?(CheckCollection)}
63+
collection.values.select{ |c| c.is_a?(CheckCollection)}
6164
end
6265

6366
def self_and_sub_collections
@@ -108,6 +111,11 @@ def success?
108111

109112
private
110113

114+
def included_collection
115+
return collection unless @exclude_skipped_checks
116+
collection.reject{ |_name, check| check.respond_to?(:skip_all) && check.skip_all }
117+
end
118+
111119
def check_in_sequence
112120
checks.each(&:run)
113121
end

‎lib/ok_computer/registry.rb‎

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,35 @@ def self.all
3131
#
3232
# Returns @default_collection
3333
def self.default_collection
34-
@default_collection ||= CheckCollection.new('Default Collection')
34+
@default_collection ||= CheckCollection.new('Default Collection', true)
3535
end
3636

3737
# Public: Register the given check with OkComputer
3838
#
3939
# check_name - The name of the check to retrieve
4040
# check_object - Instance of Checker to register
4141
# collection_name - The name of the check collection the check should be registered to
42-
def self.register(check_name, check_object, collection_name=nil)
43-
find_collection(collection_name).register(check_name, check_object)
42+
# options - Set skip_all to true to omit the check from the default collection's results
43+
def self.register(check_name, check_object, collection_name=nil, options={})
44+
if collection_name.is_a?(Hash)
45+
options = collection_name
46+
collection_name = nil
47+
end
48+
49+
if collection_name && options[:skip_all]
50+
raise ArgumentError, "skip_all is only supported in the default collection"
51+
end
52+
53+
if !collection_name && options.key?(:skip_all)
54+
if check_object.respond_to?(:skip_all=)
55+
check_object.skip_all = !!options[:skip_all]
56+
elsif options[:skip_all]
57+
raise ArgumentError, "skip_all requires a check that supports skip_all="
58+
end
59+
end
60+
61+
collection = find_collection(collection_name)
62+
collection.register(check_name, check_object)
4463
end
4564

4665
# Public: Remove the check of the given name being checked

‎spec/ok_computer/check_collection_spec.rb‎

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,12 @@
22

33
module OkComputer
44
describe CheckCollection do
5-
let(:foocheck) { double(:check) }
6-
let(:barcheck) { double(:check) }
5+
let(:foocheck) { Check.new }
6+
let(:barcheck) { Check.new }
77
let(:registry) { {foo: foocheck, bar: barcheck} }
88

9-
before do
10-
allow(foocheck).to receive(:registrant_name=)
11-
allow(barcheck).to receive(:registrant_name=)
12-
end
13-
149
subject { CheckCollection.new("foo collection name") }
10+
let(:default_collection) { CheckCollection.new("foo collection name", true) }
1511

1612
context ".new" do
1713
it "sets the display name of the check collection" do
@@ -33,6 +29,15 @@ module OkComputer
3329
expect(barcheck).to receive(:run)
3430
subject.run
3531
end
32+
33+
it "does not run checks registered with skip_all" do
34+
foocheck.skip_all = true
35+
default_collection.register(:foo, foocheck)
36+
default_collection.register(:bar, barcheck)
37+
expect(foocheck).not_to receive(:run)
38+
expect(barcheck).to receive(:run)
39+
default_collection.run
40+
end
3641
end
3742
end
3843
end
@@ -43,6 +48,19 @@ module OkComputer
4348
subject.register(:bar, barcheck)
4449
expect(subject.checks).to eq(registry.values)
4550
end
51+
52+
it "omits checks registered with skip_all" do
53+
foocheck.skip_all = true
54+
default_collection.register(:foo, foocheck)
55+
default_collection.register(:bar, barcheck)
56+
expect(default_collection.checks).to eq([barcheck])
57+
end
58+
59+
it "does not omit skipped checks from a named collection" do
60+
foocheck.skip_all = true
61+
subject.register(:foo, foocheck)
62+
expect(subject.checks).to eq([foocheck])
63+
end
4664
end
4765

4866
context "#register" do
@@ -67,6 +85,12 @@ module OkComputer
6785
expect(subject.fetch(:foo)).to eq(foocheck)
6886
end
6987

88+
it "finds checks registered with skip_all" do
89+
foocheck.skip_all = true
90+
subject.register(:foo, foocheck)
91+
expect(subject.fetch(:foo)).to eq(foocheck)
92+
end
93+
7094
it "finds checks in a sub_collection" do
7195
sub_collection = CheckCollection.new("sub")
7296
subject.register("sub", sub_collection)
@@ -121,7 +145,17 @@ module OkComputer
121145
subject.register(:bar, barcheck)
122146
allow(foocheck).to receive(:to_text) { "foo" }
123147
allow(barcheck).to receive(:to_text) { "bar" }
124-
expect(subject.to_text).to eq("foo collection name\n\s\sfoo\n\s\sbar")
148+
expect(subject.to_text).to eq("foo collection name\n\s\sbar\n\s\sfoo")
149+
end
150+
151+
it "omits checks registered with skip_all" do
152+
foocheck.skip_all = true
153+
default_collection.register(:foo, foocheck)
154+
default_collection.register(:bar, barcheck)
155+
allow(foocheck).to receive(:to_text) { "foo" }
156+
allow(barcheck).to receive(:to_text) { "bar" }
157+
expect(foocheck).not_to receive(:to_text)
158+
expect(default_collection.to_text).to eq("foo collection name\n\s\sbar")
125159
end
126160
end
127161

@@ -134,6 +168,16 @@ module OkComputer
134168
combined_hash = JSON.parse(foocheck.to_json).merge(JSON.parse(barcheck.to_json))
135169
expect(subject.to_json).to eq(combined_hash.to_json)
136170
end
171+
172+
it "omits checks registered with skip_all" do
173+
foocheck.skip_all = true
174+
default_collection.register(:foo, foocheck)
175+
default_collection.register(:bar, barcheck)
176+
allow(foocheck).to receive(:to_json) { {"foo" => "foo result"}.to_json }
177+
allow(barcheck).to receive(:to_json) { {"bar" => "bar result"}.to_json }
178+
expect(foocheck).not_to receive(:to_json)
179+
expect(default_collection.to_json).to eq({"bar" => "bar result"}.to_json)
180+
end
137181
end
138182

139183
context "#success?" do
@@ -152,6 +196,15 @@ module OkComputer
152196
allow(barcheck).to receive(:success?) { false }
153197
expect(subject).not_to be_success
154198
end
199+
200+
it "ignores failures from checks registered with skip_all" do
201+
foocheck.skip_all = true
202+
default_collection.register(:foo, foocheck)
203+
default_collection.register(:bar, barcheck)
204+
allow(barcheck).to receive(:success?) { true }
205+
expect(foocheck).not_to receive(:success?)
206+
expect(default_collection).to be_success
207+
end
155208
end
156209
end
157210
end

‎spec/ok_computer/configuration_spec.rb‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,7 @@
128128
end
129129

130130
around(:each) do |example|
131-
existing = OkComputer::Registry.instance_variable_get(:@registry)
132-
example.run
133-
OkComputer::Registry.instance_variable_set(:@registry, existing)
131+
with_clean_registry { example.run }
134132
end
135133

136134
it "marks listed checks as optional" do

‎spec/ok_computer/registry_spec.rb‎

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ module OkComputer
55
let(:check_object) { double(:first_checker, :registrant_name= => nil) }
66
let(:collection) { CheckCollection.new('foo collection') }
77

8+
around do |example|
9+
with_clean_registry { example.run }
10+
end
11+
812
context ".all" do
913
it "returns a CheckCollection with all of the registered checks" do
1014
expect(Registry.all).to be_instance_of(CheckCollection)
@@ -29,12 +33,6 @@ module OkComputer
2933
let(:second_check_object) { double(:second_checker, :registrant_name= => nil) }
3034
let(:default_collection) { double }
3135

32-
after do
33-
# Clear out registered checks to avoid leaking test doubles
34-
Registry.instance_variable_defined?(:@default_collection) &&
35-
Registry.remove_instance_variable(:@default_collection)
36-
end
37-
3836
it "assigns the given name to the check" do
3937
expect(check_object).to receive(:registrant_name=).with(check_name)
4038
Registry.register(check_name, check_object)
@@ -62,6 +60,37 @@ module OkComputer
6260
Registry.register(check_name, check_object)
6361
end
6462

63+
it "keeps a check fetchable when skip_all is true" do
64+
skipped_check = Check.new
65+
Registry.register(check_name, skipped_check, skip_all: true)
66+
expect(Registry.fetch(check_name)).to eq(skipped_check)
67+
expect(Registry.all.checks).not_to include(skipped_check)
68+
end
69+
70+
it "preserves skip_all when a check is registered again without the option" do
71+
skipped_check = Check.new
72+
Registry.register(check_name, skipped_check, skip_all: true)
73+
Registry.register(check_name, skipped_check)
74+
expect(Registry.all.checks).not_to include(skipped_check)
75+
end
76+
77+
it "clears skip_all when a check is registered again with skip_all false" do
78+
skipped_check = Check.new
79+
Registry.register(check_name, skipped_check, skip_all: true)
80+
Registry.register(check_name, skipped_check, skip_all: false)
81+
expect(Registry.all.checks).to include(skipped_check)
82+
end
83+
84+
it "preserves skip_all when making a check optional" do
85+
skipped_check = Check.new
86+
Registry.register(check_name, skipped_check, skip_all: true)
87+
OkComputer.make_optional [check_name]
88+
89+
optional_check = Registry.fetch(check_name)
90+
expect(optional_check).to be_a(OkComputer::OptionalCheck)
91+
expect(Registry.all.checks).not_to include(optional_check)
92+
end
93+
6594
it "throws a collection not found error if a collection with the given name is not found" do
6695
expect { Registry.register(check_name, check_object, "missing collection") }.to raise_error(Registry::CollectionNotFound)
6796
end
@@ -73,6 +102,23 @@ module OkComputer
73102
expect(collection.fetch(check_name)).to eq(check_object)
74103
end
75104

105+
it "can omit a check collection and its checks from all" do
106+
collection = CheckCollection.new('Versions')
107+
Registry.register('versions', collection, skip_all: true)
108+
Registry.register(check_name, check_object, 'versions')
109+
110+
expect(Registry.fetch('versions')).to eq(collection)
111+
expect(Registry.fetch(check_name)).to eq(check_object)
112+
expect(Registry.all.checks).not_to include(collection)
113+
end
114+
115+
it "rejects skip_all when registering inside a check collection" do
116+
Registry.register('test_collection', collection)
117+
expect {
118+
Registry.register(check_name, check_object, 'test_collection', skip_all: true)
119+
}.to raise_error(ArgumentError, /default collection/)
120+
end
121+
76122
it "gracefully handles checks defined with a combination of strings and symbols as their name" do
77123
Registry.register("foo", Check.new)
78124
Registry.register(:bar, Check.new)

‎spec/support/helpers.rb‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,16 @@ def with_env(env)
1212

1313
ENV.replace(original)
1414
end
15+
16+
def with_clean_registry
17+
registry = OkComputer::Registry
18+
default_collection_defined = registry.instance_variable_defined?(:@default_collection)
19+
default_collection = registry.instance_variable_get(:@default_collection)
20+
registry.remove_instance_variable(:@default_collection) if default_collection_defined
21+
22+
yield
23+
ensure
24+
registry.remove_instance_variable(:@default_collection) if registry.instance_variable_defined?(:@default_collection)
25+
registry.instance_variable_set(:@default_collection, default_collection) if default_collection_defined
26+
end
1527
end

0 commit comments

Comments
 (0)