right_support 2.10.1 → 2.11.2
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.
- 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
|