outpost 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|