newrelic_rpm 2.13.4 → 2.13.5.beta1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of newrelic_rpm might be problematic. Click here for more details.

Files changed (57) hide show
  1. data/CHANGELOG +9 -0
  2. data/lib/new_relic/agent.rb +2 -1
  3. data/lib/new_relic/agent/agent.rb +393 -204
  4. data/lib/new_relic/agent/error_collector.rb +113 -43
  5. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +14 -16
  6. data/lib/new_relic/agent/instrumentation/queue_time.rb +201 -0
  7. data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +1 -1
  8. data/lib/new_relic/agent/instrumentation/sequel.rb +95 -0
  9. data/lib/new_relic/agent/method_tracer.rb +391 -313
  10. data/lib/new_relic/agent/samplers/cpu_sampler.rb +43 -41
  11. data/lib/new_relic/agent/samplers/delayed_job_lock_sampler.rb +2 -0
  12. data/lib/new_relic/agent/samplers/memory_sampler.rb +122 -120
  13. data/lib/new_relic/agent/samplers/object_sampler.rb +2 -0
  14. data/lib/new_relic/agent/stats_engine/metric_stats.rb +0 -1
  15. data/lib/new_relic/agent/stats_engine/samplers.rb +20 -14
  16. data/lib/new_relic/agent/stats_engine/transactions.rb +35 -7
  17. data/lib/new_relic/control.rb +12 -17
  18. data/lib/new_relic/control/configuration.rb +1 -0
  19. data/lib/new_relic/control/frameworks/rails.rb +7 -4
  20. data/lib/new_relic/control/frameworks/rails3.rb +1 -1
  21. data/lib/new_relic/control/instrumentation.rb +2 -18
  22. data/lib/new_relic/local_environment.rb +117 -59
  23. data/lib/new_relic/rack/developer_mode.rb +212 -207
  24. data/lib/new_relic/recipes.rb +0 -9
  25. data/lib/new_relic/stats.rb +87 -81
  26. data/lib/new_relic/transaction_analysis.rb +1 -1
  27. data/lib/new_relic/version.rb +2 -2
  28. data/lib/newrelic_rpm.rb +2 -3
  29. data/lib/tasks/tests.rake +5 -1
  30. data/newrelic_rpm.gemspec +14 -5
  31. data/test/config/test_control.rb +14 -2
  32. data/test/new_relic/agent/active_record_instrumentation_test.rb +342 -119
  33. data/test/new_relic/agent/add_method_tracer_test.rb +158 -0
  34. data/test/new_relic/agent/agent_connect_test.rb +295 -0
  35. data/test/new_relic/agent/agent_controller_test.rb +86 -18
  36. data/test/new_relic/agent/agent_start_test.rb +326 -0
  37. data/test/new_relic/agent/agent_start_worker_thread_test.rb +157 -0
  38. data/test/new_relic/agent/apdex_from_server_test.rb +9 -0
  39. data/test/new_relic/agent/collection_helper_test.rb +3 -1
  40. data/test/new_relic/agent/error_collector_notice_error_test.rb +255 -0
  41. data/test/new_relic/agent/error_collector_test.rb +6 -0
  42. data/test/new_relic/agent/method_tracer_test.rb +2 -2
  43. data/test/new_relic/agent/method_tracer_trace_execution_scoped_test.rb +233 -0
  44. data/test/new_relic/agent/net_instrumentation_test.rb +17 -12
  45. data/test/new_relic/agent/queue_time_test.rb +333 -0
  46. data/test/new_relic/agent/rpm_agent_test.rb +4 -2
  47. data/test/new_relic/agent/stats_engine/samplers_test.rb +27 -1
  48. data/test/new_relic/agent/transaction_sample_subtest_test.rb +56 -0
  49. data/test/new_relic/agent/transaction_sample_test.rb +103 -174
  50. data/test/new_relic/agent/transaction_sampler_test.rb +9 -2
  51. data/test/new_relic/control_test.rb +7 -2
  52. data/test/new_relic/metric_spec_test.rb +1 -1
  53. data/test/new_relic/stats_test.rb +112 -15
  54. data/test/test_helper.rb +79 -16
  55. data/ui/helpers/developer_mode_helper.rb +2 -0
  56. metadata +19 -7
  57. data/lib/new_relic_api.rb +0 -276
@@ -134,10 +134,10 @@ class NewRelic::Agent::MethodTracerTest < Test::Unit::TestCase
134
134
  def test_tt_only
