不要怂,就是干,撸起袖子干!

Commit 541d2fac by Sushant Committed by GitHub

test(transaction): row locking (#12174)

1 parent 1bc36cad
File mode changed
File mode changed
File mode changed
File mode changed
...@@ -108,24 +108,34 @@ if (current.dialect.supports.transactions) { ...@@ -108,24 +108,34 @@ if (current.dialect.supports.transactions) {
//Promise rejection test is specific to postgres //Promise rejection test is specific to postgres
if (dialect === 'postgres') { if (dialect === 'postgres') {
it('do not rollback if already committed', function() { it('do not rollback if already committed', async function() {
const SumSumSum = this.sequelize.define('transaction', { const SumSumSum = this.sequelize.define('transaction', {
value: { value: {
type: Support.Sequelize.DECIMAL(10, 3), type: Support.Sequelize.DECIMAL(10, 3),
field: 'value' field: 'value'
} }
}),
transTest = val => {
return this.sequelize.transaction({ isolationLevel: 'SERIALIZABLE' }, t => {
return SumSumSum.sum('value', { transaction: t }).then(() => {
return SumSumSum.create({ value: -val }, { transaction: t });
}); });
const transTest = val => {
return this.sequelize.transaction({
isolationLevel: Transaction.ISOLATION_LEVELS.SERIALIZABLE
}, async t => {
await SumSumSum.sum('value', { transaction: t });
await SumSumSum.create({ value: -val }, { transaction: t });
}); });
}; };
// Attention: this test is a bit racy. If you find a nicer way to test this: go ahead
return SumSumSum.sync({ force: true }).then(() => { await SumSumSum.sync({ force: true });
return expect(Promise.all([transTest(80), transTest(80), transTest(80)])).to.eventually.be.rejectedWith('could not serialize access due to read/write dependencies among transactions');
}); await expect(
Promise.all([
transTest(80),
transTest(80)
])
).to.eventually.be.rejectedWith('could not serialize access due to read/write dependencies among transactions');
// one row was created, another was rejected due to rollback
expect(await SumSumSum.count()).to.equal(1);
}); });
} }
...@@ -821,64 +831,54 @@ if (current.dialect.supports.transactions) { ...@@ -821,64 +831,54 @@ if (current.dialect.supports.transactions) {
}); });
} }
it('supports for share', function() { it('supports for share', async function() {
const User = this.sequelize.define('user', { const User = this.sequelize.define('user', {
username: Support.Sequelize.STRING, username: Support.Sequelize.STRING,
awesome: Support.Sequelize.BOOLEAN awesome: Support.Sequelize.BOOLEAN
}), }, { timestamps: false });
t1Spy = sinon.spy(),
t2FindSpy = sinon.spy(),
t2UpdateSpy = sinon.spy();
return this.sequelize.sync({ force: true }).then(() => { const t1CommitSpy = sinon.spy();
return User.create({ username: 'jan' }); const t2FindSpy = sinon.spy();
}).then(() => { const t2UpdateSpy = sinon.spy();
return this.sequelize.transaction().then(t1 => {
return User.findOne({ await this.sequelize.sync({ force: true });
where: { const user = await User.create({ username: 'jan' });
username: 'jan'
}, const t1 = await this.sequelize.transaction();
const t1Jan = await User.findByPk(user.id, {
lock: t1.LOCK.SHARE, lock: t1.LOCK.SHARE,
transaction: t1 transaction: t1
}).then(t1Jan => { });
return this.sequelize.transaction({
const t2 = await this.sequelize.transaction({
isolationLevel: Transaction.ISOLATION_LEVELS.READ_COMMITTED isolationLevel: Transaction.ISOLATION_LEVELS.READ_COMMITTED
}).then(t2 => { });
return Promise.all([User.findOne({
where: { await Promise.all([
username: 'jan' User.findByPk(user.id, {
},
transaction: t2 transaction: t2
}).then(t2Jan => { }).then(async t2Jan => {
t2FindSpy(); t2FindSpy();
return t2Jan.update({
awesome: false await t2Jan.update({ awesome: false }, { transaction: t2 });
}, {
transaction: t2
}).then(() => {
t2UpdateSpy(); t2UpdateSpy();
return t2.commit().then(() => {
expect(t2FindSpy).to.have.been.calledBefore(t1Spy); // The find call should have returned await t2.commit();
expect(t2UpdateSpy).to.have.been.calledAfter(t1Spy); // But the update call should not happen before the first transaction has committed }),
}); t1Jan.update({ awesome: true }, { transaction: t1 }).then(async () => {
}); await delay(2000);
}), t1Jan.update({ t1CommitSpy();
awesome: true await t1.commit();
}, { })
transaction: t1 ]);
}).then(() => {
return delay(2000).then(() => { // (t2) find call should have returned before (t1) commit
t1Spy(); expect(t2FindSpy).to.have.been.calledBefore(t1CommitSpy);
return t1.commit();
}); // But (t2) update call should not happen before (t1) commit
})]); expect(t2UpdateSpy).to.have.been.calledAfter(t1CommitSpy);
});
});
});
});
}); });
}); });
} }
}); });
} }
File mode changed
File mode changed
File mode changed
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!