Added README and test

This commit is contained in:
Naida Vatric
2019-11-04 20:19:33 +01:00
parent a43ac6f27a
commit 0d525d486e
19 changed files with 1517 additions and 64 deletions

View File

@@ -1 +1,98 @@
# Naida test
***Permissions API
Permissions API implements a set of JSON end-points which allow other parts of a larger application to update and test user access (permissions) over a set of named objects.
The API deals with:
- a set of Named OBJECTS whose access permissions are being controlled,
- a set of USERNAMES which might have different types of permissions.
- a set of GROUPS that those users may be part of,
- a set of PERMISSIONS which specific users or groups of users might have over specific objects.
*API documentation
Complete API documentation (created with Postman) can be found on public URL: https://documenter.getpostman.com/view/9085921/SW14TwCX?version=latest
*Getting Started
Instructions for running API on your local machine for develoment and testing purposes.
*Prerequisited
Pull project folder from GitLab to your local machine: https://gitlab.com/saburly/testovi/naida
*Setting up database
Install PostgreSQL from official site if needed: https://www.postgresql.org/download/
Navigate to project folder. Open terminal and run script for creating a database. Before runing script change user to postgres.
$sudo su - postgres
$chmod +x dbscript.sh
$sh dbscript.sh
In file permissions.js change password for user postgres and local host if needed:
const db = knex ({
client: 'pg',
connection: {
host : '127.0.0.1',
user : 'postgres',
password : '0904',
database : 'testdb'
}
});
*Installing dependencies
Check that package.json has listed dependencies:
"dependencies": {
"body-parser": "^1.19.0",
"cors": "^2.8.5",
"express": "^4.17.1",
"express-validator": "^6.2.0",
"knex": "^0.20.0",
"pg": "^7.12.1",
"chai": "^4.1.2",
"chai-http": "4.2.1",
"mocha": "^5.2.0",
"mochawesome": "^3.0.2",
"supertest": "^3.1.0",
"tv4": "^1.3.0"
},
"devDependencies": {
"nodemon": "^1.19.4"
}
In terminal navigate to project folder and run:
$npm install
This should install all needed dependencies (node modules).
*Start project
To run API on your local machine open terminal, navigate to project folder and run:
$npm start
API is running on default localport 3000, for testing and development purposes.
*Running the test
For conducting script test, run in terminal:
$npm test
*Built With
-Node.js, Express
-PostgreSQL
-Postman
-Mocha
*Acknowledgments
Special thanks to authors of these excelent articles and repositories:
-https://medium.com/@olotintemitope/how-to-generate-your-api-documentation-in-20-minutes-4e0072f08b94
-https://dev.to/nedsoft/a-clean-approach-to-using-express-validator-8go
-https://medium.com/@shashiraja/convert-postman-api-tests-to-mocha-10705af6e37a
-https://medium.com/@svsh227/write-your-first-test-case-in-your-node-app-using-mocha-5250e614feb3

17
dbscript.sh Normal file
View File