135
135
 
136
136
  assert_nil @scope_listener.scope["c2"]
137
- self.class.add_method_tracer :method_c1, "c1", true
137
+ self.class.add_method_tracer :method_c1, "c1", :push_scope => true
138
138
 
139
139
  self.class.add_method_tracer :method_c2, "c2", :metric => false
140
- self.class.add_method_tracer :method_c3, "c3", false
140
+ self.class.add_method_tracer :method_c3, "c3", :push_scope => false
141
141
 
142
142
  method_c1
143
143
 
@@ -0,0 +1,233 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__),'..','..','test_helper'))
2
+ class NewRelic::Agent::MethodTracer::TraceExecutionScopedTest < Test::Unit::TestCase
3
+ require 'new_relic/agent/method_tracer'
4
+ include NewRelic::Agent::MethodTracer::InstanceMethods::TraceExecutionScoped
5
+
6
+ def test_trace_disabled_negative
7
+ self.expects(:traced?).returns(false)
8
+ options = {:force => false}
9
+ assert trace_disabled?(options)
10
+ end
11
+
12
+ def test_trace_disabled_forced
13
+ self.expects(:traced?).returns(false)
14
+ options = {:force => true}
15
+ assert !(trace_disabled?(options))
16
+ end
17
+
18
+ def test_trace_disabled_positive
19
+ self.expects(:traced?).returns(true)
20
+ options = {:force => false}
21
+ assert !(trace_disabled?(options))
22
+ end
23
+
24
+ def test_get_stats_unscoped
25
+ fake_engine = mocked_object('stat_engine')
26
+ fake_engine.expects(:get_stats_no_scope).with('foob').returns('fakestats')
27
+ assert_equal 'fakestats', get_stats_unscoped('foob')
28
+ end
29
+
30
+ def test_get_stats_scoped_scoped_only
31
+ fake_engine = mocked_object('stat_engine')
32
+ fake_engine.expects(:get_stats).with('foob', true, true).returns('fakestats')
33
+ assert_equal 'fakestats', get_stats_scoped('foob', true)
34
+ end
35
+
36
+ def test_get_stats_scoped_no_scoped_only
37
+ fake_engine = mocked_object('stat_engine')
38
+ fake_engine.expects(:get_stats).with('foob', true, false).returns('fakestats')
39
+ assert_equal 'fakestats', get_stats_scoped('foob', false)
40
+ end
41
+
42
+ def test_stat_engine
43
+ assert_equal agent_instance.stats_engine, stat_engine
44
+ end
45
+
46
+ def test_agent_instance
47
+ assert_equal NewRelic::Agent.instance, agent_instance
48
+ end
49
+
50
+ def test_main_stat
51
+ self.expects(:get_stats_scoped).with('hello', true)
52
+ opts = {:scoped_metric_only => true}
53
+ main_stat('hello', opts)
54
+ end
55
+
56
+ def test_get_metric_stats_metric
57
+ metrics = ['foo', 'bar', 'baz']
58
+ opts = {:metric => true}
59
+ self.expects(:get_stats_unscoped).twice
60
+ self.expects(:main_stat).with('foo', opts)
61
+ first_name, stats = get_metric_stats(metrics, opts)
62
+ assert_equal 'foo', first_name
63
+ assert_equal 3, stats.length
64
+ end
65
+
66
+ def test_get_metric_stats_no_metric
67
+ metrics = ['foo', 'bar', 'baz']
68
+ opts = {:metric => false}
69
+ self.expects(:get_stats_unscoped).twice
70
+ first_name, stats = get_metric_stats(metrics, opts)
71
+ assert_equal 'foo', first_name
72
+ assert_equal 2, stats.length
73
+ end
74
+
75
+ def test_set_if_nil
76
+ h = {}
77
+ set_if_nil(h, :foo)
78
+ assert h[:foo]
79
+ h[:bar] = false
80
+ set_if_nil(h, :bar)
81
+ assert !h[:bar]
82
+ end
83
+
84
+ def test_push_flag_true
85
+ fake_agent = mocked_object('agent_instance')
86
+ fake_agent.expects(:push_trace_execution_flag).with(true)
87
+ push_flag!(true)
88
+ end
89
+
90
+ def test_push_flag_false
91
+ self.expects(:agent_instance).never
92
+ push_flag!(false)
93
+ end
94
+
95
+ def test_pop_flag_true
96
+ fake_agent = mocked_object('agent_instance')
97
+ fake_agent.expects(:pop_trace_execution_flag)
98
+ pop_flag!(true)
99
+ end
100
+
101
+ def test_pop_flag_false
102
+ self.expects(:agent_instance).never
103
+ pop_flag!(false)
104
+ end
105
+
106
+ def test_log_errors_base
107
+ self.expects(:log).never
108
+ ran = false
109
+ log_errors("name", "metric") do
110
+ ran = true
111
+ end
112
+ assert ran, "should run the contents of the block"
113
+ end
114
+
115
+ def test_log_errors_with_return
116
+ self.expects(:log).never
117
+ ran = false
118
+ return_val = log_errors('name', 'metric') do
119
+ ran = true
120
+ 'happy trees'
121
+ end
122
+
123
+ assert ran, "should run contents of block"
124
+ assert_equal 'happy trees', return_val, "should return contents of the block"
125
+ end
126
+
127
+ def test_log_errors_with_error
128
+ fakelog = mocked_log
129
+ # normally I don't do this, but we really don't care what the
130
+ # backtrace looks like, beyond that it actually gets logged. Also,
131
+ # the mocks are reversed because apparently order matters.
132
+ fakelog.expects(:error).with(any_parameters)
133
+ fakelog.expects(:error).with("Caught exception in name. Metric name = metric, exception = should not propagate out of block")
134
+
135
+ log_errors("name", "metric") do
136
+ raise "should not propagate out of block"
137
+ end
138
+ end
139
+
140
+ def test_trace_execution_scoped_header
141
+ options = {:force => false, :deduct_call_time_from_parent => false}
142
+ self.expects(:log_errors).with('trace_execution_scoped header', 'foo').yields
143
+ self.expects(:push_flag!).with(false)
144
+ fakestats = mocked_object('stat_engine')
145
+ fakestats.expects(:push_scope).with('foo', 1.0, false)
146
+ trace_execution_scoped_header('foo', options, 1.0)
147
+ end
148
+
149
+ def test_trace_execution_scoped_footer
150
+ t0 = 1.0
151
+ t1 = 2.0
152
+ metric = 'foo'
153
+ metric_stats = [mock('fakestat')]
154
+ metric_stats.first.expects(:trace_call).with(1.0, 0.5)
155
+ expected_scope = 'an expected scope'
156
+ engine = mocked_object('stat_engine')
157
+ scope = mock('scope')
158
+ engine.expects(:pop_scope).with('an expected scope', 1.0, 2.0).returns(scope)
159
+ scope.expects(:children_time).returns(0.5)
160
+ self.expects(:pop_flag!).with(false)
161
+ self.expects(:log_errors).with('trace_method_execution footer', 'foo').yields
162
+
163
+ trace_execution_scoped_footer(t0, metric, metric_stats, expected_scope, false, t1)
164
+ end
165
+
166
+ def test_trace_execution_scoped_disabled
167
+ self.expects(:trace_disabled?).returns(true)
168
+ # make sure the method doesn't beyond the abort
169
+ self.expects(:set_if_nil).never
170
+ ran = false
171
+ value = trace_execution_scoped(nil, {:options => 'hash'}) do
172
+ ran = true
173
+ 1172
174
+ end
175
+
176
+ assert ran, 'should run contents of block'
177
+ assert_equal 1172, value, 'should return contents of block'
178
+ end
179
+
180
+ def test_trace_execution_scoped_default
181
+ passed_in_opts = {}
182
+ opts_after_correction = {:metric => true, :deduct_call_time_from_parent => true}
183
+ self.expects(:trace_disabled?).returns(false)
184
+ self.expects(:get_metric_stats).with(['metric', 'array'], opts_after_correction).returns(['metric', ['stats']])
185
+ self.expects(:trace_execution_scoped_header).with('metric', opts_after_correction).returns(['start_time', 'expected_scope'])
186
+ self.expects(:trace_execution_scoped_footer).with('start_time', 'metric', ['stats'], 'expected_scope', nil)
187
+ ran = false
188
+ value = trace_execution_scoped(['metric', 'array'], passed_in_opts) do
189
+ ran = true
190
+ 1172
191
+ end
192
+
193
+ assert ran, 'should run contents of the block'
194
+ assert_equal 1172, value, 'should return the contents of the block'
195
+ end
196
+
197
+ def test_trace_execution_scoped_with_error
198
+ passed_in_opts = {}
199
+ opts_after_correction = {:metric => true, :deduct_call_time_from_parent => true}
200
+ self.expects(:trace_disabled?).returns(false)
201
+ self.expects(:get_metric_stats).with(['metric', 'array'], opts_after_correction).returns(['metric', ['stats']])
202
+ self.expects(:trace_execution_scoped_header).with('metric', opts_after_correction).returns(['start_time', 'expected_scope'])
203
+ self.expects(:trace_execution_scoped_footer).with('start_time', 'metric', ['stats'], 'expected_scope', nil)
204
+ ran = false
205
+ assert_raises(RuntimeError) do
206
+ trace_execution_scoped(['metric', 'array'], passed_in_opts) do
207
+ ran = true
208
+ raise 'wtfmate'
209
+ end
210
+ end
211
+
212
+ assert ran, 'should run contents of the block'
213
+ end
214
+
215
+ private
216
+
217
+ def mocked_object(name)
218
+ object = mock(name)
219
+ self.stubs(name).returns(object)
220
+ object
221
+ end
222
+
223
+
224
+ def mocked_log
225
+ mocked_object('log')
226
+ end
227
+
228
+
229
+ def mocked_control
230
+ mocked_object('control')
231
+ end
232
+ end
233
+
@@ -7,6 +7,13 @@ class NewRelic::Agent::NetInstrumentationTest < Test::Unit::TestCase
7
7
  @engine = NewRelic::Agent.instance.stats_engine
