outpost 0.2.0 → 0.2.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.
- data/CHANGELOG.rdoc +8 -0
- data/Gemfile.lock +1 -1
- data/README.markdown +27 -2
- data/TODO.md +0 -2
- data/lib/outpost/application.rb +81 -36
- data/lib/outpost/expectations/response_code.rb +5 -1
- data/lib/outpost/report.rb +3 -1
- data/lib/outpost/scout.rb +70 -11
- data/lib/outpost/scout_config.rb +2 -5
- data/lib/outpost/scouts/http.rb +6 -2
- data/lib/outpost/scouts/ping.rb +1 -1
- data/lib/outpost/version.rb +1 -1
- data/outpost.gemspec +4 -4
- data/test/integration/basic_application_test.rb +23 -4
- data/test/integration/more_complex_test.rb +30 -4
- data/test/integration/no_subclassing_test.rb +54 -0
- data/test/integration/reporting_test.rb +40 -0
- data/test/outpost/{dsl_test.rb → application_test.rb} +68 -2
- data/test/outpost/expectations/response_code_test.rb +8 -0
- data/test/outpost/report_test.rb +12 -0
- data/test/outpost/scout_test.rb +63 -0
- data/test/outpost/scouts/http_test.rb +8 -0
- data/test/outpost/scouts/ping_test.rb +8 -0
- data/test/support/server.rb +6 -0
- data/test/support/test_app.rb +4 -0
- metadata +26 -41
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
== 0.2.1
|
2
|
+
* Features
|
3
|
+
* Support for :warning status (by github.com/sryche)
|
4
|
+
* Subclassing Outpost::Application is no longer required.
|
5
|
+
* HTTP Scout responds to response_time now
|
6
|
+
* Added scout data to the report (so you can read acquired data)
|
7
|
+
* Support for creating scouts without any expectations (good if you're
|
8
|
+
interested in the data value but not if they mean system is either up or down)
|
1
9
|
|
2
10
|
== 0.2
|
3
11
|
* Features
|
data/Gemfile.lock
CHANGED
data/README.markdown
CHANGED
@@ -73,7 +73,7 @@ reporting "down" in that case).
|
|
73
73
|
|
74
74
|
## Outpost
|
75
75
|
|
76
|
-
Outpost is the description of the system and provides a DSL to do it.
|
76
|
+
Outpost is the description of the system and provides a DSL to do it.
|
77
77
|
Check "How it works" section for an example, or check the [integration tests](https://github.com/vinibaggio/outpost/blob/master/test/integration/basic_application_test.rb)
|
78
78
|
for more.
|
79
79
|
|
@@ -110,6 +110,14 @@ method, where you can implement any kind of logic to test whether your system is
|
|
110
110
|
or not. You may also include expectations in order to process the output of your system.
|
111
111
|
For more information about expectations, check the section below.
|
112
112
|
|
113
|
+
If you're interested in the data the Scouts got through a measurement, you can
|
114
|
+
tell Outpost that it must save that data after the measurement is run. That way
|
115
|
+
you can inquiry it for further analysis. This way, you can have Scouts without
|
116
|
+
any expectations/reports, so you can collect data without telling if the system
|
117
|
+
is either up or down. You can check an usage example in the [Reports
|
118
|
+
integration
|
119
|
+
test](https://github.com/vinibaggio/outpost/blob/master/test/integration/reporting_test.rb).
|
120
|
+
|
113
121
|
## Expectations
|
114
122
|
|
115
123
|
Consider the following code snippet, taken from previous examples:
|
@@ -123,7 +131,7 @@ to get Scout's output and evaluate it, in order to determine a status.
|
|
123
131
|
They must be registered into each Scout that wish to support different types
|
124
132
|
of expectations. You can supply a block or an object that respond to #call
|
125
133
|
and return true if any of the rules match. It will receive an instance
|
126
|
-
of the scout (so you can query current system state) as the first parameter
|
134
|
+
of the scout (so you can query current system state) as the first parameter
|
127
135
|
and the state defined in the #report method as the second.
|
128
136
|
|
129
137
|
So you can easily create your own expectation. Let's recreate the :response\_code in
|
@@ -182,6 +190,23 @@ system administrator:
|
|
182
190
|
# down.
|
183
191
|
outpost.notify if outpost.down?
|
184
192
|
|
193
|
+
## Creating Outpost applications programatically
|
194
|
+
|
195
|
+
It is also possible to create Outposts without having to subclass it. Use the
|
196
|
+
methods #add_scout and #add_notifier and you're set:
|
197
|
+
|
198
|
+
outpost = Outpost::Application.new
|
199
|
+
|
200
|
+
outpost.add_scout Outpost::Scouts::Http => 'master http server' do
|
201
|
+
options :host => 'localhost', :port => 9595
|
202
|
+
report :up, :response_code => 200
|
203
|
+
end
|
204
|
+
|
205
|
+
outpost.run
|
206
|
+
|
207
|
+
This is good when you want to have some sort of template (by inheriting from
|
208
|
+
Outpost::Application) and then configure things as you go.
|
209
|
+
|
185
210
|
## TODO
|
186
211
|
|
187
212
|
See [TODO](https://github.com/vinibaggio/outpost/blob/master/TODO.md).
|
data/TODO.md
CHANGED
data/lib/outpost/application.rb
CHANGED
@@ -11,14 +11,31 @@ module Outpost
|
|
11
11
|
# end
|
12
12
|
# end
|
13
13
|
#
|
14
|
-
#
|
14
|
+
# The above example will set templates and every new instance of
|
15
|
+
# ExampleSuccess will have the same behavior. But all the methods
|
16
|
+
# are available to instances, so it is also possible to create Outpost
|
17
|
+
# applications as the following example:
|
18
|
+
#
|
19
|
+
# my_outpost = Outpost::Application.new
|
20
|
+
# my_outpost.name = 'Example'
|
21
|
+
#
|
22
|
+
# my_outpost.using(Outpost::Scouts::Http => 'master http server') do
|
23
|
+
# options :host => 'localhost', :port => 9595
|
24
|
+
# report :up, :response_code => 200
|
25
|
+
# end
|
15
26
|
class Application
|
16
27
|
class << self
|
17
|
-
|
18
|
-
|
28
|
+
def scout_templates
|
29
|
+
@scout_templates || []
|
30
|
+
end
|
19
31
|
|
20
|
-
|
21
|
-
|
32
|
+
def notifier_templates
|
33
|
+
@notifier_templates || []
|
34
|
+
end
|
35
|
+
|
36
|
+
def name_template
|
37
|
+
@name_template || self.to_s
|
38
|
+
end
|
22
39
|
|
23
40
|
# Register a scout in the list of scouts.
|
24
41
|
#
|
@@ -27,15 +44,11 @@ module Outpost
|
|
27
44
|
#
|
28
45
|
# @yield Block to be evaluated to configure the current {Scout}.
|
29
46
|
def using(scout_description, &block)
|
30
|
-
@
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
scout_description.each do |scout, description|
|
36
|
-
@scouts[scout][:description] = description
|
37
|
-
@scouts[scout][:config] = config
|
38
|
-
end
|
47
|
+
@scout_templates ||= []
|
48
|
+
@scout_templates << {
|
49
|
+
:scout_description => scout_description,
|
50
|
+
:block => block
|
51
|
+
}
|
39
52
|
end
|
40
53
|
|
41
54
|
# Register a notifier class in the list of notifications.
|
@@ -48,8 +61,8 @@ module Outpost
|
|
48
61
|
# @param [Hash, #read] options Options that will be used to configure the
|
49
62
|
# notification class.
|
50
63
|
def notify(notifier, options={})
|
51
|
-
@
|
52
|
-
@
|
64
|
+
@notifier_templates ||= []
|
65
|
+
@notifier_templates << {:notifier => notifier, :options => options}
|
53
66
|
end
|
54
67
|
|
55
68
|
# Set the name of the scout. Can be used by notifiers in order to have
|
@@ -58,11 +71,8 @@ module Outpost
|
|
58
71
|
# @param [String, #read] name The name to be given to a Outpost-based
|
59
72
|
# class.
|
60
73
|
def name(val=nil)
|
61
|
-
if val
|
62
|
-
|
63
|
-
else
|
64
|
-
@name
|
65
|
-
end
|
74
|
+
@name_template = val if val
|
75
|
+
@name_template
|
66
76
|
end
|
67
77
|
end
|
68
78
|
|
@@ -72,20 +82,57 @@ module Outpost
|
|
72
82
|
# Returns a list of {Report} containing the last results of the last check.
|
73
83
|
attr_reader :reports
|
74
84
|
|
85
|
+
# Returns all the registered scouts.
|
86
|
+
attr_reader :scouts
|
87
|
+
|
88
|
+
# Returns all the registered notifiers.
|
89
|
+
attr_reader :notifiers
|
90
|
+
|
91
|
+
# Reader/setter for the name of this scout
|
92
|
+
attr_accessor :name
|
93
|
+
|
75
94
|
# New instance of a Outpost-based class.
|
76
95
|
def initialize
|
77
|
-
@reports =
|
96
|
+
@reports = {}
|
78
97
|
@last_status = nil
|
98
|
+
@scouts = Hash.new { |h, k| h[k] = {} }
|
99
|
+
@notifiers = {}
|
100
|
+
@name = self.class.name_template
|
101
|
+
|
102
|
+
# Register scouts
|
103
|
+
self.class.scout_templates.each do |template|
|
104
|
+
add_scout(template[:scout_description], &template[:block])
|
105
|
+
end
|
106
|
+
|
107
|
+
self.class.notifier_templates.each do |template|
|
108
|
+
add_notifier(template[:notifier], template[:options])
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# @see Application#using
|
113
|
+
def add_scout(scout_description, &block)
|
114
|
+
config = ScoutConfig.new
|
115
|
+
config.instance_eval(&block)
|
116
|
+
|
117
|
+
scout_description.each do |scout, description|
|
118
|
+
@scouts[scout][:description] = description
|
119
|
+
@scouts[scout][:config] = config
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# @see Application#notify
|
124
|
+
def add_notifier(notifier_name, options)
|
125
|
+
@notifiers[notifier_name] = options
|
79
126
|
end
|
80
127
|
|
81
128
|
# Execute all the scouts associated with an Outpost-based class and returns
|
82
129
|
# either :up or :down, depending on the results.
|
83
130
|
def run
|
84
|
-
|
85
|
-
run_scout(scout, options)
|
131
|
+
scouts.map do |scout, options|
|
132
|
+
@reports[options[:description]] = run_scout(scout, options)
|
86
133
|
end
|
87
134
|
|
88
|
-
statuses = @reports.map { |r| r.status }
|
135
|
+
statuses = @reports.map { |_, r| r.status }
|
89
136
|
|
90
137
|
@last_status = Report.summarize(statuses)
|
91
138
|
end
|
@@ -93,7 +140,7 @@ module Outpost
|
|
93
140
|
# Runs all notifications associated with an Outpost-based class.
|
94
141
|
def notify
|
95
142
|
if reports.any?
|
96
|
-
|
143
|
+
@notifiers.each do |notifier, options|
|
97
144
|
# .dup is NOT reliable
|
98
145
|
options_copy = Marshal.load(Marshal.dump(options))
|
99
146
|
notifier.new(options_copy).notify(self)
|
@@ -106,24 +153,21 @@ module Outpost
|
|
106
153
|
@last_status == :up
|
107
154
|
end
|
108
155
|
|
156
|
+
# Returns true if the last status is :warning
|
157
|
+
def warning?
|
158
|
+
@last_status == :warning
|
159
|
+
end
|
160
|
+
|
109
161
|
# Returns true if the last status is :down
|
110
162
|
def down?
|
111
163
|
@last_status == :down
|
112
164
|
end
|
113
165
|
|
114
|
-
# Returns the name of an Outpost-based class or the class name itself if
|
115
|
-
# not set.
|
116
|
-
#
|
117
|
-
# @return [String] The name of the Outpost
|
118
|
-
def name
|
119
|
-
self.class.name || self.class.to_s
|
120
|
-
end
|
121
|
-
|
122
166
|
# Returns the messages of the latest service check.
|
123
167
|
#
|
124
168
|
# @return [Array<String>] An array containing all report messages.
|
125
169
|
def messages
|
126
|
-
reports.map { |r| r.to_s }
|
170
|
+
reports.map { |_, r| r.to_s }
|
127
171
|
end
|
128
172
|
|
129
173
|
private
|
@@ -135,7 +179,8 @@ module Outpost
|
|
135
179
|
params = {
|
136
180
|
:name => scout.name,
|
137
181
|
:description => options[:description],
|
138
|
-
:status => scout_instance.run
|
182
|
+
:status => scout_instance.run,
|
183
|
+
:data => scout_instance.report_data
|
139
184
|
}
|
140
185
|
Report.new(params)
|
141
186
|
end
|
@@ -11,7 +11,11 @@ module Outpost
|
|
11
11
|
|
12
12
|
# Method that will be used as an expectation to evaluate response code
|
13
13
|
def evaluate_response_code(scout, response_code)
|
14
|
-
|
14
|
+
if response_code.is_a?(Array)
|
15
|
+
response_code.include?(scout.response_code)
|
16
|
+
else
|
17
|
+
scout.response_code == response_code.to_i
|
18
|
+
end
|
15
19
|
end
|
16
20
|
end
|
17
21
|
end
|
data/lib/outpost/report.rb
CHANGED
@@ -16,15 +16,17 @@ module Outpost
|
|
16
16
|
# @return [Symbol] the final status to be considered.
|
17
17
|
def self.summarize(status_list)
|
18
18
|
return :down if status_list.empty? || status_list.include?(:down)
|
19
|
+
return :warning if status_list.include?(:warning)
|
19
20
|
return :up
|
20
21
|
end
|
21
22
|
|
22
|
-
attr_reader :name, :description, :status
|
23
|
+
attr_reader :name, :description, :status, :data
|
23
24
|
|
24
25
|
def initialize(params)
|
25
26
|
@name = params[:name]
|
26
27
|
@description = params[:description]
|
27
28
|
@status = params[:status]
|
29
|
+
@data = params[:data]
|
28
30
|
end
|
29
31
|
|
30
32
|
def to_s
|
data/lib/outpost/scout.rb
CHANGED
@@ -18,6 +18,11 @@ module Outpost
|
|
18
18
|
# scout.response_code == code
|
19
19
|
# end
|
20
20
|
#
|
21
|
+
# Scouts may also report specific data. This is useful to complement
|
22
|
+
# status reporting with the data received from the measurement. After the
|
23
|
+
# scout is run, each report data method will be executed and its calue will be
|
24
|
+
# added to the resulting report.
|
25
|
+
#
|
21
26
|
# @example an example of a Scout that parses the HTTP response code
|
22
27
|
# module Outpost
|
23
28
|
# module Scouts
|
@@ -40,10 +45,40 @@ module Outpost
|
|
40
45
|
# end
|
41
46
|
# end
|
42
47
|
#
|
48
|
+
# @example an example of a Scout that reports the duration of a HTTP request
|
49
|
+
# module Outpost
|
50
|
+
# module Scouts
|
51
|
+
# class TimedHttp < Outpost::Scout
|
52
|
+
# expect(:response_code) { |scout,code| scout.response_code == code }
|
53
|
+
#
|
54
|
+
# attr_reader :response_code, :response_time
|
55
|
+
# report_data :response_time
|
56
|
+
#
|
57
|
+
# def setup(options)
|
58
|
+
# @host = options[:host]
|
59
|
+
# @port = options[:port] || 80
|
60
|
+
# @path = options[:path] || '/'
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# def execute
|
64
|
+
# previous_time = Time.now
|
65
|
+
#
|
66
|
+
# response = Net::HTTP.get_response(@host, @path, @port)
|
67
|
+
# @response_code = response.code.to_i
|
68
|
+
#
|
69
|
+
# @response_time = Time.now - response_time
|
70
|
+
# end
|
71
|
+
# end
|
72
|
+
# end
|
73
|
+
# end
|
74
|
+
#
|
43
75
|
# @abstract Subclasses must override {#setup} and {#execute} to be a valid
|
44
76
|
# Scout
|
45
77
|
class Scout
|
78
|
+
attr_reader :report_data
|
79
|
+
|
46
80
|
class << self
|
81
|
+
attr_reader :reporting_data_methods
|
47
82
|
|
48
83
|
# Returns the hash of expectations, where the key is the name of the
|
49
84
|
# expectation and the value is the callable Object (object that responds
|
@@ -51,7 +86,7 @@ module Outpost
|
|
51
86
|
#
|
52
87
|
# @return [Hash<Symbol, Object>]
|
53
88
|
def expectations
|
54
|
-
@expectations ? @expectations.dup :
|
89
|
+
@expectations ? @expectations.dup : {}
|
55
90
|
end
|
56
91
|
|
57
92
|
# Registers a new expectation into the Scout. If the callable does not
|
@@ -74,6 +109,16 @@ module Outpost
|
|
74
109
|
raise ArgumentError, 'Object must respond to method #call to be a valid expectation.'
|
75
110
|
end
|
76
111
|
end
|
112
|
+
|
113
|
+
def reporting_data_methods
|
114
|
+
@reporting_data_methods ||= []
|
115
|
+
@reporting_data_methods
|
116
|
+
end
|
117
|
+
|
118
|
+
def report_data(*methods)
|
119
|
+
@reporting_data_methods ||= []
|
120
|
+
@reporting_data_methods += methods
|
121
|
+
end
|
77
122
|
end
|
78
123
|
|
79
124
|
# @param [String, #read] description A string containing a description of
|
@@ -83,6 +128,7 @@ module Outpost
|
|
83
128
|
def initialize(description, config)
|
84
129
|
@description = description
|
85
130
|
@config = config
|
131
|
+
@report_data = {}
|
86
132
|
|
87
133
|
setup(config.options)
|
88
134
|
end
|
@@ -90,7 +136,7 @@ module Outpost
|
|
90
136
|
# Executes the Scout and go through all the registered expectations to find
|
91
137
|
# out all expectations that match and return the associated status.
|
92
138
|
#
|
93
|
-
# @return [Symbol] the current status of the Scout (:up, :down)
|
139
|
+
# @return [Symbol] the current status of the Scout (:up, :down, :warning)
|
94
140
|
# @raise [NotImplementedError] raised when a configured expectation was not
|
95
141
|
# registered in the Scout.
|
96
142
|
def run
|
@@ -100,24 +146,37 @@ module Outpost
|
|
100
146
|
# value.
|
101
147
|
# Example: {:response_time => 200}
|
102
148
|
#
|
103
|
-
# status is the status (:up or :
|
149
|
+
# status is the status (:up, :down or :warning, for example) that will be returned
|
104
150
|
# in case the expectation match current system status.
|
105
|
-
@config.reports.
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
151
|
+
if @config.reports.present?
|
152
|
+
@config.reports.each do |response_pair, status|
|
153
|
+
response_pair.each do |expectation, value|
|
154
|
+
if self.class.expectations[expectation].nil?
|
155
|
+
message = "expectation '#{expectation}' wasn't implemented by #{self.class.name}"
|
156
|
+
raise NotImplementedError, message
|
157
|
+
end
|
111
158
|
|
112
|
-
|
113
|
-
|
159
|
+
if self.class.expectations[expectation].call(self, value)
|
160
|
+
statuses << status
|
161
|
+
end
|
114
162
|
end
|
115
163
|
end
|
116
164
|
end
|
117
165
|
|
166
|
+
gather_reporting_data
|
118
167
|
Report.summarize(statuses)
|
119
168
|
end
|
120
169
|
|
170
|
+
def gather_reporting_data
|
171
|
+
self.class.reporting_data_methods.each do |method|
|
172
|
+
if respond_to?(method)
|
173
|
+
@report_data[method.to_sym] = send(method)
|
174
|
+
else
|
175
|
+
raise ArgumentError, "Scout #{self.class.name} does not respond to ##{method} reporting data method"
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
121
180
|
# Called when the scout object is being constructed. Arguments can be
|
122
181
|
# everything the developer set in the creation of Outpost.
|
123
182
|
#
|
data/lib/outpost/scout_config.rb
CHANGED
@@ -12,11 +12,8 @@ module Outpost
|
|
12
12
|
# @param [Object] args Any argument that will be passed to the Scout.
|
13
13
|
# Rreturn [Object] The associated option
|
14
14
|
def options(args=nil)
|
15
|
-
if args
|
16
|
-
|
17
|
-
else
|
18
|
-
@options = args
|
19
|
-
end
|
15
|
+
@options = args if args
|
16
|
+
@options
|
20
17
|
end
|
21
18
|
|
22
19
|
# Reads reporting as:
|
data/lib/outpost/scouts/http.rb
CHANGED
@@ -16,8 +16,10 @@ module Outpost
|
|
16
16
|
class Http < Outpost::Scout
|
17
17
|
extend Outpost::Expectations::ResponseCode
|
18
18
|
extend Outpost::Expectations::ResponseBody
|
19
|
+
extend Outpost::Expectations::ResponseTime
|
19
20
|
|
20
|
-
attr_reader :response_code, :response_body
|
21
|
+
attr_reader :response_code, :response_body, :response_time
|
22
|
+
report_data :response_code, :response_body, :response_time
|
21
23
|
|
22
24
|
# Configure the scout with given options.
|
23
25
|
# @param [Hash] Options to setup the scout
|
@@ -37,12 +39,14 @@ module Outpost
|
|
37
39
|
# Runs the scout, connecting to the host and getting the response code,
|
38
40
|
# body and time.
|
39
41
|
def execute
|
42
|
+
previous_time = Time.now
|
40
43
|
response = @http_class.get_response(@host, @path, @port)
|
41
44
|
|
45
|
+
@response_time = (Time.now - previous_time) * 1000 # Miliseconds
|
42
46
|
@response_code = response.code.to_i
|
43
47
|
@response_body = response.body
|
44
48
|
rescue SocketError, Errno::ECONNREFUSED
|
45
|
-
@response_code = @response_body = nil
|
49
|
+
@response_code = @response_body = @response_time = nil
|
46
50
|
end
|
47
51
|
end
|
48
52
|
end
|
data/lib/outpost/scouts/ping.rb
CHANGED
data/lib/outpost/version.rb
CHANGED
data/outpost.gemspec
CHANGED
@@ -12,8 +12,8 @@ Gem::Specification.new do |s|
|
|
12
12
|
|
13
13
|
s.rubyforge_project = "outpost"
|
14
14
|
|
15
|
-
s.files = `git ls-files`.split("\n")
|
16
|
-
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
|
-
s.require_paths = ["lib"]
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
|
+
s.require_paths = ["lib"]
|
19
19
|
end
|
@@ -6,10 +6,7 @@ describe "basic application integration test" do
|
|
6
6
|
before(:each) do
|
7
7
|
@server = Server.new
|
8
8
|
@server.boot(TestApp)
|
9
|
-
|
10
|
-
while !@server.responsive?
|
11
|
-
sleep 0.1
|
12
|
-
end
|
9
|
+
@server.wait_until_booted
|
13
10
|
end
|
14
11
|
|
15
12
|
class ExampleSuccess < Outpost::Application
|
@@ -19,6 +16,13 @@ describe "basic application integration test" do
|
|
19
16
|
end
|
20
17
|
end
|
21
18
|
|
19
|
+
class ExampleWarning < Outpost::Application
|
20
|
+
using Outpost::Scouts::Http => 'master http server' do
|
21
|
+
options :host => 'localhost', :port => 9595, :path => '/warning'
|
22
|
+
report :warning, :response_code => 402
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
22
26
|
class ExampleFailure < Outpost::Application
|
23
27
|
using Outpost::Scouts::Http => 'master http server' do
|
24
28
|
options :host => 'localhost', :port => 9595, :path => '/fail'
|
@@ -40,10 +44,21 @@ describe "basic application integration test" do
|
|
40
44
|
end
|
41
45
|
end
|
42
46
|
|
47
|
+
class ExampleBodyWarning < Outpost::Application
|
48
|
+
using Outpost::Scouts::Http => 'master http server' do
|
49
|
+
options :host => 'localhost', :port => 9595, :path => '/warning'
|
50
|
+
report :warning, :response_body => {:equals => 'Omg need payment'}
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
43
54
|
it "should report up when everything's ok" do
|
44
55
|
assert_equal :up, ExampleSuccess.new.run
|
45
56
|
end
|
46
57
|
|
58
|
+
it "should report warning when there's a warning" do
|
59
|
+
assert_equal :warning, ExampleWarning.new.run
|
60
|
+
end
|
61
|
+
|
47
62
|
it "should report failure when something's wrong" do
|
48
63
|
assert_equal :down, ExampleFailure.new.run
|
49
64
|
end
|
@@ -52,6 +67,10 @@ describe "basic application integration test" do
|
|
52
67
|
assert_equal :up, ExampleBodySuccess.new.run
|
53
68
|
end
|
54
69
|
|
70
|
+
it "should report success when body have a warning" do
|
71
|
+
assert_equal :warning, ExampleBodyWarning.new.run
|
72
|
+
end
|
73
|
+
|
55
74
|
it "should report failure when body is wrong" do
|
56
75
|
assert_equal :down, ExampleBodyFailure.new.run
|
57
76
|
end
|
@@ -6,10 +6,7 @@ describe "using more complex application integration test" do
|
|
6
6
|
before(:each) do
|
7
7
|
@server = Server.new
|
8
8
|
@server.boot(TestApp)
|
9
|
-
|
10
|
-
while !@server.responsive?
|
11
|
-
sleep 0.1
|
12
|
-
end
|
9
|
+
@server.wait_until_booted
|
13
10
|
end
|
14
11
|
|
15
12
|
class ExamplePingAndHttp < Outpost::Application
|
@@ -36,6 +33,30 @@ describe "using more complex application integration test" do
|
|
36
33
|
end
|
37
34
|
end
|
38
35
|
|
36
|
+
class ExampleOneWarningOnePassing < Outpost::Application
|
37
|
+
using Outpost::Scouts::Http => 'master http server' do
|
38
|
+
options :host => 'localhost', :port => 9595, :path => '/'
|
39
|
+
report :up, :response_body => {:match => /Up/}
|
40
|
+
end
|
41
|
+
|
42
|
+
using Outpost::Scouts::Http => 'master http server' do
|
43
|
+
options :host => 'localhost', :port => 9595, :path => '/warning'
|
44
|
+
report :warning, :response_code => 402
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class ExampleOneWarningOneFailing < Outpost::Application
|
49
|
+
using Outpost::Scouts::Http => 'master http server' do
|
50
|
+
options :host => 'localhost', :port => 9595, :path => '/warning'
|
51
|
+
report :warning, :response_code => 402
|
52
|
+
end
|
53
|
+
|
54
|
+
using Outpost::Scouts::Ping => 'load balancer' do
|
55
|
+
options :host => 'localhost'
|
56
|
+
report :up, :response_time => {:less_than => 0}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
39
60
|
class ExampleAllFailing < Outpost::Application
|
40
61
|
using Outpost::Scouts::Http => 'master http server' do
|
41
62
|
options :host => 'localhost', :port => 9595, :path => '/fail'
|
@@ -52,8 +73,13 @@ describe "using more complex application integration test" do
|
|
52
73
|
assert_equal :up, ExamplePingAndHttp.new.run
|
53
74
|
end
|
54
75
|
|
76
|
+
it "should report warning when at least one scout reports warning" do
|
77
|
+
assert_equal :warning, ExampleOneWarningOnePassing.new.run
|
78
|
+
end
|
79
|
+
|
55
80
|
it "should report down when at least one scout reports down" do
|
56
81
|
assert_equal :down, ExampleOneFailingOnePassing.new.run
|
82
|
+
assert_equal :down, ExampleOneWarningOneFailing.new.run
|
57
83
|
end
|
58
84
|
|
59
85
|
it "should report down when all are down" do
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'outpost/scouts/http'
|
4
|
+
require 'outpost/notifiers/email'
|
5
|
+
|
6
|
+
describe "creating outpost apps without subclassing" do
|
7
|
+
before(:each) do
|
8
|
+
@server = Server.new
|
9
|
+
@server.boot(TestApp)
|
10
|
+
@server.wait_until_booted
|
11
|
+
|
12
|
+
Mail.defaults do
|
13
|
+
delivery_method :test
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
after(:each) do
|
18
|
+
Mail::TestMailer.deliveries = []
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should report up when everything's ok" do
|
22
|
+
assert_equal :up, outpost.run
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should notify up when everything's ok" do
|
26
|
+
outpost.add_notifier Outpost::Notifiers::Email, {
|
27
|
+
:from => 'outpost@example.com',
|
28
|
+
:to => 'sleep_deprived_admin@example.com',
|
29
|
+
:subject => 'System 1 status'
|
30
|
+
}
|
31
|
+
|
32
|
+
outpost.run
|
33
|
+
outpost.notify
|
34
|
+
|
35
|
+
refute_empty Mail::TestMailer.deliveries
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should not notify when there are no notifiers" do
|
39
|
+
outpost.run
|
40
|
+
|
41
|
+
assert_empty Mail::TestMailer.deliveries
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def outpost
|
47
|
+
@outpost ||= Outpost::Application.new.tap do |outpost|
|
48
|
+
outpost.add_scout Outpost::Scouts::Http => 'master http server' do
|
49
|
+
options :host => 'localhost', :port => 9595
|
50
|
+
report :up, :response_code => 200
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'outpost/scouts'
|
4
|
+
|
5
|
+
describe "using only report data integration test" do
|
6
|
+
class RetrieveServerData < Outpost::Application
|
7
|
+
using Outpost::Scouts::Http => 'master http server' do
|
8
|
+
options :host => 'localhost', :port => 9595, :path => '/'
|
9
|
+
end
|
10
|
+
|
11
|
+
using Outpost::Scouts::Ping => :load_balancer do
|
12
|
+
options :host => 'localhost'
|
13
|
+
report :up, :response_time => {:less_than => 500}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
before(:each) do
|
18
|
+
@server = Server.new
|
19
|
+
@server.boot(TestApp)
|
20
|
+
@server.wait_until_booted
|
21
|
+
|
22
|
+
@outpost = RetrieveServerData.new
|
23
|
+
@outpost.run
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should build report for each scout" do
|
27
|
+
assert_equal 2, @outpost.reports.size
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should build reports with data" do
|
31
|
+
http_report = @outpost.reports['master http server']
|
32
|
+
ping_report = @outpost.reports[:load_balancer]
|
33
|
+
|
34
|
+
report_data = http_report.data
|
35
|
+
|
36
|
+
assert report_data.delete(:response_time) < 500
|
37
|
+
assert_equal({:response_code => 200,
|
38
|
+
:response_body => 'Up and running!'}, http_report.data)
|
39
|
+
end
|
40
|
+
end
|
@@ -5,8 +5,10 @@ describe Outpost::Application do
|
|
5
5
|
class << self
|
6
6
|
attr_accessor :status
|
7
7
|
end
|
8
|
+
|
8
9
|
def initialize(*args); end
|
9
10
|
def run ; self.class.status ; end
|
11
|
+
def report_data; ; {} ; end
|
10
12
|
end
|
11
13
|
|
12
14
|
class NotifierMock
|
@@ -32,7 +34,7 @@ describe Outpost::Application do
|
|
32
34
|
end
|
33
35
|
|
34
36
|
before(:each) do
|
35
|
-
@scouts = ExampleOne.scouts
|
37
|
+
@scouts = ExampleOne.new.scouts
|
36
38
|
end
|
37
39
|
|
38
40
|
it "should create correct scout description" do
|
@@ -47,10 +49,37 @@ describe Outpost::Application do
|
|
47
49
|
end
|
48
50
|
|
49
51
|
it "should create notifiers configuration" do
|
50
|
-
notifiers = ExampleOne.notifiers
|
52
|
+
notifiers = ExampleOne.new.notifiers
|
51
53
|
assert_equal({NotifierMock => {:email => 'mail@example.com'}}, notifiers)
|
52
54
|
end
|
53
55
|
|
56
|
+
describe "#add_scout" do
|
57
|
+
before(:each) do
|
58
|
+
ScoutMock.status = :up
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should be able to create scouts programatically" do
|
62
|
+
outpost = create_outpost
|
63
|
+
|
64
|
+
assert_equal :up, outpost.run
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "#add_notifier" do
|
69
|
+
before(:each) do
|
70
|
+
ScoutMock.status = :up
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should be able to create notifications programatically" do
|
74
|
+
outpost = create_outpost
|
75
|
+
outpost.run
|
76
|
+
outpost.notify
|
77
|
+
|
78
|
+
assert_equal "ScoutMock: 'master http server' is reporting up.",
|
79
|
+
NotifierMock.last_messages.first
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
54
83
|
describe "#run" do
|
55
84
|
it "should return up when scouts return up" do
|
56
85
|
ScoutMock.status = :up
|
@@ -84,6 +113,7 @@ describe Outpost::Application do
|
|
84
113
|
|
85
114
|
refute NotifierMock.last_messages
|
86
115
|
end
|
116
|
+
|
87
117
|
end
|
88
118
|
|
89
119
|
describe "#up?" do
|
@@ -106,6 +136,26 @@ describe Outpost::Application do
|
|
106
136
|
end
|
107
137
|
end
|
108
138
|
|
139
|
+
describe "#warning?" do
|
140
|
+
before(:each) do
|
141
|
+
@outpost = ExampleOne.new
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should return true when last status is warning" do
|
145
|
+
ScoutMock.status = :warning
|
146
|
+
@outpost.run
|
147
|
+
|
148
|
+
assert @outpost.warning?
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should return false when last status isn't warning" do
|
152
|
+
ScoutMock.status = :up
|
153
|
+
@outpost.run
|
154
|
+
|
155
|
+
refute @outpost.warning?
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
109
159
|
describe "#down?" do
|
110
160
|
before(:each) do
|
111
161
|
@outpost = ExampleOne.new
|
@@ -154,4 +204,20 @@ describe Outpost::Application do
|
|
154
204
|
@outpost.messages.first
|
155
205
|
end
|
156
206
|
end
|
207
|
+
|
208
|
+
describe "#reports" do
|
209
|
+
|
210
|
+
end
|
211
|
+
|
212
|
+
private
|
213
|
+
|
214
|
+
def create_outpost
|
215
|
+
Outpost::Application.new.tap do |outpost|
|
216
|
+
outpost.add_scout ScoutMock => 'master http server' do
|
217
|
+
report :up, :response_code => 200
|
218
|
+
end
|
219
|
+
|
220
|
+
outpost.add_notifier NotifierMock, :email => 'mail@example.com'
|
221
|
+
end
|
222
|
+
end
|
157
223
|
end
|
@@ -36,6 +36,14 @@ describe Outpost::Expectations::ResponseCode do
|
|
36
36
|
SubjectCode.evaluation_method
|
37
37
|
end
|
38
38
|
|
39
|
+
it "should return true when response code is included in the list" do
|
40
|
+
assert SubjectCode.evaluate_response_code(scout_stub, [200, 301])
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should refute when response code is not included in the list" do
|
44
|
+
refute SubjectCode.evaluate_response_code(scout_stub, [500, 503])
|
45
|
+
end
|
46
|
+
|
39
47
|
private
|
40
48
|
def scout_stub
|
41
49
|
build_stub(:response_code => 200)
|
data/test/outpost/report_test.rb
CHANGED
@@ -16,4 +16,16 @@ describe Outpost::Report do
|
|
16
16
|
it "should report down when there are no statuses" do
|
17
17
|
assert_equal :down, Outpost::Report.summarize([])
|
18
18
|
end
|
19
|
+
|
20
|
+
it "should report warning when all are warning" do
|
21
|
+
assert_equal :warning, Outpost::Report.summarize([:warning, :warning])
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should report warning when mixed up and warning" do
|
25
|
+
assert_equal :warning, Outpost::Report.summarize([:warning, :up, :up])
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should report down when mixed down and warning" do
|
29
|
+
assert_equal :down, Outpost::Report.summarize([:warning, :down, :up])
|
30
|
+
end
|
19
31
|
end
|
data/test/outpost/scout_test.rb
CHANGED
@@ -11,6 +11,39 @@ describe Outpost::Scout do
|
|
11
11
|
def execute(*args); end
|
12
12
|
end
|
13
13
|
|
14
|
+
class ReportingScoutExample < Outpost::Scout
|
15
|
+
attr_accessor :response
|
16
|
+
report_data :translated_response_code
|
17
|
+
expect :response, lambda {|scout, status| scout.response == status }
|
18
|
+
|
19
|
+
def setup(*args); end
|
20
|
+
def execute(*args); end
|
21
|
+
|
22
|
+
def translated_response_code
|
23
|
+
"Page Not Found"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class BrokenScoutExample < Outpost::Scout
|
28
|
+
attr_accessor :response
|
29
|
+
report_data :reportive
|
30
|
+
expect :response, lambda {|scout, status| scout.response == status }
|
31
|
+
|
32
|
+
def setup(*args); end
|
33
|
+
def execute(*args); end
|
34
|
+
end
|
35
|
+
|
36
|
+
class MultipleReportsScoutExample < Outpost::Scout
|
37
|
+
attr_accessor :response
|
38
|
+
expect :response, lambda {|scout, status| scout.response == status }
|
39
|
+
def response_time; 10; end
|
40
|
+
def response_code; 200; end
|
41
|
+
def setup(*args); end
|
42
|
+
def execute(*args); end
|
43
|
+
|
44
|
+
report_data :response_time, :response_code
|
45
|
+
end
|
46
|
+
|
14
47
|
it "should report up when status match" do
|
15
48
|
scout = ScoutExample.new("a scout", config_mock)
|
16
49
|
scout.response = true
|
@@ -75,6 +108,36 @@ describe Outpost::Scout do
|
|
75
108
|
end
|
76
109
|
end
|
77
110
|
|
111
|
+
it "should complain when a scout does not respond to the method supplied" do
|
112
|
+
assert_raises(ArgumentError, 'Scout BrokenScoutExample does not respond to #reportive reporting method') do
|
113
|
+
|
114
|
+
scout = BrokenScoutExample.new("a scout", config_mock)
|
115
|
+
scout.run
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should set the report data hash as empty when scout has not been run yet" do
|
120
|
+
scout = ReportingScoutExample.new("a scout", config_mock)
|
121
|
+
assert_equal({}, scout.report_data)
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should fill the report data hash with data collected after being run" do
|
125
|
+
scout = ReportingScoutExample.new("a scout", config_mock)
|
126
|
+
scout.run
|
127
|
+
|
128
|
+
assert_equal({:translated_response_code => "Page Not Found"}, scout.report_data)
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should accept multiple method names" do
|
132
|
+
scout = MultipleReportsScoutExample.new("a scout", config_mock)
|
133
|
+
scout.run
|
134
|
+
|
135
|
+
assert_equal({
|
136
|
+
:response_time => 10,
|
137
|
+
:response_code => 200
|
138
|
+
}, scout.report_data)
|
139
|
+
end
|
140
|
+
|
78
141
|
private
|
79
142
|
def config_mock
|
80
143
|
reports = {
|
@@ -24,6 +24,14 @@ describe Outpost::Scouts::Http do
|
|
24
24
|
assert_equal 'Body', @subject.response_body
|
25
25
|
end
|
26
26
|
|
27
|
+
it "should set the reporting data accordingly" do
|
28
|
+
NetHttpStub.response { response_stub('200', 'Body') }
|
29
|
+
@subject.run
|
30
|
+
|
31
|
+
assert_equal 200 , @subject.report_data[:response_code]
|
32
|
+
assert_equal 'Body', @subject.report_data[:response_body]
|
33
|
+
end
|
34
|
+
|
27
35
|
it "should set response code and body as nil when connection refused" do
|
28
36
|
NetHttpStub.response { raise Errno::ECONNREFUSED }
|
29
37
|
@subject.execute
|
@@ -27,6 +27,14 @@ describe Outpost::Scouts::Ping do
|
|
27
27
|
refute subject.response_time
|
28
28
|
end
|
29
29
|
|
30
|
+
it "should report the response time" do
|
31
|
+
config = config_stub(:pinger => PingStub.new(true, 0.225))
|
32
|
+
subject = Outpost::Scouts::Ping.new "test", config
|
33
|
+
subject.run
|
34
|
+
|
35
|
+
assert_equal 225, subject.report_data[:response_time]
|
36
|
+
end
|
37
|
+
|
30
38
|
private
|
31
39
|
|
32
40
|
def config_stub(options={})
|
data/test/support/server.rb
CHANGED
data/test/support/test_app.rb
CHANGED
metadata
CHANGED
@@ -1,33 +1,23 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: outpost
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 2
|
9
|
-
- 0
|
10
|
-
version: 0.2.0
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.1
|
5
|
+
prerelease:
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Vinicius Baggio Fuentes
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
date: 2011-02-12 00:00:00 -02:00
|
12
|
+
date: 2011-06-26 00:00:00.000000000 -03:00
|
19
13
|
default_executable:
|
20
14
|
dependencies: []
|
21
|
-
|
22
15
|
description: Simple service monitoring with a clean DSL for configuration.
|
23
16
|
email: vinibaggio@gmail.com
|
24
17
|
executables: []
|
25
|
-
|
26
18
|
extensions: []
|
27
|
-
|
28
19
|
extra_rdoc_files: []
|
29
|
-
|
30
|
-
files:
|
20
|
+
files:
|
31
21
|
- .gitignore
|
32
22
|
- CHANGELOG.rdoc
|
33
23
|
- Gemfile
|
@@ -55,8 +45,10 @@ files:
|
|
55
45
|
- outpost.gemspec
|
56
46
|
- test/integration/basic_application_test.rb
|
57
47
|
- test/integration/more_complex_test.rb
|
48
|
+
- test/integration/no_subclassing_test.rb
|
58
49
|
- test/integration/notifiers_test.rb
|
59
|
-
- test/
|
50
|
+
- test/integration/reporting_test.rb
|
51
|
+
- test/outpost/application_test.rb
|
60
52
|
- test/outpost/expectations/response_body_test.rb
|
61
53
|
- test/outpost/expectations/response_code_test.rb
|
62
54
|
- test/outpost/expectations/response_time_test.rb
|
@@ -75,42 +67,35 @@ files:
|
|
75
67
|
has_rdoc: true
|
76
68
|
homepage: http://www.github.com/vinibaggio/outpost
|
77
69
|
licenses: []
|
78
|
-
|
79
70
|
post_install_message:
|
80
71
|
rdoc_options: []
|
81
|
-
|
82
|
-
require_paths:
|
72
|
+
require_paths:
|
83
73
|
- lib
|
84
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
85
75
|
none: false
|
86
|
-
requirements:
|
87
|
-
- -
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
|
90
|
-
|
91
|
-
- 0
|
92
|
-
version: "0"
|
93
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ! '>='
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
81
|
none: false
|
95
|
-
requirements:
|
96
|
-
- -
|
97
|
-
- !ruby/object:Gem::Version
|
98
|
-
|
99
|
-
segments:
|
100
|
-
- 0
|
101
|
-
version: "0"
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
102
86
|
requirements: []
|
103
|
-
|
104
87
|
rubyforge_project: outpost
|
105
|
-
rubygems_version: 1.
|
88
|
+
rubygems_version: 1.6.2
|
106
89
|
signing_key:
|
107
90
|
specification_version: 3
|
108
91
|
summary: Simple service monitoring with a clean DSL for configuration.
|
109
|
-
test_files:
|
92
|
+
test_files:
|
110
93
|
- test/integration/basic_application_test.rb
|
111
94
|
- test/integration/more_complex_test.rb
|
95
|
+
- test/integration/no_subclassing_test.rb
|
112
96
|
- test/integration/notifiers_test.rb
|
113
|
-
- test/
|
97
|
+
- test/integration/reporting_test.rb
|
98
|
+
- test/outpost/application_test.rb
|
114
99
|
- test/outpost/expectations/response_body_test.rb
|
115
100
|
- test/outpost/expectations/response_code_test.rb
|
116
101
|
- test/outpost/expectations/response_time_test.rb
|