diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..a1af603 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +.git +.gitlab-ci.yml +.gitattributes +.gitignore +./test/performance/docker-compose.yml \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js index 0ef31f4..58ff49d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -23,7 +23,7 @@ module.exports = function GruntConfig(grunt) { mochaOptions: ['--exit'] }, coverage: { - src: ['test/test.js'], + src: ['test/test.js', 'test/aggregation-fn-groupby-test.js', 'test/aggregation-fn-having-test.js'], options: { timeout: 60000, check: { diff --git a/README.md b/README.md index cdcb515..8406d67 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ + [start()](#start--) + [addContextField(name, property)](#addcontextfield-name--property-) + [removeForceId](#removeforceid) + + [setACLToBaseEntity](#setACLToBaseEntity) + [observers](#observers) * [Configurations](#configurations) * [Remote End point (RestAPI)](#remote-end-point--restapi-) @@ -481,6 +482,21 @@ If you want to disable this, you can use **disableForceIdForUserModels** setting **About ForceId** : In loopback 3, ForceId setting is done on model which is **true** by default. In this case, user/programmer cannot create a record on model by passing his/her own id. Id is always generated by loopback. To disable this setting, you can use removeForceId call. +### setACLToBaseEntity +This function should be called to set default ACL on BaseEntity Model. in oeCloud 2.x, BaseEntity doesn't have any ACL applied. Therefore, all operations on all models which are derived from BaseEntity are possible. To prevent that, programmer can call this method. + +```javaScript +var oecloud = require('oe-cloud'); +oecloud.setACLToBaseEntity({ + "accessType": "WRITE", + "principalType": "ROLE", + "principalId": "$unauthenticated", + "permission": "DENY" + }); +// oecloud.boot() and other code +``` +Remember that this has to be done before other models are loaded - meaning it should be done before you call boot(). + ### observers diff --git a/common/models/base-entity.json b/common/models/base-entity.json index b9a2dc5..5a93a75 100644 --- a/common/models/base-entity.json +++ b/common/models/base-entity.json @@ -16,14 +16,6 @@ }, "validations": [], "relations": {}, - "acls": [ - { - "accessType": "WRITE", - "principalType": "ROLE", - "principalId": "$unauthenticated", - "permission": "DENY" - } - ], "methods": {} } diff --git a/lib/load.js b/lib/load.js index cb4d0b8..48651de 100644 --- a/lib/load.js +++ b/lib/load.js @@ -15,6 +15,7 @@ var debug = require('debug')('oe-cloud:oe-cloud'); var async = require('async'); var jutil = require('loopback-datasource-juggler/lib/jutil'); var observerMixin = require('loopback-datasource-juggler/lib/observer'); +var fs = require('fs'); wrapper.initWrapper(); @@ -30,6 +31,7 @@ function getRootFolder() { try { rootFolder = path.dirname(module.parent.parent.filename); } catch (e) { + // eslint-disable-next-line no-console console.error('**** ERROR : Not able to get root folder from parent module. ****', e); } @@ -37,6 +39,7 @@ function getRootFolder() { try { rootFolder = process.cwd() + '/server'; } catch (e) { + // eslint-disable-next-line no-console console.error('**** ERROR : Not able to get current working directory. ****', e); } } @@ -69,7 +72,26 @@ app.createServer = function () { if ( app.server ) { return app.server; } - var server = require('http').createServer(app); + + var server; + if (process.env.REQUIRE_HTTPS === true || process.env.REQUIRE_HTTPS === 'true') { + var keyPath = process.env.SSL_KEY_PATH || ''; + var certPath = process.env.SSL_CERT_PATH || ''; + if (!(keyPath && certPath)) { + throw new Error('HTTPS Enabled but SSL_KEY_PATH or SSL_CERT_PATH are not defined'); + } + /** + * SSL_KEY_PATH & SSL_CERT_PATH should be absolute paths + */ + let configOptions = { + key: fs.readFileSync(keyPath).toString(), + cert: fs.readFileSync(certPath).toString() + }; + server = require('https').createServer(configOptions, app); + } else { + server = require('http').createServer(app); + } + app.server = server; return server; }; @@ -147,9 +169,11 @@ app.start = function () { return app.listen( () => { app.emit('started'); var baseUrl = app.get('url').replace(/\/$/, ''); + // eslint-disable-next-line no-console console.log('Web server listening at: %s', baseUrl); if (app.get('loopback-component-explorer')) { var explorerPath = app.get('loopback-component-explorer').mountPath; + // eslint-disable-next-line no-console console.log('Browse your REST API at %s%s', baseUrl, explorerPath); } }); @@ -241,6 +265,8 @@ app.addContextField('roles', { }); +// Atul : This utility function is used to remove forceId settings from model +// This is important for User/Role etc models from loopback app.removeForceId = function (modelName) { var model = loopback.getModelByType(modelName); model.settings.forceId = false; @@ -257,6 +283,25 @@ app.removeForceId = function (modelName) { } }; + +// Atul : By Default unauthenticated users can do WRITE operations on BaseEntity. To keep backward compatibility, application can call this function to set ACL on BaseEntity +// Remember that, if programmer wants to call this function to set ACL, it has to be done before boot. +// "acls": +// { +// "accessType": "WRITE", +// "principalType": "ROLE", +// "principalId": "$unauthenticated", +// "permission": "DENY" +// } +app.setACLToBaseEntity = function (acl) { + if (!Array.isArray(acl)) { + app.addSettingsToBaseEntity({acls: [acl]}); + } else { + app.addSettingsToBaseEntity({acls: acl}); + } +}; + + app.registry.modelBuilder.registerCustomType('timestamp', 'date'); var emailPattern = '^(([^<>()[\\]\\\\.,;:\\s@\\"]+(\\.[^<>()[\\]\\\\.,;:\\s@\\"]+)*)|(\\".+\\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$'; app.registry.modelBuilder.registerCustomType('email', 'string', { pattern: emailPattern }); diff --git a/lib/loopback-boot-utility/index.js b/lib/loopback-boot-utility/index.js index 4d83a4b..527bd56 100644 --- a/lib/loopback-boot-utility/index.js +++ b/lib/loopback-boot-utility/index.js @@ -5,7 +5,7 @@ function normalizeMixinName(str, normalization) { switch (normalization) { case false: case 'none': return str; - + // eslint-disable-next-line no-undefined case undefined: case 'classify': str = String(str).replace(/([A-Z]+)/g, ' $1').trim(); diff --git a/lib/loopback-datasource-juggler-wrapper/coerce.js b/lib/loopback-datasource-juggler-wrapper/coerce.js index 8e27332..e255daf 100644 --- a/lib/loopback-datasource-juggler-wrapper/coerce.js +++ b/lib/loopback-datasource-juggler-wrapper/coerce.js @@ -174,6 +174,7 @@ DataAccessObject._coerce = function (where, options) { } var val = where[p]; + // eslint-disable-next-line no-undefined if (val === null || val === undefined) { continue; } @@ -243,6 +244,7 @@ DataAccessObject._coerce = function (where, options) { // Coerce the array items if (Array.isArray(val)) { for (var i = 0; i < val.length; i++) { + // eslint-disable-next-line no-undefined if (val[i] !== null && val[i] !== undefined) { val[i] = DataType(val[i]); } diff --git a/lib/loopback-datasource-juggler-wrapper/dao-wrapper.js b/lib/loopback-datasource-juggler-wrapper/dao-wrapper.js index 00430ef..acd6f0c 100644 --- a/lib/loopback-datasource-juggler-wrapper/dao-wrapper.js +++ b/lib/loopback-datasource-juggler-wrapper/dao-wrapper.js @@ -15,6 +15,8 @@ const assert = require('assert'); const async = require('async'); require('./coerce'); +/* eslint-disable no-undefined */ + /* eslint-disable no-unused-vars */ // Atul : Keep this function for reference // function checkForOverrideAndCall(self, fn, args, optionIndex) { diff --git a/lib/loopback-datasource-juggler-wrapper/relation-definition.js b/lib/loopback-datasource-juggler-wrapper/relation-definition.js index a020e7f..8a2f225 100644 --- a/lib/loopback-datasource-juggler-wrapper/relation-definition.js +++ b/lib/loopback-datasource-juggler-wrapper/relation-definition.js @@ -12,6 +12,8 @@ const HasOne = require('loopback-datasource-juggler/lib/relation-definition').Ha const ModelBaseClass = require('loopback-datasource-juggler/lib/model.js'); const g = require('strong-globalize')(); +/* eslint-disable no-undefined */ + // Atul : Functions from relation-definition.js are overloaded. These functions are overriden so that // this.fetch() call, options can be passed. HasOne.prototype.update and destroy() overriden // default loopback-datasource-juggler doesn't pass options and hence it would crash @@ -39,6 +41,7 @@ HasOne.prototype.update = function (targetModelData, options, cb) { cb = cb || utils.createPromiseCallback(); var definition = this.definition; var fk = this.definition.keyTo; + // eslint-disable-next-line handle-callback-err this.fetch(null, options, function (err, targetModel) { if (targetModel instanceof ModelBaseClass) { // Ensures Foreign Key cannot be changed! @@ -60,6 +63,7 @@ HasOne.prototype.destroy = function (options, cb) { } cb = cb || utils.createPromiseCallback(); var definition = this.definition; + // eslint-disable-next-line handle-callback-err this.fetch(null, options, function (err, targetModel) { if (targetModel instanceof ModelBaseClass) { targetModel.destroy(options, cb); diff --git a/package.json b/package.json index 0bc9af4..2504af1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "oe-cloud", - "version": "2.0.0", + "version": "2.1.0", "description": "oe-cloud modularization aka oecloud.io", "engines": { "node": ">=6" @@ -15,15 +15,15 @@ }, "dependencies": { "async": "2.6.1", - "lodash": "4.17.11", "compression": "1.7.3", "cookie-parser": "1.4.3", - "loopback": "3.22.3", - "loopback-datasource-juggler": "3.24.0", + "cors": "2.8.5", + "lodash": "4.17.14", + "loopback": "3.26.0", "loopback-boot": "2.27.1", - "loopback-component-explorer": "5.4.0", + "loopback-datasource-juggler": "3.24.0", "mustache": "2.3.2", - "oe-logger": "2.0.0", + "oe-logger": "^2.0.0", "serve-favicon": "2.5.0", "serve-static": "1.13.2", "strong-error-handler": "2.3.2" @@ -35,7 +35,7 @@ "chai-things": "0.2.0", "chalk": "1.1.1", "eslint": "4.10.0", - "grunt": "1.0.3", + "grunt": "1.0.4", "grunt-banner": "0.6.0", "grunt-cli": "1.3.2", "grunt-contrib-clean": "2.0.0", @@ -46,11 +46,10 @@ "grunt-mocha-test": "0.13.3", "istanbul": "0.4.5", "mocha": "5.2.0", + "oe-connector-mongodb": "^2.0.0", + "oe-connector-postgresql": "^2.0.0", "superagent-defaults": "0.1.14", - "supertest": "3.4.2", - "oe-skeleton": "2.0.0", - "oe-connector-mongodb": "2.0.0", - "oe-connector-postgresql": "2.0.0" + "supertest": "3.4.2" }, "author": "Atul Pandit ", "repository": { diff --git a/server/boot/authentication.js b/server/boot/authentication.js index 84908ef..68376de 100644 --- a/server/boot/authentication.js +++ b/server/boot/authentication.js @@ -4,12 +4,12 @@ * Bangalore, India. All Rights Reserved. * */ -// Atul : This script is used to enable authentication for the application -// Also 'enableAuthCookie' is introduced. if this option is set then cookie is created when user login using user.login() -// When user logs out, cookie is deleted. This is helpfule at least for node-red because node-red application does not -// send access Token as part of URL / or AuthSession header -// Atul : This script includes aboutMe() API. This API returned user information to caller including context + +// Author : Atul +// This script has many user/authentication related functionalities. const loopback = require('loopback'); + +// Atul : This script includes aboutMe() API. This API returned user information to caller including context function aboutMe() { var userModel = loopback.getModelByType('User'); userModel.aboutMe = function (options, cb) { @@ -92,6 +92,9 @@ module.exports = function enableAuthentication(server) { server.removeForceId('RoleMapping'); } + // Atul : Below code will add Roles of the logged in user to AccessToken. + // As accessToken fields are available in context ( and henc options ), programmer can use list of Roles user belongs to + // roles field is added to AccessToken on load.js file var accessTokenModel = loopback.getModelByType('AccessToken'); accessTokenModel.observe('before save', function (ctx, next) { if (!ctx.isNewInstance) { @@ -135,7 +138,10 @@ module.exports = function enableAuthentication(server) { }); }); - + // Atul : This script is used to enable authentication for the application + // Also 'enableAuthCookie' is introduced. if this option is set then cookie is created when user login using user.login() + // When user logs out, cookie is deleted. This is helpfule at least for node-red because node-red application does not + // send access Token as part of URL / or AuthSession header var enableAuthCookie = server.get('enableAuthCookie'); if (!enableAuthCookie) { return; diff --git a/server/boot/db-models.js b/server/boot/db-models.js index f7212f5..6efdfe5 100644 --- a/server/boot/db-models.js +++ b/server/boot/db-models.js @@ -18,6 +18,7 @@ function loadModelsFromDB(app, cb) { // design break when used fetchAllScopes modelDefinition.find({where: {filebased: false}}, {fetchAllScopes: true}, (err, result) => { if (err) { + // eslint-disable-next-line no-console console.error('******* Could not able to load models from Database ********* '); return cb(); } diff --git a/test/aggregation-fn-groupby-test.js b/test/aggregation-fn-groupby-test.js new file mode 100644 index 0000000..123e265 --- /dev/null +++ b/test/aggregation-fn-groupby-test.js @@ -0,0 +1,938 @@ +/** + * + * ©2016-2017 EdgeVerve Systems Limited (a fully owned Infosys subsidiary), + * Bangalore, India. All Rights Reserved. + * + */ + +var bootstrap = require('./bootstrap.js'); +var loopback = require('loopback'); +var chalk = require('chalk'); +var chai = require('chai'); +chai.use(require('chai-things')); +var expect = chai.expect; +var api = bootstrap.api; + +describe(chalk.blue('Aggregation Functions with group filter test'), function () { + this.timeout(10000); + + var studentsData = [ + { + "name": "Rickon", + "maths": 14, + "physics": 32, + "chemistry": 23, + "section": "Bravo", + "gender": "Male" + }, { + "name": "Sansa", + "maths": 15, + "physics": 16, + "chemistry": 51, + "section": "Bravo", + "gender": "Female" + }, { + "name": "Bran", + "maths": 14, + "physics": 72, + "chemistry": 96, + "section": "Charlie", + "gender": "Male" + }, { + "name": "Cersei", + "maths": 17, + "physics": 2, + "chemistry": 29, + "section": "Charlie", + "gender": "Female" + }, { + "name": "Arya", + "maths": 20, + "physics": 81, + "chemistry": 70, + "section": "Delta", + "gender": "Female" + }, { + "name": "Eddard", + "maths": 33, + "physics": 72, + "chemistry": 36, + "section": "Charlie", + "gender": "Male" + }, { + "name": "Tyrion", + "maths": 64, + "physics": 34, + "chemistry": 73, + "section": "Echo", + "gender": "Male" + }, { + "name": "Jaime", + "maths": 20, + "physics": 79, + "chemistry": 25, + "section": "Delta", + "gender": "Male" + }, { + "name": "Shae", + "maths": 47, + "physics": 36, + "chemistry": 1, + "section": "Echo", + "gender": "Female" + }, { + "name": "Ygritte", + "maths": 66, + "physics": 99, + "chemistry": 3, + "section": "Golf", + "gender": "Female" + }, { + "name": "Ramsay", + "maths": 79, + "physics": 18, + "chemistry": 97, + "section": "Alpha", + "gender": "Male" + }, { + "name": "Daenerys", + "maths": 60, + "physics": 74, + "chemistry": 10, + "section": "Alpha", + "gender": "Female" + }, { + "name": "Samwell", + "maths": 19, + "physics": 20, + "chemistry": 40, + "section": "Golf", + "gender": "Male" + }, { + "name": "Jon", + "maths": 41, + "physics": 66, + "chemistry": 71, + "section": "Alpha", + "gender": "Male" + }, { + "name": "Davos", + "maths": 19, + "physics": 11, + "chemistry": 100, + "section": "Delta", + "gender": "Male" + }, { + "name": "Robb", + "maths": 65, + "physics": 17, + "chemistry": 67, + "section": "Delta", + "gender": "Male" + }, { + "name": "Robert", + "maths": 20, + "physics": 91, + "chemistry": 96, + "section": "Golf", + "gender": "Male" + }, { + "name": "Podrick", + "maths": 80, + "physics": 1, + "chemistry": 79, + "section": "Delta", + "gender": "Male" + }, { + "name": "Missendei", + "maths": 21, + "physics": 5, + "chemistry": 5, + "section": "Delta", + "gender": "Female" + }, { + "name": "Varys", + "maths": 71, + "physics": 40, + "chemistry": 16, + "section": "Charlie", + "gender": "Male" + }, { + "name": "Margaery", + "maths": 58, + "physics": 69, + "chemistry": 86, + "section": "Echo", + "gender": "Female" + }, { + "name": "Hodor", + "maths": 20, + "physics": 84, + "chemistry": 97, + "section": "Bravo", + "gender": "Male" + }, { + "name": "Theon", + "maths": 36, + "physics": 5, + "chemistry": 41, + "section": "Foxtrot", + "gender": "Male" + }, { + "name": "Jorah", + "maths": 42, + "physics": 97, + "chemistry": 77, + "section": "Bravo", + "gender": "Male" + }, { + "name": "Khal", + "maths": 34, + "physics": 46, + "chemistry": 87, + "section": "Alpha", + "gender": "Male" + }, { + "name": "Brienne", + "maths": 90, + "physics": 2, + "chemistry": 23, + "section": "Delta", + "gender": "Female" + }, { + "name": "Daario", + "maths": 96, + "physics": 4, + "chemistry": 6, + "section": "Echo", + "gender": "Male" + }, { + "name": "Joffrey", + "maths": 50, + "physics": 9, + "chemistry": 65, + "section": "Foxtrot", + "gender": "Male" + }, { + "name": "Melisandre", + "maths": 25, + "physics": 59, + "chemistry": 20, + "section": "Echo", + "gender": "Female" + }, { + "name": "Baelish", + "maths": 2, + "physics": 13, + "chemistry": 77, + "section": "Delta", + "gender": "Male" + } + ] + var marksList = loopback.findModel('MarksList'); + before('upload test data', function (done) { + marksList.create(studentsData, {}, function (err, res) { + done(); + }); + }); + + after('Cleanup', function (done) { + marksList.destroyAll({}, {}, function modelDestroyAll(err, result) { + done(err); + }); + }); + + describe(chalk.green('Aggregation Functions Test --REST'), function () { + + var path = bootstrap.basePath + '/' + marksList.pluralModelName; + + it('Test for GROUP BY clause', function (done) { + var filter = '{"group":{"groupBy":["section"]}}'; + var url = path + '?filter=' + filter; + api + .get(url) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .expect(200).end(function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res.body); + expect(res.body).not.to.be.null; + expect(res.body).not.to.be.empty; + expect(res.body).not.to.be.undefined; + expect(res.body).to.have.length(7); + expect(res.body[0]).to.include.keys('section'); + expect(res.body[0]).to.not.include.keys('maths', 'physics', 'chemistry', 'name'); + done(); + } + }); + }); + + it('Test for MAX aggregation function', function (done) { + var filter = '{"group":{"groupBy":["gender"],"max":{"maths":"maxMathsMarks","physics":"maxPhysicsMarks"}}}'; + var url = path + '?filter=' + filter; + api + .get(url) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .expect(200).end(function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res.body); + expect(res.body).not.to.be.null; + expect(res.body).not.to.be.empty; + expect(res.body).not.to.be.undefined; + expect(res.body).to.have.length(2); + expect(res.body[0]).to.include.keys('gender'); + expect(res.body[0]).to.not.include.keys('maths', 'physics', 'chemistry', 'name'); + expect(res.body[0].maxMathsMarks).to.be.oneOf([90, 96]); + expect(res.body[1].maxMathsMarks).to.be.oneOf([90, 96]); + expect(res.body[0].maxPhysicsMarks).to.be.oneOf([99, 97]); + expect(res.body[1].maxPhysicsMarks).to.be.oneOf([99, 97]); + done(); + } + }); + }); + + it('Test for MIN aggregation function', function (done) { + var filter = '{"group":{"groupBy":["gender"],"min":{"maths":"minMathsMarks","physics":"minPhysicsMarks"}}}'; + var url = path + '?filter=' + filter; + api + .get(url) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .expect(200).end(function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res.body); + expect(res.body).not.to.be.null; + expect(res.body).not.to.be.empty; + expect(res.body).not.to.be.undefined; + expect(res.body).to.have.length(2); + expect(res.body[0]).to.include.keys('gender'); + expect(res.body[0]).to.not.include.keys('maths', 'physics', 'chemistry', 'name'); + expect(res.body[0].minMathsMarks).to.be.oneOf([15, 2]); + expect(res.body[1].minMathsMarks).to.be.oneOf([15, 2]); + expect(res.body[0].minPhysicsMarks).to.be.oneOf([2, 1]); + expect(res.body[1].minPhysicsMarks).to.be.oneOf([2, 1]); + done(); + } + }); + }); + + it('Test for AVG aggregation function', function (done) { + var filter = '{"group":{"groupBy":["gender"],"avg":{"chemistry":"avgChemistryMarks","maths":"avgMathsMarks"}}}'; + var url = path + '?filter=' + filter; + api + .get(url) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .expect(200).end(function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res.body); + expect(res.body).not.to.be.null; + expect(res.body).not.to.be.empty; + expect(res.body).not.to.be.undefined; + expect(res.body).to.have.length(2); + expect(res.body[0]).to.include.keys('gender'); + expect(res.body[0]).to.not.include.keys('maths', 'physics', 'chemistry', 'name'); + expect(res.body[0].avgChemistryMarks).to.be.oneOf([29.8, 63.45]); + expect(res.body[1].avgChemistryMarks).to.be.oneOf([29.8, 63.45]); + expect(res.body[0].avgMathsMarks).to.be.oneOf([41.9, 40.95]); + expect(res.body[1].avgMathsMarks).to.be.oneOf([41.9, 40.95]); + done(); + } + }); + }); + + it('Test for COUNT aggregation function', function (done) { + var filter = '{"group":{"groupBy":["gender"],"count":{"gender":"noOfStudents"}}}'; + var url = path + '?filter=' + filter; + api + .get(url) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .expect(200).end(function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res.body); + expect(res.body).not.to.be.null; + expect(res.body).not.to.be.empty; + expect(res.body).not.to.be.undefined; + expect(res.body).to.have.length(2); + expect(res.body[0]).to.include.keys('gender'); + expect(res.body[0]).to.not.include.keys('maths', 'physics', 'chemistry', 'name'); + expect(res.body[0].noOfStudents).to.be.oneOf([10, 20]); + expect(res.body[1].noOfStudents).to.be.oneOf([10, 20]); + done(); + } + }); + }); + + it('Test for SUM aggregation function', function (done) { + var filter = '{"group":{"groupBy":["gender"],"sum":{"chemistry":"sumOfChemistryMarks","physics":"sumOfPhysicsMarks","maths":"sumOfMathsMarks"}}}'; + var url = path + '?filter=' + filter; + api + .get(url) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .expect(200).end(function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res.body); + expect(res.body).not.to.be.null; + expect(res.body).not.to.be.empty; + expect(res.body).not.to.be.undefined; + expect(res.body).to.have.length(2); + expect(res.body[0]).to.include.keys('gender'); + expect(res.body[0]).to.not.include.keys('maths', 'physics', 'chemistry', 'name'); + expect(res.body[0].sumOfChemistryMarks).to.be.oneOf([298, 1269]); + expect(res.body[1].sumOfChemistryMarks).to.be.oneOf([298, 1269]); + expect(res.body[0].sumOfPhysicsMarks).to.be.oneOf([443, 811]); + expect(res.body[1].sumOfPhysicsMarks).to.be.oneOf([443, 811]); + expect(res.body[0].sumOfMathsMarks).to.be.oneOf([419, 819]); + expect(res.body[1].sumOfMathsMarks).to.be.oneOf([419, 819]); + done(); + } + }); + }); + + it('Test for applying multiple aggregation functions', function (done) { + var filter = '{"group":{"groupBy":["gender"],"avg":{"chemistry":"avgChemistryMarks"},"max":{"maths":"maxMathsMarks"},"min":{"physics":"minPhysics"},"sum":{"maths":"totalMathsMarks"},"count":{"name":"headCount"}}}'; + var url = path + '?filter=' + filter; + api + .get(url) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .expect(200).end(function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res.body); + expect(res.body).not.to.be.null; + expect(res.body).not.to.be.empty; + expect(res.body).not.to.be.undefined; + expect(res.body).to.have.length(2); + expect(res.body[0]).to.include.keys('gender'); + expect(res.body[0]).to.not.include.keys('maths', 'physics', 'chemistry', 'name'); + expect(res.body[0].avgChemistryMarks).to.be.oneOf([29.8, 63.45]); + expect(res.body[1].avgChemistryMarks).to.be.oneOf([29.8, 63.45]); + expect(res.body[0].maxMathsMarks).to.be.oneOf([90, 96]); + expect(res.body[1].maxMathsMarks).to.be.oneOf([90, 96]); + expect(res.body[0].minPhysics).to.be.oneOf([2, 1]); + expect(res.body[1].minPhysics).to.be.oneOf([2, 1]); + expect(res.body[0].totalMathsMarks).to.be.oneOf([419, 819]); + expect(res.body[1].totalMathsMarks).to.be.oneOf([419, 819]); + expect(res.body[0].headCount).to.be.oneOf([10, 20]); + expect(res.body[1].headCount).to.be.oneOf([10, 20]); + done(); + } + }); + }); + + it('Test for applying multiple aggregation functions with "where" filter', function (done) { + var filter = '{"where":{"maths":{"gt":35}},"group":{"groupBy":["gender"],"avg":{"chemistry":"avgChemistryMarks"},"max":{"maths":"maxMathsMarks"},"min":{"physics":"minPhysics"},"sum":{"maths":"totalMathsMarks"},"count":{"name":"headCount"}}}'; + var url = path + '?filter=' + filter; + api + .get(url) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .expect(200).end(function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res.body); + expect(res.body).not.to.be.null; + expect(res.body).not.to.be.empty; + expect(res.body).not.to.be.undefined; + expect(res.body).to.have.length(2); + expect(res.body[0]).to.include.keys('gender'); + expect(res.body[0]).to.not.include.keys('maths', 'physics', 'chemistry', 'name'); + expect(res.body[0].avgChemistryMarks).to.be.oneOf([24.6, 59.2]); + expect(res.body[1].avgChemistryMarks).to.be.oneOf([24.6, 59.2]); + expect(res.body[0].maxMathsMarks).to.be.oneOf([90, 96]); + expect(res.body[1].maxMathsMarks).to.be.oneOf([90, 96]); + expect(res.body[0].minPhysics).to.be.oneOf([2, 1]); + expect(res.body[1].minPhysics).to.be.oneOf([2, 1]); + expect(res.body[0].totalMathsMarks).to.be.oneOf([321, 624]); + expect(res.body[1].totalMathsMarks).to.be.oneOf([321, 624]); + expect(res.body[0].headCount).to.be.oneOf([5, 10]); + expect(res.body[1].headCount).to.be.oneOf([5, 10]); + done(); + } + }); + }); + + it('Test for applying multiple aggregation functions with "fields" filter', function (done) { + var filter = '{"fields":["avgChemistryMarks","gender"],"group":{"groupBy":["gender"],"avg":{"chemistry":"avgChemistryMarks"},"max":{"maths":"maxMathsMarks"}}}'; + var url = path + '?filter=' + filter; + api + .get(url) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .expect(200).end(function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res.body); + expect(res.body).not.to.be.null; + expect(res.body).not.to.be.empty; + expect(res.body).not.to.be.undefined; + expect(res.body).to.have.length(2); + expect(res.body[0]).to.include.keys('gender', 'avgChemistryMarks'); + expect(res.body[0]).to.not.include.keys('maths', 'physics', 'chemistry', 'name', 'section', 'maxMathsMarks'); + done(); + } + }); + }); + + it('Test for applying multiple aggregation functions with "order" filter', function (done) { + var filter = '{"order":["section DESC"],"group":{"groupBy":["section"],"avg":{"chemistry":"avgChemistryMarks"},"max":{"maths":"maxMathsMarks"}}}'; + var url = path + '?filter=' + filter; + api + .get(url) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .expect(200).end(function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res.body); + expect(res.body).not.to.be.null; + expect(res.body).not.to.be.empty; + expect(res.body).not.to.be.undefined; + expect(res.body).to.have.length(7); + expect(res.body[0].section).to.be.equal('Golf'); + expect(res.body[1].section).to.be.equal('Foxtrot'); + expect(res.body[2].section).to.be.equal('Echo'); + expect(res.body[3].section).to.be.equal('Delta'); + expect(res.body[4].section).to.be.equal('Charlie'); + expect(res.body[5].section).to.be.equal('Bravo'); + expect(res.body[6].section).to.be.equal('Alpha'); + done(); + } + }); + }); + + it('Test for applying multiple aggregation functions with "order" filter(on non existing field)', function (done) { + var filter = '{"order":["section ASC", "gender DESC"],"group":{"groupBy":["section"],"avg":{"chemistry":"avgChemistryMarks"},"max":{"maths":"maxMathsMarks"}}}'; + var url = path + '?filter=' + filter; + api + .get(url) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .expect(200).end(function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res.body); + expect(res.body).not.to.be.null; + expect(res.body).not.to.be.empty; + expect(res.body).not.to.be.undefined; + expect(res.body).to.have.length(7); + expect(res.body[0].gender).to.be.equal(undefined); + expect(res.body[6].section).to.be.equal('Golf'); + expect(res.body[5].section).to.be.equal('Foxtrot'); + expect(res.body[4].section).to.be.equal('Echo'); + expect(res.body[3].section).to.be.equal('Delta'); + expect(res.body[2].section).to.be.equal('Charlie'); + expect(res.body[1].section).to.be.equal('Bravo'); + expect(res.body[0].section).to.be.equal('Alpha'); + done(); + } + }); + }); + + it('Test for applying multiple aggregation functions with "limit" filter', function (done) { + var filter = '{"limit":3,"order":["section ASC"],"group":{"groupBy":["section"],"avg":{"chemistry":"avgChemistryMarks"},"max":{"maths":"maxMathsMarks"}}}'; + var url = path + '?filter=' + filter; + api + .get(url) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .expect(200).end(function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res.body); + expect(res.body).not.to.be.null; + expect(res.body).not.to.be.empty; + expect(res.body).not.to.be.undefined; + expect(res.body).to.have.length(3); + expect(res.body[2].section).to.be.equal('Charlie'); + expect(res.body[1].section).to.be.equal('Bravo'); + expect(res.body[0].section).to.be.equal('Alpha'); + done(); + } + }); + }); + + it('Test for applying multiple aggregation functions with "skip" filter', function (done) { + var filter = '{"limit":3,"skip":2,"order":["section ASC"],"group":{"groupBy":["section"],"avg":{"chemistry":"avgChemistryMarks"},"max":{"maths":"maxMathsMarks"}}}'; + var url = path + '?filter=' + filter; + api + .get(url) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .expect(200).end(function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res.body); + expect(res.body).not.to.be.null; + expect(res.body).not.to.be.empty; + expect(res.body).not.to.be.undefined; + expect(res.body).to.have.length(3); + expect(res.body[0].section).to.be.equal('Charlie'); + expect(res.body[1].section).to.be.equal('Delta'); + expect(res.body[2].section).to.be.equal('Echo'); + done(); + } + }); + }); + + it('Test for applying multiple aggregation functions with "offset" filter', function (done) { + var filter = '{"limit":3,"offset":2,"order":["section ASC"],"group":{"groupBy":["section"],"avg":{"chemistry":"avgChemistryMarks"},"max":{"maths":"maxMathsMarks"}}}'; + var url = path + '?filter=' + filter; + api + .get(url) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .expect(200).end(function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res.body); + expect(res.body).not.to.be.null; + expect(res.body).not.to.be.empty; + expect(res.body).not.to.be.undefined; + expect(res.body).to.have.length(3); + expect(res.body[0].section).to.be.equal('Charlie'); + expect(res.body[1].section).to.be.equal('Delta'); + expect(res.body[2].section).to.be.equal('Echo'); + done(); + } + }); + }); + }); + + + describe(chalk.green('Aggregation Functions Test --Programatic'), function () { + + it('Test for GROUP BY clause', function (done) { + var filter = { "group": { "groupBy": ["section"] } }; + + marksList.find(filter, {}, function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res); + expect(res).not.to.be.null; + expect(res).not.to.be.empty; + expect(res).not.to.be.undefined; + expect(res).to.have.length(7); + expect(res[0].__data).to.include.keys('section'); + expect(res[0].__data).to.not.include.keys('maths', 'physics', 'chemistry', 'name'); + done(); + } + }); + }); + + it('Test for MAX aggregation function', function (done) { + var filter = { "group": { "groupBy": ["gender"], "max": { "maths": "maxMathsMarks", "physics": "maxPhysicsMarks" } } }; + marksList.find(filter, {}, function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res); + expect(res).not.to.be.null; + expect(res).not.to.be.empty; + expect(res).not.to.be.undefined; + expect(res).to.have.length(2); + expect(res[0].__data).to.include.keys('gender'); + expect(res[0].__data).to.not.include.keys('maths', 'physics', 'chemistry', 'name'); + expect(res[0].maxMathsMarks).to.be.oneOf([90, 96]); + expect(res[1].maxMathsMarks).to.be.oneOf([90, 96]); + expect(res[0].maxPhysicsMarks).to.be.oneOf([99, 97]); + expect(res[1].maxPhysicsMarks).to.be.oneOf([99, 97]); + done(); + } + }); + }); + + it('Test for MIN aggregation function', function (done) { + var filter = { "group": { "groupBy": ["gender"], "min": { "maths": "minMathsMarks", "physics": "minPhysicsMarks" } } }; + marksList.find(filter, {}, function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res); + expect(res).not.to.be.null; + expect(res).not.to.be.empty; + expect(res).not.to.be.undefined; + expect(res).to.have.length(2); + expect(res[0].__data).to.include.keys('gender'); + expect(res[0].__data).to.not.include.keys('maths', 'physics', 'chemistry', 'name'); + expect(res[0].minMathsMarks).to.be.oneOf([15, 2]); + expect(res[1].minMathsMarks).to.be.oneOf([15, 2]); + expect(res[0].minPhysicsMarks).to.be.oneOf([2, 1]); + expect(res[1].minPhysicsMarks).to.be.oneOf([2, 1]); + done(); + } + }); + }); + + it('Test for AVG aggregation function', function (done) { + var filter = { "group": { "groupBy": ["gender"], "avg": { "chemistry": "avgChemistryMarks", "maths": "avgMathsMarks" } } }; + marksList.find(filter, {}, function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res); + expect(res).not.to.be.null; + expect(res).not.to.be.empty; + expect(res).not.to.be.undefined; + expect(res).to.have.length(2); + expect(res[0].__data).to.include.keys('gender'); + expect(res[0].__data).to.not.include.keys('maths', 'physics', 'chemistry', 'name'); + expect(res[0].avgChemistryMarks).to.be.oneOf([29.8, 63.45]); + expect(res[1].avgChemistryMarks).to.be.oneOf([29.8, 63.45]); + expect(res[0].avgMathsMarks).to.be.oneOf([41.9, 40.95]); + expect(res[1].avgMathsMarks).to.be.oneOf([41.9, 40.95]); + done(); + } + }); + }); + + it('Test for COUNT aggregation function', function (done) { + var filter = { "group": { "groupBy": ["gender"], "count": { "gender": "noOfStudents" } } }; + marksList.find(filter, {}, function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res); + expect(res).not.to.be.null; + expect(res).not.to.be.empty; + expect(res).not.to.be.undefined; + expect(res).to.have.length(2); + expect(res[0].__data).to.include.keys('gender'); + expect(res[0].__data).to.not.include.keys('maths', 'physics', 'chemistry', 'name'); + expect(res[0].noOfStudents).to.be.oneOf([10, 20]); + expect(res[1].noOfStudents).to.be.oneOf([10, 20]); + done(); + } + }); + }); + + it('Test for SUM aggregation function', function (done) { + var filter = { "group": { "groupBy": ["gender"], "sum": { "chemistry": "sumOfChemistryMarks", "physics": "sumOfPhysicsMarks", "maths": "sumOfMathsMarks" } } }; + marksList.find(filter, {}, function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res); + expect(res).not.to.be.null; + expect(res).not.to.be.empty; + expect(res).not.to.be.undefined; + expect(res).to.have.length(2); + expect(res[0].__data).to.include.keys('gender'); + expect(res[0].__data).to.not.include.keys('maths', 'physics', 'chemistry', 'name'); + expect(res[0].sumOfChemistryMarks).to.be.oneOf([298, 1269]); + expect(res[1].sumOfChemistryMarks).to.be.oneOf([298, 1269]); + expect(res[0].sumOfPhysicsMarks).to.be.oneOf([443, 811]); + expect(res[1].sumOfPhysicsMarks).to.be.oneOf([443, 811]); + expect(res[0].sumOfMathsMarks).to.be.oneOf([419, 819]); + expect(res[1].sumOfMathsMarks).to.be.oneOf([419, 819]); + done(); + } + }); + }); + + it('Test for applying multiple aggregation functions', function (done) { + var filter = { "group": { "groupBy": ["gender"], "avg": { "chemistry": "avgChemistryMarks" }, "max": { "maths": "maxMathsMarks" }, "min": { "physics": "minPhysics" }, "sum": { "maths": "totalMathsMarks" }, "count": { "name": "headCount" } } }; + marksList.find(filter, {}, function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res); + expect(res).not.to.be.null; + expect(res).not.to.be.empty; + expect(res).not.to.be.undefined; + expect(res).to.have.length(2); + expect(res[0].__data).to.include.keys('gender'); + expect(res[0].__data).to.not.include.keys('maths', 'physics', 'chemistry', 'name'); + expect(res[0].avgChemistryMarks).to.be.oneOf([29.8, 63.45]); + expect(res[1].avgChemistryMarks).to.be.oneOf([29.8, 63.45]); + expect(res[0].maxMathsMarks).to.be.oneOf([90, 96]); + expect(res[1].maxMathsMarks).to.be.oneOf([90, 96]); + expect(res[0].minPhysics).to.be.oneOf([2, 1]); + expect(res[1].minPhysics).to.be.oneOf([2, 1]); + expect(res[0].totalMathsMarks).to.be.oneOf([419, 819]); + expect(res[1].totalMathsMarks).to.be.oneOf([419, 819]); + expect(res[0].headCount).to.be.oneOf([10, 20]); + expect(res[1].headCount).to.be.oneOf([10, 20]); + done(); + } + }); + }); + + it('Test for applying multiple aggregation functions with "where" filter', function (done) { + var filter = { "where": { "maths": { "gt": 35 } }, "group": { "groupBy": ["gender"], "avg": { "chemistry": "avgChemistryMarks" }, "max": { "maths": "maxMathsMarks" }, "min": { "physics": "minPhysics" }, "sum": { "maths": "totalMathsMarks" }, "count": { "name": "headCount" } } }; + marksList.find(filter, {}, function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res); + expect(res).not.to.be.null; + expect(res).not.to.be.empty; + expect(res).not.to.be.undefined; + expect(res).to.have.length(2); + expect(res[0].__data).to.include.keys('gender'); + expect(res[0].__data).to.not.include.keys('maths', 'physics', 'chemistry', 'name'); + expect(res[0].avgChemistryMarks).to.be.oneOf([24.6, 59.2]); + expect(res[1].avgChemistryMarks).to.be.oneOf([24.6, 59.2]); + expect(res[0].maxMathsMarks).to.be.oneOf([90, 96]); + expect(res[1].maxMathsMarks).to.be.oneOf([90, 96]); + expect(res[0].minPhysics).to.be.oneOf([2, 1]); + expect(res[1].minPhysics).to.be.oneOf([2, 1]); + expect(res[0].totalMathsMarks).to.be.oneOf([321, 624]); + expect(res[1].totalMathsMarks).to.be.oneOf([321, 624]); + expect(res[0].headCount).to.be.oneOf([5, 10]); + expect(res[1].headCount).to.be.oneOf([5, 10]); + done(); + } + }); + }); + + it('Test for applying multiple aggregation functions with "fields" filter', function (done) { + var filter = { "fields": ["avgChemistryMarks", "gender"], "group": { "groupBy": ["gender"], "avg": { "chemistry": "avgChemistryMarks" }, "max": { "maths": "maxMathsMarks" } } }; + marksList.find(filter, {}, function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res); + expect(res).not.to.be.null; + expect(res).not.to.be.empty; + expect(res).not.to.be.undefined; + expect(res).to.have.length(2); + expect(res[0].__data).to.include.keys('gender', 'avgChemistryMarks'); + expect(res[0].__data).to.not.include.keys('maths', 'physics', 'chemistry', 'name', 'section', 'maxMathsMarks'); + done(); + } + }); + }); + + it('Test for applying multiple aggregation functions with "order" filter', function (done) { + var filter = { "order": ["section DESC"], "group": { "groupBy": ["section"], "avg": { "chemistry": "avgChemistryMarks" }, "max": { "maths": "maxMathsMarks" } } }; + marksList.find(filter, {}, function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res); + expect(res).not.to.be.null; + expect(res).not.to.be.empty; + expect(res).not.to.be.undefined; + expect(res).to.have.length(7); + expect(res[0].section).to.be.equal('Golf'); + expect(res[1].section).to.be.equal('Foxtrot'); + expect(res[2].section).to.be.equal('Echo'); + expect(res[3].section).to.be.equal('Delta'); + expect(res[4].section).to.be.equal('Charlie'); + expect(res[5].section).to.be.equal('Bravo'); + expect(res[6].section).to.be.equal('Alpha'); + done(); + } + }); + }); + + it('Test for applying multiple aggregation functions with "order" filter(on non existing field)', function (done) { + var filter = { "order": ["section ASC", "gender DESC"], "group": { "groupBy": ["section"], "avg": { "chemistry": "avgChemistryMarks" }, "max": { "maths": "maxMathsMarks" } } }; + marksList.find(filter, {}, function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res); + expect(res).not.to.be.null; + expect(res).not.to.be.empty; + expect(res).not.to.be.undefined; + expect(res).to.have.length(7); + expect(res[0].gender).to.be.equal(undefined); + expect(res[6].section).to.be.equal('Golf'); + expect(res[5].section).to.be.equal('Foxtrot'); + expect(res[4].section).to.be.equal('Echo'); + expect(res[3].section).to.be.equal('Delta'); + expect(res[2].section).to.be.equal('Charlie'); + expect(res[1].section).to.be.equal('Bravo'); + expect(res[0].section).to.be.equal('Alpha'); + done(); + } + }); + }); + + it('Test for applying multiple aggregation functions with "limit" filter', function (done) { + var filter = { "limit": 3, "order": ["section ASC"], "group": { "groupBy": ["section"], "avg": { "chemistry": "avgChemistryMarks" }, "max": { "maths": "maxMathsMarks" } } }; + marksList.find(filter, {}, function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res); + expect(res).not.to.be.null; + expect(res).not.to.be.empty; + expect(res).not.to.be.undefined; + expect(res).to.have.length(3); + expect(res[2].section).to.be.equal('Charlie'); + expect(res[1].section).to.be.equal('Bravo'); + expect(res[0].section).to.be.equal('Alpha'); + done(); + } + }); + }); + + it('Test for applying multiple aggregation functions with "skip" filter', function (done) { + var filter = { "limit": 3, "skip": 2, "order": ["section ASC"], "group": { "groupBy": ["section"], "avg": { "chemistry": "avgChemistryMarks" }, "max": { "maths": "maxMathsMarks" } } }; + marksList.find(filter, {}, function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res); + expect(res).not.to.be.null; + expect(res).not.to.be.empty; + expect(res).not.to.be.undefined; + expect(res).to.have.length(3); + expect(res[0].section).to.be.equal('Charlie'); + expect(res[1].section).to.be.equal('Delta'); + expect(res[2].section).to.be.equal('Echo'); + done(); + } + }); + }); + + it('Test for applying multiple aggregation functions with "offset" filter', function (done) { + var filter = { "limit": 3, "offset": 2, "order": ["section ASC"], "group": { "groupBy": ["section"], "avg": { "chemistry": "avgChemistryMarks" }, "max": { "maths": "maxMathsMarks" } } }; + marksList.find(filter, {}, function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res); + expect(res).not.to.be.null; + expect(res).not.to.be.empty; + expect(res).not.to.be.undefined; + expect(res).to.have.length(3); + expect(res[0].section).to.be.equal('Charlie'); + expect(res[1].section).to.be.equal('Delta'); + expect(res[2].section).to.be.equal('Echo'); + done(); + } + }); + }); + + }); + +}); \ No newline at end of file diff --git a/test/aggregation-fn-having-test.js b/test/aggregation-fn-having-test.js new file mode 100644 index 0000000..6b8cd11 --- /dev/null +++ b/test/aggregation-fn-having-test.js @@ -0,0 +1,698 @@ +/** + * + * ©2016-2017 EdgeVerve Systems Limited (a fully owned Infosys subsidiary), + * Bangalore, India. All Rights Reserved. + * + */ + +var bootstrap = require('./bootstrap.js'); +var loopback = require('loopback'); +var chalk = require('chalk'); +var chai = require('chai'); +chai.use(require('chai-things')); +var expect = chai.expect; +var api = bootstrap.api; + +describe(chalk.blue('Aggregation Functions with having filter test'), function () { + this.timeout(10000); + + var studentsData = [ + { + "name": "Rickon", + "maths": 14, + "physics": 32, + "chemistry": 23, + "section": "Bravo", + "gender": "Male" + }, { + "name": "Sansa", + "maths": 15, + "physics": 16, + "chemistry": 51, + "section": "Bravo", + "gender": "Female" + }, { + "name": "Bran", + "maths": 14, + "physics": 72, + "chemistry": 96, + "section": "Charlie", + "gender": "Male" + }, { + "name": "Cersei", + "maths": 17, + "physics": 2, + "chemistry": 29, + "section": "Charlie", + "gender": "Female" + }, { + "name": "Arya", + "maths": 20, + "physics": 81, + "chemistry": 70, + "section": "Delta", + "gender": "Female" + }, { + "name": "Eddard", + "maths": 33, + "physics": 72, + "chemistry": 36, + "section": "Charlie", + "gender": "Male" + }, { + "name": "Tyrion", + "maths": 64, + "physics": 34, + "chemistry": 73, + "section": "Echo", + "gender": "Male" + }, { + "name": "Jaime", + "maths": 20, + "physics": 79, + "chemistry": 25, + "section": "Delta", + "gender": "Male" + }, { + "name": "Shae", + "maths": 47, + "physics": 36, + "chemistry": 1, + "section": "Echo", + "gender": "Female" + }, { + "name": "Ygritte", + "maths": 66, + "physics": 99, + "chemistry": 3, + "section": "Golf", + "gender": "Female" + }, { + "name": "Ramsay", + "maths": 79, + "physics": 18, + "chemistry": 97, + "section": "Alpha", + "gender": "Male" + }, { + "name": "Daenerys", + "maths": 60, + "physics": 74, + "chemistry": 10, + "section": "Alpha", + "gender": "Female" + }, { + "name": "Samwell", + "maths": 19, + "physics": 20, + "chemistry": 40, + "section": "Golf", + "gender": "Male" + }, { + "name": "Jon", + "maths": 41, + "physics": 66, + "chemistry": 71, + "section": "Alpha", + "gender": "Male" + }, { + "name": "Davos", + "maths": 19, + "physics": 11, + "chemistry": 100, + "section": "Delta", + "gender": "Male" + }, { + "name": "Robb", + "maths": 65, + "physics": 17, + "chemistry": 67, + "section": "Delta", + "gender": "Male" + }, { + "name": "Robert", + "maths": 20, + "physics": 91, + "chemistry": 96, + "section": "Golf", + "gender": "Male" + }, { + "name": "Podrick", + "maths": 80, + "physics": 1, + "chemistry": 79, + "section": "Delta", + "gender": "Male" + }, { + "name": "Missendei", + "maths": 21, + "physics": 5, + "chemistry": 5, + "section": "Delta", + "gender": "Female" + }, { + "name": "Varys", + "maths": 71, + "physics": 40, + "chemistry": 16, + "section": "Charlie", + "gender": "Male" + }, { + "name": "Margaery", + "maths": 58, + "physics": 69, + "chemistry": 86, + "section": "Echo", + "gender": "Female" + }, { + "name": "Hodor", + "maths": 20, + "physics": 84, + "chemistry": 97, + "section": "Bravo", + "gender": "Male" + }, { + "name": "Theon", + "maths": 36, + "physics": 5, + "chemistry": 41, + "section": "Foxtrot", + "gender": "Male" + }, { + "name": "Jorah", + "maths": 42, + "physics": 97, + "chemistry": 77, + "section": "Bravo", + "gender": "Male" + }, { + "name": "Khal", + "maths": 34, + "physics": 46, + "chemistry": 87, + "section": "Alpha", + "gender": "Male" + }, { + "name": "Brienne", + "maths": 90, + "physics": 2, + "chemistry": 23, + "section": "Delta", + "gender": "Female" + }, { + "name": "Daario", + "maths": 96, + "physics": 4, + "chemistry": 6, + "section": "Echo", + "gender": "Male" + }, { + "name": "Joffrey", + "maths": 50, + "physics": 9, + "chemistry": 65, + "section": "Foxtrot", + "gender": "Male" + }, { + "name": "Melisandre", + "maths": 25, + "physics": 59, + "chemistry": 20, + "section": "Echo", + "gender": "Female" + }, { + "name": "Baelish", + "maths": 2, + "physics": 13, + "chemistry": 77, + "section": "Delta", + "gender": "Male" + } + ] + var marksList = loopback.findModel('MarksList'); + before('upload test data', function (done) { + marksList.create(studentsData, {}, function (err, res) { + done(); + }); + }); + + after('Cleanup', function (done) { + marksList.destroyAll({}, {}, function modelDestroyAll(err, result) { + done(err); + }); + }); + + describe(chalk.green('Aggregation Functions having clause Test --REST'), function () { + + var path = bootstrap.basePath + '/' + marksList.pluralModelName; + + it('Test for having clause "=" operator', function (done) { + var filter = '{"group":{"groupBy":["section","gender"],"max":{"maths":"maxMaths"}},"order":["section ASC"],"having":{"max":{"maths":60}}}'; + var url = path + '?filter=' + filter; + api + .get(url) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .expect(200).end(function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res.body); + expect(res.body).not.to.be.null; + expect(res.body).not.to.be.empty; + expect(res.body).not.to.be.undefined; + expect(res.body).to.have.length(1); + expect(res.body[0].maxMaths).to.be.equal(60); + done(); + } + }); + }); + + it('Test for having clause "neq" operator', function (done) { + var filter = '{"group":{"groupBy":["section","gender"],"max":{"maths":"maxMaths"}},"order":["section ASC"],"having":{"max":{"maths":{"neq":60}}}}'; + var url = path + '?filter=' + filter; + api + .get(url) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .expect(200).end(function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res.body); + expect(res.body).not.to.be.null; + expect(res.body).not.to.be.empty; + expect(res.body).not.to.be.undefined; + expect(res.body).to.have.length(12); + expect(res.body[0].maxMaths).to.be.not.equal(60); + done(); + } + }); + }); + + it('Test for having clause "gt" operator', function (done) { + var filter = '{"group":{"groupBy":["section","gender"],"max":{"maths":"maxMaths"}},"order":["section ASC"],"having":{"max":{"maths":{"gt":60}}}}'; + var url = path + '?filter=' + filter; + api + .get(url) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .expect(200).end(function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res.body); + expect(res.body).not.to.be.null; + expect(res.body).not.to.be.empty; + expect(res.body).not.to.be.undefined; + expect(res.body).to.have.length(6); + expect(res.body[0].maxMaths).to.be.gt(60); + expect(res.body[1].maxMaths).to.be.gt(60); + done(); + } + }); + }); + + it('Test for having clause "gte" operator', function (done) { + var filter = '{"group":{"groupBy":["section","gender"],"max":{"maths":"maxMaths"}},"order":["section ASC"],"having":{"max":{"maths":{"gte":60}}}}'; + var url = path + '?filter=' + filter; + api + .get(url) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .expect(200).end(function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res.body); + expect(res.body).not.to.be.null; + expect(res.body).not.to.be.empty; + expect(res.body).not.to.be.undefined; + expect(res.body).to.have.length(7); + expect(res.body[0].maxMaths).to.be.gte(60); + expect(res.body[1].maxMaths).to.be.gte(60); + done(); + } + }); + }); + + it('Test for having clause "lt" operator', function (done) { + var filter = '{"group":{"groupBy":["section","gender"],"max":{"maths":"maxMaths"}},"order":["section ASC"],"having":{"max":{"maths":{"lt":50}}}}'; + var url = path + '?filter=' + filter; + api + .get(url) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .expect(200).end(function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res.body); + expect(res.body).not.to.be.null; + expect(res.body).not.to.be.empty; + expect(res.body).not.to.be.undefined; + expect(res.body).to.have.length(4); + expect(res.body[0].maxMaths).to.be.lt(50); + expect(res.body[1].maxMaths).to.be.lt(50); + done(); + } + }); + }); + + it('Test for having clause "lte" operator', function (done) { + var filter = '{"group":{"groupBy":["section","gender"],"max":{"maths":"maxMaths"}},"order":["section ASC"],"having":{"max":{"maths":{"lte":50}}}}'; + var url = path + '?filter=' + filter; + api + .get(url) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .expect(200).end(function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res.body); + expect(res.body).not.to.be.null; + expect(res.body).not.to.be.empty; + expect(res.body).not.to.be.undefined; + expect(res.body).to.have.length(5); + expect(res.body[0].maxMaths).to.be.lte(50); + expect(res.body[1].maxMaths).to.be.lte(50); + done(); + } + }); + }); + + it('Test for having clause "between" operator', function (done) { + var filter = '{"group":{"groupBy":["section","gender"],"max":{"maths":"maxMaths"}},"order":["section ASC"],"having":{"max":{"maths":{"between":[40,80]}}}}'; + var url = path + '?filter=' + filter; + api + .get(url) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .expect(200).end(function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res.body); + expect(res.body).not.to.be.null; + expect(res.body).not.to.be.empty; + expect(res.body).not.to.be.undefined; + expect(res.body).to.have.length(8); + expect(res.body[0].maxMaths).to.be.gte(40); + expect(res.body[0].maxMaths).to.be.lte(80); + done(); + } + }); + }); + + it('Test for having clause "inq" operator', function (done) { + var filter = '{"group":{"groupBy":["section","gender"],"max":{"maths":"maxMaths"}},"order":["section ASC"],"having":{"max":{"maths":{"inq":[60,50,80]}}}}'; + var url = path + '?filter=' + filter; + api + .get(url) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .expect(200).end(function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res.body); + expect(res.body).not.to.be.null; + expect(res.body).not.to.be.empty; + expect(res.body).not.to.be.undefined; + expect(res.body).to.have.length(3); + expect(res.body[0].maxMaths).to.be.equal(60); + expect(res.body[1].maxMaths).to.be.equal(80); + expect(res.body[2].maxMaths).to.be.equal(50); + done(); + } + }); + }); + + it('Test for having clause "nin" operator', function (done) { + var filter = '{"group":{"groupBy":["section","gender"],"max":{"maths":"maxMaths"}},"order":["section ASC"],"having":{"max":{"maths":{"nin":[60,50,80]}}}}'; + var url = path + '?filter=' + filter; + api + .get(url) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .expect(200).end(function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res.body); + expect(res.body).not.to.be.null; + expect(res.body).not.to.be.empty; + expect(res.body).not.to.be.undefined; + expect(res.body).to.have.length(10); + expect(res.body[0].maxMaths).to.be.not.equal(60); + done(); + } + }); + }); + + it('Test for having clause "and" operator', function (done) { + var filter = '{"group":{"groupBy":["section","gender"],"max":{"maths":"maxMaths"}},"order":["section ASC"],"having":{"and":[{"max":{"maths":60}},{"max":{"maths":{"inq":[50,60,80]}}}]}}'; + var url = path + '?filter=' + filter; + api + .get(url) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .expect(200).end(function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res.body); + expect(res.body).not.to.be.null; + expect(res.body).not.to.be.empty; + expect(res.body).not.to.be.undefined; + expect(res.body).to.have.length(1); + expect(res.body[0].maxMaths).to.be.equal(60); + done(); + } + }); + }); + + it('Test for having clause "or" operator', function (done) { + var filter = '{"group":{"groupBy":["section","gender"],"max":{"maths":"maxMaths"}},"order":["section ASC"],"having":{"or":[{"max":{"maths":{"gte":96}}},{"max":{"maths":{"inq":[50,60,80]}}}]}}'; + var url = path + '?filter=' + filter; + api + .get(url) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .expect(200).end(function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res.body); + expect(res.body).not.to.be.null; + expect(res.body).not.to.be.empty; + expect(res.body).not.to.be.undefined; + expect(res.body).to.have.length(4); + expect(res.body[0].maxMaths).to.be.equal(60); + done(); + } + }); + }); + + }); + + describe(chalk.green('Aggregation Functions having clause Test --Programatic'), function () { + + it('Test for having clause "=" operator', function (done) { + var filter = { "group": { "groupBy": ["section", "gender"], "max": { "maths": "maxMaths" } }, "order": ["section ASC"], "having": { "max": { "maths": 60 } } }; + marksList.find(filter, bootstrap.defaultContext, function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res); + expect(res).not.to.be.null; + expect(res).not.to.be.empty; + expect(res).not.to.be.undefined; + expect(res).to.have.length(1); + expect(res[0].maxMaths).to.be.equal(60); + done(); + } + }); + }); + + it('Test for having clause "neq" operator', function (done) { + var filter = { "group": { "groupBy": ["section", "gender"], "max": { "maths": "maxMaths" } }, "order": ["section ASC"], "having": { "max": { "maths": { "neq": 60 } } } }; + marksList.find(filter, bootstrap.defaultContext, function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res); + expect(res).not.to.be.null; + expect(res).not.to.be.empty; + expect(res).not.to.be.undefined; + expect(res).to.have.length(12); + expect(res[0].maxMaths).to.be.not.equal(60); + done(); + } + }); + }); + + it('Test for having clause "gt" operator', function (done) { + var filter = { "group": { "groupBy": ["section", "gender"], "max": { "maths": "maxMaths" } }, "order": ["section ASC"], "having": { "max": { "maths": { "gt": 60 } } } }; + marksList.find(filter, bootstrap.defaultContext, function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res); + expect(res).not.to.be.null; + expect(res).not.to.be.empty; + expect(res).not.to.be.undefined; + expect(res).to.have.length(6); + expect(res[0].maxMaths).to.be.gt(60); + expect(res[1].maxMaths).to.be.gt(60); + done(); + } + }); + }); + + it('Test for having clause "gte" operator', function (done) { + var filter = { "group": { "groupBy": ["section", "gender"], "max": { "maths": "maxMaths" } }, "order": ["section ASC"], "having": { "max": { "maths": { "gte": 60 } } } }; + marksList.find(filter, bootstrap.defaultContext, function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res); + expect(res).not.to.be.null; + expect(res).not.to.be.empty; + expect(res).not.to.be.undefined; + expect(res).to.have.length(7); + expect(res[0].maxMaths).to.be.gte(60); + expect(res[1].maxMaths).to.be.gte(60); + done(); + } + }); + }); + + it('Test for having clause "lt" operator', function (done) { + var filter = { "group": { "groupBy": ["section", "gender"], "max": { "maths": "maxMaths" } }, "order": ["section ASC"], "having": { "max": { "maths": { "lt": 50 } } } }; + marksList.find(filter, bootstrap.defaultContext, function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res); + expect(res).not.to.be.null; + expect(res).not.to.be.empty; + expect(res).not.to.be.undefined; + expect(res).to.have.length(4); + expect(res[0].maxMaths).to.be.lt(50); + expect(res[1].maxMaths).to.be.lt(50); + done(); + } + }); + }); + + it('Test for having clause "lte" operator', function (done) { + var filter = { "group": { "groupBy": ["section", "gender"], "max": { "maths": "maxMaths" } }, "order": ["section ASC"], "having": { "max": { "maths": { "lte": 50 } } } }; + marksList.find(filter, bootstrap.defaultContext, function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res); + expect(res).not.to.be.null; + expect(res).not.to.be.empty; + expect(res).not.to.be.undefined; + expect(res).to.have.length(5); + expect(res[0].maxMaths).to.be.lte(50); + expect(res[1].maxMaths).to.be.lte(50); + done(); + } + }); + }); + + it('Test for having clause "between" operator', function (done) { + var filter = { "group": { "groupBy": ["section", "gender"], "max": { "maths": "maxMaths" } }, "order": ["section ASC"], "having": { "max": { "maths": { "between": [40, 80] } } } }; + marksList.find(filter, bootstrap.defaultContext, function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res); + expect(res).not.to.be.null; + expect(res).not.to.be.empty; + expect(res).not.to.be.undefined; + expect(res).to.have.length(8); + expect(res[0].maxMaths).to.be.gte(40); + expect(res[0].maxMaths).to.be.lte(80); + done(); + } + }); + }); + + it('Test for having clause "inq" operator', function (done) { + var filter = { "group": { "groupBy": ["section", "gender"], "max": { "maths": "maxMaths" } }, "order": ["section ASC"], "having": { "max": { "maths": { "inq": [60, 50, 80] } } } }; + marksList.find(filter, bootstrap.defaultContext, function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res); + expect(res).not.to.be.null; + expect(res).not.to.be.empty; + expect(res).not.to.be.undefined; + expect(res).to.have.length(3); + expect(res[0].maxMaths).to.be.equal(60); + expect(res[1].maxMaths).to.be.equal(80); + expect(res[2].maxMaths).to.be.equal(50); + done(); + } + }); + }); + + it('Test for having clause "nin" operator', function (done) { + var filter = { "group": { "groupBy": ["section", "gender"], "max": { "maths": "maxMaths" } }, "order": ["section ASC"], "having": { "max": { "maths": { "nin": [60, 50, 80] } } } }; + marksList.find(filter, bootstrap.defaultContext, function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res); + expect(res).not.to.be.null; + expect(res).not.to.be.empty; + expect(res).not.to.be.undefined; + expect(res).to.have.length(10); + expect(res[0].maxMaths).to.be.not.equal(60); + done(); + } + }); + }); + + it('Test for having clause "and" operator', function (done) { + var filter = { "group": { "groupBy": ["section", "gender"], "max": { "maths": "maxMaths" } }, "order": ["section ASC"], "having": { "and": [{ "max": { "maths": 60 } }, { "max": { "maths": { "inq": [50, 60, 80] } } }] } }; + marksList.find(filter, bootstrap.defaultContext, function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res); + expect(res).not.to.be.null; + expect(res).not.to.be.empty; + expect(res).not.to.be.undefined; + expect(res).to.have.length(1); + expect(res[0].maxMaths).to.be.equal(60); + done(); + } + }); + }); + + it('Test for having clause "or" operator', function (done) { + var filter = { "group": { "groupBy": ["section", "gender"], "max": { "maths": "maxMaths" } }, "order": ["section ASC"], "having": { "or": [{ "max": { "maths": { "gte": 96 } } }, { "max": { "maths": { "inq": [50, 60, 80] } } }] } }; + marksList.find(filter, bootstrap.defaultContext, function (err, res) { + if (err) { + done(err); + } else { + // console.log("---> result", res); + expect(res).not.to.be.null; + expect(res).not.to.be.empty; + expect(res).not.to.be.undefined; + expect(res).to.have.length(4); + expect(res[0].maxMaths).to.be.equal(60); + done(); + } + }); + }); + + }); + +}); \ No newline at end of file diff --git a/test/app-list.json b/test/app-list.json index 9bd4393..193d4b2 100644 --- a/test/app-list.json +++ b/test/app-list.json @@ -3,10 +3,6 @@ "path": "./", "forceLoad": "index.js" }, - { - "path": "oe-skeleton", - "enabled": true - }, { "path": "./", "enabled": true, diff --git a/test/bootstrap.js b/test/bootstrap.js new file mode 100644 index 0000000..f496bb7 --- /dev/null +++ b/test/bootstrap.js @@ -0,0 +1,44 @@ +/** + * + * 2018-2019 EdgeVerve Systems Limited (a fully owned Infosys subsidiary), + * Bangalore, India. All Rights Reserved. + * + */ + +const _require = require; + +require = function (a) { + if (a === 'oe-cloud') { + return _require('../index.js'); + } + return _require(a); +}; + +var oecloud = require('oe-cloud'); +var defaults = require('superagent-defaults'); +var supertest = require('supertest'); +var api = defaults(supertest(oecloud)); + +oecloud.boot(__dirname, function (err) { + if (err) { + console.log(err); + process.exit(1); + } + oecloud.start(); + oecloud.emit('test-start'); +}); + +describe('oe-cloud test Started', function () { + this.timeout(10000); + it('Waiting for application to start', function (done) { + oecloud.on('test-start', function () { + done(); + }); + }); +}); + +module.exports = { + app: oecloud, + api: api, + basePath: oecloud.get('restApiRoot') +}; diff --git a/test/common/models/MarksList.json b/test/common/models/MarksList.json new file mode 100644 index 0000000..a328acd --- /dev/null +++ b/test/common/models/MarksList.json @@ -0,0 +1,14 @@ +{ + "name": "MarksList", + "Base": "BaseEntity", + "plural": "MarksLists", + "properties": { + "name": "string", + "maths": "number", + "physics": "number", + "chemistry": "number", + "section": "string", + "gender": "string" + }, + "strict": true +} \ No newline at end of file diff --git a/test/component-config.json b/test/component-config.json index f36959a..2c63c08 100644 --- a/test/component-config.json +++ b/test/component-config.json @@ -1,5 +1,2 @@ { - "loopback-component-explorer": { - "mountPath": "/explorer" - } } diff --git a/test/model-config.json b/test/model-config.json index 611894c..4a4b0c3 100644 --- a/test/model-config.json +++ b/test/model-config.json @@ -41,5 +41,9 @@ "Spouse": { "dataSource": "db", "public": true + }, + "MarksList": { + "dataSource": "db", + "public": true } } diff --git a/test/performance/oe-cloud-test.jmx b/test/performance/oe-cloud-test.jmx new file mode 100644 index 0000000..f02718a --- /dev/null +++ b/test/performance/oe-cloud-test.jmx @@ -0,0 +1,993 @@ + + + + + + false + true + + + + + + + + + + secure + ${__P(secure,http)} + = + + + hostname + ${__P(host,10.73.97.32)} + = + + + port + ${__P(port,3000)} + = + + + users + ${__P(users,1)} + = + + + rampUp + ${__P(rampup,1)} + = + + + loopcount + ${__P(loopcount,5)} + = + + + model + CustomerPerfModel + = + + + relatedmodel + AccountPerfModel + = + + + + + + continue + + false + 1 + + 1 + 1 + 1511329880000 + 1511329880000 + false + + + + + + true + + + + false + { + "username":"admin", + "password":"admin", + "email": "admin@oecloud.com" +} + = + + + + ${hostname} + ${port} + ${secure} + + /api/Users/ + POST + true + false + true + false + + + + + + + + + Accept-Language + en-US,en;q=0.8,hi;q=0.6 + + + accept + application/json + + + content-type + application/json + + + + + + + username + + Assertion.response_data + false + 2 + + + + + false + true + true + false + + + + + true + + + + false + { + "username":"admin", + "password":"admin" +} + = + + + + ${hostname} + ${port} + ${secure} + + /api/Users/login + POST + true + false + true + false + + + + + + + + + Accept-Language + en-US,en;q=0.8,hi;q=0.6 + + + accept + application/json + + + content-type + application/json + + + + + + access_token + $.id + 0 + null + + + + false + + + String access = vars.get("access_token"); +props.put("access_token", access); + + + + + id + + Assertion.response_data + false + 2 + + + + + false + true + true + false + + + + + true + + + + false + { + "id":"${relatedmodel}", + "name":"${relatedmodel}", + "plural":"${relatedmodel}", + "properties":{ + "accountNo":{ + "type":"string", + "required":true + }, + "accountType":{ + "type":"string", + "in":["savings","salary","current"] + }, + "balance":{ + "type":"number", + "min":0, + "max":1000000 + }, + "openingDate":{ + "type":"date" + } + }, + "base":"BaseEntity" +} + = + + + + ${hostname} + ${port} + ${secure} + + /api/ModelDefinitions?access_token=${access_token} + POST + true + false + true + false + + + + + + + + + accept + application/json + + + content-type + application/json + + + + + + false + true + true + false + + + + + true + + + + false + { + "id":"${model}", + "name":"${model}", + "plural":"${model}", + "properties":{ + "name":{ + "type":"string", + "required":true, + "length":42 + }, + "city":{ + "type":"string", + "in":["Bangalore","Hyderabad","Pune"] + }, + "state":{ + "type":"string" + }, + "email":{ + "type":"email", + "unique":true, + "index":true + }, + "phone":{ + "type":"string", + "length":10 + }, + "zipcode":{ + "type":"number", + "min":100000, + "max":999999 + }, + "country":{ + "type":"string" + }, + "aadhar":{ + "type":"string", + "length":16 + }, + "pan":{ + "type":"string", + "length":10 + }, + "userId":{ + "type":"string" + }, + "creditCard":{ + "type":"string", + "length":20 + }, + "ppfAccountNo":{ + "type":"string" + }, + "internetBanking":{ + "type":"boolean" + }, + "checkBook":{ + "type":"boolean" + } + }, + "base":"BaseEntity", + "relations":{ + "account":{ + "model":"${relatedmodel}", + "type":"hasMany" + } + } +} + = + + + + ${hostname} + ${port} + ${secure} + + /api/ModelDefinitions?access_token=${access_token} + POST + true + false + true + false + + + + + + + + + accept + application/json + + + content-type + application/json + + + + + + false + true + true + false + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + true + true + + + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + true + true + + + + + + + + continue + + false + 1 + + ${users} + ${rampUp} + 1511359936000 + 1511359936000 + false + + + + + + + + hostname + localhost + = + + + port + 3000 + = + + + model + PerfModels + = + + + + + + true + ${loopcount} + + + + 1 + 1000000 + 1 + id + + false + + + + 100000 + 10000000 + 1 + zip + + false + + + + + + accept + application/json + + + content-type + application/json + + + authorization + ${__property(access_token)} + + + + + + true + + + + false + { + "id":"customer${id}", + "name":"customer${id}", + "city":"Bangalore", + "state":"Karnataka", + "email":"user${id}@oeCloud.com", + "phone":"9080706050", + "zipcode":${zip}, + "country":"IN", + "aadhar":"1234567812345678", + "pan":"BBWAS4567H", + "userId":"cust${id}", + "creditCard":"12345678123456781234", + "ppfAccountNo":"PPF123", + "internetBanking":true, + "checkBook":true, + "account":[{ + "accountNo":"account${id}", + "accountType":"salary", + "balance":23456, + "openingDate":"2018-03-26T10:50:51.161z" + }] +} + = + + + + ${hostname} + ${port} + ${secure} + + /api/${model} + POST + true + false + true + false + + + + + + + false + true + true + false + + + + + true + ${loopcount} + + + + 1 + 1000000 + 1 + id + + false + + + + + + accept + application/json + + + content-type + application/json + + + authorization + ${__property(access_token)} + + + + + + + + + ${hostname} + ${port} + ${secure} + + /api/${model}/customer${id} + GET + true + false + true + false + + + + + + + false + true + true + false + + + + + true + ${loopcount} + + + + 1 + 1000000 + 1 + id + + false + + + + true + + + + false + { + "name":"customer${id}", + "city":"Bangalore", + "state":"Karnataka", + "email":"user${id}@oeCloud.com", + "phone":"9080706050", + "country":"IN", + "aadhar":"1234567812345678", + "pan":"BBWAS4567H", + "userId":"customerId${id}", + "creditCard":"12345678123456781234", + "ppfAccountNo":"PPF123", + "internetBanking":true, + "checkBook":false +} + = + + + + ${hostname} + ${port} + ${secure} + + /api/${model}/customer${id} + PUT + true + false + true + false + + + + + + + + + accept + application/json + + + content-type + application/json + + + authorization + ${__property(access_token)} + + + + + + false + true + true + false + + + + + true + ${loopcount} + + + + 1 + 1000000 + 1 + id + + false + + + + + + + ${hostname} + ${port} + ${secure} + + /api/${model}/customer${id} + DELETE + true + false + true + false + + + + + + + + + accept + application/json + + + content-type + application/json + + + authorization + ${__property(access_token)} + + + + + + false + true + true + false + + + + + "count":1 + + + Assertion.response_data + false + 2 + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + true + true + + + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + true + true + + + + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + false + false + true + false + true + false + false + false + true + 0 + true + true + true + true + true + + + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + true + true + + + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + true + true + + + + + + + + diff --git a/test/test.js b/test/test.js index f6e463e..ae313dc 100644 --- a/test/test.js +++ b/test/test.js @@ -5,56 +5,35 @@ * */ -const _require = require; -require = function (a) { - if (a === 'oe-cloud') { - return _require('../index.js'); - } - return _require(a); -}; - -var oecloud = require('oe-cloud'); +var bootstrap = require('./bootstrap.js'); var loopback = require('loopback'); - -const path = require('path'); - -oecloud.observe('loaded', function (ctx, next) { - if (!oecloud.options.baseEntitySources) { - oecloud.options.baseEntitySources = [process.cwd() + '/test/common/models/base-entity-test.js']; - } - oecloud.attachMixinsToModelDefinition('NewMixin'); - oecloud.attachMixinsToBaseEntity('TestMixin'); - oecloud.addSettingsToBaseEntity({ mysettings: true }); - oecloud.addSettingsToModelDefinition({ xsettings: true }); - return next(); -}); - -oecloud.boot(__dirname, function (err) { - if (err) { - console.log(err); - process.exit(1); - } - oecloud.start(); - oecloud.emit('test-start'); -}); - - var chalk = require('chalk'); var chai = require('chai'); -var async = require('async'); chai.use(require('chai-things')); - var expect = chai.expect; - -var app = oecloud; -var defaults = require('superagent-defaults'); -var supertest = require('supertest'); -var api = defaults(supertest(app)); -var basePath = app.get('restApiRoot'); -var url = basePath + '/Employees'; - -var models = oecloud.models; - +var app = bootstrap.app; +var api = bootstrap.api; +var basePath = bootstrap.basePath; + +// Atul : Below code is commented - kept is as reference to test behavior when by default BaseEntity write operation is protected. +// when this code is uncommented, t-17 would fail. +// app.setACLToBaseEntity({ +// "accessType": "WRITE", +// "principalType": "ROLE", +// "principalId": "$unauthenticated", +// "permission": "DENY" +// }); + +app.observe('loaded', function (ctx, next) { + if (!app.options.baseEntitySources) { + app.options.baseEntitySources = [process.cwd() + '/test/common/models/base-entity-test.js']; + } + app.attachMixinsToModelDefinition('NewMixin'); + app.attachMixinsToBaseEntity('TestMixin'); + app.addSettingsToBaseEntity({ mysettings: true }); + app.addSettingsToModelDefinition({ xsettings: true }); + return next(); +}); function deleteAllUsers(done) { var userModel = loopback.findModel('User'); @@ -76,7 +55,7 @@ function deleteAllUsers(done) { var globalCtx = { ignoreAutoScope: true, - ctx: { tenantId: '/default'} + ctx: { tenantId: '/default' } }; var defaultContext = { ctx: { tenantId: '/default' } @@ -87,10 +66,8 @@ describe(chalk.blue('oeCloud Test Started'), function (done) { this.timeout(10000); before('wait for boot scripts to complete', function (done) { - app.on('test-start', function () { - deleteAllUsers(function () { - return done(); - }); + deleteAllUsers(function () { + return done(); }); }); @@ -112,11 +89,11 @@ describe(chalk.blue('oeCloud Test Started'), function (done) { api.set('Accept', 'application/json') .post(url) .send([{ id: 'admin', username: 'admin', password: 'admin', email: 'admin@admin.com' }, - {id: 'evuser', username: 'evuser', password: 'evuser', email: 'evuser@evuser.com' }, - {id: 'infyuser', username: 'infyuser', password: 'infyuser', email: 'infyuser@infyuser.com' }, - { id: 'bpouser', username: 'bpouser', password: 'bpouser', email: 'bpouser@bpouser.com' }, - { id: 'iciciuser', username: 'iciciuser', password: 'iciciuser', email: 'iciciuser@iciciuser.com' }, - { id: 'citiuser', username: 'citiuser', password: 'citiuser', email: 'citiuser@citiuser.com' } + { id: 'evuser', username: 'evuser', password: 'evuser', email: 'evuser@evuser.com' }, + { id: 'infyuser', username: 'infyuser', password: 'infyuser', email: 'infyuser@infyuser.com' }, + { id: 'bpouser', username: 'bpouser', password: 'bpouser', email: 'bpouser@bpouser.com' }, + { id: 'iciciuser', username: 'iciciuser', password: 'iciciuser', email: 'iciciuser@iciciuser.com' }, + { id: 'citiuser', username: 'citiuser', password: 'citiuser', email: 'citiuser@citiuser.com' } ]) .end(function (err, response) { var result = response.body; @@ -138,10 +115,10 @@ describe(chalk.blue('oeCloud Test Started'), function (done) { // validations.id.shift(); //} roleModel.create([ - {id: 'admin', name: 'admin'}, - {id: 'businessUser', name: 'businessUser'}, - {id: 'guest', name: 'guest'}, - {id: 'poweruser', name: 'poweruser'} + { id: 'admin', name: 'admin' }, + { id: 'businessUser', name: 'businessUser' }, + { id: 'guest', name: 'guest' }, + { id: 'poweruser', name: 'poweruser' } ], function (err, result) { return done(err); }); @@ -155,10 +132,10 @@ describe(chalk.blue('oeCloud Test Started'), function (done) { //} //roleMapping.settings.forceId = false; roleMapping.create([ - {id: 'adminuser', principalType: roleMapping.USER, principalId: 'admin', roleId: 'admin'}, - {id: 'businessUser', principalType: roleMapping.USER, principalId: 'infyuser', roleId: 'businessUser'}, - {id: 'poweruser', principalType: roleMapping.USER, principalId: 'infyuser', roleId: 'poweruser'}, - {id: 'guestuser', principalType: roleMapping.USER, principalId: 'evuser', roleId: 'guest' } + { id: 'adminuser', principalType: roleMapping.USER, principalId: 'admin', roleId: 'admin' }, + { id: 'businessUser', principalType: roleMapping.USER, principalId: 'infyuser', roleId: 'businessUser' }, + { id: 'poweruser', principalType: roleMapping.USER, principalId: 'infyuser', roleId: 'poweruser' }, + { id: 'guestuser', principalType: roleMapping.USER, principalId: 'evuser', roleId: 'guest' } ], function (err, result) { return done(err); }); @@ -291,7 +268,7 @@ describe(chalk.blue('oeCloud Test Started'), function (done) { it('t7 hooking observer', function (done) { var modelDefinition = loopback.findModel('ModelDefinition'); modelDefinition.find({ - where: {name: 'NewCustomer'} + where: { name: 'NewCustomer' } }, {}, function (err, results) { var item = results[0]; expect(item.name).to.be.equal('NewCustomer'); @@ -332,7 +309,7 @@ describe(chalk.blue('oeCloud Test Started'), function (done) { if (!x) { return done(new Error('Expcted instnace query flag to be true')); } - x = utils.isInstanceQuery(newCustomerModel, { where: { and: [{ name: 'x' }, { age: 1 }, { and: [{ id: 1 }, {age: 10}]}] } }); + x = utils.isInstanceQuery(newCustomerModel, { where: { and: [{ name: 'x' }, { age: 1 }, { and: [{ id: 1 }, { age: 10 }] }] } }); if (!x) { return done(new Error('Expcted instnace query flag to be true')); } @@ -347,11 +324,11 @@ describe(chalk.blue('oeCloud Test Started'), function (done) { var id = utils.getIdValue(newCustomerModel, { id: 10, name: 'A' }); - var f = utils.checkDependency(oecloud, ['./']); - f = utils.checkDependency(oecloud, './'); + var f = utils.checkDependency(app, ['./']); + f = utils.checkDependency(app, './'); var o1 = { x: 'x', a1: [12, 3, 4] }; - var o2 = { y: 'y', a2: [1122, 33, 44], a1: [1122, 33, 44] }; + var o2 = { y: 'y', a2: [1122, 33, 44], a1: [1122, 33, 44] }; var o3 = utils.mergeObjects(o1, o2); expect(o3.x).to.be.equal('x'); @@ -554,7 +531,7 @@ describe(chalk.blue('oeCloud Test Started'), function (done) { console.log(JSON.stringify(newds)); - var datasources = [ newds ]; + var datasources = [newds]; it('t12 - creating datasource', function (done) { var ds = datasources[0]; @@ -575,20 +552,19 @@ describe(chalk.blue('oeCloud Test Started'), function (done) { }); it('t13 - changing datasource of model', function (done) { - var DataSourceDefinition = loopback.findModel('DataSourceDefinition'); - var ds = oecloud.datasources['oe-cloud-test-newdb']; + var ds = app.datasources['oe-cloud-test-newdb']; var newCustomerModel = loopback.findModel('NewCustomer'); ds.attach(newCustomerModel); - newCustomerModel.create({name: 'CustomerInNewDB'}, defaultContext, function (err, res) { + newCustomerModel.create({ name: 'CustomerInNewDB' }, defaultContext, function (err, res) { return done(err); }); }); it('t14 - testing group by', function (done) { var customerModel = loopback.findModel('Customer'); - customerModel.create([{name: 'A', age: 30}, { name: 'B', age: 30 }], {}, function (err, r) { + customerModel.create([{ name: 'A', age: 30 }, { name: 'B', age: 30 }], {}, function (err, r) { if (err) return done(err); - customerModel.find({group: {groupBy: ['age']}}, {}, function (err2, r2) { + customerModel.find({ group: { groupBy: ['age'] } }, {}, function (err2, r2) { if (err2) return done(err2); console.log(r2); return done(); @@ -642,7 +618,32 @@ describe(chalk.blue('oeCloud Test Started'), function (done) { console.log(response.error); done(err); }); - }); -}); - + }); + it('t17 - Able to create record in customer without passing access token', function (done) { + var url = basePath + '/customers'; + api.set('Accept', 'application/json') + .post(url) + .send({ name: "customer created without access token", age: 10 }) + .end(function (err, response) { + console.log(response.error); + done(err); + }); + }); + it('t17 - Should not Able to create record in customer without passing valid access token', function (done) { + var acl = { accessType: 'WRITE', permission: 'DENY', principalId: '$unauthenticated', principalType: 'ROLE' }; + var baseEntity = loopback.findModel('Customer'); + baseEntity.settings.acls = []; + baseEntity.settings.acls.push(acl); + var url = basePath + '/customers'; + api.set('Accept', 'application/json') + .post(url) + .send({ name: "Another customer created without access token", age: 10 }) + .end(function (err, response) { + if (response.status != 401) { + return done(new Error("unauthorized access should not be allowed")); + } + done(); + }); + }); +});