right_support 2.6.17 → 2.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +4 -0
- data/CHANGELOG.rdoc +37 -0
- data/Gemfile +29 -0
- data/Gemfile.lock +111 -0
- data/README.rdoc +2 -0
- data/Rakefile +62 -0
- data/VERSION +1 -0
- data/features/balancer_error_handling.feature +34 -0
- data/features/balancer_health_check.feature +33 -0
- data/features/continuous_integration.feature +51 -0
- data/features/continuous_integration_cucumber.feature +28 -0
- data/features/continuous_integration_rspec1.feature +28 -0
- data/features/continuous_integration_rspec2.feature +28 -0
- data/features/http_client_timeout.feature +19 -0
- data/features/serialization.feature +95 -0
- data/features/step_definitions/http_client_steps.rb +27 -0
- data/features/step_definitions/request_balancer_steps.rb +93 -0
- data/features/step_definitions/ruby_steps.rb +176 -0
- data/features/step_definitions/serialization_steps.rb +96 -0
- data/features/step_definitions/server_steps.rb +134 -0
- data/features/support/env.rb +138 -0
- data/features/support/file_utils_bundler_mixin.rb +45 -0
- data/lib/right_support/ci/java_cucumber_formatter.rb +22 -8
- data/lib/right_support/ci/java_spec_formatter.rb +26 -8
- data/lib/right_support/ci/rake_task.rb +3 -0
- data/lib/right_support/ci.rb +24 -0
- data/lib/right_support/crypto/signed_hash.rb +22 -0
- data/lib/right_support/data/serializer.rb +24 -2
- data/lib/right_support/net/address_helper.rb +20 -8
- data/lib/right_support/net/dns.rb +20 -8
- data/lib/right_support/net/http_client.rb +22 -0
- data/lib/right_support/net/request_balancer.rb +27 -21
- data/lib/right_support/net/s3_helper.rb +20 -8
- data/lib/right_support/net/ssl/open_ssl_patch.rb +22 -0
- data/lib/right_support/net/ssl.rb +20 -8
- data/lib/right_support/ruby/easy_singleton.rb +22 -0
- data/lib/right_support/ruby/object_extensions.rb +22 -0
- data/lib/right_support/ruby/string_extensions.rb +1 -1
- data/lib/right_support.rb +13 -10
- data/right_support.gemspec +180 -18
- data/right_support.rconf +8 -0
- data/spec/config/feature_set_spec.rb +83 -0
- data/spec/crypto/signed_hash_spec.rb +60 -0
- data/spec/data/hash_tools_spec.rb +471 -0
- data/spec/data/uuid_spec.rb +45 -0
- data/spec/db/cassandra_model_part1_spec.rb +84 -0
- data/spec/db/cassandra_model_part2_spec.rb +73 -0
- data/spec/db/cassandra_model_spec.rb +359 -0
- data/spec/fixtures/encrypted_priv_rsa.pem +30 -0
- data/spec/fixtures/good_priv_dsa.pem +12 -0
- data/spec/fixtures/good_priv_rsa.pem +15 -0
- data/spec/fixtures/good_pub_dsa.ssh +1 -0
- data/spec/fixtures/good_pub_rsa.pem +5 -0
- data/spec/fixtures/good_pub_rsa.ssh +1 -0
- data/spec/log/exception_logger_spec.rb +76 -0
- data/spec/log/filter_logger_spec.rb +8 -0
- data/spec/log/mixin_spec.rb +62 -0
- data/spec/log/multiplexer_spec.rb +54 -0
- data/spec/log/null_logger_spec.rb +36 -0
- data/spec/log/system_logger_spec.rb +92 -0
- data/spec/net/address_helper_spec.rb +57 -0
- data/spec/net/balancing/health_check_spec.rb +382 -0
- data/spec/net/balancing/round_robin_spec.rb +15 -0
- data/spec/net/balancing/sticky_policy_spec.rb +92 -0
- data/spec/net/dns_spec.rb +152 -0
- data/spec/net/http_client_spec.rb +171 -0
- data/spec/net/request_balancer_spec.rb +579 -0
- data/spec/net/s3_helper_spec.rb +160 -0
- data/spec/net/ssl_spec.rb +42 -0
- data/spec/net/string_encoder_spec.rb +58 -0
- data/spec/rack/log_setter_spec.rb +5 -0
- data/spec/rack/request_logger_spec.rb +68 -0
- data/spec/rack/request_tracker_spec.rb +5 -0
- data/spec/ruby/easy_singleton_spec.rb +72 -0
- data/spec/ruby/object_extensions_spec.rb +27 -0
- data/spec/ruby/string_extensions_spec.rb +98 -0
- data/spec/spec_helper.rb +181 -0
- data/spec/stats/activity_spec.rb +193 -0
- data/spec/stats/exceptions_spec.rb +123 -0
- data/spec/stats/helpers_spec.rb +603 -0
- data/spec/validation/openssl_spec.rb +37 -0
- data/spec/validation/ssh_spec.rb +39 -0
- metadata +218 -19
@@ -0,0 +1,152 @@
|
|
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) { ['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) { ['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) { ['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).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).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) { ['1.1.1.1', '2.2.2.2', '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).sort.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).sort.should == output.sort
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
context :resolve_with_hostnames do
|
139
|
+
context 'given common inputs' do
|
140
|
+
let(:endpoints) { ['www.example1.com','www.example2.com'] }
|
141
|
+
let(:output) { {'www.example1.com'=>['1.1.1.1', '2.2.2.2'],
|
142
|
+
'www.example2.com'=>['3.3.3.3', '4.4.4.4']} }
|
143
|
+
|
144
|
+
it 'resolves to IP addresses' do
|
145
|
+
mock_getaddrinfo('www.example1.com', ['1.1.1.1', '2.2.2.2'])
|
146
|
+
mock_getaddrinfo('www.example2.com', ['3.3.3.3', '4.4.4.4'])
|
147
|
+
subject.resolve_with_hostnames(endpoints).should == output
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RightSupport::Net::HTTPClient do
|
4
|
+
it 'has a distinct method for common HTTP verbs' do
|
5
|
+
@http_client = RightSupport::Net::HTTPClient.new()
|
6
|
+
@http_client.should respond_to(:get)
|
7
|
+
@http_client.should respond_to(:post)
|
8
|
+
@http_client.should respond_to(:put)
|
9
|
+
@http_client.should respond_to(:delete)
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'with defaults passed to initializer' do
|
13
|
+
before(:all) do
|
14
|
+
@http_client = RightSupport::Net::HTTPClient.new(:open_timeout=>999, :timeout=>101010,
|
15
|
+
:headers=>{:moo=>:bah})
|
16
|
+
end
|
17
|
+
|
18
|
+
context :process_query_string do
|
19
|
+
it 'process nil url and params' do
|
20
|
+
@http_client.instance_eval { process_query_string }.should == ''
|
21
|
+
end
|
22
|
+
it 'process empty String params' do
|
23
|
+
url = '/moo'
|
24
|
+
params = ''
|
25
|
+
@http_client.instance_eval { process_query_string(url, params) }.should == '/moo'
|
26
|
+
end
|
27
|
+
it 'process params just with question mark' do
|
28
|
+
url = '/moo'
|
29
|
+
params = '?'
|
30
|
+
@http_client.instance_eval { process_query_string(url, params) }.should == '/moo'
|
31
|
+
end
|
32
|
+
it 'process String params with question mark in the beginning' do
|
33
|
+
url = '/moo'
|
34
|
+
params = '?a=b'
|
35
|
+
@http_client.instance_eval { process_query_string(url, params) }.should == '/moo?a=b'
|
36
|
+
end
|
37
|
+
it 'process String params without question mark in the beginning' do
|
38
|
+
url = '/moo'
|
39
|
+
params = 'a=b&c=d'
|
40
|
+
@http_client.instance_eval { process_query_string(url, params) }.should == '/moo?a=b&c=d'
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'when converting with Addressable::URI' do
|
44
|
+
it 'process raw Hash params' do
|
45
|
+
url = '/moo'
|
46
|
+
params = {:a=>:b}
|
47
|
+
@http_client.instance_eval { process_query_string(url, params) }.should == '/moo?a=b'
|
48
|
+
end
|
49
|
+
it 'process Hash params with hash inside' do
|
50
|
+
url = '/moo'
|
51
|
+
params = {:a=>{:b=>:c}}
|
52
|
+
@http_client.instance_eval { process_query_string(url, params) }.should == '/moo?a[b]=c'
|
53
|
+
end
|
54
|
+
it 'process Hash params with array inside' do
|
55
|
+
url = '/moo'
|
56
|
+
params = {:a=>['b','c']}
|
57
|
+
@http_client.instance_eval { process_query_string(url, params) }.should == '/moo?a[0]=b&a[1]=c'
|
58
|
+
end
|
59
|
+
it 'process Hash params with nested array inside' do
|
60
|
+
url = '/moo'
|
61
|
+
params = {:a=>{:b=>:c,:d=>['e','f'],:g=>{:h=>'i'}},:j=>'k'}
|
62
|
+
@http_client.instance_eval { process_query_string(url, params) }.should ==
|
63
|
+
'/moo?a[b]=c&a[d][0]=e&a[d][1]=f&a[g][h]=i&j=k'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'when converting directly' do
|
68
|
+
before(:each) do
|
69
|
+
flexmock(@http_client).should_receive(:require_succeeds?).with('addressable/uri').and_return(false)
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'process raw Hash params' do
|
73
|
+
url = '/moo'
|
74
|
+
params = {:a=>:b}
|
75
|
+
@http_client.instance_eval { process_query_string(url, params) }.should == '/moo?a=b'
|
76
|
+
end
|
77
|
+
it 'process Hash params with hash inside' do
|
78
|
+
url = '/moo'
|
79
|
+
params = {:a=>{:b=>:c}}
|
80
|
+
@http_client.instance_eval { process_query_string(url, params) }.should == '/moo?a%5Bb%5D=c'
|
81
|
+
end
|
82
|
+
it 'process Hash params with array inside' do
|
83
|
+
url = '/moo'
|
84
|
+
params = {:a=>['b','c']}
|
85
|
+
@http_client.instance_eval { process_query_string(url, params) }.should == '/moo?a%5B%5D=b&a%5B%5D=c'
|
86
|
+
end
|
87
|
+
it 'process Hash params with nested array inside' do
|
88
|
+
url = '/moo'
|
89
|
+
params = {:a=>{:b=>:c,:d=>['e','f'],:g=>{:h=>'i'}},:j=>'k'}
|
90
|
+
@http_client.instance_eval { process_query_string(url, params) }.should ==
|
91
|
+
'/moo?a%5Bb%5D=c&a%5Bd%5D%5B%5D=e&a%5Bd%5D%5B%5D=f&a%5Bg%5D%5Bh%5D=i&j=k'
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context :request do
|
97
|
+
it 'uses default options on every request' do
|
98
|
+
p = {:method=>:get,
|
99
|
+
:timeout=>101010,
|
100
|
+
:open_timeout=>999,
|
101
|
+
:url=>'/moo', :headers=>{:moo=>:bah}}
|
102
|
+
flexmock(RestClient::Request).should_receive(:execute).with(p)
|
103
|
+
@http_client.get('/moo')
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'allows defaults to be overridden' do
|
107
|
+
p = {:method=>:get,
|
108
|
+
:timeout=>101010,
|
109
|
+
:open_timeout=>3,
|
110
|
+
:url=>'/moo', :headers=>{:joe=>:blow}}
|
111
|
+
flexmock(RestClient::Request).should_receive(:execute).with(p)
|
112
|
+
@http_client.get('/moo', :open_timeout=>3, :headers=>{:joe=>:blow})
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context :request do
|
118
|
+
before(:each) do
|
119
|
+
r = 'this is a short mock REST response'
|
120
|
+
flexmock(RestClient::Request).should_receive(:execute).and_return(r).by_default
|
121
|
+
@http_client = RightSupport::Net::HTTPClient.new()
|
122
|
+
end
|
123
|
+
|
124
|
+
context 'given just a URL' do
|
125
|
+
it 'succeeds' do
|
126
|
+
p = {:method=>:get,
|
127
|
+
:timeout=>RightSupport::Net::HTTPClient::DEFAULT_OPTIONS[:timeout],
|
128
|
+
:open_timeout=>RightSupport::Net::HTTPClient::DEFAULT_OPTIONS[:open_timeout],
|
129
|
+
:url=>'/moo', :headers=>{}}
|
130
|
+
flexmock(RestClient::Request).should_receive(:execute).with(p)
|
131
|
+
|
132
|
+
@http_client.get('/moo')
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
context 'given a URL and headers' do
|
137
|
+
it 'succeeds' do
|
138
|
+
p = {:method=>:get,
|
139
|
+
:timeout=>RightSupport::Net::HTTPClient::DEFAULT_OPTIONS[:timeout],
|
140
|
+
:open_timeout=>RightSupport::Net::HTTPClient::DEFAULT_OPTIONS[:open_timeout],
|
141
|
+
:url=>'/moo', :headers=>{:mrm=>1, :blah=>:foo}}
|
142
|
+
flexmock(RestClient::Request).should_receive(:execute).with(p)
|
143
|
+
|
144
|
+
@http_client.get('/moo', {:headers => {:mrm=>1, :blah=>:foo}})
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
context 'given a timeout, no headers, and a URL' do
|
150
|
+
it 'succeeds' do
|
151
|
+
p = {:method=>:get,
|
152
|
+
:timeout=>42,
|
153
|
+
:open_timeout => RightSupport::Net::HTTPClient::DEFAULT_OPTIONS[:open_timeout],
|
154
|
+
:url=>'/moo', :headers=>{}}
|
155
|
+
flexmock(RestClient::Request).should_receive(:execute).with(p)
|
156
|
+
|
157
|
+
@http_client.get('/moo', {:timeout => 42})
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
context 'given a URL and any other parameters' do
|
162
|
+
it 'succeeds' do
|
163
|
+
p = { :method=>:get, :timeout=>RightSupport::Net::HTTPClient::DEFAULT_OPTIONS[:timeout],
|
164
|
+
:url=>'/moo', :headers=>{},:open_timeout => 1, :payload=>{:foo => :bar} }
|
165
|
+
flexmock(RestClient::Request).should_receive(:execute).with(p)
|
166
|
+
|
167
|
+
@http_client.get('/moo', :open_timeout => 1, :payload=>{:foo => :bar})
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|