core/cli/src/args/permissions/topic.rs (337 lines of code) (raw):
/* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
use iggy::models::permissions::TopicPermissions;
use std::str::FromStr;
use super::constants::{
MANAGE_TOPIC_LONG, MANAGE_TOPIC_SHORT, POLL_MESSAGES_LONG, POLL_MESSAGES_SHORT,
READ_TOPIC_LONG, READ_TOPIC_SHORT, SEND_MESSAGES_LONG, SEND_MESSAGES_SHORT,
};
#[derive(Clone, Debug, PartialEq)]
enum TopicPermission {
ManageTopic,
ReadTopic,
PollMessages,
SendMessages,
}
#[derive(Clone, Debug, PartialEq)]
pub(crate) struct TopicPermissionError(String);
impl FromStr for TopicPermission {
type Err = TopicPermissionError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
MANAGE_TOPIC_SHORT | MANAGE_TOPIC_LONG => Ok(TopicPermission::ManageTopic),
READ_TOPIC_SHORT | READ_TOPIC_LONG => Ok(TopicPermission::ReadTopic),
POLL_MESSAGES_SHORT | POLL_MESSAGES_LONG => Ok(TopicPermission::PollMessages),
SEND_MESSAGES_SHORT | SEND_MESSAGES_LONG => Ok(TopicPermission::SendMessages),
"" => Err(TopicPermissionError("[empty]".to_owned())),
_ => Err(TopicPermissionError(s.to_owned())),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub(crate) struct TopicPermissionsArg {
pub(crate) topic_id: u32,
pub(crate) permissions: TopicPermissions,
}
impl From<TopicPermissionsArg> for TopicPermissions {
fn from(cmd: TopicPermissionsArg) -> Self {
cmd.permissions
}
}
impl TopicPermissionsArg {
fn new(topic_id: u32, topic_permissions: Vec<TopicPermission>) -> Self {
let mut result = Self {
topic_id,
permissions: TopicPermissions::default(),
};
for permission in topic_permissions {
result.set_permission(permission);
}
result
}
fn set_permission(&mut self, permission: TopicPermission) {
match permission {
TopicPermission::ManageTopic => self.permissions.manage_topic = true,
TopicPermission::ReadTopic => self.permissions.read_topic = true,
TopicPermission::PollMessages => self.permissions.poll_messages = true,
TopicPermission::SendMessages => self.permissions.send_messages = true,
}
}
}
impl FromStr for TopicPermissionsArg {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut parts = s.split(':');
let topic_id = parts
.next()
.ok_or("Missing topic ID".to_string())
.and_then(|id| {
id.parse()
.map_err(|error| format!("Invalid topic ID - {}", error))
})?;
let permissions: Vec<TopicPermission> = match parts.next() {
Some(permissions_str) => {
let (values, errors): (Vec<_>, Vec<_>) = permissions_str
.split(',')
.map(|s| s.parse::<TopicPermission>())
.partition(Result::is_ok);
if !errors.is_empty() {
let errors = errors
.into_iter()
.map(|e| format!("\"{}\"", e.err().unwrap().0))
.collect::<Vec<String>>();
return Err(format!(
"Unknown permission{} {} for topic ID: {}",
match errors.len() {
1 => "",
_ => "s",
},
errors.join(", "),
topic_id
));
}
values.into_iter().map(|p| p.unwrap()).collect()
}
None => vec![],
};
Ok(TopicPermissionsArg::new(topic_id, permissions))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn should_deserialize_single_permission() {
assert_eq!(
TopicPermission::from_str("manage_topic").unwrap(),
TopicPermission::ManageTopic
);
assert_eq!(
TopicPermission::from_str("read_topic").unwrap(),
TopicPermission::ReadTopic
);
assert_eq!(
TopicPermission::from_str("poll_messages").unwrap(),
TopicPermission::PollMessages
);
assert_eq!(
TopicPermission::from_str("send_messages").unwrap(),
TopicPermission::SendMessages
);
}
#[test]
fn should_deserialize_single_short_permission() {
assert_eq!(
TopicPermission::from_str("m_top").unwrap(),
TopicPermission::ManageTopic
);
assert_eq!(
TopicPermission::from_str("r_top").unwrap(),
TopicPermission::ReadTopic
);
assert_eq!(
TopicPermission::from_str("p_msg").unwrap(),
TopicPermission::PollMessages
);
assert_eq!(
TopicPermission::from_str("s_msg").unwrap(),
TopicPermission::SendMessages
);
}
#[test]
fn should_not_deserialize_single_permission() {
let wrong_permission = TopicPermission::from_str("rad_topic");
assert!(wrong_permission.is_err());
assert_eq!(
wrong_permission.unwrap_err(),
TopicPermissionError("rad_topic".to_owned())
);
let empty_permission = TopicPermission::from_str("");
assert!(empty_permission.is_err());
assert_eq!(
empty_permission.unwrap_err(),
TopicPermissionError("[empty]".to_owned())
);
}
#[test]
fn should_not_deserialize_single_short_permission() {
let wrong_permission = TopicPermission::from_str("w_top");
assert!(wrong_permission.is_err());
assert_eq!(
wrong_permission.unwrap_err(),
TopicPermissionError("w_top".to_owned())
);
let wrong_permission = TopicPermission::from_str("p_top");
assert!(wrong_permission.is_err());
assert_eq!(
wrong_permission.unwrap_err(),
TopicPermissionError("p_top".to_owned())
);
}
#[test]
fn should_deserialize_permissions() {
assert_eq!(
TopicPermissionsArg::from_str("1:manage_topic,read_topic,poll_messages,send_messages")
.unwrap(),
TopicPermissionsArg {
topic_id: 1,
permissions: TopicPermissions {
manage_topic: true,
read_topic: true,
poll_messages: true,
send_messages: true,
}
}
);
assert_eq!(
TopicPermissionsArg::from_str("1:manage_topic,read_topic").unwrap(),
TopicPermissionsArg {
topic_id: 1,
permissions: TopicPermissions {
manage_topic: true,
read_topic: true,
poll_messages: false,
send_messages: false,
}
}
);
assert_eq!(
TopicPermissionsArg::from_str("52:send_messages,read_topic").unwrap(),
TopicPermissionsArg {
topic_id: 52,
permissions: TopicPermissions {
manage_topic: false,
read_topic: true,
poll_messages: false,
send_messages: true,
}
}
);
assert_eq!(
TopicPermissionsArg::from_str("66").unwrap(),
TopicPermissionsArg {
topic_id: 66,
permissions: TopicPermissions {
manage_topic: false,
read_topic: false,
poll_messages: false,
send_messages: false,
}
}
);
assert_eq!(
TopicPermissionsArg::from_str("3:send_messages").unwrap(),
TopicPermissionsArg {
topic_id: 3,
permissions: TopicPermissions {
manage_topic: false,
read_topic: false,
poll_messages: false,
send_messages: true,
}
}
);
}
#[test]
fn should_deserialize_short_permissions() {
assert_eq!(
TopicPermissionsArg::from_str("4:m_top,r_top,p_msg,s_msg").unwrap(),
TopicPermissionsArg {
topic_id: 4,
permissions: TopicPermissions {
manage_topic: true,
read_topic: true,
poll_messages: true,
send_messages: true,
}
}
);
assert_eq!(
TopicPermissionsArg::from_str("2:m_top,r_top").unwrap(),
TopicPermissionsArg {
topic_id: 2,
permissions: TopicPermissions {
manage_topic: true,
read_topic: true,
poll_messages: false,
send_messages: false,
}
}
);
assert_eq!(
TopicPermissionsArg::from_str("41:s_msg,r_top").unwrap(),
TopicPermissionsArg {
topic_id: 41,
permissions: TopicPermissions {
manage_topic: false,
read_topic: true,
poll_messages: false,
send_messages: true,
}
}
);
assert_eq!(
TopicPermissionsArg::from_str("99:s_msg").unwrap(),
TopicPermissionsArg {
topic_id: 99,
permissions: TopicPermissions {
manage_topic: false,
read_topic: false,
poll_messages: false,
send_messages: true,
}
}
);
}
#[test]
fn should_not_deserialize_permissions() {
let wrong_id = TopicPermissionsArg::from_str("4a");
assert!(wrong_id.is_err());
assert_eq!(
wrong_id.unwrap_err(),
"Invalid topic ID - invalid digit found in string"
);
let wrong_permission = TopicPermissionsArg::from_str("41:reed_topic");
assert!(wrong_permission.is_err());
assert_eq!(
wrong_permission.unwrap_err(),
"Unknown permission \"reed_topic\" for topic ID: 41"
);
let multiple_wrong = TopicPermissionsArg::from_str("56:reed_topic,sent_messages");
assert!(multiple_wrong.is_err());
assert_eq!(
multiple_wrong.unwrap_err(),
"Unknown permissions \"reed_topic\", \"sent_messages\" for topic ID: 56"
);
}
#[test]
fn should_not_deserialize_short_permissions() {
let wrong_permission = TopicPermissionsArg::from_str("4:r_topic");
assert!(wrong_permission.is_err());
assert_eq!(
wrong_permission.unwrap_err(),
"Unknown permission \"r_topic\" for topic ID: 4"
);
let multiple_wrong = TopicPermissionsArg::from_str("55:r_topic,sent_msg");
assert!(multiple_wrong.is_err());
assert_eq!(
multiple_wrong.unwrap_err(),
"Unknown permissions \"r_topic\", \"sent_msg\" for topic ID: 55"
);
}
}