fiveruns-dash-ruby 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +68 -0
- data/Rakefile +39 -0
- data/lib/fiveruns/dash.rb +144 -0
- data/lib/fiveruns/dash/configuration.rb +116 -0
- data/lib/fiveruns/dash/exception_recorder.rb +135 -0
- data/lib/fiveruns/dash/host.rb +173 -0
- data/lib/fiveruns/dash/instrument.rb +128 -0
- data/lib/fiveruns/dash/metric.rb +379 -0
- data/lib/fiveruns/dash/recipe.rb +63 -0
- data/lib/fiveruns/dash/reporter.rb +208 -0
- data/lib/fiveruns/dash/scm.rb +126 -0
- data/lib/fiveruns/dash/session.rb +81 -0
- data/lib/fiveruns/dash/store/file.rb +24 -0
- data/lib/fiveruns/dash/store/http.rb +198 -0
- data/lib/fiveruns/dash/threads.rb +24 -0
- data/lib/fiveruns/dash/trace.rb +65 -0
- data/lib/fiveruns/dash/typable.rb +29 -0
- data/lib/fiveruns/dash/update.rb +215 -0
- data/lib/fiveruns/dash/version.rb +86 -0
- data/recipes/jruby.rb +107 -0
- data/recipes/ruby.rb +34 -0
- data/test/collector_communication_test.rb +260 -0
- data/test/configuration_test.rb +97 -0
- data/test/exception_recorder_test.rb +112 -0
- data/test/file_store_test.rb +56 -0
- data/test/fixtures/http_store_test/response.json +6 -0
- data/test/http_store_test.rb +210 -0
- data/test/metric_test.rb +204 -0
- data/test/recipe_test.rb +146 -0
- data/test/reliability_test.rb +60 -0
- data/test/reporter_test.rb +46 -0
- data/test/scm_test.rb +70 -0
- data/test/session_test.rb +49 -0
- data/test/test_helper.rb +96 -0
- data/test/tracing_test.rb +68 -0
- data/test/update_test.rb +42 -0
- data/version.yml +3 -0
- metadata +112 -0
data/test/metric_test.rb
ADDED
@@ -0,0 +1,204 @@
|
|
1
|
+
require File.dirname(__FILE__) << "/test_helper"
|
2
|
+
|
3
|
+
class MetricTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
attr_reader :metric
|
6
|
+
|
7
|
+
def self.time_me(val=0)
|
8
|
+
if val == 0
|
9
|
+
time_me(1)
|
10
|
+
end
|
11
|
+
sleep 0.01
|
12
|
+
end
|
13
|
+
|
14
|
+
context "Metric" do
|
15
|
+
|
16
|
+
teardown do
|
17
|
+
# Hacked 'uninstrument' until it's built-in
|
18
|
+
::Fiveruns::Dash::Instrument.handlers.each do |handler|
|
19
|
+
(class << MetricTest; self; end).class_eval <<-EOCE
|
20
|
+
remove_method :time_me_with_instrument_#{handler.hash}
|
21
|
+
alias_method :time_me, :time_me_without_instrument_#{handler.hash}
|
22
|
+
remove_method :time_me_without_instrument_#{handler.hash}
|
23
|
+
EOCE
|
24
|
+
end
|
25
|
+
::Fiveruns::Dash::Instrument.handlers.clear
|
26
|
+
end
|
27
|
+
|
28
|
+
context "should parse arguments for name, description and help_text" do
|
29
|
+
setup do
|
30
|
+
@options = Hash.new
|
31
|
+
@options[:method] = time_method
|
32
|
+
@metric = TimeMetric.new(:name, "Description", "HelpText", :method => time_method)
|
33
|
+
end
|
34
|
+
|
35
|
+
should "interpret name" do
|
36
|
+
assert_equal "name", @metric.name
|
37
|
+
end
|
38
|
+
|
39
|
+
should "interpret description" do
|
40
|
+
assert_equal "Description", @metric.description
|
41
|
+
end
|
42
|
+
|
43
|
+
should "interpret help text" do
|
44
|
+
assert_equal "HelpText", @metric.help_text
|
45
|
+
end
|
46
|
+
|
47
|
+
should "interpret options" do
|
48
|
+
assert_equal @options, @metric.options
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "should parse arguments for name, description using defaults" do
|
53
|
+
setup do
|
54
|
+
@options = Hash.new
|
55
|
+
@options[:method] = time_method
|
56
|
+
@metric = TimeMetric.new(:name, :method => time_method)
|
57
|
+
end
|
58
|
+
|
59
|
+
should "interpret name" do
|
60
|
+
assert_equal "name", @metric.name
|
61
|
+
end
|
62
|
+
|
63
|
+
should "default description to titleized name" do
|
64
|
+
assert_equal "Name", @metric.description
|
65
|
+
end
|
66
|
+
|
67
|
+
should "default help text to nil" do
|
68
|
+
assert_nil @metric.help_text
|
69
|
+
end
|
70
|
+
|
71
|
+
should "interpret options" do
|
72
|
+
assert_equal @options, @metric.options
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "using reentrant time" do
|
77
|
+
setup do
|
78
|
+
@metric = TimeMetric.new(:time_mes, :method => time_method, :reentrant => true)
|
79
|
+
flexmock(@metric).should_receive(:info_id).and_return(1)
|
80
|
+
end
|
81
|
+
teardown do
|
82
|
+
# Hacked 'uninstrument' until it's built-in
|
83
|
+
::Fiveruns::Dash::Instrument.handlers.each do |handler|
|
84
|
+
(class << MetricTest; self; end).class_eval <<-EOCE
|
85
|
+
remove_method :time_me_with_instrument_#{handler.hash}
|
86
|
+
alias_method :time_me, :time_me_without_instrument_#{handler.hash}
|
87
|
+
remove_method :time_me_without_instrument_#{handler.hash}
|
88
|
+
EOCE
|
89
|
+
end
|
90
|
+
::Fiveruns::Dash::Instrument.handlers.clear
|
91
|
+
end
|
92
|
+
should "get correct number of invocations" do
|
93
|
+
invoke 4
|
94
|
+
assert_invocations_reported 4
|
95
|
+
invoke 1
|
96
|
+
assert_invocations_reported 1
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context "using time" do
|
101
|
+
setup do
|
102
|
+
@metric = TimeMetric.new(:time_mes, :method => time_method)
|
103
|
+
flexmock(@metric).should_receive(:info_id).and_return(1)
|
104
|
+
end
|
105
|
+
teardown do
|
106
|
+
# Hacked 'uninstrument' until it's built-in
|
107
|
+
::Fiveruns::Dash::Instrument.handlers.each do |handler|
|
108
|
+
(class << MetricTest; self; end).class_eval <<-EOCE
|
109
|
+
remove_method :time_me_with_instrument_#{handler.hash}
|
110
|
+
alias_method :time_me, :time_me_without_instrument_#{handler.hash}
|
111
|
+
remove_method :time_me_without_instrument_#{handler.hash}
|
112
|
+
EOCE
|
113
|
+
end
|
114
|
+
::Fiveruns::Dash::Instrument.handlers.clear
|
115
|
+
end
|
116
|
+
should "raise exception without :on option" do
|
117
|
+
assert_raises ArgumentError do
|
118
|
+
TimeMetric.new(:time_mes, 'A Name')
|
119
|
+
end
|
120
|
+
end
|
121
|
+
should "get correct number of invocations" do
|
122
|
+
invoke 4
|
123
|
+
assert_invocations_reported 8
|
124
|
+
invoke 1
|
125
|
+
assert_invocations_reported 2
|
126
|
+
end
|
127
|
+
should "time invocations" do
|
128
|
+
last_total = 0
|
129
|
+
4.times do |i|
|
130
|
+
invoke
|
131
|
+
assert_equal (i + 1)*2, current_invocations
|
132
|
+
reported_total = current_time_total
|
133
|
+
assert(reported_total > last_total)
|
134
|
+
last_total = reported_total
|
135
|
+
end
|
136
|
+
metric.data # clears
|
137
|
+
assert_equal 0, current_time_total
|
138
|
+
end
|
139
|
+
should "have correct info" do
|
140
|
+
assert_equal 'time_mes', metric.info[:name]
|
141
|
+
assert_equal 'Time Mes', metric.info[:description]
|
142
|
+
end
|
143
|
+
should "be able to set context finder" do
|
144
|
+
finder = lambda { |obj, *args| [:class, obj.name] }
|
145
|
+
@metric.find_context_with(&finder)
|
146
|
+
invoke 4
|
147
|
+
assert_equal 8, metric.data[:values].select { |m| m[:context] == [:class, 'MetricTest'] }.first[:invocations]
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
context "using incremented counter" do
|
152
|
+
setup do
|
153
|
+
@metric = CounterMetric.new(:time_mes_counter, :incremented_by => time_method)
|
154
|
+
flexmock(@metric).should_receive(:info_id).and_return(1)
|
155
|
+
end
|
156
|
+
should "default to 0 before being incremented, and after reset" do
|
157
|
+
assert_counted 0
|
158
|
+
invoke 4
|
159
|
+
assert_counted 8
|
160
|
+
assert_counted 0
|
161
|
+
end
|
162
|
+
should "get correct number after being incremented" do
|
163
|
+
invoke 4
|
164
|
+
assert_counted 8
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
|
170
|
+
#######
|
171
|
+
private
|
172
|
+
#######
|
173
|
+
|
174
|
+
def current_time_total
|
175
|
+
metric.instance_eval { @data[[]][:value] }
|
176
|
+
end
|
177
|
+
|
178
|
+
def current_invocations
|
179
|
+
metric.instance_eval { @data[[]][:invocations] }
|
180
|
+
end
|
181
|
+
|
182
|
+
def time_method
|
183
|
+
'MetricTest.time_me'
|
184
|
+
end
|
185
|
+
|
186
|
+
def assert_counted(number)
|
187
|
+
counted = nil
|
188
|
+
assert_nothing_raised do
|
189
|
+
# We fetch to ensure values aren't just being returned due to hash defaults
|
190
|
+
counted = metric.data[:values].detect { |m| m[:context] == [] }[:value]
|
191
|
+
end
|
192
|
+
assert_kind_of Numeric, counted
|
193
|
+
assert_equal number, counted
|
194
|
+
end
|
195
|
+
|
196
|
+
def assert_invocations_reported(number = 1)
|
197
|
+
assert_equal number, metric.data[:values].detect { |m| m[:context] == [] }[:invocations]
|
198
|
+
end
|
199
|
+
|
200
|
+
def invoke(number = 1)
|
201
|
+
number.times { MetricTest.time_me }
|
202
|
+
end
|
203
|
+
|
204
|
+
end
|
data/test/recipe_test.rb
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
require File.dirname(__FILE__) << "/test_helper"
|
2
|
+
|
3
|
+
class RecipeTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
attr_reader :config
|
6
|
+
|
7
|
+
context "Recipe" do
|
8
|
+
|
9
|
+
setup do
|
10
|
+
mock_streams!
|
11
|
+
Fiveruns::Dash.recipes.clear
|
12
|
+
@config = Fiveruns::Dash::Configuration.new
|
13
|
+
end
|
14
|
+
|
15
|
+
teardown do
|
16
|
+
restore_streams!
|
17
|
+
end
|
18
|
+
|
19
|
+
context "when registering" do
|
20
|
+
context "with valid metadata" do
|
21
|
+
setup do
|
22
|
+
assert_nothing_raised do
|
23
|
+
recipe do |metrics|
|
24
|
+
metrics.counter :foo do
|
25
|
+
1
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
should "is added to available recipes" do
|
31
|
+
assert_equal 1, Fiveruns::Dash.recipes.size
|
32
|
+
assert_kind_of Array, Fiveruns::Dash.recipes[:test]
|
33
|
+
assert_kind_of Fiveruns::Dash::Recipe, Fiveruns::Dash.recipes[:test].first
|
34
|
+
end
|
35
|
+
end
|
36
|
+
context "without url" do
|
37
|
+
should "raise error" do
|
38
|
+
assert_raises Fiveruns::Dash::Recipe::ConfigurationError do
|
39
|
+
recipe(:test, {}) do |metrics|
|
40
|
+
metrics.counter :foo do
|
41
|
+
1
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
context "when adding" do
|
51
|
+
context "with single matching recipe" do
|
52
|
+
setup do
|
53
|
+
recipe :test, :url => 'http://test1.com' do |r|
|
54
|
+
r.counter(:test1) { }
|
55
|
+
end
|
56
|
+
config.add_recipe :test
|
57
|
+
end
|
58
|
+
should "description" do
|
59
|
+
assert_metrics(*%w(test1))
|
60
|
+
end
|
61
|
+
end
|
62
|
+
context "with multiple similiarly-named recipes" do
|
63
|
+
setup do
|
64
|
+
recipe :test, :url => 'http://test1.com' do |r|
|
65
|
+
r.counter(:test1) { }
|
66
|
+
end
|
67
|
+
recipe :test, :url => 'http://test2.com' do |r|
|
68
|
+
r.counter(:test2) { }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
should "load all by default" do
|
72
|
+
config.add_recipe :test
|
73
|
+
assert_equal 2, config.metrics.size
|
74
|
+
assert_metrics(*%w(test1 test2))
|
75
|
+
end
|
76
|
+
should "allow specific recipe to be loaded" do
|
77
|
+
config.add_recipe :test, :url => 'http://test2.com'
|
78
|
+
assert_equal 1, config.metrics.size
|
79
|
+
assert_metrics(*%w(test2))
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "when added" do
|
85
|
+
setup do
|
86
|
+
@fired = false
|
87
|
+
recipe :test, :url => 'http://test.com' do |recipe|
|
88
|
+
recipe.added do
|
89
|
+
@fired = true
|
90
|
+
end
|
91
|
+
recipe.counter(:countme) { }
|
92
|
+
end
|
93
|
+
end
|
94
|
+
should "fire recipe hook" do
|
95
|
+
config.add_recipe :test
|
96
|
+
assert @fired
|
97
|
+
end
|
98
|
+
should "allow metrics with same name and different recipes" do
|
99
|
+
config.counter(:countme) { }
|
100
|
+
config.add_recipe :test
|
101
|
+
assert_metrics(*%w(countme countme))
|
102
|
+
end
|
103
|
+
context "modifying existing metrics" do
|
104
|
+
setup do
|
105
|
+
recipe :test3 do |r|
|
106
|
+
r.modify :name => :countme do |metric|
|
107
|
+
metric.find_context_with do |obj, *args|
|
108
|
+
[:modified, true]
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
should "only occur on addition" do
|
114
|
+
config.metrics.each do |metric|
|
115
|
+
if metric.name == 'countme'
|
116
|
+
assert_nil metric.instance_eval { @metric_finder }
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
should "change context finder" do
|
121
|
+
config.add_recipe :test3
|
122
|
+
config.metrics.each do |metric|
|
123
|
+
if metric.name == 'countme'
|
124
|
+
assert_kind_of Proc, metric.instance_eval { @metric_finder }
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
#######
|
135
|
+
private
|
136
|
+
#######
|
137
|
+
|
138
|
+
def assert_metrics(*names)
|
139
|
+
assert_equal names.sort, config.metrics.map(&:name).map(&:to_s).sort
|
140
|
+
end
|
141
|
+
|
142
|
+
def recipe(name = :test, options = {:url => 'http://test.com'}, &block)
|
143
|
+
Fiveruns::Dash.register_recipe(name, options, &block)
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require File.dirname(__FILE__) << "/test_helper"
|
2
|
+
|
3
|
+
class Gizmo
|
4
|
+
|
5
|
+
def oops!
|
6
|
+
raise 'I made an oopsie!'
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
class ReliabilityTest < Test::Unit::TestCase
|
12
|
+
|
13
|
+
context "FiveRuns Dash" do
|
14
|
+
|
15
|
+
should 'not swallow user-created exceptions' do
|
16
|
+
dash do |metrics|
|
17
|
+
metrics.time(:oops, 'Time spent messing up', 'Ooops!',
|
18
|
+
:method => 'Gizmo#oops!')
|
19
|
+
end
|
20
|
+
|
21
|
+
assert_raises(RuntimeError) { Gizmo.new.oops! }
|
22
|
+
end
|
23
|
+
|
24
|
+
should 'report an exception if instrumentation cannot proceed' do
|
25
|
+
assert_raises(Fiveruns::Dash::Instrument::Error) do
|
26
|
+
dash do |metrics|
|
27
|
+
metrics.time(:wheee, 'Time spent having fun', 'Wheeee!',
|
28
|
+
:method => 'Gizmo.wheeeeeeee!')
|
29
|
+
metrics.time(:oops, 'Time spent messing up', 'Ooops!',
|
30
|
+
:method => 'Gizmo#oops!')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
should 'not proceed with instrumentation if an error occurs' do
|
36
|
+
begin
|
37
|
+
dash do |metrics|
|
38
|
+
metrics.time(:wheee, 'Time spent having fun', 'Wheeee!',
|
39
|
+
:method => 'Gizmo.wheeeeeeee!')
|
40
|
+
metrics.time(:oops, 'Time spent messing up', 'Ooops!',
|
41
|
+
:method => 'Gizmo#oops!')
|
42
|
+
end
|
43
|
+
rescue Fiveruns::Dash::Instrument::Error
|
44
|
+
end
|
45
|
+
assert_equal 0, Fiveruns::Dash.configuration.metrics.length
|
46
|
+
end
|
47
|
+
|
48
|
+
should 'not modify Thread.abort_on_exception if the user has set it' do
|
49
|
+
assert !Thread.abort_on_exception
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
def dash(&block)
|
55
|
+
Fiveruns::Dash.configure({:app => ENV['DASH_APP']}, &block)
|
56
|
+
Fiveruns::Dash.session.reporter.interval = 10
|
57
|
+
Fiveruns::Dash.session.start
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require File.dirname(__FILE__) << "/test_helper"
|
2
|
+
|
3
|
+
class ReporterTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
include Fiveruns::Dash
|
6
|
+
|
7
|
+
attr_reader :reporter
|
8
|
+
|
9
|
+
context "Reporter" do
|
10
|
+
|
11
|
+
setup do
|
12
|
+
mock!
|
13
|
+
end
|
14
|
+
|
15
|
+
context "instance" do
|
16
|
+
setup do
|
17
|
+
@reporter = Reporter.new(@session)
|
18
|
+
end
|
19
|
+
should "start normally" do
|
20
|
+
assert !@reporter.started?
|
21
|
+
assert !@reporter.background?
|
22
|
+
@reporter.start
|
23
|
+
assert_kind_of Time, @reporter.started_at
|
24
|
+
assert @reporter.started?
|
25
|
+
assert @reporter.background?
|
26
|
+
assert !@restarted
|
27
|
+
end
|
28
|
+
should "allow restart" do
|
29
|
+
@reporter.start
|
30
|
+
time = @reporter.started_at
|
31
|
+
assert_kind_of Time, time
|
32
|
+
assert !@restarted
|
33
|
+
@reporter.start
|
34
|
+
assert @restarted
|
35
|
+
assert_equal time.to_f, @reporter.started_at.to_f
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
#######
|
42
|
+
private
|
43
|
+
#######
|
44
|
+
|
45
|
+
|
46
|
+
end
|