rack-perftools_profiler 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,66 +1,5 @@
1
1
  require 'test_helper'
2
2
 
3
- ITERATIONS = case RUBY_VERSION
4
- when /1\.9\.1/
5
- 350_000 # Ruby 1.9.1 is that we need to add extra iterations to get profiling data
6
- else
7
- 35_000
8
- end
9
-
10
- # From the Rack spec (http://rack.rubyforge.org/doc/files/SPEC.html) :
11
- # The Body must respond to each and must only yield String values. The Body should not be an instance of String.
12
- # ... The Body commonly is an Array of Strings, the application instance itself, or a File-like object.
13
-
14
- class RackResponseBody
15
- include Test::Unit::Assertions
16
-
17
- def initialize(body)
18
- assert !body.instance_of?(String)
19
- @body = body
20
- end
21
-
22
- def to_s
23
- str = ""
24
- @body.each do |part|
25
- str << part
26
- end
27
- str
28
- end
29
-
30
- end
31
-
32
- class TestApp
33
-
34
- def call(env)
35
- case env['PATH_INFO']
36
- when /method1/
37
- ITERATIONS.times do
38
- self.class.new.method1
39
- end
40
- GC.start
41
- when /method2/
42
- ITERATIONS.times do
43
- self.class.new.method2
44
- end
45
- GC.start
46
- end
47
- [200, {}, ['Done']]
48
- end
49
-
50
- def method1
51
- 100.times do
52
- 1+2+3+4+5
53
- end
54
- end
55
-
56
- def method2
57
- 100.times do
58
- 1+2+3+4+5
59
- end
60
- end
61
-
62
- end
63
-
64
3
  class RackPerftoolsProfilerTest < Test::Unit::TestCase
65
4
  include Rack::PerftoolsProfiler
66
5
 
@@ -114,6 +53,19 @@ class RackPerftoolsProfilerTest < Test::Unit::TestCase
114
53
  end
115
54
  assert_match(/Invalid printer type\: badprinter/, error.message)
116
55
  end
56
+
57
+ should 'raise error if mode is invalid' do
58
+ error = assert_raises ProfilerArgumentError do
59
+ Rack::PerftoolsProfiler.with_profiling_off(@app, :mode => 'badmode', :default_printer => 'gif')
60
+ end
61
+ assert_match(/Invalid mode\: badmode/, error.message)
62
+ end
63
+
64
+ should 'not raise error if mode is unchangeable' do
65
+ assert_nothing_raised do
66
+ Rack::PerftoolsProfiler.with_profiling_off(@app, :mode => 'walltime', :default_printer => 'gif')
67
+ end
68
+ end
117
69
 
118
70
  should 'not modify options hash' do
119
71
  options = {:mode => 'walltime', :default_printer => 'gif'}
@@ -122,7 +74,7 @@ class RackPerftoolsProfilerTest < Test::Unit::TestCase
122
74
  assert_equal old_options, options
123
75
  end
124
76
 
125
- context 'without profiling' do
77
+ context 'when not profiling' do
126
78
 
127
79
  should 'call app directly' do
128
80
  status, headers, body = Rack::PerftoolsProfiler.with_profiling_off(@app).call(@root_request_env)
@@ -141,313 +93,6 @@ class RackPerftoolsProfilerTest < Test::Unit::TestCase
141
93
 
142
94
  end
143
95
 
