Skip to content

Commit 2e2c79f

Browse files
tolutheodreamorosi
authored andcommitted
dev branch commit and unit tests
1 parent bc600d0 commit 2e2c79f

File tree

8 files changed

+186
-26
lines changed

8 files changed

+186
-26
lines changed

packages/idempotency/src/IdempotencyHandler.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -313,11 +313,11 @@ export class IdempotencyHandler<Func extends AnyFunction> {
313313
);
314314
} catch (e) {
315315
if (e instanceof IdempotencyItemAlreadyExistsError) {
316-
const idempotencyRecord: IdempotencyRecord = e.existingRecord;
317-
// const idempotencyRecord: IdempotencyRecord =
318-
// await this.#persistenceStore.getRecord(
319-
// this.#functionPayloadToBeHashed
320-
// );
316+
//const idempotencyRecord: IdempotencyRecord = e.existingRecord;
317+
const idempotencyRecord: IdempotencyRecord =
318+
await this.#persistenceStore.getRecord(
319+
this.#functionPayloadToBeHashed
320+
);
321321

322322
return IdempotencyHandler.determineResultFromIdempotencyRecord(
323323
idempotencyRecord

packages/idempotency/src/persistence/BasePersistenceLayer.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,10 @@ abstract class BasePersistenceLayer implements BasePersistenceLayerInterface {
154154
}
155155

156156
if (this.getFromCache(idempotencyRecord.idempotencyKey)) {
157-
throw new IdempotencyItemAlreadyExistsError('', undefined);
157+
throw new IdempotencyItemAlreadyExistsError(
158+
`Failed to put record for already existing idempotency key: ${idempotencyRecord.idempotencyKey}`,
159+
idempotencyRecord
160+
);
158161
}
159162

160163
await this._putRecord(idempotencyRecord);

packages/idempotency/tests/unit/IdempotencyHandler.test.ts

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ describe('Class IdempotencyHandler', () => {
5656
expiryTimestamp: Date.now() + 1000, // should be in the future
5757
inProgressExpiryTimestamp: 0, // less than current time in milliseconds
5858
responseData: { responseData: 'responseData' },
59-
payloadHash: 'payloadHash',
6059
status: IdempotencyRecordStatus.INPROGRESS,
6160
});
6261

@@ -75,7 +74,6 @@ describe('Class IdempotencyHandler', () => {
7574
expiryTimestamp: Date.now() + 1000, // should be in the future
7675
inProgressExpiryTimestamp: new Date().getUTCMilliseconds() - 1000, // should be in the past
7776
responseData: { responseData: 'responseData' },
78-
payloadHash: 'payloadHash',
7977
status: IdempotencyRecordStatus.INPROGRESS,
8078
});
8179

@@ -94,7 +92,6 @@ describe('Class IdempotencyHandler', () => {
9492
expiryTimestamp: new Date().getUTCMilliseconds() - 1000, // should be in the past
9593
inProgressExpiryTimestamp: 0, // less than current time in milliseconds
9694
responseData: { responseData: 'responseData' },
97-
payloadHash: 'payloadHash',
9895
status: IdempotencyRecordStatus.EXPIRED,
9996
});
10097

@@ -109,10 +106,22 @@ describe('Class IdempotencyHandler', () => {
109106

110107
describe('Method: handle', () => {
111108
test('when IdempotencyAlreadyInProgressError is thrown, it retries once', async () => {
109+
// Arrange
110+
const existingRecord = new IdempotencyRecord({
111+
idempotencyKey: 'idempotence-key',
112+
status: 'COMPLETED',
113+
expiryTimestamp: Date.now() / 1000 - 1,
114+
responseData: { test: 'data' },
115+
});
112116
// Prepare
113117
const saveInProgressSpy = jest
114118
.spyOn(persistenceStore, 'saveInProgress')
115-
.mockRejectedValueOnce(new IdempotencyItemAlreadyExistsError());
119+
.mockRejectedValueOnce(
120+
new IdempotencyItemAlreadyExistsError(
121+
'Failed to put record for already existing idempotency key: idempotence-key',
122+
existingRecord
123+
)
124+
);
116125

117126
// Act & Assess
118127
await expect(idempotentHandler.handle()).rejects.toThrow();
@@ -123,7 +132,17 @@ describe('Class IdempotencyHandler', () => {
123132
// Prepare
124133
const mockProcessIdempotency = jest
125134
.spyOn(persistenceStore, 'saveInProgress')
126-
.mockRejectedValue(new IdempotencyItemAlreadyExistsError());
135+
.mockRejectedValue(
136+
new IdempotencyItemAlreadyExistsError(
137+
'Failed to put record for already existing idempotency key: my-lambda-function#mocked-hash',
138+
new IdempotencyRecord({
139+
idempotencyKey: 'my-lambda-function#mocked-hash',
140+
status: IdempotencyRecordStatus.EXPIRED,
141+
payloadHash: 'different-hash',
142+
expiryTimestamp: Date.now() / 1000 - 1,
143+
})
144+
)
145+
);
127146
jest.spyOn(persistenceStore, 'getRecord').mockResolvedValue(
128147
new IdempotencyRecord({
129148
status: IdempotencyRecordStatus.EXPIRED,

packages/idempotency/tests/unit/idempotencyDecorator.test.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,13 @@ describe('Given a class with a function to decorate', (classWithLambdaHandler =
124124
let resultingError: Error;
125125
beforeEach(async () => {
126126
mockSaveInProgress.mockRejectedValue(
127-
new IdempotencyItemAlreadyExistsError()
127+
new IdempotencyItemAlreadyExistsError(
128+
'Failed to put record for already existing idempotency key: key',
129+
new IdempotencyRecord({
130+
idempotencyKey: 'key',
131+
status: IdempotencyRecordStatus.INPROGRESS,
132+
})
133+
)
128134
);
129135
const idempotencyOptions: IdempotencyRecordOptions = {
130136
idempotencyKey: 'key',
@@ -164,7 +170,13 @@ describe('Given a class with a function to decorate', (classWithLambdaHandler =
164170
let resultingError: Error;
165171
beforeEach(async () => {
166172
mockSaveInProgress.mockRejectedValue(
167-
new IdempotencyItemAlreadyExistsError()
173+
new IdempotencyItemAlreadyExistsError(
174+
'Failed to put record for already existing idempotency key: key',
175+
new IdempotencyRecord({
176+
idempotencyKey: 'key',
177+
status: IdempotencyRecordStatus.EXPIRED,
178+
})
179+
)
168180
);
169181
const idempotencyOptions: IdempotencyRecordOptions = {
170182
idempotencyKey: 'key',
@@ -203,7 +215,14 @@ describe('Given a class with a function to decorate', (classWithLambdaHandler =
203215
describe('When wrapping a function with previous execution that is COMPLETED', () => {
204216
beforeEach(async () => {
205217
mockSaveInProgress.mockRejectedValue(
206-
new IdempotencyItemAlreadyExistsError()
218+
new IdempotencyItemAlreadyExistsError(
219+
'Failed to put record for already existing idempotency key: key',
220+
new IdempotencyRecord({
221+
idempotencyKey: 'key',
222+
status: IdempotencyRecordStatus.COMPLETED,
223+
responseData: 'Hi',
224+
})
225+
)
207226
);
208227
const idempotencyOptions: IdempotencyRecordOptions = {
209228
idempotencyKey: 'key',

packages/idempotency/tests/unit/makeHandlerIdempotent.test.ts

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,19 @@ describe('Middleware: makeHandlerIdempotent', () => {
159159
).use(makeHandlerIdempotent(mockIdempotencyOptions));
160160
jest
161161
.spyOn(mockIdempotencyOptions.persistenceStore, 'saveInProgress')
162-
.mockRejectedValue(new IdempotencyItemAlreadyExistsError());
162+
.mockRejectedValue(
163+
new IdempotencyItemAlreadyExistsError(
164+
'Failed to put record for already existing idempotency key: idempotencyKey',
165+
new IdempotencyRecord({
166+
idempotencyKey: 'idempotencyKey',
167+
expiryTimestamp: Date.now() + 10000,
168+
inProgressExpiryTimestamp: 0,
169+
responseData: { response: false },
170+
payloadHash: 'payloadHash',
171+
status: IdempotencyRecordStatus.COMPLETED,
172+
})
173+
)
174+
);
163175
const stubRecord = new IdempotencyRecord({
164176
idempotencyKey: 'idempotencyKey',
165177
expiryTimestamp: Date.now() + 10000,
@@ -187,7 +199,19 @@ describe('Middleware: makeHandlerIdempotent', () => {
187199
).use(makeHandlerIdempotent(mockIdempotencyOptions));
188200
jest
189201
.spyOn(mockIdempotencyOptions.persistenceStore, 'saveInProgress')
190-
.mockRejectedValue(new IdempotencyItemAlreadyExistsError());
202+
.mockRejectedValue(
203+
new IdempotencyItemAlreadyExistsError(
204+
'Failed to put record for already existing idempotency key: idempotencyKey',
205+
new IdempotencyRecord({
206+
idempotencyKey: 'idempotencyKey',
207+
expiryTimestamp: Date.now() + 10000,
208+
inProgressExpiryTimestamp: 0,
209+
responseData: { response: false },
210+
payloadHash: 'payloadHash',
211+
status: IdempotencyRecordStatus.EXPIRED,
212+
})
213+
)
214+
);
191215
const stubRecordInconsistent = new IdempotencyRecord({
192216
idempotencyKey: 'idempotencyKey',
193217
expiryTimestamp: Date.now() + 10000,
@@ -223,7 +247,19 @@ describe('Middleware: makeHandlerIdempotent', () => {
223247
).use(makeHandlerIdempotent(mockIdempotencyOptions));
224248
jest
225249
.spyOn(mockIdempotencyOptions.persistenceStore, 'saveInProgress')
226-
.mockRejectedValue(new IdempotencyItemAlreadyExistsError());
250+
.mockRejectedValue(
251+
new IdempotencyItemAlreadyExistsError(
252+
'Failed to put record for already existing idempotency key: idempotencyKey',
253+
new IdempotencyRecord({
254+
idempotencyKey: 'idempotencyKey',
255+
expiryTimestamp: Date.now() + 10000,
256+
inProgressExpiryTimestamp: 0,
257+
responseData: { response: false },
258+
payloadHash: 'payloadHash',
259+
status: IdempotencyRecordStatus.EXPIRED,
260+
})
261+
)
262+
);
227263
const stubRecordInconsistent = new IdempotencyRecord({
228264
idempotencyKey: 'idempotencyKey',
229265
expiryTimestamp: Date.now() + 10000,

packages/idempotency/tests/unit/makeIdempotent.test.ts

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,19 @@ describe('Function: makeIdempotent', () => {
177177
);
178178
jest
179179
.spyOn(mockIdempotencyOptions.persistenceStore, 'saveInProgress')
180-
.mockRejectedValue(new IdempotencyItemAlreadyExistsError());
180+
.mockRejectedValue(
181+
new IdempotencyItemAlreadyExistsError(
182+
'Failed to put record for already existing idempotency key: idempotencyKey',
183+
new IdempotencyRecord({
184+
idempotencyKey: 'idempotencyKey',
185+
expiryTimestamp: Date.now() + 10000,
186+
inProgressExpiryTimestamp: 0,
187+
responseData: { response: false },
188+
payloadHash: 'payloadHash',
189+
status: IdempotencyRecordStatus.COMPLETED,
190+
})
191+
)
192+
);
181193
const stubRecord = new IdempotencyRecord({
182194
idempotencyKey: 'idempotencyKey',
183195
expiryTimestamp: Date.now() + 10000,
@@ -209,7 +221,19 @@ describe('Function: makeIdempotent', () => {
209221
);
210222
jest
211223
.spyOn(mockIdempotencyOptions.persistenceStore, 'saveInProgress')
212-
.mockRejectedValue(new IdempotencyItemAlreadyExistsError());
224+
.mockRejectedValue(
225+
new IdempotencyItemAlreadyExistsError(
226+
'Failed to put record for already existing idempotency key: idempotencyKey',
227+
new IdempotencyRecord({
228+
idempotencyKey: 'idempotencyKey',
229+
expiryTimestamp: Date.now() + 10000,
230+
inProgressExpiryTimestamp: 0,
231+
responseData: { response: false },
232+
payloadHash: 'payloadHash',
233+
status: IdempotencyRecordStatus.COMPLETED,
234+
})
235+
)
236+
);
213237
const stubRecordInconsistent = new IdempotencyRecord({
214238
idempotencyKey: 'idempotencyKey',
215239
expiryTimestamp: Date.now() + 10000,
@@ -249,7 +273,19 @@ describe('Function: makeIdempotent', () => {
249273
);
250274
jest
251275
.spyOn(mockIdempotencyOptions.persistenceStore, 'saveInProgress')
252-
.mockRejectedValue(new IdempotencyItemAlreadyExistsError());
276+
.mockRejectedValue(
277+
new IdempotencyItemAlreadyExistsError(
278+
'Failed to put record for already existing idempotency key: idempotencyKey',
279+
new IdempotencyRecord({
280+
idempotencyKey: 'idempotencyKey',
281+
expiryTimestamp: Date.now() + 10000,
282+
inProgressExpiryTimestamp: 0,
283+
responseData: { response: false },
284+
payloadHash: 'payloadHash',
285+
status: IdempotencyRecordStatus.EXPIRED,
286+
})
287+
)
288+
);
253289
const stubRecordInconsistent = new IdempotencyRecord({
254290
idempotencyKey: 'idempotencyKey',
255291
expiryTimestamp: Date.now() + 10000,

packages/idempotency/tests/unit/persistence/BasePersistenceLayer.test.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,17 @@ describe('Class: BasePersistenceLayer', () => {
407407
// Act & Assess
408408
await expect(
409409
persistenceLayer.saveInProgress({ foo: 'bar' })
410-
).rejects.toThrow(new IdempotencyItemAlreadyExistsError());
410+
).rejects.toThrow(
411+
new IdempotencyItemAlreadyExistsError(
412+
'Failed to put record for already existing idempotency key: my-lambda-function#mocked-hash',
413+
new IdempotencyRecord({
414+
idempotencyKey: 'my-lambda-function#mocked-hash',
415+
status: IdempotencyRecordStatus.EXPIRED,
416+
payloadHash: 'different-hash',
417+
expiryTimestamp: Date.now() / 1000 - 1,
418+
})
419+
)
420+
);
411421
expect(putRecordSpy).toHaveBeenCalledTimes(0);
412422
});
413423

packages/idempotency/tests/unit/persistence/DynamoDbPersistenceLayer.test.ts

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@ import type { DynamoDBPersistenceOptions } from '../../../src/types';
1313
import { IdempotencyRecordStatus } from '../../../src';
1414
import {
1515
DynamoDBClient,
16-
DynamoDBServiceException,
16+
//DynamoDBServiceException,
1717
PutItemCommand,
1818
GetItemCommand,
1919
UpdateItemCommand,
2020
DeleteItemCommand,
21+
ConditionalCheckFailedException,
2122
} from '@aws-sdk/client-dynamodb';
2223
import { marshall } from '@aws-sdk/util-dynamodb';
2324
import { mockClient } from 'aws-sdk-client-mock';
@@ -395,19 +396,32 @@ describe('Class: DynamoDBPersistenceLayer', () => {
395396
expiryTimestamp: 0,
396397
});
397398
client.on(PutItemCommand).rejects(
398-
new DynamoDBServiceException({
399-
$fault: 'client',
399+
new ConditionalCheckFailedException({
400+
//$fault: 'client',
400401
$metadata: {
401402
httpStatusCode: 400,
402403
requestId: 'someRequestId',
403404
},
404-
name: 'ConditionalCheckFailedException',
405+
message: 'Conditional check failed',
406+
Item: {
407+
id: { S: 'test-key' },
408+
status: { S: 'INPROGRESS' },
409+
expiration: { N: Date.now().toString() },
410+
},
411+
//name: 'ConditionalCheckFailedException',
405412
})
406413
);
407414

408415
// Act & Assess
409416
await expect(persistenceLayer._putRecord(record)).rejects.toThrowError(
410-
IdempotencyItemAlreadyExistsError
417+
new IdempotencyItemAlreadyExistsError(
418+
`Failed to put record for already existing idempotency key: ${record.idempotencyKey}`,
419+
new IdempotencyRecord({
420+
idempotencyKey: record.idempotencyKey,
421+
status: IdempotencyRecordStatus.EXPIRED,
422+
expiryTimestamp: Date.now() / 1000 - 1,
423+
})
424+
)
411425
);
412426
});
413427

@@ -676,4 +690,27 @@ describe('Class: DynamoDBPersistenceLayer', () => {
676690
});
677691
});
678692
});
693+
694+
//write test for when Item is undefined
695+
test('_putRecord throws Error when Item is undefined', async () => {
696+
// Prepare
697+
const persistenceLayer = new TestDynamoDBPersistenceLayer({
698+
tableName: dummyTableName,
699+
});
700+
const mockRecord = new IdempotencyRecord({
701+
idempotencyKey: 'test-key',
702+
status: 'INPROGRESS',
703+
expiryTimestamp: Date.now(),
704+
});
705+
706+
DynamoDBClient.prototype.send = jest.fn().mockRejectedValueOnce(
707+
new ConditionalCheckFailedException({
708+
message: 'Conditional check failed',
709+
$metadata: {},
710+
})
711+
);
712+
await expect(persistenceLayer._putRecord(mockRecord)).rejects.toThrowError(
713+
'Item is undefined'
714+
);
715+
});
679716
});

0 commit comments

Comments
 (0)