@durable-streams/client-conformance-tests 0.1.5 → 0.1.7

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.
Files changed (30) hide show
  1. package/dist/adapters/typescript-adapter.cjs +75 -2
  2. package/dist/adapters/typescript-adapter.js +76 -3
  3. package/dist/{benchmark-runner-C_Yghc8f.js → benchmark-runner-CrE6JkbX.js} +106 -12
  4. package/dist/{benchmark-runner-CLAR9oLd.cjs → benchmark-runner-Db4he452.cjs} +107 -12
  5. package/dist/cli.cjs +1 -1
  6. package/dist/cli.js +1 -1
  7. package/dist/index.cjs +1 -1
  8. package/dist/index.d.cts +126 -11
  9. package/dist/index.d.ts +126 -11
  10. package/dist/index.js +1 -1
  11. package/dist/{protocol-3cf94Xyb.d.cts → protocol-D37G3c4e.d.cts} +80 -4
  12. package/dist/{protocol-DyEvTHPF.d.ts → protocol-Mcbiq3nQ.d.ts} +80 -4
  13. package/dist/protocol.d.cts +2 -2
  14. package/dist/protocol.d.ts +2 -2
  15. package/package.json +3 -3
  16. package/src/adapters/typescript-adapter.ts +127 -5
  17. package/src/protocol.ts +85 -1
  18. package/src/runner.ts +202 -17
  19. package/src/test-cases.ts +130 -8
  20. package/test-cases/consumer/error-handling.yaml +42 -0
  21. package/test-cases/consumer/fault-injection.yaml +202 -0
  22. package/test-cases/consumer/offset-handling.yaml +209 -0
  23. package/test-cases/producer/idempotent/autoclaim.yaml +214 -0
  24. package/test-cases/producer/idempotent/batching.yaml +98 -0
  25. package/test-cases/producer/idempotent/concurrent-requests.yaml +100 -0
  26. package/test-cases/producer/idempotent/epoch-management.yaml +333 -0
  27. package/test-cases/producer/idempotent/error-handling.yaml +194 -0
  28. package/test-cases/producer/idempotent/multi-producer.yaml +322 -0
  29. package/test-cases/producer/idempotent/sequence-validation.yaml +339 -0
  30. package/test-cases/producer/idempotent-json-batching.yaml +134 -0
