right_support 2.10.1 → 2.11.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/right_support/data/token.rb +51 -0
- data/lib/right_support/data.rb +1 -0
- data/lib/right_support/net/lb/base.rb +96 -0
- data/lib/right_support/net/lb/health_check.rb +22 -46
- data/lib/right_support/net/lb/round_robin.rb +5 -23
- data/lib/right_support/net/lb/sticky.rb +10 -27
- data/lib/right_support/net/lb.rb +2 -1
- data/lib/right_support/net/request_balancer.rb +184 -60
- data/lib/right_support/rack/request_logger.rb +221 -42
- data/lib/right_support/rack/request_tracker.rb +112 -25
- data/right_support.gemspec +11 -6
- data/spec/data/token_spec.rb +21 -0
- data/spec/net/{balancing → lb}/health_check_spec.rb +56 -21
- data/spec/net/{balancing → lb}/round_robin_spec.rb +0 -0
- data/spec/net/{balancing/sticky_policy_spec.rb → lb/sticky_spec.rb} +1 -1
- data/spec/net/request_balancer_spec.rb +161 -57
- data/spec/rack/request_logger_spec.rb +91 -27
- data/spec/rack/request_tracker_spec.rb +111 -1
- metadata +8 -5
@@ -8,14 +8,77 @@ describe RightSupport::Rack::RequestLogger do
|
|
8
8
|
@app.should_receive(:call).and_return([200, {}, 'body']).by_default
|
9
9
|
@logger = mock_logger
|
10
10
|
@env = {'rack.logger' => @logger}
|
11
|
-
@
|
11
|
+
@options = {}
|
12
12
|
end
|
13
13
|
|
14
|
+
subject { described_class.new(@app, @options) }
|
15
|
+
|
14
16
|
context :initialize do
|
15
17
|
context 'without :logger option' do
|
16
18
|
it 'uses rack.logger' do
|
17
19
|
@logger.should_receive(:info).at_least.once
|
18
|
-
|
20
|
+
subject.call(@env).should == [200, {}, 'body']
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'with :logger option' do
|
25
|
+
it 'uses given logger' do
|
26
|
+
@env = {'rack.logger' => flexmock('overridden')}
|
27
|
+
@options[:logger] = @logger
|
28
|
+
@logger.should_receive(:info).at_least.once
|
29
|
+
subject.call(@env).should == [200, {}, 'body']
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'with :normalize_40x option' do
|
34
|
+
it 'omits some 40x details and disables global session Set-Cookie fields' do
|
35
|
+
@options[:normalize_40x] = true
|
36
|
+
@app = flexmock('Rack app')
|
37
|
+
body = 'insecure information'
|
38
|
+
headers = { 'TooMuch' => 'info', 'Content-Type' => 'text/plain', 'Content-Length' => body.bytesize.to_s }
|
39
|
+
iterative = [nil, headers, body]
|
40
|
+
@app.should_receive(:call).and_return(iterative)
|
41
|
+
|
42
|
+
# note that sending 'X-Debug' header should have no effect on a
|
43
|
+
# normalized 40x response
|
44
|
+
@env.merge!(described_class::DEBUG_MODE_HTTP_HEADER => 'true')
|
45
|
+
(400..499).each do |code|
|
46
|
+
iterative[0] = code
|
47
|
+
if described_class::NORMALIZE_40X.include?(code)
|
48
|
+
env = @env.dup
|
49
|
+
subject.call(env).should == [code, { 'Content-Length' => '0'}, []]
|
50
|
+
env.should == @env.merge(
|
51
|
+
'global_session.req.renew' => false,
|
52
|
+
'global_session.req.update' => false,
|
53
|
+
described_class::DEBUG_MODE_ENV_KEY => false)
|
54
|
+
else
|
55
|
+
subject.call(@env).should == iterative
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'with :normalize_40x_set_cookie option' do
|
62
|
+
it 'disables global session Set-Cookie fields' do
|
63
|
+
@options[:normalize_40x_set_cookie] = true
|
64
|
+
@app = flexmock('Rack app')
|
65
|
+
body = 'whatever'
|
66
|
+
headers = { 'Content-Type' => 'text/plain', 'Content-Length' => body.bytesize.to_s }
|
67
|
+
iterative = [nil, headers, body]
|
68
|
+
@app.should_receive(:call).and_return(iterative)
|
69
|
+
|
70
|
+
(400..499).each do |code|
|
71
|
+
iterative[0] = code
|
72
|
+
if described_class::NORMALIZE_40X.include?(code)
|
73
|
+
env = @env.dup
|
74
|
+
subject.call(env).should == iterative
|
75
|
+
env.should == @env.merge(
|
76
|
+
'global_session.req.renew' => false,
|
77
|
+
'global_session.req.update' => false)
|
78
|
+
else
|
79
|
+
subject.call(@env).should == iterative
|
80
|
+
end
|
81
|
+
end
|
19
82
|
end
|
20
83
|
end
|
21
84
|
end
|
@@ -29,7 +92,7 @@ describe RightSupport::Rack::RequestLogger do
|
|
29
92
|
it 'logs the exception' do
|
30
93
|
@logger.should_receive(:error).at_least.once
|
31
94
|
lambda {
|
32
|
-
|
95
|
+
subject.call(@env)
|
33
96
|
}.should raise_error
|
34
97
|
end
|
35
98
|
end
|
@@ -43,14 +106,14 @@ describe RightSupport::Rack::RequestLogger do
|
|
43
106
|
it 'logs the exception' do
|
44
107
|
@logger.should_receive(:info)
|
45
108
|
@logger.should_receive(:error).at_least.once
|
46
|
-
|
109
|
+
subject.call(@env)
|
47
110
|
end
|
48
111
|
|
49
112
|
it 'skips logging the exception when already handled' do
|
50
113
|
@logger.should_receive(:info)
|
51
114
|
@logger.should_receive(:error).never
|
52
115
|
@env['sinatra.error.handled'] = true
|
53
|
-
|
116
|
+
subject.call(@env)
|
54
117
|
end
|
55
118
|
end
|
56
119
|
|
@@ -58,37 +121,37 @@ describe RightSupport::Rack::RequestLogger do
|
|
58
121
|
before(:each) do
|
59
122
|
@options = {:except => [/bar/]}
|
60
123
|
@env.merge!('PATH_INFO' => '/foo/bar')
|
61
|
-
|
124
|
+
subject = described_class.new(@app, @options)
|
62
125
|
@logger.should_receive(:level).and_return(Logger::INFO).by_default
|
63
126
|
end
|
64
127
|
|
65
128
|
it 'limits if logger in debug mode' do
|
66
129
|
@logger.should_receive(:level).and_return(Logger::DEBUG)
|
67
130
|
@logger.should_receive(:info).never
|
68
|
-
|
131
|
+
subject.call(@env)
|
69
132
|
end
|
70
133
|
|
71
134
|
it 'does not limit if HTTP_X_DEBUG set' do
|
72
135
|
@logger.should_receive(:info).at_least.once
|
73
|
-
|
136
|
+
subject.call(@env.merge('HTTP_X_DEBUG' => true))
|
74
137
|
end
|
75
138
|
|
76
139
|
it 'does not log for paths matching :except option' do
|
77
140
|
@logger.should_receive(:info).never
|
78
|
-
|
141
|
+
subject.call(@env)
|
79
142
|
end
|
80
143
|
|
81
144
|
it 'does log for paths matching :only option' do
|
82
145
|
@options = {:only => [/bar/]}
|
83
|
-
|
146
|
+
subject = described_class.new(@app, @options)
|
84
147
|
@logger.should_receive(:info)
|
85
|
-
|
148
|
+
subject.call(@env)
|
86
149
|
end
|
87
150
|
|
88
151
|
it 'sets rack.logging.enabled in Rack environment' do
|
89
152
|
@logger.should_receive(:info).at_least.once
|
90
153
|
@env.merge!('PATH_INFO' => '/my/app')
|
91
|
-
|
154
|
+
subject.call(@env)
|
92
155
|
@env['rack.logging.enabled'].should be_true
|
93
156
|
end
|
94
157
|
end
|
@@ -97,29 +160,29 @@ describe RightSupport::Rack::RequestLogger do
|
|
97
160
|
before(:each) do
|
98
161
|
@options = {}
|
99
162
|
@env.merge!('PATH_INFO' => '/my/app', 'QUERY_STRING' => 'foo=bar')
|
100
|
-
|
163
|
+
subject = described_class.new(@app, @options)
|
101
164
|
end
|
102
165
|
|
103
166
|
it 'does not log the query string by default' do
|
104
167
|
@logger.should_receive(:info).with(FlexMock.on { |arg| arg.should =~ /\/my\/app\?\.{3}/ } )
|
105
|
-
|
168
|
+
subject.send(:log_request_begin, @logger, @env)
|
106
169
|
end
|
107
170
|
|
108
171
|
context 'when the include_query_string option is true' do
|
109
172
|
it 'logs the query string' do
|
110
173
|
@options[:include_query_string] = true
|
111
|
-
|
174
|
+
subject = described_class.new(@app, @options)
|
112
175
|
@logger.should_receive(:info).with(FlexMock.on { |arg| arg.should =~ /\/my\/app\?foo%3Dbar/ } )
|
113
|
-
|
176
|
+
subject.send(:log_request_begin, @logger, @env)
|
114
177
|
end
|
115
178
|
end
|
116
179
|
|
117
180
|
context 'when the include_query_string option is false' do
|
118
181
|
it 'does not log the query string' do
|
119
182
|
@options[:include_query_string] = false
|
120
|
-
|
183
|
+
subject = described_class.new(@app, @options)
|
121
184
|
@logger.should_receive(:info).with(FlexMock.on { |arg| arg.should =~ /\/my\/app\?\.{3}/ } )
|
122
|
-
|
185
|
+
subject.send(:log_request_begin, @logger, @env)
|
123
186
|
end
|
124
187
|
end
|
125
188
|
end
|
@@ -131,13 +194,13 @@ describe RightSupport::Rack::RequestLogger do
|
|
131
194
|
|
132
195
|
it 'logs X-Shard header if it is present' do
|
133
196
|
@env['HTTP_X_SHARD'] = '9'
|
134
|
-
@logger.should_receive(:info).with(FlexMock.on { |arg| arg.should =~ /Shard: 9
|
135
|
-
|
197
|
+
@logger.should_receive(:info).with(FlexMock.on { |arg| arg.should =~ /Shard: 9$/ } )
|
198
|
+
subject.send(:log_request_begin, @logger, @env)
|
136
199
|
end
|
137
200
|
|
138
201
|
it 'logs "default" if X-Shard header is absent' do
|
139
|
-
@logger.should_receive(:info).with(FlexMock.on { |arg| arg.should =~ /Shard: default
|
140
|
-
|
202
|
+
@logger.should_receive(:info).with(FlexMock.on { |arg| arg.should =~ /Shard: default$/ } )
|
203
|
+
subject.send(:log_request_begin, @logger, @env)
|
141
204
|
end
|
142
205
|
end
|
143
206
|
|
@@ -147,15 +210,16 @@ describe RightSupport::Rack::RequestLogger do
|
|
147
210
|
@env['rack.request_uuid'] = 'some-uuid'
|
148
211
|
end
|
149
212
|
|
150
|
-
it 'tags the
|
151
|
-
@logger.should_receive(:info).with(FlexMock.on { |arg| arg.should =~
|
152
|
-
|
213
|
+
it 'tags the Started line' do
|
214
|
+
@logger.should_receive(:info).with(FlexMock.on { |arg| arg.should =~ /^\[some\-uuid\] Started / } )
|
215
|
+
subject.send(:log_request_begin, @logger, @env)
|
153
216
|
end
|
154
217
|
|
155
218
|
it 'tags the Completed line' do
|
156
|
-
@logger.should_receive(:info).with(FlexMock.on { |arg| arg.should =~
|
157
|
-
|
219
|
+
@logger.should_receive(:info).with(FlexMock.on { |arg| arg.should =~ /^\[some\-uuid\] Completed / } )
|
220
|
+
subject.send(:log_request_end, @logger, @env, 200, {}, '', Time.now)
|
158
221
|
end
|
159
222
|
end
|
223
|
+
|
160
224
|
end
|
161
225
|
end
|
@@ -1,5 +1,115 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe RightSupport::Rack::RequestTracker do
|
4
|
-
|
4
|
+
|
5
|
+
let(:app) { flexmock('next middleware or rack app') }
|
6
|
+
|
7
|
+
let(:generator) { described_class::Generator }
|
8
|
+
let(:generated_request_uuid) { 'generated-uuid' }
|
9
|
+
let(:request_uuid) { 'given-uuid' }
|
10
|
+
|
11
|
+
subject { described_class.new(app) }
|
12
|
+
|
13
|
+
context :call do
|
14
|
+
context 'when ID is missing from request headers' do
|
15
|
+
it 'generates a new request ID and responds as UUID for legacy reasons' do
|
16
|
+
flexmock(generator).
|
17
|
+
should_receive(:generate).
|
18
|
+
and_return(generated_request_uuid).
|
19
|
+
once
|
20
|
+
original_env = {}
|
21
|
+
expected_env = original_env.merge(described_class::REQUEST_UUID_ENV_NAME => generated_request_uuid)
|
22
|
+
app.should_receive(:call).with(expected_env).and_return([200, {}, 'body']).once
|
23
|
+
|
24
|
+
actual = subject.call(original_env)
|
25
|
+
|
26
|
+
expected_headers = { described_class::REQUEST_UUID_HEADER => generated_request_uuid }
|
27
|
+
actual[1].should == expected_headers
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'when ID sent with request' do
|
32
|
+
it 'passes incoming request ID and responds as ID' do
|
33
|
+
flexmock(generator).should_receive(:generate).never
|
34
|
+
original_env = { described_class::HTTP_REQUEST_ID_HEADER => request_uuid }
|
35
|
+
expected_env = original_env.merge(described_class::REQUEST_UUID_ENV_NAME => request_uuid)
|
36
|
+
app.should_receive(:call).with(expected_env).and_return([200, {}, 'body']).once
|
37
|
+
|
38
|
+
actual = subject.call(original_env)
|
39
|
+
|
40
|
+
expected_headers = { described_class::REQUEST_ID_HEADER => request_uuid }
|
41
|
+
actual[1].should == expected_headers
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'when UUID sent with request' do
|
46
|
+
it 'passes incoming request UUID and responds as UUID' do
|
47
|
+
flexmock(generator).should_receive(:generate).never
|
48
|
+
original_env = { described_class::HTTP_REQUEST_UUID_HEADER => request_uuid }
|
49
|
+
expected_env = original_env.merge(described_class::REQUEST_UUID_ENV_NAME => request_uuid)
|
50
|
+
app.should_receive(:call).with(expected_env).and_return([200, {}, 'body']).once
|
51
|
+
|
52
|
+
actual = subject.call(original_env)
|
53
|
+
|
54
|
+
expected_headers = { described_class::REQUEST_UUID_HEADER => request_uuid }
|
55
|
+
actual[1].should == expected_headers
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'when lineage sent with request' do
|
60
|
+
it 'passes all UUIDs in header under length limit' do
|
61
|
+
uuids = []
|
62
|
+
3.times do
|
63
|
+
uuids << ::RightSupport::Data::UUID.generate
|
64
|
+
end
|
65
|
+
lineage_uuid = uuids.join(described_class::UUID_SEPARATOR)
|
66
|
+
flexmock(generator).should_receive(:generate).never
|
67
|
+
original_env = { described_class::REQUEST_LINEAGE_UUID_HEADER => lineage_uuid }
|
68
|
+
expected_env = original_env.merge(described_class::REQUEST_UUID_ENV_NAME => lineage_uuid)
|
69
|
+
app.should_receive(:call).with(expected_env).and_return([200, {}, 'body']).once
|
70
|
+
|
71
|
+
actual = subject.call(original_env)
|
72
|
+
|
73
|
+
expected_headers = { described_class::REQUEST_UUID_HEADER => lineage_uuid }
|
74
|
+
actual[1].should == expected_headers
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'when sent ID exceeds length limit' do
|
79
|
+
it 'passes truncated request ID' do
|
80
|
+
flexmock(generator).should_receive(:generate).never
|
81
|
+
too_long_id = 'x' * 1024
|
82
|
+
truncated_id = 'x' * described_class::MAX_REQUEST_UUID_LENGTH
|
83
|
+
original_env = { described_class::HTTP_REQUEST_ID_HEADER => too_long_id }
|
84
|
+
expected_env = original_env.merge(described_class::REQUEST_UUID_ENV_NAME => truncated_id)
|
85
|
+
app.should_receive(:call).with(expected_env).and_return([200, {}, 'body']).once
|
86
|
+
|
87
|
+
actual = subject.call(original_env)
|
88
|
+
|
89
|
+
expected_headers = { described_class::REQUEST_ID_HEADER => truncated_id }
|
90
|
+
actual[1].should == expected_headers
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
context :copy_request_uuid do
|
97
|
+
it 'does nothing when request UUID is missing' do
|
98
|
+
described_class.copy_request_uuid(nil, nil).should be_empty
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'copies request UUID to target hash when present' do
|
102
|
+
env = {
|
103
|
+
described_class::REQUEST_UUID_ENV_NAME => request_uuid,
|
104
|
+
'other' => 'stuff'
|
105
|
+
}
|
106
|
+
other_headers = { 'Foo' => 'bar' }
|
107
|
+
expected = {
|
108
|
+
described_class::REQUEST_ID_HEADER => request_uuid
|
109
|
+
}.merge(other_headers)
|
110
|
+
actual = described_class.copy_request_uuid(env, other_headers)
|
111
|
+
actual.should == expected
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
5
115
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: right_support
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.11.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tony Spataro
|
@@ -13,7 +13,7 @@ authors:
|
|
13
13
|
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
|
-
date: 2016-
|
16
|
+
date: 2016-07-14 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: rake
|
@@ -132,6 +132,7 @@ files:
|
|
132
132
|
- lib/right_support/data/hash_tools.rb
|
133
133
|
- lib/right_support/data/mash.rb
|
134
134
|
- lib/right_support/data/serializer.rb
|
135
|
+
- lib/right_support/data/token.rb
|
135
136
|
- lib/right_support/data/unknown_type.rb
|
136
137
|
- lib/right_support/data/uuid.rb
|
137
138
|
- lib/right_support/db.rb
|
@@ -152,6 +153,7 @@ files:
|
|
152
153
|
- lib/right_support/net/dns.rb
|
153
154
|
- lib/right_support/net/http_client.rb
|
154
155
|
- lib/right_support/net/lb.rb
|
156
|
+
- lib/right_support/net/lb/base.rb
|
155
157
|
- lib/right_support/net/lb/health_check.rb
|
156
158
|
- lib/right_support/net/lb/round_robin.rb
|
157
159
|
- lib/right_support/net/lb/sticky.rb
|
@@ -182,6 +184,7 @@ files:
|
|
182
184
|
- spec/crypto/signed_hash_spec.rb
|
183
185
|
- spec/data/hash_tools_spec.rb
|
184
186
|
- spec/data/mash_spec.rb
|
187
|
+
- spec/data/token_spec.rb
|
185
188
|
- spec/data/uuid_spec.rb
|
186
189
|
- spec/db/cassandra_model_part1_spec.rb
|
187
190
|
- spec/db/cassandra_model_part2_spec.rb
|
@@ -200,11 +203,11 @@ files:
|
|
200
203
|
- spec/log/step_level_logger_spec.rb
|
201
204
|
- spec/log/system_logger_spec.rb
|
202
205
|
- spec/net/address_helper_spec.rb
|
203
|
-
- spec/net/balancing/health_check_spec.rb
|
204
|
-
- spec/net/balancing/round_robin_spec.rb
|
205
|
-
- spec/net/balancing/sticky_policy_spec.rb
|
206
206
|
- spec/net/dns_spec.rb
|
207
207
|
- spec/net/http_client_spec.rb
|
208
|
+
- spec/net/lb/health_check_spec.rb
|
209
|
+
- spec/net/lb/round_robin_spec.rb
|
210
|
+
- spec/net/lb/sticky_spec.rb
|
208
211
|
- spec/net/request_balancer_spec.rb
|
209
212
|
- spec/net/s3_helper_spec.rb
|
210
213
|
- spec/net/ssl_spec.rb
|