Skip to content

Commit

Permalink
Added tests and error handling for delete and put routes
Browse files Browse the repository at this point in the history
  • Loading branch information
brokoli777 committed Aug 6, 2024
1 parent 8fc7752 commit 1486882
Show file tree
Hide file tree
Showing 8 changed files with 216 additions and 17 deletions.
7 changes: 7 additions & 0 deletions src/model/data/memory/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ async function listFragments(ownerId, expand = false) {

// Delete a fragment's metadata and data from memory db. Returns a Promise
function deleteFragment(ownerId, id) {

if(!metadata.get(ownerId, id)){
throw new Error('Fragment not found');
}

logger.debug(`MEMORYDB - Deleting fragment ${id} from memory db`);

return Promise.all([
// Delete metadata
metadata.del(ownerId, id),
Expand Down
1 change: 1 addition & 0 deletions src/model/fragment.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class Fragment {
* @returns Promise<void>
*/
static delete(ownerId, id) {

try {
return deleteFragment(ownerId, id);
}
Expand Down
27 changes: 18 additions & 9 deletions src/routes/api/delete.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,25 @@ module.exports = (req, res) => {
const ownerId = req.user;
const id = req.params.id;

logger.info(`inside delete route`);
Fragment.byUser(ownerId).then((fragmentsList) => {

try{
Fragment.delete(ownerId, id);
logger.info(`Fragment ${id} deleted for user ${ownerId}`);
res.status(200).json(createSuccessResponse());
}
catch (err) {
logger.error(err);
res.status(500).json(createErrorResponse(500, err));
if (!fragmentsList.includes(id)) {
logger.error(`Fragment ${id} not found for user ${ownerId}`);
res.status(404).json(createErrorResponse(404, 'Fragment not found'));
return;
}else{
try{
Fragment.delete(ownerId, id);
logger.info(`Fragment ${id} deleted for user ${ownerId}`);
res.status(200).json(createSuccessResponse());
}
catch (err) {
logger.error(err);
res.status(500).json(createErrorResponse(500, err));
}
}
});



}
4 changes: 3 additions & 1 deletion src/routes/api/put.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ module.exports = (req, res) => {
const ownerId = req.user;
const id = req.params.id;

logger.info(`PUT /fragments/${id} for user ${ownerId}`);

if (Fragment.isSupportedType(req.get('Content-Type')) === false) {
const type = req.get('Content-Type');
logger.error(`unsupported media type: ${type}`);
res.status(415).json(createErrorResponse(415, 'unsupported media type'));
return;
}

if (!Buffer.isBuffer(req.body)) {
if (!Buffer.isBuffer(req.body) || req.body.length === 0) {
logger.error('no buffer found in request body');
res.status(400).json(createErrorResponse(400, 'no buffer found in request body'));
return;
Expand Down
4 changes: 2 additions & 2 deletions tests/integration/lab-10-dynamodb.hurl
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ jsonpath "$.fragment.id" == "{{fragment2_id}}"
jsonpath "$.fragment.type" == "text/markdown"
jsonpath "$.fragment.size" == 22

# 5. GET all fragments for the authorized user
# GET all fragments for the authorized user
GET http://localhost:8080/v1/fragments
[BasicAuth]
user1@email.com:password1
Expand All @@ -79,7 +79,7 @@ jsonpath "$.status" == "ok"
jsonpath "$.fragments" includes "{{fragment1_id}}"
jsonpath "$.fragments" includes "{{fragment2_id}}"

# 6. DELETE the first fragment
# DELETE the first fragment
DELETE {{fragment1_url}}
[BasicAuth]
user1@email.com:password1
Expand Down
60 changes: 60 additions & 0 deletions tests/unit/delete.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// tests/unit/delete.test.js

const request = require('supertest');
const app = require('../../src/app');

// jest.mock('../../src/model/fragment');

describe('DELETE /v1/fragments/:id', () => {
// If the request is missing the Authorization header, it should be forbidden
test('unauthenticated requests are denied', () =>
request(app).delete('/v1/fragments/1').expect(401)
);

// If the wrong username/password pair are invalid, it should not work
test('incorrect credentials are denied', () =>
request(app).delete('/v1/fragments/1').auth('hey@email.com', 'badpassweord').expect(401)
);

// If the id is not found, it should return a 404 error
test('fragment not found returns 404', async () => {

const res = await request(app)
.delete('/v1/fragments/doesntexistid')
.auth('user1@email.com', 'password1');

expect(res.statusCode).toBe(404);
expect(res.body.status).toBe('error');
expect(res.body.error.message).toBe('Fragment not found');
});

// Authenticated users can delete a fragment successfully
test('authenticated users can delete a fragment successfully', async () => {
// create a fragment
const postRequest = await request(app)
.post('/v1/fragments')
.auth('user1@email.com', 'password1')
.set('Content-Type', 'text/plain')
.send(Buffer.from('yoooooo'));

const fragmentId = postRequest.body.fragment.id;

// delete the fragment
const deleteResponse = await request(app)
.delete(`/v1/fragments/${fragmentId}`)
.auth('user1@email.com', 'password1');

expect(deleteResponse.statusCode).toBe(200);
expect(deleteResponse.body.status).toBe('ok');

// Verify the fragment no longer exists
const getResponse = await request(app)
.get(`/v1/fragments/${fragmentId}`)
.auth('user1@email.com', 'password1');

expect(getResponse.statusCode).toBe(404);
expect(getResponse.body.status).toBe('error');
expect(getResponse.body.error.message).toBe('Fragment not found');
});

});
9 changes: 4 additions & 5 deletions tests/unit/fragment.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ const validTypes = [
`text/markdown`,
`text/html`,
`application/json`,
// `image/png`,
// `image/jpeg`,
// `image/webp`,
// `image/gif`,
`image/png`,
`image/jpeg`,
`image/webp`,
`image/gif`,

];

Expand Down Expand Up @@ -248,7 +248,6 @@ describe('Fragment class', () => {
await fragment.setData(Buffer.from('a'));

await Fragment.delete('1234', fragment.id);
//expect(() => Fragment.byId('1234', fragment.id)).rejects.toThrow();
});
});
});
121 changes: 121 additions & 0 deletions tests/unit/put.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// tests/unit/put.test.js

const request = require('supertest');
const app = require('../../src/app');

describe('PUT /v1/fragments/:id', () => {
// Unauthenticated requests are denied
test('unauthenticated requests are denied', () =>
request(app).put('/v1/fragments/1').expect(401)
);

// Requests with incorrect credentials are denied
test('incorrect credentials are denied', () =>
request(app).put('/v1/fragments/1').auth('invalid@email.com', 'incorrect_password').expect(401)
);

// Fragment not found returns 404
test('fragment not found returns 404', async () => {
const res = await request(app)
.put('/v1/fragments/blahblahblah')
.auth('user1@email.com', 'password1')
.set('Content-Type', 'text/plain')
.send(Buffer.from('updated data'));

expect(res.statusCode).toBe(404);
expect(res.body.status).toBe('error');
expect(res.body.error.message).toBe('Fragment not found');
});

// Unsupported media type returns 415
test('unsupported media type returns 415', async () => {
// First, create a fragment with a supported type
const postRequest = await request(app)
.post('/v1/fragments')
.auth('user1@email.com', 'password1')
.set('Content-Type', 'text/plain')
.send(Buffer.from('hello world'));

const fragmentId = postRequest.body.fragment.id;

// Attempt to update with an unsupported media type
const res = await request(app)
.put(`/v1/fragments/${fragmentId}`)
.auth('user1@email.com', 'password1')
.set('Content-Type', 'application/unsupported')
.send(Buffer.from('updated data'));

expect(res.statusCode).toBe(415);
expect(res.body.status).toBe('error');
expect(res.body.error.message).toBe('unsupported media type');
});


// Fragment type mismatch returns 400
test('fragment type mismatch returns 400', async () => {

const postRequest = await request(app)
.post('/v1/fragments')
.auth('user1@email.com', 'password1')
.set('Content-Type', 'text/plain')
.send(Buffer.from('hello world'));

const fragmentId = postRequest.body.fragment.id;

const res = await request(app)
.put(`/v1/fragments/${fragmentId}`)
.auth('user1@email.com', 'password1')
.set('Content-Type', 'text/html')
.send(Buffer.from('<p>updated data</p>'));

expect(res.statusCode).toBe(400);
expect(res.body.status).toBe('error');
expect(res.body.error.message).toBe('Fragment type did not match');
});

// No buffer found in request body returns 400
test('no buffer found in request body returns 400', async () => {

const postRequest = await request(app)
.post('/v1/fragments')
.auth('user1@email.com', 'password1')
.set('Content-Type', 'text/plain')
.send(Buffer.from('hello world'));

const fragmentId = postRequest.body.fragment.id;

const res = await request(app)
.put(`/v1/fragments/${fragmentId}`)
.auth('user1@email.com', 'password1')
.set('Content-Type', 'text/plain')

expect(res.statusCode).toBe(400);
expect(res.body.status).toBe('error');
expect(res.body.error.message).toBe('no buffer found in request body');
});


// Successful fragment update
test('authenticated users can update a fragment successfully', async () => {
const postRequest = await request(app)
.post('/v1/fragments')
.auth('user1@email.com', 'password1')
.set('Content-Type', 'text/plain')
.send(Buffer.from('hello world'));

const fragmentId = postRequest.body.fragment.id;

// Update the fragment
const res = await request(app)
.put(`/v1/fragments/${fragmentId}`)
.auth('user1@email.com', 'password1')
.set('Content-Type', 'text/plain')
.send(Buffer.from('updated data'));

expect(res.statusCode).toBe(200);
expect(res.body.status).toBe('ok');
expect(res.body.fragment.id).toBe(fragmentId);
expect(res.body.fragment.type).toBe('text/plain');
expect(res.body.fragment.size).toBe(Buffer.from('updated data').length);
});
});

0 comments on commit 1486882

Please sign in to comment.