Skip to content

Commit f88b9e5

Browse files
committed
add more tests
1 parent d03af62 commit f88b9e5

2 files changed

Lines changed: 153 additions & 7 deletions

File tree

packages/sns/lib/utils/snsInitter.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -180,13 +180,22 @@ export async function initSnsSqs(
180180
}
181181
return { isAvailable: true, result: result.result }
182182
},
183-
}).catch((error) => {
184-
extraParams?.logger?.error({
185-
message: 'Background polling for SQS queue failed',
186-
queueUrl,
187-
error,
188-
})
189183
})
184+
.then((result) => {
185+
// If queue was immediately available, waitForResource returns the result
186+
// but doesn't call onResourceAvailable, so we handle it here
187+
if (result !== undefined) {
188+
queueAvailable = true
189+
notifyIfBothReady()
190+
}
191+
})
192+
.catch((error) => {
193+
extraParams?.logger?.error({
194+
message: 'Background polling for SQS queue failed',
195+
queueUrl,
196+
error,
197+
})
198+
})
190199

191200
return {
192201
subscriptionArn: locatorConfig.subscriptionArn,

packages/sns/test/consumers/SnsSqsPermissionConsumer.startupResourcePolling.spec.ts

Lines changed: 138 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
} from '@message-queue-toolkit/core'
1010
import { assertQueue, deleteQueue } from '@message-queue-toolkit/sqs'
1111
import type { AwilixContainer } from 'awilix'
12-
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from 'vitest'
12+
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'
1313
import {
1414
AbstractSnsSqsConsumer,
1515
type SNSSQSConsumerDependencies,
@@ -221,6 +221,143 @@ describe('SnsSqsPermissionConsumer - startupResourcePollingConfig', () => {
221221
})
222222
})
223223

224+
describe('when nonBlocking mode is enabled', () => {
225+
it('returns immediately when both resources are available on first check', async () => {
226+
// Create queue first, then topic (order matters for LocalStack)
227+
await assertQueue(sqsClient, { QueueName: queueName })
228+
const topicArn = await assertTopic(snsClient, stsClient, { Name: topicName })
229+
230+
const consumer = new TestStartupResourcePollingConsumer(diContainer.cradle, {
231+
locatorConfig: {
232+
topicArn,
233+
queueUrl,
234+
subscriptionArn:
235+
'arn:aws:sns:eu-west-1:000000000000:dummy:bdf640a2-bedf-475a-98b8-758b88c87395',
236+
startupResourcePolling: {
237+
enabled: true,
238+
pollingIntervalMs: 100,
239+
timeoutMs: 5000,
240+
nonBlocking: true,
241+
},
242+
},
243+
})
244+
245+
await consumer.init()
246+
247+
expect(consumer.subscriptionProps.topicArn).toBe(topicArn)
248+
expect(consumer.subscriptionProps.queueUrl).toBe(queueUrl)
249+
})
250+
251+
it('returns immediately when topic is not available', async () => {
252+
// Create queue but not topic
253+
await assertQueue(sqsClient, { QueueName: queueName })
254+
255+
const consumer = new TestStartupResourcePollingConsumer(diContainer.cradle, {
256+
locatorConfig: {
257+
topicName,
258+
queueUrl,
259+
subscriptionArn:
260+
'arn:aws:sns:eu-west-1:000000000000:dummy:bdf640a2-bedf-475a-98b8-758b88c87395',
261+
startupResourcePolling: {
262+
enabled: true,
263+
pollingIntervalMs: 100,
264+
timeoutMs: 5000,
265+
nonBlocking: true,
266+
},
267+
},
268+
creationConfig: {
269+
queue: { QueueName: queueName },
270+
},
271+
})
272+
273+
// Init should return immediately even though topic doesn't exist
274+
await consumer.init()
275+
276+
// queueName should still be set
277+
expect(consumer.subscriptionProps.queueName).toBe(queueName)
278+
})
279+
280+
it('returns immediately when queue is not available', async () => {
281+
// Create topic but not queue
282+
const topicArn = await assertTopic(snsClient, stsClient, { Name: topicName })
283+
284+
const consumer = new TestStartupResourcePollingConsumer(diContainer.cradle, {
285+
locatorConfig: {
286+
topicArn,
287+
queueUrl,
288+
subscriptionArn:
289+
'arn:aws:sns:eu-west-1:000000000000:dummy:bdf640a2-bedf-475a-98b8-758b88c87395',
290+
startupResourcePolling: {
291+
enabled: true,
292+
pollingIntervalMs: 100,
293+
timeoutMs: 5000,
294+
nonBlocking: true,
295+
},
296+
},
297+
})
298+
299+
// Init should return immediately even though queue doesn't exist
300+
await consumer.init()
301+
302+
expect(consumer.subscriptionProps.topicArn).toBe(topicArn)
303+
})
304+
305+
it('invokes onResourcesReady callback when both resources become available in background', async () => {
306+
// Test at the initter level since AbstractSnsSqsConsumer doesn't expose the callback
307+
const { initSnsSqs } = await import('../../lib/utils/snsInitter.ts')
308+
309+
let callbackInvoked = false
310+
let callbackTopicArn: string | undefined
311+
let callbackQueueUrl: string | undefined
312+
313+
// Create queue but not topic
314+
await assertQueue(sqsClient, { QueueName: queueName })
315+
316+
const result = await initSnsSqs(
317+
sqsClient,
318+
snsClient,
319+
stsClient,
320+
{
321+
topicName,
322+
queueUrl,
323+
subscriptionArn:
324+
'arn:aws:sns:eu-west-1:000000000000:dummy:bdf640a2-bedf-475a-98b8-758b88c87395',
325+
startupResourcePolling: {
326+
enabled: true,
327+
pollingIntervalMs: 50,
328+
timeoutMs: 5000,
329+
nonBlocking: true,
330+
},
331+
},
332+
undefined,
333+
undefined,
334+
{
335+
onResourcesReady: ({ topicArn, queueUrl: url }) => {
336+
callbackInvoked = true
337+
callbackTopicArn = topicArn
338+
callbackQueueUrl = url
339+
},
340+
},
341+
)
342+
343+
expect(result.resourcesReady).toBe(false)
344+
345+
// Create topic after init returns
346+
await assertTopic(snsClient, stsClient, { Name: topicName })
347+
348+
// Wait for callback to be invoked using vi.waitFor (more reliable than fixed timeout)
349+
await vi.waitFor(
350+
() => {
351+
expect(callbackInvoked).toBe(true)
352+
},
353+
{ timeout: 2000, interval: 50 },
354+
)
355+
356+
expect(callbackTopicArn).toBeDefined()
357+
expect(callbackQueueUrl).toBe(queueUrl)
358+
})
359+
})
360+
224361
describe('when startupResourcePolling is disabled', () => {
225362
it('throws immediately when topic does not exist', async () => {
226363
// Create queue but not topic

0 commit comments

Comments
 (0)