8
8
  @engine.clear_stats
9
9
  end
10
+
11
+ def metrics_without_gc
12
+ @engine.metrics - ['GC/cumulative']
13
+ end
14
+
15
+ private :metrics_without_gc
16
+
10
17
  def test_get
11
18
  url = URI.parse('http://www.google.com/index.html')
12
19
  res = Net::HTTP.start(url.host, url.port) {|http|
@@ -14,7 +21,7 @@ class NewRelic::Agent::NetInstrumentationTest < Test::Unit::TestCase
14
21
  }
15
22
  assert_match /<head>/, res.body
16
23
  assert_equal %w[External/www.google.com/Net::HTTP/GET External/allOther External/www.google.com/all].sort,
17
- @engine.metrics.sort
24
+ metrics_without_gc.sort
18
25
  end
19
26
 
20
27
  def test_background
@@ -25,9 +32,8 @@ class NewRelic::Agent::NetInstrumentationTest < Test::Unit::TestCase
25
32
  }
26
33
  assert_match /<head>/, res.body
27
34
  end
28
- assert_equal @engine.metrics.select{|m| m =~ /^External/}.sort,
29
- %w[External/www.google.com/Net::HTTP/GET External/allOther External/www.google.com/all
30
- External/www.google.com/Net::HTTP/GET:OtherTransaction/Background/NewRelic::Agent::NetInstrumentationTest/task].sort
35
+ assert_equal %w[External/www.google.com/Net::HTTP/GET External/allOther External/www.google.com/all
36
+ External/www.google.com/Net::HTTP/GET:OtherTransaction/Background/NewRelic::Agent::NetInstrumentationTest/task].sort, metrics_without_gc.select{|m| m =~ /^External/}.sort
31
37
  end
