#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ConsumerGroupMetadata {
group_id: String,
generation_id: i32,
member_id: String,
group_instance_id: Option<String>,
}
impl ConsumerGroupMetadata {
pub fn new(
group_id: impl Into<String>,
generation_id: i32,
member_id: impl Into<String>,
group_instance_id: Option<String>,
) -> Self {
Self {
group_id: group_id.into(),
generation_id,
member_id: member_id.into(),
group_instance_id,
}
}
pub fn group_id(&self) -> &str {
&self.group_id
}
pub fn generation_id(&self) -> i32 {
self.generation_id
}
pub fn member_id(&self) -> &str {
&self.member_id
}
pub fn group_instance_id(&self) -> Option<&str> {
self.group_instance_id.as_deref()
}
pub fn is_fenceable(&self) -> bool {
self.generation_id >= 0 && !self.member_id.is_empty()
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
mod tests {
use super::*;
#[test]
fn test_accessors_round_trip() {
let m = ConsumerGroupMetadata::new("g1", 7, "member-a", Some("inst-1".to_string()));
assert_eq!(m.group_id(), "g1");
assert_eq!(m.generation_id(), 7);
assert_eq!(m.member_id(), "member-a");
assert_eq!(m.group_instance_id(), Some("inst-1"));
}
#[test]
fn test_dynamic_member_has_no_instance_id() {
let m = ConsumerGroupMetadata::new("g1", 1, "member-a", None);
assert_eq!(m.group_instance_id(), None);
}
#[test]
fn test_is_fenceable_requires_generation_and_member_id() {
assert!(ConsumerGroupMetadata::new("g", 0, "m", None).is_fenceable());
assert!(ConsumerGroupMetadata::new("g", 42, "m", None).is_fenceable());
assert!(!ConsumerGroupMetadata::new("g", -1, "m", None).is_fenceable());
assert!(!ConsumerGroupMetadata::new("g", 5, "", None).is_fenceable());
assert!(!ConsumerGroupMetadata::new("g", -1, "", None).is_fenceable());
}
#[test]
fn test_equality_and_clone() {
let a = ConsumerGroupMetadata::new("g", 3, "m", Some("i".to_string()));
let b = a.clone();
assert_eq!(a, b);
let c = ConsumerGroupMetadata::new("g", 4, "m", Some("i".to_string()));
assert_ne!(a, c);
}
}