@@ -0,0 +1,17 @@
#!/bin/sh
psql -U postgres << END_OF_SCRIPT
DROP DATABASE testdb; -- drop the DB if exists
CREATE DATABASE testdb WITH OWNER = postgres;
\c testdb
-- Create tables of the DB
CREATE TABLE objects (id serial PRIMARY KEY, objname varchar (100) UNIQUE NOT NULL);
CREATE TABLE users (id serial PRIMARY KEY, username varchar (100) UNIQUE NOT NULL);
CREATE TABLE groups (id serial PRIMARY KEY, groupname varchar(100) NOT NULL, username varchar (100));
CREATE TABLE permissions (id serial PRIMARY KEY, ownertype varchar(100) NOT NULL, owner varchar(100) NOT NULL, objname varchar (100) NOT NULL, type varchar(100) NOT NULL);
END_OF_SCRIPT

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,509 @@
{
"stats": {
"suites": 7,
"tests": 12,
"passes": 12,
"pending": 0,
"failures": 0,
"start": "2019-11-04T19:07:28.048Z",
"end": "2019-11-04T19:07:28.617Z",
"duration": 569,
"testsRegistered": 12,
"passPercent": 100,
"pendingPercent": 0,
"other": 0,
"hasOther": false,
"skipped": 0,
"hasSkipped": false,
"passPercentClass": "success",
"pendingPercentClass": "danger"
},
"suites": {
"uuid": "a15f134c-99fd-439c-9da3-1b6d22ee823d",
"title": "",
"fullFile": "",
"file": "",
"beforeHooks": [],
"afterHooks": [],
"tests": [],
"suites": [
{
"uuid": "c2865b3c-162f-40ea-8f05-4036e8ebba8d",
"title": "Add user Bob to group administrators",
"fullFile": "C:\\Users\\Zeko\\Documents\\ZeroToMastery\\testni_projekat\\permissions_api\\permissions_cloned\\test\\apitest.js",
"file": "\\test\\apitest.js",
"beforeHooks": [
{
"title": "\"before all\" hook",
"fullTitle": "Add user Bob to group administrators \"before all\" hook",
"timedOut": false,
"duration": 299,
"pass": false,
"fail": false,
"pending": false,
"code": "response = await call_api_add_user(data);\nbody = response.body;",
"err": {},
"isRoot": false,
"uuid": "d8648d71-4102-4330-bbbe-072c86efb0c6",
"isHook": true,
"skipped": false
}
],
"afterHooks": [],
"tests": [
{
"title": "Status code is 200",
"fullTitle": "Add user Bob to group administrators Status code is 200",
"timedOut": false,
"duration": 2,
"state": "passed",
"speed": "fast",
"pass": true,
"fail": false,
"pending": false,
"code": "expect(response.status).to.equal(200);",
"err": {},
"isRoot": false,
"uuid": "3dc0e744-4c57-4e65-9fb4-cf89399ceb5a",
"isHook": false,
"skipped": false
},
{
"title": "Schema is valid",
"fullTitle": "Add user Bob to group administrators Schema is valid",
"timedOut": false,
"duration": 3,
"state": "passed",
"speed": "fast",
"pass": true,
"fail": false,
"pending": false,
"code": "expect(tv4.validate(body, schema1)).to.be.true;",
"err": {},
"isRoot": false,
"uuid": "346cf09b-a0bb-4fc5-a01d-f50e218345cd",
"isHook": false,
"skipped": false
}
],
"suites": [],
"passes": [
"3dc0e744-4c57-4e65-9fb4-cf89399ceb5a",
"346cf09b-a0bb-4fc5-a01d-f50e218345cd"
],
"failures": [],
"pending": [],
"skipped": [],
"duration": 5,
"root": false,
"rootEmpty": false,
"_timeout": 200000
},
{
"uuid": "0287953e-15f5-4b07-b587-fe5e8cea895f",
"title": "Add user alice to group administrators",
"fullFile": "C:\\Users\\Zeko\\Documents\\ZeroToMastery\\testni_projekat\\permissions_api\\permissions_cloned\\test\\apitest.js",
"file": "\\test\\apitest.js",
"beforeHooks": [
{
"title": "\"before all\" hook",
"fullTitle": "Add user alice to group administrators \"before all\" hook",
"timedOut": false,
"duration": 26,
"pass": false,
"fail": false,
"pending": false,
"code": "response = await call_api_add_user(data);\nbody = response.body;",
"err": {},
"isRoot": false,
"uuid": "28d45481-88b1-4263-b93e-c2a21ce1f10b",
"isHook": true,
"skipped": false
}
],
"afterHooks": [],
"tests": [
{
"title": "Status code is 200",
"fullTitle": "Add user alice to group administrators Status code is 200",
"timedOut": false,
"duration": 0,
"state": "passed",
"speed": "fast",
"pass": true,
"fail": false,
"pending": false,
"code": "expect(response.status).to.equal(200);",
"err": {},
"isRoot": false,
"uuid": "6c7e04f9-6c64-4cb6-908b-610834dc45f8",
"isHook": false,
"skipped": false
},
{
"title": "Schema is valid",
"fullTitle": "Add user alice to group administrators Schema is valid",
"timedOut": false,
"duration": 0,
"state": "passed",
"speed": "fast",
"pass": true,
"fail": false,
"pending": false,
"code": "expect(tv4.validate(body, schema1)).to.be.true;",
"err": {},
"isRoot": false,
"uuid": "e59ed3ca-b747-48cb-bcaf-cf6751025460",
"isHook": false,
"skipped": false
}
],
"suites": [],
"passes": [
"6c7e04f9-6c64-4cb6-908b-610834dc45f8",
"e59ed3ca-b747-48cb-bcaf-cf6751025460"
],
"failures": [],
"pending": [],
"skipped": [],
"duration": 0,
"root": false,
"rootEmpty": false,
"_timeout": 200000
},
{
"uuid": "c6dbf655-3d74-4e8e-ac24-f34e0dffee6c",
"title": "Add permission over object message of the day to user dan",
"fullFile": "C:\\Users\\Zeko\\Documents\\ZeroToMastery\\testni_projekat\\permissions_api\\permissions_cloned\\test\\apitest.js",
"file": "\\test\\apitest.js",
"beforeHooks": [
{
"title": "\"before all\" hook",
"fullTitle": "Add permission over object message of the day to user dan \"before all\" hook",
"timedOut": false,
"duration": 20,
"pass": false,
"fail": false,
"pending": false,
"code": "response = await call_api_add_perm(data);\nbody = response.body;",
"err": {},
"isRoot": false,
"uuid": "72dddf72-1afb-47f9-9775-c3f3092f8b70",
"isHook": true,
"skipped": false
}
],
"afterHooks": [],
"tests": [
{
"title": "Status code is 200",
"fullTitle": "Add permission over object message of the day to user dan Status code is 200",
"timedOut": false,
"duration": 0,
"state": "passed",
"speed": "fast",
"pass": true,
"fail": false,
"pending": false,
"code": "expect(response.status).to.equal(200);",
"err": {},
"isRoot": false,
"uuid": "4faf445a-18ef-4e4e-adfa-898d5d5e7500",
"isHook": false,
"skipped": false
},
{
"title": "Schema is valid",
"fullTitle": "Add permission over object message of the day to user dan Schema is valid",
"timedOut": false,
"duration": 0,
"state": "passed",
"speed": "fast",
"pass": true,
"fail": false,
"pending": false,
"code": "expect(tv4.validate(body, schema2)).to.be.true;",
"err": {},
"isRoot": false,
"uuid": "eae67793-bd93-461a-bdb9-71b0e5b4ffbf",
"isHook": false,
"skipped": false
}
],
"suites": [],
"passes": [
"4faf445a-18ef-4e4e-adfa-898d5d5e7500",
"eae67793-bd93-461a-bdb9-71b0e5b4ffbf"
],
"failures": [],
"pending": [],
"skipped": [],
"duration": 0,
"root": false,
"rootEmpty": false,
"_timeout": 200000
},
{
"uuid": "be99ef0c-e8fb-4438-84bc-ddad91f16446",
"title": "Add permission over object message of the day to group administrators",
"fullFile": "C:\\Users\\Zeko\\Documents\\ZeroToMastery\\testni_projekat\\permissions_api\\permissions_cloned\\test\\apitest.js",
"file": "\\test\\apitest.js",
"beforeHooks": [
{
"title": "\"before all\" hook",
"fullTitle": "Add permission over object message of the day to group administrators \"before all\" hook",
"timedOut": false,
"duration": 43,
"pass": false,
"fail": false,
"pending": false,
"code": "response = await call_api_add_perm(data);\nbody = response.body;",
"err": {},
"isRoot": false,
"uuid": "385d482a-01bb-47ba-b11a-350af9203970",
"isHook": true,
"skipped": false
}
],
"afterHooks": [],
"tests": [
{
"title": "Status code is 200",
"fullTitle": "Add permission over object message of the day to group administrators Status code is 200",
"timedOut": false,
"duration": 0,
"state": "passed",
"speed": "fast",
"pass": true,
"fail": false,
"pending": false,
"code": "expect(response.status).to.equal(200);",
"err": {},
"isRoot": false,
"uuid": "a79ca20c-34a0-467c-b166-4e8417cc2d6a",
"isHook": false,
"skipped": false
},
{
"title": "Schema is valid",
"fullTitle": "Add permission over object message of the day to group administrators Schema is valid",
"timedOut": false,
"duration": 0,
"state": "passed",
"speed": "fast",
"pass": true,
"fail": false,
"pending": false,
"code": "expect(tv4.validate(body, schema2)).to.be.true;",
"err": {},
"isRoot": false,
"uuid": "5448fc55-d979-4d5d-8495-593577029ab8",
"isHook": false,
"skipped": false
}
],
"suites": [],
"passes": [
"a79ca20c-34a0-467c-b166-4e8417cc2d6a",
"5448fc55-d979-4d5d-8495-593577029ab8"
],
"failures": [],
"pending": [],
"skipped": [],
"duration": 0,
"root": false,
"rootEmpty": false,
"_timeout": 200000
},
{
"uuid": "d2dfaa0c-fecc-44d7-8461-e236de2d9218",
"title": "Add permission over object message of the day to group administrators",
"fullFile": "C:\\Users\\Zeko\\Documents\\ZeroToMastery\\testni_projekat\\permissions_api\\permissions_cloned\\test\\apitest.js",
"file": "\\test\\apitest.js",
"beforeHooks": [
{
"title": "\"before all\" hook",
"fullTitle": "Add permission over object message of the day to group administrators \"before all\" hook",
"timedOut": false,
"duration": 22,
"pass": false,
"fail": false,
"pending": false,
"code": "response = await call_api_add_perm(data);\nbody = response.body;",
"err": {},
"isRoot": false,
"uuid": "31212122-e409-4dea-947a-74177d5cfee5",
"isHook": true,
"skipped": false
}
],
"afterHooks": [],
"tests": [
{
"title": "Status code is 200",
"fullTitle": "Add permission over object message of the day to group administrators Status code is 200",
"timedOut": false,
"duration": 0,
"state": "passed",
"speed": "fast",
"pass": true,
"fail": false,
"pending": false,
"code": "expect(response.status).to.equal(200);",
"err": {},
"isRoot": false,
"uuid": "a329a8e2-75c7-43a0-a538-bb1a6296a725",
"isHook": false,
"skipped": false
},
{
"title": "Schema is valid",
"fullTitle": "Add permission over object message of the day to group administrators Schema is valid",
"timedOut": false,
"duration": 1,
"state": "passed",
"speed": "fast",
"pass": true,
"fail": false,
"pending": false,
"code": "expect(tv4.validate(body, schema2)).to.be.true;",
"err": {},
"isRoot": false,
"uuid": "7b2c270d-5aa0-423e-b48d-61ca475e1bd4",
"isHook": false,
"skipped": false
}
],
"suites": [],
"passes": [
"a329a8e2-75c7-43a0-a538-bb1a6296a725",
"7b2c270d-5aa0-423e-b48d-61ca475e1bd4"
],
"failures": [],
"pending": [],
"skipped": [],
"duration": 1,
"root": false,
"rootEmpty": false,
"_timeout": 200000
},
{
"uuid": "005ccfc5-f8f1-4d20-b715-1acbd90c32dc",
"title": "Querry what permissions user Alice has over object message of the day.",
"fullFile": "C:\\Users\\Zeko\\Documents\\ZeroToMastery\\testni_projekat\\permissions_api\\permissions_cloned\\test\\apitest.js",
"file": "\\test\\apitest.js",
"beforeHooks": [
{
"title": "\"before all\" hook",
"fullTitle": "Querry what permissions user Alice has over object message of the day. \"before all\" hook",
"timedOut": false,
"duration": 20,
"pass": false,
"fail": false,
"pending": false,
"code": "response = await call_api_query_perm(data);\nbody = response.body;",
"err": {},
"isRoot": false,
"uuid": "b3052841-f131-43cb-b5fc-1dc73f555abf",
"isHook": true,
"skipped": false
}
],
"afterHooks": [],
"tests": [
{
"title": "Status code is 200",
"fullTitle": "Querry what permissions user Alice has over object message of the day. Status code is 200",
"timedOut": false,
"duration": 1,
"state": "passed",
"speed": "fast",
"pass": true,
"fail": false,
"pending": false,
"code": "expect(response.status).to.equal(200);",
"err": {},
"isRoot": false,
"uuid": "a3ca2323-803b-451d-9186-dfd4e3dd01ae",
"isHook": false,
"skipped": false
}
],
"suites": [],
"passes": [
"a3ca2323-803b-451d-9186-dfd4e3dd01ae"
],
"failures": [],
"pending": [],
"skipped": [],
"duration": 1,
"root": false,
"rootEmpty": false,
"_timeout": 200000
},
{
"uuid": "1adf81ae-f1b7-417b-8af9-4c620360df6e",
"title": "Test if user Dan has permission modify over object message of the day.",
"fullFile": "C:\\Users\\Zeko\\Documents\\ZeroToMastery\\testni_projekat\\permissions_api\\permissions_cloned\\test\\apitest.js",
"file": "\\test\\apitest.js",
"beforeHooks": [
{
"title": "\"before all\" hook",
"fullTitle": "Test if user Dan has permission modify over object message of the day. \"before all\" hook",
"timedOut": false,
"duration": 19,
"pass": false,
"fail": false,
"pending": false,
"code": "response = await call_api_test_perm(data);\nbody = response.body;",
"err": {},
"isRoot": false,
"uuid": "9248f191-d251-4d6e-b4b3-90c19bc9d407",
"isHook": true,
"skipped": false
}
],
"afterHooks": [],
"tests": [
{
"title": "Status code is 200",
"fullTitle": "Test if user Dan has permission modify over object message of the day. Status code is 200",
"timedOut": false,
"duration": 0,
"state": "passed",
"speed": "fast",
"pass": true,
"fail": false,
"pending": false,
"code": "expect(response.status).to.equal(200);",
"err": {},
"isRoot": false,
"uuid": "591da05c-cf51-48f0-9ddc-d220ddf0eb1b",
"isHook": false,
"skipped": false
}
],
"suites": [],
"passes": [
"591da05c-cf51-48f0-9ddc-d220ddf0eb1b"
],
"failures": [],
"pending": [],
"skipped": [],
"duration": 0,
"root": false,
"rootEmpty": false,
"_timeout": 200000
}
],
"passes": [],
"failures": [],
"pending": [],
"skipped": [],
"duration": 0,
"root": true,
"rootEmpty": true,
"_timeout": 200000
},
"copyrightYear": 2019
}

