ruststream_rdkafka/testing/
subscriber.rs1use std::fmt;
4use std::sync::Arc;
5
6use futures::Stream;
7use ruststream::testing::Coordinator;
8use ruststream::{AckError, BatchSubscriber, Headers, IncomingMessage, Partitioned, Subscriber};
9
10use super::broker::TestBrokerState;
11use super::router::{DeliveryReceiver, DeliverySender, SubscriptionId, TestDelivery};
12use crate::error::KafkaError;
13
14pub struct KafkaTestSubscriber {
21 state: Arc<TestBrokerState>,
22 ids: Vec<SubscriptionId>,
23 topic: String,
24 sender: DeliverySender,
25 receiver: DeliveryReceiver,
26 coordinator: Option<Coordinator>,
27}
28
29impl KafkaTestSubscriber {
30 pub(crate) fn open_many(state: &Arc<TestBrokerState>, topics: &[String]) -> Self {
31 let (ids, sender, receiver) = state.router.subscribe_many(topics);
32 let coordinator = state.coordinator();
33 Self {
34 state: Arc::clone(state),
35 ids,
36 topic: topics.join(","),
37 sender,
38 receiver,
39 coordinator,
40 }
41 }
42
43 #[must_use]
45 pub fn topic(&self) -> &str {
46 &self.topic
47 }
48}
49
50impl Drop for KafkaTestSubscriber {
51 fn drop(&mut self) {
52 for id in &self.ids {
53 self.state.router.unsubscribe(*id);
54 }
55 }
56}
57
58impl fmt::Debug for KafkaTestSubscriber {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 f.debug_struct("KafkaTestSubscriber")
61 .field("topic", &self.topic)
62 .finish_non_exhaustive()
63 }
64}
65
66impl Subscriber for KafkaTestSubscriber {
67 type Message = KafkaTestMessage;
68 type Error = KafkaError;
69
70 fn stream(&mut self) -> impl Stream<Item = Result<Self::Message, Self::Error>> + Send + '_ {
77 let Self {
78 receiver,
79 sender,
80 coordinator,
81 ..
82 } = self;
83 futures::stream::poll_fn(move |cx| {
84 receiver.poll_recv(cx).map(|delivery| {
85 delivery.map(|delivery| {
86 Ok(KafkaTestMessage {
87 delivery: Some(delivery),
88 sender: sender.clone(),
89 coordinator: coordinator.clone(),
90 })
91 })
92 })
93 })
94 }
95}
96
97impl BatchSubscriber for KafkaTestSubscriber {
98 type Batch = Vec<KafkaTestMessage>;
99
100 fn batches(
108 &mut self,
109 ) -> impl Stream<Item = Result<Self::Batch, <Self as Subscriber>::Error>> + Send + '_ {
110 let Self {
111 receiver,
112 sender,
113 coordinator,
114 ..
115 } = self;
116 futures::stream::poll_fn(move |cx| {
117 receiver.poll_recv(cx).map(|delivery| {
118 delivery.map(|first| {
119 let mut batch = vec![KafkaTestMessage {
120 delivery: Some(first),
121 sender: sender.clone(),
122 coordinator: coordinator.clone(),
123 }];
124 while let Ok(delivery) = receiver.try_recv() {
125 batch.push(KafkaTestMessage {
126 delivery: Some(delivery),
127 sender: sender.clone(),
128 coordinator: coordinator.clone(),
129 });
130 }
131 Ok(batch)
132 })
133 })
134 })
135 }
136}
137
138pub struct KafkaTestMessage {
140 delivery: Option<TestDelivery>,
141 sender: DeliverySender,
142 coordinator: Option<Coordinator>,
143}
144
145impl KafkaTestMessage {
146 fn take(&mut self) -> TestDelivery {
147 self.delivery
150 .take()
151 .expect("KafkaTestMessage settled twice")
152 }
153}
154
155impl Drop for KafkaTestMessage {
156 fn drop(&mut self) {
157 if let Some(coordinator) = self.coordinator.take() {
160 coordinator.consumed();
161 }
162 }
163}
164
165impl fmt::Debug for KafkaTestMessage {
166 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
167 f.debug_struct("KafkaTestMessage")
168 .field("delivery", &self.delivery)
169 .finish_non_exhaustive()
170 }
171}
172
173impl IncomingMessage for KafkaTestMessage {
174 fn payload(&self) -> &[u8] {
175 &self
176 .delivery
177 .as_ref()
178 .expect("message accessed after settlement")
179 .payload
180 }
181
182 fn headers(&self) -> &Headers {
183 &self
184 .delivery
185 .as_ref()
186 .expect("message accessed after settlement")
187 .headers
188 }
189
190 fn partition_key(&self) -> Option<&[u8]> {
193 self.headers().get(crate::PARTITION_KEY_HEADER)
194 }
195
196 async fn ack(mut self) -> Result<(), AckError> {
202 drop(self.take());
203 Ok(())
204 }
205
206 async fn nack(mut self, requeue: bool) -> Result<(), AckError> {
212 let delivery = self.take();
213 if requeue && self.sender.send(delivery).is_ok() {
214 if let Some(coordinator) = &self.coordinator {
216 coordinator.enqueued();
217 }
218 }
219 Ok(())
220 }
221}
222
223impl Partitioned for KafkaTestMessage {
224 fn partition_key(&self) -> Option<&[u8]> {
226 self.headers().get(crate::PARTITION_KEY_HEADER)
227 }
228}