right_support 2.6.17 → 2.7.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.
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