144
- context 'simple profiling mode' do
145
-
146
- should 'default to text printer' do
147
- _, headers, _ = Rack::PerftoolsProfiler.new(@app).call(@profiled_request_env)
148
- assert_equal "text/plain", headers['Content-Type']
149
- end
150
-
151
- should "set CPUPROFILE_REALTIME to 1 if mode is 'walltime'" do
152
- realtime = ENV['CPUPROFILE_REALTIME']
153
- assert_nil realtime
154
- app = lambda do |env|
155
- realtime = ENV['CPUPROFILE_REALTIME']
156
- [200, {}, ["hi"]]
157
- end
158
- Rack::PerftoolsProfiler.new(app, :mode => 'walltime').call(@profiled_request_env)
159
- assert_equal '1', realtime
160
- end
161
-
162
- should "set CPUPROFILE_OBJECTS to 1 if mode is 'objects'" do
163
- realtime = ENV['CPUPROFILE_OBJECTS']
164
- assert_nil realtime
165
- app = lambda do |env|
166
- realtime = ENV['CPUPROFILE_OBJECTS']
167
- [200, {}, ["hi"]]
168
- end
169
- Rack::PerftoolsProfiler.new(app, :mode => 'objects').call(@profiled_request_env)
170
- assert_equal '1', realtime
171
- end
172
-
173
- should "not set CPUPROFILE_FREQUENCY by default" do
174
- frequency = ENV['CPUPROFILE_FREQUENCY']
175
- assert_nil frequency
176
- app = lambda do |env|
177
- frequency = ENV['CPUPROFILE_FREQUENCY']
178
- [200, {}, ["hi"]]
179
- end
180
- Rack::PerftoolsProfiler.new(app).call(@profiled_request_env)
181
- assert_nil frequency
182
- end
183
-
184
- should 'alter CPUPROFILE_FREQUENCY if frequency is set' do
185
- frequency = ENV['CPUPROFILE_FREQUENCY']
186
- assert_nil frequency
187
- app = lambda do |env|
188
- frequency = ENV['CPUPROFILE_FREQUENCY']
189
- [200, {}, ["hi"]]
190
- end
191
- Rack::PerftoolsProfiler.new(app, :frequency => 500).call(@profiled_request_env)
192
- assert_equal '500', frequency
193
- end
194
-
195
- context 'text printer' do
196
-
197
- should 'return profiling data' do
198
- _, _, body = Rack::PerftoolsProfiler.new(@slow_app, :default_printer => 'text').call(@profiled_request_env)
199
- assert_match(/Total: \d+ samples/, RackResponseBody.new(body).to_s)
200
- end
201
-
202
- should 'have Content-Type text/plain' do
203
- _, headers, _ = Rack::PerftoolsProfiler.new(@app, :default_printer => 'text').call(@profiled_request_env)
204
- assert_equal "text/plain", headers['Content-Type']
205
- end
206
-
207
- should 'have Content-Length' do
208
- _, headers, _ = Rack::PerftoolsProfiler.new(@slow_app, :default_printer => 'text').call(@profiled_request_env)
209
- assert (headers.fetch('Content-Length').to_i > 500)
210
- end
211
-
212
- end
213
-
214
- context 'gif printer' do
215
-
216
- should 'gif printer has Content-Type image/gif' do
217
- _, headers, _ = Rack::PerftoolsProfiler.new(@app, :default_printer => 'gif').call(@profiled_request_env)
218
- assert_equal "image/gif", headers['Content-Type']
219
- end
220
-
221
- should 'gif printer has Content-Length' do
222
- _, headers, _ = Rack::PerftoolsProfiler.new(@slow_app, :default_printer => 'gif').call(@profiled_request_env)
223
- assert headers.fetch('Content-Length').to_i > 25_000
224
- end
225
-
226
- should 'pdf printer has Content-Type application/pdf' do
227
- _, headers, _ = Rack::PerftoolsProfiler.new(@app, :default_printer => 'pdf').call(@profiled_request_env)
228
- assert_equal "application/pdf", headers['Content-Type']
229
- end
230
-
231
- end
232
-
233
- context 'pdf printer' do
234
-
235
- should 'have default filename' do
236
- _, headers, _ = Rack::PerftoolsProfiler.new(@app, :default_printer => 'pdf').call(@profiled_request_env)
237
- assert_equal %q{attachment; filename="profile_data.pdf"}, headers['Content-Disposition']
238
- end
239
-
240
- end
241
-
242
- should 'be able to call app multiple times' do
243
- env = Rack::MockRequest.env_for('/', :params => 'profile=true&times=3')
244
- app = @app.clone
245
- app.expects(:call).times(3)
246
- Rack::PerftoolsProfiler.new(app, :default_printer => 'text').call(env)
247
- end
248
-
249
- should "allow 'printer' param override :default_printer option'" do
250
- env = Rack::MockRequest.env_for('/', :params => 'profile=true&printer=gif')
251
- _, headers, _ = Rack::PerftoolsProfiler.new(@app, :default_printer => 'pdf').call(env)
252
- assert_equal 'image/gif', headers['Content-Type']
253
- end
254
-
255
- should 'give 400 if printer is invalid' do
256
- env = Rack::MockRequest.env_for('/', :params => 'profile=true&printer=badprinter')
257
- status, _, _ = Rack::PerftoolsProfiler.new(@app).call(env)
258
- assert_equal 400, status
259
- end
260
-
261
- should 'send Rack environment to underlying application (minus special profiling GET params)' do
262
- env = Rack::MockRequest.env_for('/', :params => 'profile=true&times=1&param=value&printer=gif&focus=foo&ignore=bar')
263
- old_env = env.clone
264
- expected_env = env.clone
265
- expected_env["QUERY_STRING"] = 'param=value'
266
- app = @app.clone
267
- app.expects(:call).with(expected_env)
268
- Rack::PerftoolsProfiler.new(app, :default_printer => 'gif').call(env)
269
- assert_equal env, old_env
270
- end
271
-
272
- should "accept 'focus' param" do
273
- profiled_app = Rack::PerftoolsProfiler.with_profiling_off(TestApp.new, :default_printer => 'text', :mode => 'walltime')
274
- custom_env = Rack::MockRequest.env_for('/method1', :params => 'profile=true&focus=method1')
275
- status, headers, body = profiled_app.call(custom_env)
276
- assert_no_match(/garbage/, RackResponseBody.new(body).to_s)
277
- end
278
-
279
- should "accept 'ignore' param" do
280
- profiled_app = Rack::PerftoolsProfiler.with_profiling_off(TestApp.new, :default_printer => 'text', :mode => 'walltime')
281
- custom_env = Rack::MockRequest.env_for('/method1', :params => 'profile=true&ignore=method1')
282
- status, headers, body = profiled_app.call(custom_env)
283
- assert_match(/garbage/, RackResponseBody.new(body).to_s)
284
- assert_no_match(/method1/, RackResponseBody.new(body).to_s)
285
- end
286
-
287
- end
288
-
289
- context 'start/stop profiling' do
290
-
291
- should "set CPUPROFILE_REALTIME to 1 if mode is 'walltime' " do
292
- realtime = ENV['CPUPROFILE_REALTIME']
293
- assert_nil realtime
294
- app = lambda do |env|
295
- realtime = ENV['CPUPROFILE_REALTIME']
296
- [200, {}, ["hi"]]
297
- end
298
- profiled_app = Rack::PerftoolsProfiler.new(app, :mode => 'walltime')
299
- profiled_app.call(@start_env)
300
- profiled_app.call(@root_request_env)
301
- profiled_app.call(@stop_env)
302
- assert_equal '1', realtime
303
- end
304
-
305
- should 'alter CPUPROFILE_FREQUENCY if frequency is set' do
306
- frequency = ENV['CPUPROFILE_FREQUENCY']
307
- assert_nil frequency
308
- app = lambda do |env|
309
- frequency = ENV['CPUPROFILE_FREQUENCY']
310
- [200, {}, ["hi"]]
311
- end
312
- profiled_app = Rack::PerftoolsProfiler.new(app, :frequency => 250)
313
- profiled_app.call(@start_env)
314
- profiled_app.call(@root_request_env)
315
- assert_equal '250', frequency
316
- end
317
-
318
- context 'when profiling is on' do
319
-
320
- should 'not provide profiling data when __data__ is called' do
321
- Rack::PerftoolsProfiler.clear_data
322
- profiled_app = Rack::PerftoolsProfiler.with_profiling_off(@app, :default_printer => 'text')
323
- profiled_app.call(@start_env)
324
- profiled_app.call(@root_request_env)
325
- status, _, body = profiled_app.call(@data_env)
326
- assert_equal 400, status
327
- assert_match(/No profiling data available./, RackResponseBody.new(body).to_s)
328
- end
329
-
330
- should 'pass on profiling params in environment' do
331
- env = Rack::MockRequest.env_for('/', :params => 'times=2')
332
- old_env = env.clone
333
- app = @app.clone
334
- expected_env = env.clone
335
- expected_env['rack.request.query_string'] = 'times=2'
336
- expected_env['rack.request.query_hash'] = {'times' => '2'}
337
- app.expects(:call).with(expected_env)
338
- profiled_app = Rack::PerftoolsProfiler.new(app, :default_printer => 'text')
339
- profiled_app.call(@start_env)
340
- profiled_app.call(env)
341
- assert_equal env, old_env
342
- end
343
-
344
- should 'pass on non-profiling params in environment' do
345
- env = Rack::MockRequest.env_for('/', :params => 'param=value')
346
- old_env = env.clone
347
- app = @app.clone
348
- expected_env = env.clone
349
- expected_env['rack.request.query_string'] = 'param=value'
350
- expected_env['rack.request.query_hash'] = {'param' => 'value'}
351
- app.expects(:call).with(expected_env)
352
- profiled_app = Rack::PerftoolsProfiler.new(app, :default_printer => 'text')
353
- profiled_app.call(@start_env)
354
- profiled_app.call(env)
355
- assert_equal env, old_env
356
- end
357
-
358
- should 'not alter regular calls' do
359
- profiled_app = Rack::PerftoolsProfiler.with_profiling_off(@app, :default_printer => 'gif')
360
- profiled_app.call(@start_env)
361
- status, headers, body = profiled_app.call(@root_request_env)
362
- assert_equal 200, status
363
- assert_equal 'text/plain', headers['Content-Type']
364
- assert_equal 'Oh hai der', RackResponseBody.new(body).to_s
365
- end
366
-
367
- end
368
-
369
- context 'after profiling is finished' do
370
-
371
- should 'return profiling data when __data__ is called' do
372
- profiled_app = Rack::PerftoolsProfiler.with_profiling_off(@app, :default_printer => 'gif')
373
- profiled_app.call(@start_env)
374
- profiled_app.call(@root_request_env)
375
- profiled_app.call(@stop_env)
376
- status, headers, body = profiled_app.call(@data_env)
377
- assert_equal 200, status
378
- assert_equal "image/gif", headers['Content-Type']
379
- end
380
-
381
- end
382
-
383
- should 'keeps data from multiple calls' do
384
- profiled_app = Rack::PerftoolsProfiler.with_profiling_off(TestApp.new, :default_printer => 'text', :mode => 'walltime')
385
- profiled_app.call(@start_env)
386
- profiled_app.call(Rack::MockRequest.env_for('/method1'))
387
- profiled_app.call(Rack::MockRequest.env_for('/method2'))
388
- profiled_app.call(@stop_env)
389
- status, headers, body = profiled_app.call(@data_env)
390
- assert_match(/method1/, RackResponseBody.new(body).to_s)
391
- assert_match(/method2/, RackResponseBody.new(body).to_s)
392
- end
393
-
394
- should "allow 'printer' param to override :default_printer option'" do
395
- profiled_app = Rack::PerftoolsProfiler.new(@app, :default_printer => 'pdf')
396
- profiled_app.call(@start_env)
397
- profiled_app.call(@root_request_env)
398
- profiled_app.call(@stop_env)
399
- custom_data_env = Rack::MockRequest.env_for('__data__', :params => 'printer=gif')
400
- _, headers, _ = profiled_app.call(custom_data_env)
401
- assert_equal 'image/gif', headers['Content-Type']
402
- end
403
-
404
- should "accept 'focus' param" do
405
- profiled_app = Rack::PerftoolsProfiler.with_profiling_off(TestApp.new, :default_printer => 'text', :mode => 'walltime')
406
- profiled_app.call(@start_env)
407
- profiled_app.call(Rack::MockRequest.env_for('/method1'))
408
- profiled_app.call(Rack::MockRequest.env_for('/method2'))
409
- profiled_app.call(@stop_env)
410
- custom_data_env = Rack::MockRequest.env_for('__data__', :params => 'focus=method1')
411
- status, headers, body = profiled_app.call(custom_data_env)
412
- assert_no_match(/method2/, RackResponseBody.new(body).to_s)
413
- end
414
-
415
- should "accept 'ignore' param" do
416
- profiled_app = Rack::PerftoolsProfiler.with_profiling_off(TestApp.new, :default_printer => 'text', :mode => 'walltime')
417
- profiled_app.call(@start_env)
418
- profiled_app.call(Rack::MockRequest.env_for('/method1'))
419
- profiled_app.call(Rack::MockRequest.env_for('/method2'))
420
- profiled_app.call(@stop_env)
421
- custom_data_env = Rack::MockRequest.env_for('__data__', :params => 'ignore=method1')
422
- status, headers, body = profiled_app.call(custom_data_env)
423
- assert_no_match(/method1/, RackResponseBody.new(body).to_s)
424
- end
425
-
426
- end
427
-
428
- context "when in bundler mode" do
429
-
430
- should "call pprof.rb using 'bundle' command if bundler is set" do
431
- status = stub_everything(:exitstatus => 0)
432
- profiled_app = Rack::PerftoolsProfiler.new(@app, :bundler => true)
433
- Open4.expects(:popen4).with(regexp_matches(/^bundle exec pprof\.rb/)).returns(status)
434
- profiled_app.call(@profiled_request_env)
435
- end
436
-
437
- should "change directory into the current directory if custom Gemfile dir is not provided" do
438
- profiled_app = Rack::PerftoolsProfiler.new(@app, :bundler => true, :gemfile_dir => 'bundler')
439
- Dir.expects(:chdir).with('bundler').returns(["","",0])
440
- profiled_app.call(@profiled_request_env)
441
- end
442
-
443
- should "change directory into custom Gemfile dir if provided" do
444
- profiled_app = Rack::PerftoolsProfiler.new(@app, :bundler => true)
445
- Dir.expects(:chdir).with('.').returns(["","",0])
446
- profiled_app.call(@profiled_request_env)
447
- end
448
-
449
- end
450
-
451
96
  end
