queen-mq 0.12.0 → 0.12.2
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/client-v2/Queen.js +5 -3
- package/client-v2/builders/TransactionBuilder.js +11 -4
- package/client-v2/http/HttpClient.js +7 -2
- package/client-v2/utils/defaults.js +2 -1
- package/package.json +1 -1
- package/test-v2/bootstrap.js +316 -0
- package/test-v2/run.js +4 -15
- package/test-v2/transaction.js +66 -0
- package/test-v2/AI_TEST_SUMMARY.md +0 -226
- package/test-v2/GETTING_STARTED.md +0 -181
- package/test-v2/MAINTENANCE_TEST.md +0 -148
- package/test-v2/README_SUBSCRIPTION_TESTS.md +0 -201
- package/test-v2/ai_buffering.js +0 -194
- package/test-v2/ai_error_handling.js +0 -223
- package/test-v2/ai_lease_renewal.js +0 -206
- package/test-v2/ai_mixed_scenarios.js +0 -278
- package/test-v2/ai_priority.js +0 -169
- package/test-v2/ai_resources.js +0 -217
- package/test-v2/ai_ttl_retention.js +0 -170
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
# Subscription Mode Tests
|
|
2
|
-
|
|
3
|
-
Tests for consumer group subscription modes, compatible with any server `DEFAULT_SUBSCRIPTION_MODE` configuration.
|
|
4
|
-
|
|
5
|
-
## Test Overview
|
|
6
|
-
|
|
7
|
-
| Test Function | Description | Explicit Mode Used |
|
|
8
|
-
|--------------|-------------|-------------------|
|
|
9
|
-
| `subscriptionModeNew` | Validates `.subscriptionMode('new')` skips historical messages | Yes (`new`) |
|
|
10
|
-
| `subscriptionModeNewOnly` | Validates alias `.subscriptionMode('new-only')` | Yes (`new-only`) |
|
|
11
|
-
| `subscriptionFromNow` | Validates `.subscriptionFrom('now')` | Yes (`now`) |
|
|
12
|
-
| `subscriptionFromTimestamp` | Validates timestamp-based subscription | Yes (timestamp) |
|
|
13
|
-
| `subscriptionModeAll` | Tests default behavior (depends on server config) | Mixed |
|
|
14
|
-
| `subscriptionModeServerDefault` | **NEW:** Detects and validates server default | Mixed |
|
|
15
|
-
|
|
16
|
-
## Running the Tests
|
|
17
|
-
|
|
18
|
-
### Run all subscription tests:
|
|
19
|
-
```bash
|
|
20
|
-
cd client-js/test-v2
|
|
21
|
-
node run.js subscription
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
### Run specific subscription test:
|
|
25
|
-
```bash
|
|
26
|
-
node run.js subscriptionModeNew
|
|
27
|
-
node run.js subscriptionModeServerDefault
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
## Server Configuration Compatibility
|
|
31
|
-
|
|
32
|
-
These tests work with **any** server `DEFAULT_SUBSCRIPTION_MODE` configuration:
|
|
33
|
-
|
|
34
|
-
### Configuration 1: Standard (Default)
|
|
35
|
-
|
|
36
|
-
```bash
|
|
37
|
-
# Start server without default
|
|
38
|
-
./bin/queen-server
|
|
39
|
-
|
|
40
|
-
# Run tests
|
|
41
|
-
node run.js subscription
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
**Expected Behavior:**
|
|
45
|
-
- Consumer groups without explicit mode process all historical messages
|
|
46
|
-
- Consumer groups with `.subscriptionMode('new')` skip history
|
|
47
|
-
- `subscriptionModeServerDefault` reports: "all (or empty string)"
|
|
48
|
-
|
|
49
|
-
### Configuration 2: With DEFAULT_SUBSCRIPTION_MODE="new"
|
|
50
|
-
|
|
51
|
-
```bash
|
|
52
|
-
# Start server with "new" as default
|
|
53
|
-
DEFAULT_SUBSCRIPTION_MODE="new" ./bin/queen-server
|
|
54
|
-
|
|
55
|
-
# Run tests
|
|
56
|
-
node run.js subscription
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
**Expected Behavior:**
|
|
60
|
-
- Consumer groups without explicit mode skip historical messages
|
|
61
|
-
- Consumer groups with `.subscriptionMode('new')` skip history (same)
|
|
62
|
-
- `subscriptionModeServerDefault` reports: "new"
|
|
63
|
-
|
|
64
|
-
**✅ All tests pass with both configurations!**
|
|
65
|
-
|
|
66
|
-
## Test Details
|
|
67
|
-
|
|
68
|
-
### subscriptionModeNew
|
|
69
|
-
|
|
70
|
-
Tests the explicit `.subscriptionMode('new')` behavior:
|
|
71
|
-
|
|
72
|
-
1. Pushes 5 historical messages
|
|
73
|
-
2. Creates two consumer groups:
|
|
74
|
-
- One without explicit mode (behavior depends on server)
|
|
75
|
-
- One with `.subscriptionMode('new')` (always skips)
|
|
76
|
-
3. Verifies the `new` mode group gets 0 historical messages
|
|
77
|
-
4. Pushes 3 new messages
|
|
78
|
-
5. Verifies both groups get the new messages
|
|
79
|
-
|
|
80
|
-
**Key Assertion:** `.subscriptionMode('new')` always skips historical messages.
|
|
81
|
-
|
|
82
|
-
### subscriptionModeServerDefault (NEW)
|
|
83
|
-
|
|
84
|
-
Detects and validates the server's default subscription mode:
|
|
85
|
-
|
|
86
|
-
1. Pushes historical messages
|
|
87
|
-
2. Creates consumer group WITHOUT explicit subscription mode
|
|
88
|
-
3. Detects server default based on behavior:
|
|
89
|
-
- Got historical messages → server default is "all"
|
|
90
|
-
- Got 0 messages → server default is "new"
|
|
91
|
-
4. Validates explicit `.subscriptionMode('new')` still works
|
|
92
|
-
5. Verifies new messages are received by both groups
|
|
93
|
-
|
|
94
|
-
**Key Assertion:** Server default affects groups without explicit mode, but explicit modes always work.
|
|
95
|
-
|
|
96
|
-
### subscriptionFromTimestamp
|
|
97
|
-
|
|
98
|
-
Tests timestamp-based subscription:
|
|
99
|
-
|
|
100
|
-
1. Pushes "first batch" of messages
|
|
101
|
-
2. Records cutoff timestamp
|
|
102
|
-
3. Pushes "second batch" of messages
|
|
103
|
-
4. Creates consumer group with `.subscriptionFrom(cutoffTimestamp)`
|
|
104
|
-
5. Verifies only messages after timestamp are received
|
|
105
|
-
|
|
106
|
-
**Note:** Timestamp precision may vary based on database clock.
|
|
107
|
-
|
|
108
|
-
## Common Issues
|
|
109
|
-
|
|
110
|
-
### Issue: Test fails with "expected X, got Y"
|
|
111
|
-
|
|
112
|
-
**Cause:** Server has different default than test expects.
|
|
113
|
-
|
|
114
|
-
**Solution:** Check server configuration:
|
|
115
|
-
```bash
|
|
116
|
-
# Check if DEFAULT_SUBSCRIPTION_MODE is set
|
|
117
|
-
echo $DEFAULT_SUBSCRIPTION_MODE
|
|
118
|
-
|
|
119
|
-
# Check server logs on startup
|
|
120
|
-
LOG_LEVEL=debug ./bin/queen-server | grep "default subscription"
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
### Issue: Consumer group exists from previous run
|
|
124
|
-
|
|
125
|
-
**Cause:** Consumer groups persist between test runs.
|
|
126
|
-
|
|
127
|
-
**Solution:** The test runner cleans up test data automatically:
|
|
128
|
-
```javascript
|
|
129
|
-
await dbPool.query(`DELETE FROM queen.queues WHERE name LIKE 'test-%'`)
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
Or manually:
|
|
133
|
-
```sql
|
|
134
|
-
DELETE FROM queen.partition_consumers
|
|
135
|
-
WHERE consumer_group LIKE 'group-%';
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
### Issue: Timing-related test failures
|
|
139
|
-
|
|
140
|
-
**Cause:** Messages not fully persisted before consumption.
|
|
141
|
-
|
|
142
|
-
**Solution:** Tests include appropriate delays. If still failing, increase delays:
|
|
143
|
-
```javascript
|
|
144
|
-
await new Promise(resolve => setTimeout(resolve, 500)) // Increase if needed
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
## Adding New Subscription Tests
|
|
148
|
-
|
|
149
|
-
When adding new subscription mode tests:
|
|
150
|
-
|
|
151
|
-
1. **Use unique queue/group names** to avoid conflicts
|
|
152
|
-
2. **Be explicit about subscription modes** in test assertions
|
|
153
|
-
3. **Document expected behavior** for both server configurations
|
|
154
|
-
4. **Use descriptive group names** like `group-explicit-new` vs `group-default`
|
|
155
|
-
|
|
156
|
-
Example:
|
|
157
|
-
```javascript
|
|
158
|
-
export async function testNewFeature(client) {
|
|
159
|
-
// Setup
|
|
160
|
-
await client.queue('test-new-feature').create()
|
|
161
|
-
|
|
162
|
-
// Test explicit behavior (works with any server default)
|
|
163
|
-
const result = await client
|
|
164
|
-
.queue('test-new-feature')
|
|
165
|
-
.group('group-explicit-new')
|
|
166
|
-
.subscriptionMode('new') // Explicit!
|
|
167
|
-
.pop()
|
|
168
|
-
|
|
169
|
-
// Assert based on explicit mode, not server default
|
|
170
|
-
// ...
|
|
171
|
-
}
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
## Debugging Failed Tests
|
|
175
|
-
|
|
176
|
-
Enable detailed logging:
|
|
177
|
-
|
|
178
|
-
```bash
|
|
179
|
-
# Client logging
|
|
180
|
-
QUEEN_CLIENT_LOG=true node run.js subscriptionModeNew
|
|
181
|
-
|
|
182
|
-
# Server logging
|
|
183
|
-
LOG_LEVEL=debug ./bin/queen-server
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
Look for these log lines:
|
|
187
|
-
```
|
|
188
|
-
Consumer group 'group-xxx' exists: false, has subscription options: true
|
|
189
|
-
Subscription mode 'new' - starting from latest message: <uuid>
|
|
190
|
-
Applying default subscription mode 'new' for consumer group 'group-yyy'
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
## Summary
|
|
194
|
-
|
|
195
|
-
- ✅ Tests work with any `DEFAULT_SUBSCRIPTION_MODE` configuration
|
|
196
|
-
- ✅ Explicit subscription modes are always tested and validated
|
|
197
|
-
- ✅ Server default behavior is detected and reported
|
|
198
|
-
- ✅ All tests are documented and maintainable
|
|
199
|
-
|
|
200
|
-
Run the tests and see them pass! 🎉
|
|
201
|
-
|
package/test-v2/ai_buffering.js
DELETED
|
@@ -1,194 +0,0 @@
|
|
|
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
|
-
|
|
@@ -1,223 +0,0 @@
|
|
|
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
|
-
|