From 576b50cf2a5bee51894762808e4a52cfff7f8980 Mon Sep 17 00:00:00 2001 From: IshwaryaSriram Date: Fri, 15 Nov 2024 01:28:25 +0530 Subject: [PATCH 1/2] test(routes): increase test coverage for API endpoints --- src/service/routes/push.js | 2 +- test/testAuthRoutes.test.js | 150 ++++++ test/testClearBareClone.test.js | 4 +- test/testLogin.test.js | 70 --- test/testPush.test.js | 53 -- test/testPushRoutes.test.js | 477 ++++++++++++++++++ ...epoTest.test.js => testRepoRoutes.test.js} | 196 ++++++- test/testRoutes.test.js | 69 +++ test/testUserCreation.test.js | 5 +- test/testUserRoute.test.js | 83 +++ 10 files changed, 956 insertions(+), 153 deletions(-) create mode 100644 test/testAuthRoutes.test.js delete mode 100644 test/testLogin.test.js delete mode 100644 test/testPush.test.js create mode 100644 test/testPushRoutes.test.js rename test/{addRepoTest.test.js => testRepoRoutes.test.js} (50%) create mode 100644 test/testRoutes.test.js create mode 100644 test/testUserRoute.test.js diff --git a/src/service/routes/push.js b/src/service/routes/push.js index 9750375ca..e9145defa 100644 --- a/src/service/routes/push.js +++ b/src/service/routes/push.js @@ -171,7 +171,7 @@ router.post('/:id/cancel', async (req, res) => { console.log(`user ${req.user.username} not authorised to cancel push request for ${id}`); res.status(401).send({ message: - 'User ${req.user.username)} not authorised to cancel push requests on this project.', + `User ${req.user.username} not authorised to cancel push requests on this project.`, }); } } else { diff --git a/test/testAuthRoutes.test.js b/test/testAuthRoutes.test.js new file mode 100644 index 000000000..611d269d6 --- /dev/null +++ b/test/testAuthRoutes.test.js @@ -0,0 +1,150 @@ +// Import the dependencies for testing +const chai = require('chai'); +const chaiHttp = require('chai-http'); +const db = require('../src/db'); +const service = require('../src/service'); + +chai.use(chaiHttp); +chai.should(); +const expect = chai.expect; + +describe('Test Auth Routes', async () => { + let app; + let cookie; + + before(async function () { + app = await service.start(); + await db.deleteUser('login-test-user'); + }); + + describe('test GET / method', async function () { + it('should return auth endpoints', async function () { + const res = await chai.request(app) + .get('/api/auth'); + + expect(res.status).to.be.equal(200); + expect(res.body).to.deep.equal({ + login: { + action: 'post', + uri: '/api/auth/login', + }, + profile: { + action: 'get', + uri: '/api/auth/profile', + }, + logout: { + action: 'post', + uri: '/api/auth/logout', + } + }); + }) + }); + + + + describe('test login / logout', async function () { + // Test to get all students record + it('should get 401 not logged in', async function () { + const res = await chai.request(app).get('/api/auth/profile'); + + res.should.have.status(401); + }); + + it('should be able to login', async function () { + const res = await chai.request(app).post('/api/auth/login').send({ + username: 'admin', + password: 'admin', + }); + + expect(res).to.have.cookie('connect.sid'); + res.should.have.status(200); + + // Get the connect cooie + res.headers['set-cookie'].forEach((x) => { + if (x.startsWith('connect')) { + cookie = x.split(';')[0]; + } + }); + }); + + it('should now return success', async function () { + const res = await chai.request(app).get('/api/auth/success').set('Cookie', `${cookie}`); + res.should.have.status(200); + }); + + it('should now be able to access the user login metadata', async function () { + const res = await chai.request(app).get('/api/auth/userLoggedIn').set('Cookie', `${cookie}`); + res.should.have.status(200); + }); + + it('should now be able to access the profile', async function () { + const res = await chai.request(app).get('/api/auth/profile').set('Cookie', `${cookie}`); + res.should.have.status(200); + }); + + it('should now be able to add git account to user', async function () { + const userAccount = { "username": "admin", "gitAccount": "test", "email": "test@test.com", "admin": true }; + + const res = await chai.request(app) + .post('/api/auth/gitAccount') + .set('Cookie', `${cookie}`) + .send({ + username: 'admin', + gitAccount: userAccount + }); + res.should.have.status(200); + }); + + it('should get error when user id/name is not sent in req.bosy', async function () { + const userAccount = { "username": "admin", "gitAccount": "test", "email": "test@test.com", "admin": true }; + + const res = await chai.request(app) + .post('/api/auth/gitAccount') + .set('Cookie', `${cookie}`) + .send({ + gitAccount: userAccount + }); + res.should.have.status(500); + }); + + + it('should now be able to logout', async function () { + const res = await chai.request(app).post('/api/auth/logout').set('Cookie', `${cookie}`); + res.should.have.status(200); + }); + + it('should not get login success', async function () { + const res = await chai.request(app).get('/api/auth/success').set('Cookie', `${cookie}`); + res.should.have.status(401); + }); + + it('should not be able to add git account without login', async function () { + const userAccount = { "username": "admin", "gitAccount": "test", "email": "test@test.com", "admin": true }; + + const res = await chai.request(app) + .post('/api/auth/gitAccount') + .set('Cookie', `${cookie}`) + .send({ + username: 'admin', + gitAccount: userAccount + }); + res.should.have.status(401); + }); + + it('test cannot access profile page', async function () { + const res = await chai.request(app).get('/api/auth/profile').set('Cookie', `${cookie}`); + + res.should.have.status(401); + }); + + it('test cannot get login status', async function () { + const res = await chai.request(app).get('/api/auth/userLoggedIn').set('Cookie', `${cookie}`); + + res.should.have.status(401); + }); + }); + + after(async function () { + await service.httpServer.close(); + }); +}); diff --git a/test/testClearBareClone.test.js b/test/testClearBareClone.test.js index c600610cd..f85a1456b 100644 --- a/test/testClearBareClone.test.js +++ b/test/testClearBareClone.test.js @@ -9,7 +9,9 @@ const expect = chai.expect; const timestamp = Date.now(); describe('clear bare and local clones', async () => { - it('pull remote generates a local .remote folder', async () => { + it('pull remote generates a local .remote folder', async function () { + // eslint-disable-next-line no-invalid-this + this.timeout(5000); const action = new Action('123', 'type', 'get', timestamp, 'finos/git-proxy'); action.url = 'https://github.com/finos/git-proxy'; await pullRemote({}, action); diff --git a/test/testLogin.test.js b/test/testLogin.test.js deleted file mode 100644 index 812e4f755..000000000 --- a/test/testLogin.test.js +++ /dev/null @@ -1,70 +0,0 @@ -// Import the dependencies for testing -const chai = require('chai'); -const chaiHttp = require('chai-http'); -const db = require('../src/db'); -const service = require('../src/service'); - -chai.use(chaiHttp); -chai.should(); -const expect = chai.expect; - -describe('auth', async () => { - let app; - let cookie; - - before(async function () { - app = await service.start(); - await db.deleteUser('login-test-user'); - }); - - describe('test login / logout', async function () { - // Test to get all students record - it('should get 401 not logged in', async function () { - const res = await chai.request(app).get('/api/auth/profile'); - - res.should.have.status(401); - }); - - it('should be able to login', async function () { - const res = await chai.request(app).post('/api/auth/login').send({ - username: 'admin', - password: 'admin', - }); - - expect(res).to.have.cookie('connect.sid'); - res.should.have.status(200); - - // Get the connect cooie - res.headers['set-cookie'].forEach((x) => { - if (x.startsWith('connect')) { - cookie = x.split(';')[0]; - } - }); - }); - - it('should now be able to access the user login metadata', async function () { - const res = await chai.request(app).get('/api/auth/userLoggedIn').set('Cookie', `${cookie}`); - res.should.have.status(200); - }); - - it('should now be able to access the profile', async function () { - const res = await chai.request(app).get('/api/auth/profile').set('Cookie', `${cookie}`); - res.should.have.status(200); - }); - - it('should now be able to logout', async function () { - const res = await chai.request(app).post('/api/auth/logout').set('Cookie', `${cookie}`); - res.should.have.status(200); - }); - - it('test cannot access profile page', async function () { - const res = await chai.request(app).get('/api/auth/profile').set('Cookie', `${cookie}`); - - res.should.have.status(401); - }); - }); - - after(async function () { - await service.httpServer.close(); - }); -}); diff --git a/test/testPush.test.js b/test/testPush.test.js deleted file mode 100644 index f4e09a4a5..000000000 --- a/test/testPush.test.js +++ /dev/null @@ -1,53 +0,0 @@ -// Import the dependencies for testing -const chai = require('chai'); -const chaiHttp = require('chai-http'); -const db = require('../src/db'); -const service = require('../src/service'); - -chai.use(chaiHttp); -chai.should(); -const expect = chai.expect; - -describe('auth', async () => { - let app; - let cookie; - - before(async function () { - app = await service.start(); - await db.deleteUser('login-test-user'); - - const res = await chai.request(app).post('/api/auth/login').send({ - username: 'admin', - password: 'admin', - }); - - expect(res).to.have.cookie('connect.sid'); - res.should.have.status(200); - - // Get the connect cooie - res.headers['set-cookie'].forEach((x) => { - if (x.startsWith('connect')) { - cookie = x.split(';')[0]; - } - }); - }); - - describe('test push API', async function () { - it('should get 404 for unknown push', async function () { - const commitId = - '0000000000000000000000000000000000000000__79b4d8953cbc324bcc1eb53d6412ff89666c241f'; // eslint-disable-line max-len - const res = await chai - .request(app) - .get(`/api/v1/push/${commitId}`) - .set('Cookie', `${cookie}`); - res.should.have.status(404); - }); - }); - - after(async function () { - const res = await chai.request(app).post('/api/auth/logout').set('Cookie', `${cookie}`); - res.should.have.status(200); - - await service.httpServer.close(); - }); -}); diff --git a/test/testPushRoutes.test.js b/test/testPushRoutes.test.js new file mode 100644 index 000000000..ea0cd0487 --- /dev/null +++ b/test/testPushRoutes.test.js @@ -0,0 +1,477 @@ +// Import the dependencies for testing +const chai = require('chai'); +const chaiHttp = require('chai-http'); +const db = require('../src/db'); +const service = require('../src/service'); +const sinon = require('sinon'); + +chai.use(chaiHttp); +chai.should(); +const expect = chai.expect; + +describe('Push Routes Test with Admin Login', async () => { + let app; + let cookie; + const commitId = + '0000000000000000000000000000000000000000__79b4d8953cbc324bcc1eb53d6412ff89666c241f'; + const mockPush = { id: commitId, message: 'Test Push', user: 'testUser' }; + const commitId2 = + '0000000000000000000000000000000000000000__63b4d8953cbc324bcc1eb53d6412ff89666c241f'; // eslint-disable-line max-len + const mockPush2 = { id: commitId, message: 'Test Push', user: 'testUser2' }; + + before(async function () { + app = await service.start(); + + const res = await chai.request(app).post('/api/auth/login').send({ + username: 'admin', + password: 'admin', + }); + + expect(res).to.have.cookie('connect.sid'); + res.should.have.status(200); + + // Get the connect cooie + res.headers['set-cookie'].forEach((x) => { + if (x.startsWith('connect')) { + cookie = x.split(';')[0]; + } + }); + }); + + describe('test GET API', async function () { + it('should return pushes for /', async function () { + + const response = await chai + .request(app) + .get('/api/v1/push') + .set('Cookie', `${cookie}`); + response.should.have.status(200); + + }) + }) + + describe('test GET API with query params', async function () { + it('should ignore "limit" and "skip" query params', async () => { + const getPushStub = sinon.stub(db, 'getPush').resolves(); + + const res = await chai.request(app) + .get('/api/v1/push/') + .query({ limit: 5, skip: 10, admin: false }); + + expect(res).to.have.status(200); + expect(getPushStub.calledWith({})); + }); + }); + + describe('test push API', async function () { + it('should get 404 for unknown push', async function () { + const res = await chai + .request(app) + .get(`/api/v1/push/${commitId}`) + .set('Cookie', `${cookie}`); + res.should.have.status(404); + }); + }); + + describe('test push API', async function () { + it('should get push object if found', async function () { + sinon.stub(db, 'getPush').resolves(mockPush); + + const res = await chai + .request(app) + .get(`/api/v1/push/${commitId}`) + .set('Cookie', `${cookie}`); + res.should.have.status(200); + }); + }); + + describe('test reject POST API with req user set', async function () { + it('should respond with status 401 for invalid git account', async function () { + + sinon.stub(db, 'getPush').resolves(mockPush); + + const mockUsers = []; + sinon.stub(db, 'getUsers').resolves(mockUsers); + const response = await chai + .request(app) + .post(`/api/v1/push/${commitId}/reject`) + .set('Cookie', `${cookie}`); + response.should.have.status(401); + + expect(response.body).to.have.property('message', 'The git account testUser could not be found'); + + }) + }) + + describe('test reject POST API', async function () { + it('should respond with status 200 for rejecting push', async function () { + sinon.stub(db, 'getPush').resolves(mockPush); + + const mockUsers = [{ username: 'testUser' }]; + sinon.stub(db, 'getUsers').resolves(mockUsers); + + sinon.stub(db, 'canUserApproveRejectPush').resolves(true); + + const mockRejectRespone = { message: `reject ${commitId}` }; + sinon.stub(db, 'reject').resolves(mockRejectRespone); + + const response = await chai + .request(app) + .post(`/api/v1/push/${commitId}/reject`) + .set('Cookie', `${cookie}`); + + response.should.have.status(200); + }) + }) + + describe('test reject POST API without login', async function () { + it('should respond with status 401 for unauthorized reject', async function () { + + const response = await chai + .request(app) + .post(`/api/v1/push/${commitId}/reject`); + + // console.log(response); + response.should.have.status(401); + expect(response.body).to.have.property('message', 'not logged in'); + + }) + }) + + describe('test authorize POST API without attestation', async function () { + it('should return status 401 for unauthorized approver', async function () { + sinon.stub(db, 'getPush').resolves(mockPush); + + const mockUsers = []; + sinon.stub(db, 'getUsers').resolves(mockUsers); + const response = await chai + .request(app) + .post(`/api/v1/push/${commitId}/authorise`) + .send({ + params: { + attestation: [ + { + label: 'Authorising via GitProxy', + checked: false, + }, + ], + } + }) + .set('Cookie', `${cookie}`); + response.should.have.status(401); + + expect(response.body).to.have.property('message', 'You are unauthorized to perform this action...'); + + }) + }) + + describe('test authorize POST API', async function () { + it('should return status 401 for invalid account', async function () { + sinon.stub(db, 'getPush').resolves(mockPush); + + const mockUsers = []; + sinon.stub(db, 'getUsers').resolves(mockUsers); + const response = await chai + .request(app) + .post(`/api/v1/push/${commitId}/authorise`) + .send({ + params: { + attestation: [ + { + label: 'Authorising via GitProxy', + checked: true, + }, + ], + } + }) + .set('Cookie', `${cookie}`); + response.should.have.status(401); + + expect(response.body).to.have.property('message', 'The git account testUser could not be found'); + + }) + }) + + describe('test authorize POST API for approval without github account', async function () { + it('should return status 401 for authorising push without assosciating github account', async function () { + + sinon.stub(db, 'getPush').resolves(mockPush2); + + const mockUsers = [{ username: 'testUser2' }]; + sinon.stub(db, 'getUsers') + .onFirstCall().resolves(mockUsers) + .onSecondCall().resolves([{ username: 'admin' }]); + sinon.stub(db, 'canUserApproveRejectPush').resolves(true); + + + const response = await chai + .request(app) + .post(`/api/v1/push/${commitId2}/authorise`) + .send({ + params: { + attestation: [ + { + label: 'Authorising via GitProxy', + checked: true, + }, + ], + } + }) + .set('Cookie', `${cookie}`); + response.should.have.status(401); + + expect(response.body).to.have.property('message', 'You must associate a GitHub account with your user before approving...'); + + }) + }) + + describe('test authorize POST API for approval ', async function () { + it('should return status 200 for authorising push', async function () { + + sinon.stub(db, 'getPush').resolves(mockPush2); + + const mockUsers = [{ username: 'testUser2' }]; + sinon.stub(db, 'getUsers') + .onFirstCall().resolves(mockUsers) + .onSecondCall().resolves([{ username: 'admin', gitAccount: 'adminAccount' }]); + sinon.stub(db, 'canUserApproveRejectPush').resolves(true); + sinon.stub(db, 'authorise').resolves(`authorised ${commitId}`); + + + const response = await chai + .request(app) + .post(`/api/v1/push/${commitId2}/authorise`) + .send({ + params: { + attestation: [ + { + label: 'Authorising via GitProxy', + checked: true, + }, + ], + } + }) + .set('Cookie', `${cookie}`); + response.should.have.status(200); + + }) + }) + + describe('test cancel request POST API', async function () { + // eslint-disable-next-line no-invalid-this + this.timeout(5000); + it('should return status 200 when admin cancel push ', async function () { + sinon.stub(db, 'canUserCancelPush').resolves(true); + sinon.stub(db, 'cancel').resolves(`canceled ${commitId}`); + + const response = await chai + .request(app) + .post(`/api/v1/push/${commitId}/cancel`) + .set('Cookie', `${cookie}`); + + response.should.have.status(200); + }) + + }) + + after(async function () { + const res = await chai.request(app).post('/api/auth/logout').set('Cookie', `${cookie}`); + res.should.have.status(200); + + cookie = null; + await service.httpServer.close(); + }); + + afterEach(() => { + sinon.restore(); + }) +}); + +describe('Push Routes Test with TestUser Login', async () => { + + let testUserApp; + let cookie; + + const commitId = + '0000000000000000000000000000000000000000__79b4d8953cbc324bcc1eb53d6412ff89666c241f'; // eslint-disable-line max-len + const mockPush = { id: commitId, message: 'Test Push', user: 'testUser' }; + + const commitId2 = + '0000000000000000000000000000000000000000__63b4d8953cbc324bcc1eb53d6412ff89666c241f'; // eslint-disable-line max-len + const mockPush2 = { id: commitId, message: 'Test Push', user: 'testUser2' }; + + before(async function () { + + const testUserPassword = 'password123'; + const testUser = 'testUser'; + const testEmail = 'test@test.com'; + const testGitAccount = 'testUserAccount'; + + await db.deleteUser(testUser); + await db.createUser(testUser, testUserPassword, testEmail, testGitAccount); + + testUserApp = await service.start(); + const res = await chai.request(testUserApp).post('/api/auth/login').send({ + username: 'testUser', + password: 'password123', + }); + + expect(res).to.have.cookie('connect.sid'); + res.should.have.status(200); + + res.headers['set-cookie'].forEach((x) => { + if (x.startsWith('connect')) { + cookie = x.split(';')[0]; + } + }); + + + + }); + + describe('test reject POST API for own change', async function () { + it('should respond with status 401 for rejecting own push', async function () { + sinon.stub(db, 'getPush').resolves(mockPush); + + const mockUsers = [{ username: 'testUser' }]; + sinon.stub(db, 'getUsers').resolves(mockUsers); + const response = await chai + .request(testUserApp) + .post(`/api/v1/push/${commitId}/reject`) + .set('Cookie', `${cookie}`); + + response.should.have.status(401); + expect(response.body).to.have.property('message', 'Cannot reject your own changes'); + + + }) + }) + + describe('test reject POST API for unauthorised reject user', async function () { + it('should respond with status 401 for trying to reject without authorisation', async function () { + + + sinon.stub(db, 'getPush').resolves(mockPush2); + + const mockUsers = [{ username: 'testUser2' }]; + sinon.stub(db, 'getUsers').resolves(mockUsers); + + const mockIsAllowed = false; + sinon.stub(db, 'canUserApproveRejectPush').resolves(mockIsAllowed); + + const response = await chai + .request(testUserApp) + .post(`/api/v1/push/${commitId2}/reject`) + .set('Cookie', `${cookie}`); + + response.should.have.status(401); + expect(response.body).to.have.property('message', 'User is not authorised to reject changes'); + + + }) + }) + + describe('test authorize POST API for own change', async function () { + it('should return status 401 for approving own changes', async function () { + sinon.stub(db, 'getPush').resolves(mockPush); + + const mockUsers = [{ username: 'testUser' }]; + sinon.stub(db, 'getUsers').resolves(mockUsers); + const response = await chai + .request(testUserApp) + .post(`/api/v1/push/${commitId}/authorise`) + .send({ + params: { + attestation: [ + { + label: 'Authorising via GitProxy', + checked: true, + }, + ], + } + }) + .set('Cookie', `${cookie}`); + response.should.have.status(401); + + expect(response.body).to.have.property('message', 'Cannot approve your own changes'); + + }) + }) + + describe('test authorize POST API for unauthorized approval on project', async function () { + it('should return status 401 for authorising push without access to approve', async function () { + sinon.stub(db, 'getPush').resolves(mockPush2); + + const mockUsers = [{ username: 'testUser2' }]; + sinon.stub(db, 'getUsers').resolves(mockUsers); + sinon.stub(db, 'canUserApproveRejectPush').resolves(false); + + const response = await chai + .request(testUserApp) + .post(`/api/v1/push/${commitId2}/authorise`) + .send({ + params: { + attestation: [ + { + label: 'Authorising via GitProxy', + checked: true, + }, + ], + } + }) + .set('Cookie', `${cookie}`); + response.should.have.status(401); + + expect(response.body).to.have.property('message', 'user testUser not authorised to approve push\'s on this project'); + + }) + }) + + describe('test cancel request POST API', async function () { + // eslint-disable-next-line no-invalid-this + this.timeout(5000); + it('should return status 401 when user is not logged in to cancel push ', async function () { + + const response = await chai + .request(testUserApp) + .post(`/api/v1/push/${commitId}/cancel`); + + response.should.have.status(401); + expect(response.body).to.have.property('message', 'not logged in'); + + }) + + }) + + describe('test cancel request POST API', async function () { + // eslint-disable-next-line no-invalid-this + this.timeout(5000); + it('should return status 401 when user is not authorized to cancel push ', async function () { + sinon.stub(db, 'canUserCancelPush').resolves(false); + + const response = await chai + .request(testUserApp) + .post(`/api/v1/push/${commitId}/cancel`) + .set('Cookie', `${cookie}`); + + response.should.have.status(401); + expect(response.body).to.have.property('message', 'User testUser not authorised to cancel push requests on this project.'); + + }) + + }); + + after(async function () { + await chai.request(testUserApp).post('/api/auth/logout').set('Cookie', `${cookie}`); + + cookie = null; + await service.httpServer.close(); + + sinon.restore(); + }) + + afterEach(async function () { + sinon.restore(); + }) + +}); \ No newline at end of file diff --git a/test/addRepoTest.test.js b/test/testRepoRoutes.test.js similarity index 50% rename from test/addRepoTest.test.js rename to test/testRepoRoutes.test.js index 04983f63c..3b03b9c0f 100644 --- a/test/addRepoTest.test.js +++ b/test/testRepoRoutes.test.js @@ -3,12 +3,13 @@ const chai = require('chai'); const chaiHttp = require('chai-http'); const db = require('../src/db'); const service = require('../src/service'); +const sinon = require('sinon'); chai.use(chaiHttp); chai.should(); const expect = chai.expect; -describe('add new repo', async () => { +describe('Test Repo routes with admin credentials', async () => { let app; let cookie; @@ -21,6 +22,7 @@ describe('add new repo', async () => { }); }; + before(async function () { app = await service.start(); // Prepare the data. @@ -29,9 +31,7 @@ describe('add new repo', async () => { await db.deleteUser('u2'); await db.createUser('u1', 'abc', 'test@test.com', 'test', true); await db.createUser('u2', 'abc', 'test@test.com', 'test', true); - }); - it('login', async function () { const res = await chai.request(app).post('/api/auth/login').send({ username: 'admin', password: 'admin', @@ -40,6 +40,18 @@ describe('add new repo', async () => { setCookie(res); }); + it('should ignore "limit" and "skip" query params for GET /', async () => { + const getRepoStub = sinon.stub(db, 'getRepos').resolves([]); + + const res = await chai.request(app) + .get('/api/v1/repo/') + .query({ limit: 5, skip: 10, admin: false }); + + expect(res).to.have.status(200); + expect(getRepoStub.calledWith({})); + }); + + it('create a new repo', async function () { const res = await chai.request(app).post('/api/v1/repo').set('Cookie', `${cookie}`).send({ project: 'finos', @@ -56,6 +68,39 @@ describe('add new repo', async () => { repo.users.canAuthorise.length.should.equal(0); }); + it('create a new repo without authorisation', async function () { + const res = await chai.request(app).post('/api/v1/repo') + .send({ + project: 'finos', + name: 'test-repo', + url: 'https://github.com/finos/test-repo.git', + }); + res.should.have.status(401); + }); + + it('create a duplciate repo', async function () { + sinon.stub(db, 'getRepo').resolves([{ name: 'test-repo' }]); + const res = await chai.request(app).post('/api/v1/repo').set('Cookie', `${cookie}`).send({ + project: 'finos', + name: 'test-repo', + url: 'https://github.com/finos/test-repo.git', + }); + res.should.have.status(409); + + sinon.restore(); + }); + + describe('test GET API to get repo by name', async function () { + it('should return status 200 with repo information', async function () { + const response = await chai + .request(app) + .get(`/api/v1/repo/test-repo`); + + response.should.have.status(200); + + }) + }); + it('add 1st can push user', async function () { const res = await chai .request(app) @@ -68,22 +113,18 @@ describe('add new repo', async () => { res.should.have.status(200); const repo = await db.getRepo('test-repo'); repo.users.canPush.length.should.equal(1); - repo.users.canPush[0].should.equal('u1'); + }); - it('add 2nd can push user', async function () { + it('add 2nd can push user without authorization', async function () { const res = await chai .request(app) .patch('/api/v1/repo/test-repo/user/push') - .set('Cookie', `${cookie}`) .send({ username: 'u2', }); - res.should.have.status(200); - const repo = await db.getRepo('test-repo'); - repo.users.canPush.length.should.equal(2); - repo.users.canPush[1].should.equal('u2'); + res.should.have.status(401); }); it('add push user that does not exist', async function () { @@ -97,19 +138,41 @@ describe('add new repo', async () => { res.should.have.status(400); const repo = await db.getRepo('test-repo'); - repo.users.canPush.length.should.equal(2); + repo.users.canPush.length.should.equal(1); }); - it('delete user u2 from push', async function () { + it('delete user u1 from push', async function () { const res = await chai .request(app) - .delete('/api/v1/repo/test-repo/user/push/u2') + .delete('/api/v1/repo/test-repo/user/push/u1') .set('Cookie', `${cookie}`) .send({}); res.should.have.status(200); const repo = await db.getRepo('test-repo'); - repo.users.canPush.length.should.equal(1); + repo.users.canPush.length.should.equal(0); + repo.users.canAuthorise.length.should.equal(0); + }); + + it('delete user u2 from push without authorization', async function () { + const res = await chai + .request(app) + .delete('/api/v1/repo/test-repo/user/push/u2') + .send({}); + + res.should.have.status(401); + + }); + + it('delete user that does not exist from push', async function () { + const res = await chai + .request(app) + .delete('/api/v1/repo/test-repo/user/push/u3') + .set('Cookie', `${cookie}`) + .send({}); + + res.should.have.status(400); + }); it('add 1st can authorise user', async function () { @@ -124,22 +187,19 @@ describe('add new repo', async () => { res.should.have.status(200); const repo = await db.getRepo('test-repo'); repo.users.canAuthorise.length.should.equal(1); - repo.users.canAuthorise[0].should.equal('u1'); }); - it('add 2nd can authorise user', async function () { + it('add 2nd can authorise user without authorization', async function () { const res = await chai .request(app) .patch('/api/v1/repo/test-repo/user/authorise') - .set('Cookie', `${cookie}`) .send({ username: 'u2', }); - res.should.have.status(200); - const repo = await db.getRepo('test-repo'); - repo.users.canAuthorise.length.should.equal(2); - repo.users.canAuthorise[1].should.equal('u2'); + res.should.have.status(401); + + }); it('add authorise user that does not exist', async function () { @@ -153,19 +213,43 @@ describe('add new repo', async () => { res.should.have.status(400); const repo = await db.getRepo('test-repo'); - repo.users.canAuthorise.length.should.equal(2); + repo.users.canAuthorise.length.should.equal(1); }); - it('Can delete u2 user', async function () { + it('Can delete u1 user', async function () { const res = await chai .request(app) - .delete('/api/v1/repo/test-repo/user/authorise/u2') + .delete('/api/v1/repo/test-repo/user/authorise/u1') .set('Cookie', `${cookie}`) .send({}); res.should.have.status(200); const repo = await db.getRepo('test-repo'); - repo.users.canAuthorise.length.should.equal(1); + repo.users.canPush.length.should.equal(0); + repo.users.canAuthorise.length.should.equal(0); + }); + + it('should return 400 for deleting user authorization for user that doesnt exist', async function () { + const res = await chai + .request(app) + .delete('/api/v1/repo/test-repo/user/authorise/u3') + .set('Cookie', `${cookie}`) + .send({}); + + res.should.have.status(400); + const repo = await db.getRepo('test-repo'); + repo.users.canAuthorise.length.should.equal(0); + }); + + it('should return 401 for deleting user authorization for user without authorization', async function () { + const res = await chai + .request(app) + .delete('/api/v1/repo/test-repo/user/authorise/u3') + .send({}); + + res.should.have.status(401); + const repo = await db.getRepo('test-repo'); + repo.users.canAuthorise.length.should.equal(0); }); it('Valid user push permission on repo', async function () { @@ -185,7 +269,69 @@ describe('add new repo', async () => { expect(isAllowed).to.be.false; }); + it('Delete repo with authorisation', async function () { + const res = await chai + .request(app) + .delete('/api/v1/repo/test-repo/delete') + .set('Cookie', `${cookie}`); + + res.should.have.status(200); + }); + after(async function () { + await chai.request(app).post('/api/auth/logout').set('Cookie', `${cookie}`); + cookie = null; await service.httpServer.close(); }); }); + + +describe('Test delete repo without admin credentials', async function () { + let testUserApp; + let cookie; + + before(async function () { + + const testUserPassword = 'password123'; + const testUser = 'testUser'; + const testEmail = 'test@test.com'; + const testGitAccount = 'testUserAccount'; + + await db.deleteUser(testUser); + await db.createUser(testUser, testUserPassword, testEmail, testGitAccount); + + testUserApp = await service.start(); + const res = await chai.request(testUserApp).post('/api/auth/login').send({ + username: 'testUser', + password: 'password123', + }); + + expect(res).to.have.cookie('connect.sid'); + res.should.have.status(200); + + res.headers['set-cookie'].forEach((x) => { + if (x.startsWith('connect')) { + cookie = x.split(';')[0]; + } + }); + + + + }); + it('Delete repo with authorisation', async function () { + const res = await chai + .request(testUserApp) + .delete('/api/v1/repo/test-repo/delete') + .set('Cookie', `${cookie}`); + + + res.should.have.status(401); + }); + + after(async function () { + await chai.request(testUserApp).post('/api/auth/logout').set('Cookie', `${cookie}`); + cookie = null; + await service.httpServer.close(); + + }) +}); diff --git a/test/testRoutes.test.js b/test/testRoutes.test.js new file mode 100644 index 000000000..3968f9900 --- /dev/null +++ b/test/testRoutes.test.js @@ -0,0 +1,69 @@ +const chai = require('chai'); +const chaiHttp = require('chai-http'); +const config = require('../src/config'); +const service = require('../src/service'); +const sinon = require('sinon'); + +chai.use(chaiHttp); +chai.should(); +const expect = chai.expect; + +describe('Test home routes', async () => { + let app; + + before(async function () { + app = await service.start(); + + }); + + + it('should return API endpoints when GET /', async function () { + const res = await chai.request(app).get('/api'); + + expect(res.status).to.equal(200); + expect(res.body).to.deep.equal({ + healthcheck: '/api/v1/healthcheck', + push: '/api/v1/push', + auth: '/api/auth', + }); + }); + + it('should return OK health check', async function () { + const res = await chai.request(app).get('/api/v1/healthcheck'); + + expect(res.status).to.equal(200); + expect(res.body).to.deep.equal({ + message: 'ok', + }); + }); + + it('should call attestation config', async function () { + const stub = sinon.stub(config, 'getAttestationConfig').resolves(); + const res = await chai.request(app).get('/api/v1/config/attestation'); + + expect(res.status).to.equal(200); + expect(stub.calledOnce).to.be.true; + }); + + it('should call contactEmail config', async function () { + const stub = sinon.stub(config, 'getContactEmail').resolves(); + const res = await chai.request(app).get('/api/v1/config/contactEmail'); + + expect(res.status).to.equal(200); + expect(stub.calledOnce).to.be.true; + }); + + it('should call urlShortener config', async function () { + const stub = sinon.stub(config, 'getURLShortener').resolves(); + const res = await chai.request(app).get('/api/v1/config/urlShortener'); + + expect(res.status).to.equal(200); + expect(stub.calledOnce).to.be.true; + }); + + after(async function () { + await service.httpServer.close(); + sinon.restore(); + }); + +}); diff --git a/test/testUserCreation.test.js b/test/testUserCreation.test.js index c07dd0e7b..44fa00639 100644 --- a/test/testUserCreation.test.js +++ b/test/testUserCreation.test.js @@ -8,7 +8,6 @@ const service = require('../src/service'); chai.use(chaiHttp); chai.should(); const expect = chai.expect; -const should = chai.should(); describe('user creation', async () => { let app; @@ -39,7 +38,7 @@ describe('user creation', async () => { setCookie(res); }); - it('should be able to create a new user', async function () { + it.skip('should be able to create a new user', async function () { const res = await chai.request(app).post('/api/auth/profile').set('Cookie', `${cookie}`).send({ username: 'login-test-user', email: 'paul.timothy.groves@gmail.com', @@ -47,7 +46,7 @@ describe('user creation', async () => { admin: true, }); res.should.have.status(200); - }).skip(); + }); it('logout', async function () { const res = await chai.request(app).post('/api/auth/logout').set('Cookie', `${cookie}`); diff --git a/test/testUserRoute.test.js b/test/testUserRoute.test.js new file mode 100644 index 000000000..e9739264a --- /dev/null +++ b/test/testUserRoute.test.js @@ -0,0 +1,83 @@ +// Import the dependencies for testing +const chai = require('chai'); +const chaiHttp = require('chai-http'); +const db = require('../src/db'); +const service = require('../src/service'); +const sinon = require('sinon'); + +chai.use(chaiHttp); +chai.should(); +const expect = chai.expect; + +describe('User Routes Test', async () => { + let app; + + const testUser = { + username: 'testUser', + password: 'password123', + email: 'test@test.com', + gitAccount: 'testGitAccount' + } + + beforeEach(async function () { + app = await service.start(); + await db.deleteUser(testUser.username); + + await db.createUser(testUser.username, testUser.password, testUser.email, testUser.gitAccount); + }); + + describe('test user API for retrieving user', async function () { + it('should fetch users without any query params', async () => { + sinon.stub(db, 'getUsers').resolves([testUser]); + + const res = await chai.request(app) + .get('/api/v1/user/'); + + expect(res).to.have.status(200); + + }); + }); + + describe('test user API for retrieving user with query params', async function () { + it('should ignore "limit" and "skip" query params', async () => { + const getUsersStub = sinon.stub(db, 'getUsers').resolves([testUser]); + + const res = await chai.request(app) + .get('/api/v1/user/') + .query({ limit: 5, skip: 10, admin: false }); + + expect(res).to.have.status(200); + expect(getUsersStub.calledWith({})); + }); + }); + + describe('test user API for retrieving user with query params', async function () { + it('should convert "true" and "false" strings to boolean values', async () => { + sinon.stub(db, 'getUsers').resolves([testUser]); + + const res = await chai.request(app) + .get('/api/v1/user/') + .query({ withCredentials: true }); + + expect(res).to.have.status(200); + + }); + }); + + describe('test user API for retrieving user by ID', async function () { + it('should return 200 for user existing in the database', async function () { + + sinon.stub(db, 'findUser').resolves(testUser); + + const res = await chai + .request(app) + .get(`/api/v1/user/${testUser.username}`); + res.should.have.status(200); + }); + }); + + afterEach(async function () { + await service.httpServer.close(); + sinon.restore(); + }); +}); From c18deb17e3b8e83dfa830bee5bed37d3e3082e40 Mon Sep 17 00:00:00 2001 From: IshwaryaSriram Date: Fri, 15 Nov 2024 01:30:46 +0530 Subject: [PATCH 2/2] test(routes): add assertion for pre-commit check --- test/testUserCreation.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/testUserCreation.test.js b/test/testUserCreation.test.js index 44fa00639..1e7d74577 100644 --- a/test/testUserCreation.test.js +++ b/test/testUserCreation.test.js @@ -8,6 +8,7 @@ const service = require('../src/service'); chai.use(chaiHttp); chai.should(); const expect = chai.expect; +const should = chai.should(); describe('user creation', async () => { let app;