Skip to content

Commit 2d1483a

Browse files
Merge pull request #73 from prabalsingh24/project-tests
Project tests
2 parents 168f3a1 + 25a8f0e commit 2d1483a

File tree

7 files changed

+613
-19
lines changed

7 files changed

+613
-19
lines changed

src/routes/api/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { NextFunction, Request, Response, Router } from 'express'
22
import run from './run'
33
import submit from './submit'
4+
import project from './project'
45
import result from './result'
56
import { route as langs } from './langs'
67
import { checkValidApiKey } from '../../validators/ApiKeyValidators'
@@ -29,6 +30,7 @@ route.use((req: Request, res: Response, next: NextFunction) => {
2930
route.use('/runs', run)
3031
route.use('/result', result)
3132
route.use('/submissions', submit)
33+
route.use('/project', project)
3234
route.use('/langs', langs)
3335

3436
export default route

src/routes/api/project/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ import { Router } from 'express'
22
import Controller from './controller'
33
import Validator from './validators'
44
import { successListener } from 'rabbitmq/jobqueue'
5+
import langValidator from '../../../middlewares/langValidator';
56

67
const router: Router = Router()
78
const validator = new Validator()
89

9-
router.post('/', validator.POST, Controller.runPOST)
10+
router.post('/', validator.POST, langValidator(), Controller.runPOST)
1011
successListener.on('project_result', Controller.onSuccess)
1112

1213
export default router

src/routes/api/project/validators.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ export default class ProjectValidator extends BaseValidator {
1111
}
1212

1313
POSTSchema = Joi.object({
14+
lang: Joi
15+
.string()
16+
.required(),
1417
problem: Joi
1518
.string()
1619
.uri()

test/e2e/ProjectScenario.spec.ts

Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
import app from '../../src/server';
2+
import DB from '../../src/models';
3+
import express = require('express');
4+
import { Router } from 'express';
5+
import * as utils from '../utils/utils';
6+
7+
8+
const chai = require('chai');
9+
const chaiHttp = require('chai-http');
10+
11+
chai.use(chaiHttp);
12+
const {expect} = chai;
13+
14+
const APIKEY = '7718330d2794406c980bdbded6c9dc1d';
15+
16+
17+
function delay(ms: number) {
18+
return new Promise( resolve => setTimeout(resolve, ms) );
19+
}
20+
21+
describe('POST api/project', () => {
22+
before(async () => {
23+
await DB.apikeys.create({
24+
id: 1,
25+
key: APIKEY,
26+
whitelist_domains: ['*'],
27+
whitelist_ips: ['*']
28+
});
29+
await DB.langs.create({
30+
lang_slug: 'node',
31+
lang_name: 'NodeJS',
32+
lang_version: '10'
33+
});
34+
await utils.setupMockQueue();
35+
36+
});
37+
after(utils.truncateTables);
38+
39+
it('should throw 403 error if API Key is absent', async () => {
40+
const res = await chai.request(app).post(`/api/project`);
41+
42+
expect(res.status).to.equal(403);
43+
expect(res.body.message).to.equal('No API Key in request');
44+
});
45+
46+
it('should throw 404 error if GET request is made', async () => {
47+
const res = await chai.request(app).get(`/api/project`).set({
48+
Authorization: 'Bearer 7718330d2794406c980bdbded6c9dc1d',
49+
Accept: 'application/json'
50+
});
51+
52+
expect(res.status).to.equal(404);
53+
});
54+
55+
it('should throw 400 error if correct params are not sent along with the POST request', async () => {
56+
const res = await chai.request(app).post(`/api/project`).set({
57+
Authorization: 'Bearer 7718330d2794406c980bdbded6c9dc1d',
58+
Accept: 'application/json'
59+
}).send({});
60+
61+
expect(res.status).to.equal(400);
62+
expect(res.body.err.message).to.equal('"lang" is required');
63+
});
64+
65+
it('should throw 400 error for incorrect language', async () => {
66+
const params = {
67+
lang: 'abcd',
68+
problem: 'https://minio.cb.lk/public/input',
69+
submission: 'https://minio.cb.lk/public/input',
70+
submissionDirs: 'src',
71+
mode: 'sync',
72+
timelimit: 1
73+
};
74+
75+
const res = await chai.request(app).post(`/api/project`).set({
76+
Authorization: 'Bearer 7718330d2794406c980bdbded6c9dc1d',
77+
Accept: 'application/json'
78+
}).send(params);
79+
80+
expect(res.status).to.equal(400);
81+
});
82+
83+
it('should throw 400 error for problem missing', async () => {
84+
const params = {
85+
lang: 'node',
86+
submission: 'https://minio.cb.lk/public/input',
87+
submissionDirs: 'src',
88+
mode: 'sync',
89+
timelimit: 1
90+
};
91+
92+
const res = await chai.request(app).post(`/api/project`).set({
93+
Authorization: 'Bearer 7718330d2794406c980bdbded6c9dc1d',
94+
Accept: 'application/json'
95+
}).send(params);
96+
97+
expect(res.status).to.equal(400);
98+
expect(res.body.err.message).to.equal('"problem" is required');
99+
});
100+
101+
it('should throw 400 error when problem is not an url', async () => {
102+
const params = {
103+
lang: 'node',
104+
problem: 'not-a-url',
105+
submission: 'https://minio.cb.lk/public/input',
106+
submissionDirs: 'src',
107+
mode: 'sync',
108+
timelimit: 1
109+
};
110+
111+
const res = await chai.request(app).post(`/api/project`).set({
112+
Authorization: 'Bearer 7718330d2794406c980bdbded6c9dc1d',
113+
Accept: 'application/json'
114+
}).send(params);
115+
116+
expect(res.status).to.equal(400);
117+
expect(res.body.err.message).to.equal('"problem" must be a valid uri');
118+
});
119+
120+
it('should throw 400 error for submission missing', async () => {
121+
const params = {
122+
lang: 'node',
123+
problem: 'https://minio.cb.lk/public/input',
124+
submissionDirs: 'src',
125+
mode: 'sync',
126+
timelimit: 1
127+
};
128+
129+
const res = await chai.request(app).post(`/api/project`).set({
130+
Authorization: 'Bearer 7718330d2794406c980bdbded6c9dc1d',
131+
Accept: 'application/json'
132+
}).send(params);
133+
134+
expect(res.status).to.equal(400);
135+
expect(res.body.err.message).to.equal('"submission" is required');
136+
});
137+
138+
it('should throw 400 error when submission is not an url', async () => {
139+
const params = {
140+
lang: 'node',
141+
problem: 'https://minio.cb.lk/public/input',
142+
submission: 'not-a-url',
143+
submissionDirs: 'src',
144+
mode: 'sync',
145+
timelimit: 1
146+
};
147+
148+
const res = await chai.request(app).post(`/api/project`).set({
149+
Authorization: 'Bearer 7718330d2794406c980bdbded6c9dc1d',
150+
Accept: 'application/json'
151+
}).send(params);
152+
153+
expect(res.status).to.equal(400);
154+
expect(res.body.err.message).to.equal('"submission" must be a valid uri');
155+
});
156+
157+
it('should throw 400 error for submissionDirs missing', async () => {
158+
const params = {
159+
lang: 'node',
160+
problem: 'https://minio.cb.lk/public/input',
161+
submission: 'https://minio.cb.lk/public/input',
162+
mode: 'sync',
163+
timelimit: 1
164+
};
165+
166+
const res = await chai.request(app).post(`/api/project`).set({
167+
Authorization: 'Bearer 7718330d2794406c980bdbded6c9dc1d',
168+
Accept: 'application/json'
169+
}).send(params);
170+
171+
expect(res.status).to.equal(400);
172+
expect(res.body.err.message).to.equal('"submissionDirs" is required');
173+
});
174+
175+
it('should throw 400 error when submissionDirs is not a string', async () => {
176+
const params = {
177+
lang: 'node',
178+
problem: 'https://minio.cb.lk/public/input',
179+
submission: 'https://minio.cb.lk/public/input',
180+
submissionDirs: 123,
181+
mode: 'sync',
182+
timelimit: 1
183+
};
184+
185+
const res = await chai.request(app).post(`/api/project`).set({
186+
Authorization: 'Bearer 7718330d2794406c980bdbded6c9dc1d',
187+
Accept: 'application/json'
188+
}).send(params);
189+
190+
expect(res.status).to.equal(400);
191+
expect(res.body.err.message).to.equal('"submissionDirs" must be a string');
192+
});
193+
194+
it('should throw 400 error for incorrect mode ', async () => {
195+
const params = {
196+
lang: 'node',
197+
problem: 'https://minio.cb.lk/public/input',
198+
submission: 'https://minio.cb.lk/public/input',
199+
submissionDirs: 'src',
200+
mode: 'abc',
201+
timelimit: 1
202+
};
203+
204+
const res = await chai.request(app).post(`/api/project`).set({
205+
Authorization: 'Bearer 7718330d2794406c980bdbded6c9dc1d',
206+
Accept: 'application/json'
207+
}).send(params);
208+
209+
expect(res.status).to.equal(400);
210+
expect(res.body.err.message).to.equal('"mode" must be one of [sync, callback, poll]');
211+
});
212+
213+
it('should throw 400 if mode is callback but callback is not present', async () => {
214+
const params = {
215+
lang: 'node',
216+
problem: 'https://minio.cb.lk/public/input',
217+
submission: 'https://minio.cb.lk/public/input',
218+
submissionDirs: 'src',
219+
mode: 'callback',
220+
timelimit: 1
221+
};
222+
223+
const res = await chai.request(app).post(`/api/project`).set({
224+
Authorization: 'Bearer 7718330d2794406c980bdbded6c9dc1d',
225+
Accept: 'application/json'
226+
}).send(params);
227+
228+
expect(res.status).to.equal(400);
229+
expect(res.body.err.message).to.equal('"callback" is required');
230+
});
231+
232+
it('should return correct result in sync mode ', async () => {
233+
const params = {
234+
lang: 'node',
235+
problem: 'https://minio.cb.lk/public/input',
236+
submission: 'https://minio.cb.lk/public/input',
237+
submissionDirs: 'src',
238+
mode: 'sync',
239+
timelimit: 1
240+
};
241+
242+
const res = await chai.request(app).post(`/api/project`).set({
243+
Authorization: 'Bearer 7718330d2794406c980bdbded6c9dc1d',
244+
Accept: 'application/json'
245+
}).send(params);
246+
247+
expect(res.body.score).to.equal(100);
248+
expect(res.status).to.equal(200);
249+
});
250+
251+
252+
it('should return correct submission.id in poll mode', async () => {
253+
const params = {
254+
lang: 'node',
255+
problem: 'https://minio.cb.lk/public/input',
256+
submission: 'https://minio.cb.lk/public/input',
257+
submissionDirs: 'src',
258+
mode: 'poll',
259+
timelimit: 1
260+
};
261+
262+
const res = await chai.request(app).post(`/api/project`).set({
263+
Authorization: 'Bearer 7718330d2794406c980bdbded6c9dc1d',
264+
Accept: 'application/json'
265+
}).send(params);
266+
267+
268+
// there is a delay of 1000 for onSuccess, so setting 2000ms delay here.
269+
await delay(2000);
270+
const submission = await DB.submissions.findById(res.body.id);
271+
272+
expect(res.body.id).to.exist;
273+
expect(res.status).to.equal(200);
274+
expect(submission.results.score).to.equal(100);
275+
});
276+
277+
it('should return id and send result to callback url in callback mode', async () => {
278+
const params = {
279+
lang: 'node',
280+
problem: 'https://minio.cb.lk/public/input',
281+
submission: 'https://minio.cb.lk/public/input',
282+
submissionDirs: 'src',
283+
mode: 'callback',
284+
callback: 'http://localhost:2404',
285+
timelimit: 1
286+
};
287+
288+
const res = await chai.request(app).post(`/api/project`).set({
289+
Authorization: 'Bearer 7718330d2794406c980bdbded6c9dc1d',
290+
Accept: 'application/json'
291+
}).send(params);
292+
293+
let resultFromCallBack;
294+
295+
// Mock server for callback
296+
const app2 = express();
297+
app2.use(express.json());
298+
const router = Router();
299+
app2.listen(2404, () => {
300+
router.post('/', (req, res) => {
301+
resultFromCallBack = req.body;
302+
});
303+
app2.use('/', router);
304+
});
305+
306+
await delay(2000);
307+
308+
expect(res.body.id).to.exist;
309+
expect(res.status).to.equal(200);
310+
expect(resultFromCallBack.score).to.equal(100);
311+
});
312+
});

0 commit comments

Comments
 (0)