Skip to content

Commit 1d12b94

Browse files
committed
Fix unit tests
1 parent 46dd8ec commit 1d12b94

2 files changed

Lines changed: 74 additions & 29 deletions

File tree

packages/postDatedLambda/tests/testOrchestration.test.ts

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,29 @@ jest.unstable_mockModule("../src/sqs", () => {
3434
import {Logger} from "@aws-lambda-powertools/logger"
3535

3636
import {createMockPostModifiedDataItem} from "./testUtils"
37-
import {BatchProcessingResult, PostDatedSQSMessage} from "../src/types"
37+
import {BatchProcessingResult, PostDatedProcessingResult, PostDatedSQSMessage} from "../src/types"
3838

3939
// Import the orchestration module after mocking dependencies
4040
const {processMessages, processPostDatedQueue} = await import("../src/orchestration")
4141

4242
const logger = new Logger({serviceName: "postDatedLambdaTEST"})
4343

44+
// I needed to move these functions out of the describe block since it was too deeply nested.
45+
function createBatch(ids: Array<string>): Array<PostDatedSQSMessage> {
46+
return ids.map((id) => ({
47+
MessageId: id,
48+
Body: `Message ${id}`,
49+
prescriptionData: createMockPostModifiedDataItem({})
50+
}))
51+
}
52+
53+
function enrich(messages: Array<PostDatedSQSMessage>) {
54+
return messages.map((message) => ({
55+
...message,
56+
existingRecords: []
57+
}))
58+
}
59+
4460
describe("orchestration", () => {
4561
describe("processMessages", () => {
4662
beforeEach(() => {
@@ -50,30 +66,36 @@ describe("orchestration", () => {
5066
it("should process messages and categorize them correctly", async () => {
5167
const mockMessages: Array<PostDatedSQSMessage> = [
5268
{MessageId: "1", Body: "Message 1", prescriptionData: createMockPostModifiedDataItem({})},
53-
{MessageId: "2", Body: "Message 2", prescriptionData: createMockPostModifiedDataItem({})}
69+
{MessageId: "2", Body: "Message 2", prescriptionData: createMockPostModifiedDataItem({})},
70+
{MessageId: "3", Body: "Message 3", prescriptionData: createMockPostModifiedDataItem({})}
5471
]
5572

5673
// Mock the enrichment function to return the same messages
5774
mockEnrichMessagesWithExistingRecords.mockReturnValueOnce(mockMessages)
5875

5976
// Mock processMessage to return true for first message and false for second
60-
mockProcessMessage.mockReturnValueOnce(true)
61-
mockProcessMessage.mockReturnValueOnce(false)
77+
mockProcessMessage
78+
.mockReturnValueOnce(PostDatedProcessingResult.MATURED)
79+
.mockReturnValueOnce(PostDatedProcessingResult.IMMATURE)
80+
.mockReturnValueOnce(PostDatedProcessingResult.IGNORE)
6281

6382
const result = await processMessages(mockMessages, logger)
6483

6584
expect(result.maturedPrescriptionUpdates).toHaveLength(1)
6685
expect(result.maturedPrescriptionUpdates[0].MessageId).toBe("1")
6786
expect(result.immaturePrescriptionUpdates).toHaveLength(1)
6887
expect(result.immaturePrescriptionUpdates[0].MessageId).toBe("2")
88+
expect(result.ignoredPrescriptionUpdates).toHaveLength(1)
89+
expect(result.ignoredPrescriptionUpdates[0].MessageId).toBe("3")
6990
})
7091

7192
it("should handle empty message array", async () => {
93+
mockEnrichMessagesWithExistingRecords.mockReturnValueOnce([])
7294
const result = await processMessages([], logger)
7395

7496
expect(result.maturedPrescriptionUpdates).toHaveLength(0)
7597
expect(result.immaturePrescriptionUpdates).toHaveLength(0)
76-
expect(mockEnrichMessagesWithExistingRecords).not.toHaveBeenCalled()
98+
expect(result.ignoredPrescriptionUpdates).toHaveLength(0)
7799
})
78100

79101
it("should log errors and mark messages immature when processing throws", async () => {
@@ -84,8 +106,8 @@ describe("orchestration", () => {
84106

85107
mockEnrichMessagesWithExistingRecords.mockReturnValueOnce(mockMessages)
86108
mockProcessMessage
87-
.mockReturnValueOnce(true)
88-
.mockImplementationOnce(async () => {
109+
.mockReturnValueOnce(PostDatedProcessingResult.MATURED)
110+
.mockImplementationOnce(() => {
89111
throw new Error("processing failed")
90112
})
91113

@@ -94,6 +116,7 @@ describe("orchestration", () => {
94116

95117
expect(result.maturedPrescriptionUpdates).toHaveLength(1)
96118
expect(result.immaturePrescriptionUpdates).toHaveLength(1)
119+
expect(result.ignoredPrescriptionUpdates).toHaveLength(0)
97120
expect(result.immaturePrescriptionUpdates[0].MessageId).toBe("2")
98121
expect(errorSpy).toHaveBeenCalledWith(
99122
"Error processing message",
@@ -113,7 +136,7 @@ describe("orchestration", () => {
113136
}
114137

115138
mockEnrichMessagesWithExistingRecords.mockReturnValueOnce([enrichedMessage])
116-
mockProcessMessage.mockReturnValue(true)
139+
mockProcessMessage.mockReturnValue(PostDatedProcessingResult.MATURED)
117140

118141
await processMessages(mockMessages, logger)
119142

@@ -139,7 +162,7 @@ describe("orchestration", () => {
139162

140163
mockReceivePostDatedSQSMessages.mockReturnValueOnce(mockMessages)
141164
mockEnrichMessagesWithExistingRecords.mockReturnValueOnce(mockEnrichedMessages)
142-
mockProcessMessage.mockReturnValue(true)
165+
mockProcessMessage.mockReturnValue(PostDatedProcessingResult.MATURED)
143166

144167
await processPostDatedQueue(logger)
145168

@@ -179,7 +202,7 @@ describe("orchestration", () => {
179202
mockProcessMessage.mockImplementation(async () => {
180203
// Overrun by a second
181204
jest.advanceTimersByTime(MAX_QUEUE_RUNTIME + 1000)
182-
return true
205+
return PostDatedProcessingResult.MATURED
183206
})
184207

185208
await processPostDatedQueue(logger)
@@ -189,23 +212,10 @@ describe("orchestration", () => {
189212
})
190213

191214
it("should continue processing batches until message count drops below threshold", async () => {
192-
const createBatch = (ids: Array<string>) =>
193-
ids.map((id) => ({
194-
MessageId: id,
195-
Body: `Message ${id}`,
196-
prescriptionData: createMockPostModifiedDataItem({})
197-
}))
198-
199215
const batch1 = createBatch(["1", "2", "3"])
200216
const batch2 = createBatch(["4", "5", "6"])
201217
const batch3 = createBatch(["7"])
202218

203-
const enrich = (messages: Array<PostDatedSQSMessage>) =>
204-
messages.map((message) => ({
205-
...message,
206-
existingRecords: []
207-
}))
208-
209219
mockReceivePostDatedSQSMessages
210220
.mockReturnValueOnce(batch1)
211221
.mockReturnValueOnce(batch2)
@@ -214,7 +224,7 @@ describe("orchestration", () => {
214224
.mockReturnValueOnce(enrich(batch1))
215225
.mockReturnValueOnce(enrich(batch2))
216226
.mockReturnValueOnce(enrich(batch3))
217-
mockProcessMessage.mockReturnValue(true)
227+
mockProcessMessage.mockReturnValue(PostDatedProcessingResult.MATURED)
218228

219229
await processPostDatedQueue(logger)
220230

@@ -227,16 +237,14 @@ describe("orchestration", () => {
227237

228238
it("should treat empty receives as drained batches", async () => {
229239
mockReceivePostDatedSQSMessages.mockReturnValueOnce([])
240+
mockEnrichMessagesWithExistingRecords.mockReturnValueOnce([])
230241

231242
await processPostDatedQueue(logger)
232243

233-
expect(mockEnrichMessagesWithExistingRecords).not.toHaveBeenCalled()
234-
expect(mockProcessMessage).not.toHaveBeenCalled()
235244
expect(mockHandleProcessedMessages).toHaveBeenCalledTimes(1)
236245
const [result] = mockHandleProcessedMessages.mock.calls[0] as [BatchProcessingResult]
237246
expect(result.maturedPrescriptionUpdates).toHaveLength(0)
238247
expect(result.immaturePrescriptionUpdates).toHaveLength(0)
239-
expect(mockReportQueueStatus).not.toHaveBeenCalled()
240248
})
241249
})
242250
})

packages/postDatedLambda/tests/testSqs.test.ts

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,8 @@ describe("sqs", () => {
373373

374374
const batchResult: BatchProcessingResult = {
375375
maturedPrescriptionUpdates: maturedMessages,
376-
immaturePrescriptionUpdates: immatureMessages
376+
immaturePrescriptionUpdates: immatureMessages,
377+
ignoredPrescriptionUpdates: []
377378
}
378379

379380
// Mock SQS responses
@@ -403,7 +404,8 @@ describe("sqs", () => {
403404
it("should handle empty matured and immature message arrays gracefully", async () => {
404405
const batchResult: BatchProcessingResult = {
405406
maturedPrescriptionUpdates: [],
406-
immaturePrescriptionUpdates: []
407+
immaturePrescriptionUpdates: [],
408+
ignoredPrescriptionUpdates: []
407409
}
408410

409411
await handleProcessedMessages(batchResult, logger)
@@ -412,5 +414,40 @@ describe("sqs", () => {
412414
expect(infoSpy).not.toHaveBeenCalledWith("Successfully removed")
413415
expect(infoSpy).not.toHaveBeenCalledWith("Returning messages to queue with timeouts", expect.anything())
414416
})
417+
418+
it("should remove ignored messages from the queue so they are not reprocessed", async () => {
419+
const testUrl = "https://sqs.us-east-1.amazonaws.com/123456789012/test-queue"
420+
process.env.POST_DATED_PRESCRIPTIONS_SQS_QUEUE_URL = testUrl
421+
422+
const ignoredMessages: Array<PostDatedSQSMessage> = [
423+
{
424+
MessageId: "ignored-1",
425+
ReceiptHandle: "ignored-handle-1",
426+
prescriptionData: createMockPostModifiedDataItem({}),
427+
Attributes: {MessageDeduplicationId: "dedup-ignored", MessageGroupId: "group-ignored"}
428+
}
429+
]
430+
431+
const batchResult: BatchProcessingResult = {
432+
maturedPrescriptionUpdates: [],
433+
immaturePrescriptionUpdates: [],
434+
ignoredPrescriptionUpdates: ignoredMessages
435+
}
436+
437+
mockSend.mockReturnValueOnce({
438+
Successful: ignoredMessages.map((msg) => ({Id: msg.MessageId})),
439+
Failed: []
440+
})
441+
442+
await handleProcessedMessages(batchResult, logger)
443+
444+
expect(mockSend).toHaveBeenCalledTimes(1)
445+
446+
const deleteCommand = mockSend.mock.calls[0][0] as {input: {Entries: Array<{Id: string; ReceiptHandle: string}>}}
447+
expect(deleteCommand.input.Entries).toEqual([
448+
{Id: "ignored-1", ReceiptHandle: "ignored-handle-1"}
449+
])
450+
expect(infoSpy).toHaveBeenCalledWith("Successfully removed 1 messages from SQS")
451+
})
415452
})
416453
})

0 commit comments

Comments
 (0)