32
38
 
33
39
  def test_transactional
@@ -38,14 +44,13 @@ class NewRelic::Agent::NetInstrumentationTest < Test::Unit::TestCase
38
44
  }
39
45
  assert_match /<head>/, res.body
40
46
  end
41
- assert_equal @engine.metrics.select{|m| m =~ /^External/}.sort,
42
- %w[External/www.google.com/Net::HTTP/GET External/allWeb External/www.google.com/all
43
- External/www.google.com/Net::HTTP/GET:Controller/NewRelic::Agent::NetInstrumentationTest/task].sort
47
+ assert_equal %w[External/www.google.com/Net::HTTP/GET External/allWeb External/www.google.com/all
48
+ External/www.google.com/Net::HTTP/GET:Controller/NewRelic::Agent::NetInstrumentationTest/task].sort, metrics_without_gc.select{|m| m =~ /^External/}.sort
44
49
  end
45
50
  def test_get__simple
46
51
  Net::HTTP.get URI.parse('http://www.google.com/index.html')
47
- assert_equal @engine.metrics.sort,
48
- %w[External/www.google.com/Net::HTTP/GET External/allOther External/www.google.com/all].sort
52
+ assert_equal metrics_without_gc.sort,
53
+ %w[External/www.google.com/Net::HTTP/GET External/allOther External/www.google.com/all].sort
49
54
  end
