right_support 2.11.3 → 2.12.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +4 -0
  3. data/VERSION +1 -1
  4. data/lib/right_support/notifiers/airbrake.rb +194 -0
  5. data/lib/right_support/notifiers/base.rb +73 -0
  6. data/lib/right_support/notifiers/blacklisters/base.rb +48 -0
  7. data/lib/right_support/notifiers/blacklisters/canonical.rb +60 -0
  8. data/lib/right_support/notifiers/blacklisters/regular_expression.rb +86 -0
  9. data/{features/support/file_utils_bundler_mixin.rb → lib/right_support/notifiers/blacklisters/simple.rb} +21 -20
  10. data/lib/right_support/notifiers/blacklisters/snake_case.rb +60 -0
  11. data/lib/right_support/notifiers/blacklisters/wildcard.rb +65 -0
  12. data/lib/right_support/notifiers/blacklisters.rb +34 -0
  13. data/lib/right_support/notifiers/logger.rb +94 -0
  14. data/lib/right_support/notifiers/notification.rb +57 -0
  15. data/lib/right_support/notifiers/utilities/backtrace_decoder.rb +234 -0
  16. data/lib/right_support/notifiers/utilities.rb +29 -0
  17. data/lib/right_support/notifiers.rb +32 -0
  18. data/lib/right_support/rack/request_logger.rb +13 -9
  19. data/lib/right_support.rb +1 -0
  20. data/right_support.gemspec +19 -70
  21. metadata +17 -69
  22. data/.coveralls.yml +0 -2
  23. data/.rspec +0 -3
  24. data/.simplecov +0 -6
  25. data/.travis.yml +0 -13
  26. data/Gemfile +0 -51
  27. data/Gemfile.lock +0 -153
  28. data/features/balancer_error_handling.feature +0 -34
  29. data/features/balancer_health_check.feature +0 -33
  30. data/features/hash_tools.feature +0 -27
  31. data/features/http_client_timeout.feature +0 -19
  32. data/features/serialization.feature +0 -113
  33. data/features/step_definitions/hash_tools_steps.rb +0 -41
  34. data/features/step_definitions/http_client_steps.rb +0 -27
  35. data/features/step_definitions/request_balancer_steps.rb +0 -93
  36. data/features/step_definitions/ruby_steps.rb +0 -176
  37. data/features/step_definitions/serialization_steps.rb +0 -133
  38. data/features/step_definitions/server_steps.rb +0 -134
  39. data/features/support/env.rb +0 -148
  40. data/right_support.rconf +0 -9
  41. data/spec/config/feature_set_spec.rb +0 -83
  42. data/spec/crypto/signed_hash_spec.rb +0 -73
  43. data/spec/data/hash_tools_spec.rb +0 -602
  44. data/spec/data/mash_spec.rb +0 -313
  45. data/spec/data/token_spec.rb +0 -21
  46. data/spec/data/uuid_spec.rb +0 -45
  47. data/spec/db/cassandra_model_part1_spec.rb +0 -84
  48. data/spec/db/cassandra_model_part2_spec.rb +0 -73
  49. data/spec/db/cassandra_model_spec.rb +0 -375
  50. data/spec/fixtures/encrypted_priv_rsa.pem +0 -30
  51. data/spec/fixtures/good_priv_dsa.pem +0 -12
  52. data/spec/fixtures/good_priv_rsa.pem +0 -15
  53. data/spec/fixtures/good_pub_dsa.ssh +0 -1
  54. data/spec/fixtures/good_pub_rsa.pem +0 -5
  55. data/spec/fixtures/good_pub_rsa.ssh +0 -1
  56. data/spec/log/exception_logger_spec.rb +0 -76
  57. data/spec/log/filter_logger_spec.rb +0 -66
  58. data/spec/log/mixin_spec.rb +0 -141
  59. data/spec/log/multiplexer_spec.rb +0 -54
  60. data/spec/log/null_logger_spec.rb +0 -36
  61. data/spec/log/step_level_logger_spec.rb +0 -49
  62. data/spec/log/system_logger_spec.rb +0 -172
  63. data/spec/net/address_helper_spec.rb +0 -57
  64. data/spec/net/dns_spec.rb +0 -187
  65. data/spec/net/http_client_spec.rb +0 -181
  66. data/spec/net/lb/health_check_spec.rb +0 -417
  67. data/spec/net/lb/round_robin_spec.rb +0 -15
  68. data/spec/net/lb/sticky_spec.rb +0 -92
  69. data/spec/net/request_balancer_spec.rb +0 -690
  70. data/spec/net/s3_helper_spec.rb +0 -160
  71. data/spec/net/ssl_spec.rb +0 -42
  72. data/spec/net/string_encoder_spec.rb +0 -58
  73. data/spec/rack/log_setter_spec.rb +0 -5
  74. data/spec/rack/request_logger_spec.rb +0 -225
  75. data/spec/rack/request_tracker_spec.rb +0 -115
  76. data/spec/rack/runtime_spec.rb +0 -49
  77. data/spec/ruby/easy_singleton_spec.rb +0 -72
  78. data/spec/ruby/object_extensions_spec.rb +0 -27
  79. data/spec/ruby/string_extensions_spec.rb +0 -98
  80. data/spec/spec_helper.rb +0 -188
  81. data/spec/stats/activity_spec.rb +0 -425
  82. data/spec/stats/exceptions_spec.rb +0 -247
  83. data/spec/stats/helpers_spec.rb +0 -685
  84. data/spec/validation/openssl_spec.rb +0 -37
  85. data/spec/validation/ssh_spec.rb +0 -39
