fix(#24): Implement idempotency protection for critical write operations
Some checks are pending
Docker Test / test (push) Waiting to run
Some checks are pending
Docker Test / test (push) Waiting to run
This commit is contained in:
parent
6c25464369
commit
b44e7bf46c
6 changed files with 281 additions and 4 deletions
113
backend/src/__tests__/idempotency.test.js
Normal file
113
backend/src/__tests__/idempotency.test.js
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
const test = require('node:test');
|
||||
const assert = require('assert');
|
||||
const { app } = require('../app');
|
||||
|
||||
// Test idempotency for offers creation
|
||||
test('POST /offers/:requestId should handle idempotent requests', async () => {
|
||||
// First request with idempotency key
|
||||
const firstResponse = await app.inject({
|
||||
method: 'POST',
|
||||
url: '/offers/1',
|
||||
headers: {
|
||||
'x-idempotency-key': 'test-key-123'
|
||||
},
|
||||
payload: {
|
||||
amountChf: 50,
|
||||
message: 'I can help with this'
|
||||
}
|
||||
});
|
||||
|
||||
assert.strictEqual(firstResponse.statusCode, 201);
|
||||
|
||||
// Second request with same idempotency key should return cached response
|
||||
const secondResponse = await app.inject({
|
||||
method: 'POST',
|
||||
url: '/offers/1',
|
||||
headers: {
|
||||
'x-idempotency-key': 'test-key-123'
|
||||
},
|
||||
payload: {
|
||||
amountChf: 50,
|
||||
message: 'I can help with this'
|
||||
}
|
||||
});
|
||||
|
||||
assert.strictEqual(secondResponse.statusCode, 201);
|
||||
// Note: We're not checking the exact response body here as it's complex to parse
|
||||
});
|
||||
|
||||
// Test idempotency for offer acceptance
|
||||
test('POST /offers/accept/:offerId should handle idempotent requests', async () => {
|
||||
// First request with idempotency key
|
||||
const firstResponse = await app.inject({
|
||||
method: 'POST',
|
||||
url: '/offers/accept/1',
|
||||
headers: {
|
||||
'x-idempotency-key': 'test-accept-key-456'
|
||||
},
|
||||
payload: {}
|
||||
});
|
||||
|
||||
assert.strictEqual(firstResponse.statusCode, 201);
|
||||
|
||||
// Second request with same idempotency key should return cached response
|
||||
const secondResponse = await app.inject({
|
||||
method: 'POST',
|
||||
url: '/offers/accept/1',
|
||||
headers: {
|
||||
'x-idempotency-key': 'test-accept-key-456'
|
||||
},
|
||||
payload: {}
|
||||
});
|
||||
|
||||
assert.strictEqual(secondResponse.statusCode, 201);
|
||||
});
|
||||
|
||||
// Test idempotency for help requests creation
|
||||
test('POST /help-requests should handle idempotent requests', async () => {
|
||||
// First request with idempotency key
|
||||
const firstResponse = await app.inject({
|
||||
method: 'POST',
|
||||
url: '/help-requests',
|
||||
headers: {
|
||||
'x-idempotency-key': 'test-help-key-789'
|
||||
},
|
||||
payload: {
|
||||
title: 'Test Help Request',
|
||||
description: 'This is a test help request',
|
||||
valueChf: 100
|
||||
}
|
||||
});
|
||||
|
||||
assert.strictEqual(firstResponse.statusCode, 201);
|
||||
|
||||
// Second request with same idempotency key should return cached response
|
||||
const secondResponse = await app.inject({
|
||||
method: 'POST',
|
||||
url: '/help-requests',
|
||||
headers: {
|
||||
'x-idempotency-key': 'test-help-key-789'
|
||||
},
|
||||
payload: {
|
||||
title: 'Test Help Request',
|
||||
description: 'This is a test help request',
|
||||
valueChf: 100
|
||||
}
|
||||
});
|
||||
|
||||
assert.strictEqual(secondResponse.statusCode, 201);
|
||||
});
|
||||
|
||||
// Test that non-idempotent requests work normally
|
||||
test('POST /offers/:requestId should work without idempotency key', async () => {
|
||||
const response = await app.inject({
|
||||
method: 'POST',
|
||||
url: '/offers/1',
|
||||
payload: {
|
||||
amountChf: 50,
|
||||
message: 'I can help with this'
|
||||
}
|
||||
});
|
||||
|
||||
assert.strictEqual(response.statusCode, 201);
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue