diff options
| author | Teddy Wing | 2017-12-12 16:56:49 +0100 |
|---|---|---|
| committer | Teddy Wing | 2017-12-12 16:56:49 +0100 |
| commit | 55b995531b2504792dfa1b0314b5cc5b55a775ac (patch) | |
| tree | fe3f43a490e28fa3064541292eea6180692b31c3 /spec | |
| parent | c84154201959197a99de202d97baff1c812dead9 (diff) | |
| download | chouette-core-55b995531b2504792dfa1b0314b5cc5b55a775ac.tar.bz2 | |
Referential: Raise an error if the table lock times out
Paired with Johan on this one. There's an internal timeout on our table
lock. If it's reached, an
`ActiveRecord::StatementInvalid<PG::LockNotAvailable>` error is raised.
Use a custom error instead by "overriding" `#save` with a method that
raises our custom error in that case instead. This will enable us to
provide a custom user-facing error in the event this happens.
Refs #5024
Diffstat (limited to 'spec')
| -rw-r--r-- | spec/models/referential/referential_lock_during_creation_spec.rb | 59 |
1 files changed, 57 insertions, 2 deletions
diff --git a/spec/models/referential/referential_lock_during_creation_spec.rb b/spec/models/referential/referential_lock_during_creation_spec.rb index 0002af549..d17327d39 100644 --- a/spec/models/referential/referential_lock_during_creation_spec.rb +++ b/spec/models/referential/referential_lock_during_creation_spec.rb @@ -1,8 +1,7 @@ RSpec.describe Referential, type: :model do + let (:workbench) { create(:workbench) } context "when two identical Referentials are created, only one is saved" do - let( :workbench ){ create :workbench } - it "works synchronously" do referential_1 = build( :referential, @@ -76,5 +75,61 @@ RSpec.describe Referential, type: :model do end end end + + context "when two Referentials are created at the same time" do + it "raises an error when the DB lock timeout is reached", truncation: true do + begin + referential_1 = build( + :referential, + workbench: workbench, + organisation: workbench.organisation + ) + referential_2 = referential_1.dup + referential_2.slug = "#{referential_1.slug}_different" + referential_3 = nil + + metadata_1 = build(:referential_metadata, referential: nil) + metadata_2 = metadata_1.dup + + referential_1.metadatas << metadata_1 + referential_2.metadatas << metadata_2 + + thread_1 = Thread.new do + ActiveRecord::Base.transaction do + ActiveRecord::Base.connection.execute("SET LOCAL lock_timeout = '1s'") + + # seize LOCK + referential_1.save + sleep 10 + # release LOCK + end + end + + thread_2 = Thread.new do + sleep 5 + ActiveRecord::Base.transaction do + ActiveRecord::Base.connection.execute("SET LOCAL lock_timeout = '1s'") + # waits for LOCK, (because of sleep 5) + referential_2.save + # when lock was eventually obtained validation failed + referential_3 = create(:referential) + end + end + + thread_1.join + expect do + thread_2.join + end.to raise_error(TableLockTimeoutError) + + expect(referential_1).to be_persisted + ensure + Apartment::Tenant.drop(referential_1.slug) if referential_1.persisted? + Apartment::Tenant.drop(referential_2.slug) if referential_2.persisted? + + if referential_3.try(:persisted?) + Apartment::Tenant.drop(referential_3.slug) + end + end + end end end |