@@ -1,690 +0,0 @@
1
- require 'spec_helper'
2
-
3
- class TestException < Exception; end
4
- class OtherTestException < Exception; end
5
- class BigDeal < TestException; end
6
- class NoBigDeal < TestException; end
7
-
8
- class MockHttpError < Exception
9
- attr_reader :http_code
10
- def initialize(message=nil, code=400)
11
- super(message)
12
- @http_code = code
13
- end
14
- end
15
-
16
- class MockResourceNotFound < MockHttpError
17
- def initialize(message=nil)
18
- super(message, 404)
19
- end
20
- end
21
-
22
- class MockRequestTimeout < MockHttpError
23
- def initialize(message=nil)
24
- super(message, 408)
25
- end
26
- end
27
-
28
- describe RightSupport::Net::RequestBalancer do
29
- def test_raise(fatal, do_raise, expect)
30
- bases = []
31
- base = do_raise.superclass
32
- while base != Exception
33
- bases << base
34
- base = base.superclass
35
- end
36
-
37
- exception = expect.first
38
- count = expect.last
39
- rb = described_class.new([1,2,3], :fatal=>fatal)
40
- @tries = 0
41
-
42
- code = lambda do
43
- rb.request do |_|
44
- @tries += 1
45
- next unless do_raise
46
- if bases.include?(RestClient::ExceptionWithResponse)
47
- #Special case: RestClient exceptions need an HTTP response, but they
48
- #have stack recursion if we give them something other than a real
49
- #HTTP response. Blech!
50
- raise do_raise, nil
51
- else
52
- #Generic exception with message
53
- raise do_raise, 'Bah humbug; fie on thee!'
54
- end
55
- end
56
- end
57
-
58
- if exception
59
- code.should raise_error(expect[0])
60
- else
61
- code.should_not raise_error
62
- end
63
-
64
- @tries.should == count
65
- end
66
-
67
- def test_bad_endpoint_requests(number_of_endpoints)
68
- test = Proc.new do |endpoint|
69
- @health_checks += 1
70
- false
71
- end
72
-
73
- expect = number_of_endpoints
74
- yellow_states = 4
75
- rb = described_class.new(
76
- (1..expect).to_a,
77
- :policy => RightSupport::Net::LB::HealthCheck,
78
- :health_check => test,
79
- :yellow_states => yellow_states)
80
- @health_checks = 0
81
- tries = 0
82
- l = lambda do
83
- rb.request do |endpoint|
84
- tries += 1
85
- raise Exception
86
- end
87
- end
88
- yellow_states.times do
89
- l.should raise_error
90
- end
91
- tries.should == expect
92
- @health_checks.should == expect * (yellow_states - 1)
93
- end
94
-
95
- def make_endpoint(addresses)
96
- RightSupport::Net::ResolvedEndpoint.new(addresses)
97
- end
98
-
99
- context :initialize do
100
- it 'requires a list of endpoint URLs' do
101
- lambda do
102
- described_class.new(nil)
103
- end.should raise_exception(ArgumentError)
104
- end
105
-
106
- context 'with Integer :retry option' do
107
- [1, 2].each do |retry_value|
108
- context "and :retry=#{retry_value}" do
109
- it "stops after #{retry_value} total tries" do
110
- lambda do
111
- # note the legacy :retry integer value has no backoff.
112
- @tries = 0
113
- described_class.new([1, 2, 3], :retry => retry_value).request do |u|
114
- @tries += 1
115
- raise NoBigDeal
116
- end
117
- end.should raise_error
118
- @tries.should == retry_value
119
- end
120
- end
121
- end
122
- end
123
-
124
- context 'with Proc :retry option' do
125
- it 'stops when call evaluates to false' do
126
- @tries = 0
127
-
128
- proc = Proc.new do |ep, n|
129
- @tries < 1
130
- end
131
-
132
- balancer = described_class.new([1, 2, 3], :retry => proc)
133
- lambda do
134
- balancer.request do |u|
135
- @tries += 1
136
- raise NoBigDeal
137
- end
138
- end.should raise_error(RightSupport::Net::NoResult)
139
-
140
- @tries.should == 1
141
- end
142
-
143
- [1, 2].each do |max_attempts|
144
- context "with backoff_retry_callback(#{max_attempts})" do
145
- it "stops after #{max_attempts} total tries" do
146
- start_time = ::Time.now
147
- retry_proc = described_class.backoff_retry_callback(max_attempts)
148
- lambda do
149
- @tries = 0
150
- described_class.new([1, 2, 3], :retry => retry_proc).request do |u|
151
- @tries += 1
152
- raise NoBigDeal
153
- end
154
- end.should raise_error
155
- end_time = ::Time.now
156
- @tries.should == max_attempts
157
- if max_attempts == 2
158
- ((end_time - start_time) >= 2).should be_true # assert backoff
159
- end
160
- end
161
- end
162
- end
163
- end
164
-
165
- context ':fatal option' do
166
- it 'has reasonable defaults' do
167
- exceptions = described_class::DEFAULT_FATAL_EXCEPTIONS - [SignalException]
168
- balancer = described_class.new([1])
169
- exceptions.each do |klass|
170
- lambda do
171
- balancer.request { |ep| raise klass }
172
- end.should raise_error(klass)
173
- end
174
- end
175
-
176
- context 'with a Proc' do
177
- it 'validates the arity' do
178
- bad_lambda = lambda { |too, many, arguments| }
179
- lambda do
180
- described_class.new([1,2], :fatal=>bad_lambda)
181
- end.should raise_error(ArgumentError)
182
- end
183
-
184
- it 'delegates to the Proc' do
185
- always_retry = lambda { |e| false }
186
- balancer = described_class.new([1,2], :fatal=>always_retry)
187
-
188
- lambda do
189
- balancer.request do |ep|
190
- raise BigDeal
191
- end
192
- end.should raise_error(RightSupport::Net::NoResult)
193
-
194
- lambda do
195
- balancer.request do |ep|
196
- raise ArgumentError
197
- end
198
- end.should raise_error(RightSupport::Net::NoResult)
199
- end
200
- end
201
-
202
- context 'with an Exception' do
203
- it 'considers that class of Exception to be fatal' do
204
- balancer = described_class.new([1], :fatal=>BigDeal)
205
- lambda do
206
- balancer.request { |ep| raise BigDeal }
207
- end.should raise_error(BigDeal)
208
- end
209
- end
210
-
211
- context 'with an Array' do
212
- it 'considers any class in the array to be fatal' do
213
- exceptions = [ArgumentError, BigDeal]
214
- balancer = described_class.new([1], :fatal=>exceptions)
215
- exceptions.each do |klass|
216
- lambda do
217
- balancer.request { |ep| raise klass }
218
- end.should raise_error(klass)
219
- end
220
- end
221
- end
222
- end
223
-
224
- context 'with :on_exception option' do
225
- it 'validates the arity' do
226
- bad_lambda = lambda { |way, too, many, arguments| }
227
- lambda do
228
- described_class.new([1,2], :on_exception=>bad_lambda)
229
- end.should raise_error(ArgumentError)
230
- end
231
- end
232
-
233
- context 'with :policy option' do
234
- it 'accepts a Class' do
235
- policy = RightSupport::Net::LB::RoundRobin
236
- lambda {
237
- described_class.new([1,2], :policy=>policy)
238
- }.should_not raise_error
239
- end
240
-
241
- it 'accepts an object' do
242
- policy = RightSupport::Net::LB::RoundRobin.new([1,2])
243
- lambda {
244
- described_class.new([1,2], :policy=>policy)
245
- }.should_not raise_error
246
- end
247
-
248
- it 'checks for duck-type compatibility' do
249
- lambda {
250
- described_class.new([1,2], :policy=>String)
251
- }.should raise_error
252
- lambda {
253
- described_class.new([1,2], :policy=>'I like cheese')
254
- }.should raise_error
255
- end
256
- end
257
-
258
- context 'with :health_check option' do
259
- before(:each) do
260
- @health_check = Proc.new {|endpoint| "HealthCheck passed for #{endpoint}!" }
261
- end
262
-
263
- it 'accepts a block' do
264
- lambda {
265
- described_class.new([1,2], :health_check => @health_check)
266
- }.should_not raise_error
267
- end
268
-
269
- it 'calls specified block' do
270
- @balancer = described_class.new([1,2], :health_check => @health_check)
271
- @options = @balancer.instance_variable_get("@options")
272
- @options[:health_check].call(1).should be_eql("HealthCheck passed for 1!")
273
- end
274
-
275
- end
276
-
277
- context 'with default :health_check option' do
278
- it 'calls default block' do
279
- @balancer = described_class.new([1,2])
280
- @options = @balancer.instance_variable_get("@options")
281
- @options[:health_check].call(1).should be_true
282
- end
283
- end
284
-
285
- context 'with :on_health_change option' do
286
- before(:each) do
287
- @health_updates = []
288
- @on_health_change = Proc.new {|health| @health_updates << health }
289
- end
290
-
291
- it 'accepts a block' do
292
- lambda {
293
- described_class.new([1,2], :on_health_change => @on_health_change)
294
- }.should_not raise_error
295
- end
296
- end
297
-
298
- context 'with :resolve option' do
299
- before(:each) do
300
- flexmock(RightSupport::Net::DNS).should_receive(:resolve_with_hostnames).
301
- with(['host1', 'host2']).and_return({'host1' => make_endpoint(['1.1.1.1', '2.2.2.2']), 'host2' => make_endpoint(['3.3.3.3'])})
302
- @balancer = described_class.new(['host1', 'host2'], :resolve => 15)
303
- end
304
-
305
- it 'performs an initial resolution' do
306
- @balancer.instance_variable_get("@resolved_at").to_f.should be_within(1.0).of(Time.now.to_f)
307
- @balancer.instance_variable_get("@ips").should include('1.1.1.1')
308
- @balancer.instance_variable_get("@ips").should include('2.2.2.2')
309
- @balancer.instance_variable_get("@ips").should include('3.3.3.3')
310
- end
311
-
312
- it 'reports on the resolved endpoints' do
313
- @balancer.resolved_endpoints.sort.should == ['1.1.1.1', '2.2.2.2', '3.3.3.3']
314
- end
315
- end
316
- end
317
-
318
- context :request do
319
- it 'requires a block' do
320
- lambda do
321
- described_class.new([1]).request
322
- end.should raise_exception(ArgumentError)
323
- end
324
-
325
- context 'with a single thread' do
326
- let(:list) { [1,2,3,4,5,6,7,8,9,10] }
327
-
328
- subject { described_class.new(list) }
329
-
330
- it 'retries until a request completes' do
331
- queue = Queue.new
332
- 10.times do
333
- x = subject.request do |l|
334
- raise NoBigDeal, "Fall down go boom!" unless l == 5
335
- l
336
- end
337
- x.should == 5
338
- end
339
- end
340
- end
341
-
342
- context 'with multiple threads and thread-safety enabled' do
343
- let(:list) { [1,2,3,4,5,6,7,8,9,10] }
344
-
345
- def boom(ep)
346
- raise NoBigDeal, "Fall down go boom!" unless ep == 5
347
- true
348
- end
349
-
350
- subject do
351
- described_class.new(
352
- list,
353
- thread_safe: true,
354
- policy: ::RightSupport::Net::LB::HealthCheck,
355
- health_check: method(:boom))
356
- end
357
-
358
- it 'retries until a request completes' do
359
- count = list.size * 3
360
- expected_responses = nil
361
- expected_stats = list.inject({}) do |h, ep|
362
- begin
363
- boom(ep)
364
- h[ep] = 'green'
365
- expected_responses = [ep] * count
366
- rescue NoBigDeal
367
- h[ep] = 'red'
368
- end
369
- h
370
- end
371
-
372
- queue = Queue.new
373
- count.times do
374
- ::Thread.new do
375
- stop_time = ::Time.now + 10
376
- loop do
377
- begin
378
- x = subject.request do |ep|
379
- boom(ep)
380
- ep
381
- end
382
- queue.push(x)
383
- break
384
- rescue ::RightSupport::Net::NoResult => e
385
- # this can happen with too much thread contention for failing
386
- # endpoints. the issue is that other threads keep snaking the
387
- # only good endpoint away from this thread (i.e. keep
388
- # incrementing the counter in health-check policy) until the
389
- # allowed number of retries is exhausted. only when the other
390
- # threads die can we be sure of getting the only good endpoint.
391
- #
392
- # keep trying for the purpose of this test but do not allow
393
- # infinite retries.
394
- if ::Time.now >= stop_time
395
- queue.push(e)
396
- break
397
- end
398
- rescue ::Exception => e
399
- queue.push(e)
400
- break
401
- end
402
- end
403
- end
404
- end
405
- actual_responses = []
406
- count.times do
407
- actual_responses << queue.pop
408
- end
409
- actual_responses.should == expected_responses
410
- subject.get_stats.should == expected_stats
411
- end
412
- end
413
-
414
- it 'raises if no request completes' do
415
- lambda do
416
- described_class.request([1,2,3]) do |l|
417
- raise NoBigDeal, "Fall down go boom!"
418
- end
419
- end.should raise_exception(RightSupport::Net::NoResult, /NoBigDeal/)
420
- end
421
-
422
- context 'without :fatal option' do
423
- it 're-raises reasonable default fatal errors' do
424
- test_raise(nil, ArgumentError, [ArgumentError, 1])
425
- test_raise(nil, MockResourceNotFound, [MockResourceNotFound, 1])
426
- end
427
-
428
- it 'swallows StandardError and friends' do
429
- [SystemCallError, SocketError].each do |klass|
430
- test_raise(nil, klass, [RightSupport::Net::NoResult, 3])
431
- end
432
- end
433
- end
434
-
435
- context 'with :fatal option' do
436
- it 're-raises fatal errors' do
437
- test_raise(BigDeal, BigDeal, [BigDeal, 1])
438
- test_raise([BigDeal, NoBigDeal], NoBigDeal, [NoBigDeal, 1])
439
- test_raise(true, NoBigDeal, [NoBigDeal, 1])
440
- test_raise(lambda {|e| e.is_a? BigDeal }, BigDeal, [BigDeal, 1])
441
- end
442
-
443
- it 'swallows nonfatal errors' do
444
- test_raise(nil, BigDeal, [RightSupport::Net::NoResult, 3])
445
- test_raise(BigDeal, NoBigDeal, [RightSupport::Net::NoResult, 3])
446
- test_raise([BigDeal], NoBigDeal, [RightSupport::Net::NoResult, 3])
447
- test_raise(false, NoBigDeal, [RightSupport::Net::NoResult, 3])
448
- test_raise(lambda {|e| e.is_a? BigDeal }, NoBigDeal, [RightSupport::Net::NoResult, 3])
449
- end
450
- end
451
-
452
- context 'with default :fatal option' do
453
- it 'retries most Ruby builtin errors' do
454
- list = [1,2,3,4,5,6,7,8,9,10]
455
- rb = described_class.new(list)
456
-
457
- [IOError, SystemCallError, SocketError].each do |klass|
458
- test_raise(nil, klass, [RightSupport::Net::NoResult, 3])
459
- end
460
- end
461
-
462
- it 'does not retry program errors' do
463
- list = [1,2,3,4,5,6,7,8,9,10]
464
- rb = described_class.new(list)
465
-
466
- [ArgumentError, LoadError, NameError].each do |klass|
467
- test_raise(nil, klass, [klass, 1])
468
- end
469
- end
470
-
471
- it 'retries HTTP timeouts' do
472
- test_raise(nil, MockRequestTimeout, [RightSupport::Net::NoResult, 3])
473
- test_raise(nil, RestClient::RequestTimeout, [RightSupport::Net::NoResult, 3])
474
- end
475
-
476
- it 'does not retry HTTP 4xx other than timeout' do
477
- list = [1,2,3,4,5,6,7,8,9,10]
478
- rb = described_class.new(list)
479
-
480
- codes = [401, 402, 403, 404, 405, 406, 407, 409]
481
- codes.each do |code|
482
- lambda do
483
- rb.request { |l| raise MockHttpError.new(nil, code) }
484
- end.should raise_error(MockHttpError)
485
- end
486
- end
487
-
488
- context 'with default :retry option' do
489
- it 'marks endpoints as bad if they encounter retryable errors' do
490
- rb = described_class.new([1,2,3], :policy => RightSupport::Net::LB::HealthCheck, :health_check => Proc.new {|endpoint| false})
491
- expect = rb.get_stats
492
- codes = [401, 402, 403, 404, 405, 406, 407, 408, 409]
493
- codes.each do |code|
494
- lambda do
495
- rb.request { |l| raise MockHttpError.new(nil, code) }
496
- end.should raise_error
497
- end
498
-
499
- rb.get_stats.should_not == expect
500
- end
501
-
502
- it 'does not mark endpoints as bad if they raise fatal errors' do
503
- rb = described_class.new([1,2,3], :policy => RightSupport::Net::LB::HealthCheck, :health_check => Proc.new {|endpoint| false})
504
- codes = [401, 402, 403, 404, 405, 406, 407, 409]
505
- codes.each do |code|
506
- lambda do
507
- rb.request { |l| raise MockHttpError.new(nil, code) }
508
- end.should raise_error
509
- end
510
-
511
- # The EPs started in yellow-1, then passed an initial health check which
512
- # changed them to green, then executed a failing request, which should
513
- # not count against them. They should still be green.
514
- rb.get_stats.should == {1=>'green', 2=>'green', 3=>'green'}
515
- end
516
- end
517
- end
518
-
519
- context 'with :on_exception option' do
520
- before(:each) do
521
- @list = [1,2,3,4,5,6,7,8,9,10]
522
- @callback = flexmock('Callback proc')
523
- @callback.should_receive(:respond_to?).with(:call).and_return(true)
524
- @callback.should_receive(:respond_to?).with(:arity).and_return(true)
525
- @callback.should_receive(:arity).and_return(3)
526
- @rb = described_class.new(@list, :fatal=>BigDeal, :on_exception=>@callback)
527
- end
528
-
529
- it 'calls me back with fatal exceptions' do
530
- @callback.should_receive(:call).with(true, BigDeal, Integer)
531
- lambda {
532
- @rb.request { raise BigDeal }
533
- }.should raise_error(BigDeal)
534
- end
535
-
536
- it 'calls me back with nonfatal exceptions' do
537
- @callback.should_receive(:call).with(false, NoBigDeal, Integer)
538
- lambda {
539
- @rb.request { raise NoBigDeal }
540
- }.should raise_error(RightSupport::Net::NoResult)
541
-
542
- end
543
- end
544
-
545
- context 'given a class-level logger' do
546
- before(:all) do
547
- @logger = Logger.new(StringIO.new)
548
- described_class.logger = @logger
549
- RightSupport::Net::LB::HealthCheck.logger = @logger
550
- end
551
-
552
- after(:all) do
553
- described_class.logger = nil
554
- end
555
-
556
- context 'when a retryable exception is raised' do
557
- it 'logs an error' do
558
- flexmock(@logger).should_receive(:error).times(4)
559
-
560
- lambda {
561
- balancer = described_class.new([1,2,3])
562
- balancer.request do |ep|
563
- raise NoBigDeal, "Too many cows on the moon"
564
- end
565
- }.should raise_error(RightSupport::Net::NoResult)
566
- end
567
- end
568
-
569
- context 'when the health of an endpoint changes' do
570
- it 'logs the change' do
571
- health_check = Proc.new do |endpoint|
572
- false
573
- end
574
- flexmock(@logger).should_receive(:info).times(8)
575
-
576
- lambda {
577
- balancer = described_class.new([1,2,3,4], :policy => RightSupport::Net::LB::HealthCheck, :health_check => health_check)
578
- balancer.request do |ep|
579
- raise "Bad Endpoint"
580
- end
581
- }.should raise_error(RightSupport::Net::NoResult)
582
- end
583
- end
584
- end
585
-
586
- context 'given a class health check policy' do
587
- it 'retries and health checks the correct number of times' do
588
- (1..10).to_a.each {|endpoint| test_bad_endpoint_requests(endpoint) }
589
- end
590
- end
591
-
592
- context 'with :resolve option' do
593
- before(:each) do
594
- @endpoints = ['host1', 'host2', 'host3', 'host4']
595
- @resolved_set_1 = {'host1' => make_endpoint(['1.1.1.1', '2.2.2.2', '3.3.3.3', '4.4.4.4'])}
596
- @resolved_set_2 = {'host1'=> make_endpoint(['5.5.5.5']),'host2'=>make_endpoint(['6.6.6.6']),'host3'=>make_endpoint(['7.7.7.7']),'host4'=>make_endpoint(['8.8.8.8'])}
597
- @resolved_set_2_array = []
598
- @resolved_set_2.each_value{ |v| @resolved_set_2_array.concat(v.addrs) }
599
- @dns = flexmock(RightSupport::Net::DNS)
600
- end
601
-
602
- it 'resolves ip addresses for specified list of endpoints' do
603
- @dns.should_receive(:resolve_with_hostnames).with(@endpoints).and_return(@resolved_set_1)
604
- @rb = described_class.new(@endpoints, :resolve => 15)
605
-
606
- @rb.request { true }
607
- @policy = @rb.instance_variable_get("@policy")
608
- @resolved_set_1['host1'].addrs.include?(@policy.next.first).should be_true
609
- end
610
-
611
- it 're-resolves list of ip addresses if TTL is expired' do
612
- @dns.should_receive(:resolve_with_hostnames).with(@endpoints).twice.and_return(@resolved_set_1, @resolved_set_2)
613
- @rb = described_class.new(@endpoints, :resolve => 15)
614
-
615
- @rb.request { true }
616
- @policy = @rb.instance_variable_get("@policy")
617
- @resolved_set_1['host1'].addrs.include?(@policy.next.first).should be_true
618
-
619
- @rb.instance_variable_set("@resolved_at", Time.now.to_i - 16)
620
- @rb.request { true }
621
- @policy = @rb.instance_variable_get("@policy")
622
- @resolved_set_2_array.include?(@policy.next.first).should be_true
623
- end
624
- end
625
-
626
- context 'when a request raises NoResult' do
627
- before(:each) do
628
- @endpoints = [1,2,3,4,5,6]
629
- @exceptions = [BigDeal, NoBigDeal, OtherTestException]
630
- @rb = described_class.new(@endpoints)
631
- @tries = 0
632
- begin
633
- @rb.request do |ep|
634
- @tries += 1
635
- raise @exceptions[@tries % @exceptions.size]
636
- end
637
- rescue Exception => e
638
- @raised = e
639
- end
640
-
641
- @raised.should be_kind_of RightSupport::Net::NoResult
642
- end
643
-
644
- it 'provides detailed information about the exceptions' do
645
- # We should have details about all six endpoints
646
- @raised.details.should_not be_nil
647
- @raised.details.keys.size.should == 6
648
-
649
- # Three exception types across six endpoints, means we should
650
- # see each exception type appear twice
651
- seen = {}
652
- @raised.details.each_pair do |_, exceptions|
653
- exceptions.each do |exception|
654
- seen[exception.class] ||= []
655
- seen[exception.class] << exception
656
- end
657
- end
658
- seen.keys.size.should == 3
659
- seen.values.all? { |v| v.size == 2}.should be_true
660
- end
661
- end
662
- end
663
-
664
- context :get_stats do
665
- context 'using default balancing profile' do
666
- it 'returns stats in an endpoint-keyed hash' do
667
- expected_hash = {}
668
- list = [1,2,3,4]
669
- list.each { |k| expected_hash[k] = 'n/a' }
670
- rb = described_class.new(list)
671
-
672
- rb.get_stats.should_not be_nil
673
- rb.get_stats.should == expected_hash
674
- end
675
- end
676
-
677
- context 'using health check balancing profile' do
678
- it 'returns stats in an endpoint-keyed hash' do
679
- expected_hash = {}
680
- list = [1,2,3,4]
681
- rb = described_class.new(
682
- list,
683
- :policy => RightSupport::Net::LB::HealthCheck,
684
- :health_check => Proc.new {|endpoint| "HealthCheck passed for #{endpoint}!"})
685
- rb.get_stats.should_not be_nil
686
- rb.get_stats.should_not == expected_hash
687
- end
688
- end
689
- end
690
- end