Skip to content

Commit e9634a8

Browse files
committed
enhance tests, use real v2 service endpoints
1 parent 8c597d7 commit e9634a8

File tree

2 files changed

+72
-21
lines changed

2 files changed

+72
-21
lines changed

middleware/service_broker_rate_limiter.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ module Middleware
66
RateLimitEndpoint = Struct.new(:endpoint_pattern, :request_methods)
77

88
RATE_LIMITED_ENDPOINTS = [
9-
RateLimitEndpoint.new(%r{\A/v2/(service_instances|service_credential_bindings|service_route_bindings)}, %w[PUT POST DELETE PATCH]),
9+
RateLimitEndpoint.new(%r{\A/v2/(service_instances|service_bindings|service_keys)}, %w[PUT POST DELETE]),
1010
RateLimitEndpoint.new(%r{\A/v3/(service_instances|service_credential_bindings|service_route_bindings)/.+/parameters\z}, %w[GET])
1111
].freeze
1212

spec/unit/middleware/service_broker_rate_limiter_spec.rb

Lines changed: 71 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ module Middleware
55
RSpec.describe ServiceBrokerRateLimiter do
66
let(:app) { double(:app) }
77
let(:logger) { double }
8-
let(:path_info) { '/v3/service_instances' }
8+
let(:instance) { VCAP::CloudController::Service.make(instances_retrievable: true) }
9+
let(:path_info) { '/v2/service_instances' }
910
let(:user_guid) { SecureRandom.uuid }
1011
let(:user_env) { { 'cf.user_guid' => user_guid, 'PATH_INFO' => path_info } }
11-
let(:fake_request) { instance_double(ActionDispatch::Request, fullpath: '/v3/service_instances', method: 'POST') }
12+
let(:env) { { 'cf.user_guid' => user_guid, 'PATH_INFO' => path, 'REQUEST_METHOD' => request_method } }
13+
let(:fake_request) { instance_double(ActionDispatch::Request, fullpath: '/v2/service_instances', method: 'POST') }
1214
let(:max_concurrent_requests) { 1 }
1315
let(:broker_timeout) { 60 }
1416
let(:middleware) do
@@ -39,16 +41,6 @@ module Middleware
3941
expect(status).to eq(200)
4042
end
4143

42-
it 'does not allow more than the max number of concurrent requests' do
43-
threads = 2.times.map { Thread.new { Thread.current[:status], = middleware.call(user_env) } }
44-
statuses = threads.map { |t| t.join[:status] }
45-
46-
expect(statuses).to include(200)
47-
expect(statuses).to include(429)
48-
expect(app).to have_received(:call).once
49-
expect(logger).to have_received(:info).with("Service broker concurrent rate limit exceeded for user '#{user_guid}'")
50-
end
51-
5244
it 'counts concurrent requests per user' do
5345
other_user_env = { 'cf.user_guid' => 'other_user_guid', 'PATH_INFO' => path_info }
5446
threads = [user_env, other_user_env].map do |env|
@@ -117,20 +109,79 @@ module Middleware
117109
end
118110
end
119111
end
112+
113+
shared_examples 'rate-limited endpoint' do
114+
it 'does not allow more than the max number of concurrent requests' do
115+
allow(app).to receive(:call) do
116+
sleep(1)
117+
[200, {}, 'a body']
118+
end
119+
120+
threads = 2.times.map { Thread.new { middleware.call(env) } }
121+
statuses = threads.map(&:join).map(&:value).map(&:first)
122+
123+
expect(statuses).to include(200)
124+
expect(statuses).to include(429)
125+
expect(app).to have_received(:call).once
126+
expect(logger).to have_received(:info).with("Service broker concurrent rate limit exceeded for user '#{user_guid}'")
127+
end
128+
end
129+
130+
v2_rate_limited_service_endpoints = %w[/v2/service_instances /v2/service_bindings /v2/service_keys]
131+
132+
methods = %w[PUT POST DELETE]
133+
134+
v2_rate_limited_service_endpoints.each do |endpoint|
135+
methods.each do |method|
136+
context "#{endpoint} #{method} endpoint" do
137+
let(:path) { endpoint }
138+
let(:request_method) { method }
139+
let(:fake_request) { instance_double(ActionDispatch::Request, fullpath: endpoint, method: method) }
140+
141+
include_examples 'rate-limited endpoint'
142+
end
143+
end
144+
end
145+
146+
v3_rate_limited_service_endpoints = %w[/v3/service_instances/:guid/parameters /v3/service_credential_bindings/:guid/parameters /v3/service_route_bindings/:guid/parameters]
147+
148+
v3_rate_limited_service_endpoints.each do |endpoint|
149+
context "#{endpoint} GET" do
150+
let(:path) { endpoint.gsub(':guid', instance.guid.to_s) }
151+
let(:request_method) { 'GET' }
152+
let(:fake_request) { instance_double(ActionDispatch::Request, fullpath: path, method: request_method) }
153+
154+
include_examples 'rate-limited endpoint'
155+
end
156+
end
120157
end
121158

122159
describe 'excluded requests' do
123-
let(:fake_request) { instance_double(ActionDispatch::Request, fullpath: '/v3/service_instances', method: 'POST') }
160+
shared_examples 'non-rate-limited endpoint' do
161+
it 'allows concurrent requests without limits' do
162+
threads = 2.times.map { Thread.new { middleware.call(env) } }
163+
statuses = threads.map(&:join).map(&:value).map(&:first)
164+
165+
expect(statuses).to all(eq(200))
166+
expect(app).to have_received(:call).twice
167+
expect(logger).not_to have_received(:info)
168+
end
169+
end
124170

125-
it 'allows requests that are no longer rate limited' do
126-
status, = middleware.call(user_env)
127-
expect(status).to eq(200)
171+
v3_not_rate_limited_service_endpoints = %w[/v3/service_instances /v3/service_credential_bindings /v3/service_route_bindings]
128172

129-
status, = middleware.call(user_env)
130-
expect(status).to eq(200)
173+
methods = %w[POST PATCH DELETE]
174+
175+
v3_not_rate_limited_service_endpoints.each do |endpoint|
176+
methods.each do |method|
177+
context "#{endpoint} #{method} - non-rate-limited" do
178+
let(:path) { endpoint }
179+
let(:request_method) { method }
180+
let(:fake_request) { instance_double(ActionDispatch::Request, fullpath: endpoint, method: method) }
131181

132-
statuses = 2.times.map { middleware.call(user_env).first }
133-
expect(statuses).to contain_exactly(200, 200)
182+
include_examples 'non-rate-limited endpoint'
183+
end
184+
end
134185
end
135186
end
136187

0 commit comments

Comments
 (0)