Skip to content

Commit a8f7659

Browse files
authored
Stabilize concurrent binding creation test (#4558)
The test for concurrent service credential binding creation used threads, which caused sporadic failures in other tests due to database connection interference. This commit rewrites the test to use a spy instead of threads. The spy simulates the race condition by creating a conflicting binding after the database lock is acquired, verifying the code's locking mechanism without the side effects of multi-threading.
1 parent 8e92607 commit a8f7659

File tree

1 file changed

+11
-12
lines changed

1 file changed

+11
-12
lines changed

spec/unit/actions/service_credential_binding_app_create_spec.rb

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -234,20 +234,19 @@ module V3
234234
# TODO: Once the unique constraints to allow multiple bindings are removed, this needs to be set to 1
235235
# before { TestConfig.override(max_service_credential_bindings_per_app_service_instance: 1) }
236236

237-
def attempt_precursor
238-
action.precursor(service_instance, app:, message:)
239-
:ok
240-
rescue StandardError => e
241-
e
242-
end
243-
244237
it 'allows only one binding when two creates run in parallel' do
245-
results = [Thread.new { attempt_precursor }, Thread.new { attempt_precursor }].map(&:value)
238+
# This test simulates a race condition for concurrent binding creation using a spy on `service_instance`.
239+
# We mock that a second binding is created after the first one acquires a lock and expect an `UnprocessableCreate` error.
240+
allow(service_instance).to receive(:lock!).and_wrap_original do |m, *args, &block|
241+
m.call(*args, &block)
242+
ServiceBinding.make(service_instance:, app:)
243+
end
244+
245+
expect do
246+
action.precursor(service_instance, app:, message:)
247+
end.to raise_error(ServiceCredentialBindingAppCreate::UnprocessableCreate, 'The app is already bound to the service instance')
246248

247-
expect(ServiceBinding.where(app:, service_instance:).count).to eq(1)
248-
expect(results.count(:ok)).to eq(1)
249-
expect(results.count { |r| r.is_a?(VCAP::CloudController::V3::ServiceBindingCreate::UnprocessableCreate) }).to eq(1)
250-
expect(results.grep(Exception).map(&:message)).to include('The app is already bound to the service instance')
249+
expect(service_instance).to have_received(:lock!)
251250
end
252251
end
253252

0 commit comments

Comments
 (0)