746
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -5,8 +5,9 @@
"main": "permissions.js",
"scripts": {
"start": "nodemon permissions.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"test": "mocha test/apitest.js"
},
"author": "",
"license": "ISC",
"dependencies": {
@@ -15,7 +16,13 @@
"express": "^4.17.1",
"express-validator": "^6.2.0",
"knex": "^0.20.0",
"pg": "^7.12.1"
"pg": "^7.12.1",
"chai": "^4.1.2",
"chai-http": "4.2.1",
"mocha": "^5.2.0",
"mochawesome": "^3.0.2",
"supertest": "^3.1.0",
"tv4": "^1.3.0"
},
"devDependencies": {
"nodemon": "^1.19.4"

View File

@@ -68,3 +68,6 @@ app.post('/querypermiss', (req,res) => {
app.listen(3000, () => {
console.log(`App is running on port 3000`);
})
//For testing purpose
//module.exports = app;

184
test/apitest.js Normal file
View File

@@ -0,0 +1,184 @@
//TEST - Case from assignement. It is assumed that it is first to be run after database creation.
//Requirements for testing purpose
const supertest = require('supertest');
const expect = require('chai').expect;
const mocha = require('mocha');
const tv4 = require('tv4');
//Data for testing
const test1_data = [
{
"reqgroup": "administrators",
"requser": "Bob"
},
{
"reqgroup": "administrators",
"requser": "alice"
},
];
const test2_data = [
{
"reqowner": "dan",
"reqownertype": "user",
"reqobjname" : "message of the day",
"reqtype" : "view"
},
{
"reqowner": "administrators",
"reqownertype": "group",
"reqobjname" : "message of the day",
"reqtype" : "view"
},
{
"reqowner": "administrators",
"reqownertype": "group",
"reqobjname" : "message of the day",
"reqtype" : "modify"
}
];
const test3_data = [
{
"requser": "Alice",
"reqobject" : "message of the day"
}
];
const test4_data = [
{
"reqowner": "Dan",
"reqobjname": "message of the day",
"reqtype": "modify"
}
];
//Defining server location and endpoints - temporary running locally
const baseUrl = supertest("http://localhost:3000");
const apiEndAddUser = "/addusertogroup";
const apiEndAddPerm ="/addpermission";
const apiEndQueryPerm ="/querypermiss";
const apiEndTestPerm = "/testuserperm";
//Defining excpected response schemas
var schema1 = {
"id": {
"type": "integer"
},
"groupname": {
"type": "string"
},
"username": {
"type": "string"
}
}
var schema2 = {
"id": {
"type": "integer"
},
"ownertype": {
"type": "string"
},
"owner": {
"type": "string"
},
"objname": {
"type": "string"
}
}
//Seting up headers
const call_api_add_user = async function (request_body) {
return baseUrl.post(apiEndAddUser)
.set('Accept', 'application/json')
.set('Content-Type', 'application/json')
.send(request_body);
}
const call_api_add_perm = async function (request_body) {
return baseUrl.post(apiEndAddPerm)
.set('Accept', 'application/json')
.set('Content-Type', 'application/json')
.send(request_body);
}
const call_api_query_perm = async function (request_body) {
return baseUrl.post(apiEndQueryPerm)
.set('Accept', 'application/json')
.set('Content-Type', 'application/json')
.send(request_body);
}
const call_api_test_perm = async function (request_body) {
return baseUrl.post(apiEndTestPerm)
.set('Accept', 'application/json')
.set('Content-Type', 'application/json')
.send(request_body);
}
//Test 1 - adding user to group
test1_data.forEach(async function (data) {
describe(`Add user ${data.requser} to group ${data.reqgroup}`, function () {
var response;
var body;
before(async function () {
response = await call_api_add_user(data);
body = response.body;
});
//Status code is 200 - succesful
it("Status code is 200", function () {
expect(response.status).to.equal(200);
});
//Schema is valid
it("Schema is valid", function() {
expect(tv4.validate(body, schema1)).to.be.true;
});
});
});
//Test 2 - adding permission to user or group
test2_data.forEach(async function (data) {
describe(`Add permission over object ${data.reqobjname} to ${data.reqownertype} ${data.reqowner}`, function () {
var response;
var body;
before(async function () {
response = await call_api_add_perm(data);
body = response.body;
});
//Status code is 200 - succesful
it("Status code is 200", function () {
expect(response.status).to.equal(200);
});
//Schema is valid
it("Schema is valid", function() {
expect(tv4.validate(body, schema2)).to.be.true;
});
});
});
//Test 3 - querying permission of user over object
test3_data.forEach(async function (data) {
describe(`Querry what permissions user ${data.requser} has over object ${data.reqobject}.`, function () {
var response;
var body;
before(async function () {
response = await call_api_query_perm(data);
body = response.body;
});
//Status code is 200 - succesful
it("Status code is 200", function () {
expect(response.status).to.equal(200);
});
});
});
//Test 4 - testing particular permission of user over object
test4_data.forEach(async function (data) {
describe(`Test if user ${data.reqowner} has permission ${data.reqtype} over object ${data.reqobjname}.`, function () {
var response;
var body;
before(async function () {
response = await call_api_test_perm(data);
body = response.body;
});
//Status code is 200 - succesful
it("Status code is 200", function () {
expect(response.status).to.equal(200);
});
});
});

3
test/mocha.opts Normal file
View File

@@ -0,0 +1,3 @@
--timeout 200000
--recursive
--reporter mochawesome