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

Added Question Types #181

Merged
merged 13 commits into from
Apr 21, 2024
18 changes: 17 additions & 1 deletion gatewayservice/src/controllers/question-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,20 @@ const getQuestions = async (
}
};

export { getQuestions };
const getQuestionTypes = async (
_: Request,
res: Response,
next: NextFunction
) => {
try {
const questionTypesResponse = await axios.get(
QUESTION_SERVICE_URL + '/questions/types'
);

res.json(questionTypesResponse.data);
} catch (error: any) {
next(error);
}
}

export { getQuestions, getQuestionTypes };
4 changes: 2 additions & 2 deletions gatewayservice/src/routes/question-routes.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import express from 'express';
import { getQuestions } from '../controllers/question-controller';
import { getQuestions, getQuestionTypes } from '../controllers/question-controller';

const router = express.Router();

router.get('/questions/types', getQuestionTypes);
router.get('/questions', getQuestions);

export default router;
101 changes: 63 additions & 38 deletions gatewayservice/test/gateway-service.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const request = require('supertest');
import axios, {AxiosError, AxiosHeaders, AxiosResponse} from 'axios';
import axios, { AxiosError, AxiosHeaders, AxiosResponse } from 'axios';
import app from '../src/app';
import { Response } from 'express';

Expand All @@ -8,14 +8,18 @@ jest.mock('axios');
const getMocks = (url: string) => {
if (url.endsWith('/questions')) {
return Promise.resolve({ data: { size: 10 } });
} else if (url.endsWith('/history')) {
}
else if (url.endsWith('/questions/types')) {
return Promise.resolve({ data: { types: {} } });
}
else if (url.endsWith('/history')) {
return Promise.resolve({ data: { gamesPlayed: 10 } });
} else if (url.endsWith('/history/leaderboard')) {
return Promise.resolve({ data: { leaderboard: {} } });
return Promise.resolve({ data: { leaderboard: {} } });
} else if (url.endsWith('/health')) {
return Promise.resolve();
} else if (url.endsWith('/profile')) {
return Promise.resolve({data: { bio: 'Test' }});
return Promise.resolve({ data: { bio: 'Test' } });
}
return Promise.resolve({});
};
Expand All @@ -30,7 +34,7 @@ const postMocks = (url: string) => {
} else if (url.endsWith('/history/increment')) {
return Promise.resolve({ data: { gamesPlayed: 20 } });
} else if (url.endsWith('/profile')) {
return Promise.resolve({data: { bio: 'Test' }});
return Promise.resolve({ data: { bio: 'Test' } });
}
return Promise.resolve({});
};
Expand All @@ -53,8 +57,8 @@ describe('Gateway Service', () => {
it('should get an error when auth service is down', async () => {
const response = await testWithoutServices(() => {
return request(app)
.post('/login')
.send({ username: 'testuser', password: 'testpassword' })
.post('/login')
.send({ username: 'testuser', password: 'testpassword' })
});

expect(response.statusCode).toBe(500);
Expand All @@ -74,8 +78,8 @@ describe('Gateway Service', () => {
it('should get an error when user service is down', async () => {
const response = await testWithoutServices(() => {
return request(app)
.post('/adduser')
.send({ username: 'newuser', password: 'newpassword' })
.post('/adduser')
.send({ username: 'newuser', password: 'newpassword' })
});

expect(response.statusCode).toBe(500);
Expand All @@ -95,8 +99,8 @@ describe('Gateway Service', () => {
it('should get an error when user service is down', async () => {
const response = await testWithoutServices(() => {
return request(app)
.post('/history')
.send({ username: 'testuser', gamesPlayed: 10 })
.post('/history')
.send({ username: 'testuser', gamesPlayed: 10 })
});

expect(response.statusCode).toBe(500);
Expand All @@ -105,8 +109,8 @@ describe('Gateway Service', () => {
// Test POST /history/increment endpoint
it('should forward history request to user service', async () => {
const response = await request(app)
.post('/history/increment')
.send({ username: 'testuser', gamesPlayed: 10 });
.post('/history/increment')
.send({ username: 'testuser', gamesPlayed: 10 });

expect(response.statusCode).toBe(200);
expect(response.body.gamesPlayed).toBe(20);
Expand All @@ -116,8 +120,8 @@ describe('Gateway Service', () => {
it('should get an error when user service is down', async () => {
const response = await testWithoutServices(() => {
return request(app)
.post('/history/increment')
.send({ username: 'testuser', gamesPlayed: 10 })
.post('/history/increment')
.send({ username: 'testuser', gamesPlayed: 10 })
});

expect(response.statusCode).toBe(500);
Expand All @@ -138,9 +142,9 @@ describe('Gateway Service', () => {
it('should get an error when user service is down', async () => {
const response = await testWithoutServices(() => {
return request(app)
.get('/history')
.query({ user: 'newuser' })
.send();
.get('/history')
.query({ user: 'newuser' })
.send();
});

expect(response.statusCode).toBe(500);
Expand All @@ -149,8 +153,8 @@ describe('Gateway Service', () => {
// Test GET /history/leaderboard endpoint
it('should forward history request to user service', async () => {
const response = await request(app)
.get('/history/leaderboard')
.send();
.get('/history/leaderboard')
.send();

expect(response.statusCode).toBe(200);
expect(response.body.leaderboard).toBeDefined();
Expand All @@ -160,8 +164,8 @@ describe('Gateway Service', () => {
it('should get an error when user service is down', async () => {
const response = await testWithoutServices(() => {
return request(app)
.get('/history/leaderboard')
.send();
.get('/history/leaderboard')
.send();
});

expect(response.statusCode).toBe(500);
Expand All @@ -182,9 +186,30 @@ describe('Gateway Service', () => {
it('should get an error when user service is down', async () => {
const response = await testWithoutServices(() => {
return request(app)
.get('/questions')
.query({ size: 10 })
.send();
.get('/questions')
.query({ size: 10 })
.send();
});

expect(response.statusCode).toBe(500);
});

// Test /questions/types endpoint
it('should forward question types request to question service', async () => {
const response = await request(app)
.get('/questions/types')
.send();

expect(response.statusCode).toBe(200);
expect(response.body.types).toBeDefined();
});

// Test /questions/types endpoint down
it('should get an error when question service is down', async () => {
const response = await testWithoutServices(() => {
return request(app)
.get('/questions/types')
.send();
});

expect(response.statusCode).toBe(500);
Expand Down Expand Up @@ -278,8 +303,8 @@ describe('Gateway Service', () => {
// Test POST /history endpoint with authorization header
it('should forward history request to user service', async () => {
const response = await request(app)
.post('/history')
.set('authorization', '');
.post('/history')
.set('authorization', '');

expect(response.statusCode).toBe(200);
expect(response.body.gamesPlayed).toBe(10);
Expand All @@ -288,7 +313,7 @@ describe('Gateway Service', () => {
// Test POST /history endpoint with headers
it('should forward history request to user service', async () => {
const response = await request(app)
.post('/history');
.post('/history');

expect(response.statusCode).toBe(200);
expect(response.body.gamesPlayed).toBe(10);
Expand All @@ -297,8 +322,8 @@ describe('Gateway Service', () => {
// Test POST /history endpoint with authorization header
it('should forward history request to user service', async () => {
const response = await request(app)
.post('/history')
.set('authorization', '');
.post('/history')
.set('authorization', '');

expect(response.statusCode).toBe(200);
expect(response.body.gamesPlayed).toBe(10);
Expand All @@ -307,8 +332,8 @@ describe('Gateway Service', () => {
// Test POST /history/increment endpoint with authorization header
it('should forward history request to user service', async () => {
const response = await request(app)
.post('/history/increment')
.set('authorization', '');
.post('/history/increment')
.set('authorization', '');

expect(response.statusCode).toBe(200);
expect(response.body.gamesPlayed).toBe(20);
Expand All @@ -328,8 +353,8 @@ describe('Gateway Service', () => {
it('should get an error when user service is down', async () => {
const response = await testWithoutServices(() => {
return request(app)
.post('/profile')
.send({ username: 'testuser', bio: 'Test' })
.post('/profile')
.send({ username: 'testuser', bio: 'Test' })
});

expect(response.statusCode).toBe(500);
Expand All @@ -350,16 +375,16 @@ describe('Gateway Service', () => {
it('should get an error when user service is down', async () => {
const response = await testWithoutServices(() => {
return request(app)
.get('/profile')
.query({ user: 'newuser' })
.send();
.get('/profile')
.query({ user: 'newuser' })
.send();
});

expect(response.statusCode).toBe(500);
});
});

async function testWithoutServices(paramFunc : Function) {
async function testWithoutServices(paramFunc: Function) {
// Clear the mocks
(axios.get as jest.Mock).mockImplementation((url: string) => { if (url) return; })
await (axios.post as jest.Mock).mockImplementation((url: string) => { if (url) return; })
Expand Down
33 changes: 28 additions & 5 deletions questionservice/src/controllers/question-controller.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,36 @@
import { Request, Response } from 'express';
import { generateQuestions } from '../services/question-generator';
import { validateLanguage, validateNumber, validateSizePresent } from '../utils/validations';
import { validateLanguage, validateNumber, validateSizePresent, validateTypes } from '../utils/validations';
import { getQuestionTypes } from '../services/question-storage';


const generateQuestionsController = async (req: Request, res: Response) => {
try {
const requestedParam = req.query.size;
const language = req.query.lang;
let types = req.query.type;


validateSizePresent(req);

// If language is not present, there is no need to validate since undefined values are accepted
if (language) {
validateLanguage(language as string)
validateLanguage(language as string)
}
// If types is not present, there is no need to validate since undefined values are accepted
if (types) {
if (typeof types === 'string') {
types = [types];
}
types = types as string[];
types.map((type) => type.toLowerCase());

await validateTypes(types)
}
let size = validateNumber(requestedParam as string);

try {
const questions = await generateQuestions(size, language);
const questions = await generateQuestions(size, language, types);
res.json(questions);
} catch (err: any) {
res.status(500).json({
Expand All @@ -30,4 +43,14 @@ const generateQuestionsController = async (req: Request, res: Response) => {
}
};

export { generateQuestionsController };
const getQuestionTypesController = async (_: Request, res: Response) => {
try {
let types = await getQuestionTypes();
res.status(200).json({ types: types, n_types: types.length });
} catch (error: any) {
console.log(error);
res.status(500).json({ status: 'fail', message: 'There was a problem obtaining types, please try again later.' });
}
}

export { generateQuestionsController, getQuestionTypesController };
1 change: 1 addition & 0 deletions questionservice/src/models/question-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const questionSchema = new Schema<Question>({
question: { type: String, required: true },
answers: { type: [Object], required: true },
correctAnswerId: { type: Number, required: true },
type: { type: String, required: true },
image: { type: String, required: false }
});

Expand Down
Loading