typedkafka 0.3.1__py3-none-any.whl
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.
- typedkafka/__init__.py +53 -0
- typedkafka/admin.py +336 -0
- typedkafka/aio.py +328 -0
- typedkafka/config.py +405 -0
- typedkafka/consumer.py +415 -0
- typedkafka/exceptions.py +130 -0
- typedkafka/producer.py +492 -0
- typedkafka/retry.py +154 -0
- typedkafka/serializers.py +293 -0
- typedkafka/testing.py +523 -0
- typedkafka-0.3.1.dist-info/METADATA +263 -0
- typedkafka-0.3.1.dist-info/RECORD +14 -0
- typedkafka-0.3.1.dist-info/WHEEL +4 -0
- typedkafka-0.3.1.dist-info/licenses/LICENSE +21 -0
typedkafka/testing.py
ADDED
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Testing utilities for typedkafka - Mock producer and consumer for unit tests.
|
|
3
|
+
|
|
4
|
+
This module provides mock implementations that don't require a running Kafka broker,
|
|
5
|
+
making it easy to write fast, reliable unit tests for code that uses Kafka.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from collections import defaultdict
|
|
9
|
+
from typing import Any, Callable, Optional
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class MockMessage:
|
|
13
|
+
"""
|
|
14
|
+
A mock Kafka message for testing.
|
|
15
|
+
|
|
16
|
+
Attributes:
|
|
17
|
+
topic: The topic this message was sent to
|
|
18
|
+
value: The message value
|
|
19
|
+
key: The message key (optional)
|
|
20
|
+
partition: The partition number
|
|
21
|
+
offset: The message offset
|
|
22
|
+
headers: Message headers
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
topic: str,
|
|
28
|
+
value: bytes,
|
|
29
|
+
key: Optional[bytes] = None,
|
|
30
|
+
partition: int = 0,
|
|
31
|
+
offset: int = 0,
|
|
32
|
+
headers: Optional[list[tuple[str, bytes]]] = None,
|
|
33
|
+
):
|
|
34
|
+
"""
|
|
35
|
+
Initialize a mock message.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
topic: Topic name
|
|
39
|
+
value: Message value as bytes
|
|
40
|
+
key: Optional message key
|
|
41
|
+
partition: Partition number (default: 0)
|
|
42
|
+
offset: Message offset (default: 0)
|
|
43
|
+
headers: Optional list of (key, value) header tuples
|
|
44
|
+
"""
|
|
45
|
+
self.topic = topic
|
|
46
|
+
self.value = value
|
|
47
|
+
self.key = key
|
|
48
|
+
self.partition = partition
|
|
49
|
+
self.offset = offset
|
|
50
|
+
self.headers = headers or []
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class MockProducer:
|
|
54
|
+
"""
|
|
55
|
+
A mock Kafka producer for testing.
|
|
56
|
+
|
|
57
|
+
Records all messages sent to topics without actually sending to Kafka.
|
|
58
|
+
Perfect for unit tests to verify your code sends the right messages.
|
|
59
|
+
|
|
60
|
+
Examples:
|
|
61
|
+
>>> producer = MockProducer()
|
|
62
|
+
>>> producer.send("my-topic", b"test message", key=b"test-key")
|
|
63
|
+
>>>
|
|
64
|
+
>>> # Verify the message was sent
|
|
65
|
+
>>> assert len(producer.messages["my-topic"]) == 1
|
|
66
|
+
>>> msg = producer.messages["my-topic"][0]
|
|
67
|
+
>>> assert msg.value == b"test message"
|
|
68
|
+
>>> assert msg.key == b"test-key"
|
|
69
|
+
|
|
70
|
+
Attributes:
|
|
71
|
+
messages: Dict mapping topic names to lists of MockMessage objects
|
|
72
|
+
call_count: Number of times send() was called
|
|
73
|
+
flushed: Whether flush() has been called
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
def __init__(self, config: Optional[dict[str, Any]] = None):
|
|
77
|
+
"""
|
|
78
|
+
Initialize a mock producer.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
config: Optional config dict (ignored, but accepted for compatibility)
|
|
82
|
+
"""
|
|
83
|
+
self.config = config or {}
|
|
84
|
+
self.messages: dict[str, list[MockMessage]] = defaultdict(list)
|
|
85
|
+
self.call_count = 0
|
|
86
|
+
self.flushed = False
|
|
87
|
+
self._closed = False
|
|
88
|
+
self._in_transaction = False
|
|
89
|
+
self._transaction_messages: list[tuple[str, MockMessage]] = []
|
|
90
|
+
|
|
91
|
+
def send(
|
|
92
|
+
self,
|
|
93
|
+
topic: str,
|
|
94
|
+
value: bytes,
|
|
95
|
+
key: Optional[bytes] = None,
|
|
96
|
+
partition: Optional[int] = None,
|
|
97
|
+
on_delivery: Optional[Callable[[Any, Any], None]] = None,
|
|
98
|
+
) -> None:
|
|
99
|
+
"""
|
|
100
|
+
Record a message send (doesn't actually send to Kafka).
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
topic: Topic to send to
|
|
104
|
+
value: Message value
|
|
105
|
+
key: Optional message key
|
|
106
|
+
partition: Optional partition (default: 0)
|
|
107
|
+
on_delivery: Optional callback (will be called immediately with success)
|
|
108
|
+
|
|
109
|
+
Examples:
|
|
110
|
+
>>> producer = MockProducer()
|
|
111
|
+
>>> producer.send("events", b"data", key=b"key-1")
|
|
112
|
+
>>> assert len(producer.messages["events"]) == 1
|
|
113
|
+
"""
|
|
114
|
+
self.call_count += 1
|
|
115
|
+
offset = len(self.messages[topic])
|
|
116
|
+
|
|
117
|
+
msg = MockMessage(
|
|
118
|
+
topic=topic,
|
|
119
|
+
value=value,
|
|
120
|
+
key=key,
|
|
121
|
+
partition=partition or 0,
|
|
122
|
+
offset=offset,
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
if self._in_transaction:
|
|
126
|
+
self._transaction_messages.append((topic, msg))
|
|
127
|
+
else:
|
|
128
|
+
self.messages[topic].append(msg)
|
|
129
|
+
|
|
130
|
+
# Call delivery callback with success
|
|
131
|
+
if on_delivery:
|
|
132
|
+
on_delivery(None, msg)
|
|
133
|
+
|
|
134
|
+
def send_json(
|
|
135
|
+
self,
|
|
136
|
+
topic: str,
|
|
137
|
+
value: Any,
|
|
138
|
+
key: Optional[str] = None,
|
|
139
|
+
partition: Optional[int] = None,
|
|
140
|
+
on_delivery: Optional[Callable[[Any, Any], None]] = None,
|
|
141
|
+
) -> None:
|
|
142
|
+
"""
|
|
143
|
+
Record a JSON message send.
|
|
144
|
+
|
|
145
|
+
Args:
|
|
146
|
+
topic: Topic to send to
|
|
147
|
+
value: JSON-serializable value
|
|
148
|
+
key: Optional string key
|
|
149
|
+
partition: Optional partition
|
|
150
|
+
on_delivery: Optional delivery callback
|
|
151
|
+
|
|
152
|
+
Examples:
|
|
153
|
+
>>> producer = MockProducer()
|
|
154
|
+
>>> producer.send_json("events", {"user_id": 123})
|
|
155
|
+
>>> import json
|
|
156
|
+
>>> data = json.loads(producer.messages["events"][0].value)
|
|
157
|
+
>>> assert data["user_id"] == 123
|
|
158
|
+
"""
|
|
159
|
+
import json
|
|
160
|
+
|
|
161
|
+
value_bytes = json.dumps(value).encode("utf-8")
|
|
162
|
+
key_bytes = key.encode("utf-8") if key else None
|
|
163
|
+
self.send(topic, value_bytes, key=key_bytes, partition=partition, on_delivery=on_delivery)
|
|
164
|
+
|
|
165
|
+
def send_string(
|
|
166
|
+
self,
|
|
167
|
+
topic: str,
|
|
168
|
+
value: str,
|
|
169
|
+
key: Optional[str] = None,
|
|
170
|
+
partition: Optional[int] = None,
|
|
171
|
+
on_delivery: Optional[Callable[[Any, Any], None]] = None,
|
|
172
|
+
) -> None:
|
|
173
|
+
"""
|
|
174
|
+
Record a string message send.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
topic: Topic to send to
|
|
178
|
+
value: String value
|
|
179
|
+
key: Optional string key
|
|
180
|
+
partition: Optional partition
|
|
181
|
+
on_delivery: Optional delivery callback
|
|
182
|
+
"""
|
|
183
|
+
value_bytes = value.encode("utf-8")
|
|
184
|
+
key_bytes = key.encode("utf-8") if key else None
|
|
185
|
+
self.send(topic, value_bytes, key=key_bytes, partition=partition, on_delivery=on_delivery)
|
|
186
|
+
|
|
187
|
+
def send_batch(
|
|
188
|
+
self,
|
|
189
|
+
topic: str,
|
|
190
|
+
messages: list[tuple[bytes, Optional[bytes]]],
|
|
191
|
+
on_delivery: Optional[Callable[[Any, Any], None]] = None,
|
|
192
|
+
) -> None:
|
|
193
|
+
"""
|
|
194
|
+
Record a batch of message sends.
|
|
195
|
+
|
|
196
|
+
Args:
|
|
197
|
+
topic: Topic to send to
|
|
198
|
+
messages: List of (value, key) tuples
|
|
199
|
+
on_delivery: Optional delivery callback
|
|
200
|
+
"""
|
|
201
|
+
for value, key in messages:
|
|
202
|
+
self.send(topic, value, key=key, on_delivery=on_delivery)
|
|
203
|
+
|
|
204
|
+
def flush(self, timeout: float = -1) -> int:
|
|
205
|
+
"""
|
|
206
|
+
Mark producer as flushed (no-op in mock).
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
timeout: Ignored in mock
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
0 (always successful in mock)
|
|
213
|
+
|
|
214
|
+
Examples:
|
|
215
|
+
>>> producer = MockProducer()
|
|
216
|
+
>>> producer.send("topic", b"msg")
|
|
217
|
+
>>> remaining = producer.flush()
|
|
218
|
+
>>> assert remaining == 0
|
|
219
|
+
>>> assert producer.flushed is True
|
|
220
|
+
"""
|
|
221
|
+
self.flushed = True
|
|
222
|
+
return 0
|
|
223
|
+
|
|
224
|
+
def close(self) -> None:
|
|
225
|
+
"""Mark producer as closed."""
|
|
226
|
+
self._closed = True
|
|
227
|
+
self.flush()
|
|
228
|
+
|
|
229
|
+
def init_transactions(self, timeout: float = 30.0) -> None:
|
|
230
|
+
"""Initialize transactions (no-op in mock)."""
|
|
231
|
+
pass
|
|
232
|
+
|
|
233
|
+
def begin_transaction(self) -> None:
|
|
234
|
+
"""Begin a mock transaction."""
|
|
235
|
+
self._in_transaction = True
|
|
236
|
+
self._transaction_messages = []
|
|
237
|
+
|
|
238
|
+
def commit_transaction(self, timeout: float = 30.0) -> None:
|
|
239
|
+
"""Commit the mock transaction, flushing buffered messages."""
|
|
240
|
+
for topic, msg in self._transaction_messages:
|
|
241
|
+
self.messages[topic].append(msg)
|
|
242
|
+
self._transaction_messages = []
|
|
243
|
+
self._in_transaction = False
|
|
244
|
+
|
|
245
|
+
def abort_transaction(self, timeout: float = 30.0) -> None:
|
|
246
|
+
"""Abort the mock transaction, discarding buffered messages."""
|
|
247
|
+
self._transaction_messages = []
|
|
248
|
+
self._in_transaction = False
|
|
249
|
+
|
|
250
|
+
def transaction(self) -> "MockTransactionContext":
|
|
251
|
+
"""Return a mock transaction context manager."""
|
|
252
|
+
return MockTransactionContext(self)
|
|
253
|
+
|
|
254
|
+
def reset(self) -> None:
|
|
255
|
+
"""
|
|
256
|
+
Clear all recorded messages and reset state.
|
|
257
|
+
|
|
258
|
+
Useful for reusing the same mock across multiple test cases.
|
|
259
|
+
|
|
260
|
+
Examples:
|
|
261
|
+
>>> producer = MockProducer()
|
|
262
|
+
>>> producer.send("topic", b"msg1")
|
|
263
|
+
>>> producer.reset()
|
|
264
|
+
>>> assert len(producer.messages) == 0
|
|
265
|
+
>>> assert producer.call_count == 0
|
|
266
|
+
"""
|
|
267
|
+
self.messages.clear()
|
|
268
|
+
self.call_count = 0
|
|
269
|
+
self.flushed = False
|
|
270
|
+
self._closed = False
|
|
271
|
+
self._in_transaction = False
|
|
272
|
+
self._transaction_messages = []
|
|
273
|
+
|
|
274
|
+
def __enter__(self) -> "MockProducer":
|
|
275
|
+
"""Context manager entry."""
|
|
276
|
+
return self
|
|
277
|
+
|
|
278
|
+
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
279
|
+
"""Context manager exit."""
|
|
280
|
+
self.close()
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
class MockTransactionContext:
|
|
284
|
+
"""Mock transaction context manager for testing."""
|
|
285
|
+
|
|
286
|
+
def __init__(self, producer: MockProducer):
|
|
287
|
+
self._producer = producer
|
|
288
|
+
|
|
289
|
+
def __enter__(self) -> "MockTransactionContext":
|
|
290
|
+
self._producer.begin_transaction()
|
|
291
|
+
return self
|
|
292
|
+
|
|
293
|
+
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
294
|
+
if exc_type is not None:
|
|
295
|
+
self._producer.abort_transaction()
|
|
296
|
+
else:
|
|
297
|
+
self._producer.commit_transaction()
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
class MockConsumer:
|
|
301
|
+
"""
|
|
302
|
+
A mock Kafka consumer for testing.
|
|
303
|
+
|
|
304
|
+
Allows you to inject predefined messages for testing code that consumes from Kafka.
|
|
305
|
+
|
|
306
|
+
Examples:
|
|
307
|
+
>>> consumer = MockConsumer()
|
|
308
|
+
>>> consumer.add_message("my-topic", b"test message", key=b"test-key")
|
|
309
|
+
>>> consumer.subscribe(["my-topic"])
|
|
310
|
+
>>>
|
|
311
|
+
>>> msg = consumer.poll()
|
|
312
|
+
>>> assert msg.value == b"test message"
|
|
313
|
+
>>> assert msg.key == b"test-key"
|
|
314
|
+
|
|
315
|
+
Attributes:
|
|
316
|
+
messages: Queue of MockMessage objects to be consumed
|
|
317
|
+
subscribed_topics: List of subscribed topics
|
|
318
|
+
committed_offsets: Dict of committed offsets by topic/partition
|
|
319
|
+
poll_timeout: Timeout used by __iter__ (matches KafkaConsumer)
|
|
320
|
+
"""
|
|
321
|
+
|
|
322
|
+
def __init__(self, config: Optional[dict[str, Any]] = None):
|
|
323
|
+
"""
|
|
324
|
+
Initialize a mock consumer.
|
|
325
|
+
|
|
326
|
+
Args:
|
|
327
|
+
config: Optional config dict (ignored, but accepted for compatibility)
|
|
328
|
+
"""
|
|
329
|
+
self.config = config or {}
|
|
330
|
+
self.messages: list[MockMessage] = []
|
|
331
|
+
self.subscribed_topics: list[str] = []
|
|
332
|
+
self.committed_offsets: dict[tuple[str, int], int] = {}
|
|
333
|
+
self._closed = False
|
|
334
|
+
self._message_index = 0
|
|
335
|
+
self.poll_timeout: float = 1.0
|
|
336
|
+
|
|
337
|
+
def add_message(
|
|
338
|
+
self,
|
|
339
|
+
topic: str,
|
|
340
|
+
value: bytes,
|
|
341
|
+
key: Optional[bytes] = None,
|
|
342
|
+
partition: int = 0,
|
|
343
|
+
offset: Optional[int] = None,
|
|
344
|
+
headers: Optional[list[tuple[str, bytes]]] = None,
|
|
345
|
+
) -> None:
|
|
346
|
+
"""
|
|
347
|
+
Add a message to be consumed.
|
|
348
|
+
|
|
349
|
+
Call this in your tests to inject messages that your code will consume.
|
|
350
|
+
|
|
351
|
+
Args:
|
|
352
|
+
topic: Topic name
|
|
353
|
+
value: Message value
|
|
354
|
+
key: Optional message key
|
|
355
|
+
partition: Partition number (default: 0)
|
|
356
|
+
offset: Message offset (auto-generated if None)
|
|
357
|
+
headers: Optional message headers
|
|
358
|
+
|
|
359
|
+
Examples:
|
|
360
|
+
>>> consumer = MockConsumer()
|
|
361
|
+
>>> consumer.add_message("events", b'{"user_id": 123}')
|
|
362
|
+
>>> consumer.add_message("events", b'{"user_id": 456}')
|
|
363
|
+
>>> assert len(consumer.messages) == 2
|
|
364
|
+
"""
|
|
365
|
+
if offset is None:
|
|
366
|
+
offset = len(self.messages)
|
|
367
|
+
|
|
368
|
+
msg = MockMessage(
|
|
369
|
+
topic=topic,
|
|
370
|
+
value=value,
|
|
371
|
+
key=key,
|
|
372
|
+
partition=partition,
|
|
373
|
+
offset=offset,
|
|
374
|
+
headers=headers,
|
|
375
|
+
)
|
|
376
|
+
self.messages.append(msg)
|
|
377
|
+
|
|
378
|
+
def add_json_message(
|
|
379
|
+
self,
|
|
380
|
+
topic: str,
|
|
381
|
+
value: Any,
|
|
382
|
+
key: Optional[str] = None,
|
|
383
|
+
partition: int = 0,
|
|
384
|
+
) -> None:
|
|
385
|
+
"""
|
|
386
|
+
Add a JSON message to be consumed.
|
|
387
|
+
|
|
388
|
+
Args:
|
|
389
|
+
topic: Topic name
|
|
390
|
+
value: JSON-serializable value
|
|
391
|
+
key: Optional string key
|
|
392
|
+
partition: Partition number
|
|
393
|
+
|
|
394
|
+
Examples:
|
|
395
|
+
>>> consumer = MockConsumer()
|
|
396
|
+
>>> consumer.add_json_message("events", {"user_id": 123, "action": "click"})
|
|
397
|
+
"""
|
|
398
|
+
import json
|
|
399
|
+
|
|
400
|
+
value_bytes = json.dumps(value).encode("utf-8")
|
|
401
|
+
key_bytes = key.encode("utf-8") if key else None
|
|
402
|
+
self.add_message(topic, value_bytes, key=key_bytes, partition=partition)
|
|
403
|
+
|
|
404
|
+
def subscribe(
|
|
405
|
+
self,
|
|
406
|
+
topics: list[str],
|
|
407
|
+
on_assign: Optional[Callable[[Any, Any], None]] = None,
|
|
408
|
+
on_revoke: Optional[Callable[[Any, Any], None]] = None,
|
|
409
|
+
on_lost: Optional[Callable[[Any, Any], None]] = None,
|
|
410
|
+
) -> None:
|
|
411
|
+
"""
|
|
412
|
+
Subscribe to topics (recorded but not enforced in mock).
|
|
413
|
+
|
|
414
|
+
Args:
|
|
415
|
+
topics: List of topic names
|
|
416
|
+
on_assign: Optional rebalance callback (stored but not called in mock)
|
|
417
|
+
on_revoke: Optional rebalance callback (stored but not called in mock)
|
|
418
|
+
on_lost: Optional rebalance callback (stored but not called in mock)
|
|
419
|
+
|
|
420
|
+
Examples:
|
|
421
|
+
>>> consumer = MockConsumer()
|
|
422
|
+
>>> consumer.subscribe(["topic1", "topic2"])
|
|
423
|
+
>>> assert "topic1" in consumer.subscribed_topics
|
|
424
|
+
"""
|
|
425
|
+
self.subscribed_topics = topics
|
|
426
|
+
self._on_assign = on_assign
|
|
427
|
+
self._on_revoke = on_revoke
|
|
428
|
+
self._on_lost = on_lost
|
|
429
|
+
|
|
430
|
+
def poll(self, timeout: float = 1.0) -> Optional[MockMessage]:
|
|
431
|
+
"""
|
|
432
|
+
Poll for the next message.
|
|
433
|
+
|
|
434
|
+
Returns messages in the order they were added with add_message().
|
|
435
|
+
|
|
436
|
+
Args:
|
|
437
|
+
timeout: Ignored in mock
|
|
438
|
+
|
|
439
|
+
Returns:
|
|
440
|
+
Next MockMessage or None if no more messages
|
|
441
|
+
|
|
442
|
+
Examples:
|
|
443
|
+
>>> consumer = MockConsumer()
|
|
444
|
+
>>> consumer.add_message("topic", b"msg1")
|
|
445
|
+
>>> consumer.add_message("topic", b"msg2")
|
|
446
|
+
>>>
|
|
447
|
+
>>> msg1 = consumer.poll()
|
|
448
|
+
>>> assert msg1.value == b"msg1"
|
|
449
|
+
>>> msg2 = consumer.poll()
|
|
450
|
+
>>> assert msg2.value == b"msg2"
|
|
451
|
+
>>> msg3 = consumer.poll()
|
|
452
|
+
>>> assert msg3 is None
|
|
453
|
+
"""
|
|
454
|
+
if self._message_index < len(self.messages):
|
|
455
|
+
msg = self.messages[self._message_index]
|
|
456
|
+
self._message_index += 1
|
|
457
|
+
return msg
|
|
458
|
+
return None
|
|
459
|
+
|
|
460
|
+
def commit(
|
|
461
|
+
self, message: Optional[MockMessage] = None, asynchronous: bool = True
|
|
462
|
+
) -> None:
|
|
463
|
+
"""
|
|
464
|
+
Record a commit (doesn't actually commit to Kafka).
|
|
465
|
+
|
|
466
|
+
Args:
|
|
467
|
+
message: Message to commit offset for
|
|
468
|
+
asynchronous: Ignored in mock
|
|
469
|
+
|
|
470
|
+
Examples:
|
|
471
|
+
>>> consumer = MockConsumer()
|
|
472
|
+
>>> consumer.add_message("topic", b"msg", partition=0, offset=42)
|
|
473
|
+
>>> msg = consumer.poll()
|
|
474
|
+
>>> consumer.commit(msg)
|
|
475
|
+
>>> assert consumer.committed_offsets[("topic", 0)] == 42
|
|
476
|
+
"""
|
|
477
|
+
if message:
|
|
478
|
+
key = (message.topic, message.partition)
|
|
479
|
+
self.committed_offsets[key] = message.offset
|
|
480
|
+
|
|
481
|
+
def close(self) -> None:
|
|
482
|
+
"""Mark consumer as closed."""
|
|
483
|
+
self._closed = True
|
|
484
|
+
|
|
485
|
+
def reset(self) -> None:
|
|
486
|
+
"""
|
|
487
|
+
Clear all messages and reset state.
|
|
488
|
+
|
|
489
|
+
Examples:
|
|
490
|
+
>>> consumer = MockConsumer()
|
|
491
|
+
>>> consumer.add_message("topic", b"msg")
|
|
492
|
+
>>> consumer.reset()
|
|
493
|
+
>>> assert len(consumer.messages) == 0
|
|
494
|
+
"""
|
|
495
|
+
self.messages.clear()
|
|
496
|
+
self.subscribed_topics.clear()
|
|
497
|
+
self.committed_offsets.clear()
|
|
498
|
+
self._closed = False
|
|
499
|
+
self._message_index = 0
|
|
500
|
+
|
|
501
|
+
def __iter__(self):
|
|
502
|
+
"""
|
|
503
|
+
Iterate over queued messages.
|
|
504
|
+
|
|
505
|
+
Yields all queued messages then stops. In tests, use poll() in a loop
|
|
506
|
+
or add all messages before iterating.
|
|
507
|
+
|
|
508
|
+
Yields:
|
|
509
|
+
MockMessage objects until queue is exhausted
|
|
510
|
+
"""
|
|
511
|
+
while True:
|
|
512
|
+
msg = self.poll()
|
|
513
|
+
if msg is None:
|
|
514
|
+
break
|
|
515
|
+
yield msg
|
|
516
|
+
|
|
517
|
+
def __enter__(self) -> "MockConsumer":
|
|
518
|
+
"""Context manager entry."""
|
|
519
|
+
return self
|
|
520
|
+
|
|
521
|
+
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
522
|
+
"""Context manager exit."""
|
|
523
|
+
self.close()
|