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

Commit 16d175a1 by Matt Broadstone

Merge pull request #3359 from sequelize/test-verify-no-running-queries

feat(test/misc): utils for verifying sequelize has no running/pending queries
2 parents ce2e86b1 9920fee5
...@@ -17,15 +17,15 @@ else ...@@ -17,15 +17,15 @@ else
test: test:
make jshint && make teaser && make test-unit && make test-integration make jshint && make teaser && make test-unit && make test-integration
@if [ "$$GREP" ]; then \ @if [ "$$GREP" ]; then \
make jshint && make teaser && ./node_modules/mocha/bin/mocha --globals setImmediate,clearImmediate --ui tdd --check-leaks --colors -t 10000 --reporter $(REPORTER) -g "$$GREP" $(TESTS); \ make jshint && make teaser && ./node_modules/mocha/bin/mocha --globals setImmediate,clearImmediate --ui tdd --check-leaks --colors -t 15000 --reporter $(REPORTER) -g "$$GREP" $(TESTS); \
else \ else \
make jshint && make teaser && ./node_modules/mocha/bin/mocha --globals setImmediate,clearImmediate --ui tdd --check-leaks --colors -t 10000 --reporter $(REPORTER) $(TESTS); \ make jshint && make teaser && ./node_modules/mocha/bin/mocha --globals setImmediate,clearImmediate --ui tdd --check-leaks --colors -t 15000 --reporter $(REPORTER) $(TESTS); \
fi fi
endif endif
# Unit tests # Unit tests
test-unit: test-unit:
./node_modules/mocha/bin/mocha --globals setImmediate,clearImmediate --ui tdd --check-leaks --colors -t 10000 --reporter $(REPORTER) ./test/unit/*.js ./test/unit/**/*.js ./node_modules/mocha/bin/mocha --globals setImmediate,clearImmediate --ui tdd --check-leaks --colors -t 15000 --reporter $(REPORTER) ./test/unit/*.js ./test/unit/**/*.js
test-unit-all: test-unit-sqlite test-unit-mysql test-unit-postgres test-unit-postgres-native test-unit-mariadb test-unit-mssql test-unit-all: test-unit-sqlite test-unit-mysql test-unit-postgres test-unit-postgres-native test-unit-mariadb test-unit-mssql
...@@ -45,9 +45,9 @@ test-unit-postgres-native: ...@@ -45,9 +45,9 @@ test-unit-postgres-native:
# Integration tests # Integration tests
test-integration: test-integration:
@if [ "$$GREP" ]; then \ @if [ "$$GREP" ]; then \
./node_modules/mocha/bin/mocha --globals setImmediate,clearImmediate --ui tdd --check-leaks --colors -t 10000 --reporter $(REPORTER) -g "$$GREP" $(TESTS); \ ./node_modules/mocha/bin/mocha --globals setImmediate,clearImmediate --ui tdd --check-leaks --colors -t 15000 --reporter $(REPORTER) -g "$$GREP" $(TESTS); \
else \ else \
./node_modules/mocha/bin/mocha --globals setImmediate,clearImmediate --ui tdd --check-leaks --colors -t 10000 --reporter $(REPORTER) $(TESTS); \ ./node_modules/mocha/bin/mocha --globals setImmediate,clearImmediate --ui tdd --check-leaks --colors -t 15000 --reporter $(REPORTER) $(TESTS); \
fi fi
test-integration-all: test-integration-sqlite test-integration-mysql test-integration-postgres test-integration-postgres-native test-integration-mariadb test-integration-mssql test-integration-all: test-integration-sqlite test-integration-mysql test-integration-postgres test-integration-postgres-native test-integration-mariadb test-integration-mssql
...@@ -85,7 +85,7 @@ postgres-native: ...@@ -85,7 +85,7 @@ postgres-native:
# Coverage # Coverage
cover: cover:
rm -rf coverage \ rm -rf coverage \
make teaser && ./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha --report lcovonly -- -t 10000 --ui tdd $(TESTS); \ make teaser && ./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha --report lcovonly -- -t 15000 --ui tdd $(TESTS); \
mariadb-cover: mariadb-cover:
rm -rf coverage rm -rf coverage
......
...@@ -612,7 +612,6 @@ module.exports = (function() { ...@@ -612,7 +612,6 @@ module.exports = (function() {
QueryInterface.prototype.delete = function(dao, tableName, identifier, options) { QueryInterface.prototype.delete = function(dao, tableName, identifier, options) {
var self = this var self = this
, restrict = false
, cascades = [] , cascades = []
, sql = self.QueryGenerator.deleteQuery(tableName, identifier, null, dao.Model); , sql = self.QueryGenerator.deleteQuery(tableName, identifier, null, dao.Model);
...@@ -623,70 +622,22 @@ module.exports = (function() { ...@@ -623,70 +622,22 @@ module.exports = (function() {
for (var i = 0; i < length; i++) { for (var i = 0; i < length; i++) {
if (dao.Model.associations[keys[i]].options && dao.Model.associations[keys[i]].options.onDelete) { if (dao.Model.associations[keys[i]].options && dao.Model.associations[keys[i]].options.onDelete) {
if (dao.Model.associations[keys[i]].options.onDelete === 'restrict') { if (dao.Model.associations[keys[i]].options.onDelete === 'cascade' && dao.Model.associations[keys[i]].options.useHooks === true) {
restrict = true; cascades.push(dao.Model.associations[keys[i]].accessors.get);
}
else if (dao.Model.associations[keys[i]].options.onDelete === 'cascade' && dao.Model.associations[keys[i]].options.useHooks === true) {
cascades[cascades.length] = dao.Model.associations[keys[i]].accessors.get;
}
}
}
}
return new Utils.Promise(function(resolve, reject) {
var tick = 0;
var iterate = function(err, i) {
if (err) {
return reject(err);
}
if (i >= cascades.length) {
return resolve();
}
dao[cascades[i]]().success(function(tasks) {
if (tasks === null || tasks.length < 1) {
if (i >= cascades.length) {
return resolve();
} else {
tick++;
return iterate(null, tick);
} }
} }
tasks = Array.isArray(tasks) ? tasks : [tasks];
var ii = 0;
var next = function(err, ii) {
if (!!err || ii >= tasks.length) {
return iterate(err);
} }
tasks[ii].destroy().error(function(err) {
return iterate(err);
})
.success(function() {
ii++;
if (ii >= tasks.length) {
tick++;
return iterate(null, tick);
} }
next(null, ii); return Promise.reduce(cascades, function (memo, cascade) {
}); return dao[cascade]().then(function (instances) {
}; if (!Array.isArray(instances)) instances = [instances];
next(null, ii); return Promise.reduce(instances, function (memo, instance) {
return instance.destroy();
}, []);
}); });
}; }, []).then(function () {
if (cascades.length > 0) {
iterate(null, tick);
} else {
resolve();
}
}).then(function() {
return self.sequelize.query(sql, dao, options); return self.sequelize.query(sql, dao, options);
}); });
}; };
......
...@@ -198,6 +198,17 @@ module.exports = (function() { ...@@ -198,6 +198,17 @@ module.exports = (function() {
this.importCache = {}; this.importCache = {};
this.test = {
$trackRunningQueries: false,
$runningQueries: 0,
trackRunningQueries: function() {
this.$trackRunningQueries = true;
},
verifyNoRunningQueries: function() {
if (this.$runningQueries > 0) throw new Error('Expected 0 running queries. '+this.$runningQueries+' queries still running');
}
};
Sequelize.runHooks('afterInit', this); Sequelize.runHooks('afterInit', this);
}; };
...@@ -731,6 +742,10 @@ module.exports = (function() { ...@@ -731,6 +742,10 @@ module.exports = (function() {
return Promise.reject(options.transaction.finished+' has been called on this transaction, you can no longer use it'); return Promise.reject(options.transaction.finished+' has been called on this transaction, you can no longer use it');
} }
if (this.test.$trackRunningQueries) {
this.test.$runningQueries++;
}
return Promise.resolve( return Promise.resolve(
options.transaction ? options.transaction.connection : self.connectionManager.getConnection(options) options.transaction ? options.transaction.connection : self.connectionManager.getConnection(options)
).then(function (connection) { ).then(function (connection) {
...@@ -739,6 +754,10 @@ module.exports = (function() { ...@@ -739,6 +754,10 @@ module.exports = (function() {
if (options.transaction) return; if (options.transaction) return;
return self.connectionManager.releaseConnection(connection); return self.connectionManager.releaseConnection(connection);
}); });
}).finally(function () {
if (self.test.$trackRunningQueries) {
self.test.$runningQueries--;
}
}); });
}; };
......
...@@ -4676,12 +4676,13 @@ describe(Support.getTestDialectTeaser('Hooks'), function() { ...@@ -4676,12 +4676,13 @@ describe(Support.getTestDialectTeaser('Hooks'), function() {
}); });
}); });
it('with errors', function(done) { it('with errors', function() {
var self = this var self = this
, beforeProject = false , beforeProject = false
, afterProject = false , afterProject = false
, beforeTask = false , beforeTask = false
, afterTask = false; , afterTask = false
, VeryCustomError = function() {};
this.Projects.beforeCreate(function(project, options, fn) { this.Projects.beforeCreate(function(project, options, fn) {
beforeProject = true; beforeProject = true;
...@@ -4695,7 +4696,7 @@ describe(Support.getTestDialectTeaser('Hooks'), function() { ...@@ -4695,7 +4696,7 @@ describe(Support.getTestDialectTeaser('Hooks'), function() {
this.Tasks.beforeDestroy(function(task, options, fn) { this.Tasks.beforeDestroy(function(task, options, fn) {
beforeTask = true; beforeTask = true;
fn(new Error('Whoops!')); fn(new VeryCustomError('Whoops!'));
}); });
this.Tasks.afterDestroy(function(task, options, fn) { this.Tasks.afterDestroy(function(task, options, fn) {
...@@ -4703,16 +4704,14 @@ describe(Support.getTestDialectTeaser('Hooks'), function() { ...@@ -4703,16 +4704,14 @@ describe(Support.getTestDialectTeaser('Hooks'), function() {
fn(); fn();
}); });
this.Projects.create({title: 'New Project'}).success(function(project) { return this.Projects.create({title: 'New Project'}).then(function(project) {
self.Tasks.create({title: 'New Task'}).success(function(task) { return self.Tasks.create({title: 'New Task'}).then(function(task) {
project.setTask(task).success(function() { return project.setTask(task).then(function() {
project.destroy().error(function(err) { return expect(project.destroy()).to.eventually.be.rejectedWith(VeryCustomError).then(function () {
expect(err).to.be.instanceOf(Error);
expect(beforeProject).to.be.true; expect(beforeProject).to.be.true;
expect(afterProject).to.be.true; expect(afterProject).to.be.true;
expect(beforeTask).to.be.true; expect(beforeTask).to.be.true;
expect(afterTask).to.be.false; expect(afterTask).to.be.false;
done();
}); });
}); });
}); });
...@@ -5580,37 +5579,32 @@ describe(Support.getTestDialectTeaser('Hooks'), function() { ...@@ -5580,37 +5579,32 @@ describe(Support.getTestDialectTeaser('Hooks'), function() {
, beforeTask = false , beforeTask = false
, afterTask = false , afterTask = false
, beforeMiniTask = false , beforeMiniTask = false
, afterMiniTask = false; , afterMiniTask = false
, VeryCustomError = function() {};
this.Projects.beforeCreate(function(project, options, fn) { this.Projects.beforeCreate(function(project, options) {
beforeProject = true; beforeProject = true;
fn();
}); });
this.Projects.afterCreate(function(project, options, fn) { this.Projects.afterCreate(function(project, options) {
afterProject = true; afterProject = true;
fn();
}); });
this.Tasks.beforeDestroy(function(task, options, fn) { this.Tasks.beforeDestroy(function(task, options) {
beforeTask = true; beforeTask = true;
fn(new Error('Whoops!')); throw new VeryCustomError('Whoops!');
fn();
}); });
this.Tasks.afterDestroy(function(task, options, fn) { this.Tasks.afterDestroy(function(task, options) {
afterTask = true; afterTask = true;
fn();
}); });
this.MiniTasks.beforeDestroy(function(minitask, options, fn) { this.MiniTasks.beforeDestroy(function(minitask, options) {
beforeMiniTask = true; beforeMiniTask = true;
}); });
this.MiniTasks.afterDestroy(function(minitask, options, fn) { this.MiniTasks.afterDestroy(function(minitask, options) {
afterMiniTask = true; afterMiniTask = true;
fn();
}); });
return this.sequelize.Promise.all([ return this.sequelize.Promise.all([
...@@ -5623,8 +5617,7 @@ describe(Support.getTestDialectTeaser('Hooks'), function() { ...@@ -5623,8 +5617,7 @@ describe(Support.getTestDialectTeaser('Hooks'), function() {
project.addTask(task) project.addTask(task)
]).return(project); ]).return(project);
}).then(function(project) { }).then(function(project) {
return project.destroy(); return expect(project.destroy()).to.eventually.be.rejectedWith(VeryCustomError).then(function () {
}).catch(function() {
expect(beforeProject).to.be.true; expect(beforeProject).to.be.true;
expect(afterProject).to.be.true; expect(afterProject).to.be.true;
expect(beforeTask).to.be.true; expect(beforeTask).to.be.true;
...@@ -5636,6 +5629,7 @@ describe(Support.getTestDialectTeaser('Hooks'), function() { ...@@ -5636,6 +5629,7 @@ describe(Support.getTestDialectTeaser('Hooks'), function() {
}); });
}); });
}); });
});
} }
}); });
......
...@@ -7,7 +7,8 @@ var chai = require('chai') ...@@ -7,7 +7,8 @@ var chai = require('chai')
, DataTypes = require(__dirname + '/../../../lib/data-types') , DataTypes = require(__dirname + '/../../../lib/data-types')
, datetime = require('chai-datetime') , datetime = require('chai-datetime')
, async = require('async') , async = require('async')
, Promise = Sequelize.Promise; , Promise = Sequelize.Promise
, _ = require('lodash');
chai.use(datetime); chai.use(datetime);
chai.config.includeStack = true; chai.config.includeStack = true;
...@@ -122,106 +123,79 @@ describe(Support.getTestDialectTeaser('Include'), function() { ...@@ -122,106 +123,79 @@ describe(Support.getTestDialectTeaser('Include'), function() {
return Tag.findAll(); return Tag.findAll();
}) })
}).then(function (results) { }).then(function (results) {
var count = 4 var groups = results.groups
, i = -1
, groups = results.groups
, ranks = results.ranks , ranks = results.ranks
, tags = results.tags , tags = results.tags
, companies = results.companies; , companies = results.companies;
return new Promise(function (resolve, reject) { return Promise.reduce(_.range(5), function (memo, i) {
async.whilst( return Promise.props({
function() { return i < count; }, user: User.create(),
function(callback) { products: Product.bulkCreate([
i++;
async.auto({
user: function(callback) {
User.create().nodeify(callback);
},
memberships: ['user', function(callback, results) {
var groupMembers = [
{AccUserId: results.user.id, GroupId: groups[0].id, RankId: ranks[0].id},
{AccUserId: results.user.id, GroupId: groups[1].id, RankId: ranks[2].id}
];
if (i < 3) {
groupMembers.push({AccUserId: results.user.id, GroupId: groups[2].id, RankId: ranks[1].id});
}
GroupMember.bulkCreate(groupMembers).nodeify(callback);
}],
products: function(callback) {
Product.bulkCreate([
{title: 'Chair'}, {title: 'Chair'},
{title: 'Desk'}, {title: 'Desk'},
{title: 'Bed'}, {title: 'Bed'},
{title: 'Pen'}, {title: 'Pen'},
{title: 'Monitor'} {title: 'Monitor'}
]).done(function(err) { ]).then(function(err) {
if (err) return callback(err); return Product.findAll();
Product.findAll().nodeify(callback); })
}); }).then(function (results) {
}, var user = results.user
userProducts: ['user', 'products', function(callback, results) { , products = results.products
results.user.setProducts([ , groupMembers;
results.products[(i * 5) + 0],
results.products[(i * 5) + 1], groupMembers = [
results.products[(i * 5) + 3] {AccUserId: user.id, GroupId: groups[0].id, RankId: ranks[0].id},
]).nodeify(callback); {AccUserId: user.id, GroupId: groups[1].id, RankId: ranks[2].id}
}], ];
productTags: ['products', function(callback, results) { if (i < 3) {
var chainer = new Sequelize.Utils.QueryChainer(); groupMembers.push({AccUserId: user.id, GroupId: groups[2].id, RankId: ranks[1].id});
}
chainer.add(results.products[(i * 5) + 0].setTags([ return Promise.join(
GroupMember.bulkCreate(groupMembers),
user.setProducts([
products[(i * 5) + 0],
products[(i * 5) + 1],
products[(i * 5) + 3]
]),
Promise.join(
products[(i * 5) + 0].setTags([
tags[0], tags[0],
tags[2] tags[2]
])); ]),
chainer.add(results.products[(i * 5) + 1].setTags([ products[(i * 5) + 1].setTags([
tags[1] tags[1]
])); ]),
chainer.add(results.products[(i * 5) + 0].setCategory(tags[1])); products[(i * 5) + 0].setCategory(tags[1]),
products[(i * 5) + 2].setTags([
chainer.add(results.products[(i * 5) + 2].setTags([
tags[0] tags[0]
])); ]),
products[(i * 5) + 3].setTags([
chainer.add(results.products[(i * 5) + 3].setTags([
tags[0] tags[0]
])); ])
),
chainer.run().done(callback); Promise.join(
}], products[(i * 5) + 0].setCompany(companies[4]),
companies: ['products', function(callback, results) { products[(i * 5) + 1].setCompany(companies[3]),
var chainer = new Sequelize.Utils.QueryChainer(); products[(i * 5) + 2].setCompany(companies[2]),
products[(i * 5) + 3].setCompany(companies[1]),
results.products[(i * 5) + 0].setCompany(companies[4]); products[(i * 5) + 4].setCompany(companies[0])
results.products[(i * 5) + 1].setCompany(companies[3]); ),
results.products[(i * 5) + 2].setCompany(companies[2]);
results.products[(i * 5) + 3].setCompany(companies[1]);
results.products[(i * 5) + 4].setCompany(companies[0]);
chainer.run().done(callback);
}],
prices: ['products', function(callback, results) {
Price.bulkCreate([ Price.bulkCreate([
{ProductId: results.products[(i * 5) + 0].id, value: 5}, {ProductId: products[(i * 5) + 0].id, value: 5},
{ProductId: results.products[(i * 5) + 0].id, value: 10}, {ProductId: products[(i * 5) + 0].id, value: 10},
{ProductId: results.products[(i * 5) + 1].id, value: 5}, {ProductId: products[(i * 5) + 1].id, value: 5},
{ProductId: results.products[(i * 5) + 1].id, value: 10}, {ProductId: products[(i * 5) + 1].id, value: 10},
{ProductId: results.products[(i * 5) + 1].id, value: 15}, {ProductId: products[(i * 5) + 1].id, value: 15},
{ProductId: results.products[(i * 5) + 1].id, value: 20}, {ProductId: products[(i * 5) + 1].id, value: 20},
{ProductId: results.products[(i * 5) + 2].id, value: 20}, {ProductId: products[(i * 5) + 2].id, value: 20},
{ProductId: results.products[(i * 5) + 3].id, value: 20} {ProductId: products[(i * 5) + 3].id, value: 20}
]).nodeify(callback); ])
}]
}, callback);
},
function(err) {
if (err) return reject(err);
resolve();
}
); );
}); });
}, []);
}); });
}); });
}; };
...@@ -1046,7 +1020,7 @@ describe(Support.getTestDialectTeaser('Include'), function() { ...@@ -1046,7 +1020,7 @@ describe(Support.getTestDialectTeaser('Include'), function() {
return Promise.join( return Promise.join(
results.users[0].setGroup(results.groups[1]), results.users[0].setGroup(results.groups[1]),
results.users[1].setGroup(results.groups[0]), results.users[1].setGroup(results.groups[0]),
results.groups.map(function (group) { Promise.map(results.groups, function (group) {
return group.setCategories(results.categories); return group.setCategories(results.categories);
}) })
); );
...@@ -1099,7 +1073,7 @@ describe(Support.getTestDialectTeaser('Include'), function() { ...@@ -1099,7 +1073,7 @@ describe(Support.getTestDialectTeaser('Include'), function() {
return Promise.join( return Promise.join(
results.users[0].setTeam(results.groups[1]), results.users[0].setTeam(results.groups[1]),
results.users[1].setTeam(results.groups[0]), results.users[1].setTeam(results.groups[0]),
results.groups.map(function (group) { Promise.map(results.groups, function (group) {
return group.setTags(results.categories); return group.setTags(results.categories);
}) })
); );
...@@ -1152,7 +1126,7 @@ describe(Support.getTestDialectTeaser('Include'), function() { ...@@ -1152,7 +1126,7 @@ describe(Support.getTestDialectTeaser('Include'), function() {
return Promise.join( return Promise.join(
results.users[0].setGroup(results.groups[1]), results.users[0].setGroup(results.groups[1]),
results.users[1].setGroup(results.groups[0]), results.users[1].setGroup(results.groups[0]),
results.groups.map(function (group) { Promise.map(results.groups, function (group) {
return group.setCategories(results.categories); return group.setCategories(results.categories);
}) })
); );
...@@ -1253,7 +1227,7 @@ describe(Support.getTestDialectTeaser('Include'), function() { ...@@ -1253,7 +1227,7 @@ describe(Support.getTestDialectTeaser('Include'), function() {
results.products[2].addTag(results.tags[2], {priority: 2}) results.products[2].addTag(results.tags[2], {priority: 2})
); );
}).then(function () { }).then(function () {
Product.findAll({ return Product.findAll({
include: [ include: [
{model: Tag, where: {name: 'C'}} {model: Tag, where: {name: 'C'}}
] ]
...@@ -1632,8 +1606,7 @@ describe(Support.getTestDialectTeaser('Include'), function() { ...@@ -1632,8 +1606,7 @@ describe(Support.getTestDialectTeaser('Include'), function() {
return Member.bulkCreate(members).then(function () { return Member.bulkCreate(members).then(function () {
return Album.bulkCreate(albums).then(function () { return Album.bulkCreate(albums).then(function () {
return Member.findAll({
Member.findAll({
attributes: ['email'], attributes: ['email'],
include: [ include: [
{ {
......
...@@ -7,7 +7,8 @@ var chai = require('chai') ...@@ -7,7 +7,8 @@ var chai = require('chai')
, DataTypes = require(__dirname + '/../../../lib/data-types') , DataTypes = require(__dirname + '/../../../lib/data-types')
, datetime = require('chai-datetime') , datetime = require('chai-datetime')
, async = require('async') , async = require('async')
, Promise = Sequelize.Promise; , Promise = Sequelize.Promise
, _ = require('lodash');
chai.use(datetime); chai.use(datetime);
chai.config.includeStack = true; chai.config.includeStack = true;
...@@ -126,106 +127,79 @@ describe(Support.getTestDialectTeaser('Includes with schemas'), function() { ...@@ -126,106 +127,79 @@ describe(Support.getTestDialectTeaser('Includes with schemas'), function() {
return Tag.findAll(); return Tag.findAll();
}) })
}).then(function (results) { }).then(function (results) {
var count = 4 var groups = results.groups
, i = -1
, groups = results.groups
, ranks = results.ranks , ranks = results.ranks
, tags = results.tags , tags = results.tags
, companies = results.companies; , companies = results.companies;
return new Promise(function (resolve, reject) { return Promise.reduce(_.range(5), function (memo, i) {
async.whilst( return Promise.props({
function() { return i < count; }, user: AccUser.create(),
function(callback) { products: Product.bulkCreate([
i++;
async.auto({
user: function(callback) {
AccUser.create().done(callback);
},
memberships: ['user', function(callback, results) {
var groupMembers = [
{AccUserId: results.user.id, GroupId: groups[0].id, RankId: ranks[0].id},
{AccUserId: results.user.id, GroupId: groups[1].id, RankId: ranks[2].id}
];
if (i < 3) {
groupMembers.push({AccUserId: results.user.id, GroupId: groups[2].id, RankId: ranks[1].id});
}
GroupMember.bulkCreate(groupMembers).done(callback);
}],
products: function(callback) {
Product.bulkCreate([
{title: 'Chair'}, {title: 'Chair'},
{title: 'Desk'}, {title: 'Desk'},
{title: 'Bed'}, {title: 'Bed'},
{title: 'Pen'}, {title: 'Pen'},
{title: 'Monitor'} {title: 'Monitor'}
]).done(function(err) { ]).then(function(err) {
if (err) return callback(err); return Product.findAll();
Product.findAll().done(callback); })
}); }).then(function (results) {
}, var user = results.user
userProducts: ['user', 'products', function(callback, results) { , products = results.products
results.user.setProducts([ , groupMembers;
results.products[(i * 5) + 0],
results.products[(i * 5) + 1], groupMembers = [
results.products[(i * 5) + 3] {AccUserId: user.id, GroupId: groups[0].id, RankId: ranks[0].id},
]).done(callback); {AccUserId: user.id, GroupId: groups[1].id, RankId: ranks[2].id}
}], ];
productTags: ['products', function(callback, results) { if (i < 3) {
var chainer = new Sequelize.Utils.QueryChainer(); groupMembers.push({AccUserId: user.id, GroupId: groups[2].id, RankId: ranks[1].id});
}
chainer.add(results.products[(i * 5) + 0].setTags([ return Promise.join(
GroupMember.bulkCreate(groupMembers),
user.setProducts([
products[(i * 5) + 0],
products[(i * 5) + 1],
products[(i * 5) + 3]
]),
Promise.join(
products[(i * 5) + 0].setTags([
tags[0], tags[0],
tags[2] tags[2]
])); ]),
chainer.add(results.products[(i * 5) + 1].setTags([ products[(i * 5) + 1].setTags([
tags[1] tags[1]
])); ]),
chainer.add(results.products[(i * 5) + 0].setCategory(tags[1])); products[(i * 5) + 0].setCategory(tags[1]),
products[(i * 5) + 2].setTags([
chainer.add(results.products[(i * 5) + 2].setTags([
tags[0] tags[0]
])); ]),
products[(i * 5) + 3].setTags([
chainer.add(results.products[(i * 5) + 3].setTags([
tags[0] tags[0]
])); ])
),
chainer.run().done(callback); Promise.join(
}], products[(i * 5) + 0].setCompany(companies[4]),
companies: ['products', function(callback, results) { products[(i * 5) + 1].setCompany(companies[3]),
var chainer = new Sequelize.Utils.QueryChainer(); products[(i * 5) + 2].setCompany(companies[2]),
products[(i * 5) + 3].setCompany(companies[1]),
results.products[(i * 5) + 0].setCompany(companies[4]); products[(i * 5) + 4].setCompany(companies[0])
results.products[(i * 5) + 1].setCompany(companies[3]); ),
results.products[(i * 5) + 2].setCompany(companies[2]);
results.products[(i * 5) + 3].setCompany(companies[1]);
results.products[(i * 5) + 4].setCompany(companies[0]);
chainer.run().done(callback);
}],
prices: ['products', function(callback, results) {
Price.bulkCreate([ Price.bulkCreate([
{ProductId: results.products[(i * 5) + 0].id, value: 5}, {ProductId: products[(i * 5) + 0].id, value: 5},
{ProductId: results.products[(i * 5) + 0].id, value: 10}, {ProductId: products[(i * 5) + 0].id, value: 10},
{ProductId: results.products[(i * 5) + 1].id, value: 5}, {ProductId: products[(i * 5) + 1].id, value: 5},
{ProductId: results.products[(i * 5) + 1].id, value: 10}, {ProductId: products[(i * 5) + 1].id, value: 10},
{ProductId: results.products[(i * 5) + 1].id, value: 15}, {ProductId: products[(i * 5) + 1].id, value: 15},
{ProductId: results.products[(i * 5) + 1].id, value: 20}, {ProductId: products[(i * 5) + 1].id, value: 20},
{ProductId: results.products[(i * 5) + 2].id, value: 20}, {ProductId: products[(i * 5) + 2].id, value: 20},
{ProductId: results.products[(i * 5) + 3].id, value: 20} {ProductId: products[(i * 5) + 3].id, value: 20}
]).done(callback); ])
}]
}, callback);
},
function(err) {
if (err) return reject(err);
resolve();
}
); );
}); });
}, []);
}); });
}); });
}); });
......
...@@ -291,7 +291,7 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -291,7 +291,7 @@ describe(Support.getTestDialectTeaser('Model'), function() {
}); });
}); });
it('allows multiple column unique keys to be defined', function(done) { it('allows multiple column unique keys to be defined', function() {
var User = this.sequelize.define('UserWithUniqueUsername', { var User = this.sequelize.define('UserWithUniqueUsername', {
username: { type: Sequelize.STRING, unique: 'user_and_email' }, username: { type: Sequelize.STRING, unique: 'user_and_email' },
email: { type: Sequelize.STRING, unique: 'user_and_email' }, email: { type: Sequelize.STRING, unique: 'user_and_email' },
...@@ -299,7 +299,7 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -299,7 +299,7 @@ describe(Support.getTestDialectTeaser('Model'), function() {
bCol: { type: Sequelize.STRING, unique: 'a_and_b' } bCol: { type: Sequelize.STRING, unique: 'a_and_b' }
}); });
User.sync({ force: true }).on('sql', _.after(2, _.once(function(sql) { return User.sync({ force: true, logging: _.after(2, _.once(function(sql) {
if (dialect === 'mssql') { if (dialect === 'mssql') {
expect(sql).to.match(/CONSTRAINT\s*([`"\[]?user_and_email[`"\]]?)?\s*UNIQUE\s*\([`"\[]?username[`"\]]?, [`"\[]?email[`"\]]?\)/); expect(sql).to.match(/CONSTRAINT\s*([`"\[]?user_and_email[`"\]]?)?\s*UNIQUE\s*\([`"\[]?username[`"\]]?, [`"\[]?email[`"\]]?\)/);
expect(sql).to.match(/CONSTRAINT\s*([`"\[]?a_and_b[`"\]]?)?\s*UNIQUE\s*\([`"\[]?aCol[`"\]]?, [`"\[]?bCol[`"\]]?\)/); expect(sql).to.match(/CONSTRAINT\s*([`"\[]?a_and_b[`"\]]?)?\s*UNIQUE\s*\([`"\[]?aCol[`"\]]?, [`"\[]?bCol[`"\]]?\)/);
...@@ -307,8 +307,7 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -307,8 +307,7 @@ describe(Support.getTestDialectTeaser('Model'), function() {
expect(sql).to.match(/UNIQUE\s*([`"]?user_and_email[`"]?)?\s*\([`"]?username[`"]?, [`"]?email[`"]?\)/); expect(sql).to.match(/UNIQUE\s*([`"]?user_and_email[`"]?)?\s*\([`"]?username[`"]?, [`"]?email[`"]?\)/);
expect(sql).to.match(/UNIQUE\s*([`"]?a_and_b[`"]?)?\s*\([`"]?aCol[`"]?, [`"]?bCol[`"]?\)/); expect(sql).to.match(/UNIQUE\s*([`"]?a_and_b[`"]?)?\s*\([`"]?aCol[`"]?, [`"]?bCol[`"]?\)/);
} }
done(); }))});
})));
}); });
it('allows unique on column with field aliases', function() { it('allows unique on column with field aliases', function() {
...@@ -1423,7 +1422,7 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -1423,7 +1422,7 @@ describe(Support.getTestDialectTeaser('Model'), function() {
}); });
}); });
it('supports table schema/prefix', function(done) { it('supports table schema/prefix', function() {
var self = this var self = this
, data = [{ username: 'Peter', secretValue: '42' }, , data = [{ username: 'Peter', secretValue: '42' },
{ username: 'Paul', secretValue: '42' }, { username: 'Paul', secretValue: '42' },
...@@ -1431,24 +1430,23 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -1431,24 +1430,23 @@ describe(Support.getTestDialectTeaser('Model'), function() {
, prefixUser = self.User.schema('prefix'); , prefixUser = self.User.schema('prefix');
var run = function() { var run = function() {
prefixUser.sync({ force: true }).success(function() { return prefixUser.sync({ force: true }).then(function() {
prefixUser.bulkCreate(data).success(function() { return prefixUser.bulkCreate(data).then(function() {
prefixUser.destroy({where: {secretValue: '42'}}) return prefixUser.destroy({where: {secretValue: '42'}}).then(function() {
.success(function() { return prefixUser.findAll({order: 'id'}).then(function(users) {
prefixUser.findAll({order: 'id'}).success(function(users) {
expect(users.length).to.equal(1); expect(users.length).to.equal(1);
expect(users[0].username).to.equal('Bob'); expect(users[0].username).to.equal('Bob');
done();
}); });
}); });
}); });
}); });
}; };
this.sequelize.queryInterface.createSchema('prefix').success(function() { return this.sequelize.queryInterface.dropAllSchemas().then(function() {
run.call(self); return self.sequelize.queryInterface.createSchema('prefix').then(function() {
return run.call(self);
});
}); });
}); });
}); });
...@@ -2022,7 +2020,7 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -2022,7 +2020,7 @@ describe(Support.getTestDialectTeaser('Model'), function() {
}); });
}); });
it('should be able to reference a table with a schema set', function(done) { it('should be able to reference a table with a schema set', function() {
var self = this; var self = this;
var UserPub = this.sequelize.define('UserPub', { var UserPub = this.sequelize.define('UserPub', {
...@@ -2038,8 +2036,8 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -2038,8 +2036,8 @@ describe(Support.getTestDialectTeaser('Model'), function() {
}); });
var run = function() { var run = function() {
UserPub.sync({ force: true }).success(function() { return UserPub.sync({ force: true }).then(function() {
ItemPub.sync({ force: true }).on('sql', _.after(2, _.once(function(sql) { return ItemPub.sync({ force: true, logging: _.after(2, _.once(function(sql) {
if (dialect === 'postgres') { if (dialect === 'postgres') {
expect(sql).to.match(/REFERENCES\s+"prefix"\."UserPubs" \("id"\)/); expect(sql).to.match(/REFERENCES\s+"prefix"\."UserPubs" \("id"\)/);
} else if (dialect === 'mssql') { } else if (dialect === 'mssql') {
...@@ -2047,17 +2045,19 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -2047,17 +2045,19 @@ describe(Support.getTestDialectTeaser('Model'), function() {
} else { } else {
expect(sql).to.match(/REFERENCES\s+`prefix\.UserPubs` \(`id`\)/); expect(sql).to.match(/REFERENCES\s+`prefix\.UserPubs` \(`id`\)/);
} }
done();
}))); }))});
}); });
}; };
if (dialect === 'postgres') { if (dialect === 'postgres') {
this.sequelize.queryInterface.createSchema('prefix').success(function() { return this.sequelize.queryInterface.dropAllSchemas().then(function() {
run.call(self); return self.sequelize.queryInterface.createSchema('prefix').then(function() {
return run.call(self);
});
}); });
} else { } else {
run.call(self); return run.call(self);
} }
}); });
...@@ -2127,7 +2127,7 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -2127,7 +2127,7 @@ describe(Support.getTestDialectTeaser('Model'), function() {
}); });
}); });
it('uses an existing dao factory and references the author table', function(done) { it('uses an existing dao factory and references the author table', function() {
var self = this var self = this
, Post = this.sequelize.define('post', { , Post = this.sequelize.define('post', {
title: Sequelize.STRING, title: Sequelize.STRING,
...@@ -2142,7 +2142,7 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -2142,7 +2142,7 @@ describe(Support.getTestDialectTeaser('Model'), function() {
Post.belongsTo(this.Author); Post.belongsTo(this.Author);
// The posts table gets dropped in the before filter. // The posts table gets dropped in the before filter.
Post.sync().on('sql', _.once(function(sql) { return Post.sync({logging: _.once(function(sql) {
if (dialect === 'postgres') { if (dialect === 'postgres') {
expect(sql).to.match(/"authorId" INTEGER REFERENCES "authors" \("id"\)/); expect(sql).to.match(/"authorId" INTEGER REFERENCES "authors" \("id"\)/);
} else if (Support.dialectIsMySQL()) { } else if (Support.dialectIsMySQL()) {
...@@ -2154,12 +2154,10 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -2154,12 +2154,10 @@ describe(Support.getTestDialectTeaser('Model'), function() {
} else { } else {
throw new Error('Undefined dialect!'); throw new Error('Undefined dialect!');
} }
})});
done();
}));
}); });
it('uses a table name as a string and references the author table', function(done) { it('uses a table name as a string and references the author table', function() {
var self = this var self = this
, Post = self.sequelize.define('post', { , Post = self.sequelize.define('post', {
title: Sequelize.STRING, title: Sequelize.STRING,
...@@ -2174,7 +2172,7 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -2174,7 +2172,7 @@ describe(Support.getTestDialectTeaser('Model'), function() {
Post.belongsTo(this.Author); Post.belongsTo(this.Author);
// The posts table gets dropped in the before filter. // The posts table gets dropped in the before filter.
Post.sync().on('sql', _.once(function(sql) { return Post.sync({logging: _.once(function(sql) {
if (dialect === 'postgres') { if (dialect === 'postgres') {
expect(sql).to.match(/"authorId" INTEGER REFERENCES "authors" \("id"\)/); expect(sql).to.match(/"authorId" INTEGER REFERENCES "authors" \("id"\)/);
} else if (Support.dialectIsMySQL()) { } else if (Support.dialectIsMySQL()) {
...@@ -2186,9 +2184,7 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -2186,9 +2184,7 @@ describe(Support.getTestDialectTeaser('Model'), function() {
} else { } else {
throw new Error('Undefined dialect!'); throw new Error('Undefined dialect!');
} }
})});
done();
}));
}); });
it('emits an error event as the referenced table name is invalid', function(done) { it('emits an error event as the referenced table name is invalid', function(done) {
...@@ -2238,7 +2234,7 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -2238,7 +2234,7 @@ describe(Support.getTestDialectTeaser('Model'), function() {
}); });
}); });
it('works with comments', function(done) { it('works with comments', function() {
// Test for a case where the comment was being moved to the end of the table when there was also a reference on the column, see #1521 // Test for a case where the comment was being moved to the end of the table when there was also a reference on the column, see #1521
var Member = this.sequelize.define('Member', {}) var Member = this.sequelize.define('Member', {})
, Profile = this.sequelize.define('Profile', { , Profile = this.sequelize.define('Profile', {
...@@ -2252,30 +2248,25 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -2252,30 +2248,25 @@ describe(Support.getTestDialectTeaser('Model'), function() {
} }
}); });
this.sequelize.sync({ force: true }).success(function() { return this.sequelize.sync({ force: true });
done();
});
}); });
}); });
describe('blob', function() { describe('blob', function() {
beforeEach(function(done) { beforeEach(function() {
this.BlobUser = this.sequelize.define('blobUser', { this.BlobUser = this.sequelize.define('blobUser', {
data: Sequelize.BLOB data: Sequelize.BLOB
}); });
this.BlobUser.sync({ force: true }).success(function() { return this.BlobUser.sync({ force: true });
done();
});
}); });
describe('buffers', function() { describe('buffers', function() {
it('should be able to take a buffer as parameter to a BLOB field', function(done) { it('should be able to take a buffer as parameter to a BLOB field', function() {
this.BlobUser.create({ return this.BlobUser.create({
data: new Buffer('Sequelize') data: new Buffer('Sequelize')
}).success(function(user) { }).then(function(user) {
expect(user).to.be.ok; expect(user).to.be.ok;
done();
}); });
}); });
...@@ -2511,40 +2502,37 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -2511,40 +2502,37 @@ describe(Support.getTestDialectTeaser('Model'), function() {
} }
describe('Unique', function() { describe('Unique', function() {
it('should set unique when unique is true', function(done) { it('should set unique when unique is true', function() {
var self = this; var self = this;
var uniqueTrue = self.sequelize.define('uniqueTrue', { var uniqueTrue = self.sequelize.define('uniqueTrue', {
str: { type: Sequelize.STRING, unique: true } str: { type: Sequelize.STRING, unique: true }
}); });
uniqueTrue.sync({force: true}).on('sql', _.after(2, _.once(function(s) { return uniqueTrue.sync({force: true, logging: _.after(2, _.once(function(s) {
expect(s).to.match(/UNIQUE/); expect(s).to.match(/UNIQUE/);
done(); }))});
})));
}); });
it('should not set unique when unique is false', function(done) { it('should not set unique when unique is false', function() {
var self = this; var self = this;
var uniqueFalse = self.sequelize.define('uniqueFalse', { var uniqueFalse = self.sequelize.define('uniqueFalse', {
str: { type: Sequelize.STRING, unique: false } str: { type: Sequelize.STRING, unique: false }
}); });
uniqueFalse.sync({force: true}).on('sql', _.after(2, _.once(function(s) { return uniqueFalse.sync({force: true, logging: _.after(2, _.once(function(s) {
expect(s).not.to.match(/UNIQUE/); expect(s).not.to.match(/UNIQUE/);
done(); }))});
})));
}); });
it('should not set unique when unique is unset', function(done) { it('should not set unique when unique is unset', function() {
var self = this; var self = this;
var uniqueUnset = self.sequelize.define('uniqueUnset', { var uniqueUnset = self.sequelize.define('uniqueUnset', {
str: { type: Sequelize.STRING } str: { type: Sequelize.STRING }
}); });
uniqueUnset.sync({force: true}).on('sql', _.after(2, _.once(function(s) { return uniqueUnset.sync({force: true, logging: _.after(2, _.once(function(s) {
expect(s).not.to.match(/UNIQUE/); expect(s).not.to.match(/UNIQUE/);
done(); }))});
})));
}); });
}); });
......
...@@ -114,11 +114,13 @@ describe(Support.getTestDialectTeaser('Sequelize'), function() { ...@@ -114,11 +114,13 @@ describe(Support.getTestDialectTeaser('Sequelize'), function() {
.sequelizeWithInvalidConnection .sequelizeWithInvalidConnection
.authenticate() .authenticate()
.complete(function(err, result) { .complete(function(err, result) {
console.log(err.message);
expect( expect(
err.message.match(/connect ECONNREFUSED/) || err.message.match(/connect ECONNREFUSED/) ||
err.message.match(/invalid port number/) || err.message.match(/invalid port number/) ||
err.message.match(/RangeError: Port should be > 0 and < 65536/) || err.message.match(/RangeError: Port should be > 0 and < 65536/) ||
err.message.match(/RangeError: port should be > 0 and < 65536/) || err.message.match(/RangeError: port should be > 0 and < 65536/) ||
err.message.match(/RangeError: port should be >= 0 and < 65536: 99999/) ||
err.message.match(/ConnectionError: Login failed for user/) err.message.match(/ConnectionError: Login failed for user/)
).to.be.ok; ).to.be.ok;
done(); done();
......
...@@ -10,21 +10,33 @@ var chai = require('chai') ...@@ -10,21 +10,33 @@ var chai = require('chai')
if (current.dialect.supports.transactions) { if (current.dialect.supports.transactions) {
describe(Support.getTestDialectTeaser('Sequelize#transaction'), function() { describe(Support.getTestDialectTeaser('Sequelize#transaction'), function() {
this.timeout(4000); describe('then', function() {
it('gets triggered once a transaction has been successfully committed', function() {
describe('success', function() { var called = false;
it('gets triggered once a transaction has been successfully committed', function(done) { return this
this
.sequelize .sequelize
.transaction().then(function(t) { t.commit(); }) .transaction().then(function(t) {
.success(function() { done(); }); return t.commit().then(function () {
called = 1;
});
})
.then(function() {
expect(called).to.be.ok;
});
}); });
it('gets triggered once a transaction has been successfully rolled back', function(done) { it('gets triggered once a transaction has been successfully rolled back', function() {
this var called = false;
return this
.sequelize .sequelize
.transaction().then(function(t) { t.rollback(); }) .transaction().then(function(t) {
.success(function() { done(); }); return t.rollback().then(function () {
called = 1;
});
})
.then(function() {
expect(called).to.be.ok;
});
}); });
if (Support.getTestDialect() !== 'sqlite') { if (Support.getTestDialect() !== 'sqlite') {
...@@ -71,52 +83,29 @@ describe(Support.getTestDialectTeaser('Sequelize#transaction'), function() { ...@@ -71,52 +83,29 @@ describe(Support.getTestDialectTeaser('Sequelize#transaction'), function() {
} }
}); });
describe('error', function() {
if (Support.getTestDialect() === 'sqlite') {
// not sure if we can test this in sqlite ...
// how could we enforce an authentication error in sqlite?
} else {
it('gets triggered once an error occurs', function(done) {
// Supply bad config to force an error
var sequelize = Support.getSequelizeInstance('this', 'is', 'fake config');
sequelize
.transaction().then(function() {})
.catch (function(err) {
expect(err).to.not.be.undefined;
done();
});
});
}
});
describe('complex long running example', function() { describe('complex long running example', function() {
it('works with promise syntax', function(done) { it('works with promise syntax', function() {
Support.prepareTransactionTest(this.sequelize, function(sequelize) { return Support.prepareTransactionTest(this.sequelize).then(function(sequelize) {
var Test = sequelize.define('Test', { var Test = sequelize.define('Test', {
id: { type: Support.Sequelize.INTEGER, primaryKey: true, autoIncrement: true}, id: { type: Support.Sequelize.INTEGER, primaryKey: true, autoIncrement: true},
name: { type: Support.Sequelize.STRING } name: { type: Support.Sequelize.STRING }
}); });
sequelize return sequelize.sync({ force: true }).then(function() {
.sync({ force: true }) return sequelize.transaction().then(function(transaction) {
.then(function() {
sequelize.transaction().then(function(transaction) {
expect(transaction).to.be.instanceOf(Transaction); expect(transaction).to.be.instanceOf(Transaction);
Test return Test
.create({ name: 'Peter' }, { transaction: transaction }) .create({ name: 'Peter' }, { transaction: transaction })
.then(function() { .then(function() {
setTimeout(function() { return Promise.delay(1000).then(function () {
transaction return transaction
.commit() .commit()
.then(function() { return Test.count(); }) .then(function() { return Test.count(); })
.then(function(count) { .then(function(count) {
expect(count).to.equal(1); expect(count).to.equal(1);
done();
}); });
}, 1000); });
}); });
}); });
}); });
...@@ -126,10 +115,10 @@ describe(Support.getTestDialectTeaser('Sequelize#transaction'), function() { ...@@ -126,10 +115,10 @@ describe(Support.getTestDialectTeaser('Sequelize#transaction'), function() {
describe('concurrency', function() { describe('concurrency', function() {
describe('having tables with uniqueness constraints', function() { describe('having tables with uniqueness constraints', function() {
beforeEach(function(done) { beforeEach(function() {
var self = this; var self = this;
Support.prepareTransactionTest(this.sequelize, function(sequelize) { return Support.prepareTransactionTest(this.sequelize).then(function(sequelize) {
self.sequelize = sequelize; self.sequelize = sequelize;
self.Model = sequelize.define('Model', { self.Model = sequelize.define('Model', {
...@@ -138,9 +127,7 @@ describe(Support.getTestDialectTeaser('Sequelize#transaction'), function() { ...@@ -138,9 +127,7 @@ describe(Support.getTestDialectTeaser('Sequelize#transaction'), function() {
timestamps: false timestamps: false
}); });
self.Model return self.Model.sync({ force: true });
.sync({ force: true })
.success(function() { done(); });
}); });
}); });
......
...@@ -20,7 +20,17 @@ before(function() { ...@@ -20,7 +20,17 @@ before(function() {
}); });
beforeEach(function() { beforeEach(function() {
this.sequelize.test.trackRunningQueries();
return Support.clearDatabase(this.sequelize); return Support.clearDatabase(this.sequelize);
}); });
afterEach(function () {
try {
this.sequelize.test.verifyNoRunningQueries();
} catch (err) {
err.message += " in "+this.currentTest.fullTitle();
throw err;
}
});
module.exports = Support; module.exports = Support;
...@@ -121,8 +121,7 @@ describe(Support.getTestDialectTeaser('Transaction'), function() { ...@@ -121,8 +121,7 @@ describe(Support.getTestDialectTeaser('Transaction'), function() {
if (current.dialect.supports.lock) { if (current.dialect.supports.lock) {
describe('row locking', function () { describe('row locking', function () {
this.timeout(10000); it('supports for update', function() {
it('supports for update', function(done) {
var User = this.sequelize.define('user', { var User = this.sequelize.define('user', {
username: Support.Sequelize.STRING, username: Support.Sequelize.STRING,
awesome: Support.Sequelize.BOOLEAN awesome: Support.Sequelize.BOOLEAN
...@@ -131,10 +130,10 @@ describe(Support.getTestDialectTeaser('Transaction'), function() { ...@@ -131,10 +130,10 @@ describe(Support.getTestDialectTeaser('Transaction'), function() {
, t1Spy = sinon.spy() , t1Spy = sinon.spy()
, t2Spy = sinon.spy(); , t2Spy = sinon.spy();
this.sequelize.sync({ force: true }).then(function() { return this.sequelize.sync({ force: true }).then(function() {
return User.create({ username: 'jan'}); return User.create({ username: 'jan'});
}).then(function() { }).then(function() {
self.sequelize.transaction().then(function(t1) { return self.sequelize.transaction().then(function(t1) {
return User.find({ return User.find({
where: { where: {
username: 'jan' username: 'jan'
...@@ -143,9 +142,10 @@ describe(Support.getTestDialectTeaser('Transaction'), function() { ...@@ -143,9 +142,10 @@ describe(Support.getTestDialectTeaser('Transaction'), function() {
lock: t1.LOCK.UPDATE, lock: t1.LOCK.UPDATE,
transaction: t1 transaction: t1
}).then(function(t1Jan) { }).then(function(t1Jan) {
self.sequelize.transaction({ return self.sequelize.transaction({
isolationLevel: Transaction.ISOLATION_LEVELS.READ_COMMITTED isolationLevel: Transaction.ISOLATION_LEVELS.READ_COMMITTED
}).then(function(t2) { }).then(function(t2) {
return Promise.join(
User.find({ User.find({
where: { where: {
username: 'jan' username: 'jan'
...@@ -155,25 +155,27 @@ describe(Support.getTestDialectTeaser('Transaction'), function() { ...@@ -155,25 +155,27 @@ describe(Support.getTestDialectTeaser('Transaction'), function() {
transaction: t2 transaction: t2
}).then(function() { }).then(function() {
t2Spy(); t2Spy();
t2.commit().then(function() { return t2.commit().then(function() {
expect(t2Spy).to.have.been.calledAfter(t1Spy); // Find should not succeed before t1 has comitted expect(t2Spy).to.have.been.calledAfter(t1Spy); // Find should not succeed before t1 has comitted
done();
});
}); });
}),
t1Jan.updateAttributes({ t1Jan.updateAttributes({
awesome: true awesome: true
}, { transaction: t1}).then(function() { }, { transaction: t1}).then(function() {
t1Spy(); t1Spy();
setTimeout(t1.commit.bind(t1), 2000); return Promise.delay(2000).then(function () {
return t1.commit();
}); });
})
);
}); });
}); });
}); });
}); });
}); });
it('supports for share', function(done) { it('supports for share', function() {
var User = this.sequelize.define('user', { var User = this.sequelize.define('user', {
username: Support.Sequelize.STRING, username: Support.Sequelize.STRING,
awesome: Support.Sequelize.BOOLEAN awesome: Support.Sequelize.BOOLEAN
...@@ -183,10 +185,10 @@ describe(Support.getTestDialectTeaser('Transaction'), function() { ...@@ -183,10 +185,10 @@ describe(Support.getTestDialectTeaser('Transaction'), function() {
, t2FindSpy = sinon.spy() , t2FindSpy = sinon.spy()
, t2UpdateSpy = sinon.spy(); , t2UpdateSpy = sinon.spy();
this.sequelize.sync({ force: true }).then(function() { return this.sequelize.sync({ force: true }).then(function() {
return User.create({ username: 'jan'}); return User.create({ username: 'jan'});
}).then(function() { }).then(function() {
self.sequelize.transaction().then(function(t1) { return self.sequelize.transaction().then(function(t1) {
return User.find({ return User.find({
where: { where: {
username: 'jan' username: 'jan'
...@@ -195,9 +197,10 @@ describe(Support.getTestDialectTeaser('Transaction'), function() { ...@@ -195,9 +197,10 @@ describe(Support.getTestDialectTeaser('Transaction'), function() {
lock: t1.LOCK.SHARE, lock: t1.LOCK.SHARE,
transaction: t1 transaction: t1
}).then(function(t1Jan) { }).then(function(t1Jan) {
self.sequelize.transaction({ return self.sequelize.transaction({
isolationLevel: Transaction.ISOLATION_LEVELS.READ_COMMITTED isolationLevel: Transaction.ISOLATION_LEVELS.READ_COMMITTED
}).then(function(t2) { }).then(function(t2) {
return Promise.join(
User.find({ User.find({
where: { where: {
username: 'jan' username: 'jan'
...@@ -205,30 +208,30 @@ describe(Support.getTestDialectTeaser('Transaction'), function() { ...@@ -205,30 +208,30 @@ describe(Support.getTestDialectTeaser('Transaction'), function() {
}, { transaction: t2}).then(function(t2Jan) { }, { transaction: t2}).then(function(t2Jan) {
t2FindSpy(); t2FindSpy();
t2Jan.updateAttributes({ return t2Jan.updateAttributes({
awesome: false awesome: false
}, { }, {
transaction: t2 transaction: t2
}).then(function() { }).then(function() {
t2UpdateSpy(); t2UpdateSpy();
t2.commit().then(function() { return t2.commit().then(function() {
expect(t2FindSpy).to.have.been.calledBefore(t1Spy); // The find call should have returned expect(t2FindSpy).to.have.been.calledBefore(t1Spy); // The find call should have returned
expect(t2UpdateSpy).to.have.been.calledAfter(t1Spy); // But the update call should not happen before the first transaction has committed expect(t2UpdateSpy).to.have.been.calledAfter(t1Spy); // But the update call should not happen before the first transaction has committed
done();
});
}); });
}); });
}),
t1Jan.updateAttributes({ t1Jan.updateAttributes({
awesome: true awesome: true
}, { }, {
transaction: t1 transaction: t1
}).then(function() { }).then(function() {
setTimeout(function() { return Promise.delay(2000).then(function () {
t1Spy(); t1Spy();
t1.commit(); return t1.commit();
}, 2000);
}); });
})
);
}); });
}); });
}); });
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!