fiveruns-dash-ruby 0.7.0
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/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
|