From ed953a4c6fb0671fabbe00e3719e329e3ccabf82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Wed, 3 Aug 2016 15:55:29 +0200 Subject: [PATCH] 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. --- test/role.test.js | 529 ++++++++++++++++++++++++++++++---------------- 1 file changed, 352 insertions(+), 177 deletions(-) diff --git a/test/role.test.js b/test/role.test.js index 50a5e032..971ed622 100644 --- a/test/role.test.js +++ b/test/role.test.js @@ -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,55 +47,91 @@ describe('role model', function() { Role.applicationModel = Application; }); - it('should define role/role relations', function() { - Role.create({name: 'user'}, function(err, userRole) { - Role.create({name: 'admin'}, function(err, adminRole) { - userRole.principals.create({principalType: RoleMapping.ROLE, principalId: adminRole.id}, function(err, mapping) { - Role.find(function(err, roles) { - assert.equal(roles.length, 2); + 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) { + 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); }); - RoleMapping.find(function(err, mappings) { - assert.equal(mappings.length, 1); - assert.equal(mappings[0].principalType, RoleMapping.ROLE); - assert.equal(mappings[0].principalId, adminRole.id); - }); - userRole.principals(function(err, principals) { - assert.equal(principals.length, 1); - }); - userRole.roles(function(err, roles) { - assert.equal(roles.length, 1); - }); - }); }); }); - }); - 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) { - Role.find(function(err, roles) { - assert(!err); - assert.equal(roles.length, 1); - assert.equal(roles[0].name, 'userRole'); - }); - role.principals(function(err, principals) { - assert(!err); - assert.equal(principals.length, 1); - assert.equal(principals[0].principalType, RoleMapping.USER); - assert.equal(principals[0].principalId, user.id); - }); - role.users(function(err, users) { - assert(!err); - assert.equal(users.length, 1); - assert.equal(users[0].id, user.id); - }); + if (err) return done(err); + async.parallel([ + function(next) { + Role.find(function(err, roles) { + if (err) return next(err); + assert.equal(roles.length, 1); + assert.equal(roles[0].name, 'userRole'); + next(); + }); + }, + function(next) { + role.principals(function(err, principals) { + 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) { + if (err) return next(err); + assert.equal(users.length, 1); + assert.equal(users[0].id, user.id); + next(); + }); + }, + ], done); }); }); }); - }); it('should not allow duplicate role name', function(done) { @@ -107,81 +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) { - assert(p.id); - assert.equal(p.roleId, role.id); - Role.find(function(err, roles) { - assert(!err); - assert.equal(roles.length, 1); - assert.equal(roles[0].name, 'userRole'); - }); - role.principals(function(err, principals) { - assert(!err); - assert.equal(principals.length, 1); - assert.equal(principals[0].principalType, RoleMapping.USER); - assert.equal(principals[0].principalId, user.id); - }); - role.users(function(err, users) { - assert(!err); - assert.equal(users.length, 1); - assert.equal(users[0].id, user.id); - }); - }); - }); - }); - - }); - - it('should support getRoles() and isInRole()', function() { - User.create({ name: 'Raymond', email: 'x@y.com', password: 'foobar' }, function(err, user) { - Role.create({ name: 'userRole' }, function(err, role) { 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); - }); - - Role.isInRole('userRole', {principalType: RoleMapping.APP, principalId: user.id}, function(err, exists) { - assert(!err && exists === false); - }); - - Role.isInRole('userRole', {principalType: RoleMapping.USER, principalId: 100}, function(err, exists) { - assert(!err && exists === false); - }); - - 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); - }); - 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); - }); - 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); - }); - 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 done(err); + assert(p.id); + assert.equal(p.roleId, role.id); + async.parallel([ + function(next) { + Role.find(function(err, roles) { + if (err) return next(err); + assert.equal(roles.length, 1); + assert.equal(roles[0].name, 'userRole'); + next(); + }); + }, + function(next) { + role.principals(function(err, principals) { + 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) { + if (err) return next(err); + assert.equal(users.length, 1); + assert.equal(users[0].id, user.id); + }); + next(); + }, + ], done); }); }); }); - }); - it('should support owner role resolver', 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) { + 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(); + }); + }, + function(next) { + Role.isInRole( + 'userRole', + { principalType: RoleMapping.APP, principalId: user.id }, + function(err, inRole) { + if (err) return next(err); + assert(!inRole); + next(); + }); + }, + function(next) { + Role.isInRole( + 'userRole', + { principalType: RoleMapping.USER, principalId: 100 }, + function(err, inRole) { + if (err) return next(err); + assert(!inRole); + next(); + }); + }, + function(next) { + Role.getRoles( + { principalType: RoleMapping.USER, principalId: user.id }, + function(err, roles) { + if (err) return next(err); + expect(roles).to.eql([ + Role.AUTHENTICATED, + Role.EVERYONE, + role.id, + ]); + next(); + }); + }, + function(next) { + Role.getRoles( + { principalType: RoleMapping.APP, principalId: user.id }, + function(err, roles) { + if (err) return next(err); + expect(roles).to.eql([ + Role.AUTHENTICATED, + Role.EVERYONE, + ]); + next(); + }); + }, + function(next) { + Role.getRoles( + { principalType: RoleMapping.USER, principalId: 100 }, + function(err, roles) { + if (err) return next(err); + expect(roles).to.eql([ + Role.AUTHENTICATED, + Role.EVERYONE, + ]); + next(); + }); + }, + function(next) { + Role.getRoles( + { principalType: RoleMapping.USER, principalId: null }, + function(err, roles) { + if (err) return next(err); + expect(roles).to.eql([ + Role.UNAUTHENTICATED, + Role.EVERYONE, + ]); + next(); + }); + }, + ], done); + }); + }); + }); + }); + + it('should support owner role resolver', function(done) { Role.registerResolver('returnPromise', function(role, context) { return new Promise(function(resolve) { process.nextTick(function() { @@ -190,61 +298,120 @@ describe('role model', function() { }); }); - var Album = ds.createModel('Album', { + var Album = app.registry.createModel('Album', { name: String, - userId: Number + userId: Number, }, { relations: { user: { type: 'belongsTo', model: 'User', - foreignKey: 'userId' - } - } + foreignKey: 'userId', + }, + }, }); + 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 }, - function(err, yes) { - assert(!err && yes); - }); + User.create({ name: 'Raymond', email: 'x@y.com', password: 'foobar' }, function(err, user) { + if (err) return done(err); + async.parallel([ + function(next) { + Role.isInRole( + 'returnPromise', + { principalType: ACL.USER, principalId: user.id }, + function(err, yes) { + if (err) return next(err); + assert(yes); + next(); + }); + }, + function(next) { + Role.isInRole( + Role.AUTHENTICATED, + { principalType: ACL.USER, principalId: user.id }, + function(err, yes) { + if (err) next(err); + assert(yes); + next(); + }); + }, + function(next) { + Role.isInRole( + Role.AUTHENTICATED, + { principalType: ACL.USER, principalId: null }, + function(err, yes) { + if (err) next(err); + assert(!yes); + next(); + }); + }, + function(next) { + Role.isInRole( + Role.UNAUTHENTICATED, + { principalType: ACL.USER, principalId: user.id }, + function(err, yes) { + if (err) return next(err); + assert(!yes); + next(); + }); + }, + function(next) { + Role.isInRole( + Role.UNAUTHENTICATED, + { principalType: ACL.USER, principalId: null }, + function(err, yes) { + if (err) return next(err); + assert(yes); + next(); + }); + }, + function(next) { + Role.isInRole( + Role.EVERYONE, + { principalType: ACL.USER, principalId: user.id }, + function(err, yes) { + if (err) return next(err); + assert(yes); + next(); + }); + }, + function(next) { + Role.isInRole( + Role.EVERYONE, + { principalType: ACL.USER, principalId: null }, + function(err, yes) { + if (err) return next(err); + assert(yes); + next(); + }); + }, + function(next) { + Album.create({ name: 'Album 1', userId: user.id }, function(err, album1) { + 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) { + if (err) return next(err); + assert(yes); - Role.isInRole(Role.AUTHENTICATED, { principalType: ACL.USER, principalId: user.id }, - function(err, yes) { - assert(!err && yes); - }); - - Role.isInRole(Role.AUTHENTICATED, { principalType: ACL.USER, principalId: null }, - function(err, yes) { - assert(!err && !yes); - }); - - Role.isInRole(Role.UNAUTHENTICATED, {principalType: ACL.USER, principalId: user.id}, function(err, yes) { - assert(!err && !yes); - }); - Role.isInRole(Role.UNAUTHENTICATED, {principalType: ACL.USER, principalId: null}, function(err, yes) { - assert(!err && yes); - }); - - Role.isInRole(Role.EVERYONE, {principalType: ACL.USER, principalId: user.id}, function(err, yes) { - assert(!err && yes); - }); - - Role.isInRole(Role.EVERYONE, {principalType: ACL.USER, principalId: null}, function(err, yes) { - assert(!err && yes); - }); - - Album.create({ name: 'Album 1', userId: user.id }, function(err, album1) { - var role = { principalType: ACL.USER, principalId: user.id, model: Album, id: album1.id }; - Role.isInRole(Role.OWNER, role, function(err, yes) { - assert(!err && yes); - }); - Album.create({name: 'Album 2'}, function(err, album2) { - Role.isInRole(Role.OWNER, {principalType: ACL.USER, principalId: user.id, model: Album, id: album2.id}, function(err, yes) { - assert(!err && !yes); + Album.create({ name: 'Album 2' }, function(err, album2) { + 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) { + if (err) return next(err); + assert(!yes); + next(); + }); + }); + }); }); - }); - }); + }, + ], done); }); }); @@ -255,7 +422,7 @@ describe('role model', function() { User.create({ username: 'john', email: 'john@gmail.com', - password: 'jpass' + password: 'jpass', }, function(err, u) { if (err) return done(err); @@ -263,18 +430,18 @@ describe('role model', function() { User.create({ username: 'mary', email: 'mary@gmail.com', - password: 'mpass' + password: 'mpass', }, function(err, u) { if (err) return done(err); Application.create({ - name: 'demo' + name: 'demo', }, function(err, a) { if (err) return done(err); app = a; Role.create({ - name: 'admin' + name: 'admin', }, function(err, r) { if (err) return done(err); @@ -282,12 +449,12 @@ describe('role model', function() { var principals = [ { principalType: ACL.USER, - principalId: user.id + principalId: user.id, }, { principalType: ACL.APP, - principalId: app.id - } + principalId: app.id, + }, ]; async.each(principals, function(p, done) { role.principals.create(p, done); @@ -398,7 +565,6 @@ describe('role model', function() { done(); }); }); - }); describe('listByPrincipalType', function() { @@ -425,12 +591,17 @@ 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) { - role.principals.create({principalType: principalType, principalId: model.id}, function(err, p) { + Model.create({ name: 'test', email: 'x@y.com', password: 'foobar' }, function(err, model) { + 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) { @@ -444,13 +615,17 @@ describe('role model', function() { }); it('should apply query', function(done) { - User.create({name: 'Raymond', email: 'x@y.com', password: 'foobar'}, function(err, user) { - Role.create({name: 'userRole'}, function(err, role) { - role.principals.create({principalType: RoleMapping.USER, principalId: user.id}, function(err, p) { - var query = {fields:['id', 'name']}; + 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));