Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: increased test coverage for push action #805

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/proxy/processors/push-action/checkAuthorEmails.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,19 @@ const config = require('../../../config');
const commitConfig = config.getCommitConfig();

function isEmailAllowed(email) {
if (!email) {
console.log('Invalid email address...');
return false; // If the email is null, undefined, or an empty string, return false
}

const [emailLocal, emailDomain] = email.split('@');

// Check if split was successful
if (!emailLocal || !emailDomain) {
console.log('Invalid email format (missing local or domain part)...');
return false; // If either part is missing, return false
}

console.log({ emailLocal, emailDomain });

// E-mail address is not a permissible domain name
Expand Down
2 changes: 1 addition & 1 deletion src/service/routes/push.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
100 changes: 100 additions & 0 deletions test/checkGetDiff.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
const { expect } = require('chai');
const sinon = require('sinon');
const child = require('child_process');
const { exec } = require('../src/proxy/processors/push-action/getDiff');
const { Step } = require('../src/proxy/actions');

describe('getDiff.exec', () => {
let req;
let action;
let spawnSyncStub;

beforeEach(() => {
req = {}
action = {
proxyGitPath: '/path/to/git',
repoName: 'my-repo',
commitFrom: 'commit-from',
commitTo: 'commit-to',
commitData: [{ parent: 'parent-commit' }],
addStep: sinon.stub(),
};
spawnSyncStub = sinon.stub(child, 'spawnSync').returns({ stdout: 'diff content' });
});

afterEach(() => {
sinon.restore();
});

it('should execute git diff command and set the content', async () => {
const expectedContent = 'diff content';

await exec(req, action);

expect(
spawnSyncStub.calledOnceWithExactly(
'git',
['diff', 'commit-from', 'commit-to'],
{
cwd: '/path/to/git/my-repo',
encoding: 'utf-8',
maxBuffer: 50 * 1024 * 1024,
}
)
).to.be.true;

expect(action.addStep.calledOnce).to.be.true;
const step = action.addStep.getCall(0).args[0];
expect(step).to.be.instanceOf(Step);
expect(step.content).to.equal(expectedContent);
});

it('should handle error and set the error message', async () => {
const errorMessage = 'some error';
spawnSyncStub.throws(new Error(errorMessage));

await exec(req, action);

expect(action.addStep.calledOnce).to.be.true;
const step = action.addStep.getCall(0).args[0];
expect(step).to.be.instanceOf(Step);
});

it('should handle commitFrom as all zeros and set the correct commitFrom', async () => {
action.commitFrom = '0000000000000000000000000000000000000000';
action.commitData = [{ parent: 'parent-commit' }];

await exec(req, action);

expect(
spawnSyncStub.calledOnceWithExactly(
'git',
['diff', 'parent-commit', 'commit-to'],
{
cwd: '/path/to/git/my-repo',
encoding: 'utf-8',
maxBuffer: 50 * 1024 * 1024,
}
)
).to.be.true;
});

it('should handle commitFrom as all zeros and no parent commit', async () => {
action.commitFrom = '0000000000000000000000000000000000000000';
action.commitData = [{ parent: '0000000000000000000000000000000000000000' }];

await exec(req, action);

expect(
spawnSyncStub.calledOnceWithExactly(
'git',
['diff', '4b825dc642cb6eb9a060e54bf8d69288fbee4904', 'commit-to'],
{
cwd: '/path/to/git/my-repo',
encoding: 'utf-8',
maxBuffer: 50 * 1024 * 1024,
}
)
).to.be.true;
});
});
252 changes: 252 additions & 0 deletions test/push.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
const chai = require('chai');
const chaiHttp = require('chai-http');
const sinon = require('sinon');
const db = require('../src/db');
const service = require('../src/service');

chai.use(chaiHttp);
chai.should();
const { expect } = chai;

describe('Push Routes', function () {
let app;
let cookie;

before(async function () {
// Start the service and clean up test data
app = await service.start();
await db.deleteUser('login-test-user');

// Login to get session cookie
const res = await chai.request(app).post('/api/auth/login').send({
username: 'admin',
password: 'admin',
});

expect(res).to.have.cookie('connect.sid');
cookie = res.headers['set-cookie'].find((x) => x.startsWith('connect.sid'));
expect(res.status).to.equal(200);

// Get the connect cookie
res.headers['set-cookie'].forEach((x) => {
if (x.startsWith('connect')) {
cookie = x.split(";")[0];
}
});
})

after(async function () {
// Logout and stop the service
const res = await chai.request(app).post('/api/auth/logout').set('Cookie', `${cookie}`);
res.should.have.status(200);
await service.httpServer.close();
});

afterEach(function () {
sinon.restore(); // Restore stubs after each test
});

describe('GET /push', function () {
it('should return pushes with query parameters', async function () {
sinon.stub(db, 'getPushes').resolves([{ id: 1, type: 'push' }]);

const res = await chai
.request(app)
.get('/api/v1/push')
.query({ limit: 10, skip: 0, active: 'true' });

expect(res.status).to.equal(200);
expect(res.body).to.deep.equal([{ id: 1, type: 'push' }]);
});
});

describe('GET /push/:id', function () {
it('should return a push by ID', async function () {
sinon.stub(db, 'getPush').resolves({ id: 1, type: 'push' });

const res = await chai.request(app).get('/api/v1/push/1');

expect(res.status).to.equal(200);
expect(res.body).to.deep.equal({ id: 1, type: 'push' });
});

it('should return 404 if push not found', async function () {
sinon.stub(db, 'getPush').resolves(null);

const res = await chai.request(app).get('/api/v1/push/1');

expect(res.status).to.equal(404);
expect(res.body.message).to.equal('not found');
});
});

describe('POST /push/:id/reject', function () {
it('should reject a push request', async function () {
sinon.stub(db, 'getPush').resolves({ id: 1, user: 'author' });
sinon.stub(db, 'getUsers').resolves([{ username: ' author', admin: false }]);
sinon.stub(db, 'canUserApproveRejectPush').resolves(true);
sinon.stub(db, 'reject').resolves({ success: true });

const res = await chai
.request(app)
.post('/api/v1/push/1/reject')
.set('Cookie', cookie);

expect(res.status).to.equal(200);
expect(res.body).to.deep.equal({ success: true });
});

it('should return 401 if user is not logged in', async function () {
const res = await chai.request(app).post('/api/v1/push/1/reject');
expect(res.status).to.equal(401);
expect(res.body).to.deep.equal({ message: 'not logged in' });
});

it('should return 401 if user is the author and not admin', async function () {
sinon.stub(db, 'getPush').resolves({ id: 1, user: 'admin' });
sinon.stub(db, 'getUsers').resolves([{ username: 'admin', admin: false }]);

const res = await chai
.request(app)
.post('/api/v1/push/1/reject')
.set('Cookie', cookie);

expect(res.status).to.equal(401);
expect(res.body).to.deep.equal({ message: 'Cannot reject your own changes' });
});

it('should return 401 if user is unauthorised to reject', async function () {
sinon.stub(db, 'getPush').resolves({ id: 1, user: 'author' });
sinon.stub(db, 'getUsers').resolves([{ username: 'author', admin: false }]);
sinon.stub(db, 'canUserApproveRejectPush').resolves(false);

const res = await chai
.request(app)
.post('/api/v1/push/1/reject')
.set('Cookie', cookie);

expect(res.status).to.equal(401);
expect(res.body.message).to.equal('User is not authorised to reject changes');
});
});

describe('POST /push/:id/authorise', function () {
it('should authorise a push request', async function () {
sinon.stub(db, 'getPush').resolves({ id: 1, user: 'user1' });
sinon.stub(db, 'getUsers').resolves([{ username: 'userl', gitAccount: 'userl', admin: false }])
sinon.stub(db, 'canUserApproveRejectPush').resolves(true);
sinon.stub(db, 'authorise').resolves({ success: true });

const res = await chai
.request(app)
.post('/api/v1/push/1/authorise')
.set('Cookie', cookie)
.send({ params: { attestation: [{ checked: true }] } });

expect(res.status).to.equal(200);
expect(res.body).to.deep.equal({ success: true });
});

it('should return 401 if user is not logged in', async () => {
const res = await chai.request(app).post('/api/v1/push/1/authorise');
expect(res.status).to.be.equal(401);
expect(res.body).to.deep.equal({ message: 'You are unauthorized to perform this action...' });
});

it('should return 401 if attestation is incomplete', async () => {
const res = await chai
.request(app)
.post('/api/v1/push/1/authorise')
.set('Cookie', cookie)
.send({ params: { attestation: [{ checked: false }] } });
expect(res.status).to.be.equal(401);
expect(res.body).to.deep.equal({ message: 'You are unauthorized to perform this action...' });
});

it('should return 401 if user is the author and not admin', async function () {
sinon.stub(db, 'getPush').resolves({ id: 1, user: 'admin' });
sinon.stub(db, 'getUsers').resolves([{ username: 'admin', admin: false }]);

const res = await chai
.request(app)
.post('/api/v1/push/1/authorise')
.set('Cookie', cookie)
.send({ params: { attestation: [{ checked: true }] } });

expect(res.status).to.be.equal(401);
expect(res.body).to.deep.equal({ message: 'Cannot approve your own changes' });
});


it('should return 401 if user is unauthorised to authorise', async function () {
sinon.stub(db, 'getPush').resolves({ id: 1, user: 'user1' });
sinon.stub(db, 'getUsers').resolves([{ username: 'author', admin: false }]);
sinon.stub(db, 'canUserApproveRejectPush').resolves(false);

const res = await chai
.request(app)
.post('/api/v1/push/1/authorise')
.set('Cookie', cookie)
.send({ params: { attestation: [{ checked: true }] } });

expect(res.status).to.equal(401);
expect(res.body.message).to.equal("user admin not authorised to approve push's on this project");
});

it('should return 401 if user has no associated GitHub account', async () => {
sinon.stub(db, 'getPush').resolves({ id: 1, user: 'author' });
sinon.stub(db, 'getUsers').resolves([{ username: 'author', admin: false }]);
sinon.stub(db, 'canUserApproveRejectPush').resolves(true);

const res = await chai
.request(app)
.post('/api/v1/push/1/authorise')
.set('Cookie', cookie)
.send({ params: { attestation: [{ checked: true }] } });

expect(res.status).to.be.equal(401);
expect(res.body).to.deep.equal({
message: 'You must associate a GitHub account with your user before approving...',
});
});


});

describe('POST /push/:id/cancel', function () {
it('should cancel a push request', async function () {
sinon.stub(db, 'canUserCancelPush').resolves(true);
sinon.stub(db, 'cancel').resolves({ success: true });

const res = await chai
.request(app)
.post('/api/v1/push/1/cancel')
.set('Cookie', cookie);

expect(res.status).to.equal(200);
expect(res.body).to.deep.equal({ success: true });
});

it('should return 401 if user is not logged in', async () => {
const res = await chai
.request(app)
.post('/api/v1/push/1/cancel');

expect(res.status).to.be.equal(401);
expect(res.body).to.deep.equal({ message: 'not logged in' });
});


it('should return 401 if user is unauthorised to cancel', async function () {
sinon.stub(db, 'canUserCancelPush').resolves(false);

const res = await chai
.request(app)
.post('/api/v1/push/1/cancel')
.set('Cookie', cookie);

expect(res.status).to.equal(401);
expect(res.body).to.deep.equal({ message: 'User admin not authorised to cancel push requests on this project.' });
});
});
})
Loading
Loading