50
55
  def test_ignore
51
56
  NewRelic::Agent.disable_all_tracing do
@@ -54,7 +59,7 @@ class NewRelic::Agent::NetInstrumentationTest < Test::Unit::TestCase
54
59
  http.post('/index.html','data')
55
60
  }
56
61
  end
57
- assert_equal 0, @engine.metrics.size
62
+ assert_equal 0, metrics_without_gc.size
58
63
  end
59
64
  def test_head
60
65
  url = URI.parse('http://www.google.com/index.html')
@@ -62,7 +67,7 @@ class NewRelic::Agent::NetInstrumentationTest < Test::Unit::TestCase
62
67
  http.head('/index.html')
63
68
  }
64
69
  assert_equal %w[External/www.google.com/Net::HTTP/HEAD External/allOther External/www.google.com/all].sort,
65
- @engine.metrics.sort
70
+ metrics_without_gc.sort
66
71
  end
67
72
 
68
73
  def test_post
@@ -71,7 +76,7 @@ class NewRelic::Agent::NetInstrumentationTest < Test::Unit::TestCase
71
76
  http.post('/index.html','data')
72
77
  }
73
78
  assert_equal %w[External/www.google.com/Net::HTTP/POST External/allOther External/www.google.com/all].sort,
74
- @engine.metrics.sort
79
+ metrics_without_gc.sort
75
80
  end
76
81
 
77
82
  end
