queen-mq 0.2.23 → 0.3.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/README.md +162 -136
- package/client-js/client-v2/LOGGING.md +240 -0
- package/client-js/client-v2/Queen.js +389 -0
- package/client-js/client-v2/README.md +1883 -0
- package/client-js/client-v2/buffer/BufferManager.js +215 -0
- package/client-js/client-v2/buffer/MessageBuffer.js +132 -0
- package/client-js/client-v2/builders/QueueBuilder.js +724 -0
- package/client-js/client-v2/builders/TransactionBuilder.js +110 -0
- package/client-js/client-v2/consumer/ConsumerManager.js +390 -0
- package/client-js/client-v2/http/HttpClient.js +215 -0
- package/client-js/client-v2/http/LoadBalancer.js +50 -0
- package/client-js/client-v2/index.js +7 -0
- package/client-js/client-v2/utils/defaults.js +54 -0
- package/client-js/client-v2/utils/logger.js +54 -0
- package/client-js/client-v2/utils/validation.js +31 -0
- package/client-js/test-v2/AI_TEST_SUMMARY.md +226 -0
- package/client-js/test-v2/GETTING_STARTED.md +154 -0
- package/client-js/test-v2/ai_buffering.js +194 -0
- package/client-js/test-v2/ai_error_handling.js +223 -0
- package/client-js/test-v2/ai_lease_renewal.js +206 -0
- package/client-js/test-v2/ai_mixed_scenarios.js +278 -0
- package/client-js/test-v2/ai_priority.js +169 -0
- package/client-js/test-v2/ai_resources.js +217 -0
- package/client-js/test-v2/ai_ttl_retention.js +170 -0
- package/client-js/test-v2/complete.js +59 -0
- package/client-js/test-v2/consume.js +655 -0
- package/client-js/test-v2/dlq.js +82 -0
- package/client-js/test-v2/load.js +177 -0
- package/client-js/test-v2/pop.js +114 -0
- package/client-js/test-v2/push.js +333 -0
- package/client-js/test-v2/queue.js +39 -0
- package/client-js/test-v2/run.js +187 -0
- package/client-js/test-v2/subscription.js +354 -0
- package/client-js/test-v2/transaction.js +443 -0
- package/package.json +1 -1
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-Side Buffering Tests
|
|
3
|
+
* Tests for buffer management and statistics
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export async function testBufferStatistics(client) {
|
|
7
|
+
const queue = await client.queue('test-queue-v2-buffer-stats').create()
|
|
8
|
+
if (!queue.configured) {
|
|
9
|
+
return { success: false, message: 'Queue not created' }
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Get initial stats
|
|
13
|
+
const statsBefore = client.getBufferStats()
|
|
14
|
+
|
|
15
|
+
if (!statsBefore || typeof statsBefore !== 'object') {
|
|
16
|
+
return { success: false, message: 'Buffer stats not available' }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Push some buffered messages
|
|
20
|
+
for (let i = 0; i < 5; i++) {
|
|
21
|
+
await client.queue('test-queue-v2-buffer-stats')
|
|
22
|
+
.buffer({ messageCount: 10, timeMillis: 5000 })
|
|
23
|
+
.push([{ data: { id: i } }])
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Get stats after buffering
|
|
27
|
+
const statsAfter = client.getBufferStats()
|
|
28
|
+
|
|
29
|
+
// Stats should show buffer activity
|
|
30
|
+
return {
|
|
31
|
+
success: statsAfter !== null,
|
|
32
|
+
message: `Buffer stats retrieved: ${JSON.stringify(statsAfter)}`
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export async function testManualBufferFlush(client) {
|
|
37
|
+
const queue = await client.queue('test-queue-v2-manual-flush').create()
|
|
38
|
+
if (!queue.configured) {
|
|
39
|
+
return { success: false, message: 'Queue not created' }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Push buffered messages (with high threshold so they don't auto-flush)
|
|
43
|
+
for (let i = 0; i < 5; i++) {
|
|
44
|
+
await client.queue('test-queue-v2-manual-flush')
|
|
45
|
+
.buffer({ messageCount: 100, timeMillis: 30000 })
|
|
46
|
+
.push([{ data: { id: i } }])
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Check that messages are not in queue yet
|
|
50
|
+
const beforeFlush = await client.queue('test-queue-v2-manual-flush')
|
|
51
|
+
.batch(10)
|
|
52
|
+
.wait(false)
|
|
53
|
+
.pop()
|
|
54
|
+
|
|
55
|
+
if (beforeFlush.length > 0) {
|
|
56
|
+
return { success: false, message: 'Messages not buffered (flushed too early)' }
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Manually flush all buffers
|
|
60
|
+
await client.flushAllBuffers()
|
|
61
|
+
|
|
62
|
+
// Now messages should be in the queue
|
|
63
|
+
const afterFlush = await client.queue('test-queue-v2-manual-flush')
|
|
64
|
+
.batch(10)
|
|
65
|
+
.wait(false)
|
|
66
|
+
.pop()
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
success: afterFlush.length === 5,
|
|
70
|
+
message: `Manual flush successful: ${afterFlush.length} messages`
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export async function testBufferTimeThreshold(client) {
|
|
75
|
+
const queue = await client.queue('test-queue-v2-buffer-time').create()
|
|
76
|
+
if (!queue.configured) {
|
|
77
|
+
return { success: false, message: 'Queue not created' }
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Push with time-based buffer (1 second)
|
|
81
|
+
await client.queue('test-queue-v2-buffer-time')
|
|
82
|
+
.buffer({ messageCount: 1000, timeMillis: 1000 })
|
|
83
|
+
.push([{ data: { test: 'data' } }])
|
|
84
|
+
|
|
85
|
+
// Wait for time threshold
|
|
86
|
+
await new Promise(resolve => setTimeout(resolve, 1500))
|
|
87
|
+
|
|
88
|
+
// Message should be auto-flushed by time
|
|
89
|
+
const messages = await client.queue('test-queue-v2-buffer-time')
|
|
90
|
+
.batch(1)
|
|
91
|
+
.wait(false)
|
|
92
|
+
.pop()
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
success: messages.length === 1,
|
|
96
|
+
message: 'Time-based buffer flush works'
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export async function testBufferCountThreshold(client) {
|
|
101
|
+
const queue = await client.queue('test-queue-v2-buffer-count').create()
|
|
102
|
+
if (!queue.configured) {
|
|
103
|
+
return { success: false, message: 'Queue not created' }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Push exactly 5 messages with count threshold of 5
|
|
107
|
+
for (let i = 0; i < 5; i++) {
|
|
108
|
+
await client.queue('test-queue-v2-buffer-count')
|
|
109
|
+
.buffer({ messageCount: 5, timeMillis: 30000 })
|
|
110
|
+
.push([{ data: { id: i } }])
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Small delay for flush to process
|
|
114
|
+
await new Promise(resolve => setTimeout(resolve, 200))
|
|
115
|
+
|
|
116
|
+
// All 5 should be flushed when threshold reached
|
|
117
|
+
const messages = await client.queue('test-queue-v2-buffer-count')
|
|
118
|
+
.batch(10)
|
|
119
|
+
.wait(false)
|
|
120
|
+
.pop()
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
success: messages.length === 5,
|
|
124
|
+
message: `Count-based buffer flush: ${messages.length} messages`
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export async function testMultipleBuffers(client) {
|
|
129
|
+
// Create multiple queues with buffering
|
|
130
|
+
await client.queue('test-queue-v2-multi-buf-1').create()
|
|
131
|
+
await client.queue('test-queue-v2-multi-buf-2').create()
|
|
132
|
+
await client.queue('test-queue-v2-multi-buf-3').create()
|
|
133
|
+
|
|
134
|
+
// Buffer messages to different queues
|
|
135
|
+
for (let i = 0; i < 3; i++) {
|
|
136
|
+
await client.queue('test-queue-v2-multi-buf-1')
|
|
137
|
+
.buffer({ messageCount: 100, timeMillis: 10000 })
|
|
138
|
+
.push([{ data: { queue: 1, id: i } }])
|
|
139
|
+
|
|
140
|
+
await client.queue('test-queue-v2-multi-buf-2')
|
|
141
|
+
.buffer({ messageCount: 100, timeMillis: 10000 })
|
|
142
|
+
.push([{ data: { queue: 2, id: i } }])
|
|
143
|
+
|
|
144
|
+
await client.queue('test-queue-v2-multi-buf-3')
|
|
145
|
+
.buffer({ messageCount: 100, timeMillis: 10000 })
|
|
146
|
+
.push([{ data: { queue: 3, id: i } }])
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Get stats to see multiple buffers
|
|
150
|
+
const stats = client.getBufferStats()
|
|
151
|
+
|
|
152
|
+
// Flush all buffers
|
|
153
|
+
await client.flushAllBuffers()
|
|
154
|
+
|
|
155
|
+
// Verify all queues received messages
|
|
156
|
+
const msgs1 = await client.queue('test-queue-v2-multi-buf-1').batch(10).wait(false).pop()
|
|
157
|
+
const msgs2 = await client.queue('test-queue-v2-multi-buf-2').batch(10).wait(false).pop()
|
|
158
|
+
const msgs3 = await client.queue('test-queue-v2-multi-buf-3').batch(10).wait(false).pop()
|
|
159
|
+
|
|
160
|
+
return {
|
|
161
|
+
success: msgs1.length === 3 && msgs2.length === 3 && msgs3.length === 3,
|
|
162
|
+
message: `Multiple buffers flushed: ${msgs1.length + msgs2.length + msgs3.length} total`
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export async function testBufferWithPartition(client) {
|
|
167
|
+
const queue = await client.queue('test-queue-v2-buffer-partition').create()
|
|
168
|
+
if (!queue.configured) {
|
|
169
|
+
return { success: false, message: 'Queue not created' }
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Buffer messages to specific partition
|
|
173
|
+
for (let i = 0; i < 5; i++) {
|
|
174
|
+
await client.queue('test-queue-v2-buffer-partition')
|
|
175
|
+
.partition('test-partition-buf')
|
|
176
|
+
.buffer({ messageCount: 100, timeMillis: 10000 })
|
|
177
|
+
.push([{ data: { id: i } }])
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
await client.flushAllBuffers()
|
|
181
|
+
|
|
182
|
+
// Pop from that partition
|
|
183
|
+
const messages = await client.queue('test-queue-v2-buffer-partition')
|
|
184
|
+
.partition('test-partition-buf')
|
|
185
|
+
.batch(10)
|
|
186
|
+
.wait(false)
|
|
187
|
+
.pop()
|
|
188
|
+
|
|
189
|
+
return {
|
|
190
|
+
success: messages.length === 5,
|
|
191
|
+
message: 'Buffering with partition works'
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error Handling & Edge Cases Tests
|
|
3
|
+
* Tests various error conditions and edge cases
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export async function testInvalidQueueName(client) {
|
|
7
|
+
try {
|
|
8
|
+
await client.queue('').create()
|
|
9
|
+
return { success: false, message: 'Empty queue name should fail' }
|
|
10
|
+
} catch (error) {
|
|
11
|
+
return { success: true, message: 'Empty queue name correctly rejected' }
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function testInvalidConfiguration(client) {
|
|
16
|
+
try {
|
|
17
|
+
await client.queue('test-queue-invalid-config')
|
|
18
|
+
.config({ leaseTime: -1 })
|
|
19
|
+
.create()
|
|
20
|
+
return { success: false, message: 'Negative leaseTime should fail' }
|
|
21
|
+
} catch (error) {
|
|
22
|
+
return { success: true, message: 'Invalid config correctly rejected' }
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function testInvalidMessageFormat(client) {
|
|
27
|
+
const queue = await client.queue('test-queue-v2-invalid-msg').create()
|
|
28
|
+
if (!queue.configured) {
|
|
29
|
+
return { success: false, message: 'Queue not created' }
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
// Push without data property
|
|
34
|
+
await client.queue('test-queue-v2-invalid-msg').push([{ invalid: 'structure' }])
|
|
35
|
+
// If it doesn't throw, check if it still works
|
|
36
|
+
return { success: true, message: 'Client handles flexible message format' }
|
|
37
|
+
} catch (error) {
|
|
38
|
+
return { success: true, message: 'Invalid message format correctly handled' }
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function testPushEmptyArray(client) {
|
|
43
|
+
const queue = await client.queue('test-queue-v2-empty-array').create()
|
|
44
|
+
if (!queue.configured) {
|
|
45
|
+
return { success: false, message: 'Queue not created' }
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const result = await client.queue('test-queue-v2-empty-array').push([])
|
|
49
|
+
return { success: result.length === 0, message: 'Empty array push handled correctly' }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export async function testAckWithoutPartitionId(client) {
|
|
53
|
+
const queue = await client.queue('test-queue-v2-ack-no-partition').create()
|
|
54
|
+
if (!queue.configured) {
|
|
55
|
+
return { success: false, message: 'Queue not created' }
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
await client.queue('test-queue-v2-ack-no-partition')
|
|
59
|
+
.push([{ data: { test: 'data' } }])
|
|
60
|
+
|
|
61
|
+
const messages = await client.queue('test-queue-v2-ack-no-partition')
|
|
62
|
+
.batch(1)
|
|
63
|
+
.wait(false)
|
|
64
|
+
.pop()
|
|
65
|
+
|
|
66
|
+
if (messages.length === 0) {
|
|
67
|
+
return { success: false, message: 'No message to test' }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Try to ack without partitionId (should fail)
|
|
71
|
+
const messageWithoutPartition = { transactionId: messages[0].transactionId }
|
|
72
|
+
const result = await client.ack(messageWithoutPartition)
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
success: result.success === false && result.error.includes('partitionId'),
|
|
76
|
+
message: 'Ack without partitionId correctly rejected'
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export async function testPopFromNonExistentQueue(client) {
|
|
81
|
+
try {
|
|
82
|
+
const result = await client
|
|
83
|
+
.queue('non-existent-queue-xyz')
|
|
84
|
+
.batch(1)
|
|
85
|
+
.wait(false)
|
|
86
|
+
.pop()
|
|
87
|
+
|
|
88
|
+
// It's okay if it returns empty or throws
|
|
89
|
+
return { success: true, message: 'Non-existent queue handled gracefully' }
|
|
90
|
+
} catch (error) {
|
|
91
|
+
return { success: true, message: 'Non-existent queue error handled' }
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export async function testMultiplePushesWithSameTransactionId(client) {
|
|
96
|
+
const queue = await client.queue('test-queue-v2-same-txid').create()
|
|
97
|
+
if (!queue.configured) {
|
|
98
|
+
return { success: false, message: 'Queue not created' }
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const txId = 'duplicate-transaction-id-test'
|
|
102
|
+
|
|
103
|
+
const result1 = await client.queue('test-queue-v2-same-txid')
|
|
104
|
+
.push([{ transactionId: txId, data: { first: true } }])
|
|
105
|
+
|
|
106
|
+
const result2 = await client.queue('test-queue-v2-same-txid')
|
|
107
|
+
.push([{ transactionId: txId, data: { second: true } }])
|
|
108
|
+
|
|
109
|
+
const result3 = await client.queue('test-queue-v2-same-txid')
|
|
110
|
+
.push([{ transactionId: txId, data: { third: true } }])
|
|
111
|
+
|
|
112
|
+
const duplicates = [result1[0], result2[0], result3[0]].filter(r => r.status === 'duplicate').length
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
success: duplicates >= 2,
|
|
116
|
+
message: `Duplicate detection working (${duplicates} duplicates found)`
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export async function testAckExpiredLease(client) {
|
|
121
|
+
const queue = await client.queue('test-queue-v2-expired-lease')
|
|
122
|
+
.config({ leaseTime: 1 })
|
|
123
|
+
.create()
|
|
124
|
+
|
|
125
|
+
if (!queue.configured) {
|
|
126
|
+
return { success: false, message: 'Queue not created' }
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
await client.queue('test-queue-v2-expired-lease')
|
|
130
|
+
.push([{ data: { test: 'data' } }])
|
|
131
|
+
|
|
132
|
+
const messages = await client.queue('test-queue-v2-expired-lease')
|
|
133
|
+
.batch(1)
|
|
134
|
+
.wait(false)
|
|
135
|
+
.pop()
|
|
136
|
+
|
|
137
|
+
if (messages.length === 0) {
|
|
138
|
+
return { success: false, message: 'No message to test' }
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Wait for lease to expire
|
|
142
|
+
await new Promise(resolve => setTimeout(resolve, 2000))
|
|
143
|
+
|
|
144
|
+
// Try to ack expired lease
|
|
145
|
+
const result = await client.ack(messages[0], true)
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
success: result.success === false,
|
|
149
|
+
message: 'Expired lease ack correctly rejected'
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export async function testBatchAckMixedResults(client) {
|
|
154
|
+
const queue = await client.queue('test-queue-v2-batch-ack-mixed')
|
|
155
|
+
.config({ leaseTime: 2 })
|
|
156
|
+
.create()
|
|
157
|
+
|
|
158
|
+
if (!queue.configured) {
|
|
159
|
+
return { success: false, message: 'Queue not created' }
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
await client.queue('test-queue-v2-batch-ack-mixed').push([
|
|
163
|
+
{ data: { id: 1 } },
|
|
164
|
+
{ data: { id: 2 } },
|
|
165
|
+
{ data: { id: 3 } }
|
|
166
|
+
])
|
|
167
|
+
|
|
168
|
+
const messages = await client.queue('test-queue-v2-batch-ack-mixed')
|
|
169
|
+
.batch(3)
|
|
170
|
+
.wait(false)
|
|
171
|
+
.pop()
|
|
172
|
+
|
|
173
|
+
if (messages.length !== 3) {
|
|
174
|
+
return { success: false, message: 'Expected 3 messages' }
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Wait for one lease to expire
|
|
178
|
+
await new Promise(resolve => setTimeout(resolve, 2500))
|
|
179
|
+
|
|
180
|
+
// Try to ack all three (one should fail due to expired lease)
|
|
181
|
+
const result = await client.ack(messages, true)
|
|
182
|
+
|
|
183
|
+
// Should indicate some failures
|
|
184
|
+
return {
|
|
185
|
+
success: result.success === true, // Batch ack returns overall success
|
|
186
|
+
message: 'Batch ack with expired lease handled'
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export async function testVeryLargePayload(client) {
|
|
191
|
+
const queue = await client.queue('test-queue-v2-very-large').create()
|
|
192
|
+
if (!queue.configured) {
|
|
193
|
+
return { success: false, message: 'Queue not created' }
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Create a very large payload (attempt to push near limits)
|
|
197
|
+
const hugeArray = new Array(50000).fill({
|
|
198
|
+
id: Math.random().toString(36),
|
|
199
|
+
data: 'x'.repeat(100)
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
try {
|
|
203
|
+
const result = await client.queue('test-queue-v2-very-large')
|
|
204
|
+
.push([{ data: hugeArray }])
|
|
205
|
+
|
|
206
|
+
const received = await client.queue('test-queue-v2-very-large')
|
|
207
|
+
.batch(1)
|
|
208
|
+
.wait(false)
|
|
209
|
+
.pop()
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
success: received.length === 1 && received[0].data.length === 50000,
|
|
213
|
+
message: 'Very large payload handled correctly'
|
|
214
|
+
}
|
|
215
|
+
} catch (error) {
|
|
216
|
+
// It's okay if it fails - system has limits
|
|
217
|
+
return {
|
|
218
|
+
success: true,
|
|
219
|
+
message: `Large payload limit enforced: ${error.message}`
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lease Renewal Tests
|
|
3
|
+
* Tests manual lease extension functionality
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export async function testManualLeaseRenewal(client) {
|
|
7
|
+
const queue = await client.queue('test-queue-v2-manual-renewal')
|
|
8
|
+
.config({ leaseTime: 2 })
|
|
9
|
+
.create()
|
|
10
|
+
|
|
11
|
+
if (!queue.configured) {
|
|
12
|
+
return { success: false, message: 'Queue not created' }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
await client.queue('test-queue-v2-manual-renewal')
|
|
16
|
+
.push([{ data: { test: 'renewal' } }])
|
|
17
|
+
|
|
18
|
+
const messages = await client.queue('test-queue-v2-manual-renewal')
|
|
19
|
+
.batch(1)
|
|
20
|
+
.wait(false)
|
|
21
|
+
.pop()
|
|
22
|
+
|
|
23
|
+
if (messages.length === 0) {
|
|
24
|
+
return { success: false, message: 'No message to test' }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const message = messages[0]
|
|
28
|
+
|
|
29
|
+
// Wait 1 second
|
|
30
|
+
await new Promise(resolve => setTimeout(resolve, 1000))
|
|
31
|
+
|
|
32
|
+
// Renew the lease
|
|
33
|
+
const renewResult = await client.renew(message)
|
|
34
|
+
|
|
35
|
+
if (!renewResult.success) {
|
|
36
|
+
return { success: false, message: 'Lease renewal failed' }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Wait another 2 seconds (total 3 seconds, original lease was 2 seconds)
|
|
40
|
+
await new Promise(resolve => setTimeout(resolve, 2000))
|
|
41
|
+
|
|
42
|
+
// Try to ack - should succeed because we renewed
|
|
43
|
+
const ackResult = await client.ack(message, true)
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
success: ackResult.success === true,
|
|
47
|
+
message: 'Manual lease renewal works correctly'
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export async function testBatchLeaseRenewal(client) {
|
|
52
|
+
const queue = await client.queue('test-queue-v2-batch-renewal')
|
|
53
|
+
.config({ leaseTime: 2 })
|
|
54
|
+
.create()
|
|
55
|
+
|
|
56
|
+
if (!queue.configured) {
|
|
57
|
+
return { success: false, message: 'Queue not created' }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
await client.queue('test-queue-v2-batch-renewal').push([
|
|
61
|
+
{ data: { id: 1 } },
|
|
62
|
+
{ data: { id: 2 } },
|
|
63
|
+
{ data: { id: 3 } }
|
|
64
|
+
])
|
|
65
|
+
|
|
66
|
+
const messages = await client.queue('test-queue-v2-batch-renewal')
|
|
67
|
+
.batch(3)
|
|
68
|
+
.wait(false)
|
|
69
|
+
.pop()
|
|
70
|
+
|
|
71
|
+
if (messages.length !== 3) {
|
|
72
|
+
return { success: false, message: 'Expected 3 messages' }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Wait 1 second
|
|
76
|
+
await new Promise(resolve => setTimeout(resolve, 1000))
|
|
77
|
+
|
|
78
|
+
// Renew all leases
|
|
79
|
+
const renewResults = await client.renew(messages)
|
|
80
|
+
|
|
81
|
+
const allSuccess = renewResults.every(r => r.success === true)
|
|
82
|
+
|
|
83
|
+
if (!allSuccess) {
|
|
84
|
+
return { success: false, message: 'Batch renewal failed' }
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Wait another 2 seconds
|
|
88
|
+
await new Promise(resolve => setTimeout(resolve, 2000))
|
|
89
|
+
|
|
90
|
+
// Try to ack all - should succeed
|
|
91
|
+
const ackResult = await client.ack(messages, true)
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
success: ackResult.success === true,
|
|
95
|
+
message: 'Batch lease renewal works correctly'
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export async function testRenewalWithLeaseId(client) {
|
|
100
|
+
const queue = await client.queue('test-queue-v2-renewal-leaseid')
|
|
101
|
+
.config({ leaseTime: 2 })
|
|
102
|
+
.create()
|
|
103
|
+
|
|
104
|
+
if (!queue.configured) {
|
|
105
|
+
return { success: false, message: 'Queue not created' }
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
await client.queue('test-queue-v2-renewal-leaseid')
|
|
109
|
+
.push([{ data: { test: 'data' } }])
|
|
110
|
+
|
|
111
|
+
const messages = await client.queue('test-queue-v2-renewal-leaseid')
|
|
112
|
+
.batch(1)
|
|
113
|
+
.wait(false)
|
|
114
|
+
.pop()
|
|
115
|
+
|
|
116
|
+
if (messages.length === 0 || !messages[0].leaseId) {
|
|
117
|
+
return { success: false, message: 'No message or leaseId' }
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const leaseId = messages[0].leaseId
|
|
121
|
+
|
|
122
|
+
// Renew using just the leaseId string
|
|
123
|
+
const renewResult = await client.renew(leaseId)
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
success: renewResult.success === true,
|
|
127
|
+
message: 'Lease renewal with leaseId string works'
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export async function testRenewalOfExpiredLease(client) {
|
|
132
|
+
const queue = await client.queue('test-queue-v2-renewal-expired')
|
|
133
|
+
.config({ leaseTime: 1 })
|
|
134
|
+
.create()
|
|
135
|
+
|
|
136
|
+
if (!queue.configured) {
|
|
137
|
+
return { success: false, message: 'Queue not created' }
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
await client.queue('test-queue-v2-renewal-expired')
|
|
141
|
+
.push([{ data: { test: 'data' } }])
|
|
142
|
+
|
|
143
|
+
const messages = await client.queue('test-queue-v2-renewal-expired')
|
|
144
|
+
.batch(1)
|
|
145
|
+
.wait(false)
|
|
146
|
+
.pop()
|
|
147
|
+
|
|
148
|
+
if (messages.length === 0) {
|
|
149
|
+
return { success: false, message: 'No message to test' }
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Wait for lease to expire
|
|
153
|
+
await new Promise(resolve => setTimeout(resolve, 2000))
|
|
154
|
+
|
|
155
|
+
// Try to renew expired lease
|
|
156
|
+
const renewResult = await client.renew(messages[0])
|
|
157
|
+
|
|
158
|
+
// Should fail
|
|
159
|
+
return {
|
|
160
|
+
success: renewResult.success === false,
|
|
161
|
+
message: 'Expired lease renewal correctly rejected'
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export async function testMultipleRenewals(client) {
|
|
166
|
+
const queue = await client.queue('test-queue-v2-multiple-renewals')
|
|
167
|
+
.config({ leaseTime: 2 })
|
|
168
|
+
.create()
|
|
169
|
+
|
|
170
|
+
if (!queue.configured) {
|
|
171
|
+
return { success: false, message: 'Queue not created' }
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
await client.queue('test-queue-v2-multiple-renewals')
|
|
175
|
+
.push([{ data: { test: 'data' } }])
|
|
176
|
+
|
|
177
|
+
const messages = await client.queue('test-queue-v2-multiple-renewals')
|
|
178
|
+
.batch(1)
|
|
179
|
+
.wait(false)
|
|
180
|
+
.pop()
|
|
181
|
+
|
|
182
|
+
if (messages.length === 0) {
|
|
183
|
+
return { success: false, message: 'No message to test' }
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const message = messages[0]
|
|
187
|
+
|
|
188
|
+
// Renew multiple times
|
|
189
|
+
await new Promise(resolve => setTimeout(resolve, 1000))
|
|
190
|
+
const renew1 = await client.renew(message)
|
|
191
|
+
|
|
192
|
+
await new Promise(resolve => setTimeout(resolve, 1000))
|
|
193
|
+
const renew2 = await client.renew(message)
|
|
194
|
+
|
|
195
|
+
await new Promise(resolve => setTimeout(resolve, 1000))
|
|
196
|
+
const renew3 = await client.renew(message)
|
|
197
|
+
|
|
198
|
+
// After 3 seconds, ack should still work
|
|
199
|
+
const ackResult = await client.ack(message, true)
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
success: renew1.success && renew2.success && renew3.success && ackResult.success,
|
|
203
|
+
message: 'Multiple lease renewals work correctly'
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|