queen-mq 0.2.23 → 0.3.1
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 +2 -2
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mixed Scenario Tests
|
|
3
|
+
* Complex tests combining multiple features
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export async function testMultipleQueuesSimultaneous(client) {
|
|
7
|
+
// Create multiple queues with different configurations
|
|
8
|
+
await client.queue('test-queue-v2-mixed-1')
|
|
9
|
+
.config({ priority: 1, leaseTime: 60 })
|
|
10
|
+
.create()
|
|
11
|
+
|
|
12
|
+
await client.queue('test-queue-v2-mixed-2')
|
|
13
|
+
.config({ priority: 5, retryLimit: 5 })
|
|
14
|
+
.create()
|
|
15
|
+
|
|
16
|
+
await client.queue('test-queue-v2-mixed-3')
|
|
17
|
+
.config({ priority: 10, delayedProcessing: 1 })
|
|
18
|
+
.create()
|
|
19
|
+
|
|
20
|
+
// Push to all queues
|
|
21
|
+
await Promise.all([
|
|
22
|
+
client.queue('test-queue-v2-mixed-1').push([{ data: { queue: 1 } }]),
|
|
23
|
+
client.queue('test-queue-v2-mixed-2').push([{ data: { queue: 2 } }]),
|
|
24
|
+
client.queue('test-queue-v2-mixed-3').push([{ data: { queue: 3 } }])
|
|
25
|
+
])
|
|
26
|
+
|
|
27
|
+
// Wait for delayed queue
|
|
28
|
+
await new Promise(resolve => setTimeout(resolve, 1500))
|
|
29
|
+
|
|
30
|
+
// Pop from all
|
|
31
|
+
const results = await Promise.all([
|
|
32
|
+
client.queue('test-queue-v2-mixed-1').batch(1).wait(false).pop(),
|
|
33
|
+
client.queue('test-queue-v2-mixed-2').batch(1).wait(false).pop(),
|
|
34
|
+
client.queue('test-queue-v2-mixed-3').batch(1).wait(false).pop()
|
|
35
|
+
])
|
|
36
|
+
|
|
37
|
+
const totalMessages = results.reduce((sum, msgs) => sum + msgs.length, 0)
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
success: totalMessages === 3,
|
|
41
|
+
message: `Multiple queues working: ${totalMessages} messages`
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export async function testCrossQueueWorkflow(client) {
|
|
46
|
+
// Setup: 3-stage processing pipeline
|
|
47
|
+
await client.queue('test-queue-v2-workflow-stage1').create()
|
|
48
|
+
await client.queue('test-queue-v2-workflow-stage2').create()
|
|
49
|
+
await client.queue('test-queue-v2-workflow-stage3').create()
|
|
50
|
+
|
|
51
|
+
// Stage 1: Initial message
|
|
52
|
+
await client.queue('test-queue-v2-workflow-stage1')
|
|
53
|
+
.push([{ data: { stage: 1, value: 10 } }])
|
|
54
|
+
|
|
55
|
+
// Process stage 1 -> stage 2
|
|
56
|
+
const msg1 = await client.queue('test-queue-v2-workflow-stage1')
|
|
57
|
+
.batch(1).wait(false).pop()
|
|
58
|
+
|
|
59
|
+
if (msg1.length === 0) {
|
|
60
|
+
return { success: false, message: 'Stage 1 failed' }
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
await client.transaction()
|
|
64
|
+
.queue('test-queue-v2-workflow-stage2')
|
|
65
|
+
.push([{ data: { stage: 2, value: msg1[0].data.value * 2 } }])
|
|
66
|
+
.ack(msg1[0])
|
|
67
|
+
.commit()
|
|
68
|
+
|
|
69
|
+
// Process stage 2 -> stage 3
|
|
70
|
+
const msg2 = await client.queue('test-queue-v2-workflow-stage2')
|
|
71
|
+
.batch(1).wait(false).pop()
|
|
72
|
+
|
|
73
|
+
if (msg2.length === 0) {
|
|
74
|
+
return { success: false, message: 'Stage 2 failed' }
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
await client.transaction()
|
|
78
|
+
.queue('test-queue-v2-workflow-stage3')
|
|
79
|
+
.push([{ data: { stage: 3, value: msg2[0].data.value + 5 } }])
|
|
80
|
+
.ack(msg2[0])
|
|
81
|
+
.commit()
|
|
82
|
+
|
|
83
|
+
// Verify final result
|
|
84
|
+
const msg3 = await client.queue('test-queue-v2-workflow-stage3')
|
|
85
|
+
.batch(1).wait(false).pop()
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
success: msg3.length === 1 && msg3[0].data.value === 25,
|
|
89
|
+
message: `Cross-queue workflow completed: final value ${msg3[0]?.data.value}`
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export async function testPartitionWithConsumerGroupAndRetries(client) {
|
|
94
|
+
const queue = await client.queue('test-queue-v2-complex-partition')
|
|
95
|
+
.config({ retryLimit: 2 })
|
|
96
|
+
.create()
|
|
97
|
+
|
|
98
|
+
if (!queue.configured) {
|
|
99
|
+
return { success: false, message: 'Queue not created' }
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Push to specific partition
|
|
103
|
+
await client.queue('test-queue-v2-complex-partition')
|
|
104
|
+
.partition('complex-partition-1')
|
|
105
|
+
.push([{ data: { test: 'complex' } }])
|
|
106
|
+
|
|
107
|
+
let attemptCount = 0
|
|
108
|
+
|
|
109
|
+
// Consume with consumer group, fail first time
|
|
110
|
+
await client.queue('test-queue-v2-complex-partition')
|
|
111
|
+
.partition('complex-partition-1')
|
|
112
|
+
.group('complex-group')
|
|
113
|
+
.batch(1)
|
|
114
|
+
.wait(false)
|
|
115
|
+
.limit(2)
|
|
116
|
+
.each()
|
|
117
|
+
.consume(async (msg) => {
|
|
118
|
+
attemptCount++
|
|
119
|
+
if (attemptCount === 1) {
|
|
120
|
+
throw new Error('First attempt fails')
|
|
121
|
+
}
|
|
122
|
+
// Second attempt succeeds
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
success: attemptCount === 2,
|
|
127
|
+
message: 'Complex partition/group/retry scenario works'
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export async function testBufferedPushWithTransactionConsume(client) {
|
|
132
|
+
await client.queue('test-queue-v2-buf-txn-source').create()
|
|
133
|
+
await client.queue('test-queue-v2-buf-txn-dest').create()
|
|
134
|
+
|
|
135
|
+
// Buffered push to source
|
|
136
|
+
for (let i = 0; i < 10; i++) {
|
|
137
|
+
await client.queue('test-queue-v2-buf-txn-source')
|
|
138
|
+
.buffer({ messageCount: 10, timeMillis: 2000 })
|
|
139
|
+
.push([{ data: { id: i } }])
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Wait for flush
|
|
143
|
+
await new Promise(resolve => setTimeout(resolve, 2500))
|
|
144
|
+
|
|
145
|
+
// Consume with transaction to move to destination
|
|
146
|
+
let processed = 0
|
|
147
|
+
await client.queue('test-queue-v2-buf-txn-source')
|
|
148
|
+
.batch(10)
|
|
149
|
+
.wait(false)
|
|
150
|
+
.limit(1)
|
|
151
|
+
.autoAck(false)
|
|
152
|
+
.consume(async (msgs) => {
|
|
153
|
+
for (const msg of msgs) {
|
|
154
|
+
await client.transaction()
|
|
155
|
+
.queue('test-queue-v2-buf-txn-dest')
|
|
156
|
+
.push([{ data: { processed: true, originalId: msg.data.id } }])
|
|
157
|
+
.ack(msg)
|
|
158
|
+
.commit()
|
|
159
|
+
processed++
|
|
160
|
+
}
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
// Verify destination
|
|
164
|
+
const destMsgs = await client.queue('test-queue-v2-buf-txn-dest')
|
|
165
|
+
.batch(20).wait(false).pop()
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
success: processed === 10 && destMsgs.length === 10,
|
|
169
|
+
message: `Buffered push + transaction consume: ${destMsgs.length} messages`
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export async function testNamespaceWithMultipleQueues(client) {
|
|
174
|
+
const namespace = 'test-mixed-namespace'
|
|
175
|
+
|
|
176
|
+
// Create multiple queues in same namespace
|
|
177
|
+
await client.queue('test-queue-v2-ns-multi-a')
|
|
178
|
+
.namespace(namespace)
|
|
179
|
+
.config({ priority: 10 })
|
|
180
|
+
.create()
|
|
181
|
+
|
|
182
|
+
await client.queue('test-queue-v2-ns-multi-b')
|
|
183
|
+
.namespace(namespace)
|
|
184
|
+
.config({ priority: 5 })
|
|
185
|
+
.create()
|
|
186
|
+
|
|
187
|
+
await client.queue('test-queue-v2-ns-multi-c')
|
|
188
|
+
.namespace(namespace)
|
|
189
|
+
.config({ priority: 1 })
|
|
190
|
+
.create()
|
|
191
|
+
|
|
192
|
+
// Push to all
|
|
193
|
+
await client.queue('test-queue-v2-ns-multi-a').push([{ data: { from: 'a' } }])
|
|
194
|
+
await client.queue('test-queue-v2-ns-multi-b').push([{ data: { from: 'b' } }])
|
|
195
|
+
await client.queue('test-queue-v2-ns-multi-c').push([{ data: { from: 'c' } }])
|
|
196
|
+
|
|
197
|
+
// Consume from namespace (should get all 3)
|
|
198
|
+
const messages = []
|
|
199
|
+
await client.queue()
|
|
200
|
+
.namespace(namespace)
|
|
201
|
+
.batch(10)
|
|
202
|
+
.wait(false)
|
|
203
|
+
.limit(1)
|
|
204
|
+
.consume(async (msgs) => {
|
|
205
|
+
messages.push(...msgs)
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
success: messages.length === 3,
|
|
210
|
+
message: `Namespace multi-queue: ${messages.length} messages`
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export async function testEncryptedWithPartitionAndGroup(client) {
|
|
215
|
+
const queue = await client.queue('test-queue-v2-encrypted-complex')
|
|
216
|
+
.config({ encryptionEnabled: true })
|
|
217
|
+
.create()
|
|
218
|
+
|
|
219
|
+
if (!queue.configured) {
|
|
220
|
+
return { success: false, message: 'Queue not created' }
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Push encrypted to partition
|
|
224
|
+
await client.queue('test-queue-v2-encrypted-complex')
|
|
225
|
+
.partition('secure-partition')
|
|
226
|
+
.push([{ data: { secret: 'sensitive-data', id: 123 } }])
|
|
227
|
+
|
|
228
|
+
// Consume with group
|
|
229
|
+
let receivedData = null
|
|
230
|
+
await client.queue('test-queue-v2-encrypted-complex')
|
|
231
|
+
.partition('secure-partition')
|
|
232
|
+
.group('secure-group')
|
|
233
|
+
.batch(1)
|
|
234
|
+
.wait(false)
|
|
235
|
+
.limit(1)
|
|
236
|
+
.each()
|
|
237
|
+
.consume(async (msg) => {
|
|
238
|
+
receivedData = msg.data
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
return {
|
|
242
|
+
success: receivedData && receivedData.secret === 'sensitive-data',
|
|
243
|
+
message: 'Encrypted + partition + group works'
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export async function testHighConcurrencyMixedOperations(client) {
|
|
248
|
+
await client.queue('test-queue-v2-concurrency-mixed').create()
|
|
249
|
+
|
|
250
|
+
// Push many messages
|
|
251
|
+
const pushPromises = []
|
|
252
|
+
for (let i = 0; i < 50; i++) {
|
|
253
|
+
pushPromises.push(
|
|
254
|
+
client.queue('test-queue-v2-concurrency-mixed')
|
|
255
|
+
.push([{ data: { id: i } }])
|
|
256
|
+
)
|
|
257
|
+
}
|
|
258
|
+
await Promise.all(pushPromises)
|
|
259
|
+
|
|
260
|
+
// Consume with high concurrency
|
|
261
|
+
let processedCount = 0
|
|
262
|
+
await client.queue('test-queue-v2-concurrency-mixed')
|
|
263
|
+
.concurrency(10)
|
|
264
|
+
.batch(5)
|
|
265
|
+
.wait(false)
|
|
266
|
+
.limit(10)
|
|
267
|
+
.each()
|
|
268
|
+
.consume(async (msg) => {
|
|
269
|
+
processedCount++
|
|
270
|
+
await new Promise(resolve => setTimeout(resolve, 10))
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
return {
|
|
274
|
+
success: processedCount === 50,
|
|
275
|
+
message: `High concurrency mixed ops: ${processedCount} messages`
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Priority Queue Tests
|
|
3
|
+
* Tests for message priority handling
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export async function testBasicPriority(client) {
|
|
7
|
+
// Create queues with different priorities
|
|
8
|
+
const highPriorityQueue = await client.queue('test-queue-v2-priority-high')
|
|
9
|
+
.config({ priority: 10 })
|
|
10
|
+
.create()
|
|
11
|
+
|
|
12
|
+
const lowPriorityQueue = await client.queue('test-queue-v2-priority-low')
|
|
13
|
+
.config({ priority: 1 })
|
|
14
|
+
.create()
|
|
15
|
+
|
|
16
|
+
if (!highPriorityQueue.configured || !lowPriorityQueue.configured) {
|
|
17
|
+
return { success: false, message: 'Queues not created' }
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Push to low priority first
|
|
21
|
+
await client.queue('test-queue-v2-priority-low')
|
|
22
|
+
.push([{ data: { priority: 'low', message: 'Should process second' } }])
|
|
23
|
+
|
|
24
|
+
// Then push to high priority
|
|
25
|
+
await client.queue('test-queue-v2-priority-high')
|
|
26
|
+
.push([{ data: { priority: 'high', message: 'Should process first' } }])
|
|
27
|
+
|
|
28
|
+
// Note: Testing actual priority processing order requires namespace/task filtering
|
|
29
|
+
// as pop() from specific queue will only get that queue's messages
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
success: true,
|
|
33
|
+
message: 'Priority queues configured successfully'
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function testPriorityWithNamespace(client) {
|
|
38
|
+
const namespace = 'test-priority-namespace'
|
|
39
|
+
|
|
40
|
+
// Create multiple queues in same namespace with different priorities
|
|
41
|
+
await client.queue('test-queue-v2-pri-ns-high')
|
|
42
|
+
.namespace(namespace)
|
|
43
|
+
.config({ priority: 10 })
|
|
44
|
+
.create()
|
|
45
|
+
|
|
46
|
+
await client.queue('test-queue-v2-pri-ns-medium')
|
|
47
|
+
.namespace(namespace)
|
|
48
|
+
.config({ priority: 5 })
|
|
49
|
+
.create()
|
|
50
|
+
|
|
51
|
+
await client.queue('test-queue-v2-pri-ns-low')
|
|
52
|
+
.namespace(namespace)
|
|
53
|
+
.config({ priority: 1 })
|
|
54
|
+
.create()
|
|
55
|
+
|
|
56
|
+
// Push messages in reverse priority order
|
|
57
|
+
await client.queue('test-queue-v2-pri-ns-low')
|
|
58
|
+
.push([{ data: { order: 'third', value: 1 } }])
|
|
59
|
+
|
|
60
|
+
await client.queue('test-queue-v2-pri-ns-medium')
|
|
61
|
+
.push([{ data: { order: 'second', value: 5 } }])
|
|
62
|
+
|
|
63
|
+
await client.queue('test-queue-v2-pri-ns-high')
|
|
64
|
+
.push([{ data: { order: 'first', value: 10 } }])
|
|
65
|
+
|
|
66
|
+
// Pop from namespace (should respect priority)
|
|
67
|
+
const messages = []
|
|
68
|
+
await client.queue()
|
|
69
|
+
.namespace(namespace)
|
|
70
|
+
.batch(3)
|
|
71
|
+
.wait(false)
|
|
72
|
+
.limit(1)
|
|
73
|
+
.consume(async (msgs) => {
|
|
74
|
+
messages.push(...msgs)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
// Messages should be in priority order
|
|
78
|
+
if (messages.length !== 3) {
|
|
79
|
+
return { success: false, message: `Expected 3 messages, got ${messages.length}` }
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// High priority should come first
|
|
83
|
+
const firstIsHighPriority = messages[0].data.value === 10
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
success: firstIsHighPriority,
|
|
87
|
+
message: `Priority ordering: ${messages.map(m => m.data.order).join(', ')}`
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export async function testPriorityWithTask(client) {
|
|
92
|
+
const task = 'test-priority-task'
|
|
93
|
+
|
|
94
|
+
// Create queues with same task but different priorities
|
|
95
|
+
await client.queue('test-queue-v2-pri-task-urgent')
|
|
96
|
+
.task(task)
|
|
97
|
+
.config({ priority: 100 })
|
|
98
|
+
.create()
|
|
99
|
+
|
|
100
|
+
await client.queue('test-queue-v2-pri-task-normal')
|
|
101
|
+
.task(task)
|
|
102
|
+
.config({ priority: 50 })
|
|
103
|
+
.create()
|
|
104
|
+
|
|
105
|
+
// Push to normal first
|
|
106
|
+
await client.queue('test-queue-v2-pri-task-normal')
|
|
107
|
+
.push([{ data: { urgency: 'normal' } }])
|
|
108
|
+
|
|
109
|
+
// Then urgent
|
|
110
|
+
await client.queue('test-queue-v2-pri-task-urgent')
|
|
111
|
+
.push([{ data: { urgency: 'urgent' } }])
|
|
112
|
+
|
|
113
|
+
// Pop from task
|
|
114
|
+
const messages = []
|
|
115
|
+
await client.queue()
|
|
116
|
+
.task(task)
|
|
117
|
+
.batch(2)
|
|
118
|
+
.wait(false)
|
|
119
|
+
.limit(1)
|
|
120
|
+
.consume(async (msgs) => {
|
|
121
|
+
messages.push(...msgs)
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
if (messages.length !== 2) {
|
|
125
|
+
return { success: false, message: `Expected 2 messages, got ${messages.length}` }
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Urgent should come first
|
|
129
|
+
const urgentFirst = messages[0].data.urgency === 'urgent'
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
success: urgentFirst,
|
|
133
|
+
message: 'Task-based priority ordering works'
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export async function testDynamicPriorityChange(client) {
|
|
138
|
+
const queueName = 'test-queue-v2-priority-dynamic'
|
|
139
|
+
|
|
140
|
+
// Create with low priority
|
|
141
|
+
await client.queue(queueName)
|
|
142
|
+
.config({ priority: 1 })
|
|
143
|
+
.create()
|
|
144
|
+
|
|
145
|
+
// Push a message
|
|
146
|
+
await client.queue(queueName)
|
|
147
|
+
.push([{ data: { phase: 'low-priority' } }])
|
|
148
|
+
|
|
149
|
+
// Reconfigure with high priority
|
|
150
|
+
await client.queue(queueName)
|
|
151
|
+
.config({ priority: 10 })
|
|
152
|
+
.create()
|
|
153
|
+
|
|
154
|
+
// Push another message
|
|
155
|
+
await client.queue(queueName)
|
|
156
|
+
.push([{ data: { phase: 'high-priority' } }])
|
|
157
|
+
|
|
158
|
+
// Pop messages
|
|
159
|
+
const messages = await client.queue(queueName)
|
|
160
|
+
.batch(2)
|
|
161
|
+
.wait(false)
|
|
162
|
+
.pop()
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
success: messages.length === 2,
|
|
166
|
+
message: 'Dynamic priority change handled'
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resource & Status API Tests
|
|
3
|
+
* Tests for querying system resources and status
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Helper to make direct HTTP calls
|
|
7
|
+
async function httpGet(url) {
|
|
8
|
+
const response = await fetch(url)
|
|
9
|
+
if (!response.ok) {
|
|
10
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
|
|
11
|
+
}
|
|
12
|
+
return await response.json()
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function testListQueues(client) {
|
|
16
|
+
// Create some test queues
|
|
17
|
+
await client.queue('test-queue-v2-list-1').create()
|
|
18
|
+
await client.queue('test-queue-v2-list-2').create()
|
|
19
|
+
await client.queue('test-queue-v2-list-3').create()
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
const result = await httpGet('http://localhost:6632/api/v1/resources/queues')
|
|
23
|
+
|
|
24
|
+
if (!result || !Array.isArray(result)) {
|
|
25
|
+
return { success: false, message: 'Invalid queue list response' }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const testQueues = result.filter(q => q.name && q.name.startsWith('test-queue-v2-list'))
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
success: testQueues.length >= 3,
|
|
32
|
+
message: `Found ${testQueues.length} test queues`
|
|
33
|
+
}
|
|
34
|
+
} catch (error) {
|
|
35
|
+
return { success: false, message: `Error listing queues: ${error.message}` }
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function testGetQueueDetails(client) {
|
|
40
|
+
const queueName = 'test-queue-v2-details'
|
|
41
|
+
await client.queue(queueName)
|
|
42
|
+
.config({
|
|
43
|
+
leaseTime: 123,
|
|
44
|
+
maxSize: 5000,
|
|
45
|
+
retryLimit: 5
|
|
46
|
+
})
|
|
47
|
+
.create()
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
const result = await httpGet(`http://localhost:6632/api/v1/resources/queues/${queueName}`)
|
|
51
|
+
|
|
52
|
+
if (!result || !result.name) {
|
|
53
|
+
return { success: false, message: 'Invalid queue details response' }
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const hasCorrectConfig = result.name === queueName
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
success: hasCorrectConfig,
|
|
60
|
+
message: 'Queue details retrieved successfully'
|
|
61
|
+
}
|
|
62
|
+
} catch (error) {
|
|
63
|
+
return { success: false, message: `Error getting queue details: ${error.message}` }
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export async function testGetNamespaces(client) {
|
|
68
|
+
// Create queues with different namespaces
|
|
69
|
+
await client.queue('test-queue-v2-ns-1')
|
|
70
|
+
.namespace('test-namespace-alpha')
|
|
71
|
+
.create()
|
|
72
|
+
|
|
73
|
+
await client.queue('test-queue-v2-ns-2')
|
|
74
|
+
.namespace('test-namespace-beta')
|
|
75
|
+
.create()
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
const result = await httpGet('http://localhost:6632/api/v1/resources/namespaces')
|
|
79
|
+
|
|
80
|
+
if (!result || !Array.isArray(result)) {
|
|
81
|
+
return { success: false, message: 'Invalid namespaces response' }
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const testNamespaces = result.filter(ns =>
|
|
85
|
+
typeof ns === 'string' && ns.startsWith('test-namespace')
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
success: testNamespaces.length >= 2,
|
|
90
|
+
message: `Found ${testNamespaces.length} test namespaces`
|
|
91
|
+
}
|
|
92
|
+
} catch (error) {
|
|
93
|
+
return { success: false, message: `Error listing namespaces: ${error.message}` }
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export async function testGetTasks(client) {
|
|
98
|
+
// Create queues with different tasks
|
|
99
|
+
await client.queue('test-queue-v2-task-1')
|
|
100
|
+
.task('test-task-one')
|
|
101
|
+
.create()
|
|
102
|
+
|
|
103
|
+
await client.queue('test-queue-v2-task-2')
|
|
104
|
+
.task('test-task-two')
|
|
105
|
+
.create()
|
|
106
|
+
|
|
107
|
+
try {
|
|
108
|
+
const result = await httpGet('http://localhost:6632/api/v1/resources/tasks')
|
|
109
|
+
|
|
110
|
+
if (!result || !Array.isArray(result)) {
|
|
111
|
+
return { success: false, message: 'Invalid tasks response' }
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const testTasks = result.filter(task =>
|
|
115
|
+
typeof task === 'string' && task.startsWith('test-task')
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
success: testTasks.length >= 2,
|
|
120
|
+
message: `Found ${testTasks.length} test tasks`
|
|
121
|
+
}
|
|
122
|
+
} catch (error) {
|
|
123
|
+
return { success: false, message: `Error listing tasks: ${error.message}` }
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export async function testGetMessages(client) {
|
|
128
|
+
const queueName = 'test-queue-v2-get-messages'
|
|
129
|
+
await client.queue(queueName).create()
|
|
130
|
+
|
|
131
|
+
// Push some messages
|
|
132
|
+
await client.queue(queueName).push([
|
|
133
|
+
{ data: { id: 1 } },
|
|
134
|
+
{ data: { id: 2 } },
|
|
135
|
+
{ data: { id: 3 } }
|
|
136
|
+
])
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
const result = await httpGet(
|
|
140
|
+
`http://localhost:6632/api/v1/messages?queue=${queueName}&status=pending&limit=10`
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
if (!result || !result.messages) {
|
|
144
|
+
return { success: false, message: 'Invalid messages response' }
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
success: result.messages.length >= 3,
|
|
149
|
+
message: `Found ${result.messages.length} pending messages`
|
|
150
|
+
}
|
|
151
|
+
} catch (error) {
|
|
152
|
+
return { success: false, message: `Error getting messages: ${error.message}` }
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export async function testSystemOverview(client) {
|
|
157
|
+
try {
|
|
158
|
+
const result = await httpGet('http://localhost:6632/api/v1/resources/overview')
|
|
159
|
+
|
|
160
|
+
if (!result) {
|
|
161
|
+
return { success: false, message: 'Invalid overview response' }
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Check for expected overview fields
|
|
165
|
+
const hasExpectedFields = 'totalQueues' in result || 'queues' in result
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
success: hasExpectedFields,
|
|
169
|
+
message: 'System overview retrieved successfully'
|
|
170
|
+
}
|
|
171
|
+
} catch (error) {
|
|
172
|
+
return { success: false, message: `Error getting overview: ${error.message}` }
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export async function testHealthCheck(client) {
|
|
177
|
+
try {
|
|
178
|
+
const result = await httpGet('http://localhost:6632/health')
|
|
179
|
+
|
|
180
|
+
if (!result || result.status !== 'healthy') {
|
|
181
|
+
return { success: false, message: 'Health check failed' }
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return {
|
|
185
|
+
success: true,
|
|
186
|
+
message: 'Health check passed'
|
|
187
|
+
}
|
|
188
|
+
} catch (error) {
|
|
189
|
+
return { success: false, message: `Health check error: ${error.message}` }
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export async function testDeleteQueue(client) {
|
|
194
|
+
const queueName = 'test-queue-v2-to-delete'
|
|
195
|
+
await client.queue(queueName).create()
|
|
196
|
+
|
|
197
|
+
// Verify it exists
|
|
198
|
+
const queues1 = await httpGet('http://localhost:6632/api/v1/resources/queues')
|
|
199
|
+
const existsBefore = queues1.some(q => q.name === queueName)
|
|
200
|
+
|
|
201
|
+
if (!existsBefore) {
|
|
202
|
+
return { success: false, message: 'Queue not created' }
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Delete it
|
|
206
|
+
const deleteResult = await client.queue(queueName).delete()
|
|
207
|
+
|
|
208
|
+
if (!deleteResult.deleted) {
|
|
209
|
+
return { success: false, message: 'Queue deletion failed' }
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
success: true,
|
|
214
|
+
message: 'Queue deleted successfully'
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|