@@ -0,0 +1,339 @@
1
+ id: idempotent-sequence-validation
2
+ name: Idempotent Producer - Sequence Validation
3
+ description: |
4
+ Tests for producer sequence number validation.
5
+ Sequences must start at 0 and increment monotonically within an epoch.
6
+ category: producer
7
+ tags:
8
+ - idempotent
9
+ - sequence
10
+
11
+ tests:
12
+ - id: first-append-accepted
13
+ name: First append with producer headers is accepted
14
+ description: Server should accept first append with epoch=0, seq=0
15
+ setup:
16
+ - action: create
17
+ as: streamPath
18
+ contentType: text/plain
19
+ operations:
20
+ - action: server-append
21
+ path: ${streamPath}
22
+ data: "hello"
23
+ producerId: test-producer
24
+ producerEpoch: 0
25
+ producerSeq: 0
26
+ expect:
27
+ status: 200
28
+ producerEpoch: 0
29
+
30
+ - id: sequential-sequences
31
+ name: Sequential producer sequences accepted
32
+ description: Server should accept monotonically increasing sequences
33
+ setup:
34
+ - action: create
35
+ as: streamPath
36
+ contentType: text/plain
37
+ operations:
38
+ - action: server-append
39
+ path: ${streamPath}
40
+ data: "msg0"
41
+ producerId: test-producer
42
+ producerEpoch: 0
43
+ producerSeq: 0
44
+ expect:
45
+ status: 200
46
+ - action: server-append
47
+ path: ${streamPath}
48
+ data: "msg1"
49
+ producerId: test-producer
50
+ producerEpoch: 0
51
+ producerSeq: 1
52
+ expect:
53
+ status: 200
54
+ - action: server-append
55
+ path: ${streamPath}
56
+ data: "msg2"
57
+ producerId: test-producer
58
+ producerEpoch: 0
59
+ producerSeq: 2
60
+ expect:
61
+ status: 200
62
+
63
+ - id: sequence-gap-rejected
64
+ name: Sequence gap returns 409
65
+ description: Skipping a sequence number should return 409 with expected/received seq
66
+ setup:
67
+ - action: create
68
+ as: streamPath
69
+ contentType: text/plain
70
+ operations:
71
+ - action: server-append
72
+ path: ${streamPath}
73
+ data: "msg0"
74
+ producerId: test-producer
75
+ producerEpoch: 0
76
+ producerSeq: 0
77
+ expect:
78
+ status: 200
79
+ # Skip seq=1, try seq=2
80
+ - action: server-append
81
+ path: ${streamPath}
82
+ data: "msg2"
83
+ producerId: test-producer
84
+ producerEpoch: 0
85
+ producerSeq: 2
86
+ expect:
87
+ status: 409
88
+ producerExpectedSeq: 1
89
+ producerReceivedSeq: 2
90
+
91
+ - id: new-producer-seq-not-zero
92
+ name: New producer starting with seq > 0 returns 409
93
+ description: A never-seen producer sending seq > 0 should get 409 (gap), not 400
94
+ setup:
95
+ - action: create
96
+ as: streamPath
97
+ contentType: text/plain
98
+ operations:
99
+ - action: server-append
100
+ path: ${streamPath}
101
+ data: "msg"
102
+ producerId: brand-new-producer
103
+ producerEpoch: 0
104
+ producerSeq: 5
105
+ expect:
106
+ status: 409
107
+ producerExpectedSeq: 0
108
+ producerReceivedSeq: 5
109
+
110
+ - id: duplicate-returns-204
111
+ name: Duplicate sequence returns 204 (idempotent success)
112
+ description: Retrying the same seq should return 204 without duplicating data
113
+ setup:
114
+ - action: create
115
+ as: streamPath
116
+ contentType: text/plain
117
+ operations:
118
+ - action: server-append
119
+ path: ${streamPath}
120
+ data: "hello"
121
+ producerId: test-producer
122
+ producerEpoch: 0
123
+ producerSeq: 0
124
+ expect:
125
+ status: 200
126
+ - action: server-append
127
+ path: ${streamPath}
128
+ data: "hello"
129
+ producerId: test-producer
130
+ producerEpoch: 0
131
+ producerSeq: 0
132
+ expect:
133
+ status: 204
134
+ duplicate: true
135
+ # Verify only one message in stream
136
+ - action: read
137
+ path: ${streamPath}
138
+ expect:
139
+ data: "hello"
140
+ upToDate: true
141
+
142
+ - id: duplicate-seq-zero-preserves-state
143
+ name: Duplicate of seq=0 does not corrupt state
144
+ description: Retrying seq=0 should not affect subsequent sequence tracking
145
+ setup:
146
+ - action: create
147
+ as: streamPath
148
+ contentType: text/plain
149
+ operations:
150
+ - action: server-append
151
+ path: ${streamPath}
152
+ data: "first"
153
+ producerId: test-producer
154
+ producerEpoch: 0
155
+ producerSeq: 0
156
+ expect:
157
+ status: 200
158
+ # Retry seq=0
159
+ - action: server-append
160
+ path: ${streamPath}
161
+ data: "first"
162
+ producerId: test-producer
163
+ producerEpoch: 0
164
+ producerSeq: 0
165
+ expect:
166
+ status: 204
167
+ # seq=1 should still work
168
+ - action: server-append
169
+ path: ${streamPath}
170
+ data: "second"
171
+ producerId: test-producer
172
+ producerEpoch: 0
173
+ producerSeq: 1
174
+ expect:
175
+ status: 200
176
+
177
+ - id: duplicate-ignores-different-data
178
+ name: Duplicate seq ignores payload differences
179
+ description: Same (producer, epoch, seq) returns 204 even with different data - dedup is by headers only
180
+ setup:
181
+ - action: create
182
+ as: streamPath
183
+ contentType: text/plain
184
+ operations:
185
+ - action: server-append
186
+ path: ${streamPath}
187
+ data: "original payload"
188
+ producerId: test-producer
189
+ producerEpoch: 0
190
+ producerSeq: 0
191
+ expect:
192
+ status: 200
193
+ # Retry with different data - should still be 204 (idempotent)
194
+ - action: server-append
195
+ path: ${streamPath}
196
+ data: "different payload"
197
+ producerId: test-producer
198
+ producerEpoch: 0
199
+ producerSeq: 0
200
+ expect:
201
+ status: 204
202
+ duplicate: true
203
+ # Verify only original data is in stream
204
+ - action: read
205
+ path: ${streamPath}
206
+ expect:
207
+ data: "original payload"
208
+ upToDate: true
209
+
210
+ - id: ordering-preserved-in-stream
211
+ name: Message ordering preserved in stream
212
+ description: Messages from idempotent producer maintain sequence order
213
+ setup:
214
+ - action: create
215
+ as: streamPath
216
+ contentType: application/json
217
+ operations:
218
+ - action: server-append
219
+ path: ${streamPath}
220
+ data: '{"seq": 0}'
221
+ producerId: order-test
222
+ producerEpoch: 0
223
+ producerSeq: 0
224
+ expect:
225
+ status: 200
226
+ - action: server-append
227
+ path: ${streamPath}
228
+ data: '{"seq": 1}'
229
+ producerId: order-test
230
+ producerEpoch: 0
231
+ producerSeq: 1
232
+ expect:
233
+ status: 200
234
+ - action: server-append
235
+ path: ${streamPath}
236
+ data: '{"seq": 2}'
237
+ producerId: order-test
238
+ producerEpoch: 0
239
+ producerSeq: 2
240
+ expect:
241
+ status: 200
242
+ - action: read
243
+ path: ${streamPath}
244
+ expect:
245
+ dataContainsAll:
246
+ - '"seq":0'
247
+ - '"seq":1'
248
+ - '"seq":2'
249
+ upToDate: true
250
+
251
+ - id: duplicate-old-sequence
252
+ name: Duplicate of old (non-tail) sequence returns 204
253
+ description: |
254
+ Retrying a sequence far back in history should still return 204.
255
+ This tests that the server tracks more than just the last sequence.
256
+ (Kafka distinguishes DuplicateSequenceException vs OutOfOrderSequenceException)
257
+ setup:
258
+ - action: create
259
+ as: streamPath
260
+ contentType: text/plain
261
+ operations:
262
+ # Send sequences 0-5
263
+ - action: server-append
264
+ path: ${streamPath}
265
+ data: "msg0"
266
+ producerId: test-producer
267
+ producerEpoch: 0
268
+ producerSeq: 0
269
+ expect:
270
+ status: 200
271
+ - action: server-append
272
+ path: ${streamPath}
273
+ data: "msg1"
274
+ producerId: test-producer
275
+ producerEpoch: 0
276
+ producerSeq: 1
277
+ expect:
278
+ status: 200
279
+ - action: server-append
280
+ path: ${streamPath}
281
+ data: "msg2"
282
+ producerId: test-producer
283
+ producerEpoch: 0
284
+ producerSeq: 2
285
+ expect:
286
+ status: 200
287
+ - action: server-append
288
+ path: ${streamPath}
289
+ data: "msg3"
290
+ producerId: test-producer
291
+ producerEpoch: 0
292
+ producerSeq: 3
293
+ expect:
294
+ status: 200
295
+ - action: server-append
296
+ path: ${streamPath}
297
+ data: "msg4"
298
+ producerId: test-producer
299
+ producerEpoch: 0
300
+ producerSeq: 4
301
+ expect:
302
+ status: 200
303
+ - action: server-append
304
+ path: ${streamPath}
305
+ data: "msg5"
306
+ producerId: test-producer
307
+ producerEpoch: 0
308
+ producerSeq: 5
309
+ expect:
310
+ status: 200
311
+ # Retry seq=1 (old, non-tail sequence)
312
+ - action: server-append
313
+ path: ${streamPath}
314
+ data: "msg1"
315
+ producerId: test-producer
316
+ producerEpoch: 0
317
+ producerSeq: 1
318
+ expect:
319
+ status: 204
320
+ duplicate: true
321
+ # Retry seq=0 (first sequence)
322
+ - action: server-append
323
+ path: ${streamPath}
324
+ data: "msg0"
325
+ producerId: test-producer
326
+ producerEpoch: 0
327
+ producerSeq: 0
328
+ expect:
329
+ status: 204
330
+ duplicate: true
331
+ # New sequence should still work
332
+ - action: server-append
333
+ path: ${streamPath}
334
+ data: "msg6"
335
+ producerId: test-producer
336
+ producerEpoch: 0
337
+ producerSeq: 6
338
+ expect:
339
+ status: 200
@@ -0,0 +1,134 @@
1
+ id: idempotent-json-batching
2
+ name: Idempotent Producer JSON Batching
3
+ description: Tests for client-side JSON batching in IdempotentProducer
4
+ category: producer
5
+ tags:
6
+ - idempotent
7
+ - json
8
+ - batching
9
+
10
+ tests:
11
+ - id: json-batch-single-item
12
+ name: Single JSON item via IdempotentProducer
13
+ description: A single JSON value should be wrapped in array and stored correctly
14
+ setup:
15
+ - action: create
16
+ as: streamPath
17
+ contentType: application/json
18
+ operations:
19
+ - action: idempotent-append
20
+ path: ${streamPath}
21
+ producerId: test-producer
22
+ epoch: 0
23
+ data: '{"message": "hello"}'
24
+ expect:
25
+ status: 200
26
+ - action: read
27
+ path: ${streamPath}
28
+ expect:
29
+ # JSON streams return data as array
30
+ data: '[{"message":"hello"}]'
31
+ upToDate: true
32
+
33
+ - id: json-batch-multiple-items
34
+ name: Multiple JSON items batched via IdempotentProducer
35
+ description: Multiple JSON values should be batched into single request and stored as separate entries
36
+ setup:
37
+ - action: create
38
+ as: streamPath
39
+ contentType: application/json
40
+ operations:
41
+ - action: idempotent-append-batch
42
+ path: ${streamPath}
43
+ producerId: test-producer
44
+ epoch: 0
45
+ items:
46
+ - data: '{"id": 1}'
47
+ - data: '{"id": 2}'
48
+ - data: '{"id": 3}'
49
+ expect:
50
+ allSucceed: true
51
+ - action: read
52
+ path: ${streamPath}
53
+ expect:
54
+ # Each item should be stored separately, read back as JSON array
55
+ dataContainsAll:
56
+ - '"id":1'
57
+ - '"id":2'
58
+ - '"id":3'
59
+ upToDate: true
60
+
61
+ - id: json-batch-nested-arrays
62
+ name: JSON arrays batched correctly
63
+ description: Batched JSON arrays should each be stored as single entries, not flattened further
64
+ setup:
65
+ - action: create
66
+ as: streamPath
67
+ contentType: application/json
68
+ operations:
69
+ - action: idempotent-append-batch
70
+ path: ${streamPath}
71
+ producerId: test-producer
72
+ epoch: 0
73
+ items:
74
+ - data: "[1, 2, 3]"
75
+ - data: "[4, 5, 6]"
76
+ expect:
77
+ allSucceed: true
78
+ - action: read
79
+ path: ${streamPath}
80
+ expect:
81
+ # Each array should be stored as a single entry (JSON normalized without spaces)
82
+ dataContainsAll:
83
+ - "[1,2,3]"
84
+ - "[4,5,6]"
85
+ upToDate: true
86
+
87
+ - id: json-batch-mixed-types
88
+ name: Mixed JSON types batched correctly
89
+ description: Batched values of different JSON types should each be stored correctly
90
+ setup:
91
+ - action: create
92
+ as: streamPath
93
+ contentType: application/json
94
+ operations:
95
+ - action: idempotent-append-batch
96
+ path: ${streamPath}
97
+ producerId: test-producer
98
+ epoch: 0
99
+ items:
100
+ - data: "42"
101
+ - data: '"string"'
102
+ - data: "null"
103
+ - data: "true"
104
+ - data: '{"obj": 1}'
105
+ expect:
106
+ allSucceed: true
107
+ - action: read
108
+ path: ${streamPath}
109
+ expect:
110
+ upToDate: true
111
+
112
+ - id: bytes-batch-concatenates
113
+ name: Byte stream batching concatenates data
114
+ description: For non-JSON streams, batched items should be concatenated
115
+ setup:
116
+ - action: create
117
+ as: streamPath
118
+ contentType: text/plain
119
+ operations:
120
+ - action: idempotent-append-batch
121
+ path: ${streamPath}
122
+ producerId: test-producer
123
+ epoch: 0
124
+ items:
125
+ - data: "Hello"
126
+ - data: " "
127
+ - data: "World"
128
+ expect:
129
+ allSucceed: true
130
+ - action: read
131
+ path: ${streamPath}
132
+ expect:
133
+ data: "Hello World"
134
+ upToDate: true