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,141 +0,0 @@
1
- require 'spec_helper'
2
-
3
- class InnocentVictim
4
- include RightSupport::Log::Mixin
5
- end
6
-
7
- class Bystander < InnocentVictim
8
- end
9
-
10
- module Parasite
11
- include RightSupport::Log::Mixin
12
- end
13
-
14
- class Host
15
- include Parasite
16
- end
17
-
18
- describe RightSupport::Log::Mixin do
19
- context 'when mixed into a module' do
20
- before(:each) do
21
- @victim = Host.new
22
- end
23
-
24
- it 'provides instance-level accesssor to hosts' do
25
- @victim.should respond_to(:logger)
26
- @victim.should respond_to(:logger=)
27
- @victim.logger.info 'haha'
28
- end
29
-
30
- it 'provides a module-method-level accessor' do
31
- Parasite.should respond_to(:logger)
32
- Parasite.should respond_to(:logger=)
33
- Parasite.logger.info 'haha'
34
- end
35
- end
36
-
37
- context 'when mixed into a base class' do
38
- before(:each) do
39
- @victim = InnocentVictim.new
40
- end
41
-
42
- it 'provides a class-level accessor' do
43
- @victim.class.should respond_to(:logger)
44
- @victim.class.should respond_to(:logger=)
45
- @victim.class.logger.info 'haha'
46
- end
47
-
48
- it 'provides an instance-level accessor' do
49
- @victim.should respond_to(:logger)
50
- @victim.should respond_to(:logger=)
51
- @victim.logger.info 'haha'
52
- end
53
-
54
- context :logger do
55
- context 'without a logger' do
56
- before(:each) do
57
- @victim.class.logger = nil
58
- end
59
-
60
- it 'uses the default logger' do
61
- flexmock(RightSupport::Log::Mixin.default_logger).should_receive(:info).twice.and_return(true)
62
- @victim.class.logger.info('lalalala').should be_true
63
- @victim.logger.info('lalalala').should be_true
64
- end
65
- end
66
-
67
- context 'with class logger' do
68
- before(:each) do
69
- @logger = mock_logger
70
- @victim.class.logger = @logger
71
- end
72
-
73
- it 'uses class logger' do
74
- @logger.should_receive(:info).and_return(true).twice
75
- @victim.class.logger.info('lalalala').should be_true
76
- @victim.logger.info('lalalala').should be_true
77
- end
78
-
79
- context 'with instance logger' do
80
- before(:each) do
81
- @instance_logger = mock_logger
82
- @victim.logger = @instance_logger
83
- end
84
-
85
- it 'uses instance logger' do
86
- @instance_logger.should_receive(:info).and_return(true).once
87
- @logger.should_receive(:info).never
88
- @victim.logger.info('lalalala').should be_true
89
- end
90
- end
91
- end
92
- end
93
- end
94
-
95
- context 'when inherited from a base class' do
96
- let(:base_logger) { flexmock('base-class logger') }
97
- let(:subclass_logger) { flexmock('derived-class logger') }
98
-
99
- after(:each) do
100
- InnocentVictim.logger = nil
101
- Bystander.logger = nil
102
- end
103
-
104
- it 'delegates to base class' do
105
- InnocentVictim.logger = base_logger
106
- base_logger.should_receive(:error).with('foo').once
107
-
108
- Bystander.logger.error('foo')
109
- end
110
-
111
- it 'allows override in child class' do
112
- InnocentVictim.logger = base_logger
113
- Bystander.logger = subclass_logger
114
- base_logger.should_receive(:error).never
115
- subclass_logger.should_receive(:error).with('foo').once
116
-
117
- Bystander.logger.error('foo')
118
- end
119
- end
120
-
121
- context 'given someone has defined Class#logger' do
122
- before(:all) do
123
- InnocentVictim.logger = nil
124
- class Class
125
- def logger
126
- raise "THIS SHOULD NEVER BE CALLED"
127
- end
128
- end
129
- end
130
-
131
- after(:all) do
132
- class Class
133
- remove_method :logger
134
- end
135
- end
136
-
137
- it 'should never delegate to Class#logger' do
138
- InnocentVictim.logger.info 'test log'
139
- end
140
- end
141
- end
@@ -1,54 +0,0 @@
1
- #
2
- # Copyright (c) 2009-2012 RightScale Inc
3
- #
4
- # Permission is hereby granted, free of charge, to any person obtaining
5
- # a copy of this software and associated documentation files (the
6
- # "Software"), to deal in the Software without restriction, including
7
- # without limitation the rights to use, copy, modify, merge, publish,
8
- # distribute, sublicense, and/or sell copies of the Software, and to
9
- # permit persons to whom the Software is furnished to do so, subject to
10
- # the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be
13
- # included in all copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
- # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
- # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
- # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
-
23
- require 'spec_helper'
24
-
25
- describe RightSupport::Log::Multiplexer do
26
-
27
- before(:all) do
28
- @target1 = RightSupport::Log::NullLogger.new
29
- @target2 = RightSupport::Log::NullLogger.new
30
- @target3 = RightSupport::Log::NullLogger.new
31
- @multiplexer = RightSupport::Log::Multiplexer.new(@target1, @target2, @target3)
32
- end
33
-
34
- it 'multiplexes method calls to all callers' do
35
- flexmock(@target1).should_receive(:some_method).with('arg', 'arg2').once
36
- flexmock(@target2).should_receive(:some_method).with('arg', 'arg2').once
37
- flexmock(@target3).should_receive(:some_method).with('arg', 'arg2').once
38
- @multiplexer.some_method('arg', 'arg2')
39
- end
40
-
41
- it 'returns the result returned by the first target' do
42
- flexmock(@target1).should_receive(:some_method).with('arg', 'arg2').and_return('res1').once
43
- flexmock(@target2).should_receive(:some_method).with('arg', 'arg2').and_return('res2').once
44
- flexmock(@target3).should_receive(:some_method).with('arg', 'arg2').and_return('res3').once
45
- @multiplexer.some_method('arg', 'arg2').should == 'res1'
46
- end
47
-
48
- it 'multiplexes #warn by undefining Object#warn' do
49
- flexmock(@target1).should_receive(:warn).with('arg').and_return('res1')
50
- flexmock(@target2).should_receive(:warn).with('arg').and_return('res2')
51
- flexmock(@target3).should_receive(:warn).with('arg').and_return('res3')
52
- @multiplexer.warn('arg').should == 'res1'
53
- end
54
- end
@@ -1,36 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe RightSupport::Log::NullLogger do
4
- before(:each) do
5
- @logger = RightSupport::Log::NullLogger.new
6
- end
7
-
8
- context 'log levels' do
9
- [:debug, :info, :warn, :error, :fatal].each do |method|
10
- it "responds to ##{method}" do
11
- block_called = false
12
- @logger.__send__(method, 'lalalala').should be_true
13
- @logger.__send__(method) { block_called = true ; 'lalalala' }.should be_true
14
- block_called.should be_true
15
- end
16
- end
17
- end
18
-
19
- context '<< method' do
20
- it 'responds like Logger' do
21
- (@logger << 'lalalala').should == 8
22
- end
23
- end
24
-
25
- context :close do
26
- it 'responds' do
27
- @logger.close.should be_nil
28
- end
29
-
30
- it 'is idempotent' do
31
- @logger.close.should be_nil
32
- @logger.close.should be_nil
33
- @logger.close.should be_nil
34
- end
35
- end
36
- end
@@ -1,49 +0,0 @@
1
- require ::File.expand_path('../../spec_helper', __FILE__)
2
- require 'stringio'
3
-
4
- describe RightSupport::Log::StepLevelLogger do
5
- context 'with a decorated logger' do
6
- let(:buffer) { ::StringIO.new }
7
-
8
- let(:decorated_logger) { ::Logger.new(buffer) }
9
-
10
- def try_all_levels(l)
11
- l.debug('debug')
12
- l.info('info')
13
- l.warn('warn')
14
- l.error('error')
15
- l.fatal('fatal')
16
- end
17
-
18
- context 'with default level' do
19
- subject { described_class.new(decorated_logger) }
20
-
21
- it 'passes all messages' do
22
- try_all_levels(subject)
23
- buffer.string.should =~ /debug.+info.+warn.+error.+fatal/m
24
- end
25
- end
26
-
27
- context 'with error level' do
28
- subject do
29
- s = described_class.new(decorated_logger)
30
- s.level = ::Logger::ERROR
31
- s
32
- end
33
-
34
- it 'passes error and fatal messages' do
35
- try_all_levels(subject)
36
- buffer.string.should_not =~ /debug/
37
- buffer.string.should_not =~ /info/
38
- buffer.string.should_not =~ /warn/
39
- buffer.string.should =~ /error.+fatal/m
40
- end
41
-
42
- it 'does not change level of decorated logger' do
43
- try_all_levels(decorated_logger)
44
- buffer.string.should =~ /debug.+info.+warn.+error.+fatal/m
45
- end
46
- end
47
-
48
- end
49
- end
@@ -1,172 +0,0 @@
1
- require 'spec_helper'
2
- require 'socket'
3
-
4
- # NOTE: this spec does not get defined or executed unless SystemLogger
5
- # is defined, which only happens if Ruby standard-library 'syslog' module is
6
- # available at runtime. Thus, the spec does not run on Windows.
7
- #
8
- # The selective execution is accomplished with a trailing 'if' for this
9
- # outermost describe block. Crude but effective. You have been warned!
10
- describe 'RightSupport::Log::SystemLogger' do
11
- subject { RightSupport::Log::SystemLogger }
12
-
13
- # Duplicate constants for easier reading
14
- SEVERITY_MAP = RightSupport::Log::SystemLogger::SEVERITY_MAP
15
- FACILITY_MAP = RightSupport::Log::SystemLogger::FACILITY_MAP
16
-
17
- after(:each) do
18
- subject.instance_eval { class_variable_set(:@@syslog, nil) }
19
- end
20
-
21
- context :local do
22
- before(:each) do
23
- @mock_syslog = flexmock(Syslog)
24
- #indicates we sent a bogus severity to syslog!
25
- @mock_syslog.should_receive(SEVERITY_MAP[Logger::UNKNOWN]).never
26
- flexmock(Syslog).should_receive(:open).and_return(@mock_syslog).by_default
27
- @mock_syslog.should_receive(:info).with('Connected to syslog: :local').once
28
- end
29
-
30
- context :initialize do
31
- context 'with :facility option' do
32
- FACILITY_MAP.each_pair do |name, const|
33
- it "should handle #{name}" do
34
- @mock_syslog.should_receive(:open).with('unit tests', nil, const).and_return(@mock_syslog)
35
- subject.new('unit tests', :facility=>name, :connection=>:local)
36
- end
37
- end
38
- end
39
- end
40
-
41
- context :add do
42
- context 'severity levels' do
43
- levels = { :debug=>:debug,
44
- :info=>:info, :warn=>:notice,
45
- :error=>:warning, :fatal=>:err }
46
-
47
- levels.each_pair do |logger_method, syslog_method|
48
- it "translates Logger##{logger_method} to Syslog##{syslog_method}" do
49
- @logger = subject.new('spec', :connection=>:local)
50
- @mock_syslog.should_receive(syslog_method).with('moo bah oink')
51
- @logger.__send__(logger_method, 'moo bah oink')
52
- end
53
- end
54
- end
55
-
56
- it 'escapes % characters to avoid confusing printf()' do
57
- @logger = subject.new('spec', :connection=>:local)
58
- @mock_syslog.should_receive(:info).with('All systems 100%% -- %%licious!')
59
-
60
- @logger.info('All systems 100% -- %licious!')
61
- end
62
-
63
- context 'given :split option' do
64
- it 'when true, splits multi-line messages' do
65
- @logger = subject.new('spec', :split=>true, :connection=>:local)
66
-
67
- actual = []
68
- @mock_syslog.should_receive(:info).and_return do |message|
69
- actual << message
70
- true
71
- end
72
-
73
- @logger.info("This is a\nmulti line\r\nlog message\n\rwith all kinds\n\n\rof stuff")
74
- actual.should == ["This is a", "multi line", "log message", "with all kinds", "of stuff"]
75
- end
76
-
77
- it 'when false, passes through multi-line messages' do
78
- @logger = subject.new('spec', :split=>false, :connection=>:local)
79
-
80
- actual = []
81
- @mock_syslog.should_receive(:info).and_return do |message|
82
- actual << message
83
- true
84
- end
85
-
86
- msg = "This is a\nmulti line\r\nlog message\n\rwith all kinds\n\n\rof stuff"
87
- @logger.info(msg)
88
- actual.should == [msg]
89
- end
90
- end
91
-
92
- context 'given :color option' do
93
- it 'when true, passes through ANSI color codes' do
94
- @logger = subject.new('spec', :color=>true, :connection=>:local)
95
-
96
- actual = []
97
- @mock_syslog.should_receive(:info).and_return do |message|
98
- actual << message
99
- true
100
- end
101
-
102
- msg = "This has \e[16;32mcolor\e[7;0m inside it!"
103
- @logger.info(msg)
104
- actual.should == [msg]
105
- end
106
-
107
- it 'when false, strips out ANSI color codes' do
108
- @logger = subject.new('spec', :color=>false, :connection=>:local)
109
-
110
- actual = []
111
- @mock_syslog.should_receive(:info).and_return do |message|
112
- actual << message
113
- true
114
- end
115
-
116
- @logger.info("This has \e[16;32mcolor\e[7;0m inside it!")
117
- actual.should == ['This has color inside it!']
118
- end
119
- end
120
- end
121
- end
122
-
123
- context :remote do
124
- it 'sends protocol-formatted messages to a syslog service' do
125
- server = ::TCPServer.new(2345)
126
- data = nil
127
- ::Thread.start do
128
- client = server.accept
129
- data = client.readline
130
- client.close
131
- end
132
- logger = subject.new('spec', :connection=>'tcp://localhost:2345')
133
- stop_time = ::Time.now + 3
134
- while data.nil?
135
- sleep(0.1)
136
- fail 'Did not receive expected data' if ::Time.now >= stop_time
137
- end
138
-
139
- # example: "<134> Sep 23 13:45:42 ubuntu spec[3891]: Connected to syslog: \"tcp://localhost:2345\"\n"
140
- regex = /^<134> \w+ \d+ \d+:\d+:\d+ .+ spec\[\d+\]: Connected to syslog: \"tcp:\/\/localhost:2345\"$/
141
- data.chomp.should match(regex)
142
-
143
- # attempt to reconnect to closed server.
144
- server.close
145
- server = nil
146
- data = nil
147
- ::Thread.start do
148
- sleep 1 # should cause 1-2 reconnect error(s) to appear in STDERR
149
- server = ::TCPServer.new(2345)
150
- client = server.accept
151
- data = client.readline
152
- client.close
153
- server.close
154
- server = nil
155
- end
156
-
157
- # explicitly reconnect and send with delayed server restart. reconnection
158
- # happens automagically (only for remote) but explicit reconnection will
159
- # reestablish the PID, etc., which is useful for forking.
160
- logger.reconnect
161
- logger.debug("Hello syslog")
162
- stop_time = ::Time.now + 3
163
- while data.nil?
164
- sleep(0.1)
165
- fail 'Did not receive expected data' if ::Time.now >= stop_time
166
- end
167
- regex = /^<135> \w+ \d+ \d+:\d+:\d+ .+ spec\[\d+\]: Hello syslog$/
168
- data.chomp.should match(regex)
169
- end
170
- end
171
-
172
- end if defined?(RightSupport::Log::SystemLogger)
@@ -1,57 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe RightSupport::Net::AddressHelper do
4
- class AddressHelperTarget
5
- include RightSupport::Net::AddressHelper
6
- end
7
-
8
- before(:each) do
9
- @helper = AddressHelperTarget.new
10
- end
11
-
12
- describe :my_ipv4_addresses do
13
-
14
- end
15
-
16
- describe :my_ipv4_address do
17
- it 'consistently chooses the lowest-numbered address' do
18
- p = ['10.0.1.17', '192.168.7.5', '192.168.4.2', '127.0.0.1']
19
- flexmock(@helper).should_receive(:local_routable_address).with(Socket::AF_INET).and_return(p[0])
20
- flexmock(@helper).should_receive(:local_hostname_addresses).with(Socket::AF_INET).once.ordered.and_return([ p[3], p[2] ])
21
- flexmock(@helper).should_receive(:local_hostname_addresses).with(Socket::AF_INET).once.ordered.and_return([ p[1], p[2] ])
22
-
23
- one = @helper.my_ipv4_address(:private)
24
- two = @helper.my_ipv4_address(:private)
25
- one.should == p[0]
26
- two.should == p[0]
27
- end
28
- end
29
-
30
- describe :my_ipv4_addresses do
31
- before(:each) do
32
- routable_addr = '67.2.204.5'
33
- hostname_addrs = ['127.0.0.1', '10.0.0.15', '67.2.204.5']
34
- flexmock(@helper).should_receive(:local_routable_address).with(Socket::AF_INET).and_return(routable_addr)
35
- flexmock(@helper).should_receive(:local_hostname_addresses).with(Socket::AF_INET).and_return(hostname_addrs)
36
- flexmock(@helper).should_receive(:local_hostname_addresses).with(Socket::AF_INET).and_return(hostname_addrs)
37
- end
38
-
39
- context 'with :loopback option' do
40
- it 'returns only loopback addresses' do
41
- @helper.my_ipv4_addresses(:loopback).should == ['127.0.0.1']
42
- end
43
- end
44
-
45
- context 'with :private option' do
46
- it 'returns only private addresses' do
47
- @helper.my_ipv4_addresses(:private).should == ['10.0.0.15']
48
- end
49
- end
50
-
51
- context 'with :public option' do
52
- it 'returns only public addresses' do
53
- @helper.my_ipv4_addresses(:public).should == ['67.2.204.5']
54
- end
55
- end
56
- end
57
- end
data/spec/net/dns_spec.rb DELETED
@@ -1,187 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe RightSupport::Net::DNS do
4
- include SpecHelper::SocketMocking
5
-
6
- subject { RightSupport::Net::DNS } #the module itself
7
-
8
- context :resolve_all_ip_addresses do
9
- before(:all) do
10
- @hostnames = ['1.1.1.1', '2.2.2.2', '3.3.3.3']
11
- @hostnames .each do |hostname|
12
- flexmock(Socket).should_receive(:getaddrinfo).with(hostname, 443, Socket::AF_INET, Socket::SOCK_STREAM, Socket::IPPROTO_TCP).once.and_return([[0,0,0,hostname]])
13
- end
14
- end
15
- it 'resolves all ip addresses for specified array of endpoints' do
16
- @resolved_hostnames = subject.resolve_all_ip_addresses(@hostnames)
17
- (@resolved_hostnames - @hostnames).should be_eql([])
18
- end
19
- end
20
-
21
-
22
- context :resolve do
23
- context 'given default :retry => 3' do
24
- let(:endpoint) { 'www.example.com' }
25
- let(:output) { [RightSupport::Net::ResolvedEndpoint.new(['1.1.1.1', '2.2.2.2'])] }
26
-
27
- it 'retries SocketError' do
28
- mock_getaddrinfo('www.example.com', SocketError)
29
- mock_getaddrinfo('www.example.com', ['1.1.1.1', '2.2.2.2'])
30
-
31
- subject.resolve(endpoint).should == output
32
- end
33
-
34
- it 'stops retrying SocketError after three attempts' do
35
- mock_getaddrinfo('www.example.com', SocketError, 3)
36
-
37
- expect { subject.resolve(endpoint) }.to raise_error(SocketError)
38
- end
39
-
40
- it 'does not rescue other exceptions' do
41
- mock_getaddrinfo('www.example.com', ArgumentError)
42
-
43
- expect { subject.resolve(endpoint) }.to raise_error(ArgumentError)
44
- end
45
- end
46
-
47
- context 'given :retry => 0' do
48
- it 'does not retry SocketError' do
49
- mock_getaddrinfo('www.example.com', SocketError)
50
-
51
- expect { subject.resolve('www.example.com', :retry=>0) }.to raise_error(SocketError)
52
- end
53
- end
54
-
55
- context 'given various endpoint formats' do
56
- context 'e.g. a DNS hostname' do
57
- let(:endpoint) { 'www.example.com' }
58
- let(:output) { [RightSupport::Net::ResolvedEndpoint.new(['1.1.1.1', '2.2.2.2'])] }
59
-
60
- it 'resolves to IP addresses' do
61
- mock_getaddrinfo('www.example.com', ['1.1.1.1', '2.2.2.2'])
62
- subject.resolve(endpoint).should == output
63
- end
64
- end
65
-
66
- context 'e.g. an IPv4 address' do
67
- let(:endpoint) { '127.0.0.1' }
68
- let(:output) { [RightSupport::Net::ResolvedEndpoint.new(['127.0.0.1'])] }
69
-
70
- it 'resolves to the same address' do
71
- mock_getaddrinfo('127.0.0.1', ['127.0.0.1'])
72
- subject.resolve(endpoint).should == output
73
- end
74
- end
75
-
76
- context 'e.g. an HTTP URL' do
77
- let(:endpoint) { 'http://www.example.com' }
78
- let(:output) { ['http://1.1.1.1', 'http://2.2.2.2'] }
79
-
80
- it 'resolves to URLs with addresses substituted' do
81
- mock_getaddrinfo('www.example.com', ['1.1.1.1', '2.2.2.2'])
82
- subject.resolve(endpoint).first.addrs.should == output
83
- end
84
-
85
- context 'with a path component' do
86
- let(:endpoint) { 'http://www.example.com/foo/bar' }
87
- let(:output) { ['http://1.1.1.1/foo/bar', 'http://2.2.2.2/foo/bar'] }
88
-
89
- it 'resolves to URLs with path component preserved' do
90
- mock_getaddrinfo('www.example.com', ['1.1.1.1', '2.2.2.2'])
91
- subject.resolve(endpoint).first.addrs.should == output
92
- end
93
- end
94
- end
95
-
96
- # The double slash in a URI indicates that an authority follows. The authority
97
- # is interpreted as a hostname for most URL schemes we are interested in. We
98
- # can't deal with URLs unless they have a clear authority/hostname that we
99
- # can substitute.
100
- #
101
- # For more information, see: http://tools.ietf.org/html/rfc3986#section-3
102
- context 'e.g. a URI without an authority' do
103
- let(:endpoint) { 'urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66' }
104
-
105
- it 'raises URI::InvalidURIError' do
106
- lambda do
107
- subject.resolve(endpoint)
108
- end.should raise_error(URI::InvalidURIError)
109
- end
110
- end
111
-
112
- context 'e.g. several hostnames' do
113
- let(:endpoints) { ['www.example.com', 'www.example.net'] }
114
- let(:output) { [RightSupport::Net::ResolvedEndpoint.new(['1.1.1.1', '2.2.2.2']), RightSupport::Net::ResolvedEndpoint.new(['3.3.3.3', '4.4.4.4'])] }
115
-
116
- it 'resolves to IP addresses' do
117
- mock_getaddrinfo('www.example.com', ['1.1.1.1', '2.2.2.2'])
118
- mock_getaddrinfo('www.example.net', ['3.3.3.3', '4.4.4.4'])
119
-
120
- subject.resolve(endpoints).should == output
121
- end
122
- end
123
-
124
- context 'e.g. several HTTP URLs' do
125
- let(:endpoints) { ['http://www.example.com', 'http://www.example.net'] }
126
- let(:output) { ['http://1.1.1.1', 'http://2.2.2.2', 'http://3.3.3.3', 'http://4.4.4.4'] }
127
-
128
- it 'resolves to URLs with addresses substituted' do
129
- mock_getaddrinfo('www.example.com', ['1.1.1.1', '2.2.2.2'])
130
- mock_getaddrinfo('www.example.net', ['3.3.3.3', '4.4.4.4'])
131
-
132
- subject.resolve(endpoints).map {|ep| ep.addrs}.flatten == output
133
- end
134
- end
135
- end
136
-
137
- context 'requesting CIDR blocks' do
138
- context 'DNS resolvable addresses' do
139
- let(:endpoint) { 'www.example.com' }
140
- let(:output) { ['1.1.1.1/32', '2.2.2.2/32'] }
141
-
142
- it 'resolves hostname to CIDR /32 blocks' do
143
- mock_getaddrinfo('www.example.com', ['1.1.1.1', '2.2.2.2'])
144
- subject.resolve(endpoint).first.blocks.should == output
145
- end
146
-
147
- it 'resolves IP addresses to CIDR /32 blocks' do
148
- mock_getaddrinfo('1.1.1.1', ['1.1.1.1'])
149
- mock_getaddrinfo('2.2.2.2', ['2.2.2.2'])
150
- subject.resolve(['1.1.1.1', '2.2.2.2']).map {|endpoint| endpoint.blocks}.flatten.should =~ output
151
- end
152
-
153
- it 'refuses to resolve a URI having a CIDR block < /32' do
154
- lambda do
155
- subject.resolve("http://cf-mirror.rightscale.com")
156
- end.should raise_error(URI::InvalidURIError)
157
- end
158
- end
159
-
160
- context 'Static CIDR blocks' do
161
- let(:endpoint) { 'cf-mirror.rightscale.com' }
162
-
163
- it 'resolves hostname to static CIDR blocks' do
164
- subject.resolve(endpoint).first.blocks.each do |addr|
165
- # Addresses should all be in CIDR form and not single /32 addresses
166
- addr.should =~ /^\d+(?:\.\d+){3}\/(?:#{1.upto(31).to_a.join('|')})$/
167
- end
168
- end
169
- end
170
- end
171
- end
172
-
173
- context :resolve_with_hostnames do
174
- context 'given common inputs' do
175
- let(:endpoints) { ['www.example1.com','www.example2.com'] }
176
- let(:output) { {'www.example1.com'=>RightSupport::Net::ResolvedEndpoint.new(['1.1.1.1', '2.2.2.2']),
177
- 'www.example2.com'=>RightSupport::Net::ResolvedEndpoint.new(['3.3.3.3', '4.4.4.4'])} }
178
-
179
- it 'resolves to IP addresses' do
180
- mock_getaddrinfo('www.example1.com', ['1.1.1.1', '2.2.2.2'])
181
- mock_getaddrinfo('www.example2.com', ['3.3.3.3', '4.4.4.4'])
182
- subject.resolve_with_hostnames(endpoints).should == output
183
- end
184
- end
185
- end
186
-
187
- end