adc-streaming 2.4.0__tar.gz → 2.5.0__tar.gz
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.
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/.github/workflows/build.yml +1 -1
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/PKG-INFO +1 -1
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/adc/auth.py +5 -0
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/adc/consumer.py +4 -3
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/adc/producer.py +6 -4
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/adc_streaming.egg-info/PKG-INFO +1 -1
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/tests/test_auth.py +1 -1
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/tests/test_kafka_integration.py +39 -10
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/.gitignore +0 -0
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/LICENSE +0 -0
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/Makefile +0 -0
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/README.md +0 -0
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/adc/__init__.py +0 -0
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/adc/errors.py +0 -0
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/adc/io.py +0 -0
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/adc/kafka.py +0 -0
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/adc/oidc.py +0 -0
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/adc_streaming.egg-info/SOURCES.txt +0 -0
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/adc_streaming.egg-info/dependency_links.txt +0 -0
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/adc_streaming.egg-info/not-zip-safe +0 -0
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/adc_streaming.egg-info/requires.txt +0 -0
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/adc_streaming.egg-info/top_level.txt +0 -0
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/doc/Makefile +0 -0
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/doc/_static/css/my_theme.css +0 -0
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/doc/_templates/layout.html +0 -0
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/doc/api/api.rst +0 -0
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/doc/api/streaming.rst +0 -0
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/doc/conf.py +0 -0
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/doc/index.rst +0 -0
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/doc/user/installation.rst +0 -0
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/doc/user/quickstart.rst +0 -0
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/pyproject.toml +0 -0
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/recipe/meta.yaml +0 -0
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/setup.cfg +0 -0
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/setup.py +0 -0
- {adc-streaming-2.4.0 → adc-streaming-2.5.0}/tests/test_kafka.py +0 -0
|
@@ -38,6 +38,8 @@ class SASLAuth(object):
|
|
|
38
38
|
ssl_ca_location : `str`, optional
|
|
39
39
|
If using SSL via a self-signed cert, a path/location
|
|
40
40
|
to the certificate.
|
|
41
|
+
ssl_endpoint_identification_algorithm : `str`, optional
|
|
42
|
+
If using SSL, the algorithm used to verify that certificate is valid for the endpoint.
|
|
41
43
|
token_endpoint : `str`, optional
|
|
42
44
|
The OpenID Connect token endpoint URL.
|
|
43
45
|
Required for OAUTHBEARER / OpenID Connect, otherwise ignored.
|
|
@@ -63,6 +65,9 @@ class SASLAuth(object):
|
|
|
63
65
|
"security.protocol": "SASL_SSL",
|
|
64
66
|
"ssl.ca.location": ssl_cert,
|
|
65
67
|
}
|
|
68
|
+
if "ssl_endpoint_identification_algorithm" in kwargs:
|
|
69
|
+
self._config["ssl.endpoint.identification.algorithm"] = \
|
|
70
|
+
kwargs["ssl_endpoint_identification_algorithm"]
|
|
66
71
|
else:
|
|
67
72
|
self._config = {"security.protocol": "SASL_PLAINTEXT"}
|
|
68
73
|
|
|
@@ -38,7 +38,8 @@ class Consumer:
|
|
|
38
38
|
self.logger = logging.getLogger("adc-streaming.consumer")
|
|
39
39
|
self.conf = conf
|
|
40
40
|
self._consumer = confluent_kafka.Consumer(conf._to_confluent_kafka())
|
|
41
|
-
# Workaround for
|
|
41
|
+
# Workaround for
|
|
42
|
+
# https://github.com/confluentinc/librdkafka/issues/3753#issuecomment-1058272987.
|
|
42
43
|
# FIXME: Remove once fixed upstream, or on removal of oauth_cb.
|
|
43
44
|
self._consumer.poll(0)
|
|
44
45
|
self._stop_event = threading.Event()
|
|
@@ -196,7 +197,7 @@ class Consumer:
|
|
|
196
197
|
self.mark_done(m, asynchronous=True)
|
|
197
198
|
yield m
|
|
198
199
|
else:
|
|
199
|
-
raise(confluent_kafka.KafkaException(err))
|
|
200
|
+
raise (confluent_kafka.KafkaException(err))
|
|
200
201
|
finally:
|
|
201
202
|
if autocommit:
|
|
202
203
|
self._consumer.commit(asynchronous=True)
|
|
@@ -242,7 +243,7 @@ class Consumer:
|
|
|
242
243
|
# Done with all partitions for the topic, remove it
|
|
243
244
|
del active_partitions[m.topic()]
|
|
244
245
|
else:
|
|
245
|
-
raise(confluent_kafka.KafkaException(err))
|
|
246
|
+
raise (confluent_kafka.KafkaException(err))
|
|
246
247
|
finally:
|
|
247
248
|
if autocommit:
|
|
248
249
|
self._consumer.commit(asynchronous=True)
|
|
@@ -27,7 +27,8 @@ class Producer:
|
|
|
27
27
|
self.conf = conf
|
|
28
28
|
self.logger.debug(f"connecting to producer with config {conf._to_confluent_kafka()}")
|
|
29
29
|
self._producer = confluent_kafka.Producer(conf._to_confluent_kafka())
|
|
30
|
-
# Workaround for
|
|
30
|
+
# Workaround for
|
|
31
|
+
# https://github.com/confluentinc/librdkafka/issues/3753#issuecomment-1058272987.
|
|
31
32
|
# FIXME: Remove once fixed upstream, or on removal of oauth_cb.
|
|
32
33
|
self._producer.poll(0)
|
|
33
34
|
|
|
@@ -35,7 +36,8 @@ class Producer:
|
|
|
35
36
|
msg: Union[bytes, 'Serializable'],
|
|
36
37
|
headers: Optional[Union[dict, list]] = None,
|
|
37
38
|
delivery_callback: Optional[DeliveryCallback] = log_delivery_errors,
|
|
38
|
-
topic: Optional[str] = None
|
|
39
|
+
topic: Optional[str] = None,
|
|
40
|
+
key: Optional[Union[str, bytes]] = None) -> None:
|
|
39
41
|
if isinstance(msg, Serializable):
|
|
40
42
|
msg = msg.serialize()
|
|
41
43
|
if topic is None:
|
|
@@ -47,10 +49,10 @@ class Producer:
|
|
|
47
49
|
"or specify the topic argument to write()")
|
|
48
50
|
self.logger.debug("writing message to %s", topic)
|
|
49
51
|
if delivery_callback is not None:
|
|
50
|
-
self._producer.produce(topic, msg, headers=headers,
|
|
52
|
+
self._producer.produce(topic, msg, headers=headers, key=key,
|
|
51
53
|
on_delivery=delivery_callback)
|
|
52
54
|
else:
|
|
53
|
-
self._producer.produce(topic, msg, headers=headers)
|
|
55
|
+
self._producer.produce(topic, msg, headers=headers, key=key,)
|
|
54
56
|
|
|
55
57
|
def flush(self, timeout: timedelta = timedelta(seconds=10)) -> int:
|
|
56
58
|
"""Attempt to flush enqueued messages. Return the number of messages still
|
|
@@ -2,8 +2,8 @@ import logging
|
|
|
2
2
|
import tempfile
|
|
3
3
|
import time
|
|
4
4
|
import unittest
|
|
5
|
-
from datetime import datetime, timedelta
|
|
6
|
-
from typing import List
|
|
5
|
+
from datetime import datetime, timedelta
|
|
6
|
+
from typing import List, Optional
|
|
7
7
|
|
|
8
8
|
import docker
|
|
9
9
|
import pytest
|
|
@@ -59,6 +59,31 @@ class KafkaIntegrationTestCase(unittest.TestCase):
|
|
|
59
59
|
self.assertEqual(msg.topic(), topic)
|
|
60
60
|
self.assertEqual(msg.value(), b"can you hear me?")
|
|
61
61
|
|
|
62
|
+
def test_message_with_key(self):
|
|
63
|
+
"""Try writing a message into the Kafka broker, and try pulling the same
|
|
64
|
+
message back out.
|
|
65
|
+
|
|
66
|
+
"""
|
|
67
|
+
topic = "test_message_with_key"
|
|
68
|
+
# Push one message in...
|
|
69
|
+
simple_write_msg(self.kafka, topic, "can you hear me?", key="test_msg")
|
|
70
|
+
# ... and pull it back out.
|
|
71
|
+
consumer = adc.consumer.Consumer(adc.consumer.ConsumerConfig(
|
|
72
|
+
broker_urls=[self.kafka.address],
|
|
73
|
+
group_id="test_consumer",
|
|
74
|
+
auth=self.kafka.auth,
|
|
75
|
+
))
|
|
76
|
+
consumer.subscribe(topic)
|
|
77
|
+
stream = consumer.stream()
|
|
78
|
+
|
|
79
|
+
msg = next(stream)
|
|
80
|
+
if msg.error() is not None:
|
|
81
|
+
raise Exception(msg.error())
|
|
82
|
+
|
|
83
|
+
self.assertEqual(msg.topic(), topic)
|
|
84
|
+
self.assertEqual(msg.value(), b"can you hear me?")
|
|
85
|
+
self.assertEqual(msg.key(), b"test_msg")
|
|
86
|
+
|
|
62
87
|
def test_reset_to_end(self):
|
|
63
88
|
# Write a few messages.
|
|
64
89
|
topic = "test_reset_to_end"
|
|
@@ -283,7 +308,7 @@ class KafkaIntegrationTestCase(unittest.TestCase):
|
|
|
283
308
|
"message 1",
|
|
284
309
|
"message 2",
|
|
285
310
|
"message 3",
|
|
286
|
-
])
|
|
311
|
+
])
|
|
287
312
|
# Wait a while, write, and wait some more
|
|
288
313
|
time.sleep(2)
|
|
289
314
|
client_middle_time = datetime.now()
|
|
@@ -390,8 +415,8 @@ class KafkaIntegrationTestCase(unittest.TestCase):
|
|
|
390
415
|
topic=None,
|
|
391
416
|
auth=self.kafka.auth,
|
|
392
417
|
))
|
|
393
|
-
for i in range(0,8):
|
|
394
|
-
producer.write(str(i), topic=topics[i%2])
|
|
418
|
+
for i in range(0, 8):
|
|
419
|
+
producer.write(str(i), topic=topics[i % 2])
|
|
395
420
|
producer.flush()
|
|
396
421
|
logger.info("messages sent")
|
|
397
422
|
|
|
@@ -403,12 +428,12 @@ class KafkaIntegrationTestCase(unittest.TestCase):
|
|
|
403
428
|
))
|
|
404
429
|
consumer.subscribe(topics)
|
|
405
430
|
stream = consumer.stream()
|
|
406
|
-
total_messages = 0
|
|
431
|
+
total_messages = 0
|
|
407
432
|
for msg in stream:
|
|
408
433
|
if msg.error() is not None:
|
|
409
434
|
raise Exception(msg.error())
|
|
410
435
|
idx = int(msg.value())
|
|
411
|
-
self.assertEqual(msg.topic(), topics[idx%2])
|
|
436
|
+
self.assertEqual(msg.topic(), topics[idx % 2])
|
|
412
437
|
total_messages += 1
|
|
413
438
|
if total_messages == 8:
|
|
414
439
|
break
|
|
@@ -451,6 +476,10 @@ class KafkaDockerConnection:
|
|
|
451
476
|
self.auth = adc.auth.SASLAuth(
|
|
452
477
|
user="test", password="test-pass",
|
|
453
478
|
ssl_ca_location=self.certfile.name,
|
|
479
|
+
# disable endpoint verification because the docker service generates a certificate with
|
|
480
|
+
# a useless subject (the container ID) which can never match the hostname used to
|
|
481
|
+
# connect (typically 0.0.0.0)
|
|
482
|
+
ssl_endpoint_identification_algorithm="none",
|
|
454
483
|
)
|
|
455
484
|
|
|
456
485
|
def poll_for_kafka_broker_address(self, maxiter=20, sleep=timedelta(milliseconds=500)):
|
|
@@ -550,7 +579,7 @@ class KafkaDockerConnection:
|
|
|
550
579
|
# these tests cannot run if there is already an instance of Kafka running on
|
|
551
580
|
# the same host.
|
|
552
581
|
ports={"9092/tcp": 9092},
|
|
553
|
-
command=["/root/runServer","--advertisedListener","SASL_SSL://localhost:9092"],
|
|
582
|
+
command=["/root/runServer", "--advertisedListener", "SASL_SSL://localhost:9092"],
|
|
554
583
|
)
|
|
555
584
|
|
|
556
585
|
def get_or_create_docker_network(self):
|
|
@@ -565,13 +594,13 @@ class KafkaDockerConnection:
|
|
|
565
594
|
return self.docker_client.networks.create(name="adc-integration-test")
|
|
566
595
|
|
|
567
596
|
|
|
568
|
-
def simple_write_msg(conn: KafkaDockerConnection, topic: str, msg: str):
|
|
597
|
+
def simple_write_msg(conn: KafkaDockerConnection, topic: str, msg: str, key: Optional[str] = None):
|
|
569
598
|
producer = adc.producer.Producer(adc.producer.ProducerConfig(
|
|
570
599
|
broker_urls=[conn.address],
|
|
571
600
|
topic=topic,
|
|
572
601
|
auth=conn.auth,
|
|
573
602
|
))
|
|
574
|
-
producer.write(msg)
|
|
603
|
+
producer.write(msg, key=key)
|
|
575
604
|
producer.flush()
|
|
576
605
|
|
|
577
606
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|