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.
Files changed (83) hide show
  1. data/.rspec +4 -0
  2. data/CHANGELOG.rdoc +37 -0
  3. data/Gemfile +29 -0
  4. data/Gemfile.lock +111 -0
  5. data/README.rdoc +2 -0
  6. data/Rakefile +62 -0
  7. data/VERSION +1 -0
  8. data/features/balancer_error_handling.feature +34 -0
  9. data/features/balancer_health_check.feature +33 -0
  10. data/features/continuous_integration.feature +51 -0
  11. data/features/continuous_integration_cucumber.feature +28 -0
  12. data/features/continuous_integration_rspec1.feature +28 -0
  13. data/features/continuous_integration_rspec2.feature +28 -0
  14. data/features/http_client_timeout.feature +19 -0
  15. data/features/serialization.feature +95 -0
  16. data/features/step_definitions/http_client_steps.rb +27 -0
  17. data/features/step_definitions/request_balancer_steps.rb +93 -0
  18. data/features/step_definitions/ruby_steps.rb +176 -0
  19. data/features/step_definitions/serialization_steps.rb +96 -0
  20. data/features/step_definitions/server_steps.rb +134 -0
  21. data/features/support/env.rb +138 -0
  22. data/features/support/file_utils_bundler_mixin.rb +45 -0
  23. data/lib/right_support/ci/java_cucumber_formatter.rb +22 -8
  24. data/lib/right_support/ci/java_spec_formatter.rb +26 -8
  25. data/lib/right_support/ci/rake_task.rb +3 -0
  26. data/lib/right_support/ci.rb +24 -0
  27. data/lib/right_support/crypto/signed_hash.rb +22 -0
  28. data/lib/right_support/data/serializer.rb +24 -2
  29. data/lib/right_support/net/address_helper.rb +20 -8
  30. data/lib/right_support/net/dns.rb +20 -8
  31. data/lib/right_support/net/http_client.rb +22 -0
  32. data/lib/right_support/net/request_balancer.rb +27 -21
  33. data/lib/right_support/net/s3_helper.rb +20 -8
  34. data/lib/right_support/net/ssl/open_ssl_patch.rb +22 -0
  35. data/lib/right_support/net/ssl.rb +20 -8
  36. data/lib/right_support/ruby/easy_singleton.rb +22 -0
  37. data/lib/right_support/ruby/object_extensions.rb +22 -0
  38. data/lib/right_support/ruby/string_extensions.rb +1 -1
  39. data/lib/right_support.rb +13 -10
  40. data/right_support.gemspec +180 -18
  41. data/right_support.rconf +8 -0
  42. data/spec/config/feature_set_spec.rb +83 -0
  43. data/spec/crypto/signed_hash_spec.rb +60 -0
  44. data/spec/data/hash_tools_spec.rb +471 -0
  45. data/spec/data/uuid_spec.rb +45 -0
  46. data/spec/db/cassandra_model_part1_spec.rb +84 -0
  47. data/spec/db/cassandra_model_part2_spec.rb +73 -0
  48. data/spec/db/cassandra_model_spec.rb +359 -0
  49. data/spec/fixtures/encrypted_priv_rsa.pem +30 -0
  50. data/spec/fixtures/good_priv_dsa.pem +12 -0
  51. data/spec/fixtures/good_priv_rsa.pem +15 -0
  52. data/spec/fixtures/good_pub_dsa.ssh +1 -0
  53. data/spec/fixtures/good_pub_rsa.pem +5 -0
  54. data/spec/fixtures/good_pub_rsa.ssh +1 -0
  55. data/spec/log/exception_logger_spec.rb +76 -0
  56. data/spec/log/filter_logger_spec.rb +8 -0
  57. data/spec/log/mixin_spec.rb +62 -0
  58. data/spec/log/multiplexer_spec.rb +54 -0
  59. data/spec/log/null_logger_spec.rb +36 -0
  60. data/spec/log/system_logger_spec.rb +92 -0
  61. data/spec/net/address_helper_spec.rb +57 -0
  62. data/spec/net/balancing/health_check_spec.rb +382 -0
  63. data/spec/net/balancing/round_robin_spec.rb +15 -0
  64. data/spec/net/balancing/sticky_policy_spec.rb +92 -0
  65. data/spec/net/dns_spec.rb +152 -0
  66. data/spec/net/http_client_spec.rb +171 -0
  67. data/spec/net/request_balancer_spec.rb +579 -0
  68. data/spec/net/s3_helper_spec.rb +160 -0
  69. data/spec/net/ssl_spec.rb +42 -0
  70. data/spec/net/string_encoder_spec.rb +58 -0
  71. data/spec/rack/log_setter_spec.rb +5 -0
  72. data/spec/rack/request_logger_spec.rb +68 -0
  73. data/spec/rack/request_tracker_spec.rb +5 -0
  74. data/spec/ruby/easy_singleton_spec.rb +72 -0
  75. data/spec/ruby/object_extensions_spec.rb +27 -0
  76. data/spec/ruby/string_extensions_spec.rb +98 -0
  77. data/spec/spec_helper.rb +181 -0
  78. data/spec/stats/activity_spec.rb +193 -0
  79. data/spec/stats/exceptions_spec.rb +123 -0
  80. data/spec/stats/helpers_spec.rb +603 -0
  81. data/spec/validation/openssl_spec.rb +37 -0
  82. data/spec/validation/ssh_spec.rb +39 -0
  83. 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