@defra-fish/sqs-receiver-service 1.61.0-rc.9 → 1.62.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -4
- package/src/__tests__/delete-messages.spec.js +50 -3
- package/src/__tests__/read-queue.spec.js +96 -21
- package/src/__tests__/receiver.spec.js +52 -6
- package/src/__tests__/show_queue-statistics.spec.js +21 -6
- package/src/delete-messages.js +1 -1
- package/src/read-queue.js +5 -7
- package/src/show-queue-statistics.js +1 -1
- package/src/__mocks__/aws-sdk.js +0 -190
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@defra-fish/sqs-receiver-service",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.62.0-rc.0",
|
|
4
4
|
"description": "SQS Receiver service",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
7
|
-
"node": ">=
|
|
7
|
+
"node": ">=20"
|
|
8
8
|
},
|
|
9
9
|
"keywords": [
|
|
10
10
|
"rod",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"test": "echo \"Error: run tests from root\" && exit 1"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@defra-fish/connectors-lib": "1.
|
|
38
|
+
"@defra-fish/connectors-lib": "1.62.0-rc.0",
|
|
39
39
|
"debug": "^4.3.1",
|
|
40
40
|
"joi": "^17.3.0",
|
|
41
41
|
"node-fetch": "^2.6.1",
|
|
@@ -44,5 +44,5 @@
|
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"pm2": "^4.5.6"
|
|
46
46
|
},
|
|
47
|
-
"gitHead": "
|
|
47
|
+
"gitHead": "d56e1a0d0f4b22f1dded800c0ed511b737cb91a7"
|
|
48
48
|
}
|
|
@@ -1,9 +1,33 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
import deleteMessages from '../delete-messages'
|
|
4
|
-
import AWS from '
|
|
4
|
+
import { AWS } from '@defra-fish/connectors-lib'
|
|
5
|
+
const { sqs } = AWS.mock.results[0].value
|
|
6
|
+
|
|
7
|
+
const getSampleDeleteMessageBatchResponse = (successfulIds, failedIds = []) => ({
|
|
8
|
+
ResponseMetadata: {
|
|
9
|
+
RequestId: '00000000-0000-0000-0000-000000000000'
|
|
10
|
+
},
|
|
11
|
+
Successful: successfulIds.map(Id => ({ Id })),
|
|
12
|
+
Failed: failedIds.map(Id => ({ Id }))
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
jest.mock('@defra-fish/connectors-lib', () => ({
|
|
16
|
+
AWS: jest.fn(() => ({
|
|
17
|
+
sqs: {
|
|
18
|
+
deleteMessageBatch: jest.fn(() => {})
|
|
19
|
+
}
|
|
20
|
+
}))
|
|
21
|
+
}))
|
|
22
|
+
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
sqs.deleteMessageBatch.mockClear()
|
|
25
|
+
})
|
|
5
26
|
|
|
6
27
|
test('Delete messages successfully', async () => {
|
|
28
|
+
sqs.deleteMessageBatch.mockResolvedValueOnce(
|
|
29
|
+
getSampleDeleteMessageBatchResponse(['58f6f3c9-97f8-405a-a3a7-5ac467277521', '58f6f3c9-97f8-405a-a3a7-5ac467277522'])
|
|
30
|
+
)
|
|
7
31
|
const results = await deleteMessages('http://0.0.0.0:0000/queue', [
|
|
8
32
|
{
|
|
9
33
|
id: '58f6f3c9-97f8-405a-a3a7-5ac467277521',
|
|
@@ -26,6 +50,7 @@ test('Delete messages successfully', async () => {
|
|
|
26
50
|
})
|
|
27
51
|
|
|
28
52
|
test('Delete messages nothing to delete', async () => {
|
|
53
|
+
sqs.deleteMessageBatch.mockResolvedValueOnce(getSampleDeleteMessageBatchResponse([]))
|
|
29
54
|
const results = await deleteMessages('http://0.0.0.0:0000/queue', [
|
|
30
55
|
{
|
|
31
56
|
id: '58f6f3c9-97f8-405a-a3a7-5ac467277521',
|
|
@@ -45,11 +70,14 @@ test('Delete messages nothing to delete', async () => {
|
|
|
45
70
|
])
|
|
46
71
|
|
|
47
72
|
expect(results).toBeUndefined()
|
|
73
|
+
sqs.deleteMessageBatch.mockReset()
|
|
48
74
|
})
|
|
49
75
|
|
|
50
76
|
test('Delete messages with failures', async () => {
|
|
51
77
|
const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {})
|
|
52
|
-
|
|
78
|
+
sqs.deleteMessageBatch.mockResolvedValueOnce(
|
|
79
|
+
getSampleDeleteMessageBatchResponse([], ['58f6f3c9-97f8-405a-a3a7-5ac467277521', '58f6f3c9-97f8-405a-a3a7-5ac467277522'])
|
|
80
|
+
)
|
|
53
81
|
const results = await deleteMessages('http://0.0.0.0:0000/queue', [
|
|
54
82
|
{
|
|
55
83
|
id: '58f6f3c9-97f8-405a-a3a7-5ac467277521',
|
|
@@ -73,7 +101,9 @@ test('Delete messages with failures', async () => {
|
|
|
73
101
|
})
|
|
74
102
|
|
|
75
103
|
test('Delete message does not throw exception', async () => {
|
|
76
|
-
|
|
104
|
+
const exception = new Error('Not Found')
|
|
105
|
+
exception.code = 404
|
|
106
|
+
sqs.deleteMessageBatch.mockRejectedValueOnce(exception)
|
|
77
107
|
|
|
78
108
|
const result = await deleteMessages('http://0.0.0.0:0000/queue', [
|
|
79
109
|
{
|
|
@@ -84,3 +114,20 @@ test('Delete message does not throw exception', async () => {
|
|
|
84
114
|
])
|
|
85
115
|
expect(result).toBeUndefined()
|
|
86
116
|
})
|
|
117
|
+
|
|
118
|
+
test('Delete message batch logs exception with console.error', async () => {
|
|
119
|
+
const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {})
|
|
120
|
+
const exception = new Error('Not Found')
|
|
121
|
+
exception.code = 404
|
|
122
|
+
const url = 'http://0.0.0.0:0000/queue'
|
|
123
|
+
sqs.deleteMessageBatch.mockRejectedValueOnce(exception)
|
|
124
|
+
|
|
125
|
+
await deleteMessages(url, [
|
|
126
|
+
{
|
|
127
|
+
id: '58f6f3c9-97f8-405a-a3a7-5ac467277521',
|
|
128
|
+
handle: '58f6f3c9-97f8-405a-a3a7-5ac467277521#03f003bc-7770-41c2-9217-aed966b578b1',
|
|
129
|
+
status: 200
|
|
130
|
+
}
|
|
131
|
+
])
|
|
132
|
+
expect(consoleError).toHaveBeenCalledWith('Error deleting messages for %s: %o', url, exception)
|
|
133
|
+
})
|
|
@@ -1,19 +1,73 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
import readQueue from '../read-queue'
|
|
4
|
-
import AWS from '
|
|
4
|
+
import { AWS } from '@defra-fish/connectors-lib'
|
|
5
|
+
const { sqs } = AWS.mock.results[0].value
|
|
6
|
+
|
|
7
|
+
jest.mock('@defra-fish/connectors-lib', () => ({
|
|
8
|
+
AWS: jest.fn(() => ({
|
|
9
|
+
sqs: {
|
|
10
|
+
receiveMessage: jest.fn(() => ({ Messages: [] }))
|
|
11
|
+
}
|
|
12
|
+
}))
|
|
13
|
+
}))
|
|
14
|
+
|
|
15
|
+
const getSampleError = (httpStatusCode = undefined) => {
|
|
16
|
+
const error = new Error('Queue error')
|
|
17
|
+
if (httpStatusCode) {
|
|
18
|
+
error.$metadata = { httpStatusCode }
|
|
19
|
+
}
|
|
20
|
+
return error
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
sqs.receiveMessage.mockClear()
|
|
25
|
+
})
|
|
5
26
|
|
|
6
27
|
test('Nothing queued', async () => {
|
|
7
|
-
AWS.__mockEmptyQueue()
|
|
8
28
|
const messages = await readQueue('http://0.0.0.0:0000/queue')
|
|
9
29
|
expect(messages).toHaveLength(0)
|
|
10
30
|
})
|
|
11
31
|
|
|
32
|
+
test.each`
|
|
33
|
+
queueUrl | visibilityTimeoutMs | waitTimeMs | expectedVTS | expectedWTS
|
|
34
|
+
${'http://0.0.0.0:0000/queue'} | ${1000} | ${2000} | ${1} | ${2}
|
|
35
|
+
${'http://1.2.3.4:5432/line'} | ${3000} | ${4000} | ${3} | ${4}
|
|
36
|
+
${'http://9.8.7.6:1234/joinThe'} | ${7000} | ${20000} | ${7} | ${20}
|
|
37
|
+
`(
|
|
38
|
+
'Specifies message configuration: queue url $queueUrl read with visibility timeout $expectedVTS seconds and a wait time of $expectedWTS seconds',
|
|
39
|
+
async ({ queueUrl, visibilityTimeoutMs, waitTimeMs, expectedVTS, expectedWTS }) => {
|
|
40
|
+
await readQueue(queueUrl, visibilityTimeoutMs, waitTimeMs)
|
|
41
|
+
expect(sqs.receiveMessage).toHaveBeenCalledWith(
|
|
42
|
+
expect.objectContaining({
|
|
43
|
+
QueueUrl: queueUrl,
|
|
44
|
+
MaxNumberOfMessages: 10,
|
|
45
|
+
MessageAttributeNames: ['/*'],
|
|
46
|
+
AttributeNames: ['MessageGroupId'],
|
|
47
|
+
VisibilityTimeout: expectedVTS,
|
|
48
|
+
WaitTimeSeconds: expectedWTS
|
|
49
|
+
})
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
)
|
|
53
|
+
|
|
12
54
|
test('One message queued', async () => {
|
|
13
|
-
|
|
55
|
+
sqs.receiveMessage.mockResolvedValueOnce({
|
|
56
|
+
Messages: [
|
|
57
|
+
{
|
|
58
|
+
MessageId: '15eb8abc-c7c1-4167-9590-839c8feed6dd',
|
|
59
|
+
ReceiptHandle: '15eb8abc-c7c1-4167-9590-839c8feed6dd#9be8971c-f9a9-4bb2-8515-98cdab660e1b',
|
|
60
|
+
MD5OfBody: '640ad880b5be372fcb5c5ad8b5eb50af',
|
|
61
|
+
Body: '{"id":"7f6e04fe-4cec-4f40-b763-8c66d71062d9"}',
|
|
62
|
+
Attributes: {
|
|
63
|
+
MessageGroupId: 'service-1'
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
})
|
|
14
68
|
const messages = await readQueue('http://0.0.0.0:0000/queue')
|
|
15
69
|
expect(messages).toHaveLength(1)
|
|
16
|
-
expect(messages).
|
|
70
|
+
expect(messages[0]).toMatchObject({
|
|
17
71
|
MessageId: '15eb8abc-c7c1-4167-9590-839c8feed6dd',
|
|
18
72
|
ReceiptHandle: '15eb8abc-c7c1-4167-9590-839c8feed6dd#9be8971c-f9a9-4bb2-8515-98cdab660e1b',
|
|
19
73
|
MD5OfBody: '640ad880b5be372fcb5c5ad8b5eb50af',
|
|
@@ -25,29 +79,50 @@ test('One message queued', async () => {
|
|
|
25
79
|
})
|
|
26
80
|
|
|
27
81
|
test('Five messages queued', async () => {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
82
|
+
const messages = Array(5)
|
|
83
|
+
.fill(null)
|
|
84
|
+
.map((_, i) => ({
|
|
85
|
+
MessageId: `msg-${i}`,
|
|
86
|
+
ReceiptHandle: `handle-${i}`,
|
|
87
|
+
MD5OfBody: 'hash',
|
|
88
|
+
Body: '{}',
|
|
89
|
+
Attributes: { MessageGroupId: 'service-1' }
|
|
90
|
+
}))
|
|
91
|
+
sqs.receiveMessage.mockResolvedValueOnce({ Messages: messages })
|
|
92
|
+
const result = await readQueue('http://0.0.0.0:0000/queue')
|
|
93
|
+
expect(result).toHaveLength(5)
|
|
31
94
|
})
|
|
32
95
|
|
|
33
|
-
test(
|
|
96
|
+
test.each([
|
|
97
|
+
['when error contains http status code', 500],
|
|
98
|
+
["when error doesn't contain http status code", undefined]
|
|
99
|
+
])('Writes error to console %s', async (_d, httpStatusCode) => {
|
|
34
100
|
const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {})
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
101
|
+
const e = getSampleError(httpStatusCode)
|
|
102
|
+
sqs.receiveMessage.mockRejectedValueOnce(e)
|
|
103
|
+
try {
|
|
104
|
+
await readQueue('http://0.0.0.0:0000/queue')
|
|
105
|
+
} catch {
|
|
106
|
+
// swallow error (if it's thrown) as we're not interested in it
|
|
42
107
|
}
|
|
43
|
-
await expect(check()).rejects.toThrow(Error)
|
|
44
108
|
expect(consoleError).toHaveBeenCalled()
|
|
45
109
|
})
|
|
46
110
|
|
|
47
|
-
test('
|
|
48
|
-
|
|
49
|
-
|
|
111
|
+
test('Handles queue errors gracefully', async () => {
|
|
112
|
+
jest.spyOn(console, 'error').mockImplementation(() => {})
|
|
113
|
+
sqs.receiveMessage.mockRejectedValueOnce(getSampleError(500))
|
|
50
114
|
const result = await readQueue('http://0.0.0.0:0000/queue')
|
|
51
|
-
expect(result).
|
|
52
|
-
|
|
115
|
+
expect(result).toEqual([])
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
test("If error doesn't contain an HTTP status code, it is re-thrown", async () => {
|
|
119
|
+
jest.spyOn(console, 'error').mockImplementation(() => {})
|
|
120
|
+
sqs.receiveMessage.mockRejectedValueOnce(getSampleError())
|
|
121
|
+
await expect(readQueue('http://0.0.0.0:0000/queue')).rejects.toThrow('Queue error')
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
test("messages default to an empty array if messages key isn't available on receiveMessage return value", async () => {
|
|
125
|
+
sqs.receiveMessage.mockResolvedValueOnce({})
|
|
126
|
+
const result = await readQueue('http://0.0.0.0:0000/queue')
|
|
127
|
+
expect(result).toEqual([])
|
|
53
128
|
})
|
|
@@ -1,13 +1,57 @@
|
|
|
1
|
-
import AWS from 'aws-sdk'
|
|
2
1
|
import fetch from 'node-fetch'
|
|
3
2
|
import testEnv from '../../test-env'
|
|
3
|
+
import { AWS } from '@defra-fish/connectors-lib'
|
|
4
|
+
import { v4 as uuidv4 } from 'uuid'
|
|
5
|
+
|
|
6
|
+
jest.mock('@defra-fish/connectors-lib', () => {
|
|
7
|
+
const AWS = jest.fn(() => ({
|
|
8
|
+
sqs: {
|
|
9
|
+
getQueueAttributes: jest.fn(() => ({
|
|
10
|
+
Attributes: {
|
|
11
|
+
ApproximateNumberOfMessagesDelayed: 0,
|
|
12
|
+
ApproximateNumberOfMessagesNotVisible: 0,
|
|
13
|
+
ApproximateNumberOfMessages: 0
|
|
14
|
+
}
|
|
15
|
+
})),
|
|
16
|
+
receiveMessage: jest.fn(() => ({
|
|
17
|
+
Messages: []
|
|
18
|
+
})),
|
|
19
|
+
send: jest.fn()
|
|
20
|
+
}
|
|
21
|
+
}))
|
|
22
|
+
return { AWS }
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const getSampleMessages = (number = 1) => {
|
|
26
|
+
const Messages = []
|
|
27
|
+
for (let i = 0; i < number; i++) {
|
|
28
|
+
Messages.push({
|
|
29
|
+
MessageId: uuidv4(),
|
|
30
|
+
ReceiptHandle: '15eb8abc-c7c1-4167-9590-839c8feed6dd#9be8971c-f9a9-4bb2-8515-98cdab660e1b',
|
|
31
|
+
Body: `{"id":"${uuidv4()}"}`,
|
|
32
|
+
Attributes: {
|
|
33
|
+
MessageGroupId: 'service-1'
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
ResponseMetadata: {
|
|
39
|
+
RequestId: '00000000-0000-0000-0000-000000000000'
|
|
40
|
+
},
|
|
41
|
+
Messages
|
|
42
|
+
}
|
|
43
|
+
}
|
|
4
44
|
|
|
5
45
|
let receiver
|
|
46
|
+
let sqs
|
|
6
47
|
|
|
7
48
|
beforeEach(() => {
|
|
8
49
|
jest.clearAllMocks()
|
|
9
50
|
process.env = Object.assign(process.env, testEnv)
|
|
10
51
|
receiver = require('../receiver').default
|
|
52
|
+
if (!sqs) {
|
|
53
|
+
sqs = AWS.mock.results[0].value.sqs
|
|
54
|
+
}
|
|
11
55
|
})
|
|
12
56
|
|
|
13
57
|
afterAll(() => {
|
|
@@ -15,25 +59,24 @@ afterAll(() => {
|
|
|
15
59
|
})
|
|
16
60
|
|
|
17
61
|
test('One message: completes without error', async () => {
|
|
18
|
-
|
|
62
|
+
sqs.receiveMessage.mockResolvedValueOnce(getSampleMessages())
|
|
19
63
|
fetch.__goodResult()
|
|
20
64
|
await expect(receiver()).resolves.toBeUndefined()
|
|
21
65
|
})
|
|
22
66
|
|
|
23
67
|
test('No messages: complete without error', async () => {
|
|
24
|
-
AWS.__mockEmptyQueue()
|
|
25
68
|
fetch.__goodResult()
|
|
26
69
|
await expect(receiver()).resolves.toBeUndefined()
|
|
27
70
|
})
|
|
28
71
|
|
|
29
72
|
test('10 messages: complete without error', async () => {
|
|
30
|
-
|
|
73
|
+
sqs.receiveMessage.mockResolvedValueOnce(getSampleMessages(10))
|
|
31
74
|
fetch.__goodResult()
|
|
32
75
|
await expect(receiver()).resolves.toBeUndefined()
|
|
33
76
|
})
|
|
34
77
|
|
|
35
78
|
test('Imposes delay after several empty reads', async () => {
|
|
36
|
-
|
|
79
|
+
sqs.receiveMessage.mockResolvedValueOnce({ Messages: [] })
|
|
37
80
|
fetch.__goodResult()
|
|
38
81
|
const setTimeoutSpy = jest.spyOn(global, 'setTimeout').mockImplementation(cb => cb())
|
|
39
82
|
for (let i = 0; i < testEnv.TEST_ATTEMPTS_WITH_NO_DELAY; i++) {
|
|
@@ -44,7 +87,10 @@ test('Imposes delay after several empty reads', async () => {
|
|
|
44
87
|
|
|
45
88
|
test('Receiver: throws exception on general error', async () => {
|
|
46
89
|
const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {})
|
|
47
|
-
|
|
90
|
+
const queueError = new Error('connect ECONNREFUSED 0.0.0.0:9325')
|
|
91
|
+
queueError.code = 'NetworkingError'
|
|
92
|
+
sqs.receiveMessage.mockRejectedValueOnce(queueError)
|
|
93
|
+
|
|
48
94
|
await expect(receiver()).rejects.toThrow(Error)
|
|
49
95
|
expect(consoleError).toHaveBeenCalled()
|
|
50
96
|
})
|
|
@@ -1,11 +1,26 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { AWS } from '@defra-fish/connectors-lib'
|
|
2
2
|
import showQueueStatistics from '../show-queue-statistics.js'
|
|
3
3
|
import testEnv from '../../test-env'
|
|
4
4
|
import debug from 'debug'
|
|
5
|
+
const { sqs } = AWS.mock.results[0].value
|
|
6
|
+
|
|
7
|
+
jest.mock('@defra-fish/connectors-lib', () => ({
|
|
8
|
+
AWS: jest.fn(() => ({
|
|
9
|
+
sqs: {
|
|
10
|
+
getQueueAttributes: jest.fn(() => ({
|
|
11
|
+
Attributes: {
|
|
12
|
+
ApproximateNumberOfMessages: 0,
|
|
13
|
+
ApproximateNumberOfMessagesNotVisible: 0,
|
|
14
|
+
ApproximateNumberOfMessagesDelayed: 0
|
|
15
|
+
}
|
|
16
|
+
}))
|
|
17
|
+
}
|
|
18
|
+
}))
|
|
19
|
+
}))
|
|
5
20
|
|
|
6
21
|
beforeEach(() => {
|
|
7
22
|
process.env = Object.assign(process.env, testEnv)
|
|
8
|
-
|
|
23
|
+
sqs.getQueueAttributes.mockClear()
|
|
9
24
|
})
|
|
10
25
|
|
|
11
26
|
test('shows queue statistics when debug is enabled', async () => {
|
|
@@ -15,20 +30,20 @@ test('shows queue statistics when debug is enabled', async () => {
|
|
|
15
30
|
await showQueueStatistics('http://0.0.0.0:0000/queue')
|
|
16
31
|
}
|
|
17
32
|
await expect(check()).resolves.toBeUndefined()
|
|
18
|
-
expect(
|
|
33
|
+
expect(sqs.getQueueAttributes).toHaveBeenCalledTimes(2)
|
|
19
34
|
})
|
|
20
35
|
|
|
21
36
|
test('does not throw errors if the AWS API call fails', async () => {
|
|
22
|
-
|
|
37
|
+
sqs.getQueueAttributes.mockRejectedValueOnce(new Error('AWS API call failed'))
|
|
23
38
|
debug.enable('sqs:queue-stats')
|
|
24
39
|
const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {})
|
|
25
40
|
await expect(showQueueStatistics('http://0.0.0.0:0000/queue')).resolves.toBeUndefined()
|
|
26
|
-
expect(
|
|
41
|
+
expect(sqs.getQueueAttributes).toHaveBeenCalledTimes(1)
|
|
27
42
|
expect(consoleError).toHaveBeenCalled()
|
|
28
43
|
})
|
|
29
44
|
|
|
30
45
|
test('does not query queue statistics if debug is not enabled', async () => {
|
|
31
46
|
debug.disable()
|
|
32
47
|
await expect(showQueueStatistics('http://0.0.0.0:0000/queue')).resolves.toBeUndefined()
|
|
33
|
-
expect(
|
|
48
|
+
expect(sqs.getQueueAttributes).not.toHaveBeenCalled()
|
|
34
49
|
})
|
package/src/delete-messages.js
CHANGED
|
@@ -18,7 +18,7 @@ const deleteMessages = async (url, messageSubscriberResults) => {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
if (params.Entries.length) {
|
|
21
|
-
const results = await sqs.deleteMessageBatch(params)
|
|
21
|
+
const results = await sqs.deleteMessageBatch(params)
|
|
22
22
|
|
|
23
23
|
if (results.Failed.length) {
|
|
24
24
|
console.error('Failed to delete messages from %s: %o', url, results.Failed)
|
package/src/read-queue.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
import db from 'debug'
|
|
3
3
|
import { AWS } from '@defra-fish/connectors-lib'
|
|
4
|
+
|
|
4
5
|
const { sqs } = AWS()
|
|
5
6
|
const debug = db('sqs:read-queue')
|
|
6
7
|
|
|
@@ -12,7 +13,7 @@ const debug = db('sqs:read-queue')
|
|
|
12
13
|
* @param {number} waitTimeMs the amount of time to wait for messages to become available
|
|
13
14
|
* @returns {Promise<SQS.Message[]|*[]>}
|
|
14
15
|
*/
|
|
15
|
-
|
|
16
|
+
export default async (url, visibilityTimeoutMs, waitTimeMs) => {
|
|
16
17
|
try {
|
|
17
18
|
const params = {
|
|
18
19
|
QueueUrl: url,
|
|
@@ -22,7 +23,7 @@ const readQueue = async (url, visibilityTimeoutMs, waitTimeMs) => {
|
|
|
22
23
|
VisibilityTimeout: visibilityTimeoutMs / 1000,
|
|
23
24
|
WaitTimeSeconds: waitTimeMs / 1000
|
|
24
25
|
}
|
|
25
|
-
const data = await sqs.receiveMessage(params)
|
|
26
|
+
const data = await sqs.receiveMessage(params)
|
|
26
27
|
const messages = data.Messages || []
|
|
27
28
|
debug('Retrieved %d messages from %s', messages.length, url)
|
|
28
29
|
return messages
|
|
@@ -33,12 +34,9 @@ const readQueue = async (url, visibilityTimeoutMs, waitTimeMs) => {
|
|
|
33
34
|
*/
|
|
34
35
|
console.error(`Error reading queue: ${url}`, err)
|
|
35
36
|
|
|
36
|
-
if (!err
|
|
37
|
+
if (!err.$metadata?.httpStatusCode) {
|
|
37
38
|
throw err
|
|
38
|
-
} else {
|
|
39
|
-
return []
|
|
40
39
|
}
|
|
40
|
+
return []
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
-
|
|
44
|
-
export default readQueue
|
|
@@ -22,7 +22,7 @@ const showQueueStatistics = async url => {
|
|
|
22
22
|
AttributeNames: ['ApproximateNumberOfMessages', 'ApproximateNumberOfMessagesNotVisible', 'ApproximateNumberOfMessagesDelayed']
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
const { Attributes } = await sqs.getQueueAttributes(params)
|
|
25
|
+
const { Attributes } = await sqs.getQueueAttributes(params)
|
|
26
26
|
const prt = attr => {
|
|
27
27
|
const change = Number.parseInt(Attributes[attr]) - Number.parseInt(last[attr])
|
|
28
28
|
if (change > 0) {
|
package/src/__mocks__/aws-sdk.js
DELETED
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
import { v4 as uuidv4 } from 'uuid'
|
|
4
|
-
import { configureAwsSdkMock } from '@defra-fish/connectors-lib/src/__mocks__/aws-mock-helper.js'
|
|
5
|
-
const AwsSdk = configureAwsSdkMock()
|
|
6
|
-
|
|
7
|
-
let result
|
|
8
|
-
let exception
|
|
9
|
-
let deleteFailures
|
|
10
|
-
|
|
11
|
-
AwsSdk.__mockEmptyQueue = () => {
|
|
12
|
-
exception = null
|
|
13
|
-
result = Object.create({})
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
AwsSdk.__mockOneMessage = () => {
|
|
17
|
-
exception = null
|
|
18
|
-
result = Object.create({
|
|
19
|
-
ResponseMetadata: {
|
|
20
|
-
RequestId: '00000000-0000-0000-0000-000000000000'
|
|
21
|
-
},
|
|
22
|
-
Messages: [
|
|
23
|
-
{
|
|
24
|
-
MessageId: '15eb8abc-c7c1-4167-9590-839c8feed6dd',
|
|
25
|
-
ReceiptHandle: '15eb8abc-c7c1-4167-9590-839c8feed6dd#9be8971c-f9a9-4bb2-8515-98cdab660e1b',
|
|
26
|
-
MD5OfBody: '640ad880b5be372fcb5c5ad8b5eb50af',
|
|
27
|
-
Body: '{"id":"7f6e04fe-4cec-4f40-b763-8c66d71062d9"}',
|
|
28
|
-
Attributes: {
|
|
29
|
-
MessageGroupId: 'service-1'
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
]
|
|
33
|
-
})
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
AwsSdk.__mockNMessages = n => {
|
|
37
|
-
exception = null
|
|
38
|
-
result = Object.create(
|
|
39
|
-
(result = Object.create({
|
|
40
|
-
ResponseMetadata: {
|
|
41
|
-
RequestId: '00000000-0000-0000-0000-000000000000'
|
|
42
|
-
},
|
|
43
|
-
Messages: []
|
|
44
|
-
}))
|
|
45
|
-
)
|
|
46
|
-
for (let i = 0; i < n; i++) {
|
|
47
|
-
result.Messages.push({
|
|
48
|
-
MessageId: uuidv4(),
|
|
49
|
-
ReceiptHandle: '15eb8abc-c7c1-4167-9590-839c8feed6dd#9be8971c-f9a9-4bb2-8515-98cdab660e1b',
|
|
50
|
-
MD5OfBody: '640ad880b5be372fcb5c5ad8b5eb50af',
|
|
51
|
-
Body: `{"id":"${uuidv4()}"}`,
|
|
52
|
-
Attributes: {
|
|
53
|
-
MessageGroupId: 'service-1'
|
|
54
|
-
}
|
|
55
|
-
})
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
AwsSdk.__mockFailNoQueue = () => {
|
|
60
|
-
exception = new Error('connect ECONNREFUSED 0.0.0.0:9325')
|
|
61
|
-
exception.code = 'NetworkingError'
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
AwsSdk.__mockNotFound = () => {
|
|
65
|
-
exception = new Error('Not Found')
|
|
66
|
-
exception.code = 404
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
AwsSdk.__mockAWSError = () => {
|
|
70
|
-
result = []
|
|
71
|
-
exception = new Error()
|
|
72
|
-
exception = Object.assign(exception, {
|
|
73
|
-
message: 'ReadCountOutOfRange; see the SQS docs.',
|
|
74
|
-
code: 'ReadCountOutOfRange',
|
|
75
|
-
time: '2020-03-05T10:27:42.852Z',
|
|
76
|
-
statusCode: 400,
|
|
77
|
-
retryable: false,
|
|
78
|
-
retryDelay: 49.19455461172468
|
|
79
|
-
})
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
AwsSdk.__mockDeleteMessages = () => {
|
|
83
|
-
exception = null
|
|
84
|
-
result = Object.create({
|
|
85
|
-
ResponseMetadata: {
|
|
86
|
-
RequestId: '00000000-0000-0000-0000-000000000000'
|
|
87
|
-
},
|
|
88
|
-
Successful: [
|
|
89
|
-
{
|
|
90
|
-
Id: '705e5bc6-bd0f-4424-95aa-7caf9a8eaab4'
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
Id: '7ae59705-333f-4d38-b5d9-2c71f4f4ecae'
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
Id: '23207320-8c75-4a12-960d-b87455ce7826'
|
|
97
|
-
}
|
|
98
|
-
],
|
|
99
|
-
Failed: []
|
|
100
|
-
})
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const receiveMessage = () => {
|
|
104
|
-
if (exception) {
|
|
105
|
-
throw exception
|
|
106
|
-
}
|
|
107
|
-
return {
|
|
108
|
-
promise: () => result
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
AwsSdk.__mockDeleteMessageFailures = () => {
|
|
113
|
-
deleteFailures = true
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const deleteMessageBatch = params => {
|
|
117
|
-
if (exception) {
|
|
118
|
-
throw exception
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
result = () => {
|
|
122
|
-
if (deleteFailures) {
|
|
123
|
-
return {
|
|
124
|
-
ResponseMetadata: {
|
|
125
|
-
RequestId: '00000000-0000-0000-0000-000000000000'
|
|
126
|
-
},
|
|
127
|
-
Successful: [],
|
|
128
|
-
Failed: params.Entries.map(p => ({ Id: p.Id }))
|
|
129
|
-
}
|
|
130
|
-
} else {
|
|
131
|
-
return {
|
|
132
|
-
ResponseMetadata: {
|
|
133
|
-
RequestId: '00000000-0000-0000-0000-000000000000'
|
|
134
|
-
},
|
|
135
|
-
Successful: params.Entries.map(p => ({ Id: p.Id })),
|
|
136
|
-
Failed: []
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
return {
|
|
142
|
-
promise: () => result()
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
AwsSdk.__mockGetAttributesThrows = () => {
|
|
147
|
-
exception = new Error()
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
export const GetQueueAttributesMockImplementation = jest.fn()
|
|
151
|
-
|
|
152
|
-
GetQueueAttributesMockImplementation.mockReturnValueOnce({
|
|
153
|
-
promise: () => {
|
|
154
|
-
if (exception) {
|
|
155
|
-
throw exception
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
return {
|
|
159
|
-
Attributes: {
|
|
160
|
-
ApproximateNumberOfMessagesDelayed: 1,
|
|
161
|
-
ApproximateNumberOfMessagesNotVisible: 2,
|
|
162
|
-
ApproximateNumberOfMessages: 3
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}).mockReturnValue({
|
|
167
|
-
promise: () => {
|
|
168
|
-
if (exception) {
|
|
169
|
-
throw exception
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
return {
|
|
173
|
-
Attributes: {
|
|
174
|
-
ApproximateNumberOfMessagesDelayed: 0,
|
|
175
|
-
ApproximateNumberOfMessagesNotVisible: 0,
|
|
176
|
-
ApproximateNumberOfMessages: 0
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
})
|
|
181
|
-
|
|
182
|
-
AwsSdk.SQS.mockImplementation(() => {
|
|
183
|
-
return {
|
|
184
|
-
receiveMessage: receiveMessage,
|
|
185
|
-
deleteMessageBatch: deleteMessageBatch,
|
|
186
|
-
getQueueAttributes: GetQueueAttributesMockImplementation
|
|
187
|
-
}
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
export default AwsSdk
|