test: fix broken Role tests

Rework the test suite to always report errors and correctly signal
when async tests are done.

This should prevent spurious test failures on CI servers that are
difficult to troubleshoot, because the error is reported for different
test case.
This commit is contained in:
Miroslav Bajtoš 2016-08-03 15:55:29 +02:00
parent 7546ee531d
commit 48205fb2bd
1 changed files with 319 additions and 154 deletions

View File

@ -6,11 +6,6 @@
var assert = require('assert');
var sinon = require('sinon');
var loopback = require('../index');
var Role = loopback.Role;
var RoleMapping = loopback.RoleMapping;
var User = loopback.User;
var Application = loopback.Application;
var ACL = loopback.ACL;
var async = require('async');
var expect = require('chai').expect;
var Promise = require('bluebird');
@ -20,17 +15,29 @@ function checkResult(err, result) {
}
describe('role model', function() {
var ds;
var app, Role, RoleMapping, User, Application, ACL;
beforeEach(function() {
ds = loopback.createDataSource({ connector: 'memory' });
// Re-attach the models so that they can have isolated store to avoid
// Use local app registry to ensure models are isolated to avoid
// pollutions from other tests
ACL.attachTo(ds);
User.attachTo(ds);
Role.attachTo(ds);
RoleMapping.attachTo(ds);
Application.attachTo(ds);
app = loopback({ localRegistry: true, loadBuiltinModels: true });
app.dataSource('db', { connector: 'memory' });
ACL = app.registry.getModel('ACL');
app.model(ACL, { dataSource: 'db' });
User = app.registry.getModel('User');
app.model(User, { dataSource: 'db' });
Role = app.registry.getModel('Role');
app.model(Role, { dataSource: 'db' });
RoleMapping = app.registry.getModel('RoleMapping');
app.model(RoleMapping, { dataSource: 'db' });
Application = app.registry.getModel('Application');
app.model(Application, { dataSource: 'db' });
ACL.roleModel = Role;
ACL.roleMappingModel = RoleMapping;
ACL.userModel = User;
@ -40,51 +47,88 @@ describe('role model', function() {
Role.applicationModel = Application;
});
it('should define role/role relations', function() {
it('should define role/role relations', function(done) {
Role.create({ name: 'user' }, function(err, userRole) {
if (err) return done(err);
Role.create({ name: 'admin' }, function(err, adminRole) {
userRole.principals.create({ principalType: RoleMapping.ROLE, principalId: adminRole.id },
if (err) return done(err);
userRole.principals.create(
{ principalType: RoleMapping.ROLE, principalId: adminRole.id },
function(err, mapping) {
if (err) return done(err);
async.parallel([
function(next) {
Role.find(function(err, roles) {
if (err) return next(err);
assert.equal(roles.length, 2);
next();
});
},
function(next) {
RoleMapping.find(function(err, mappings) {
if (err) return next(err);
assert.equal(mappings.length, 1);
assert.equal(mappings[0].principalType, RoleMapping.ROLE);
assert.equal(mappings[0].principalId, adminRole.id);
next();
});
},
function(next) {
userRole.principals(function(err, principals) {
if (err) return next(err);
assert.equal(principals.length, 1);
next();
});
},
function(next) {
userRole.roles(function(err, roles) {
if (err) return next(err);
assert.equal(roles.length, 1);
next();
});
},
], done);
});
});
});
});
it('should define role/user relations', function() {
it('should define role/user relations', function(done) {
User.create({ name: 'Raymond', email: 'x@y.com', password: 'foobar' }, function(err, user) {
if (err) return done(err);
Role.create({ name: 'userRole' }, function(err, role) {
if (err) return done(err);
role.principals.create({ principalType: RoleMapping.USER, principalId: user.id },
function(err, p) {
if (err) return done(err);
async.parallel([
function(next) {
Role.find(function(err, roles) {
assert(!err);
if (err) return next(err);
assert.equal(roles.length, 1);
assert.equal(roles[0].name, 'userRole');
next();
});
},
function(next) {
role.principals(function(err, principals) {
assert(!err);
if (err) return next(err);
assert.equal(principals.length, 1);
assert.equal(principals[0].principalType, RoleMapping.USER);
assert.equal(principals[0].principalId, user.id);
next();
});
},
function(next) {
role.users(function(err, users) {
assert(!err);
if (err) return next(err);
assert.equal(users.length, 1);
assert.equal(users[0].id, user.id);
next();
});
},
], done);
});
});
});
@ -106,86 +150,146 @@ describe('role model', function() {
});
});
it('should automatically generate role id', function() {
it('should automatically generate role id', function(done) {
User.create({ name: 'Raymond', email: 'x@y.com', password: 'foobar' }, function(err, user) {
if (err) return done(err);
Role.create({ name: 'userRole' }, function(err, role) {
if (err) return done(err);
assert(role.id);
role.principals.create({ principalType: RoleMapping.USER, principalId: user.id },
function(err, p) {
if (err) return done(err);
assert(p.id);
assert.equal(p.roleId, role.id);
async.parallel([
function(next) {
Role.find(function(err, roles) {
assert(!err);
if (err) return next(err);
assert.equal(roles.length, 1);
assert.equal(roles[0].name, 'userRole');
next();
});
},
function(next) {
role.principals(function(err, principals) {
assert(!err);
if (err) return next(err);
assert.equal(principals.length, 1);
assert.equal(principals[0].principalType, RoleMapping.USER);
assert.equal(principals[0].principalId, user.id);
next();
});
},
function(next) {
role.users(function(err, users) {
assert(!err);
if (err) return next(err);
assert.equal(users.length, 1);
assert.equal(users[0].id, user.id);
});
next();
},
], done);
});
});
});
});
it('should support getRoles() and isInRole()', function() {
it('should support getRoles() and isInRole()', function(done) {
User.create({ name: 'Raymond', email: 'x@y.com', password: 'foobar' }, function(err, user) {
if (err) return done(err);
Role.create({ name: 'userRole' }, function(err, role) {
if (err) return done(err);
role.principals.create({ principalType: RoleMapping.USER, principalId: user.id },
function(err, p) {
Role.isInRole('userRole', { principalType: RoleMapping.USER, principalId: user.id },
function(err, exists) {
assert(!err && exists === true);
if (err) return done(err);
async.series([
function(next) {
Role.isInRole(
'userRole',
{ principalType: RoleMapping.USER, principalId: user.id },
function(err, inRole) {
if (err) return next(err);
// NOTE(bajtos) Apparently isRole is not a boolean,
// but the matchin role object instead
assert(!!inRole);
next();
});
Role.isInRole('userRole', { principalType: RoleMapping.APP, principalId: user.id },
function(err, exists) {
assert(!err && exists === false);
},
function(next) {
Role.isInRole(
'userRole',
{ principalType: RoleMapping.APP, principalId: user.id },
function(err, inRole) {
if (err) return next(err);
assert(!inRole);
next();
});
Role.isInRole('userRole', { principalType: RoleMapping.USER, principalId: 100 },
function(err, exists) {
assert(!err && exists === false);
},
function(next) {
Role.isInRole(
'userRole',
{ principalType: RoleMapping.USER, principalId: 100 },
function(err, inRole) {
if (err) return next(err);
assert(!inRole);
next();
});
Role.getRoles({ principalType: RoleMapping.USER, principalId: user.id },
},
function(next) {
Role.getRoles(
{ principalType: RoleMapping.USER, principalId: user.id },
function(err, roles) {
assert.equal(roles.length, 3); // everyone, authenticated, userRole
assert(roles.indexOf(role.id) >= 0);
assert(roles.indexOf(Role.EVERYONE) >= 0);
assert(roles.indexOf(Role.AUTHENTICATED) >= 0);
if (err) return next(err);
expect(roles).to.eql([
Role.AUTHENTICATED,
Role.EVERYONE,
role.id,
]);
next();
});
Role.getRoles({ principalType: RoleMapping.APP, principalId: user.id },
},
function(next) {
Role.getRoles(
{ principalType: RoleMapping.APP, principalId: user.id },
function(err, roles) {
assert.equal(roles.length, 2);
assert(roles.indexOf(Role.EVERYONE) >= 0);
assert(roles.indexOf(Role.AUTHENTICATED) >= 0);
if (err) return next(err);
expect(roles).to.eql([
Role.AUTHENTICATED,
Role.EVERYONE,
]);
next();
});
Role.getRoles({ principalType: RoleMapping.USER, principalId: 100 },
},
function(next) {
Role.getRoles(
{ principalType: RoleMapping.USER, principalId: 100 },
function(err, roles) {
assert.equal(roles.length, 2);
assert(roles.indexOf(Role.EVERYONE) >= 0);
assert(roles.indexOf(Role.AUTHENTICATED) >= 0);
if (err) return next(err);
expect(roles).to.eql([
Role.AUTHENTICATED,
Role.EVERYONE,
]);
next();
});
Role.getRoles({ principalType: RoleMapping.USER, principalId: null },
},
function(next) {
Role.getRoles(
{ principalType: RoleMapping.USER, principalId: null },
function(err, roles) {
assert.equal(roles.length, 2);
assert(roles.indexOf(Role.EVERYONE) >= 0);
assert(roles.indexOf(Role.UNAUTHENTICATED) >= 0);
if (err) return next(err);
expect(roles).to.eql([
Role.UNAUTHENTICATED,
Role.EVERYONE,
]);
next();
});
},
], done);
});
});
});
});
it('should support owner role resolver', function() {
it('should support owner role resolver', function(done) {
Role.registerResolver('returnPromise', function(role, context) {
return new Promise(function(resolve) {
process.nextTick(function() {
@ -194,7 +298,7 @@ describe('role model', function() {
});
});
var Album = ds.createModel('Album', {
var Album = app.registry.createModel('Album', {
name: String,
userId: Number,
}, {
@ -206,55 +310,109 @@ describe('role model', function() {
},
},
});
app.model(Album, { dataSource: 'db' });
User.create({ name: 'Raymond', email: 'x@y.com', password: 'foobar' }, function(err, user) {
Role.isInRole('returnPromise', { principalType: ACL.USER, principalId: user.id },
if (err) return done(err);
async.parallel([
function(next) {
Role.isInRole(
'returnPromise',
{ principalType: ACL.USER, principalId: user.id },
function(err, yes) {
assert(!err && yes);
if (err) return next(err);
assert(yes);
next();
});
Role.isInRole(Role.AUTHENTICATED, { principalType: ACL.USER, principalId: user.id },
},
function(next) {
Role.isInRole(
Role.AUTHENTICATED,
{ principalType: ACL.USER, principalId: user.id },
function(err, yes) {
assert(!err && yes);
if (err) next(err);
assert(yes);
next();
});
Role.isInRole(Role.AUTHENTICATED, { principalType: ACL.USER, principalId: null },
},
function(next) {
Role.isInRole(
Role.AUTHENTICATED,
{ principalType: ACL.USER, principalId: null },
function(err, yes) {
assert(!err && !yes);
if (err) next(err);
assert(!yes);
next();
});
Role.isInRole(Role.UNAUTHENTICATED, { principalType: ACL.USER, principalId: user.id },
},
function(next) {
Role.isInRole(
Role.UNAUTHENTICATED,
{ principalType: ACL.USER, principalId: user.id },
function(err, yes) {
assert(!err && !yes);
if (err) return next(err);
assert(!yes);
next();
});
Role.isInRole(Role.UNAUTHENTICATED, { principalType: ACL.USER, principalId: null },
},
function(next) {
Role.isInRole(
Role.UNAUTHENTICATED,
{ principalType: ACL.USER, principalId: null },
function(err, yes) {
assert(!err && yes);
if (err) return next(err);
assert(yes);
next();
});
Role.isInRole(Role.EVERYONE, { principalType: ACL.USER, principalId: user.id },
},
function(next) {
Role.isInRole(
Role.EVERYONE,
{ principalType: ACL.USER, principalId: user.id },
function(err, yes) {
assert(!err && yes);
if (err) return next(err);
assert(yes);
next();
});
Role.isInRole(Role.EVERYONE, { principalType: ACL.USER, principalId: null },
},
function(next) {
Role.isInRole(
Role.EVERYONE,
{ principalType: ACL.USER, principalId: null },
function(err, yes) {
assert(!err && yes);
if (err) return next(err);
assert(yes);
next();
});
},
function(next) {
Album.create({ name: 'Album 1', userId: user.id }, function(err, album1) {
var role = { principalType: ACL.USER, principalId: user.id, model: Album, id: album1.id };
if (err) return done(err);
var role = {
principalType: ACL.USER, principalId: user.id,
model: Album, id: album1.id,
};
Role.isInRole(Role.OWNER, role, function(err, yes) {
assert(!err && yes);
});
if (err) return next(err);
assert(yes);
Album.create({ name: 'Album 2' }, function(err, album2) {
role = { principalType: ACL.USER, principalId: user.id, model: Album, id: album2.id };
if (err) return next(err);
role = {
principalType: ACL.USER, principalId: user.id,
model: Album, id: album2.id,
};
Role.isInRole(Role.OWNER, role, function(err, yes) {
assert(!err && !yes);
if (err) return next(err);
assert(!yes);
next();
});
});
});
});
},
], done);
});
});
describe('isMappedToRole', function() {
@ -434,12 +592,16 @@ describe('role model', function() {
mappings.forEach(function(principalType) {
var Model = principalTypesToModels[principalType];
Model.create({ name: 'test', email: 'x@y.com', password: 'foobar' }, function(err, model) {
Role.create({ name: 'testRole' }, function(err, role) {
if (err) return done(err);
var uniqueRoleName = 'testRoleFor' + principalType;
Role.create({ name: uniqueRoleName }, function(err, role) {
if (err) return done(err);
role.principals.create({ principalType: principalType, principalId: model.id },
function(err, p) {
if (err) return done(err);
var pluralName = Model.pluralModelName.toLowerCase();
role[pluralName](function(err, models) {
assert(!err);
if (err) return done(err);
assert.equal(models.length, 1);
if (++runs === mappings.length) {
@ -454,13 +616,16 @@ describe('role model', function() {
it('should apply query', function(done) {
User.create({ name: 'Raymond', email: 'x@y.com', password: 'foobar' }, function(err, user) {
if (err) return done(err);
Role.create({ name: 'userRole' }, function(err, role) {
if (err) return done(err);
role.principals.create({ principalType: RoleMapping.USER, principalId: user.id },
function(err, p) {
if (err) return done(err);
var query = { fields: ['id', 'name'] };
sandbox.spy(User, 'find');
role.users(query, function(err, users) {
assert(!err);
if (err) return done(err);
assert.equal(users.length, 1);
assert.equal(users[0].id, user.id);
assert(User.find.calledWith(query));