452
97
 
453
98
  end
@@ -0,0 +1,278 @@
1
+ require 'test_helper'
2
+
3
+ class SingleRequestProfilingTest < Test::Unit::TestCase
4
+ include Rack::PerftoolsProfiler
5
+
6
+ def setup
7
+ @app = lambda { |env| ITERATIONS.times {1+2+3+4+5}; [200, {'Content-Type' => 'text/plain'}, ['Oh hai der']] }
8
+ @slow_app = lambda { |env| ITERATIONS.times {1+2+3+4+5}; [200, {'Content-Type' => 'text/plain'}, ['slow app']] }
9
+ @root_request_env = Rack::MockRequest.env_for("/")
10
+ @profiled_request_env = Rack::MockRequest.env_for("/", :params => "profile=true")
11
+ @profiled_request_env_with_times = Rack::MockRequest.env_for("/", :params => "profile=true&times=2")
12
+ end
13
+
14
+ context "(common behavior)" do
15
+
16
+ should 'default to text printer' do
17
+ _, headers, _ = Rack::PerftoolsProfiler.new(@app).call(@profiled_request_env)
18
+ assert_equal "text/plain", headers['Content-Type']
19
+ end
20
+
21
+ should "set CPUPROFILE_REALTIME to 1 if mode is 'walltime'" do
22
+ realtime = ENV['CPUPROFILE_REALTIME']
23
+ assert_nil realtime
24
+ app = lambda do |env|
25
+ realtime = ENV['CPUPROFILE_REALTIME']
26
+ [200, {}, ["hi"]]
27
+ end
28
+ Rack::PerftoolsProfiler.new(app, :mode => 'walltime').call(@profiled_request_env)
29
+ assert_equal '1', realtime
30
+ end
31
+
32
+ should "set CPUPROFILE_OBJECTS to 1 if mode is 'objects'" do
33
+ objects = ENV['CPUPROFILE_OBJECTS']
34
+ assert_nil objects
35
+ app = lambda do |env|
36
+ objects = ENV['CPUPROFILE_OBJECTS']
37
+ [200, {}, ["hi"]]
38
+ end
39
+ Rack::PerftoolsProfiler.new(app, :mode => 'objects').call(@profiled_request_env)
40
+ assert_equal '1', objects
41
+ end
42
+
43
+ should "set CPUPROFILE_METHODS to 1 if mode is 'methods'" do
44
+ methods = ENV['CPUPROFILE_METHODS']
45
+ assert_nil methods
46
+ app = lambda do |env|
47
+ methods = ENV['CPUPROFILE_METHODS']
48
+ [200, {}, ["hi"]]
49
+ end
50
+ status, headers, body = Rack::PerftoolsProfiler.new(app, :mode => 'methods').call(@profiled_request_env)
51
+ assert_equal '1', methods
52
+ end
53
+
54
+ should "not set CPUPROFILE_FREQUENCY by default" do
55
+ frequency = ENV['CPUPROFILE_FREQUENCY']
56
+ assert_nil frequency
57
+ app = lambda do |env|
58
+ frequency = ENV['CPUPROFILE_FREQUENCY']
59
+ [200, {}, ["hi"]]
60
+ end
61
+ Rack::PerftoolsProfiler.new(app).call(@profiled_request_env)
62
+ assert_nil frequency
63
+ end
64
+
65
+ should 'alter CPUPROFILE_FREQUENCY if frequency is set' do
66
+ frequency = ENV['CPUPROFILE_FREQUENCY']
67
+ assert_nil frequency
68
+ app = lambda do |env|
69
+ frequency = ENV['CPUPROFILE_FREQUENCY']
70
+ [200, {}, ["hi"]]
71
+ end
72
+ Rack::PerftoolsProfiler.new(app, :frequency => 500).call(@profiled_request_env)
73
+ assert_equal '500', frequency
74
+ end
75
+
76
+ should "allow 'printer' param override :default_printer option'" do
77
+ env = Rack::MockRequest.env_for('/', :params => 'profile=true&printer=gif')
78
+ _, headers, _ = Rack::PerftoolsProfiler.new(@app, :default_printer => 'pdf').call(env)
79
+ assert_equal 'image/gif', headers['Content-Type']
80
+ end
81
+
82
+ should 'give 400 if printer is invalid' do
83
+ env = Rack::MockRequest.env_for('/', :params => 'profile=true&printer=badprinter')
84
+ status, _, _ = Rack::PerftoolsProfiler.new(@app).call(env)
85
+ assert_equal 400, status
86
+ end
87
+
88
+ should "accept 'focus' param" do
89
+ profiled_app = Rack::PerftoolsProfiler.with_profiling_off(TestApp.new, :default_printer => 'text', :mode => 'walltime')
90
+ custom_env = Rack::MockRequest.env_for('/method1', :params => 'profile=true&focus=method1')
91
+ status, headers, body = profiled_app.call(custom_env)
92
+ assert_no_match(/garbage/, RackResponseBody.new(body).to_s)
93
+ end
94
+
95
+ should "accept 'ignore' param" do
96
+ profiled_app = Rack::PerftoolsProfiler.with_profiling_off(TestApp.new, :default_printer => 'text', :mode => 'walltime')
97
+ custom_env = Rack::MockRequest.env_for('/method1', :params => 'profile=true&ignore=method1')
98
+ status, headers, body = profiled_app.call(custom_env)
99
+ assert_match(/garbage/, RackResponseBody.new(body).to_s)
100
+ assert_no_match(/method1/, RackResponseBody.new(body).to_s)
101
+ end
102
+
103
+ context "when in bundler mode" do
104
+
105
+ should "call pprof.rb using 'bundle' command if bundler is set" do
106
+ status = stub_everything(:exitstatus => 0)
107
+ profiled_app = Rack::PerftoolsProfiler.new(@app, :bundler => true)
108
+ Open4.expects(:popen4).with(regexp_matches(/^bundle exec pprof\.rb/)).returns(status)
109
+ profiled_app.call(@profiled_request_env)
110
+ end
111
+
112
+ should "change directory into the current directory if custom Gemfile dir is not provided" do
113
+ profiled_app = Rack::PerftoolsProfiler.new(@app, :bundler => true, :gemfile_dir => 'bundler')
114
+ Dir.expects(:chdir).with('bundler').returns(["","",0])
115
+ profiled_app.call(@profiled_request_env)
116
+ end
117
+
118
+ should "change directory into custom Gemfile dir if provided" do
119
+ profiled_app = Rack::PerftoolsProfiler.new(@app, :bundler => true)
120
+ Dir.expects(:chdir).with('.').returns(["","",0])
121
+ profiled_app.call(@profiled_request_env)
122
+ end
123
+
124
+ end
125
+
126
+ context "when overriding profiling mode" do
127
+
128
+ should "default to configured mode if mode is empty string" do
129
+ realtime = ENV['CPUPROFILE_REALTIME']
130
+ assert_nil realtime
131
+ app = lambda do |env|
132
+ realtime = ENV['CPUPROFILE_REALTIME']
133
+ [200, {}, ["hi"]]
134
+ end
135
+ request = Rack::MockRequest.env_for("/", :params => 'profile=true&mode=')
136
+ Rack::PerftoolsProfiler.new(app, :mode => :walltime).call(request)
137
+ assert_equal '1', realtime
138
+ end
139
+
140
+ should "set CPUPROFILE_OBJECTS to 1 if mode is 'objects'" do
141
+ objects = ENV['CPUPROFILE_OBJECTS']
142
+ assert_nil objects
143
+ app = lambda do |env|
144
+ objects = ENV['CPUPROFILE_OBJECTS']
145
+ [200, {}, ["hi"]]
146
+ end
147
+ request = Rack::MockRequest.env_for("/", :params => 'profile=true&mode=objects')
148
+ Rack::PerftoolsProfiler.new(app, :mode => :cputime).call(request)
149
+ assert_equal '1', objects
150
+ end
151
+
152
+ should "set CPUPROFILE_METHODS to 1 if mode is 'methods'" do
153
+ methods = ENV['CPUPROFILE_METHODS']
154
+ assert_nil methods
155
+ app = lambda do |env|
156
+ methods = ENV['CPUPROFILE_METHODS']
157
+ [200, {}, ["hi"]]
158
+ end
159
+ request = Rack::MockRequest.env_for("/", :params => 'profile=true&mode=methods')
160
+ Rack::PerftoolsProfiler.new(app, :mode => :cputime).call(request)
161
+ assert_equal '1', methods
162
+ end
163
+
164
+ should "return to default mode if no mode is specified" do
165
+ objects = ENV['CPUPROFILE_OBJECTS']
166
+ assert_nil objects
167
+ app = lambda do |env|
168
+ objects = ENV['CPUPROFILE_OBJECTS']
169
+ [200, {}, ["hi"]]
170
+ end
171
+
172
+ request = Rack::MockRequest.env_for("/", :params => 'profile=true&mode=objects')
173
+ rack_profiler = Rack::PerftoolsProfiler.new(app, :mode => :cputime)
174
+ rack_profiler.call(request)
175
+ rack_profiler.call(@profiled_request_env)
176
+ assert_nil objects
177
+ end
178
+
179
+ should "return error message if mode is unrecognized" do
180
+ profiled_app = Rack::PerftoolsProfiler.new(@app)
181
+ mode = "foobar"
182
+ request = Rack::MockRequest.env_for("/", :params => "profile=true&mode=#{mode}")
183
+ status, _, body = profiled_app.call(request)
184
+ assert_equal 400, status
185
+ assert_match(/Cannot change mode to '#{mode}'.\nPer-request mode changes are only available for the following modes: 'methods', 'objects'/,
186
+ RackResponseBody.new(body).to_s)
187
+ end
188
+
189
+ should "return error message if mode is 'walltime'" do
190
+ profiled_app = Rack::PerftoolsProfiler.new(@app)
191
+ mode = "walltime"
192
+ request = Rack::MockRequest.env_for("/", :params => "profile=true&mode=#{mode}")
193
+ status, _, body = profiled_app.call(request)
194
+ assert_equal 400, status
195
+ assert_match(/Cannot change mode to '#{mode}'.\nPer-request mode changes are only available for the following modes: 'methods', 'objects'/,
196
+ RackResponseBody.new(body).to_s)
197
+ end
198
+
199
+ should "return error message if mode is 'cputime'" do
200
+ profiled_app = Rack::PerftoolsProfiler.new(@app)
201
+ mode = "cputime"
202
+ request = Rack::MockRequest.env_for("/", :params => "profile=true&mode=#{mode}")
203
+ status, _, body = profiled_app.call(request)
204
+ assert_equal 400, status
205
+ assert_match(/Cannot change mode to '#{mode}'.\nPer-request mode changes are only available for the following modes: 'methods', 'objects'/,
206
+ RackResponseBody.new(body).to_s)
207
+ end
208
+
209
+ end
210
+
211
+ end
212
+
213
+ context 'when using the text printer' do
214
+
215
+ should 'return profiling data' do
216
+ _, _, body = Rack::PerftoolsProfiler.new(@slow_app, :default_printer => 'text').call(@profiled_request_env)
217
+ assert_match(/Total: \d+ samples/, RackResponseBody.new(body).to_s)
218
+ end
219
+
220
+ should 'have Content-Type text/plain' do
221
+ _, headers, _ = Rack::PerftoolsProfiler.new(@app, :default_printer => 'text').call(@profiled_request_env)
222
+ assert_equal "text/plain", headers['Content-Type']
223
+ end
224
+
225
+ should 'have Content-Length' do
226
+ _, headers, _ = Rack::PerftoolsProfiler.new(@slow_app, :default_printer => 'text').call(@profiled_request_env)
227
+ assert (headers.fetch('Content-Length').to_i > 500)
228
+ end
229
+
230
+ end
231
+
232
+ context 'when using the gif printer' do
233
+
234
+ should 'gif printer has Content-Type image/gif' do
235
+ _, headers, _ = Rack::PerftoolsProfiler.new(@app, :default_printer => 'gif').call(@profiled_request_env)
236
+ assert_equal "image/gif", headers['Content-Type']
237
+ end
238
+
239
+ should 'gif printer has Content-Length' do
240
+ _, headers, _ = Rack::PerftoolsProfiler.new(@slow_app, :default_printer => 'gif').call(@profiled_request_env)
241
+ assert headers.fetch('Content-Length').to_i > 25_000
242
+ end
243
+
244
+ should 'pdf printer has Content-Type application/pdf' do
245
+ _, headers, _ = Rack::PerftoolsProfiler.new(@app, :default_printer => 'pdf').call(@profiled_request_env)
246
+ assert_equal "application/pdf", headers['Content-Type']
247
+ end
248
+
249
+ end
250
+
251
+ context 'when using the pdf printer' do
252
+
253
+ should 'have default filename' do
254
+ _, headers, _ = Rack::PerftoolsProfiler.new(@app, :default_printer => 'pdf').call(@profiled_request_env)
255
+ assert_equal %q{attachment; filename="profile_data.pdf"}, headers['Content-Disposition']
256
+ end
257
+
258
+ end
259
+
260
+ should 'be able to call app multiple times' do
261
+ env = Rack::MockRequest.env_for('/', :params => 'profile=true&times=3')
262
+ app = @app.clone
263
+ app.expects(:call).times(3)
264
+ Rack::PerftoolsProfiler.new(app, :default_printer => 'text').call(env)
265
+ end
266
+
267
+ should 'send Rack environment to underlying application (minus special profiling GET params)' do
268
+ env = Rack::MockRequest.env_for('/', :params => 'profile=true&times=1&param=value&printer=gif&focus=foo&ignore=bar')
269
+ old_env = env.clone
270
+ expected_env = env.clone
271
+ expected_env["QUERY_STRING"] = 'param=value'
272
+ app = @app.clone
273
+ app.expects(:call).with(expected_env)
274
+ Rack::PerftoolsProfiler.new(app, :default_printer => 'gif').call(env)
275
+ assert_equal env, old_env
276
+ end
277
+
278
+ end