@@ -0,0 +1,333 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'test_helper'))
2
+ class NewRelic::Agent::Instrumentation::QueueTimeTest < Test::Unit::TestCase
3
+ require 'new_relic/agent/instrumentation/queue_time'
4
+ include NewRelic::Agent::Instrumentation::QueueTime
5
+
6
+ def setup
7
+ NewRelic::Agent.instance.stats_engine.clear_stats
8
+ end
9
+
10
+ def create_test_start_time(env)
11
+ env[APP_HEADER] = "t=#{convert_to_microseconds(Time.at(1002))}"
12
+ end
13
+
14
+ def test_parse_frontend_headers
15
+ self.expects(:current_time).returns('END_TIME')
16
+ self.expects(:add_end_time_header).with('END_TIME', {:env => 'hash'})
17
+ # ordering is important here, unfortunately, the mocks don't
18
+ # support that kind of checking.
19
+ self.expects(:parse_middleware_time_from).with({:env => 'hash'})
20
+ self.expects(:parse_queue_time_from).with({:env => 'hash'})
21
+ self.expects(:parse_server_time_from).with({:env => 'hash'})
22
+ parse_frontend_headers({:env => 'hash'})
23
+ end
24
+
25
+ def test_all_combined_frontend_headers
26
+ env = {}
27
+ env[MAIN_HEADER] = "t=#{convert_to_microseconds(Time.at(1000))}"
28
+ env[QUEUE_HEADER] = "t=#{convert_to_microseconds(Time.at(1001))}"
29
+ env[MIDDLEWARE_HEADER] = "t=#{convert_to_microseconds(Time.at(1002))}"
30
+
31
+ env[APP_HEADER] = "t=#{convert_to_microseconds(Time.at(1003))}"
32
+
33
+ assert_calls_metrics('WebFrontend/WebServer/all', 'WebFrontend/QueueTime', 'Middleware/all') do
34
+ parse_middleware_time_from(env)
35
+ parse_queue_time_from(env)
36
+ parse_server_time_from(env)
37
+ end
38
+
39
+ check_metric_time('WebFrontend/WebServer/all', 1.0, 0.001)
40
+ check_metric_time('WebFrontend/QueueTime', 1.0, 0.001)
41
+ check_metric_time('Middleware/all', 1.0, 0.001)
42
+ end
43
+
44
+ def test_combined_middleware_and_queue
45
+ env = {}
46
+ env[QUEUE_HEADER] = "t=#{convert_to_microseconds(Time.at(1000))}"
47
+ env[MIDDLEWARE_HEADER] = "t=#{convert_to_microseconds(Time.at(1001))}"
48
+ create_test_start_time(env)
49
+
50
+ assert_calls_metrics('Middleware/all', 'WebFrontend/QueueTime') do
51
+ parse_middleware_time_from(env)
52
+ parse_queue_time_from(env)
53
+ end
54
+
55
+ check_metric_time('Middleware/all', 1.0, 0.001)
56
+ check_metric_time('WebFrontend/QueueTime', 1.0, 0.001)
57
+ end
58
+
59
+ def test_combined_queue_and_server
60
+ env = {}
61
+ env[MAIN_HEADER] = "t=#{convert_to_microseconds(Time.at(1000))}"
62
+ env[QUEUE_HEADER] = "t=#{convert_to_microseconds(Time.at(1001))}"
63
+ create_test_start_time(env)
64
+
65
+ assert_calls_metrics('WebFrontend/WebServer/all', 'WebFrontend/QueueTime') do
66
+ parse_queue_time_from(env)
67
+ parse_server_time_from(env)
68
+ end
69
+
70
+ check_metric_time('WebFrontend/WebServer/all', 1.0, 0.001)
71
+ check_metric_time('WebFrontend/QueueTime', 1.0, 0.001)
72
+ end
73
+
74
+ def test_combined_middleware_and_server
75
+ env = {}
76
+ env[MAIN_HEADER] = "t=#{convert_to_microseconds(Time.at(1000))}"
77
+ env[MIDDLEWARE_HEADER] = "t=#{convert_to_microseconds(Time.at(1001))}"
78
+ create_test_start_time(env)
79
+
80
+ assert_calls_metrics('WebFrontend/WebServer/all', 'Middleware/all') do
81
+ parse_middleware_time_from(env)
82
+ parse_server_time_from(env)
83
+ end
84
+
85
+ check_metric_time('WebFrontend/WebServer/all', 1.0, 0.001)
86
+ check_metric_time('Middleware/all', 1.0, 0.001)
87
+ end
88
+
89
+ # initial base case, a router and a static content server
90
+ def test_parse_server_time_from_initial
91
+ env = {}
92
+ create_test_start_time(env)
93
+ time1 = convert_to_microseconds(Time.at(1000))
94
+ time2 = convert_to_microseconds(Time.at(1001))
95
+ env['HTTP_X_REQUEST_START'] = "servera t=#{time1}, serverb t=#{time2}"
96
+ assert_calls_metrics('WebFrontend/WebServer/all', 'WebFrontend/WebServer/servera', 'WebFrontend/WebServer/serverb') do
97
+ parse_server_time_from(env)
98
+ end
99
+ check_metric_time('WebFrontend/WebServer/all', 2.0, 0.1)
100
+ check_metric_time('WebFrontend/WebServer/servera', 1.0, 0.1)
101
+ check_metric_time('WebFrontend/WebServer/serverb', 1.0, 0.1)
102
+ end
103
+
104
+ # test for backwards compatibility with old header
105
+ def test_parse_server_time_from_with_no_server_name
106
+ env = {'HTTP_X_REQUEST_START' => "t=#{convert_to_microseconds(Time.at(1001))}"}
107
+ create_test_start_time(env)
108
+ assert_calls_metrics('WebFrontend/WebServer/all') do
109
+ parse_server_time_from(env)
110
+ end
111
+ check_metric_time('WebFrontend/WebServer/all', 1.0, 0.1)
112
+ end
113
+
114
+ def test_parse_server_time_from_with_bad_header
115
+ env = {'HTTP_X_REQUEST_START' => 't=t=t=t='}
116
+ create_test_start_time(env)
117
+ assert_calls_metrics('WebFrontend/WebServer/all') do
118
+ parse_server_time_from(env)
119
+ end
120
+ end
121
+
122
+ def test_parse_server_time_from_with_no_header
123
+ assert_calls_metrics('WebFrontend/WebServer/all') do
124
+ parse_server_time_from({})
125
+ end
126
+ end
127
+
128
+ def test_parse_middleware_time
129
+ env = {}
130
+ create_test_start_time(env)
131
+ time1 = convert_to_microseconds(Time.at(1000))
132
+ time2 = convert_to_microseconds(Time.at(1001))
133
+
134
+ env['HTTP_X_MIDDLEWARE_START'] = "base t=#{time1}, second t=#{time2}"
135
+ assert_calls_metrics('Middleware/all', 'Middleware/base', 'Middleware/second') do
136
+ parse_middleware_time_from(env)
137
+ end
138
+ check_metric_time('Middleware/all', 2.0, 0.1)
139
+ check_metric_time('Middleware/base', 1.0, 0.1)
140
+ check_metric_time('Middleware/second', 1.0, 0.1)
141
+ end
142
+
143
+ def test_parse_queue_time
144
+ env = {}
145
+ create_test_start_time(env)
146
+ time1 = convert_to_microseconds(Time.at(1000))
147
+
148
+ env['HTTP_X_QUEUE_START'] = "t=#{time1}"
149
+ assert_calls_metrics('WebFrontend/QueueTime') do
150
+ parse_queue_time_from(env)
151
+ end
152
+
153
+ check_metric_time('WebFrontend/QueueTime', 2.0, 0.1)
154
+ end
155
+
156
+ def test_check_for_alternate_queue_length
157
+ env = {}
158
+ create_test_start_time(env)
159
+ env['HTTP_X_QUEUE_TIME'] = '1000000'
160
+ assert_calls_metrics('WebFrontend/QueueTime') do
161
+ parse_queue_time_from(env)
162
+ end
163
+
164
+ check_metric_time('WebFrontend/QueueTime', 1.0, 0.001)
165
+ end
166
+
167
+ # each server should be one second, and the total would be 2 seconds
168
+ def test_record_individual_server_stats
169
+ matches = [['foo', Time.at(1000)], ['bar', Time.at(1001)]]
170
+ assert_calls_metrics('WebFrontend/WebServer/foo', 'WebFrontend/WebServer/bar') do
171
+ record_individual_server_stats(Time.at(1002), matches)
172
+ end
173
+ check_metric_time('WebFrontend/WebServer/foo', 1.0, 0.1)
174
+ check_metric_time('WebFrontend/WebServer/bar', 1.0, 0.1)
175
+ end
176
+
177
+ def test_record_rollup_server_stat
178
+ assert_calls_metrics('WebFrontend/WebServer/all') do
179
+ record_rollup_server_stat(Time.at(1001), [['a', Time.at(1000)]])
180
+ end
181
+ check_metric_time('WebFrontend/WebServer/all', 1.0, 0.1)
182
+ end
183
+
184
+ def test_record_rollup_server_stat_no_data
185
+ assert_calls_metrics('WebFrontend/WebServer/all') do
186
+ record_rollup_server_stat(Time.at(1001), [])
187
+ end
188
+ check_metric_time('WebFrontend/WebServer/all', 0.0, 0.001)
189
+ end
190
+
191
+ def test_record_rollup_middleware_stat
192
+ assert_calls_metrics('Middleware/all') do
193
+ record_rollup_middleware_stat(Time.at(1001), [['a', Time.at(1000)]])
194
+ end
195
+ check_metric_time('Middleware/all', 1.0, 0.1)
196
+ end
197
+
198
+ def test_record_rollup_middleware_stat_no_data
199
+ assert_calls_metrics('Middleware/all') do
200
+ record_rollup_middleware_stat(Time.at(1001), [])
201
+ end
202
+ check_metric_time('Middleware/all', 0.0, 0.001)
203
+ end
204
+
205
+ def test_record_rollup_queue_stat
206
+ assert_calls_metrics('WebFrontend/QueueTime') do
207
+ record_rollup_queue_stat(Time.at(1001), [[nil, Time.at(1000)]])
208
+ end
209
+ check_metric_time('WebFrontend/QueueTime', 1.0, 0.1)
210
+ end
211
+
212
+ def test_record_rollup_queue_stat_no_data
213
+ assert_calls_metrics('WebFrontend/QueueTime') do
214
+ record_rollup_queue_stat(Time.at(1001), [])
215
+ end
216
+ check_metric_time('WebFrontend/QueueTime', 0.0, 0.001)
217
+ end
218
+
219
+
220
+ # check all the combinations to make sure that ordering doesn't
221
+ # affect the return value
222
+ def test_find_oldest_time
223
+ test_arrays = [
224
+ ['a', Time.at(1000)],
225
+ ['b', Time.at(1001)],
226
+ ['c', Time.at(1002)],
227
+ ['d', Time.at(1000)],
228
+ ]
229
+ test_arrays = test_arrays.permutation
230
+ test_arrays.each do |test_array|
231
+ assert_equal find_oldest_time(test_array), Time.at(1000), "Should be the oldest time in the array"
232
+ end
233
+ end
234
+
235
+ # trivial test but the method doesn't do much
236
+ def test_record_server_time_for
237
+ name = 'foo'
238
+ time = Time.at(1000)
239
+ start_time = Time.at(1001)
240
+ self.expects(:record_time_stat).with('WebFrontend/WebServer/foo', time, start_time)
241
+ record_server_time_for(name, time, start_time)
242
+ end
243
+
244
+ def test_record_time_stat
245
+ assert_calls_metrics('WebFrontend/WebServer/foo') do
246
+ record_time_stat('WebFrontend/WebServer/foo', Time.at(1000), Time.at(1001))
247
+ end
248
+ check_metric_time('WebFrontend/WebServer/foo', 1.0, 0.1)
249
+ assert_raises(RuntimeError) do
250
+ record_time_stat('foo', Time.at(1001), Time.at(1000))
251
+ end
252
+ end
253
+
254
+ def test_record_time_stat_with_end_after_start
255
+ record_time_stat('WebFrontend/WebServer/foo', 2, 1)
256
+ rescue RuntimeError => e
257
+ assert_equal("should not provide an end time less than start time: 1 is less than 2", e.message)
258
+ end
259
+
260
+ def test_convert_to_microseconds
261
+ assert_equal((1_000_000_000), convert_to_microseconds(Time.at(1000)), 'time at 1000 seconds past epoch should be 1,000,000,000 usec')
262
+ assert_equal 1_000_000_000, convert_to_microseconds(1_000_000_000), 'should not mess with a number if passed in'
263
+ assert_raises(TypeError) do
264
+ convert_to_microseconds('whoo yeah buddy')
265
+ end
266
+ end
267
+
268
+ def test_convert_from_microseconds
269
+ assert_equal Time.at(1000), convert_from_microseconds(1_000_000_000), 'time at 1,000,000,000 usec should be 1000 seconds after epoch'
270
+ assert_equal Time.at(1000), convert_from_microseconds(Time.at(1000)), 'should not mess with a time passed in'
271
+ assert_raises(TypeError) do
272
+ convert_from_microseconds('10000000000')
273
+ end
274
+ end
275
+
276
+ def test_add_end_time_header
277
+ env = {}
278
+ start_time = Time.at(1)
279
+ add_end_time_header(start_time, env)
280
+ assert_equal({'HTTP_X_APPLICATION_START' => "t=#{convert_to_microseconds(Time.at(1))}"}, env, "should add the header to the env hash")
281
+ end
282
+
283
+ def test_parse_end_time_base
284
+ env = {}
285
+ env['HTTP_X_APPLICATION_START'] = "t=#{convert_to_microseconds(Time.at(1))}"
286
+ start_time = parse_end_time(env)
287
+ assert_equal(Time.at(1), start_time, "should pull the correct start time from the app header")
288
+ end
289
+
290
+ def test_get_matches_from_header
291
+ env = {'A HEADER' => 't=1000000'}
292
+ self.expects(:convert_from_microseconds).with(1000000).returns(Time.at(1))
293
+ matches = get_matches_from_header('A HEADER', env)
294
+ assert_equal [[nil, Time.at(1)]], matches, "should pull the correct time from the string"
295
+ end
296
+
297
+ def test_convert_to_name_time_pair
298
+ name = :foo
299
+ time = "1000000"
300
+
301
+ pair = convert_to_name_time_pair(name, time)
302
+ assert_equal [:foo, Time.at(1)], pair
303
+ end
304
+
305
+ def test_get_matches
306
+ str = "servera t=1000000, serverb t=1000000"
307
+ matches = get_matches(str) # start a fire
308
+ assert_equal [['servera', '1000000'], ['serverb', '1000000']], matches
309
+ end
310
+
311
+ def test_matches_with_bad_data
312
+ str = "stephan is a dumb lol"
313
+ matches = get_matches(str)
314
+ assert_equal [], matches
315
+
316
+ str = "t=100"
317
+ matches = get_matches(str)
318
+ assert_equal [[nil, '100']], matches
319
+
320
+ str = nil
321
+ matches = get_matches(str)
322
+ assert_equal [], matches
323
+ end
324
+ # each server should be one second, and the total would be 2 seconds
325
+ def test_record_individual_middleware_stats
326
+ matches = [['foo', Time.at(1000)], ['bar', Time.at(1001)]]
327
+ assert_calls_metrics('Middleware/foo', 'Middleware/bar') do
328
+ record_individual_middleware_stats(Time.at(1002), matches)
329
+ end
330
+ check_metric_time('Middleware/foo', 1.0, 0.1)
331
+ check_metric_time('Middleware/bar', 1.0, 0.1)
332
+ end
333
+ end