kronk 1.4.0 → 1.5.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.
@@ -0,0 +1,589 @@
1
+ require 'test/test_helper'
2
+
3
+ class TestPlayer < Test::Unit::TestCase
4
+
5
+ class MockPipe < StringIO; end
6
+
7
+ class MockOutput < Kronk::Player::Output
8
+ attr_accessor :result_calls
9
+
10
+ def initialize *args
11
+ @result_calls = 0
12
+ super
13
+ end
14
+
15
+ def result kronk, mutex
16
+ mutex.synchronize do
17
+ @result_calls += 1
18
+ end
19
+ end
20
+ end
21
+
22
+ class MockParser
23
+ def self.parse str
24
+ str
25
+ end
26
+ end
27
+
28
+
29
+ def setup
30
+ @io = MockPipe.new
31
+ @parser = MockParser
32
+ @output = MockOutput
33
+ @player = Kronk::Player.new :io => @io,
34
+ :parser => @parser,
35
+ :output => @output
36
+ end
37
+
38
+
39
+ def test_init_defaults
40
+ player = Kronk::Player.new
41
+ assert_equal Kronk::Player::Suite, player.output.class
42
+ assert_equal Kronk::Player::InputReader, player.input.class
43
+ assert_equal Mutex, player.mutex.class
44
+ assert_equal 1, player.concurrency
45
+ assert_nil player.input.io
46
+ assert_nil player.number
47
+ assert player.queue.empty?
48
+ assert player.threads.empty?
49
+ end
50
+
51
+
52
+ def test_init
53
+ assert_equal Kronk::Player::InputReader, @player.input.class
54
+ assert_equal Mutex, @player.mutex.class
55
+ assert_equal @io, @player.input.io
56
+ assert_equal 1, @player.concurrency
57
+ assert_nil @player.number
58
+ assert @player.queue.empty?
59
+ assert @player.threads.empty?
60
+ end
61
+
62
+
63
+ def test_init_opts
64
+ player = Kronk::Player.new :number => 1000,
65
+ :concurrency => 10,
66
+ :output => :stream
67
+
68
+ assert_equal Kronk::Player::Stream, player.output.class
69
+ assert_equal Kronk::Player::RequestParser, player.input.parser
70
+ assert_equal 10, player.concurrency
71
+ assert_equal 1000, player.number
72
+ end
73
+
74
+
75
+ def test_output
76
+ @player.output_from :benchmark
77
+ assert_equal Kronk::Player::Benchmark, @player.output.class
78
+
79
+ @player.output_from :stream
80
+ assert_equal Kronk::Player::Stream, @player.output.class
81
+
82
+ @player.output_from :suite
83
+ assert_equal Kronk::Player::Suite, @player.output.class
84
+
85
+ @player.output_from Kronk::Player::Benchmark
86
+ assert_equal Kronk::Player::Benchmark, @player.output.class
87
+ end
88
+
89
+
90
+ def test_queue_req
91
+ @player.queue_req :first_item
92
+ @player.queue_req :second_item
93
+ assert_equal [:first_item, :second_item], @player.queue
94
+ end
95
+
96
+
97
+ def test_from_io
98
+ @player.from_io "mock"
99
+ assert_equal "mock", @player.input.io
100
+ assert_equal MockParser, @player.input.parser
101
+
102
+ @player.from_io "mock", "mock_parser"
103
+ assert_equal "mock", @player.input.io
104
+ assert_equal "mock_parser", @player.input.parser
105
+ end
106
+
107
+
108
+ def test_output_results
109
+ @player.output.expects(:completed).with().returns "FINISHED"
110
+ assert_equal "FINISHED", @player.output_results
111
+ end
112
+
113
+
114
+ def test_finished_false
115
+ @player.number = nil
116
+
117
+ @player.queue.clear
118
+ @player.count = 2
119
+ @player.input.stubs(:eof?).returns false
120
+ assert !@player.finished?
121
+
122
+ @player.queue << "test"
123
+ @player.count = 2
124
+ @player.input.stubs(:eof?).returns true
125
+ assert !@player.finished?
126
+
127
+ @player.count = 0
128
+ @player.queue.clear
129
+ @player.input.stubs(:eof?).returns true
130
+ assert !@player.finished?
131
+
132
+ @player.count = 4
133
+ @player.queue.clear
134
+ @player.input.stubs(:eof?).returns true
135
+ @player.reader_thread = "mock thread"
136
+ @player.reader_thread.expects(:alive?).returns true
137
+ assert !@player.finished?
138
+
139
+ @player.queue << "test"
140
+ @player.input.stubs(:eof?).returns true
141
+ @player.reader_thread.stubs(:alive?).returns false
142
+ @player.count = 5
143
+ @player.number = 10
144
+ assert !@player.finished?
145
+ end
146
+
147
+
148
+ def test_finished_true
149
+ @player.number = 4
150
+ @player.count = 4
151
+ assert @player.finished?
152
+
153
+ @player.number = nil
154
+ @player.count = 1
155
+ @player.queue.clear
156
+ @player.input.stubs(:eof?).returns true
157
+ @player.reader_thread = "mock thread"
158
+ @player.reader_thread.expects(:alive?).returns false
159
+ assert @player.finished?
160
+
161
+ @player.number = 10
162
+ @player.count = 1
163
+ @player.queue.clear
164
+ @player.input.stubs(:eof?).returns true
165
+ @player.reader_thread.expects(:alive?).returns false
166
+ assert @player.finished?
167
+ end
168
+
169
+
170
+ def test_compare_single
171
+ io1 = StringIO.new(mock_200_response)
172
+ io2 = StringIO.new(mock_302_response)
173
+ expect_compare_output mock_200_response, mock_302_response
174
+
175
+ @player.compare io1, io2
176
+ end
177
+
178
+
179
+ def test_compare
180
+ @player.concurrency = 3
181
+ @player.input.parser = Kronk::Player::RequestParser
182
+ @player.input.io << "/req3\n/req4\n/req5\n"
183
+ @player.input.io.rewind
184
+ @player.input.io.close_write
185
+
186
+ @player.queue.concat [{:uri_suffix => "/req1"}, {:uri_suffix => "/req2"}]
187
+
188
+ part1 = (1..2).map{|n| "/req#{n}"}
189
+ part2 = (3..5).map{|n| "/req#{n}"}
190
+
191
+ part1.each do |path|
192
+ mock_requests "example.com", "beta-example.com",
193
+ :uri_suffix => path,
194
+ :query => "foo=bar"
195
+ end
196
+
197
+ part2.each do |path|
198
+ mock_requests "example.com", "beta-example.com",
199
+ :uri_suffix => path,
200
+ :query => "foo=bar"
201
+ end
202
+
203
+ @player.compare "example.com", "beta-example.com", :query => "foo=bar"
204
+
205
+ assert_equal 5, @player.output.result_calls
206
+ end
207
+
208
+
209
+ def test_request_single
210
+ io = StringIO.new(mock_200_response)
211
+ expect_request_output mock_200_response
212
+
213
+ @player.request io
214
+ end
215
+
216
+
217
+ def test_request
218
+ @player.concurrency = 3
219
+ @player.input.parser = Kronk::Player::RequestParser
220
+ @player.input.io << "/req3\n/req4\n/req5\n"
221
+ @player.input.io.rewind
222
+ @player.input.io.close_write
223
+
224
+ @player.queue.concat [{:uri_suffix => "/req1"}, {:uri_suffix => "/req2"}]
225
+
226
+ part1 = (1..2).map{|n| "/req#{n}"}
227
+ part2 = (3..5).map{|n| "/req#{n}"}
228
+
229
+ part1.each do |path|
230
+ mock_requests "example.com",
231
+ :uri_suffix => path,
232
+ :query => "foo=bar"
233
+ end
234
+
235
+ part2.each do |path|
236
+ mock_requests "example.com",
237
+ :uri_suffix => path,
238
+ :query => "foo=bar"
239
+ end
240
+
241
+ @player.request "example.com", :query => "foo=bar"
242
+
243
+ assert_equal 5, @player.output.result_calls
244
+ end
245
+
246
+
247
+ def test_process_queue_interrupted
248
+ @player.concurrency = 0
249
+
250
+ @player.output.expects :start
251
+ @player.output.expects :completed
252
+
253
+ thread = Thread.new do
254
+ @player.process_queue
255
+ end
256
+
257
+ sleep 0.1
258
+ assert_exit 2 do
259
+ Process.kill 'INT', Process.pid
260
+ end
261
+
262
+ ensure
263
+ thread.kill
264
+ end
265
+
266
+
267
+ def test_process_queue
268
+ @player.concurrency = 10
269
+ requests = (1..20).map{|n| "request #{n}"}
270
+ @player.queue.concat requests.dup
271
+ @player.input.io.close
272
+
273
+ @player.output.expects :start
274
+ @player.output.expects :completed
275
+
276
+ start = Time.now
277
+ processed = []
278
+
279
+ @player.process_queue do |req|
280
+ processed << req
281
+ sleep 0.5
282
+ end
283
+
284
+ time_spent = (Time.now - start).to_i
285
+ assert_equal 1, time_spent
286
+ assert_equal 20, @player.count
287
+ assert @player.queue.empty?, "Expected queue to be empty"
288
+
289
+ processed.sort!{|r1, r2| r1.split.last.to_i <=> r2.split.last.to_i}
290
+ assert_equal requests, processed
291
+ end
292
+
293
+
294
+ def test_process_queue_from_io
295
+ @player.concurrency = 10
296
+ @player.output.expects :start
297
+ @player.output.expects :completed
298
+
299
+ @player.input.parser.stubs(:start_new?).returns true
300
+ @player.input.parser.stubs(:start_new?).with("").returns false
301
+
302
+ processed = []
303
+ start_time = 0
304
+ time_spent = 0
305
+
306
+ requests = (1..20).map{|n| "request #{n}\n"}
307
+ @player.from_io StringIO.new(requests.join)
308
+
309
+ start_time = Time.now
310
+ @player.process_queue do |req|
311
+ processed << req
312
+ sleep 0.5
313
+ end
314
+
315
+ time_spent = (Time.now - start_time).to_i
316
+
317
+ assert_equal 1, time_spent
318
+ assert_equal 20, @player.count
319
+ assert @player.queue.empty?, "Expected queue to be empty"
320
+
321
+ processed.sort! do |r1, r2|
322
+ r1.split.last.strip.to_i <=> r2.split.last.strip.to_i
323
+ end
324
+
325
+ assert_equal requests, processed
326
+ end
327
+
328
+
329
+ def test_single_request_from_io
330
+ @player.input.io = StringIO.new "mock request"
331
+ @player.input.parser.stubs(:start_new?).returns true
332
+ assert @player.single_request?, "Expected player to have one request"
333
+ end
334
+
335
+
336
+ def test_single_request_from_queue
337
+ @player.input.io = nil
338
+ assert @player.single_request?, "Expected player to have one request"
339
+ end
340
+
341
+
342
+ def test_not_single_request
343
+ @player.input.io = nil
344
+ @player.queue.concat Array.new(10, "mock request")
345
+ assert !@player.single_request?, "Expected player to have many requests"
346
+
347
+ @player.input.io = StringIO.new Array.new(5, "mock request").join("\n")
348
+ @player.queue.clear
349
+ @player.input.parser.expects(:start_new?).returns(true)
350
+
351
+ assert !@player.single_request?, "Expected player to have many requests"
352
+ end
353
+
354
+
355
+ def test_try_fill_queue_from_input
356
+ @player.input.stubs(:get_next).returns "mock_request"
357
+
358
+ @player.concurrency = 5
359
+ @player.number = 20
360
+
361
+ thread = @player.try_fill_queue
362
+ assert_equal Thread, thread.class
363
+
364
+ sleep 0.2
365
+ assert_equal Array.new(10, "mock_request"), @player.queue
366
+
367
+ @player.queue.slice!(8)
368
+
369
+ sleep 0.2
370
+ assert_equal Array.new(10, "mock_request"), @player.queue
371
+
372
+ ensure
373
+ thread.kill
374
+ end
375
+
376
+
377
+ def test_try_fill_queue_from_last
378
+ @player.input.stubs(:get_next).returns nil
379
+ @player.input.stubs(:eof?).returns false
380
+
381
+ @player.concurrency = 5
382
+ @player.queue << "mock_request"
383
+
384
+ thread = @player.try_fill_queue
385
+ assert_equal Thread, thread.class
386
+
387
+ sleep 0.2
388
+ assert_equal Array.new(10, "mock_request"), @player.queue
389
+
390
+ @player.queue.slice!(8)
391
+
392
+ sleep 0.2
393
+ assert_equal Array.new(10, "mock_request"), @player.queue
394
+
395
+ ensure
396
+ thread.kill
397
+ end
398
+
399
+
400
+ def test_try_fill_queue_no_input
401
+ @player.input.stubs(:eof?).returns true
402
+
403
+ @player.concurrency = 5
404
+ @player.queue << "mock_request"
405
+
406
+ thread = @player.try_fill_queue
407
+ assert_equal Thread, thread.class
408
+
409
+ sleep 0.2
410
+ assert_equal ["mock_request"], @player.queue
411
+
412
+ ensure
413
+ thread.kill
414
+ end
415
+
416
+
417
+ def test_next_request
418
+ @player.input.expects(:get_next).returns "NEXT ITEM"
419
+ assert_equal "NEXT ITEM", @player.next_request
420
+
421
+ @player.input.expects(:get_next).returns nil
422
+ @player.queue.concat ["FIRST ITEM", "QUEUE REPEAT"]
423
+ assert_equal "QUEUE REPEAT", @player.next_request
424
+
425
+ @player.input.expects(:get_next).returns nil
426
+ @player.queue.clear
427
+ @player.instance_variable_set "@last_req", "LAST REQ"
428
+ assert_equal "LAST REQ", @player.next_request
429
+
430
+ @player.input.expects(:get_next).returns nil
431
+ @player.queue.clear
432
+ @player.instance_variable_set "@last_req", nil
433
+ assert_equal Hash.new, @player.next_request
434
+ end
435
+
436
+
437
+ def test_process_compare
438
+ mock_thread = "mock_thread"
439
+ Thread.expects(:new).twice.yields.returns mock_thread
440
+ mock_thread.expects(:join).twice
441
+
442
+ resp1 = Kronk::Response.new mock_resp("200_response.json")
443
+ resp1.parser = JSON
444
+ resp2 = Kronk::Response.new mock_resp("200_response.txt")
445
+
446
+ req1 = Kronk::Request.new "example.com"
447
+ req2 = Kronk::Request.new "beta-example.com"
448
+
449
+ Kronk::Request.expects(:new).returns req2
450
+ Kronk::Request.expects(:new).returns req1
451
+
452
+ req1.expects(:retrieve).returns resp1
453
+ req2.expects(:retrieve).returns resp2
454
+
455
+ @got_results = nil
456
+
457
+ @player.output.expects(:result).with do |kronk, mutex|
458
+ @got_results = true
459
+ assert_equal @player.mutex, mutex
460
+ assert_equal Kronk::Diff.new(resp1.stringify, resp2.stringify).formatted,
461
+ kronk.diff.formatted
462
+ true
463
+ end
464
+
465
+ @player.process_compare "example.com", "beta-example.com",
466
+ :uri_suffix => "/test", :include_headers => true
467
+
468
+ assert @got_results, "Expected output to get results but didn't"
469
+ end
470
+
471
+
472
+ def test_process_compare_error
473
+ @got_results = []
474
+
475
+ @player.output.expects(:error).times(3).with do |error, kronk, mutex|
476
+ @got_results << error.class
477
+ assert_equal @player.mutex, mutex
478
+ assert_equal Kronk, kronk.class
479
+ true
480
+ end
481
+
482
+ errs = [Kronk::Exception, Kronk::Response::MissingParser, Errno::ECONNRESET]
483
+ errs.each do |eklass|
484
+ Kronk.any_instance.expects(:compare).raises eklass
485
+
486
+ @player.process_compare "example.com", "beta-example.com",
487
+ :uri_suffix => "/test", :include_headers => true
488
+ end
489
+
490
+ assert_equal errs, @got_results, "Expected output to get errors but didn't"
491
+ end
492
+
493
+
494
+ def test_process_compare_error_not_caught
495
+ Kronk.any_instance.expects(:compare).raises RuntimeError
496
+
497
+ assert_raises RuntimeError do
498
+ @player.process_compare "example.com", "beta-example.com",
499
+ :uri_suffix => "/test", :include_headers => true
500
+ end
501
+ end
502
+
503
+
504
+ def test_process_request
505
+ resp = Kronk::Response.new mock_resp("200_response.json")
506
+ resp.parser = JSON
507
+
508
+ req = Kronk::Request.new "example.com"
509
+ req.expects(:retrieve).returns resp
510
+
511
+ Kronk::Request.expects(:new).returns req
512
+
513
+ @got_results = nil
514
+
515
+ @player.output.expects(:result).with do |kronk, mutex|
516
+ @got_results = true
517
+ assert_equal @player.mutex, mutex
518
+ assert_equal resp, kronk.response
519
+ true
520
+ end
521
+
522
+ @player.process_request "example.com",
523
+ :uri_suffix => "/test", :include_headers => true
524
+
525
+ assert @got_results, "Expected output to get results but didn't"
526
+ end
527
+
528
+
529
+ def test_process_request_error
530
+ @got_results = []
531
+
532
+ @player.output.expects(:error).times(3).with do |error, kronk, mutex|
533
+ @got_results << error.class
534
+ assert_equal @player.mutex, mutex
535
+ assert_equal Kronk, kronk.class
536
+ true
537
+ end
538
+
539
+ errs = [Kronk::Exception, Kronk::Response::MissingParser, Errno::ECONNRESET]
540
+ errs.each do |eklass|
541
+ Kronk.any_instance.expects(:retrieve).raises eklass
542
+
543
+ @player.process_request "example.com",
544
+ :uri_suffix => "/test", :include_headers => true
545
+ end
546
+
547
+ assert_equal errs, @got_results, "Expected output to get errors but didn't"
548
+ end
549
+
550
+
551
+ def test_process_request_error_not_caught
552
+ Kronk.any_instance.expects(:retrieve).raises RuntimeError
553
+
554
+ assert_raises RuntimeError do
555
+ @player.process_request "example.com",
556
+ :uri_suffix => "/test", :include_headers => true
557
+ end
558
+ end
559
+
560
+
561
+ private
562
+
563
+ def mock_requests *setup
564
+ resp = []
565
+ req = []
566
+
567
+ opts = setup.length > 1 && Hash === setup.last ?
568
+ setup.delete_at(-1) : Hash.new
569
+
570
+ case setup.first
571
+ when Hash
572
+ hash = setup.first
573
+ req = hash.keys
574
+ resp = req.map{|k| hash[k]}
575
+
576
+ when String
577
+ req = setup
578
+ resp = [mock_resp("200_response.txt")] * setup.length
579
+ end
580
+
581
+ req.each_with_index do |r, i|
582
+ mock_req = "mock request"
583
+ mock_res = Kronk::Response.new resp[i]
584
+ Kronk::Request.stubs(:new).with(req[i], opts).returns mock_req
585
+ mock_req.stubs(:retrieve).returns mock_res
586
+ mock_req.stubs(:uri).returns nil
587
+ end
588
+ end
589
+ end