1use crate::codec::{Decoder, Encoder};
2use crate::error::Result;
3use crate::header::RequestHeader;
4
5pub const INITIALIZE_API_KEY: i16 = 83;
7pub const READ_API_KEY: i16 = 84;
9pub const WRITE_API_KEY: i16 = 85;
11pub const DELETE_API_KEY: i16 = 86;
13pub const SUMMARY_API_KEY: i16 = 87;
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub struct InitializeShareGroupStatePartition {
19 pub partition: i32,
20 pub state_epoch: i32,
21 pub start_offset: i64,
22}
23
24#[derive(Debug, Clone, PartialEq, Eq)]
26pub struct InitializeShareGroupStateTopic {
27 pub topic_id: [u8; 16],
28 pub partitions: Vec<InitializeShareGroupStatePartition>,
29}
30
31#[derive(Debug, Clone, PartialEq, Eq)]
33pub struct InitializeShareGroupStateRequestV0 {
34 pub correlation_id: i32,
35 pub client_id: Option<String>,
36 pub group_id: String,
37 pub topics: Vec<InitializeShareGroupStateTopic>,
38}
39
40impl InitializeShareGroupStateRequestV0 {
41 pub fn encode(&self) -> Result<Vec<u8>> {
43 encode_request(
44 INITIALIZE_API_KEY,
45 0,
46 self.correlation_id,
47 self.client_id.clone(),
48 &self.group_id,
49 &self.topics,
50 |encoder, topic| {
51 encoder.write_uuid(&topic.topic_id);
52 encoder.write_compact_array(Some(&topic.partitions), |encoder, partition| {
53 encoder.write_i32(partition.partition);
54 encoder.write_i32(partition.state_epoch);
55 encoder.write_i64(partition.start_offset);
56 encoder.write_empty_tagged_fields();
57 Ok(())
58 })?;
59 encoder.write_empty_tagged_fields();
60 Ok(())
61 },
62 )
63 }
64}
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq)]
68pub struct ReadShareGroupStatePartition {
69 pub partition: i32,
70 pub leader_epoch: i32,
71}
72
73#[derive(Debug, Clone, PartialEq, Eq)]
75pub struct ReadShareGroupStateTopic {
76 pub topic_id: [u8; 16],
77 pub partitions: Vec<ReadShareGroupStatePartition>,
78}
79
80fn encode_read_request(
81 api_key: i16,
82 api_version: i16,
83 correlation_id: i32,
84 client_id: Option<String>,
85 group_id: &str,
86 topics: &[ReadShareGroupStateTopic],
87) -> Result<Vec<u8>> {
88 encode_request(
89 api_key,
90 api_version,
91 correlation_id,
92 client_id,
93 group_id,
94 topics,
95 |encoder, topic| {
96 encoder.write_uuid(&topic.topic_id);
97 encoder.write_compact_array(Some(&topic.partitions), |encoder, partition| {
98 encoder.write_i32(partition.partition);
99 encoder.write_i32(partition.leader_epoch);
100 encoder.write_empty_tagged_fields();
101 Ok(())
102 })?;
103 encoder.write_empty_tagged_fields();
104 Ok(())
105 },
106 )
107}
108
109fn encode_request<T>(
110 api_key: i16,
111 api_version: i16,
112 correlation_id: i32,
113 client_id: Option<String>,
114 group_id: &str,
115 topics: &[T],
116 mut encode_topic: impl FnMut(&mut Encoder, &T) -> Result<()>,
117) -> Result<Vec<u8>> {
118 let mut encoder = Encoder::new();
119 RequestHeader {
120 api_key,
121 api_version,
122 correlation_id,
123 client_id,
124 }
125 .encode_v2(&mut encoder)?;
126 encoder.write_compact_string(group_id)?;
127 encoder.write_compact_array(Some(topics), |encoder, topic| encode_topic(encoder, topic))?;
128 encoder.write_empty_tagged_fields();
129 Ok(encoder.into_bytes())
130}
131
132#[derive(Debug, Clone, PartialEq, Eq)]
134pub struct ReadShareGroupStateRequestV0 {
135 pub correlation_id: i32,
136 pub client_id: Option<String>,
137 pub group_id: String,
138 pub topics: Vec<ReadShareGroupStateTopic>,
139}
140
141impl ReadShareGroupStateRequestV0 {
142 pub fn encode(&self) -> Result<Vec<u8>> {
144 encode_read_request(
145 READ_API_KEY,
146 0,
147 self.correlation_id,
148 self.client_id.clone(),
149 &self.group_id,
150 &self.topics,
151 )
152 }
153}
154
155#[derive(Debug, Clone, Copy, PartialEq, Eq)]
157pub struct ShareGroupStateBatch {
158 pub first_offset: i64,
159 pub last_offset: i64,
160 pub delivery_state: i8,
161 pub delivery_count: i16,
162}
163
164#[derive(Debug, Clone, PartialEq, Eq)]
166pub struct ShareGroupStatePartitionResult {
167 pub partition: i32,
168 pub error_code: i16,
169 pub error_message: Option<String>,
170}
171
172#[derive(Debug, Clone, PartialEq, Eq)]
174pub struct ShareGroupStateTopicResult {
175 pub topic_id: [u8; 16],
176 pub partitions: Vec<ShareGroupStatePartitionResult>,
177}
178
179fn decode_state_results(
180 decoder: &mut Decoder<'_>,
181 kind: &'static str,
182) -> Result<Vec<ShareGroupStateTopicResult>> {
183 let results = decoder
184 .read_compact_array(kind, |decoder| {
185 let topic_id = decoder.read_uuid()?;
186 let partitions = decoder
187 .read_compact_array("share group state result partitions", |decoder| {
188 let result = ShareGroupStatePartitionResult {
189 partition: decoder.read_i32()?,
190 error_code: decoder.read_i16()?,
191 error_message: decoder.read_compact_nullable_string()?,
192 };
193 decoder.read_tagged_fields()?;
194 Ok(result)
195 })?
196 .unwrap_or_default();
197 decoder.read_tagged_fields()?;
198 Ok(ShareGroupStateTopicResult {
199 topic_id,
200 partitions,
201 })
202 })?
203 .unwrap_or_default();
204 Ok(results)
205}
206
207#[derive(Debug, Clone, PartialEq, Eq)]
210pub struct ShareGroupStateResultResponse {
211 pub results: Vec<ShareGroupStateTopicResult>,
212}
213
214impl ShareGroupStateResultResponse {
215 pub fn decode_body(decoder: &mut Decoder<'_>) -> Result<Self> {
217 let results = decode_state_results(decoder, "share group state results")?;
218 decoder.read_tagged_fields()?;
219 Ok(Self { results })
220 }
221}
222
223pub type InitializeShareGroupStateResponseV0 = ShareGroupStateResultResponse;
225
226#[derive(Debug, Clone, PartialEq, Eq)]
228pub struct ReadShareGroupStatePartitionResult {
229 pub partition: i32,
230 pub error_code: i16,
231 pub error_message: Option<String>,
232 pub state_epoch: i32,
233 pub start_offset: i64,
234 pub state_batches: Vec<ShareGroupStateBatch>,
235}
236
237#[derive(Debug, Clone, PartialEq, Eq)]
239pub struct ReadShareGroupStateTopicResult {
240 pub topic_id: [u8; 16],
241 pub partitions: Vec<ReadShareGroupStatePartitionResult>,
242}
243
244#[derive(Debug, Clone, PartialEq, Eq)]
246pub struct ReadShareGroupStateResponseV0 {
247 pub results: Vec<ReadShareGroupStateTopicResult>,
248}
249
250impl ReadShareGroupStateResponseV0 {
251 pub fn decode_body(decoder: &mut Decoder<'_>) -> Result<Self> {
253 Ok(Self {
254 results: decode_read_results(decoder, "read share group state results")?,
255 })
256 }
257}
258
259fn decode_read_results(
260 decoder: &mut Decoder<'_>,
261 kind: &'static str,
262) -> Result<Vec<ReadShareGroupStateTopicResult>> {
263 let results = decoder
264 .read_compact_array(kind, |decoder| {
265 let topic_id = decoder.read_uuid()?;
266 let partitions = decoder
267 .read_compact_array("read share group state partitions", |decoder| {
268 let partition = ReadShareGroupStatePartitionResult {
269 partition: decoder.read_i32()?,
270 error_code: decoder.read_i16()?,
271 error_message: decoder.read_compact_nullable_string()?,
272 state_epoch: decoder.read_i32()?,
273 start_offset: decoder.read_i64()?,
274 state_batches: decoder
275 .read_compact_array("share group state batches", |decoder| {
276 let batch = ShareGroupStateBatch {
277 first_offset: decoder.read_i64()?,
278 last_offset: decoder.read_i64()?,
279 delivery_state: decoder.read_i8()?,
280 delivery_count: decoder.read_i16()?,
281 };
282 decoder.read_tagged_fields()?;
283 Ok(batch)
284 })?
285 .unwrap_or_default(),
286 };
287 decoder.read_tagged_fields()?;
288 Ok(partition)
289 })?
290 .unwrap_or_default();
291 decoder.read_tagged_fields()?;
292 Ok(ReadShareGroupStateTopicResult {
293 topic_id,
294 partitions,
295 })
296 })?
297 .unwrap_or_default();
298 decoder.read_tagged_fields()?;
299 Ok(results)
300}
301
302#[derive(Debug, Clone, PartialEq, Eq)]
304pub struct WriteShareGroupStatePartitionV0 {
305 pub partition: i32,
306 pub state_epoch: i32,
307 pub leader_epoch: i32,
308 pub start_offset: i64,
309 pub state_batches: Vec<ShareGroupStateBatch>,
310}
311
312#[derive(Debug, Clone, PartialEq, Eq)]
314pub struct WriteShareGroupStateTopicV0 {
315 pub topic_id: [u8; 16],
316 pub partitions: Vec<WriteShareGroupStatePartitionV0>,
317}
318
319#[derive(Debug, Clone, PartialEq, Eq)]
321pub struct WriteShareGroupStatePartitionV1 {
322 pub partition: i32,
323 pub state_epoch: i32,
324 pub leader_epoch: i32,
325 pub start_offset: i64,
326 pub delivery_complete_count: i32,
327 pub state_batches: Vec<ShareGroupStateBatch>,
328}
329
330#[derive(Debug, Clone, PartialEq, Eq)]
332pub struct WriteShareGroupStateTopicV1 {
333 pub topic_id: [u8; 16],
334 pub partitions: Vec<WriteShareGroupStatePartitionV1>,
335}
336
337fn encode_write_partition(
338 encoder: &mut Encoder,
339 partition: i32,
340 state_epoch: i32,
341 leader_epoch: i32,
342 start_offset: i64,
343 delivery_complete_count: Option<i32>,
344 state_batches: &[ShareGroupStateBatch],
345) -> Result<()> {
346 encoder.write_i32(partition);
347 encoder.write_i32(state_epoch);
348 encoder.write_i32(leader_epoch);
349 encoder.write_i64(start_offset);
350 if let Some(delivery_complete_count) = delivery_complete_count {
351 encoder.write_i32(delivery_complete_count);
352 }
353 encoder.write_compact_array(Some(state_batches), |encoder, batch| {
354 encoder.write_i64(batch.first_offset);
355 encoder.write_i64(batch.last_offset);
356 encoder.write_i8(batch.delivery_state);
357 encoder.write_i16(batch.delivery_count);
358 encoder.write_empty_tagged_fields();
359 Ok(())
360 })?;
361 encoder.write_empty_tagged_fields();
362 Ok(())
363}
364
365#[derive(Debug, Clone, PartialEq, Eq)]
367pub struct WriteShareGroupStateRequestV0 {
368 pub correlation_id: i32,
369 pub client_id: Option<String>,
370 pub group_id: String,
371 pub topics: Vec<WriteShareGroupStateTopicV0>,
372}
373
374impl WriteShareGroupStateRequestV0 {
375 pub fn encode(&self) -> Result<Vec<u8>> {
377 encode_request(
378 WRITE_API_KEY,
379 0,
380 self.correlation_id,
381 self.client_id.clone(),
382 &self.group_id,
383 &self.topics,
384 |encoder, topic| {
385 encoder.write_uuid(&topic.topic_id);
386 encoder.write_compact_array(Some(&topic.partitions), |encoder, partition| {
387 encode_write_partition(
388 encoder,
389 partition.partition,
390 partition.state_epoch,
391 partition.leader_epoch,
392 partition.start_offset,
393 None,
394 &partition.state_batches,
395 )
396 })?;
397 encoder.write_empty_tagged_fields();
398 Ok(())
399 },
400 )
401 }
402}
403
404#[derive(Debug, Clone, PartialEq, Eq)]
406pub struct WriteShareGroupStateRequestV1 {
407 pub correlation_id: i32,
408 pub client_id: Option<String>,
409 pub group_id: String,
410 pub topics: Vec<WriteShareGroupStateTopicV1>,
411}
412
413impl WriteShareGroupStateRequestV1 {
414 pub fn encode(&self) -> Result<Vec<u8>> {
416 encode_request(
417 WRITE_API_KEY,
418 1,
419 self.correlation_id,
420 self.client_id.clone(),
421 &self.group_id,
422 &self.topics,
423 |encoder, topic| {
424 encoder.write_uuid(&topic.topic_id);
425 encoder.write_compact_array(Some(&topic.partitions), |encoder, partition| {
426 encode_write_partition(
427 encoder,
428 partition.partition,
429 partition.state_epoch,
430 partition.leader_epoch,
431 partition.start_offset,
432 Some(partition.delivery_complete_count),
433 &partition.state_batches,
434 )
435 })?;
436 encoder.write_empty_tagged_fields();
437 Ok(())
438 },
439 )
440 }
441}
442
443pub type WriteShareGroupStateResponseV0 = ShareGroupStateResultResponse;
445pub type WriteShareGroupStateResponseV1 = ShareGroupStateResultResponse;
447
448#[derive(Debug, Clone, PartialEq, Eq)]
450pub struct DeleteShareGroupStateTopic {
451 pub topic_id: [u8; 16],
452 pub partitions: Vec<i32>,
453}
454
455#[derive(Debug, Clone, PartialEq, Eq)]
457pub struct DeleteShareGroupStateRequestV0 {
458 pub correlation_id: i32,
459 pub client_id: Option<String>,
460 pub group_id: String,
461 pub topics: Vec<DeleteShareGroupStateTopic>,
462}
463
464impl DeleteShareGroupStateRequestV0 {
465 pub fn encode(&self) -> Result<Vec<u8>> {
467 encode_request(
468 DELETE_API_KEY,
469 0,
470 self.correlation_id,
471 self.client_id.clone(),
472 &self.group_id,
473 &self.topics,
474 |encoder, topic| {
475 encoder.write_uuid(&topic.topic_id);
476 encoder.write_compact_array(Some(&topic.partitions), |encoder, partition| {
477 encoder.write_i32(*partition);
478 encoder.write_empty_tagged_fields();
479 Ok(())
480 })?;
481 encoder.write_empty_tagged_fields();
482 Ok(())
483 },
484 )
485 }
486}
487
488pub type DeleteShareGroupStateResponseV0 = ShareGroupStateResultResponse;
490
491#[derive(Debug, Clone, PartialEq, Eq)]
493pub struct ReadShareGroupStateSummaryRequestV0 {
494 pub correlation_id: i32,
495 pub client_id: Option<String>,
496 pub group_id: String,
497 pub topics: Vec<ReadShareGroupStateTopic>,
498}
499
500impl ReadShareGroupStateSummaryRequestV0 {
501 pub fn encode(&self) -> Result<Vec<u8>> {
503 encode_read_request(
504 SUMMARY_API_KEY,
505 0,
506 self.correlation_id,
507 self.client_id.clone(),
508 &self.group_id,
509 &self.topics,
510 )
511 }
512}
513
514#[derive(Debug, Clone, PartialEq, Eq)]
516pub struct ReadShareGroupStateSummaryRequestV1 {
517 pub correlation_id: i32,
518 pub client_id: Option<String>,
519 pub group_id: String,
520 pub topics: Vec<ReadShareGroupStateTopic>,
521}
522
523impl ReadShareGroupStateSummaryRequestV1 {
524 pub fn encode(&self) -> Result<Vec<u8>> {
526 encode_read_request(
527 SUMMARY_API_KEY,
528 1,
529 self.correlation_id,
530 self.client_id.clone(),
531 &self.group_id,
532 &self.topics,
533 )
534 }
535}
536
537#[derive(Debug, Clone, PartialEq, Eq)]
539pub struct ReadShareGroupStateSummaryPartitionResult {
540 pub partition: i32,
541 pub error_code: i16,
542 pub error_message: Option<String>,
543 pub state_epoch: i32,
544 pub leader_epoch: i32,
545 pub start_offset: i64,
546 pub delivery_complete_count: Option<i32>,
547}
548
549#[derive(Debug, Clone, PartialEq, Eq)]
551pub struct ReadShareGroupStateSummaryTopicResult {
552 pub topic_id: [u8; 16],
553 pub partitions: Vec<ReadShareGroupStateSummaryPartitionResult>,
554}
555
556fn decode_summary_results(
557 decoder: &mut Decoder<'_>,
558 api_version: i16,
559) -> Result<Vec<ReadShareGroupStateSummaryTopicResult>> {
560 let results = decoder
561 .read_compact_array("read share group state summary results", |decoder| {
562 let topic_id = decoder.read_uuid()?;
563 let partitions = decoder
564 .read_compact_array("share group state summary partitions", |decoder| {
565 let partition = ReadShareGroupStateSummaryPartitionResult {
566 partition: decoder.read_i32()?,
567 error_code: decoder.read_i16()?,
568 error_message: decoder.read_compact_nullable_string()?,
569 state_epoch: decoder.read_i32()?,
570 leader_epoch: decoder.read_i32()?,
571 start_offset: decoder.read_i64()?,
572 delivery_complete_count: (api_version >= 1)
573 .then(|| decoder.read_i32())
574 .transpose()?,
575 };
576 decoder.read_tagged_fields()?;
577 Ok(partition)
578 })?
579 .unwrap_or_default();
580 decoder.read_tagged_fields()?;
581 Ok(ReadShareGroupStateSummaryTopicResult {
582 topic_id,
583 partitions,
584 })
585 })?
586 .unwrap_or_default();
587 decoder.read_tagged_fields()?;
588 Ok(results)
589}
590
591#[derive(Debug, Clone, PartialEq, Eq)]
593pub struct ReadShareGroupStateSummaryResponseV0 {
594 pub results: Vec<ReadShareGroupStateSummaryTopicResult>,
595}
596
597impl ReadShareGroupStateSummaryResponseV0 {
598 pub fn decode_body(decoder: &mut Decoder<'_>) -> Result<Self> {
600 Ok(Self {
601 results: decode_summary_results(decoder, 0)?,
602 })
603 }
604}
605
606#[derive(Debug, Clone, PartialEq, Eq)]
608pub struct ReadShareGroupStateSummaryResponseV1 {
609 pub results: Vec<ReadShareGroupStateSummaryTopicResult>,
610}
611
612impl ReadShareGroupStateSummaryResponseV1 {
613 pub fn decode_body(decoder: &mut Decoder<'_>) -> Result<Self> {
615 Ok(Self {
616 results: decode_summary_results(decoder, 1)?,
617 })
618 }
619}
620
621#[cfg(test)]
622#[allow(clippy::unwrap_used)]
623mod tests {
624 use super::*;
625 use crate::codec::{Decoder, Encoder};
626
627 fn read_header(decoder: &mut Decoder<'_>, api_key: i16, api_version: i16) {
628 assert_eq!(decoder.read_i16().unwrap(), api_key);
629 assert_eq!(decoder.read_i16().unwrap(), api_version);
630 assert_eq!(decoder.read_i32().unwrap(), 7);
631 assert_eq!(
632 decoder.read_nullable_string().unwrap().as_deref(),
633 Some("kafrust")
634 );
635 assert!(decoder.read_tagged_fields().unwrap().is_empty());
636 }
637
638 fn batch() -> ShareGroupStateBatch {
639 ShareGroupStateBatch {
640 first_offset: 10,
641 last_offset: 12,
642 delivery_state: 2,
643 delivery_count: 3,
644 }
645 }
646
647 #[test]
648 fn encodes_initialize_share_group_state_v0() {
649 let request = InitializeShareGroupStateRequestV0 {
650 correlation_id: 7,
651 client_id: Some("kafrust".to_owned()),
652 group_id: "share-orders".to_owned(),
653 topics: vec![InitializeShareGroupStateTopic {
654 topic_id: [1; 16],
655 partitions: vec![InitializeShareGroupStatePartition {
656 partition: 2,
657 state_epoch: 4,
658 start_offset: 10,
659 }],
660 }],
661 };
662 let encoded = request.encode().unwrap();
663 let mut decoder = Decoder::new(&encoded);
664 read_header(&mut decoder, INITIALIZE_API_KEY, 0);
665 assert_eq!(decoder.read_compact_string().unwrap(), "share-orders");
666 assert_eq!(decoder.read_unsigned_varint().unwrap(), 2);
667 assert_eq!(decoder.read_uuid().unwrap(), [1; 16]);
668 assert_eq!(decoder.read_unsigned_varint().unwrap(), 2);
669 assert_eq!(decoder.read_i32().unwrap(), 2);
670 assert_eq!(decoder.read_i32().unwrap(), 4);
671 assert_eq!(decoder.read_i64().unwrap(), 10);
672 assert!(decoder.read_tagged_fields().unwrap().is_empty());
673 assert!(decoder.read_tagged_fields().unwrap().is_empty());
674 assert!(decoder.read_tagged_fields().unwrap().is_empty());
675 assert!(decoder.is_empty());
676 }
677
678 #[test]
679 fn encodes_write_v1_delivery_complete_count_without_v0_field() {
680 let topic = WriteShareGroupStateTopicV1 {
681 topic_id: [2; 16],
682 partitions: vec![WriteShareGroupStatePartitionV1 {
683 partition: 1,
684 state_epoch: 3,
685 leader_epoch: 4,
686 start_offset: 5,
687 delivery_complete_count: 6,
688 state_batches: vec![batch()],
689 }],
690 };
691 let request = WriteShareGroupStateRequestV1 {
692 correlation_id: 7,
693 client_id: Some("kafrust".to_owned()),
694 group_id: "share-orders".to_owned(),
695 topics: vec![topic],
696 };
697 let encoded = request.encode().unwrap();
698 let mut decoder = Decoder::new(&encoded);
699 read_header(&mut decoder, WRITE_API_KEY, 1);
700 assert_eq!(decoder.read_compact_string().unwrap(), "share-orders");
701 assert_eq!(decoder.read_unsigned_varint().unwrap(), 2);
702 assert_eq!(decoder.read_uuid().unwrap(), [2; 16]);
703 assert_eq!(decoder.read_unsigned_varint().unwrap(), 2);
704 assert_eq!(decoder.read_i32().unwrap(), 1);
705 assert_eq!(decoder.read_i32().unwrap(), 3);
706 assert_eq!(decoder.read_i32().unwrap(), 4);
707 assert_eq!(decoder.read_i64().unwrap(), 5);
708 assert_eq!(decoder.read_i32().unwrap(), 6);
709 assert_eq!(decoder.read_unsigned_varint().unwrap(), 2);
710 assert_eq!(decoder.read_i64().unwrap(), 10);
711 assert_eq!(decoder.read_i64().unwrap(), 12);
712 assert_eq!(decoder.read_i8().unwrap(), 2);
713 assert_eq!(decoder.read_i16().unwrap(), 3);
714 assert!(decoder.read_tagged_fields().unwrap().is_empty());
715 assert!(decoder.read_tagged_fields().unwrap().is_empty());
716 assert!(decoder.read_tagged_fields().unwrap().is_empty());
717 assert!(decoder.read_tagged_fields().unwrap().is_empty());
718 assert!(decoder.is_empty());
719 }
720
721 #[test]
722 fn decodes_read_and_summary_results_by_version() -> crate::error::Result<()> {
723 let mut body = Encoder::new();
724 body.write_compact_array(Some(&[()]), |encoder, ()| {
725 encoder.write_uuid(&[3; 16]);
726 encoder.write_compact_array(Some(&[()]), |encoder, ()| {
727 encoder.write_i32(1);
728 encoder.write_i16(0);
729 encoder.write_compact_nullable_string(None)?;
730 encoder.write_i32(2);
731 encoder.write_i64(10);
732 encoder.write_compact_array(Some(&[()]), |encoder, ()| {
733 encoder.write_i64(10);
734 encoder.write_i64(12);
735 encoder.write_i8(0);
736 encoder.write_i16(1);
737 encoder.write_empty_tagged_fields();
738 Ok(())
739 })?;
740 encoder.write_empty_tagged_fields();
741 Ok(())
742 })?;
743 encoder.write_empty_tagged_fields();
744 Ok(())
745 })?;
746 body.write_empty_tagged_fields();
747 let encoded = body.into_bytes();
748 let mut decoder = Decoder::new(&encoded);
749 let response = ReadShareGroupStateResponseV0::decode_body(&mut decoder)?;
750 assert_eq!(
751 response.results[0].partitions[0].state_batches[0],
752 ShareGroupStateBatch {
753 first_offset: 10,
754 last_offset: 12,
755 delivery_state: 0,
756 delivery_count: 1,
757 }
758 );
759 assert!(decoder.is_empty());
760
761 let mut summary = Encoder::new();
762 summary.write_compact_array(Some(&[()]), |encoder, ()| {
763 encoder.write_uuid(&[4; 16]);
764 encoder.write_compact_array(Some(&[()]), |encoder, ()| {
765 encoder.write_i32(1);
766 encoder.write_i16(0);
767 encoder.write_compact_nullable_string(None)?;
768 encoder.write_i32(2);
769 encoder.write_i32(3);
770 encoder.write_i64(10);
771 encoder.write_i32(9);
772 encoder.write_empty_tagged_fields();
773 Ok(())
774 })?;
775 encoder.write_empty_tagged_fields();
776 Ok(())
777 })?;
778 summary.write_empty_tagged_fields();
779 let encoded = summary.into_bytes();
780 let mut decoder = Decoder::new(&encoded);
781 let response = ReadShareGroupStateSummaryResponseV1::decode_body(&mut decoder)?;
782 assert_eq!(
783 response.results[0].partitions[0].delivery_complete_count,
784 Some(9)
785 );
786 assert!(decoder.is_empty());
787 Ok(())
788 }
789
790 #[test]
791 fn encodes_delete_share_group_state_v0() {
792 let request = DeleteShareGroupStateRequestV0 {
793 correlation_id: 7,
794 client_id: Some("kafrust".to_owned()),
795 group_id: "share-orders".to_owned(),
796 topics: vec![DeleteShareGroupStateTopic {
797 topic_id: [5; 16],
798 partitions: vec![0, 2],
799 }],
800 };
801 let encoded = request.encode().unwrap();
802 let mut decoder = Decoder::new(&encoded);
803 read_header(&mut decoder, DELETE_API_KEY, 0);
804 assert_eq!(decoder.read_compact_string().unwrap(), "share-orders");
805 assert_eq!(decoder.read_unsigned_varint().unwrap(), 2);
806 assert_eq!(decoder.read_uuid().unwrap(), [5; 16]);
807 assert_eq!(decoder.read_unsigned_varint().unwrap(), 3);
808 assert_eq!(decoder.read_i32().unwrap(), 0);
809 assert!(decoder.read_tagged_fields().unwrap().is_empty());
810 assert_eq!(decoder.read_i32().unwrap(), 2);
811 assert!(decoder.read_tagged_fields().unwrap().is_empty());
812 assert!(decoder.read_tagged_fields().unwrap().is_empty());
813 assert!(decoder.read_tagged_fields().unwrap().is_empty());
814 assert!(decoder.is_empty());
815 }
816}