From e57bb9805be960781e262f6ddc77e93d38d43f58 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 1 May 2025 13:52:28 -0400 Subject: [PATCH 01/47] Fix a few Clippy 1.88 warnings (cherry picked from commit 534193310d71d1ddc8b78ad4d2efa0796ebe2f19) --- src/formatting.rs | 8 ++++---- src/responses.rs | 4 ++-- src/transformers.rs | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/formatting.rs b/src/formatting.rs index c75ad62..a595290 100644 --- a/src/formatting.rs +++ b/src/formatting.rs @@ -295,7 +295,7 @@ pub fn fmt_map_as_colon_separated_pairs( xs: &Map, ) -> fmt::Result { for (k, v) in xs.iter() { - writeln!(f, "{}: {}", k, v)?; + writeln!(f, "{k}: {v}")?; } Ok(()) @@ -307,7 +307,7 @@ where { match opt { None => "".to_owned(), - Some(val) => format!("{}", val).to_owned(), + Some(val) => format!("{val}").to_owned(), } } @@ -321,7 +321,7 @@ pub fn display_option_details_rate(opt: &Option) -> String { pub fn display_arg_table(xs: &XArguments) -> String { let mut s = String::new(); for (k, v) in xs.0.iter() { - let line = format!("{}: {}\n", k, v); + let line = format!("{k}: {v}\n"); s += line.as_str() } @@ -334,7 +334,7 @@ pub fn display_tag_map_option(opt: &Option) -> String { let mut s = String::new(); let iter = val.0.clone().into_iter(); for (k, v) in iter { - let line = format!("\"{}\": {}\n", k, v); + let line = format!("\"{k}\": {v}\n"); s += line.as_str() } diff --git a/src/responses.rs b/src/responses.rs index e686fc7..aeee58f 100644 --- a/src/responses.rs +++ b/src/responses.rs @@ -2329,8 +2329,8 @@ impl fmt::Display for WarmStandbyReplicationLinkStateOnDownstream { impl fmt::Display for WarmStandbyReplicationState { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - WarmStandbyReplicationState::Upstream(val) => write!(f, "{}", val), - WarmStandbyReplicationState::Downstream(val) => write!(f, "{}", val), + WarmStandbyReplicationState::Upstream(val) => write!(f, "{val}"), + WarmStandbyReplicationState::Downstream(val) => write!(f, "{val}"), WarmStandbyReplicationState::Unknown => write!(f, "(unknown)"), } } diff --git a/src/transformers.rs b/src/transformers.rs index 190a4bd..94e9fbd 100644 --- a/src/transformers.rs +++ b/src/transformers.rs @@ -79,7 +79,7 @@ impl DefinitionSetTransformer for ObfuscateUsernames { let mut obfuscated = HashMap::::new(); let mut i = 1u16; for u in &defs.users { - let new_name = format!("obfuscated-user-{}", i); + let new_name = format!("obfuscated-user-{i}"); i += 1; obfuscated.insert(u.name.clone(), new_name.clone()); } @@ -88,7 +88,7 @@ impl DefinitionSetTransformer for ObfuscateUsernames { let updated_users = defs.users.clone().into_iter().map(|u| { let new_name = obfuscated.get(&u.name).unwrap_or(&u.name).as_str(); let salt = password_hashing::salt(); - let new_password = format!("password-{}", i); + let new_password = format!("password-{i}"); let hash = password_hashing::base64_encoded_salted_password_hash_sha256(&salt, &new_password); From c2f0540fd54afb834f7643b13944eadd7a30d7a9 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 1 May 2025 13:53:24 -0400 Subject: [PATCH 02/47] cargo clippy --fix (cherry picked from commit dd2c1d65e472b26b6058e11d1dff7a02c4f81135) --- src/commons.rs | 4 +- src/formatting.rs | 24 +++++----- src/responses.rs | 2 +- src/utils.rs | 2 +- tests/async_binding_tests.rs | 51 ++++++++++------------ tests/async_channel_tests.rs | 4 +- tests/async_connection_tests.rs | 17 +++----- tests/async_consumer_tests.rs | 4 +- tests/async_definitions_tests.rs | 43 +++++++----------- tests/async_dynamic_shovel_tests.rs | 24 +++++----- tests/async_exchange_tests.rs | 2 +- tests/async_leader_rebalancing_tests.rs | 3 +- tests/async_message_tests.rs | 10 ++--- tests/async_overview_tests.rs | 2 +- tests/async_permission_tests.rs | 13 +++--- tests/async_policy_tests.rs | 4 +- tests/async_queue_tests.rs | 18 ++++---- tests/async_runtime_parameter_tests.rs | 3 +- tests/async_stream_consumer_tests.rs | 6 +-- tests/async_stream_publisher_tests.rs | 6 +-- tests/async_stream_tests.rs | 4 +- tests/async_user_tests.rs | 2 +- tests/blocking_binding_tests.rs | 51 ++++++++++------------ tests/blocking_channel_tests.rs | 4 +- tests/blocking_connection_tests.rs | 14 +++--- tests/blocking_consumer_tests.rs | 4 +- tests/blocking_definitions_tests.rs | 43 +++++++----------- tests/blocking_dynamic_shovel_tests.rs | 24 +++++----- tests/blocking_exchange_tests.rs | 2 +- tests/blocking_leader_rebalancing_tests.rs | 3 +- tests/blocking_message_tests.rs | 10 ++--- tests/blocking_overview_tests.rs | 2 +- tests/blocking_permission_tests.rs | 13 +++--- tests/blocking_policy_tests.rs | 4 +- tests/blocking_queue_tests.rs | 18 ++++---- tests/blocking_runtime_parameter_tests.rs | 3 +- tests/blocking_stream_consumer_tests.rs | 6 +-- tests/blocking_stream_publisher_tests.rs | 6 +-- tests/blocking_stream_tests.rs | 4 +- tests/blocking_user_tests.rs | 2 +- tests/test_helpers.rs | 4 +- 41 files changed, 201 insertions(+), 264 deletions(-) diff --git a/src/commons.rs b/src/commons.rs index c8c770d..075eef1 100644 --- a/src/commons.rs +++ b/src/commons.rs @@ -232,7 +232,7 @@ impl From<&SupportedProtocol> for String { impl fmt::Display for SupportedProtocol { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let proto: String = self.into(); - write!(f, "{}", proto) + write!(f, "{proto}") } } @@ -360,7 +360,7 @@ impl Display for QueueType { QueueType::Quorum => write!(f, "quorum"), QueueType::Stream => write!(f, "stream"), QueueType::Delayed => write!(f, "delayed"), - QueueType::Unsupported(s) => write!(f, "{}", s), + QueueType::Unsupported(s) => write!(f, "{s}"), } } } diff --git a/src/formatting.rs b/src/formatting.rs index a595290..56fc0f8 100644 --- a/src/formatting.rs +++ b/src/formatting.rs @@ -98,7 +98,7 @@ impl Display for TagMap { impl Display for DeprecatedFeatureList { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { for df in &self.0 { - writeln!(f, "{}", df)?; + writeln!(f, "{df}")?; } Ok(()) @@ -142,7 +142,7 @@ impl Display for FeatureFlag { impl Display for FeatureFlagList { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { for ff in &self.0 { - writeln!(f, "{}", ff)?; + writeln!(f, "{ff}")?; } Ok(()) @@ -152,7 +152,7 @@ impl Display for FeatureFlagList { impl Display for MessageList { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { for msg in &self.0 { - writeln!(f, "{}", msg)?; + writeln!(f, "{msg}")?; } Ok(()) @@ -230,9 +230,9 @@ pub fn fmt_list_as_json_array(f: &mut fmt::Formatter<'_>, xs: &[String]) -> fmt: let mut xs = xs.to_owned(); let last_element = xs.pop().unwrap(); for elem in xs { - write!(f, "{}, ", elem)?; + write!(f, "{elem}, ")?; } - write!(f, "{}", last_element)?; + write!(f, "{last_element}")?; write!(f, "]")?; Ok(()) } @@ -248,9 +248,9 @@ pub fn fmt_comma_separated_list(f: &mut fmt::Formatter<'_>, xs: &[String]) -> fm let mut xs = xs.to_owned(); let last_element = xs.pop().unwrap(); for elem in xs { - write!(f, "{}, ", elem)?; + write!(f, "{elem}, ")?; } - write!(f, "{}", last_element)?; + write!(f, "{last_element}")?; Ok(()) } } @@ -265,9 +265,9 @@ pub fn fmt_vertical_list_with_bullets(f: &mut fmt::Formatter<'_>, xs: &[String]) let mut xs = xs.to_owned(); let last_element = xs.pop().unwrap(); for elem in xs { - writeln!(f, "* {}", elem)?; + writeln!(f, "* {elem}")?; } - write!(f, "* {}", last_element)?; + write!(f, "* {last_element}")?; Ok(()) } } @@ -282,9 +282,9 @@ pub fn fmt_vertical_list_without_bullets(f: &mut fmt::Formatter<'_>, xs: &[Strin let mut xs = xs.to_owned(); let last_element = xs.pop().unwrap(); for elem in xs { - writeln!(f, "{}", elem)?; + writeln!(f, "{elem}")?; } - write!(f, "{}", last_element)?; + write!(f, "{last_element}")?; Ok(()) } } @@ -350,7 +350,7 @@ pub fn display_tag_list_option(opt: &Option) -> String { let mut s = String::new(); let iter = val.0.clone().into_iter(); for t in iter { - let line = format!("{}\n", t); + let line = format!("{t}\n"); s += line.as_str() } diff --git a/src/responses.rs b/src/responses.rs index aeee58f..e848c2d 100644 --- a/src/responses.rs +++ b/src/responses.rs @@ -378,7 +378,7 @@ impl fmt::Display for NodeMemoryBreakdown { ]; for (k, v) in data { - writeln!(f, "{}: {}", k, v)?; + writeln!(f, "{k}: {v}")?; } Ok(()) diff --git a/src/utils.rs b/src/utils.rs index 572a16e..f6d56ab 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -18,7 +18,7 @@ pub fn percentage(a: u64, b: u64) -> f64 { pub fn percentage_as_text(a: u64, b: u64) -> String { let p = percentage(a, b); - format!("{:.2}%", p) + format!("{p:.2}%") } #[macro_export] diff --git a/tests/async_binding_tests.rs b/tests/async_binding_tests.rs index 9907105..ee49f8d 100644 --- a/tests/async_binding_tests.rs +++ b/tests/async_binding_tests.rs @@ -32,20 +32,20 @@ async fn test_async_list_all_bindings() { let result1 = rc .declare_queue(vh_name, &QueueParams::new_durable_classic_queue(cq, None)) .await; - assert!(result1.is_ok(), "declare_queue returned {:?}", result1); + assert!(result1.is_ok(), "declare_queue returned {result1:?}"); let result2 = rc.bind_queue(vh_name, cq, fanout, None, None).await; - assert!(result2.is_ok(), "bind_queue returned {:?}", result2); + assert!(result2.is_ok(), "bind_queue returned {result2:?}"); let result3 = rc.list_bindings().await; - assert!(result3.is_ok(), "list_bindings returned {:?}", result3); + assert!(result3.is_ok(), "list_bindings returned {result3:?}"); let vec = result3.unwrap(); assert!(vec .iter() .any(|b| b.destination == cq && b.source == fanout)); let result4 = rc.list_bindings_in(vh_name).await; - assert!(result4.is_ok(), "list_bindings_in returned {:?}", result4); + assert!(result4.is_ok(), "list_bindings_in returned {result4:?}"); let vec = result4.unwrap(); assert!(vec .iter() @@ -66,16 +66,15 @@ async fn test_async_list_only_queue_bindings() { let result1 = rc .declare_queue(vh_name, &QueueParams::new_durable_classic_queue(cq, None)) .await; - assert!(result1.is_ok(), "declare_queue returned {:?}", result1); + assert!(result1.is_ok(), "declare_queue returned {result1:?}"); let result2 = rc.bind_queue(vh_name, cq, fanout, None, None).await; - assert!(result2.is_ok(), "bind_queue returned {:?}", result2); + assert!(result2.is_ok(), "bind_queue returned {result2:?}"); let result3 = rc.list_queue_bindings(vh_name, cq).await; assert!( result3.is_ok(), - "list_queue_bindings returned {:?}", - result3 + "list_queue_bindings returned {result3:?}" ); let vec = result3.unwrap(); assert!(vec @@ -104,28 +103,27 @@ async fn test_async_list_only_exchange_bindings() { &ExchangeParams::fanout(fanout2, false, false, None), ) .await; - assert!(result1.is_ok(), "declare_exchange returned {:?}", result1); + assert!(result1.is_ok(), "declare_exchange returned {result1:?}"); let result2 = rc .bind_exchange(vh_name, fanout1, fanout2, None, None) .await; - assert!(result2.is_ok(), "bind_exchange returned {:?}", result2); + assert!(result2.is_ok(), "bind_exchange returned {result2:?}"); let result3 = rc .declare_queue(vh_name, &QueueParams::new_durable_classic_queue(cq, None)) .await; - assert!(result3.is_ok(), "declare_queue returned {:?}", result3); + assert!(result3.is_ok(), "declare_queue returned {result3:?}"); let result4 = rc.bind_queue(vh_name, cq, fanout1, None, None).await; - assert!(result4.is_ok(), "bind_queue returned {:?}", result4); + assert!(result4.is_ok(), "bind_queue returned {result4:?}"); let result5 = rc .list_exchange_bindings_with_source(vh_name, fanout2) .await; assert!( result5.is_ok(), - "list_exchange_bindings_with_source returned {:?}", - result5 + "list_exchange_bindings_with_source returned {result5:?}" ); let vec = result5.unwrap(); assert!(!vec @@ -143,8 +141,7 @@ async fn test_async_list_only_exchange_bindings() { .await; assert!( result6.is_ok(), - "list_exchange_bindings_with_destination returned {:?}", - result6 + "list_exchange_bindings_with_destination returned {result6:?}" ); let vec = result6.unwrap(); assert!(!vec @@ -173,16 +170,15 @@ async fn test_async_delete_queue_bindings() { let result1 = rc .declare_queue(vh_name, &QueueParams::new_durable_classic_queue(cq, None)) .await; - assert!(result1.is_ok(), "declare_queue returned {:?}", result1); + assert!(result1.is_ok(), "declare_queue returned {result1:?}"); let result2 = rc.bind_queue(vh_name, cq, fanout, Some("foo"), None).await; - assert!(result2.is_ok(), "bind_queue returned {:?}", result2); + assert!(result2.is_ok(), "bind_queue returned {result2:?}"); let result3 = rc.list_queue_bindings(vh_name, cq).await; assert!( result3.is_ok(), - "list_queue_bindings returned {:?}", - result3 + "list_queue_bindings returned {result3:?}" ); let vec = result3.unwrap(); assert!(vec @@ -203,13 +199,12 @@ async fn test_async_delete_queue_bindings() { Some(m), ) .await; - assert!(result4.is_ok(), "delete_binding returned {:?}", result4); + assert!(result4.is_ok(), "delete_binding returned {result4:?}"); let result5 = rc.list_queue_bindings(vh_name, cq).await; assert!( result5.is_ok(), - "list_queue_bindings returned {:?}", - result5 + "list_queue_bindings returned {result5:?}" ); let vec = result5.unwrap(); assert!(!vec @@ -234,15 +229,14 @@ async fn test_async_delete_exchange_bindings() { let result2 = rc .bind_exchange(vh_name, direct, fanout, Some("foo"), None) .await; - assert!(result2.is_ok(), "bind_queue returned {:?}", result2); + assert!(result2.is_ok(), "bind_queue returned {result2:?}"); let result3 = rc .list_exchange_bindings_with_destination(vh_name, direct) .await; assert!( result3.is_ok(), - "list_exchange_bindings_with_destination returned {:?}", - result3 + "list_exchange_bindings_with_destination returned {result3:?}" ); let vec = result3.unwrap(); assert!(vec @@ -263,15 +257,14 @@ async fn test_async_delete_exchange_bindings() { Some(m), ) .await; - assert!(result4.is_ok(), "delete_binding returned {:?}", result4); + assert!(result4.is_ok(), "delete_binding returned {result4:?}"); let result5 = rc .list_exchange_bindings_with_destination(vh_name, direct) .await; assert!( result5.is_ok(), - "list_exchange_bindings_with_destination returned {:?}", - result5 + "list_exchange_bindings_with_destination returned {result5:?}" ); let vec = result5.unwrap(); assert!(!vec diff --git a/tests/async_channel_tests.rs b/tests/async_channel_tests.rs index 091d369..1516749 100644 --- a/tests/async_channel_tests.rs +++ b/tests/async_channel_tests.rs @@ -30,7 +30,7 @@ async fn test_list_channels() { assert!(ch.is_open()); let result1 = rc.list_channels().await; - assert!(result1.is_ok(), "list_channels returned {:?}", result1); + assert!(result1.is_ok(), "list_channels returned {result1:?}"); // just to be explicit ch.close().await.unwrap(); @@ -51,7 +51,7 @@ async fn test_list_virtual_host_channels() { let vh_name = "/"; let result1 = rc.list_channels_in(vh_name).await; - assert!(result1.is_ok(), "list_channels_in returned {:?}", result1); + assert!(result1.is_ok(), "list_channels_in returned {result1:?}"); // just to be explicit ch.close().await.unwrap(); diff --git a/tests/async_connection_tests.rs b/tests/async_connection_tests.rs index dd3bd13..14df2cd 100644 --- a/tests/async_connection_tests.rs +++ b/tests/async_connection_tests.rs @@ -29,7 +29,7 @@ async fn test_async_list_connections() { assert!(conn.is_open()); let result1 = rc.list_connections().await; - assert!(result1.is_ok(), "list_connections returned {:?}", result1); + assert!(result1.is_ok(), "list_connections returned {result1:?}"); conn.close().await.unwrap(); } @@ -42,8 +42,7 @@ async fn test_async_list_user_connections() { let result1 = rc.list_user_connections(USERNAME).await; assert!( result1.is_ok(), - "list_user_connections returned {:?}", - result1 + "list_user_connections returned {result1:?}" ); } @@ -61,8 +60,7 @@ async fn test_async_list_virtual_host_connections() { let result1 = rc.list_connections_in(vh).await; assert!( result1.is_ok(), - "list_connections_in returned {:?}", - result1 + "list_connections_in returned {result1:?}" ); rc.delete_vhost(vh, true).await.unwrap(); @@ -76,8 +74,7 @@ async fn test_async_list_stream_connections() { let result1 = rc.list_stream_connections().await; assert!( result1.is_ok(), - "list_stream_connections returned {:?}", - result1 + "list_stream_connections returned {result1:?}" ); } @@ -90,8 +87,7 @@ async fn test_async_list_virtual_host_stream_connections() { let result1 = rc.list_stream_connections_in(vh_name).await; assert!( result1.is_ok(), - "list_stream_connections returned {:?}", - result1 + "list_stream_connections returned {result1:?}" ); } @@ -112,8 +108,7 @@ async fn test_async_close_user_connections() { .await; assert!( result1.is_ok(), - "close_user_connections returned {:?}", - result1 + "close_user_connections returned {result1:?}" ); tokio::time::sleep(Duration::from_millis(50)).await; diff --git a/tests/async_consumer_tests.rs b/tests/async_consumer_tests.rs index e8ad709..4bcbfda 100644 --- a/tests/async_consumer_tests.rs +++ b/tests/async_consumer_tests.rs @@ -22,7 +22,7 @@ async fn test_async_list_consumers() { let rc = Client::new(&endpoint, USERNAME, PASSWORD); let result1 = rc.list_consumers().await; - assert!(result1.is_ok(), "list_consumers returned {:?}", result1); + assert!(result1.is_ok(), "list_consumers returned {result1:?}"); } #[tokio::test] @@ -35,7 +35,7 @@ async fn test_async_list_vhost_consumers() { assert!(result1.is_ok()); let result2 = rc.list_consumers_in(vh_params.name).await; - assert!(result2.is_ok(), "list_consumers_in returned {:?}", result2); + assert!(result2.is_ok(), "list_consumers_in returned {result2:?}"); rc.delete_vhost(vh_params.name, true).await.unwrap(); } diff --git a/tests/async_definitions_tests.rs b/tests/async_definitions_tests.rs index 6f4243f..ad66dfb 100644 --- a/tests/async_definitions_tests.rs +++ b/tests/async_definitions_tests.rs @@ -31,8 +31,7 @@ async fn test_async_export_definitions_as_string() { assert!( result.is_ok(), - "export_definitions_as_string returned {:?}", - result + "export_definitions_as_string returned {result:?}" ); } @@ -76,7 +75,7 @@ async fn test_async_export_cluster_wide_definitions_as_data() { &QueueParams::new_durable_classic_queue(q_name, None), ) .await; - assert!(q_result.is_ok(), "failed to declare queue {}", q_name); + assert!(q_result.is_ok(), "failed to declare queue {q_name}"); let _ = rc .bind_queue(vh_params.name, q_name, x_name, None, None) @@ -87,8 +86,7 @@ async fn test_async_export_cluster_wide_definitions_as_data() { assert!( result.is_ok(), - "export_definitions_as_data returned {:?}", - result + "export_definitions_as_data returned {result:?}" ); let defs = result.unwrap(); @@ -112,15 +110,13 @@ async fn test_async_export_cluster_wide_definitions_as_data() { let x_found = defs.exchanges.iter().any(|x| x.name == x_name); assert!( x_found, - "expected to find exchange {} in definitions", - x_name + "expected to find exchange {x_name} in definitions" ); let qq_pol_found = defs.policies.iter().any(|p| p.name == qq_pol_name); assert!( qq_pol_found, - "expected to find policy {} in definitions", - qq_pol_name + "expected to find policy {qq_pol_name} in definitions" ); let b_found = defs @@ -129,8 +125,7 @@ async fn test_async_export_cluster_wide_definitions_as_data() { .any(|b| b.destination_type == "queue".into() && b.destination == q_name); assert!( b_found, - "expected to find a binding for queue {} in definitions", - q_name + "expected to find a binding for queue {q_name} in definitions" ); rc.delete_exchange(vh, x_name, false).await.unwrap(); @@ -178,7 +173,7 @@ async fn test_async_export_vhost_definitions_as_data() { &QueueParams::new_durable_classic_queue(q_name, None), ) .await; - assert!(q_result.is_ok(), "failed to declare queue {}", q_name); + assert!(q_result.is_ok(), "failed to declare queue {q_name}"); let _ = rc .bind_queue(vh_params.name, q_name, x_name, None, None) @@ -189,8 +184,7 @@ async fn test_async_export_vhost_definitions_as_data() { assert!( result.is_ok(), - "test_export_vhost_definitions_as_data returned {:?}", - result + "test_export_vhost_definitions_as_data returned {result:?}" ); let defs = result.unwrap(); @@ -202,15 +196,13 @@ async fn test_async_export_vhost_definitions_as_data() { let x_found = defs.exchanges.iter().any(|x| x.name == x_name); assert!( x_found, - "expected to find exchange {} in definitions", - x_name + "expected to find exchange {x_name} in definitions" ); let qq_pol_found = defs.policies.iter().any(|p| p.name == qq_pol_name); assert!( qq_pol_found, - "expected to find policy {} in definitions", - qq_pol_name + "expected to find policy {qq_pol_name} in definitions" ); let b_found = defs @@ -219,8 +211,7 @@ async fn test_async_export_vhost_definitions_as_data() { .any(|b| b.destination_type == "queue".into() && b.destination == q_name); assert!( b_found, - "expected to find a binding for queue {} in definitions", - q_name + "expected to find a binding for queue {q_name} in definitions" ); rc.delete_exchange(vh, x_name, false).await.unwrap(); @@ -245,15 +236,13 @@ async fn test_async_import_cluster_definitions() { let result = rc.import_cluster_wide_definitions(defs).await; assert!( result.is_ok(), - "import_cluster_wide_definitions returned {:?}", - result + "import_cluster_wide_definitions returned {result:?}" ); let result1 = rc.get_queue_info("/", "imported_queue").await; assert!( result1.is_ok(), - "can't get the imported queue: {:?}", - result1 + "can't get the imported queue: {result1:?}" ); } @@ -280,8 +269,7 @@ async fn test_async_import_vhost_definitions() { let result = rc.import_vhost_definitions(vh, defs).await; assert!( result.is_ok(), - "import_vhost_definitions returned {:?}", - result + "import_vhost_definitions returned {result:?}" ); await_queue_metric_emission(); @@ -289,8 +277,7 @@ async fn test_async_import_vhost_definitions() { let result1 = rc.get_queue_info(vh, q).await; assert!( result1.is_ok(), - "can't get the imported queue: {:?}", - result1 + "can't get the imported queue: {result1:?}" ); rc.delete_vhost(vh, true).await.unwrap(); diff --git a/tests/async_dynamic_shovel_tests.rs b/tests/async_dynamic_shovel_tests.rs index 16abf1b..97bfdbf 100644 --- a/tests/async_dynamic_shovel_tests.rs +++ b/tests/async_dynamic_shovel_tests.rs @@ -40,8 +40,8 @@ async fn test_async_declare_a_dynamic_amqp091_shovel() { let result1 = rc.create_vhost(&vh_params).await; assert!(result1.is_ok()); - let src_q = format!("{0}.src.q", sh); - let dest_q = format!("{0}.dest.q", sh); + let src_q = format!("{sh}.src.q"); + let dest_q = format!("{sh}.dest.q"); let amqp_endpoint = amqp_endpoint_with_vhost(vh); let shovel_params = Amqp091ShovelParams { @@ -80,10 +80,10 @@ async fn test_async_declare_a_dynamic_amqp10_shovel() { // note: 4.1.0 will use a different addressing scheme, // see https://www.rabbitmq.com/docs/next/amqp#address-v2 - let src_queue = format!("{}.src.q", sh); - let src_address = format!("/queue/{}.src.q", sh); - let dest_queue = format!("{}.dest.q", sh); - let dest_address = format!("/queue/{}.dest.q", sh); + let src_queue = format!("{sh}.src.q"); + let src_address = format!("/queue/{sh}.src.q"); + let dest_queue = format!("{sh}.dest.q"); + let dest_address = format!("/queue/{sh}.dest.q"); let src_params = QueueParams::new_durable_classic_queue(&src_queue, None); let result2 = rc.declare_queue(vh, &src_params).await; @@ -124,8 +124,8 @@ async fn test_async_declare_a_dynamic_amqp091_shovel_with_predeclared_source_top let result1 = rc.create_vhost(&vh_params).await; assert!(result1.is_ok()); - let src_q = format!("{0}.src.q", sh); - let dest_q = format!("{0}.dest.q", sh); + let src_q = format!("{sh}.src.q"); + let dest_q = format!("{sh}.dest.q"); let q_params = QueueParams::new_durable_classic_queue(&src_q, None); let result2 = rc.declare_queue(vh, &q_params).await; @@ -166,8 +166,8 @@ async fn test_async_declare_a_dynamic_amqp091_shovel_with_predeclared_destinatio let result1 = rc.create_vhost(&vh_params).await; assert!(result1.is_ok()); - let src_q = format!("{0}.src.q", sh); - let dest_q = format!("{0}.dest.q", sh); + let src_q = format!("{sh}.src.q"); + let dest_q = format!("{sh}.dest.q"); let q_params = QueueParams::new_durable_classic_queue(&dest_q, None); let result2 = rc.declare_queue(vh, &q_params).await; @@ -211,8 +211,8 @@ async fn test_async_delete_a_dynamic_amqp091_shovel() { let result1 = rc.create_vhost(&vh_params).await; assert!(result1.is_ok()); - let src_q = format!("{0}.src.q", sh); - let dest_q = format!("{0}.dest.q", sh); + let src_q = format!("{sh}.src.q"); + let dest_q = format!("{sh}.dest.q"); let amqp_endpoint = amqp_endpoint_with_vhost(vh); let shovel_params = Amqp091ShovelParams { diff --git a/tests/async_exchange_tests.rs b/tests/async_exchange_tests.rs index 5bcc4b2..c82809a 100644 --- a/tests/async_exchange_tests.rs +++ b/tests/async_exchange_tests.rs @@ -139,5 +139,5 @@ async fn test_async_list_exchanges_in_a_virtual_host() { let rc = Client::new(&endpoint, USERNAME, PASSWORD); let result1 = rc.list_exchanges_in("/").await; - assert!(result1.is_ok(), "list_exchanges_in returned {:?}", result1); + assert!(result1.is_ok(), "list_exchanges_in returned {result1:?}"); } diff --git a/tests/async_leader_rebalancing_tests.rs b/tests/async_leader_rebalancing_tests.rs index 05758d1..909f115 100644 --- a/tests/async_leader_rebalancing_tests.rs +++ b/tests/async_leader_rebalancing_tests.rs @@ -24,7 +24,6 @@ async fn test_async_leader_rebalancing() { let result1 = rc.rebalance_queue_leaders().await; assert!( result1.is_ok(), - "rebalance_queue_leaders returned {:?}", - result1 + "rebalance_queue_leaders returned {result1:?}" ); } diff --git a/tests/async_message_tests.rs b/tests/async_message_tests.rs index 2cac9a4..28b5349 100644 --- a/tests/async_message_tests.rs +++ b/tests/async_message_tests.rs @@ -32,7 +32,7 @@ async fn test_async_publish_and_get() { let params = QueueParams::new_durable_classic_queue(queue, None); let result2 = rc.declare_queue(vhost, ¶ms).await; - assert!(result2.is_ok(), "declare_queue returned {:?}", result2); + assert!(result2.is_ok(), "declare_queue returned {result2:?}"); let result3 = rc .publish_message( @@ -43,7 +43,7 @@ async fn test_async_publish_and_get() { requests::MessageProperties::default(), ) .await; - assert!(result3.is_ok(), "get_messages returned {:?}", result3); + assert!(result3.is_ok(), "get_messages returned {result3:?}"); assert_eq!(result3.unwrap(), MessageRouted { routed: true }); let mut props = Map::::new(); @@ -51,11 +51,11 @@ async fn test_async_publish_and_get() { let result4 = rc .publish_message(vhost, "", queue, "rust test 2", props.clone()) .await; - assert!(result4.is_ok(), "get_messages returned {:?}", result4); + assert!(result4.is_ok(), "get_messages returned {result4:?}"); assert_eq!(result4.unwrap(), MessageRouted { routed: true }); let result5 = rc.get_messages(vhost, queue, 1, "ack_requeue_false").await; - assert!(result5.is_ok(), "get_messages returned {:?}", result5); + assert!(result5.is_ok(), "get_messages returned {result5:?}"); let msg_list = result5.unwrap(); assert_eq!( @@ -73,7 +73,7 @@ async fn test_async_publish_and_get() { ); let result7 = rc.get_messages(vhost, queue, 1, "ack_requeue_false").await; - assert!(result7.is_ok(), "get_messages returned {:?}", result7); + assert!(result7.is_ok(), "get_messages returned {result7:?}"); let props = MessageProperties(props); let msg_list2 = result7.unwrap(); diff --git a/tests/async_overview_tests.rs b/tests/async_overview_tests.rs index c69a58f..a4bf90a 100644 --- a/tests/async_overview_tests.rs +++ b/tests/async_overview_tests.rs @@ -25,7 +25,7 @@ async fn test_async_overview() { let _ = generate_activity().await; let result1 = rc.overview().await; - assert!(result1.is_ok(), "overview returned {:?}", result1); + assert!(result1.is_ok(), "overview returned {result1:?}"); let ov = result1.unwrap(); assert!(ov.object_totals.exchanges > 0); diff --git a/tests/async_permission_tests.rs b/tests/async_permission_tests.rs index 57481a6..1321ac3 100644 --- a/tests/async_permission_tests.rs +++ b/tests/async_permission_tests.rs @@ -55,7 +55,7 @@ async fn test_async_list_permissions_in() { assert!(result1.is_ok()); let result = rc.list_permissions_in("test_list_permissions_in").await; - assert!(result.is_ok(), "list_permissions_in returned {:?}", result); + assert!(result.is_ok(), "list_permissions_in returned {result:?}"); let vec = result.unwrap(); assert!(vec.iter().any(|p| p @@ -81,7 +81,7 @@ async fn test_async_list_permissions_of() { assert!(result1.is_ok()); let result = rc.list_permissions_of("guest").await; - assert!(result.is_ok(), "list_permissions_of returned {:?}", result); + assert!(result.is_ok(), "list_permissions_of returned {result:?}"); let vec = result.unwrap(); assert!(vec.iter().any(|p| p @@ -109,8 +109,7 @@ async fn test_async_get_permissions() { let result2 = rc.get_permissions("test_get_permissions", "guest").await; assert!( result2.is_ok(), - "list_permissions_of returned {:?}", - result2 + "list_permissions_of returned {result2:?}" ); let permissions = result2.unwrap(); @@ -146,10 +145,10 @@ async fn test_async_grant_permissions() { write: "write", }; let result = rc.declare_permissions(¶ms).await; - assert!(result.is_ok(), "declare_permissions returned {:?}", result); + assert!(result.is_ok(), "declare_permissions returned {result:?}"); let result2 = rc.get_permissions(vh_params.name, "guest").await; - assert!(result2.is_ok(), "get_permissions_of returned {:?}", result2); + assert!(result2.is_ok(), "get_permissions_of returned {result2:?}"); let result3 = result2.unwrap(); assert_eq!( @@ -164,7 +163,7 @@ async fn test_async_grant_permissions() { ); let result4 = rc.grant_permissions(vh_params.name, "guest").await; - assert!(result4.is_ok(), "delete_permissions returned {:?}", result4); + assert!(result4.is_ok(), "delete_permissions returned {result4:?}"); let result5 = rc.get_permissions(vh_params.name, "guest").await; assert!(result5.is_err(), "permissions found after deletion"); diff --git a/tests/async_policy_tests.rs b/tests/async_policy_tests.rs index ef44af5..f59398e 100644 --- a/tests/async_policy_tests.rs +++ b/tests/async_policy_tests.rs @@ -108,7 +108,7 @@ async fn test_a_policy(rc: &Client<&str, &str, &str>, policy: &PolicyParams<'_>) assert!(!policies.iter().any(|p| p.name == policy.name)); let result = rc.declare_policy(policy).await; - assert!(result.is_ok(), "declare_policy returned {:?}", result); + assert!(result.is_ok(), "declare_policy returned {result:?}"); // validate it was created as expected let fetched_policy = rc.get_policy(policy.vhost, policy.name).await.unwrap(); @@ -128,7 +128,7 @@ async fn test_an_operator_policy(rc: &Client<&str, &str, &str>, policy: &PolicyP assert!(!policies.iter().any(|p| p.name == policy.name)); let result = rc.declare_operator_policy(policy).await; - assert!(result.is_ok(), "declare_policy returned {:?}", result); + assert!(result.is_ok(), "declare_policy returned {result:?}"); // validate it was created as expected let fetched_policy = rc diff --git a/tests/async_queue_tests.rs b/tests/async_queue_tests.rs index 9dae357..0aefe25 100644 --- a/tests/async_queue_tests.rs +++ b/tests/async_queue_tests.rs @@ -35,11 +35,11 @@ async fn test_async_declare_and_redeclare_a_classic_queue() { let optional_args = Some(map); let params = QueueParams::new_durable_classic_queue(name, optional_args.clone()); let result2 = rc.declare_queue(vhost, ¶ms).await; - assert!(result2.is_ok(), "declare_queue returned {:?}", result2); + assert!(result2.is_ok(), "declare_queue returned {result2:?}"); let params2 = QueueParams::new(name, QueueType::Classic, true, false, optional_args.clone()); let result3 = rc.declare_queue(vhost, ¶ms2).await; - assert!(result3.is_ok(), "declare_queue returned {:?}", result3); + assert!(result3.is_ok(), "declare_queue returned {result3:?}"); let _ = rc.delete_queue(vhost, name, false).await; } @@ -61,7 +61,7 @@ async fn test_async_declare_a_quorum_queue() { let optional_args = Some(map); let params = QueueParams::new_quorum_queue(name, optional_args); let result2 = rc.declare_queue(vhost, ¶ms).await; - assert!(result2.is_ok(), "declare_queue returned {:?}", result2); + assert!(result2.is_ok(), "declare_queue returned {result2:?}"); let _ = rc.delete_queue(vhost, name, false).await; } @@ -83,7 +83,7 @@ async fn test_async_declare_a_stream_with_declare_queue() { let optional_args = Some(map); let params = QueueParams::new_stream(name, optional_args); let result2 = rc.declare_queue(vhost, ¶ms).await; - assert!(result2.is_ok(), "declare_queue returned {:?}", result2); + assert!(result2.is_ok(), "declare_queue returned {result2:?}"); let _ = rc.delete_queue(vhost, name, false).await; } @@ -102,7 +102,7 @@ async fn test_async_delete_queue() { let params = QueueParams::new_durable_classic_queue(name, None); let result2 = rc.declare_queue(vhost, ¶ms).await; - assert!(result2.is_ok(), "declare_queue returned {:?}", result2); + assert!(result2.is_ok(), "declare_queue returned {result2:?}"); rc.delete_queue(vhost, name, false).await.unwrap(); let result3 = rc.get_queue_info(vhost, name).await; @@ -118,12 +118,12 @@ async fn test_async_list_all_queues() { let params = QueueParams::new_durable_classic_queue("rust.tests.cq.23487866", None); let result1 = rc.declare_queue(vh_name, ¶ms).await; - assert!(result1.is_ok(), "declare_queue returned {:?}", result1); + assert!(result1.is_ok(), "declare_queue returned {result1:?}"); test_helpers::async_await_queue_metric_emission().await; let result2 = rc.list_queues().await; - assert!(result2.is_ok(), "list_queues returned {:?}", result2); + assert!(result2.is_ok(), "list_queues returned {result2:?}"); rc.delete_queue(vh_name, params.name, false).await.unwrap(); } @@ -137,12 +137,12 @@ async fn test_async_list_queues_in_a_virtual_host() { let params = QueueParams::new_durable_classic_queue("rust.tests.cq.64692734867", None); let result1 = rc.declare_queue(vh_name, ¶ms).await; - assert!(result1.is_ok(), "declare_queue returned {:?}", result1); + assert!(result1.is_ok(), "declare_queue returned {result1:?}"); test_helpers::async_await_queue_metric_emission().await; let result2 = rc.list_queues_in(vh_name).await; - assert!(result2.is_ok(), "list_queues_in returned {:?}", result2); + assert!(result2.is_ok(), "list_queues_in returned {result2:?}"); rc.delete_queue(vh_name, params.name, false).await.unwrap(); } diff --git a/tests/async_runtime_parameter_tests.rs b/tests/async_runtime_parameter_tests.rs index a6afdc2..ed4fbba 100644 --- a/tests/async_runtime_parameter_tests.rs +++ b/tests/async_runtime_parameter_tests.rs @@ -77,8 +77,7 @@ async fn test_async_clear_runtime_parameter() { let result4 = rc.list_runtime_parameters().await; assert!( result4.is_ok(), - "list_runtime_parameters returned {:?}", - result4 + "list_runtime_parameters returned {result4:?}" ); let vec = result4.unwrap(); assert!(!vec diff --git a/tests/async_stream_consumer_tests.rs b/tests/async_stream_consumer_tests.rs index 4a9fe00..f5a422d 100644 --- a/tests/async_stream_consumer_tests.rs +++ b/tests/async_stream_consumer_tests.rs @@ -24,8 +24,7 @@ async fn test_async_list_stream_consumers() { let result1 = rc.list_stream_consumers().await; assert!( result1.is_ok(), - "list_stream_publishers returned {:?}", - result1 + "list_stream_publishers returned {result1:?}" ); } @@ -38,7 +37,6 @@ async fn test_async_list_virtual_host_stream_consumers() { let result1 = rc.list_stream_consumers_in(vh_name).await; assert!( result1.is_ok(), - "list_stream_publishers_in returned {:?}", - result1 + "list_stream_publishers_in returned {result1:?}" ); } diff --git a/tests/async_stream_publisher_tests.rs b/tests/async_stream_publisher_tests.rs index 55ed1d0..7958d86 100644 --- a/tests/async_stream_publisher_tests.rs +++ b/tests/async_stream_publisher_tests.rs @@ -24,8 +24,7 @@ async fn test_async_list_stream_publishers() { let result1 = rc.list_stream_publishers().await; assert!( result1.is_ok(), - "list_stream_publishers returned {:?}", - result1 + "list_stream_publishers returned {result1:?}" ); } @@ -38,7 +37,6 @@ async fn test_async_list_virtual_host_stream_publishers() { let result1 = rc.list_stream_publishers_in(vh_name).await; assert!( result1.is_ok(), - "list_stream_publishers_in returned {:?}", - result1 + "list_stream_publishers_in returned {result1:?}" ); } diff --git a/tests/async_stream_tests.rs b/tests/async_stream_tests.rs index ae0a4bc..a282a4d 100644 --- a/tests/async_stream_tests.rs +++ b/tests/async_stream_tests.rs @@ -43,7 +43,7 @@ async fn test_async_declare_stream() { }; let result2 = rc.declare_stream(vhost, ¶ms).await; - assert!(result2.is_ok(), "declare_stream returned {:?}", result2); + assert!(result2.is_ok(), "declare_stream returned {result2:?}"); let _ = rc.delete_stream(vhost, name, false).await; } @@ -63,7 +63,7 @@ async fn test_async_delete_stream() { let params = StreamParams::new(name, "7D"); let result2 = rc.declare_stream(vhost, ¶ms).await; - assert!(result2.is_ok(), "declare_stream returned {:?}", result2); + assert!(result2.is_ok(), "declare_stream returned {result2:?}"); rc.delete_stream(vhost, name, false).await.unwrap(); let result3 = rc.get_stream_info(vhost, name).await; diff --git a/tests/async_user_tests.rs b/tests/async_user_tests.rs index a84a7c2..5171261 100644 --- a/tests/async_user_tests.rs +++ b/tests/async_user_tests.rs @@ -33,7 +33,7 @@ async fn test_async_list_users_without_permissions() { let rc = Client::new(&endpoint, USERNAME, PASSWORD); let test_name = "test_async_list_users_without_permissions"; - let username = format!("{}.1", test_name); + let username = format!("{test_name}.1"); rc.delete_user(&username, true) .await .expect("failed to delete a user"); diff --git a/tests/blocking_binding_tests.rs b/tests/blocking_binding_tests.rs index 1d225cc..0bf9cdd 100644 --- a/tests/blocking_binding_tests.rs +++ b/tests/blocking_binding_tests.rs @@ -30,20 +30,20 @@ fn test_blocking_list_all_bindings() { let fanout = "amq.fanout"; let result1 = rc.declare_queue(vh_name, &QueueParams::new_durable_classic_queue(cq, None)); - assert!(result1.is_ok(), "declare_queue returned {:?}", result1); + assert!(result1.is_ok(), "declare_queue returned {result1:?}"); let result2 = rc.bind_queue(vh_name, cq, fanout, None, None); - assert!(result2.is_ok(), "bind_queue returned {:?}", result2); + assert!(result2.is_ok(), "bind_queue returned {result2:?}"); let result3 = rc.list_bindings(); - assert!(result3.is_ok(), "list_bindings returned {:?}", result3); + assert!(result3.is_ok(), "list_bindings returned {result3:?}"); let vec = result3.unwrap(); assert!(vec .iter() .any(|b| b.destination == cq && b.source == fanout)); let result4 = rc.list_bindings_in(vh_name); - assert!(result4.is_ok(), "list_bindings_in returned {:?}", result4); + assert!(result4.is_ok(), "list_bindings_in returned {result4:?}"); let vec = result4.unwrap(); assert!(vec .iter() @@ -62,16 +62,15 @@ fn test_blocking_list_only_queue_bindings() { let fanout = "amq.fanout"; let result1 = rc.declare_queue(vh_name, &QueueParams::new_durable_classic_queue(cq, None)); - assert!(result1.is_ok(), "declare_queue returned {:?}", result1); + assert!(result1.is_ok(), "declare_queue returned {result1:?}"); let result2 = rc.bind_queue(vh_name, cq, fanout, None, None); - assert!(result2.is_ok(), "bind_queue returned {:?}", result2); + assert!(result2.is_ok(), "bind_queue returned {result2:?}"); let result3 = rc.list_queue_bindings(vh_name, cq); assert!( result3.is_ok(), - "list_queue_bindings returned {:?}", - result3 + "list_queue_bindings returned {result3:?}" ); let vec = result3.unwrap(); assert!(vec @@ -98,22 +97,21 @@ fn test_blocking_list_only_exchange_bindings() { vh_name, &ExchangeParams::fanout(fanout2, false, false, None), ); - assert!(result1.is_ok(), "declare_exchange returned {:?}", result1); + assert!(result1.is_ok(), "declare_exchange returned {result1:?}"); let result2 = rc.bind_exchange(vh_name, fanout1, fanout2, None, None); - assert!(result2.is_ok(), "bind_exchange returned {:?}", result2); + assert!(result2.is_ok(), "bind_exchange returned {result2:?}"); let result3 = rc.declare_queue(vh_name, &QueueParams::new_durable_classic_queue(cq, None)); - assert!(result3.is_ok(), "declare_queue returned {:?}", result3); + assert!(result3.is_ok(), "declare_queue returned {result3:?}"); let result4 = rc.bind_queue(vh_name, cq, fanout1, None, None); - assert!(result4.is_ok(), "bind_queue returned {:?}", result4); + assert!(result4.is_ok(), "bind_queue returned {result4:?}"); let result5 = rc.list_exchange_bindings_with_source(vh_name, fanout2); assert!( result5.is_ok(), - "list_exchange_bindings_with_source returned {:?}", - result5 + "list_exchange_bindings_with_source returned {result5:?}" ); let vec = result5.unwrap(); assert!(!vec @@ -129,8 +127,7 @@ fn test_blocking_list_only_exchange_bindings() { let result6 = rc.list_exchange_bindings_with_destination(vh_name, fanout1); assert!( result6.is_ok(), - "list_exchange_bindings_with_destination returned {:?}", - result6 + "list_exchange_bindings_with_destination returned {result6:?}" ); let vec = result6.unwrap(); assert!(!vec @@ -157,16 +154,15 @@ fn test_blocking_delete_queue_bindings() { let fanout = "amq.fanout"; let result1 = rc.declare_queue(vh_name, &QueueParams::new_durable_classic_queue(cq, None)); - assert!(result1.is_ok(), "declare_queue returned {:?}", result1); + assert!(result1.is_ok(), "declare_queue returned {result1:?}"); let result2 = rc.bind_queue(vh_name, cq, fanout, Some("foo"), None); - assert!(result2.is_ok(), "bind_queue returned {:?}", result2); + assert!(result2.is_ok(), "bind_queue returned {result2:?}"); let result3 = rc.list_queue_bindings(vh_name, cq); assert!( result3.is_ok(), - "list_queue_bindings returned {:?}", - result3 + "list_queue_bindings returned {result3:?}" ); let vec = result3.unwrap(); assert!(vec @@ -185,13 +181,12 @@ fn test_blocking_delete_queue_bindings() { "foo", Some(m), ); - assert!(result4.is_ok(), "delete_binding returned {:?}", result4); + assert!(result4.is_ok(), "delete_binding returned {result4:?}"); let result5 = rc.list_queue_bindings(vh_name, cq); assert!( result5.is_ok(), - "list_queue_bindings returned {:?}", - result5 + "list_queue_bindings returned {result5:?}" ); let vec = result5.unwrap(); assert!(!vec @@ -214,13 +209,12 @@ fn test_blocking_delete_exchange_bindings() { let direct = "amq.direct"; let result2 = rc.bind_exchange(vh_name, direct, fanout, Some("foo"), None); - assert!(result2.is_ok(), "bind_queue returned {:?}", result2); + assert!(result2.is_ok(), "bind_queue returned {result2:?}"); let result3 = rc.list_exchange_bindings_with_destination(vh_name, direct); assert!( result3.is_ok(), - "list_exchange_bindings_with_destination returned {:?}", - result3 + "list_exchange_bindings_with_destination returned {result3:?}" ); let vec = result3.unwrap(); assert!(vec @@ -239,13 +233,12 @@ fn test_blocking_delete_exchange_bindings() { "foo", Some(m), ); - assert!(result4.is_ok(), "delete_binding returned {:?}", result4); + assert!(result4.is_ok(), "delete_binding returned {result4:?}"); let result5 = rc.list_exchange_bindings_with_destination(vh_name, direct); assert!( result5.is_ok(), - "list_exchange_bindings_with_destination returned {:?}", - result5 + "list_exchange_bindings_with_destination returned {result5:?}" ); let vec = result5.unwrap(); assert!(!vec diff --git a/tests/blocking_channel_tests.rs b/tests/blocking_channel_tests.rs index 11a3e39..ad74f14 100644 --- a/tests/blocking_channel_tests.rs +++ b/tests/blocking_channel_tests.rs @@ -22,7 +22,7 @@ fn test_blocking_list_channels() { let rc = Client::new(&endpoint, USERNAME, PASSWORD); let result1 = rc.list_channels(); - assert!(result1.is_ok(), "list_channels returned {:?}", result1); + assert!(result1.is_ok(), "list_channels returned {result1:?}"); } #[test] @@ -32,5 +32,5 @@ fn test_blocking_list_virtual_host_channels() { let vh_name = "/"; let result1 = rc.list_channels_in(vh_name); - assert!(result1.is_ok(), "list_channels_in returned {:?}", result1); + assert!(result1.is_ok(), "list_channels_in returned {result1:?}"); } diff --git a/tests/blocking_connection_tests.rs b/tests/blocking_connection_tests.rs index 4f06454..cd94599 100644 --- a/tests/blocking_connection_tests.rs +++ b/tests/blocking_connection_tests.rs @@ -23,7 +23,7 @@ fn test_blocking_list_connections() { let rc = Client::new(&endpoint, USERNAME, PASSWORD); let result1 = rc.list_connections(); - assert!(result1.is_ok(), "list_connections returned {:?}", result1); + assert!(result1.is_ok(), "list_connections returned {result1:?}"); } #[test] @@ -34,8 +34,7 @@ fn test_blocking_list_user_connections() { let result1 = rc.list_user_connections(USERNAME); assert!( result1.is_ok(), - "list_user_connections returned {:?}", - result1 + "list_user_connections returned {result1:?}" ); } @@ -53,8 +52,7 @@ fn test_blocking_list_virtual_host_connections() { let result1 = rc.list_connections_in(vh); assert!( result1.is_ok(), - "list_connections_in returned {:?}", - result1 + "list_connections_in returned {result1:?}" ); rc.delete_vhost(vh, true).unwrap(); @@ -68,8 +66,7 @@ fn test_blocking_list_stream_connections() { let result1 = rc.list_stream_connections(); assert!( result1.is_ok(), - "list_stream_connections returned {:?}", - result1 + "list_stream_connections returned {result1:?}" ); } @@ -82,7 +79,6 @@ fn test_blocking_list_virtual_host_stream_connections() { let result1 = rc.list_stream_connections_in(vh_name); assert!( result1.is_ok(), - "list_stream_connections returned {:?}", - result1 + "list_stream_connections returned {result1:?}" ); } diff --git a/tests/blocking_consumer_tests.rs b/tests/blocking_consumer_tests.rs index 9fbdb5c..5220493 100644 --- a/tests/blocking_consumer_tests.rs +++ b/tests/blocking_consumer_tests.rs @@ -22,7 +22,7 @@ fn test_blocking_list_consumers() { let rc = Client::new(&endpoint, USERNAME, PASSWORD); let result1 = rc.list_consumers(); - assert!(result1.is_ok(), "list_consumers returned {:?}", result1); + assert!(result1.is_ok(), "list_consumers returned {result1:?}"); } #[test] @@ -35,7 +35,7 @@ fn test_blocking_list_vhost_consumers() { assert!(result1.is_ok()); let result2 = rc.list_consumers_in(vh_params.name); - assert!(result2.is_ok(), "list_consumers_in returned {:?}", result2); + assert!(result2.is_ok(), "list_consumers_in returned {result2:?}"); rc.delete_vhost(vh_params.name, true).unwrap(); } diff --git a/tests/blocking_definitions_tests.rs b/tests/blocking_definitions_tests.rs index baa39f1..6c6c417 100644 --- a/tests/blocking_definitions_tests.rs +++ b/tests/blocking_definitions_tests.rs @@ -31,8 +31,7 @@ fn test_blocking_export_definitions_as_string() { let result = rc.export_cluster_wide_definitions_as_string(); assert!( result.is_ok(), - "export_definitions_as_string returned {:?}", - result + "export_definitions_as_string returned {result:?}" ); } @@ -72,7 +71,7 @@ fn test_blocking_export_cluster_wide_definitions_as_data() { vh_params.name, &QueueParams::new_durable_classic_queue(q_name, None), ); - assert!(q_result.is_ok(), "failed to declare queue {}", q_name); + assert!(q_result.is_ok(), "failed to declare queue {q_name}"); let _ = rc.bind_queue(vh_params.name, q_name, x_name, None, None); await_metric_emission(1000); @@ -80,8 +79,7 @@ fn test_blocking_export_cluster_wide_definitions_as_data() { let result = rc.export_cluster_wide_definitions_as_data(); assert!( result.is_ok(), - "export_definitions_as_data returned {:?}", - result + "export_definitions_as_data returned {result:?}" ); let defs = result.unwrap(); @@ -105,15 +103,13 @@ fn test_blocking_export_cluster_wide_definitions_as_data() { let x_found = defs.exchanges.iter().any(|x| x.name == x_name); assert!( x_found, - "expected to find exchange {} in definitions", - x_name + "expected to find exchange {x_name} in definitions" ); let qq_pol_found = defs.policies.iter().any(|p| p.name == qq_pol_name); assert!( qq_pol_found, - "expected to find policy {} in definitions", - qq_pol_name + "expected to find policy {qq_pol_name} in definitions" ); let b_found = defs @@ -122,8 +118,7 @@ fn test_blocking_export_cluster_wide_definitions_as_data() { .any(|b| b.destination_type == "queue".into() && b.destination == q_name); assert!( b_found, - "expected to find a binding for queue {} in definitions", - q_name + "expected to find a binding for queue {q_name} in definitions" ); rc.delete_exchange(vh, x_name, false).unwrap(); @@ -167,7 +162,7 @@ fn test_blocking_export_vhost_definitions_as_data() { vh_params.name, &QueueParams::new_durable_classic_queue(q_name, None), ); - assert!(q_result.is_ok(), "failed to declare queue {}", q_name); + assert!(q_result.is_ok(), "failed to declare queue {q_name}"); let _ = rc.bind_queue(vh_params.name, q_name, x_name, None, None); await_metric_emission(1000); @@ -175,8 +170,7 @@ fn test_blocking_export_vhost_definitions_as_data() { let result = rc.export_vhost_definitions_as_data(vh); assert!( result.is_ok(), - "export_definitions_as_data returned {:?}", - result + "export_definitions_as_data returned {result:?}" ); let defs = result.unwrap(); @@ -189,15 +183,13 @@ fn test_blocking_export_vhost_definitions_as_data() { let x_found = defs.exchanges.iter().any(|x| x.name == x_name); assert!( x_found, - "expected to find exchange {} in definitions", - x_name + "expected to find exchange {x_name} in definitions" ); let qq_pol_found = defs.policies.iter().any(|p| p.name == qq_pol_name); assert!( qq_pol_found, - "expected to find policy {} in definitions", - qq_pol_name + "expected to find policy {qq_pol_name} in definitions" ); let b_found = defs @@ -206,8 +198,7 @@ fn test_blocking_export_vhost_definitions_as_data() { .any(|b| b.destination_type == "queue".into() && b.destination == q_name); assert!( b_found, - "expected to find a binding for queue {} in definitions", - q_name + "expected to find a binding for queue {q_name} in definitions" ); rc.delete_exchange(vh, x_name, false).unwrap(); @@ -234,15 +225,13 @@ fn test_blocking_import_cluster_definitions() { let result = rc.import_cluster_wide_definitions(defs); assert!( result.is_ok(), - "import_cluster_wide_definitions returned {:?}", - result + "import_cluster_wide_definitions returned {result:?}" ); let result1 = rc.get_queue_info("/", q); assert!( result1.is_ok(), - "can't get the imported import_cluster_wide_definitions: {:?}", - result1 + "can't get the imported import_cluster_wide_definitions: {result1:?}" ); rc.delete_queue("/", q, true).unwrap(); @@ -271,8 +260,7 @@ fn test_blocking_import_vhost_definitions() { let result = rc.import_vhost_definitions(vh, defs); assert!( result.is_ok(), - "import_vhost_definitions returned {:?}", - result + "import_vhost_definitions returned {result:?}" ); await_queue_metric_emission(); @@ -280,8 +268,7 @@ fn test_blocking_import_vhost_definitions() { let result1 = rc.get_queue_info(vh, q); assert!( result1.is_ok(), - "can't get the imported queue: {:?}", - result1 + "can't get the imported queue: {result1:?}" ); rc.delete_vhost(vh, true).unwrap(); diff --git a/tests/blocking_dynamic_shovel_tests.rs b/tests/blocking_dynamic_shovel_tests.rs index 988af70..88ce6c2 100644 --- a/tests/blocking_dynamic_shovel_tests.rs +++ b/tests/blocking_dynamic_shovel_tests.rs @@ -40,8 +40,8 @@ fn test_blocking_declare_a_dynamic_amqp091_shovel() { let result1 = rc.create_vhost(&vh_params); assert!(result1.is_ok()); - let src_q = format!("{0}.src.q", sh); - let dest_q = format!("{0}.dest.q", sh); + let src_q = format!("{sh}.src.q"); + let dest_q = format!("{sh}.dest.q"); let amqp_endpoint = amqp_endpoint_with_vhost(vh); let shovel_params = Amqp091ShovelParams { @@ -80,10 +80,10 @@ fn test_blocking_declare_a_dynamic_amqp10_shovel() { // note: 4.1.0 will use a different addressing scheme, // see https://www.rabbitmq.com/docs/next/amqp#address-v2 - let src_queue = format!("{}.src.q", sh); - let src_address = format!("/queue/{}.src.q", sh); - let dest_queue = format!("{}.dest.q", sh); - let dest_address = format!("/queue/{}.dest.q", sh); + let src_queue = format!("{sh}.src.q"); + let src_address = format!("/queue/{sh}.src.q"); + let dest_queue = format!("{sh}.dest.q"); + let dest_address = format!("/queue/{sh}.dest.q"); let src_params = QueueParams::new_durable_classic_queue(&src_queue, None); let result2 = rc.declare_queue(vh, &src_params); @@ -124,8 +124,8 @@ fn test_blocking_declare_a_dynamic_amqp091_shovel_with_predeclared_source_topolo let result1 = rc.create_vhost(&vh_params); assert!(result1.is_ok()); - let src_q = format!("{0}.src.q", sh); - let dest_q = format!("{0}.dest.q", sh); + let src_q = format!("{sh}.src.q"); + let dest_q = format!("{sh}.dest.q"); let q_params = QueueParams::new_durable_classic_queue(&src_q, None); let result2 = rc.declare_queue(vh, &q_params); @@ -166,8 +166,8 @@ fn test_blocking_declare_a_dynamic_amqp091_shovel_with_predeclared_destination_t let result1 = rc.create_vhost(&vh_params); assert!(result1.is_ok()); - let src_q = format!("{0}.src.q", sh); - let dest_q = format!("{0}.dest.q", sh); + let src_q = format!("{sh}.src.q"); + let dest_q = format!("{sh}.dest.q"); let q_params = QueueParams::new_durable_classic_queue(&dest_q, None); let result2 = rc.declare_queue(vh, &q_params); @@ -211,8 +211,8 @@ fn test_blocking_delete_a_dynamic_amqp091_shovel() { let result1 = rc.create_vhost(&vh_params); assert!(result1.is_ok()); - let src_q = format!("{0}.src.q", sh); - let dest_q = format!("{0}.dest.q", sh); + let src_q = format!("{sh}.src.q"); + let dest_q = format!("{sh}.dest.q"); let amqp_endpoint = amqp_endpoint_with_vhost(vh); let shovel_params = Amqp091ShovelParams { diff --git a/tests/blocking_exchange_tests.rs b/tests/blocking_exchange_tests.rs index bfdc32f..c787983 100644 --- a/tests/blocking_exchange_tests.rs +++ b/tests/blocking_exchange_tests.rs @@ -133,5 +133,5 @@ fn test_blocking_list_exchanges_in_a_virtual_host() { let rc = Client::new(&endpoint, USERNAME, PASSWORD); let result1 = rc.list_exchanges_in("/"); - assert!(result1.is_ok(), "list_exchanges_in returned {:?}", result1); + assert!(result1.is_ok(), "list_exchanges_in returned {result1:?}"); } diff --git a/tests/blocking_leader_rebalancing_tests.rs b/tests/blocking_leader_rebalancing_tests.rs index 99ca892..0c3bbac 100644 --- a/tests/blocking_leader_rebalancing_tests.rs +++ b/tests/blocking_leader_rebalancing_tests.rs @@ -24,7 +24,6 @@ fn test_blocking_leader_rebalancing() { let result1 = rc.rebalance_queue_leaders(); assert!( result1.is_ok(), - "rebalance_queue_leaders returned {:?}", - result1 + "rebalance_queue_leaders returned {result1:?}" ); } diff --git a/tests/blocking_message_tests.rs b/tests/blocking_message_tests.rs index b89f800..b43693b 100644 --- a/tests/blocking_message_tests.rs +++ b/tests/blocking_message_tests.rs @@ -32,7 +32,7 @@ fn test_blocking_publish_and_get() { let params = QueueParams::new_durable_classic_queue(queue, None); let result2 = rc.declare_queue(vhost, ¶ms); - assert!(result2.is_ok(), "declare_queue returned {:?}", result2); + assert!(result2.is_ok(), "declare_queue returned {result2:?}"); let result3 = rc.publish_message( vhost, @@ -41,17 +41,17 @@ fn test_blocking_publish_and_get() { "rust test 1", requests::MessageProperties::default(), ); - assert!(result3.is_ok(), "get_messages returned {:?}", result3); + assert!(result3.is_ok(), "get_messages returned {result3:?}"); assert_eq!(result3.unwrap(), MessageRouted { routed: true }); let mut props = Map::::new(); props.insert(String::from("timestamp"), json!(123456789)); let result4 = rc.publish_message(vhost, "", queue, "rust test 2", props.clone()); - assert!(result4.is_ok(), "get_messages returned {:?}", result4); + assert!(result4.is_ok(), "get_messages returned {result4:?}"); assert_eq!(result4.unwrap(), MessageRouted { routed: true }); let result5 = rc.get_messages(vhost, queue, 1, "ack_requeue_false"); - assert!(result5.is_ok(), "get_messages returned {:?}", result5); + assert!(result5.is_ok(), "get_messages returned {result5:?}"); let msg_list = result5.unwrap(); assert_eq!( @@ -69,7 +69,7 @@ fn test_blocking_publish_and_get() { ); let result7 = rc.get_messages(vhost, queue, 1, "ack_requeue_false"); - assert!(result7.is_ok(), "get_messages returned {:?}", result7); + assert!(result7.is_ok(), "get_messages returned {result7:?}"); let props = MessageProperties(props); let msg_list2 = result7.unwrap(); diff --git a/tests/blocking_overview_tests.rs b/tests/blocking_overview_tests.rs index 6578edc..c3764d0 100644 --- a/tests/blocking_overview_tests.rs +++ b/tests/blocking_overview_tests.rs @@ -22,7 +22,7 @@ fn test_blocking_overview() { let rc = Client::new(&endpoint, USERNAME, PASSWORD); let result1 = rc.overview(); - assert!(result1.is_ok(), "overview returned {:?}", result1); + assert!(result1.is_ok(), "overview returned {result1:?}"); let ov = result1.unwrap(); assert!(ov.object_totals.exchanges > 0); diff --git a/tests/blocking_permission_tests.rs b/tests/blocking_permission_tests.rs index 136956e..4348507 100644 --- a/tests/blocking_permission_tests.rs +++ b/tests/blocking_permission_tests.rs @@ -55,7 +55,7 @@ fn test_blocking_list_permissions_in() { assert!(result1.is_ok()); let result = rc.list_permissions_in("test_list_permissions_in"); - assert!(result.is_ok(), "list_permissions_in returned {:?}", result); + assert!(result.is_ok(), "list_permissions_in returned {result:?}"); let vec = result.unwrap(); assert!(vec.iter().any(|p| p @@ -81,7 +81,7 @@ fn test_blocking_list_permissions_of() { assert!(result1.is_ok()); let result = rc.list_permissions_of("guest"); - assert!(result.is_ok(), "list_permissions_of returned {:?}", result); + assert!(result.is_ok(), "list_permissions_of returned {result:?}"); let vec = result.unwrap(); assert!(vec.iter().any(|p| p @@ -109,8 +109,7 @@ fn test_blocking_get_permissions() { let result2 = rc.get_permissions("test_get_permissions", "guest"); assert!( result2.is_ok(), - "list_permissions_of returned {:?}", - result2 + "list_permissions_of returned {result2:?}" ); let result3 = result2.unwrap(); @@ -146,10 +145,10 @@ fn test_blocking_grant_permissions() { write: "write", }; let result = rc.declare_permissions(¶ms); - assert!(result.is_ok(), "declare_permissions returned {:?}", result); + assert!(result.is_ok(), "declare_permissions returned {result:?}"); let result2 = rc.get_permissions(vh_params.name, "guest"); - assert!(result2.is_ok(), "get_permissions_of returned {:?}", result2); + assert!(result2.is_ok(), "get_permissions_of returned {result2:?}"); let result3 = result2.unwrap(); assert_eq!( @@ -164,7 +163,7 @@ fn test_blocking_grant_permissions() { ); let result4 = rc.grant_permissions(vh_params.name, "guest"); - assert!(result4.is_ok(), "delete_permissions returned {:?}", result4); + assert!(result4.is_ok(), "delete_permissions returned {result4:?}"); let result5 = rc.get_permissions(vh_params.name, "guest"); assert!(result5.is_err(), "permissions found after deletion"); diff --git a/tests/blocking_policy_tests.rs b/tests/blocking_policy_tests.rs index c7a3b0a..46ccac3 100644 --- a/tests/blocking_policy_tests.rs +++ b/tests/blocking_policy_tests.rs @@ -108,7 +108,7 @@ fn test_a_policy(rc: &Client<&str, &str, &str>, policy: &PolicyParams) { assert!(!policies.iter().any(|p| p.name == policy.name)); let result = rc.declare_policy(policy); - assert!(result.is_ok(), "declare_policy returned {:?}", result); + assert!(result.is_ok(), "declare_policy returned {result:?}"); // validate it was created as expected let fetched_policy = rc.get_policy(policy.vhost, policy.name).unwrap(); @@ -128,7 +128,7 @@ fn test_an_operator_policy(rc: &Client<&str, &str, &str>, policy: &PolicyParams) assert!(!policies.iter().any(|p| p.name == policy.name)); let result = rc.declare_operator_policy(policy); - assert!(result.is_ok(), "declare_policy returned {:?}", result); + assert!(result.is_ok(), "declare_policy returned {result:?}"); // validate it was created as expected let fetched_policy = rc.get_operator_policy(policy.vhost, policy.name).unwrap(); diff --git a/tests/blocking_queue_tests.rs b/tests/blocking_queue_tests.rs index 5c5323c..4ffcb05 100644 --- a/tests/blocking_queue_tests.rs +++ b/tests/blocking_queue_tests.rs @@ -35,11 +35,11 @@ fn test_blocking_declare_and_redeclare_a_classic_queue() { let optional_args = Some(map); let params = QueueParams::new_durable_classic_queue(name, optional_args.clone()); let result2 = rc.declare_queue(vhost, ¶ms); - assert!(result2.is_ok(), "declare_queue returned {:?}", result2); + assert!(result2.is_ok(), "declare_queue returned {result2:?}"); let params2 = QueueParams::new(name, QueueType::Classic, true, false, optional_args.clone()); let result3 = rc.declare_queue(vhost, ¶ms2); - assert!(result3.is_ok(), "declare_queue returned {:?}", result3); + assert!(result3.is_ok(), "declare_queue returned {result3:?}"); let _ = rc.delete_queue(vhost, name, false); } @@ -61,7 +61,7 @@ fn test_blocking_declare_a_quorum_queue() { let optional_args = Some(map); let params = QueueParams::new_quorum_queue(name, optional_args); let result2 = rc.declare_queue(vhost, ¶ms); - assert!(result2.is_ok(), "declare_queue returned {:?}", result2); + assert!(result2.is_ok(), "declare_queue returned {result2:?}"); let _ = rc.delete_queue(vhost, name, false); } @@ -83,7 +83,7 @@ fn test_blocking_declare_a_stream_with_declare_queue() { let optional_args = Some(map); let params = QueueParams::new_stream(name, optional_args); let result2 = rc.declare_queue(vhost, ¶ms); - assert!(result2.is_ok(), "declare_queue returned {:?}", result2); + assert!(result2.is_ok(), "declare_queue returned {result2:?}"); let _ = rc.delete_queue(vhost, name, false); } @@ -102,7 +102,7 @@ fn test_blocking_delete_queue() { let params = QueueParams::new_durable_classic_queue(name, None); let result2 = rc.declare_queue(vhost, ¶ms); - assert!(result2.is_ok(), "declare_queue returned {:?}", result2); + assert!(result2.is_ok(), "declare_queue returned {result2:?}"); rc.delete_queue(vhost, name, false).unwrap(); let result3 = rc.get_queue_info(vhost, name); @@ -118,12 +118,12 @@ fn test_blocking_list_all_queues() { let params = QueueParams::new_durable_classic_queue("rust.tests.cq.23487866", None); let result1 = rc.declare_queue(vh_name, ¶ms); - assert!(result1.is_ok(), "declare_queue returned {:?}", result1); + assert!(result1.is_ok(), "declare_queue returned {result1:?}"); test_helpers::await_queue_metric_emission(); let result2 = rc.list_queues(); - assert!(result2.is_ok(), "list_queues returned {:?}", result2); + assert!(result2.is_ok(), "list_queues returned {result2:?}"); rc.delete_queue(vh_name, params.name, false).unwrap(); } @@ -137,12 +137,12 @@ fn test_blocking_list_queues_in_a_virtual_host() { let params = QueueParams::new_durable_classic_queue("rust.tests.cq.64692734867", None); let result1 = rc.declare_queue(vh_name, ¶ms); - assert!(result1.is_ok(), "declare_queue returned {:?}", result1); + assert!(result1.is_ok(), "declare_queue returned {result1:?}"); test_helpers::await_queue_metric_emission(); let result2 = rc.list_queues_in(vh_name); - assert!(result2.is_ok(), "list_queues_in returned {:?}", result2); + assert!(result2.is_ok(), "list_queues_in returned {result2:?}"); rc.delete_queue(vh_name, params.name, false).unwrap(); } diff --git a/tests/blocking_runtime_parameter_tests.rs b/tests/blocking_runtime_parameter_tests.rs index 3ef7769..387e33d 100644 --- a/tests/blocking_runtime_parameter_tests.rs +++ b/tests/blocking_runtime_parameter_tests.rs @@ -72,8 +72,7 @@ fn test_blocking_clear_runtime_parameter() { let result4 = rc.list_runtime_parameters(); assert!( result4.is_ok(), - "list_runtime_parameters returned {:?}", - result4 + "list_runtime_parameters returned {result4:?}" ); let vec = result4.unwrap(); assert!(!vec diff --git a/tests/blocking_stream_consumer_tests.rs b/tests/blocking_stream_consumer_tests.rs index d718be0..9cce499 100644 --- a/tests/blocking_stream_consumer_tests.rs +++ b/tests/blocking_stream_consumer_tests.rs @@ -24,8 +24,7 @@ fn test_blocking_list_stream_consumers() { let result1 = rc.list_stream_consumers(); assert!( result1.is_ok(), - "list_stream_publishers returned {:?}", - result1 + "list_stream_publishers returned {result1:?}" ); } @@ -38,7 +37,6 @@ fn test_blocking_list_virtual_host_stream_consumers() { let result1 = rc.list_stream_consumers_in(vh_name); assert!( result1.is_ok(), - "list_stream_publishers_in returned {:?}", - result1 + "list_stream_publishers_in returned {result1:?}" ); } diff --git a/tests/blocking_stream_publisher_tests.rs b/tests/blocking_stream_publisher_tests.rs index 1c8da60..72ea952 100644 --- a/tests/blocking_stream_publisher_tests.rs +++ b/tests/blocking_stream_publisher_tests.rs @@ -24,8 +24,7 @@ fn test_blocking_list_stream_publishers() { let result1 = rc.list_stream_publishers(); assert!( result1.is_ok(), - "list_stream_publishers returned {:?}", - result1 + "list_stream_publishers returned {result1:?}" ); } @@ -38,7 +37,6 @@ fn test_blocking_list_virtual_host_stream_publishers() { let result1 = rc.list_stream_publishers_in(vh_name); assert!( result1.is_ok(), - "list_stream_publishers_in returned {:?}", - result1 + "list_stream_publishers_in returned {result1:?}" ); } diff --git a/tests/blocking_stream_tests.rs b/tests/blocking_stream_tests.rs index 82c9505..cd1ae74 100644 --- a/tests/blocking_stream_tests.rs +++ b/tests/blocking_stream_tests.rs @@ -43,7 +43,7 @@ fn test_blocking_declare_stream() { }; let result2 = rc.declare_stream(vhost, ¶ms); - assert!(result2.is_ok(), "declare_stream returned {:?}", result2); + assert!(result2.is_ok(), "declare_stream returned {result2:?}"); let _ = rc.delete_stream(vhost, name, false); } @@ -63,7 +63,7 @@ fn test_blocking_delete_stream() { let params = StreamParams::new(name, "7D"); let result2 = rc.declare_stream(vhost, ¶ms); - assert!(result2.is_ok(), "declare_stream returned {:?}", result2); + assert!(result2.is_ok(), "declare_stream returned {result2:?}"); rc.delete_stream(vhost, name, false).unwrap(); let result3 = rc.get_stream_info(vhost, name); diff --git a/tests/blocking_user_tests.rs b/tests/blocking_user_tests.rs index 8b9f74f..5508e14 100644 --- a/tests/blocking_user_tests.rs +++ b/tests/blocking_user_tests.rs @@ -33,7 +33,7 @@ fn test_blocking_list_users_without_permissions() { let rc = Client::new(&endpoint, USERNAME, PASSWORD); let test_name = "test_blocking_list_users_without_permissions"; - let username = format!("{}.1", test_name); + let username = format!("{test_name}.1"); rc.delete_user(&username, true) .expect("failed to delete a user"); diff --git a/tests/test_helpers.rs b/tests/test_helpers.rs index 00cfa55..f25ba77 100644 --- a/tests/test_helpers.rs +++ b/tests/test_helpers.rs @@ -48,11 +48,11 @@ pub fn amqp_endpoint() -> String { } pub fn amqp_endpoint_with_vhost(name: &str) -> String { - format!("{0}/{1}", AMQP_ENDPOINT, name).to_owned() + format!("{AMQP_ENDPOINT}/{name}").to_owned() } pub fn amqp10_endpoint_with_vhost(name: &str) -> String { - format!("{0}?hostname='vhost:{1}'", AMQP_ENDPOINT, name).to_owned() + format!("{AMQP_ENDPOINT}?hostname='vhost:{name}'").to_owned() } // From 58a8b026d0862a8b9402848bf2ef8f5172f18e25 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Sat, 28 Jun 2025 17:25:48 +0400 Subject: [PATCH 03/47] Back to dev version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 89ff97a..0ea7fd0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rabbitmq_http_client" -version = "0.35.0" +version = "0.36.0" edition = "2021" description = "RabbitMQ HTTP API client" From 4b4bd04ef250d94584bc64ca8d8764b35945fb03 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 3 Jul 2025 10:00:17 +0300 Subject: [PATCH 04/47] cargo fmt --all --- tests/async_binding_tests.rs | 15 +++------------ tests/async_connection_tests.rs | 5 +---- tests/async_definitions_tests.rs | 20 ++++---------------- tests/async_permission_tests.rs | 5 +---- tests/blocking_binding_tests.rs | 15 +++------------ tests/blocking_connection_tests.rs | 5 +---- tests/blocking_definitions_tests.rs | 15 +++------------ tests/blocking_permission_tests.rs | 5 +---- 8 files changed, 17 insertions(+), 68 deletions(-) diff --git a/tests/async_binding_tests.rs b/tests/async_binding_tests.rs index ee49f8d..aa80fff 100644 --- a/tests/async_binding_tests.rs +++ b/tests/async_binding_tests.rs @@ -72,10 +72,7 @@ async fn test_async_list_only_queue_bindings() { assert!(result2.is_ok(), "bind_queue returned {result2:?}"); let result3 = rc.list_queue_bindings(vh_name, cq).await; - assert!( - result3.is_ok(), - "list_queue_bindings returned {result3:?}" - ); + assert!(result3.is_ok(), "list_queue_bindings returned {result3:?}"); let vec = result3.unwrap(); assert!(vec .iter() @@ -176,10 +173,7 @@ async fn test_async_delete_queue_bindings() { assert!(result2.is_ok(), "bind_queue returned {result2:?}"); let result3 = rc.list_queue_bindings(vh_name, cq).await; - assert!( - result3.is_ok(), - "list_queue_bindings returned {result3:?}" - ); + assert!(result3.is_ok(), "list_queue_bindings returned {result3:?}"); let vec = result3.unwrap(); assert!(vec .iter() @@ -202,10 +196,7 @@ async fn test_async_delete_queue_bindings() { assert!(result4.is_ok(), "delete_binding returned {result4:?}"); let result5 = rc.list_queue_bindings(vh_name, cq).await; - assert!( - result5.is_ok(), - "list_queue_bindings returned {result5:?}" - ); + assert!(result5.is_ok(), "list_queue_bindings returned {result5:?}"); let vec = result5.unwrap(); assert!(!vec .iter() diff --git a/tests/async_connection_tests.rs b/tests/async_connection_tests.rs index 14df2cd..a69a6ca 100644 --- a/tests/async_connection_tests.rs +++ b/tests/async_connection_tests.rs @@ -58,10 +58,7 @@ async fn test_async_list_virtual_host_connections() { rc.create_vhost(&vh_params).await.unwrap(); let result1 = rc.list_connections_in(vh).await; - assert!( - result1.is_ok(), - "list_connections_in returned {result1:?}" - ); + assert!(result1.is_ok(), "list_connections_in returned {result1:?}"); rc.delete_vhost(vh, true).await.unwrap(); } diff --git a/tests/async_definitions_tests.rs b/tests/async_definitions_tests.rs index ad66dfb..49cd448 100644 --- a/tests/async_definitions_tests.rs +++ b/tests/async_definitions_tests.rs @@ -108,10 +108,7 @@ async fn test_async_export_cluster_wide_definitions_as_data() { assert!(u_found, "expected to find user {} in definitions", "rust3"); let x_found = defs.exchanges.iter().any(|x| x.name == x_name); - assert!( - x_found, - "expected to find exchange {x_name} in definitions" - ); + assert!(x_found, "expected to find exchange {x_name} in definitions"); let qq_pol_found = defs.policies.iter().any(|p| p.name == qq_pol_name); assert!( @@ -194,10 +191,7 @@ async fn test_async_export_vhost_definitions_as_data() { ); let x_found = defs.exchanges.iter().any(|x| x.name == x_name); - assert!( - x_found, - "expected to find exchange {x_name} in definitions" - ); + assert!(x_found, "expected to find exchange {x_name} in definitions"); let qq_pol_found = defs.policies.iter().any(|p| p.name == qq_pol_name); assert!( @@ -240,10 +234,7 @@ async fn test_async_import_cluster_definitions() { ); let result1 = rc.get_queue_info("/", "imported_queue").await; - assert!( - result1.is_ok(), - "can't get the imported queue: {result1:?}" - ); + assert!(result1.is_ok(), "can't get the imported queue: {result1:?}"); } #[tokio::test] @@ -275,10 +266,7 @@ async fn test_async_import_vhost_definitions() { await_queue_metric_emission(); let result1 = rc.get_queue_info(vh, q).await; - assert!( - result1.is_ok(), - "can't get the imported queue: {result1:?}" - ); + assert!(result1.is_ok(), "can't get the imported queue: {result1:?}"); rc.delete_vhost(vh, true).await.unwrap(); } diff --git a/tests/async_permission_tests.rs b/tests/async_permission_tests.rs index 1321ac3..4ad1d9f 100644 --- a/tests/async_permission_tests.rs +++ b/tests/async_permission_tests.rs @@ -107,10 +107,7 @@ async fn test_async_get_permissions() { assert!(result1.is_ok()); let result2 = rc.get_permissions("test_get_permissions", "guest").await; - assert!( - result2.is_ok(), - "list_permissions_of returned {result2:?}" - ); + assert!(result2.is_ok(), "list_permissions_of returned {result2:?}"); let permissions = result2.unwrap(); assert_eq!( diff --git a/tests/blocking_binding_tests.rs b/tests/blocking_binding_tests.rs index 0bf9cdd..84f1fb1 100644 --- a/tests/blocking_binding_tests.rs +++ b/tests/blocking_binding_tests.rs @@ -68,10 +68,7 @@ fn test_blocking_list_only_queue_bindings() { assert!(result2.is_ok(), "bind_queue returned {result2:?}"); let result3 = rc.list_queue_bindings(vh_name, cq); - assert!( - result3.is_ok(), - "list_queue_bindings returned {result3:?}" - ); + assert!(result3.is_ok(), "list_queue_bindings returned {result3:?}"); let vec = result3.unwrap(); assert!(vec .iter() @@ -160,10 +157,7 @@ fn test_blocking_delete_queue_bindings() { assert!(result2.is_ok(), "bind_queue returned {result2:?}"); let result3 = rc.list_queue_bindings(vh_name, cq); - assert!( - result3.is_ok(), - "list_queue_bindings returned {result3:?}" - ); + assert!(result3.is_ok(), "list_queue_bindings returned {result3:?}"); let vec = result3.unwrap(); assert!(vec .iter() @@ -184,10 +178,7 @@ fn test_blocking_delete_queue_bindings() { assert!(result4.is_ok(), "delete_binding returned {result4:?}"); let result5 = rc.list_queue_bindings(vh_name, cq); - assert!( - result5.is_ok(), - "list_queue_bindings returned {result5:?}" - ); + assert!(result5.is_ok(), "list_queue_bindings returned {result5:?}"); let vec = result5.unwrap(); assert!(!vec .iter() diff --git a/tests/blocking_connection_tests.rs b/tests/blocking_connection_tests.rs index cd94599..3eb8264 100644 --- a/tests/blocking_connection_tests.rs +++ b/tests/blocking_connection_tests.rs @@ -50,10 +50,7 @@ fn test_blocking_list_virtual_host_connections() { rc.create_vhost(&vh_params).unwrap(); let result1 = rc.list_connections_in(vh); - assert!( - result1.is_ok(), - "list_connections_in returned {result1:?}" - ); + assert!(result1.is_ok(), "list_connections_in returned {result1:?}"); rc.delete_vhost(vh, true).unwrap(); } diff --git a/tests/blocking_definitions_tests.rs b/tests/blocking_definitions_tests.rs index 6c6c417..8c20d8b 100644 --- a/tests/blocking_definitions_tests.rs +++ b/tests/blocking_definitions_tests.rs @@ -101,10 +101,7 @@ fn test_blocking_export_cluster_wide_definitions_as_data() { assert!(u_found, "expected to find user {} in definitions", "rust3"); let x_found = defs.exchanges.iter().any(|x| x.name == x_name); - assert!( - x_found, - "expected to find exchange {x_name} in definitions" - ); + assert!(x_found, "expected to find exchange {x_name} in definitions"); let qq_pol_found = defs.policies.iter().any(|p| p.name == qq_pol_name); assert!( @@ -181,10 +178,7 @@ fn test_blocking_export_vhost_definitions_as_data() { ); let x_found = defs.exchanges.iter().any(|x| x.name == x_name); - assert!( - x_found, - "expected to find exchange {x_name} in definitions" - ); + assert!(x_found, "expected to find exchange {x_name} in definitions"); let qq_pol_found = defs.policies.iter().any(|p| p.name == qq_pol_name); assert!( @@ -266,10 +260,7 @@ fn test_blocking_import_vhost_definitions() { await_queue_metric_emission(); let result1 = rc.get_queue_info(vh, q); - assert!( - result1.is_ok(), - "can't get the imported queue: {result1:?}" - ); + assert!(result1.is_ok(), "can't get the imported queue: {result1:?}"); rc.delete_vhost(vh, true).unwrap(); } diff --git a/tests/blocking_permission_tests.rs b/tests/blocking_permission_tests.rs index 4348507..7b85232 100644 --- a/tests/blocking_permission_tests.rs +++ b/tests/blocking_permission_tests.rs @@ -107,10 +107,7 @@ fn test_blocking_get_permissions() { assert!(result1.is_ok()); let result2 = rc.get_permissions("test_get_permissions", "guest"); - assert!( - result2.is_ok(), - "list_permissions_of returned {result2:?}" - ); + assert!(result2.is_ok(), "list_permissions_of returned {result2:?}"); let result3 = result2.unwrap(); assert_eq!( From 457a4e40ee19f0a294467468cf207a1b382cb769 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 4 Jul 2025 12:39:28 -0400 Subject: [PATCH 05/47] Adapt responses::Connection for direct connections Direct connections in RabbitMQ are the connections that use the "direct" connectivity option in the Erlang AMQP 0-9-1 client, that is, rely on the Erlang distribution protocol over a net TCP connection. In practical terms, they are the local halves of shovels or federation links, whereas the remote parts use regular ("network") connections that open new TCP connections, like any AMQP 0-9-1 client would. Because direct connections are not necessarily backed by a network connection (imagine a shovel that uses a queue with a leader hosted on the very same node), they may or may not have certain fields that responses::Connection was expecting. This solution is more straightforward and less disruptive compared to using an enum that represents both connection types, and trying to implement Tabled for it. Closes #68. --- src/responses.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/responses.rs b/src/responses.rs index 2f22cca..b4e61dd 100644 --- a/src/responses.rs +++ b/src/responses.rs @@ -523,9 +523,11 @@ pub struct Connection { pub name: String, /// To what node the client is connected pub node: String, - /// Connection state - #[serde(default = "undefined")] - pub state: String, + /// Connection state. + /// Regular client connections (a.k.a. network connections) will usually + /// have this state, while direct AMQP 0-9-1 Erlang client connections won't. + #[cfg_attr(feature = "tabled", tabled(display = "display_option"))] + pub state: Option, /// What protocol the connection uses pub protocol: String, /// The name of the authenticated user @@ -535,16 +537,20 @@ pub struct Connection { pub connected_at: u64, /// The hostname used to connect. #[serde(rename(deserialize = "host"))] - pub server_hostname: String, + #[cfg_attr(feature = "tabled", tabled(display = "display_option"))] + pub server_hostname: Option, /// The port used to connect. #[serde(rename(deserialize = "port"))] - pub server_port: u32, + #[cfg_attr(feature = "tabled", tabled(display = "display_option"))] + pub server_port: Option, /// Client hostname. #[serde(rename(deserialize = "peer_host"))] - pub client_hostname: String, + #[cfg_attr(feature = "tabled", tabled(display = "display_option"))] + pub client_hostname: Option, /// Ephemeral client port. #[serde(rename(deserialize = "peer_port"))] - pub client_port: u32, + #[cfg_attr(feature = "tabled", tabled(display = "display_option"))] + pub client_port: Option, /// Maximum number of channels that can be opened on this connection. #[cfg_attr(feature = "tabled", tabled(display = "display_option"))] pub channel_max: Option, From 3907f0165b50b20d22902810726f387c8aec6c82 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 4 Jul 2025 12:51:58 -0400 Subject: [PATCH 06/47] Change log updates for #61, 0.36.0 --- CHANGELOG.md | 18 +++++++++++++++++- README.md | 8 ++++---- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad7b27b..439106f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,26 @@ # Rust Client for the RabbitMQ HTTP API Change Log -## v0.36.0 (in development) +## v0.37.0 (in development) No changes yet. +## v0.36.0 (Jul 4, 2025) + +### Enhancements + + * `response::Connection` now can represent direct connections, + a special kind of connections supported by the Erlang AMQP 0-9-1 client, + that shovels and federation links use when connecting to the local + node. + + GitHub issues: [rabbitmq/rabbitmqadmin-ng#68](https://github.com/rabbitmq/rabbitmqadmin-ng/issues/68), [#61](https://github.com/michaelklishin/rabbitmq-http-api-rs/pull/61) + + ## v0.35.0 (Jun 28, 2025) +### Enhancements + * `ClientCapabilities` fields now default to `false` when not provided in the API response. @@ -15,6 +29,8 @@ No changes yet. ## v0.34.0 (Jun 12, 2025) +### Upgrades + * `tabled` was upgraded to `0.20.0` diff --git a/README.md b/README.md index 47f3d84..195b11c 100644 --- a/README.md +++ b/README.md @@ -14,25 +14,25 @@ This library is relatively young, breaking API changes are possible. ### Blocking Client ```toml -rabbitmq_http_client = { version = "0.35.0", features = ["core", "blocking"] } +rabbitmq_http_client = { version = "0.36.0", features = ["core", "blocking"] } ``` ### Async Client ```toml -rabbitmq_http_client = { version = "0.35.0", features = ["core", "async"] } +rabbitmq_http_client = { version = "0.36.0", features = ["core", "async"] } ``` ### Blocking Client with Tabled Support ```toml -rabbitmq_http_client = { version = "0.35.0", features = ["core", "blocking", "tabled"] } +rabbitmq_http_client = { version = "0.36.0", features = ["core", "blocking", "tabled"] } ``` ### Async Client with Tabled Support ```toml -rabbitmq_http_client = { version = "0.35.0", features = ["core", "async", "tabled"] } +rabbitmq_http_client = { version = "0.36.0", features = ["core", "async", "tabled"] } ``` From 05a532b7d0c248e0aa15ff59606203802375c847 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 4 Jul 2025 12:59:25 -0400 Subject: [PATCH 07/47] Bump dev version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 0ea7fd0..12d920a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rabbitmq_http_client" -version = "0.36.0" +version = "0.37.0" edition = "2021" description = "RabbitMQ HTTP API client" From b703d45bb06b726355ecc6e0e42e64c0094191b4 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 10 Jul 2025 14:23:49 -0400 Subject: [PATCH 08/47] PolicyDefinitionOps => PolicyDefinitionAndXArgumentsOps because it now covers XArguments and more operations. --- src/responses.rs | 189 ++++++++++++++++-- src/transformers.rs | 2 +- ...er_definition_set_transformations_tests.rs | 2 +- tests/unit_policy_tests.rs | 31 ++- 4 files changed, 201 insertions(+), 23 deletions(-) diff --git a/src/responses.rs b/src/responses.rs index b4e61dd..b7b0e68 100644 --- a/src/responses.rs +++ b/src/responses.rs @@ -47,17 +47,58 @@ pub struct PluginList(pub Vec); pub struct XArguments(pub Map); impl XArguments { + pub const CMQ_KEYS: [&'static str; 6] = [ + "ha-mode", + "ha-params", + "ha-promote-on-shutdown", + "ha-promote-on-failure", + "ha-sync-mode", + "ha-sync-batch-size", + ]; + pub const QUORUM_QUEUE_INCOMPATIBLE_KEYS: [&'static str; 7] = [ + "ha-mode", + "ha-params", + "ha-promote-on-shutdown", + "ha-promote-on-failure", + "ha-sync-mode", + "ha-sync-batch-size", + "queue-mode", + ]; + pub fn get(&self, key: &str) -> Option<&serde_json::Value> { self.0.get(key) } - pub fn insert(&mut self, key: &str, value: serde_json::Value) -> Option { - self.0.insert(key.to_owned(), value) + pub fn len(&self) -> usize { + self.0.len() + } + + pub fn keys(&self) -> Vec { + self.0.keys().cloned().collect() + } + + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + pub fn insert(&mut self, key: String, value: serde_json::Value) -> Option { + self.0.insert(key, value) + } + + pub fn contains_key(&self, key: &str) -> bool { + self.0.contains_key(key) } pub fn remove(&mut self, key: &str) -> Option { self.0.remove(key) } + + pub fn merge(&mut self, other: &Self) { + let mut m: Map = self.0.clone(); + m.extend(other.0.clone()); + + self.0 = m; + } } #[derive(Debug, Deserialize, Clone)] @@ -870,11 +911,47 @@ impl QueueOps for QueueDefinition { } } +impl PolicyDefinitionAndXArgumentsOps for QueueDefinition { + fn contains_any_keys_of(&self, keys: Vec<&str>) -> bool { + self.arguments.keys().iter().any(|key| keys.contains(&key.as_str())) + } + + fn has_cmq_keys(&self) -> bool { + self.contains_any_keys_of(XArguments::CMQ_KEYS.to_vec()) + } + + fn has_quorum_queue_incompatible_keys(&self) -> bool { + self.contains_any_keys_of(XArguments::QUORUM_QUEUE_INCOMPATIBLE_KEYS.to_vec()) + } + + fn is_empty(&self) -> bool { + self.arguments.is_empty() + } + + fn without_keys(&self, keys: Vec<&str>) -> Self { + let mut new_args = self.arguments.clone(); + for key in keys { + new_args.0.remove(key); + } + let mut copy = self.clone(); + copy.arguments = new_args; + copy + } + + fn without_cmq_keys(&self) -> Self { + self.without_keys(XArguments::CMQ_KEYS.to_vec()) + } + + fn without_quorum_queue_incompatible_keys(&self) -> Self { + self.without_keys(XArguments::QUORUM_QUEUE_INCOMPATIBLE_KEYS.to_vec()) + } +} + impl QueueDefinition { pub fn update_queue_type(&mut self, typ: QueueType) -> &mut Self { self.arguments.remove(X_ARGUMENT_KEY_X_QUEUE_TYPE); self.arguments - .insert(X_ARGUMENT_KEY_X_QUEUE_TYPE, json!(typ)); + .insert(X_ARGUMENT_KEY_X_QUEUE_TYPE.to_owned(), json!(typ)); self } @@ -1072,14 +1149,20 @@ impl From for ClusterTags { } } -pub trait PolicyDefinitionOps { +pub trait PolicyDefinitionAndXArgumentsOps { + fn contains_any_keys_of(&self, keys: Vec<&str>) -> bool; + fn has_cmq_keys(&self) -> bool; + fn has_quorum_queue_incompatible_keys(&self) -> bool; + fn is_empty(&self) -> bool; fn without_keys(&self, keys: Vec<&str>) -> Self; fn without_cmq_keys(&self) -> Self; + + fn without_quorum_queue_incompatible_keys(&self) -> Self; } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -1094,6 +1177,15 @@ impl PolicyDefinition { "ha-sync-mode", "ha-sync-batch-size", ]; + pub const QUORUM_QUEUE_INCOMPATIBLE_KEYS: [&'static str; 7] = [ + "ha-mode", + "ha-params", + "ha-promote-on-shutdown", + "ha-promote-on-failure", + "ha-sync-mode", + "ha-sync-batch-size", + "queue-mode", + ]; pub fn len(&self) -> usize { match &self.0 { @@ -1149,13 +1241,20 @@ impl PolicyDefinition { } } -impl PolicyDefinitionOps for PolicyDefinition { +impl PolicyDefinitionAndXArgumentsOps for PolicyDefinition { fn has_cmq_keys(&self) -> bool { - match &self.0 { - None => false, - Some(m) => m - .keys() - .any(|k| PolicyDefinition::CMQ_KEYS.contains(&k.as_str())), + self.contains_any_keys_of(Self::CMQ_KEYS.to_vec()) + } + + fn has_quorum_queue_incompatible_keys(&self) -> bool { + self.contains_any_keys_of(Self::QUORUM_QUEUE_INCOMPATIBLE_KEYS.to_vec()) + } + + fn contains_any_keys_of(&self, keys: Vec<&str>) -> bool { + if let Some(ref map) = self.0 { + map.keys().any(|key| keys.contains(&key.as_str())) + } else { + false } } @@ -1179,7 +1278,11 @@ impl PolicyDefinitionOps for PolicyDefinition { } fn without_cmq_keys(&self) -> Self { - self.without_keys(Vec::from(PolicyDefinition::CMQ_KEYS)) + self.without_keys(PolicyDefinition::CMQ_KEYS.to_vec()) + } + + fn without_quorum_queue_incompatible_keys(&self) -> Self { + self.without_keys(PolicyDefinition::QUORUM_QUEUE_INCOMPATIBLE_KEYS.to_vec()) } } @@ -1290,11 +1393,19 @@ impl Policy { } } -impl PolicyDefinitionOps for Policy { +impl PolicyDefinitionAndXArgumentsOps for Policy { + fn contains_any_keys_of(&self, keys: Vec<&str>) -> bool { + self.definition.contains_any_keys_of(keys) + } + fn has_cmq_keys(&self) -> bool { self.definition.has_cmq_keys() } + fn has_quorum_queue_incompatible_keys(&self) -> bool { + self.definition.has_quorum_queue_incompatible_keys() + } + fn is_empty(&self) -> bool { self.definition.is_empty() } @@ -1313,13 +1424,11 @@ impl PolicyDefinitionOps for Policy { } fn without_cmq_keys(&self) -> Self { - self.without_keys(Vec::from(PolicyDefinition::CMQ_KEYS)) + self.without_keys(PolicyDefinition::CMQ_KEYS.to_vec()) } -} -impl PolicyWithoutVirtualHost { - pub fn does_match(&self, name: &str, typ: PolicyTarget) -> bool { - Policy::is_a_name_match(&self.pattern, self.apply_to.clone(), name, typ) + fn without_quorum_queue_incompatible_keys(&self) -> Self { + self.without_keys(PolicyDefinition::QUORUM_QUEUE_INCOMPATIBLE_KEYS.to_vec()) } } @@ -1338,6 +1447,50 @@ pub struct PolicyWithoutVirtualHost { pub definition: PolicyDefinition, } +impl PolicyWithoutVirtualHost { + pub fn does_match(&self, name: &str, typ: PolicyTarget) -> bool { + Policy::is_a_name_match(&self.pattern, self.apply_to.clone(), name, typ) + } +} + +impl PolicyDefinitionAndXArgumentsOps for PolicyWithoutVirtualHost { + fn contains_any_keys_of(&self, keys: Vec<&str>) -> bool { + self.definition.contains_any_keys_of(keys) + } + + fn has_cmq_keys(&self) -> bool { + self.definition.has_cmq_keys() + } + + fn has_quorum_queue_incompatible_keys(&self) -> bool { + self.definition.has_quorum_queue_incompatible_keys() + } + + fn is_empty(&self) -> bool { + self.definition.is_empty() + } + + fn without_keys(&self, keys: Vec<&str>) -> Self { + let defs = self.definition.without_keys(keys); + + Self { + name: self.name.clone(), + pattern: self.pattern.clone(), + apply_to: self.apply_to.clone(), + priority: self.priority, + definition: defs, + } + } + + fn without_cmq_keys(&self) -> Self { + self.without_keys(PolicyDefinition::CMQ_KEYS.to_vec()) + } + + fn without_quorum_queue_incompatible_keys(&self) -> Self { + self.without_keys(PolicyDefinition::QUORUM_QUEUE_INCOMPATIBLE_KEYS.to_vec()) + } +} + /// Represents an object a policy can match: a queue, a stream, an exchange. pub trait NamedPolicyTargetObject { fn vhost(&self) -> String; @@ -1464,7 +1617,7 @@ impl ClusterDefinitionSet { ) -> Option { if let Some(qd) = self.find_queue_mut(vhost, name) { let mut args = qd.arguments.clone(); - args.insert(X_ARGUMENT_KEY_X_QUEUE_TYPE, json!(typ.clone())); + args.insert(X_ARGUMENT_KEY_X_QUEUE_TYPE.to_owned(), json!(typ.clone())); qd.arguments = args; diff --git a/src/transformers.rs b/src/transformers.rs index 94e9fbd..1929342 100644 --- a/src/transformers.rs +++ b/src/transformers.rs @@ -15,7 +15,7 @@ use std::collections::HashMap; use crate::commons::QueueType; -use crate::responses::{ClusterDefinitionSet, Policy, PolicyDefinitionOps}; +use crate::responses::{ClusterDefinitionSet, Policy, PolicyDefinitionAndXArgumentsOps}; use crate::password_hashing; diff --git a/tests/unit_cluster_definition_set_transformations_tests.rs b/tests/unit_cluster_definition_set_transformations_tests.rs index bc2f8a3..18eb483 100644 --- a/tests/unit_cluster_definition_set_transformations_tests.rs +++ b/tests/unit_cluster_definition_set_transformations_tests.rs @@ -14,7 +14,7 @@ mod test_helpers; use rabbitmq_http_client::commons::{QueueType, X_ARGUMENT_KEY_X_QUEUE_TYPE}; -use rabbitmq_http_client::responses::{ClusterDefinitionSet, PolicyDefinitionOps}; +use rabbitmq_http_client::responses::{ClusterDefinitionSet, PolicyDefinitionAndXArgumentsOps}; use rabbitmq_http_client::transformers::{StripCmqKeysFromPolicies, TransformationChain}; use serde_json::json; diff --git a/tests/unit_policy_tests.rs b/tests/unit_policy_tests.rs index 318fa76..40b2cdf 100644 --- a/tests/unit_policy_tests.rs +++ b/tests/unit_policy_tests.rs @@ -14,7 +14,7 @@ mod test_helpers; use rabbitmq_http_client::commons::PolicyTarget; -use rabbitmq_http_client::responses::{Policy, PolicyDefinition, PolicyDefinitionOps}; +use rabbitmq_http_client::responses::{Policy, PolicyDefinition, PolicyDefinitionAndXArgumentsOps}; use serde_json::{json, Map}; #[test] @@ -143,19 +143,44 @@ fn test_unit_policy_definition_merge_case1() { fn test_unit_policy_definition_without_keys_case1() { let k1 = "max-age".to_owned(); let k2 = "max-length-bytes".to_owned(); + let k3 = "queue-mode".to_owned(); let mut m = Map::new(); m.insert(k1.clone(), json!("1D")); m.insert(k2.clone(), json!(20_000_000)); + m.insert(k3.clone(), json!("lazy")); let defs1 = PolicyDefinition(Some(m)); - let defs2 = defs1.without_keys(vec!["max-length-bytes"]); + let defs2 = defs1.without_keys(vec!["max-length-bytes", "queue-mode"]); - assert_eq!(2, defs1.len()); + assert_eq!(3, defs1.len()); assert_eq!(1, defs2.len()); let m2 = defs2.0.unwrap(); assert!(m2.contains_key(&k1)); assert!(!m2.contains_key(&k2)); + assert!(!m2.contains_key(&k3)); +} + +#[test] +fn test_unit_policy_definition_without_quorum_queue_incompatible_keys_case1() { + let k1 = "ha-mode".to_owned(); + let k2 = "max-length-bytes".to_owned(); + let k3 = "queue-mode".to_owned(); + + let mut m = Map::new(); + m.insert(k1.clone(), json!("all")); + m.insert(k2.clone(), json!(20_000_000)); + m.insert(k3.clone(), json!("lazy")); + let defs1 = PolicyDefinition(Some(m)); + let defs2 = defs1.without_quorum_queue_incompatible_keys(); + + assert_eq!(3, defs1.len()); + assert_eq!(1, defs2.len()); + + let m2 = defs2.0.unwrap(); + assert!(!m2.contains_key(&k1)); + assert!(m2.contains_key(&k2)); + assert!(!m2.contains_key(&k3)); } #[test] From 36492820d74e38e720e10ad2fc8075d60f07d55f Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 10 Jul 2025 14:28:47 -0400 Subject: [PATCH 09/47] PolicyDefinitionAndXArgumentsOps => OptionalArgumentSourceOps --- src/responses.rs | 15 +++++++++------ src/transformers.rs | 2 +- ...luster_definition_set_transformations_tests.rs | 2 +- tests/unit_policy_tests.rs | 2 +- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/responses.rs b/src/responses.rs index b7b0e68..d1b3547 100644 --- a/src/responses.rs +++ b/src/responses.rs @@ -911,9 +911,12 @@ impl QueueOps for QueueDefinition { } } -impl PolicyDefinitionAndXArgumentsOps for QueueDefinition { +impl OptionalArgumentSourceOps for QueueDefinition { fn contains_any_keys_of(&self, keys: Vec<&str>) -> bool { - self.arguments.keys().iter().any(|key| keys.contains(&key.as_str())) + self.arguments + .keys() + .iter() + .any(|key| keys.contains(&key.as_str())) } fn has_cmq_keys(&self) -> bool { @@ -1149,7 +1152,7 @@ impl From for ClusterTags { } } -pub trait PolicyDefinitionAndXArgumentsOps { +pub trait OptionalArgumentSourceOps { fn contains_any_keys_of(&self, keys: Vec<&str>) -> bool; fn has_cmq_keys(&self) -> bool; @@ -1241,7 +1244,7 @@ impl PolicyDefinition { } } -impl PolicyDefinitionAndXArgumentsOps for PolicyDefinition { +impl OptionalArgumentSourceOps for PolicyDefinition { fn has_cmq_keys(&self) -> bool { self.contains_any_keys_of(Self::CMQ_KEYS.to_vec()) } @@ -1393,7 +1396,7 @@ impl Policy { } } -impl PolicyDefinitionAndXArgumentsOps for Policy { +impl OptionalArgumentSourceOps for Policy { fn contains_any_keys_of(&self, keys: Vec<&str>) -> bool { self.definition.contains_any_keys_of(keys) } @@ -1453,7 +1456,7 @@ impl PolicyWithoutVirtualHost { } } -impl PolicyDefinitionAndXArgumentsOps for PolicyWithoutVirtualHost { +impl OptionalArgumentSourceOps for PolicyWithoutVirtualHost { fn contains_any_keys_of(&self, keys: Vec<&str>) -> bool { self.definition.contains_any_keys_of(keys) } diff --git a/src/transformers.rs b/src/transformers.rs index 1929342..ea2ea56 100644 --- a/src/transformers.rs +++ b/src/transformers.rs @@ -15,7 +15,7 @@ use std::collections::HashMap; use crate::commons::QueueType; -use crate::responses::{ClusterDefinitionSet, Policy, PolicyDefinitionAndXArgumentsOps}; +use crate::responses::{ClusterDefinitionSet, OptionalArgumentSourceOps, Policy}; use crate::password_hashing; diff --git a/tests/unit_cluster_definition_set_transformations_tests.rs b/tests/unit_cluster_definition_set_transformations_tests.rs index 18eb483..f252433 100644 --- a/tests/unit_cluster_definition_set_transformations_tests.rs +++ b/tests/unit_cluster_definition_set_transformations_tests.rs @@ -14,7 +14,7 @@ mod test_helpers; use rabbitmq_http_client::commons::{QueueType, X_ARGUMENT_KEY_X_QUEUE_TYPE}; -use rabbitmq_http_client::responses::{ClusterDefinitionSet, PolicyDefinitionAndXArgumentsOps}; +use rabbitmq_http_client::responses::{ClusterDefinitionSet, OptionalArgumentSourceOps}; use rabbitmq_http_client::transformers::{StripCmqKeysFromPolicies, TransformationChain}; use serde_json::json; diff --git a/tests/unit_policy_tests.rs b/tests/unit_policy_tests.rs index 40b2cdf..ca66363 100644 --- a/tests/unit_policy_tests.rs +++ b/tests/unit_policy_tests.rs @@ -14,7 +14,7 @@ mod test_helpers; use rabbitmq_http_client::commons::PolicyTarget; -use rabbitmq_http_client::responses::{Policy, PolicyDefinition, PolicyDefinitionAndXArgumentsOps}; +use rabbitmq_http_client::responses::{OptionalArgumentSourceOps, Policy, PolicyDefinition}; use serde_json::{json, Map}; #[test] From eb75c63b3f9dbbff6d454d458f84cf9f2edc1ef1 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 10 Jul 2025 14:30:20 -0400 Subject: [PATCH 10/47] Update change log --- CHANGELOG.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 439106f..355d31b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,14 @@ ## v0.37.0 (in development) -No changes yet. +### Breaking Changes + + * `responses::PolicyDefinitionOps` was extended and renamed to `responses::OptionalArgumentSourceOps` + +### Enhancements + + * `responses::OptionalArgumentSourceOps` now supports more operations on [optional queue arguments](https://www.rabbitmq.com/docs/queues#optional-arguments) + as well as `responses::PolicyDefinition` and `responses::Policy` ## v0.36.0 (Jul 4, 2025) From e61fe1301a93bfd28a15828a8a00cfa1de36fa0c Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 10 Jul 2025 14:33:14 -0400 Subject: [PATCH 11/47] The max-priority x-argument is not supported by quorum queues --- CHANGELOG.md | 2 +- src/responses.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 355d31b..ae78f36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ ### Enhancements * `responses::OptionalArgumentSourceOps` now supports more operations on [optional queue arguments](https://www.rabbitmq.com/docs/queues#optional-arguments) - as well as `responses::PolicyDefinition` and `responses::Policy` + of `responses::QueueDefinition` as well as policy definitions (`responses::PolicyDefinition`, `responses::Policy`) ## v0.36.0 (Jul 4, 2025) diff --git a/src/responses.rs b/src/responses.rs index d1b3547..1df4052 100644 --- a/src/responses.rs +++ b/src/responses.rs @@ -55,7 +55,7 @@ impl XArguments { "ha-sync-mode", "ha-sync-batch-size", ]; - pub const QUORUM_QUEUE_INCOMPATIBLE_KEYS: [&'static str; 7] = [ + pub const QUORUM_QUEUE_INCOMPATIBLE_KEYS: [&'static str; 8] = [ "ha-mode", "ha-params", "ha-promote-on-shutdown", @@ -63,6 +63,7 @@ impl XArguments { "ha-sync-mode", "ha-sync-batch-size", "queue-mode", + "max-priority" ]; pub fn get(&self, key: &str) -> Option<&serde_json::Value> { From 12525279c8418604f6b1291f76f4401aa9a9553f Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 11 Jul 2025 00:21:54 -0400 Subject: [PATCH 12/47] New DefinitionSetTransformer: PrepareForQuorumQueueMigration This one not only strips off the CMQ-related keys but also handles an incompatible overflow/x-overflow value and queue-mode/x-queue-mode, both not supported by quorum queues. --- src/commons.rs | 33 +++++++++ src/responses.rs | 103 ++++++++++++++++++++++----- src/transformers.rs | 63 +++++++++++++++- tests/unit_queue_definition_tests.rs | 48 +++++++++++++ 4 files changed, 228 insertions(+), 19 deletions(-) create mode 100644 tests/unit_queue_definition_tests.rs diff --git a/src/commons.rs b/src/commons.rs index 075eef1..a85095a 100644 --- a/src/commons.rs +++ b/src/commons.rs @@ -279,6 +279,7 @@ pub enum ExchangeType { } pub const X_ARGUMENT_KEY_X_QUEUE_TYPE: &str = "x-queue-type"; +pub const X_ARGUMENT_KEY_X_OVERFLOW: &str = "x-overflow"; pub const EXCHANGE_TYPE_FANOUT: &str = "fanout"; pub const EXCHANGE_TYPE_TOPIC: &str = "topic"; @@ -483,6 +484,38 @@ impl From for PolicyTarget { } } +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +#[serde(rename_all = "kebab-case")] +pub enum OverflowBehavior { + DropHead, + RejectPublish, + RejectPublishDlx, +} + +pub const OVERFLOW_REJECT_PUBLISH: &str = "reject-publish"; +pub const OVERFLOW_REJECT_PUBLISH_DLX: &str = "reject-publish-dlx"; +pub const OVERFLOW_DROP_HEAD: &str = "drop-head"; + +impl From for &str { + fn from(value: OverflowBehavior) -> Self { + match value { + OverflowBehavior::DropHead => OVERFLOW_DROP_HEAD, + OverflowBehavior::RejectPublish => OVERFLOW_REJECT_PUBLISH, + OverflowBehavior::RejectPublishDlx => OVERFLOW_REJECT_PUBLISH_DLX, + } + } +} + +impl From for String { + fn from(value: OverflowBehavior) -> Self { + match value { + OverflowBehavior::DropHead => OVERFLOW_DROP_HEAD.to_owned(), + OverflowBehavior::RejectPublish => OVERFLOW_REJECT_PUBLISH.to_owned(), + OverflowBehavior::RejectPublishDlx => OVERFLOW_REJECT_PUBLISH_DLX.to_owned(), + } + } +} + impl PolicyTarget { // Returns true if this policy target includes the target category. // For example, [`PolicyTarget::Queue`] matches [`PolicyTarget::ClassicQueues`], [`PolicyTarget::QuorumQueues`], diff --git a/src/responses.rs b/src/responses.rs index 1df4052..57cc0ad 100644 --- a/src/responses.rs +++ b/src/responses.rs @@ -14,8 +14,8 @@ use std::{fmt, ops}; use crate::commons::{ - BindingDestinationType, MessageTransferAcknowledgementMode, PolicyTarget, QueueType, - X_ARGUMENT_KEY_X_QUEUE_TYPE, + BindingDestinationType, MessageTransferAcknowledgementMode, OverflowBehavior, PolicyTarget, + QueueType, X_ARGUMENT_KEY_X_OVERFLOW, X_ARGUMENT_KEY_X_QUEUE_TYPE, }; use crate::error::ConversionError; use crate::formatting::*; @@ -48,22 +48,22 @@ pub struct XArguments(pub Map); impl XArguments { pub const CMQ_KEYS: [&'static str; 6] = [ - "ha-mode", - "ha-params", - "ha-promote-on-shutdown", - "ha-promote-on-failure", - "ha-sync-mode", - "ha-sync-batch-size", + "x-ha-mode", + "x-ha-params", + "x-ha-promote-on-shutdown", + "x-ha-promote-on-failure", + "x-ha-sync-mode", + "x-ha-sync-batch-size", ]; pub const QUORUM_QUEUE_INCOMPATIBLE_KEYS: [&'static str; 8] = [ - "ha-mode", - "ha-params", - "ha-promote-on-shutdown", - "ha-promote-on-failure", - "ha-sync-mode", - "ha-sync-batch-size", - "queue-mode", - "max-priority" + "x-ha-mode", + "x-ha-params", + "x-ha-promote-on-shutdown", + "x-ha-promote-on-failure", + "x-ha-sync-mode", + "x-ha-sync-batch-size", + "x-queue-mode", + "x-max-priority", ]; pub fn get(&self, key: &str) -> Option<&serde_json::Value> { @@ -959,6 +959,35 @@ impl QueueDefinition { self } + + pub fn compare_and_swap_string_argument( + &mut self, + argument: &str, + value: &str, + new_value: &str, + ) -> &mut Self { + if let Some(val) = self.arguments.get(argument) { + if let Some(s) = val.as_str() { + if s == value { + self.arguments.insert(argument.to_owned(), json!(new_value)); + } + } + } + + self + } + + pub fn compare_and_swap_overflow_argument( + &mut self, + value: OverflowBehavior, + new_value: OverflowBehavior, + ) -> &mut Self { + self.compare_and_swap_string_argument( + X_ARGUMENT_KEY_X_OVERFLOW, + value.into(), + new_value.into(), + ) + } } /// Used in virtual host-specific definitions. @@ -1202,6 +1231,10 @@ impl PolicyDefinition { self.len() == 0 } + pub fn get(&self, key: &str) -> Option<&serde_json::Value> { + self.0.as_ref()?.get(key) + } + pub fn insert(&mut self, key: String, value: serde_json::Value) -> Option { match self.0 { Some(ref mut m) => m.insert(key, value), @@ -1243,6 +1276,37 @@ impl PolicyDefinition { self.0 = merged; } + + pub fn compare_and_swap_string_argument( + &mut self, + argument: &str, + value: &str, + new_value: &str, + ) -> &mut Self { + if let Some(m) = &self.0 { + if let Some(raw_val) = m.get(argument) { + if let Some(s) = raw_val.as_str() { + if s == value { + self.insert(argument.to_owned(), json!(new_value)); + } + } + } + } + + self + } + + pub fn compare_and_swap_overflow_argument( + &mut self, + value: OverflowBehavior, + new_value: OverflowBehavior, + ) -> &mut Self { + self.compare_and_swap_string_argument( + X_ARGUMENT_KEY_X_OVERFLOW, + value.into(), + new_value.into(), + ) + } } impl OptionalArgumentSourceOps for PolicyDefinition { @@ -1650,6 +1714,13 @@ impl ClusterDefinitionSet { None } } + + pub fn update_queues(&mut self, f: TransformerFn) -> Vec { + let updated = self.queues.iter().map(|p| f(p.clone())).collect::>(); + self.queues = updated.clone(); + + updated.clone() + } } /// Represents definitions of a single virtual host. diff --git a/src/transformers.rs b/src/transformers.rs index ea2ea56..c984d03 100644 --- a/src/transformers.rs +++ b/src/transformers.rs @@ -12,11 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. +use crate::commons::{ + OverflowBehavior, QueueType, OVERFLOW_REJECT_PUBLISH, OVERFLOW_REJECT_PUBLISH_DLX, + X_ARGUMENT_KEY_X_OVERFLOW, +}; +use crate::responses::{ClusterDefinitionSet, OptionalArgumentSourceOps, Policy, QueueDefinition}; +use serde_json::json; use std::collections::HashMap; -use crate::commons::QueueType; -use crate::responses::{ClusterDefinitionSet, OptionalArgumentSourceOps, Policy}; - use crate::password_hashing; pub trait DefinitionSetTransformer { @@ -36,6 +39,57 @@ impl DefinitionSetTransformer for NoOp { } } +#[derive(Default, Debug)] +pub struct PrepareForQuorumQueueMigration {} + +impl DefinitionSetTransformer for PrepareForQuorumQueueMigration { + fn transform<'a>(&self, defs: &'a mut ClusterDefinitionSet) -> &'a mut ClusterDefinitionSet { + // remove CMQ-related keys policies + let f1 = Box::new(|p: Policy| p.without_cmq_keys()); + let matched_policies = defs.update_policies(f1); + + // for the queue matched by the above policies, inject an "x-queue-type" set to `QueueType::Quorum` + for mp in matched_policies { + defs.update_queue_type_of_matching(&mp, QueueType::Quorum) + } + + // remove other policy keys that are not supported by quorum queues + let f2 = Box::new(|p: Policy| p.without_quorum_queue_incompatible_keys()); + defs.update_policies(f2); + + // Queue x-arguments: + // replace x-overflow values that are equal to "reject-publish-dlx" + let f3 = Box::new(|mut qd: QueueDefinition| { + if let Some(val) = qd.arguments.get(X_ARGUMENT_KEY_X_OVERFLOW) { + if val.as_str().unwrap_or(OVERFLOW_REJECT_PUBLISH) == OVERFLOW_REJECT_PUBLISH_DLX { + qd.arguments.insert( + X_ARGUMENT_KEY_X_OVERFLOW.to_owned(), + json!(OverflowBehavior::RejectPublish), + ); + } + } + qd + }); + defs.update_queues(f3); + + // Policy definitions: + // replace x-overflow values that are equal to "reject-publish-dlx" + let f4 = Box::new(|mut p: Policy| { + let key = "overflow"; + if let Some(val) = p.definition.get(key) { + if val.as_str().unwrap_or(OVERFLOW_REJECT_PUBLISH) == OVERFLOW_REJECT_PUBLISH_DLX { + p.definition + .insert(key.to_owned(), json!(OverflowBehavior::RejectPublish)); + } + } + p + }); + defs.update_policies(f4); + + defs + } +} + #[derive(Default, Debug)] pub struct StripCmqKeysFromPolicies {} @@ -162,6 +216,9 @@ impl From> for TransformationChain { let mut vec: Vec> = Vec::new(); for name in names { match name { + "prepare_for_quorum_queue_migration" => { + vec.push(Box::new(PrepareForQuorumQueueMigration::default())); + } "strip_cmq_keys_from_policies" => { vec.push(Box::new(StripCmqKeysFromPolicies::default())); } diff --git a/tests/unit_queue_definition_tests.rs b/tests/unit_queue_definition_tests.rs new file mode 100644 index 0000000..1bbd1a5 --- /dev/null +++ b/tests/unit_queue_definition_tests.rs @@ -0,0 +1,48 @@ +// Copyright (C) 2023-2025 RabbitMQ Core Team (teamrabbitmq@gmail.com) +// +// Licensed 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. +mod test_helpers; + +use rabbitmq_http_client::responses::{ + NamedPolicyTargetObject, OptionalArgumentSourceOps, QueueDefinition, QueueOps, +}; + +#[test] +fn test_unit_queue_definition_without_quorum_queue_incompatible_keys_case1() { + let input = r#"{ + "name": "cq.1", + "vhost": "/", + "durable": true, + "auto_delete": false, + "arguments": { + "x-queue-type": "quorum", + "x-queue-mode": "lazy", + "x-max-priority": 11 + } + }"#; + let k1 = "x-queue-type".to_owned(); + let k2 = "x-queue-mode".to_owned(); + let k3 = "x-max-priority".to_owned(); + + let def1 = serde_json::from_str::(input).unwrap(); + + let def2 = def1.without_quorum_queue_incompatible_keys(); + + assert!(def1.arguments.contains_key(&k1)); + assert!(def1.arguments.contains_key(&k2)); + assert!(def1.arguments.contains_key(&k3)); + + assert!(def2.arguments.contains_key(&k1)); + assert!(!def2.arguments.contains_key(&k2)); + assert!(!def2.arguments.contains_key(&k3)); +} From 74d5fd8e4fe4f20f9784920635bfd3cad526eb21 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 11 Jul 2025 00:23:26 -0400 Subject: [PATCH 13/47] dbg spam --- tests/async_runtime_parameter_tests.rs | 1 - tests/unit_queue_definition_tests.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/async_runtime_parameter_tests.rs b/tests/async_runtime_parameter_tests.rs index 866a40b..69b3f28 100644 --- a/tests/async_runtime_parameter_tests.rs +++ b/tests/async_runtime_parameter_tests.rs @@ -74,7 +74,6 @@ async fn test_async_list_all_runtime_parameters() { assert!(result2.is_ok()); let result3 = rc.list_runtime_parameters().await; - dbg!(&result3); assert!(result3.is_ok()); assert!(result3 .unwrap() diff --git a/tests/unit_queue_definition_tests.rs b/tests/unit_queue_definition_tests.rs index 1bbd1a5..2339113 100644 --- a/tests/unit_queue_definition_tests.rs +++ b/tests/unit_queue_definition_tests.rs @@ -41,7 +41,7 @@ fn test_unit_queue_definition_without_quorum_queue_incompatible_keys_case1() { assert!(def1.arguments.contains_key(&k1)); assert!(def1.arguments.contains_key(&k2)); assert!(def1.arguments.contains_key(&k3)); - + assert!(def2.arguments.contains_key(&k1)); assert!(!def2.arguments.contains_key(&k2)); assert!(!def2.arguments.contains_key(&k3)); From 8a8406831579a5d54158291d816a878962cc78c7 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 11 Jul 2025 00:26:04 -0400 Subject: [PATCH 14/47] Update change log --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae78f36..c9d9492 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,13 @@ ### Enhancements + * New `DefinitionSetTransformer`: `PrepareForQuorumQueueMigration`. + + This one not only strips off the CMQ-related keys + but also handles an incompatible `"overflow"`/`"x-overflow"` key value + and `"queue-mode"`/`"x-queue-mode"` keys, both not supported + by quorum queues. + * `responses::OptionalArgumentSourceOps` now supports more operations on [optional queue arguments](https://www.rabbitmq.com/docs/queues#optional-arguments) of `responses::QueueDefinition` as well as policy definitions (`responses::PolicyDefinition`, `responses::Policy`) From 5b601edf629d741dce3aa9c70f53bd05a04559d0 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 11 Jul 2025 00:27:14 -0400 Subject: [PATCH 15/47] 0.37.0 --- CHANGELOG.md | 7 ++++++- README.md | 8 ++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9d9492..46e8983 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Rust Client for the RabbitMQ HTTP API Change Log -## v0.37.0 (in development) +## v0.38.0 (in development) + +No changes yet. + + +## v0.37.0 (Jul 11, 2025) ### Breaking Changes diff --git a/README.md b/README.md index 195b11c..25921ce 100644 --- a/README.md +++ b/README.md @@ -14,25 +14,25 @@ This library is relatively young, breaking API changes are possible. ### Blocking Client ```toml -rabbitmq_http_client = { version = "0.36.0", features = ["core", "blocking"] } +rabbitmq_http_client = { version = "0.37.0", features = ["core", "blocking"] } ``` ### Async Client ```toml -rabbitmq_http_client = { version = "0.36.0", features = ["core", "async"] } +rabbitmq_http_client = { version = "0.37.0", features = ["core", "async"] } ``` ### Blocking Client with Tabled Support ```toml -rabbitmq_http_client = { version = "0.36.0", features = ["core", "blocking", "tabled"] } +rabbitmq_http_client = { version = "0.37.0", features = ["core", "blocking", "tabled"] } ``` ### Async Client with Tabled Support ```toml -rabbitmq_http_client = { version = "0.36.0", features = ["core", "async", "tabled"] } +rabbitmq_http_client = { version = "0.37.0", features = ["core", "async", "tabled"] } ``` From 1cb2dde85115dce4620ddd0d3b69a20a20d1ee8c Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 11 Jul 2025 00:28:07 -0400 Subject: [PATCH 16/47] Bump dev version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 12d920a..a5c49a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rabbitmq_http_client" -version = "0.37.0" +version = "0.38.0" edition = "2021" description = "RabbitMQ HTTP API client" From 93175c8a653685d0266f22ac46d2547af106a8bf Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 11 Jul 2025 14:47:23 -0400 Subject: [PATCH 17/47] Support for SHA-512 digest/hashing of salted passwords --- src/password_hashing.rs | 100 ++++++++++++++++++++++++--- tests/blocking_user_tests.rs | 26 ++++++- tests/unit_queue_definition_tests.rs | 4 +- 3 files changed, 118 insertions(+), 12 deletions(-) diff --git a/src/password_hashing.rs b/src/password_hashing.rs index 4aaddbc..fdbb6d3 100644 --- a/src/password_hashing.rs +++ b/src/password_hashing.rs @@ -12,7 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. use rand::RngCore; -use ring::digest::{Context, SHA256}; +use ring::digest::{Context, SHA256, SHA512}; +use std::fmt; +use thiserror::Error; const SALT_LENGTH: usize = 4; @@ -32,14 +34,15 @@ pub fn salt() -> Vec { /// /// See the [Credentials and Passwords guide](https://rabbitmq.com/docs/passwords/). pub fn salted_password_hash_sha256(salt: &[u8], password: &str) -> Vec { - let mut ctx = Context::new(&SHA256); - let vec = [salt, password.as_bytes()].concat(); - - ctx.update(&vec); - let digest = ctx.finish(); - let digest_vec = Vec::from(digest.as_ref()); + salted_password_hash(salt, password, &SHA256) +} - [salt, &digest_vec[..]].concat() +/// Produces a SHA-512 hashed, salted password hash. +/// Prefer [`base64_encoded_salted_password_hash_sha512`]. +/// +/// See the [Credentials and Passwords guide](https://rabbitmq.com/docs/passwords/). +pub fn salted_password_hash_sha512(salt: &[u8], password: &str) -> Vec { + salted_password_hash(salt, password, &SHA512) } /// @@ -51,3 +54,84 @@ pub fn base64_encoded_salted_password_hash_sha256(salt: &[u8], password: &str) - let salted = salted_password_hash_sha256(salt, password); rbase64::encode(salted.as_slice()) } + +/// +/// Produces a Base64-encoded, SHA-512 hashed, salted password hash that can be passed +/// as [`crate::requests::UserParams::password_hash`] when adding a user with [`crate::blocking_api::Client::create_user`]. +/// +/// See the [Credentials and Passwords guide](https://rabbitmq.com/docs/passwords/). +pub fn base64_encoded_salted_password_hash_sha512(salt: &[u8], password: &str) -> String { + let salted = salted_password_hash_sha512(salt, password); + rbase64::encode(salted.as_slice()) +} + +#[derive(Clone, Default, PartialEq, Eq, Hash, Debug)] +pub enum HashingAlgorithm { + #[default] + SHA256, + SHA512, + // Unlike RabbitMQ that accepts module implementations via configuration, + // we cannot support salting and hashing for arbitrary algorithm names, + // so Other(String) is omitted by design +} + +impl fmt::Display for HashingAlgorithm { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + HashingAlgorithm::SHA256 => write!(f, "SHA-256"), + HashingAlgorithm::SHA512 => write!(f, "SHA-512"), + } + } +} + +impl From<&str> for HashingAlgorithm { + fn from(s: &str) -> Self { + match s.to_uppercase().as_str() { + "SHA256" => HashingAlgorithm::SHA256, + "SHA-256" => HashingAlgorithm::SHA256, + "SHA512" => HashingAlgorithm::SHA512, + "SHA-512" => HashingAlgorithm::SHA512, + _ => HashingAlgorithm::default(), + } + } +} + +impl From for HashingAlgorithm { + fn from(s: String) -> Self { + HashingAlgorithm::from(s.as_str()) + } +} + +#[derive(Error, Debug)] +pub enum HashingError { + #[error("Provided algorithm is not supported")] + UnsupportedAlgorithm, +} + +impl HashingAlgorithm { + pub fn salt_and_hash(&self, salt: &[u8], password: &str) -> Result, HashingError> { + match self { + HashingAlgorithm::SHA256 => Ok(salted_password_hash_sha256(salt, password)), + HashingAlgorithm::SHA512 => Ok(salted_password_hash_sha512(salt, password)), + } + } +} + +// +// Implementation +// + +fn salted_password_hash( + salt: &[u8], + password: &str, + algo: &'static ring::digest::Algorithm, +) -> Vec { + let mut ctx = Context::new(algo); + let vec = [salt, password.as_bytes()].concat(); + + ctx.update(&vec); + let digest = ctx.finish(); + let digest_vec = Vec::from(digest.as_ref()); + + [salt, &digest_vec[..]].concat() +} diff --git a/tests/blocking_user_tests.rs b/tests/blocking_user_tests.rs index 5508e14..3bfd562 100644 --- a/tests/blocking_user_tests.rs +++ b/tests/blocking_user_tests.rs @@ -71,7 +71,7 @@ fn test_blocking_get_user() { } #[test] -fn test_blocking_user_creation() { +fn test_blocking_user_creation_using_default_hashing_algorithm() { let endpoint = endpoint(); let rc = Client::new(&endpoint, USERNAME, PASSWORD); @@ -86,6 +86,30 @@ fn test_blocking_user_creation() { }; let result = rc.create_user(¶ms); assert!(result.is_ok()); + + rc.delete_user(¶ms.name, true) + .expect("failed to delete a user"); +} + +#[test] +fn test_blocking_user_creation_using_sha512() { + let endpoint = endpoint(); + let rc = Client::new(&endpoint, USERNAME, PASSWORD); + + let salt = password_hashing::salt(); + let password_hash = + password_hashing::base64_encoded_salted_password_hash_sha512(&salt, "rust4_t0p_sEkr37"); + + let params = UserParams { + name: "rust4", + password_hash: &password_hash, + tags: "management", + }; + let result = rc.create_user(¶ms); + assert!(result.is_ok()); + + rc.delete_user(¶ms.name, true) + .expect("failed to delete a user"); } #[test] diff --git a/tests/unit_queue_definition_tests.rs b/tests/unit_queue_definition_tests.rs index 2339113..e1b9852 100644 --- a/tests/unit_queue_definition_tests.rs +++ b/tests/unit_queue_definition_tests.rs @@ -13,9 +13,7 @@ // limitations under the License. mod test_helpers; -use rabbitmq_http_client::responses::{ - NamedPolicyTargetObject, OptionalArgumentSourceOps, QueueDefinition, QueueOps, -}; +use rabbitmq_http_client::responses::{OptionalArgumentSourceOps, QueueDefinition}; #[test] fn test_unit_queue_definition_without_quorum_queue_incompatible_keys_case1() { From da18d1571bbf7213b214a7ecdecb782b4f8d4a9f Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 11 Jul 2025 14:50:42 -0400 Subject: [PATCH 18/47] Change log update --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46e8983..dffe508 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,10 @@ ## v0.38.0 (in development) -No changes yet. +### Enhancements + + * Introduce `password_hashing::HashingAlgorithm` with two variants, SHA-256 and SHA-512 + * Support for SHA-512 hashing of salted passwords ## v0.37.0 (Jul 11, 2025) From f4e582ed17a83c5d7430c707f3ad2f7dc68b2cbc Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 11 Jul 2025 15:02:32 -0400 Subject: [PATCH 19/47] Make sure HashingAlgorithm#salt_and_hash base64-encoded the result --- src/password_hashing.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/password_hashing.rs b/src/password_hashing.rs index fdbb6d3..7dd6b04 100644 --- a/src/password_hashing.rs +++ b/src/password_hashing.rs @@ -29,7 +29,7 @@ pub fn salt() -> Vec { Vec::from(&buf) } -/// Produces a SHA-256 hashed, salted passowrd hash. +/// Produces a SHA-256 hashed, salted password hash. /// Prefer [`base64_encoded_salted_password_hash_sha256`]. /// /// See the [Credentials and Passwords guide](https://rabbitmq.com/docs/passwords/). @@ -110,10 +110,12 @@ pub enum HashingError { impl HashingAlgorithm { pub fn salt_and_hash(&self, salt: &[u8], password: &str) -> Result, HashingError> { - match self { - HashingAlgorithm::SHA256 => Ok(salted_password_hash_sha256(salt, password)), - HashingAlgorithm::SHA512 => Ok(salted_password_hash_sha512(salt, password)), - } + let hash = match self { + HashingAlgorithm::SHA256 => salted_password_hash_sha256(salt, password), + HashingAlgorithm::SHA512 => salted_password_hash_sha512(salt, password), + }; + let encoded = rbase64::encode(hash.as_slice()); + Ok(encoded.as_bytes().to_vec()) } } From 85b2800c2561d2f6658610be52291213ee20abdb Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 11 Jul 2025 15:06:23 -0400 Subject: [PATCH 20/47] 0.38.0 --- CHANGELOG.md | 7 ++++++- README.md | 8 ++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dffe508..c1e4550 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Rust Client for the RabbitMQ HTTP API Change Log -## v0.38.0 (in development) +## v0.39.0 (in development) + +No changes yet. + + +## v0.38.0 (Jul 11, 2025) ### Enhancements diff --git a/README.md b/README.md index 25921ce..d191c1e 100644 --- a/README.md +++ b/README.md @@ -14,25 +14,25 @@ This library is relatively young, breaking API changes are possible. ### Blocking Client ```toml -rabbitmq_http_client = { version = "0.37.0", features = ["core", "blocking"] } +rabbitmq_http_client = { version = "0.38.0", features = ["core", "blocking"] } ``` ### Async Client ```toml -rabbitmq_http_client = { version = "0.37.0", features = ["core", "async"] } +rabbitmq_http_client = { version = "0.38.0", features = ["core", "async"] } ``` ### Blocking Client with Tabled Support ```toml -rabbitmq_http_client = { version = "0.37.0", features = ["core", "blocking", "tabled"] } +rabbitmq_http_client = { version = "0.38.0", features = ["core", "blocking", "tabled"] } ``` ### Async Client with Tabled Support ```toml -rabbitmq_http_client = { version = "0.37.0", features = ["core", "async", "tabled"] } +rabbitmq_http_client = { version = "0.38.0", features = ["core", "async", "tabled"] } ``` From f4ac0c2f6c47d07020d774c8c1d2c5a067c358b7 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 11 Jul 2025 15:58:34 -0400 Subject: [PATCH 21/47] Bump dev version --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a5c49a7..46aadca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rabbitmq_http_client" -version = "0.38.0" -edition = "2021" +version = "0.39.0" +edition = "2024" description = "RabbitMQ HTTP API client" license = "MIT OR Apache-2.0" From c74a26b0e752c99202d39f38cfca08e179cc32a2 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 11 Jul 2025 15:58:41 -0400 Subject: [PATCH 22/47] cargo fmt --- src/api.rs | 9 +- src/blocking_api.rs | 9 +- src/error.rs | 6 +- src/requests.rs | 2 +- src/responses.rs | 4 +- src/transformers.rs | 2 +- tests/async_auth_configuration_tests.rs | 2 +- tests/async_binding_tests.rs | 121 ++++++++++-------- tests/async_channel_tests.rs | 2 +- tests/async_cluster_metadata_tests.rs | 4 +- tests/async_connection_tests.rs | 2 +- tests/async_consumer_tests.rs | 2 +- tests/async_definitions_tests.rs | 4 +- tests/async_deprecated_feature_tests.rs | 20 +-- tests/async_dynamic_shovel_tests.rs | 8 +- tests/async_exchange_tests.rs | 4 +- tests/async_feature_flag_tests.rs | 29 +++-- tests/async_health_checks_tests.rs | 2 +- tests/async_leader_rebalancing_tests.rs | 2 +- tests/async_message_tests.rs | 4 +- tests/async_node_memory_footprint_tests.rs | 2 +- tests/async_node_tests.rs | 2 +- tests/async_overview_tests.rs | 2 +- tests/async_permission_tests.rs | 2 +- tests/async_policy_tests.rs | 13 +- tests/async_queue_federation_tests.rs | 2 +- tests/async_queue_tests.rs | 4 +- tests/async_runtime_parameter_tests.rs | 37 +++--- tests/async_stream_consumer_tests.rs | 2 +- tests/async_stream_publisher_tests.rs | 2 +- tests/async_stream_tests.rs | 4 +- tests/async_user_limit_tests.rs | 30 +++-- tests/async_user_tests.rs | 2 +- tests/async_virtual_host_limit_tests.rs | 30 +++-- tests/async_virtual_host_tests.rs | 2 +- tests/blocking_auth_configuration_tests.rs | 2 +- tests/blocking_binding_tests.rs | 121 ++++++++++-------- tests/blocking_channel_tests.rs | 2 +- tests/blocking_cluster_metadata_tests.rs | 4 +- tests/blocking_connection_tests.rs | 2 +- tests/blocking_consumer_tests.rs | 2 +- tests/blocking_definitions_tests.rs | 4 +- tests/blocking_deprecated_feature_tests.rs | 20 +-- tests/blocking_dynamic_shovel_tests.rs | 8 +- tests/blocking_exchange_tests.rs | 4 +- tests/blocking_feature_flag_tests.rs | 29 +++-- tests/blocking_health_checks_tests.rs | 2 +- tests/blocking_leader_rebalancing_tests.rs | 2 +- tests/blocking_message_tests.rs | 4 +- tests/blocking_node_memory_footprint_tests.rs | 2 +- tests/blocking_node_tests.rs | 2 +- tests/blocking_overview_tests.rs | 2 +- tests/blocking_permission_tests.rs | 2 +- tests/blocking_policy_tests.rs | 4 +- tests/blocking_queue_federation_tests.rs | 2 +- tests/blocking_queue_tests.rs | 4 +- tests/blocking_runtime_parameter_tests.rs | 37 +++--- tests/blocking_stream_consumer_tests.rs | 2 +- tests/blocking_stream_publisher_tests.rs | 2 +- tests/blocking_stream_tests.rs | 4 +- tests/blocking_user_limit_tests.rs | 30 +++-- tests/blocking_user_tests.rs | 2 +- tests/blocking_virtual_host_limit_tests.rs | 30 +++-- tests/blocking_virtual_host_tests.rs | 2 +- tests/test_helpers.rs | 4 +- tests/unit_policy_tests.rs | 2 +- tests/unit_queue_tests.rs | 2 +- 67 files changed, 387 insertions(+), 328 deletions(-) diff --git a/src/api.rs b/src/api.rs index b6cb938..08432a3 100644 --- a/src/api.rs +++ b/src/api.rs @@ -16,9 +16,8 @@ use crate::error::Error; use crate::error::Error::{ClientErrorResponse, NotFound, ServerErrorResponse}; use crate::requests::{ - Amqp091ShovelParams, Amqp10ShovelParams, EmptyPayload, FederationUpstreamParams, - GlobalRuntimeParameterDefinition, StreamParams, FEDERATION_UPSTREAM_COMPONENT, - SHOVEL_COMPONENT, + Amqp10ShovelParams, Amqp091ShovelParams, EmptyPayload, FEDERATION_UPSTREAM_COMPONENT, + FederationUpstreamParams, GlobalRuntimeParameterDefinition, SHOVEL_COMPONENT, StreamParams, }; use crate::responses::{ ClusterTags, DeprecatedFeatureList, FeatureFlag, FeatureFlagList, FeatureFlagStability, @@ -36,11 +35,11 @@ use crate::{ }; use backtrace::Backtrace; use reqwest::{ - header::{HeaderMap, HeaderValue}, Client as HttpClient, StatusCode, + header::{HeaderMap, HeaderValue}, }; use serde::Serialize; -use serde_json::{json, Map, Value}; +use serde_json::{Map, Value, json}; use std::fmt; pub type HttpClientResponse = reqwest::Response; diff --git a/src/blocking_api.rs b/src/blocking_api.rs index 513e98a..5ae2820 100644 --- a/src/blocking_api.rs +++ b/src/blocking_api.rs @@ -16,9 +16,8 @@ use crate::error::Error; use crate::error::Error::{ClientErrorResponse, NotFound, ServerErrorResponse}; use crate::requests::{ - Amqp091ShovelParams, Amqp10ShovelParams, EmptyPayload, FederationUpstreamParams, - GlobalRuntimeParameterDefinition, StreamParams, FEDERATION_UPSTREAM_COMPONENT, - SHOVEL_COMPONENT, + Amqp10ShovelParams, Amqp091ShovelParams, EmptyPayload, FEDERATION_UPSTREAM_COMPONENT, + FederationUpstreamParams, GlobalRuntimeParameterDefinition, SHOVEL_COMPONENT, StreamParams, }; use crate::responses::{ ClusterTags, DeprecatedFeatureList, FeatureFlag, FeatureFlagList, FeatureFlagStability, @@ -36,12 +35,12 @@ use crate::{ }; use backtrace::Backtrace; use reqwest::{ + StatusCode, blocking::Client as HttpClient, header::{HeaderMap, HeaderValue}, - StatusCode, }; use serde::Serialize; -use serde_json::{json, Map, Value}; +use serde_json::{Map, Value, json}; use std::fmt; pub type HttpClientResponse = reqwest::blocking::Response; diff --git a/src/error.rs b/src/error.rs index 08d8eca..56d90c7 100644 --- a/src/error.rs +++ b/src/error.rs @@ -18,8 +18,8 @@ use thiserror::Error; use backtrace::Backtrace; use reqwest::{ - header::{HeaderMap, InvalidHeaderValue}, StatusCode, Url, + header::{HeaderMap, InvalidHeaderValue}, }; #[derive(Error, Debug)] @@ -56,7 +56,9 @@ pub enum Error { }, #[error("API responded with a 404 Not Found")] NotFound, - #[error("Cannot delete a binding: multiple matching bindings were found, provide additional properties")] + #[error( + "Cannot delete a binding: multiple matching bindings were found, provide additional properties" + )] MultipleMatchingBindings, #[error("could not convert provided value into an HTTP header value")] InvalidHeaderValue { error: InvalidHeaderValue }, diff --git a/src/requests.rs b/src/requests.rs index 479b16e..985af7a 100644 --- a/src/requests.rs +++ b/src/requests.rs @@ -15,7 +15,7 @@ use crate::commons::{ExchangeType, MessageTransferAcknowledgementMode, PolicyTar use crate::responses; use crate::responses::{Policy, PolicyDefinition as PolDef}; use serde::{Deserialize, Serialize}; -use serde_json::{json, Map, Value}; +use serde_json::{Map, Value, json}; /// Properties of a [virtual host](https://rabbitmq.com/docs/vhosts/) to be created or updated. #[derive(Serialize)] diff --git a/src/responses.rs b/src/responses.rs index 57cc0ad..ed00223 100644 --- a/src/responses.rs +++ b/src/responses.rs @@ -21,11 +21,11 @@ use crate::error::ConversionError; use crate::formatting::*; use crate::utils::{percentage, percentage_as_text}; use serde::{ - de::{MapAccess, Visitor}, Deserialize, Serialize, + de::{MapAccess, Visitor}, }; use serde_aux::prelude::*; -use serde_json::{json, Map}; +use serde_json::{Map, json}; use time::OffsetDateTime; diff --git a/src/transformers.rs b/src/transformers.rs index c984d03..8acdb52 100644 --- a/src/transformers.rs +++ b/src/transformers.rs @@ -13,7 +13,7 @@ // limitations under the License. use crate::commons::{ - OverflowBehavior, QueueType, OVERFLOW_REJECT_PUBLISH, OVERFLOW_REJECT_PUBLISH_DLX, + OVERFLOW_REJECT_PUBLISH, OVERFLOW_REJECT_PUBLISH_DLX, OverflowBehavior, QueueType, X_ARGUMENT_KEY_X_OVERFLOW, }; use crate::responses::{ClusterDefinitionSet, OptionalArgumentSourceOps, Policy, QueueDefinition}; diff --git a/tests/async_auth_configuration_tests.rs b/tests/async_auth_configuration_tests.rs index 19f2d3e..2c54532 100644 --- a/tests/async_auth_configuration_tests.rs +++ b/tests/async_auth_configuration_tests.rs @@ -14,7 +14,7 @@ use rabbitmq_http_client::api::Client; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; // // Authentication configuration info diff --git a/tests/async_binding_tests.rs b/tests/async_binding_tests.rs index aa80fff..ce8834e 100644 --- a/tests/async_binding_tests.rs +++ b/tests/async_binding_tests.rs @@ -18,7 +18,7 @@ use rabbitmq_http_client::{ }; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[tokio::test] async fn test_async_list_all_bindings() { @@ -40,16 +40,18 @@ async fn test_async_list_all_bindings() { let result3 = rc.list_bindings().await; assert!(result3.is_ok(), "list_bindings returned {result3:?}"); let vec = result3.unwrap(); - assert!(vec - .iter() - .any(|b| b.destination == cq && b.source == fanout)); + assert!( + vec.iter() + .any(|b| b.destination == cq && b.source == fanout) + ); let result4 = rc.list_bindings_in(vh_name).await; assert!(result4.is_ok(), "list_bindings_in returned {result4:?}"); let vec = result4.unwrap(); - assert!(vec - .iter() - .any(|vh| vh.vhost == vh_name && vh.source == fanout)); + assert!( + vec.iter() + .any(|vh| vh.vhost == vh_name && vh.source == fanout) + ); let _ = rc.delete_queue(vh_name, cq, false).await; } @@ -74,12 +76,13 @@ async fn test_async_list_only_queue_bindings() { let result3 = rc.list_queue_bindings(vh_name, cq).await; assert!(result3.is_ok(), "list_queue_bindings returned {result3:?}"); let vec = result3.unwrap(); - assert!(vec - .iter() - .any(|b| b.destination_type == BindingDestinationType::Queue - && b.vhost == vh_name - && b.destination == cq - && b.source == fanout)); + assert!( + vec.iter() + .any(|b| b.destination_type == BindingDestinationType::Queue + && b.vhost == vh_name + && b.destination == cq + && b.source == fanout) + ); let _ = rc.delete_queue(vh_name, cq, false).await; } @@ -123,15 +126,17 @@ async fn test_async_list_only_exchange_bindings() { "list_exchange_bindings_with_source returned {result5:?}" ); let vec = result5.unwrap(); - assert!(!vec - .iter() - .any(|b| b.destination_type == BindingDestinationType::Queue)); - assert!(vec - .iter() - .any(|b| b.destination_type == BindingDestinationType::Exchange - && b.vhost == vh_name - && b.destination == fanout1 - && b.source == fanout2)); + assert!( + !vec.iter() + .any(|b| b.destination_type == BindingDestinationType::Queue) + ); + assert!( + vec.iter() + .any(|b| b.destination_type == BindingDestinationType::Exchange + && b.vhost == vh_name + && b.destination == fanout1 + && b.source == fanout2) + ); let result6 = rc .list_exchange_bindings_with_destination(vh_name, fanout1) @@ -141,15 +146,17 @@ async fn test_async_list_only_exchange_bindings() { "list_exchange_bindings_with_destination returned {result6:?}" ); let vec = result6.unwrap(); - assert!(!vec - .iter() - .any(|b| b.destination_type == BindingDestinationType::Queue)); - assert!(vec - .iter() - .any(|b| b.destination_type == BindingDestinationType::Exchange - && b.vhost == vh_name - && b.destination == fanout1 - && b.source == fanout2)); + assert!( + !vec.iter() + .any(|b| b.destination_type == BindingDestinationType::Queue) + ); + assert!( + vec.iter() + .any(|b| b.destination_type == BindingDestinationType::Exchange + && b.vhost == vh_name + && b.destination == fanout1 + && b.source == fanout2) + ); let _ = rc.delete_queue(vh_name, cq, false).await; let _ = rc.delete_exchange(vh_name, fanout2, false).await; @@ -175,12 +182,13 @@ async fn test_async_delete_queue_bindings() { let result3 = rc.list_queue_bindings(vh_name, cq).await; assert!(result3.is_ok(), "list_queue_bindings returned {result3:?}"); let vec = result3.unwrap(); - assert!(vec - .iter() - .any(|b| b.destination_type == BindingDestinationType::Queue - && b.vhost == vh_name - && b.destination == cq - && b.source == fanout)); + assert!( + vec.iter() + .any(|b| b.destination_type == BindingDestinationType::Queue + && b.vhost == vh_name + && b.destination == cq + && b.source == fanout) + ); let m: serde_json::Map = serde_json::Map::new(); let result4 = rc @@ -198,12 +206,13 @@ async fn test_async_delete_queue_bindings() { let result5 = rc.list_queue_bindings(vh_name, cq).await; assert!(result5.is_ok(), "list_queue_bindings returned {result5:?}"); let vec = result5.unwrap(); - assert!(!vec - .iter() - .any(|b| b.destination_type == BindingDestinationType::Queue - && b.vhost == vh_name - && b.destination == cq - && b.source == fanout)); + assert!( + !vec.iter() + .any(|b| b.destination_type == BindingDestinationType::Queue + && b.vhost == vh_name + && b.destination == cq + && b.source == fanout) + ); let _ = rc.delete_queue(vh_name, cq, false).await; } @@ -230,12 +239,13 @@ async fn test_async_delete_exchange_bindings() { "list_exchange_bindings_with_destination returned {result3:?}" ); let vec = result3.unwrap(); - assert!(vec - .iter() - .any(|b| b.destination_type == BindingDestinationType::Exchange - && b.vhost == vh_name - && b.destination == direct - && b.source == fanout)); + assert!( + vec.iter() + .any(|b| b.destination_type == BindingDestinationType::Exchange + && b.vhost == vh_name + && b.destination == direct + && b.source == fanout) + ); let m: serde_json::Map = serde_json::Map::new(); let result4 = rc @@ -258,10 +268,11 @@ async fn test_async_delete_exchange_bindings() { "list_exchange_bindings_with_destination returned {result5:?}" ); let vec = result5.unwrap(); - assert!(!vec - .iter() - .any(|b| b.destination_type == BindingDestinationType::Exchange - && b.vhost == vh_name - && b.destination == direct - && b.source == fanout)); + assert!( + !vec.iter() + .any(|b| b.destination_type == BindingDestinationType::Exchange + && b.vhost == vh_name + && b.destination == direct + && b.source == fanout) + ); } diff --git a/tests/async_channel_tests.rs b/tests/async_channel_tests.rs index 1516749..f7b6170 100644 --- a/tests/async_channel_tests.rs +++ b/tests/async_channel_tests.rs @@ -15,7 +15,7 @@ use amqprs::connection::{Connection, OpenConnectionArguments}; use rabbitmq_http_client::api::Client; mod test_helpers; -use crate::test_helpers::{endpoint, hostname, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint, hostname}; #[tokio::test] async fn test_list_channels() { diff --git a/tests/async_cluster_metadata_tests.rs b/tests/async_cluster_metadata_tests.rs index b0d3b98..c7a4d9c 100644 --- a/tests/async_cluster_metadata_tests.rs +++ b/tests/async_cluster_metadata_tests.rs @@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. use rabbitmq_http_client::api::Client; -use serde_json::{json, Map, Value}; +use serde_json::{Map, Value, json}; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[tokio::test] async fn test_async_get_cluster_name() { diff --git a/tests/async_connection_tests.rs b/tests/async_connection_tests.rs index a69a6ca..23d0f24 100644 --- a/tests/async_connection_tests.rs +++ b/tests/async_connection_tests.rs @@ -17,7 +17,7 @@ use rabbitmq_http_client::api::Client; use rabbitmq_http_client::requests::VirtualHostParams; mod test_helpers; -use crate::test_helpers::{endpoint, hostname, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint, hostname}; #[tokio::test] async fn test_async_list_connections() { diff --git a/tests/async_consumer_tests.rs b/tests/async_consumer_tests.rs index 4bcbfda..78e46e4 100644 --- a/tests/async_consumer_tests.rs +++ b/tests/async_consumer_tests.rs @@ -14,7 +14,7 @@ use rabbitmq_http_client::{api::Client, requests::VirtualHostParams}; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[tokio::test] async fn test_async_list_consumers() { diff --git a/tests/async_definitions_tests.rs b/tests/async_definitions_tests.rs index 49cd448..be91bff 100644 --- a/tests/async_definitions_tests.rs +++ b/tests/async_definitions_tests.rs @@ -15,13 +15,13 @@ use rabbitmq_http_client::api::Client; mod test_helpers; use crate::test_helpers::{ - await_metric_emission, await_queue_metric_emission, endpoint, PASSWORD, USERNAME, + PASSWORD, USERNAME, await_metric_emission, await_queue_metric_emission, endpoint, }; use rabbitmq_http_client::commons::PolicyTarget; use rabbitmq_http_client::requests::{ ExchangeParams, PolicyParams, QueueParams, VirtualHostParams, }; -use serde_json::{json, Map, Value}; +use serde_json::{Map, Value, json}; #[tokio::test] async fn test_async_export_definitions_as_string() { diff --git a/tests/async_deprecated_feature_tests.rs b/tests/async_deprecated_feature_tests.rs index b38d5f2..ffb4212 100644 --- a/tests/async_deprecated_feature_tests.rs +++ b/tests/async_deprecated_feature_tests.rs @@ -15,7 +15,7 @@ use rabbitmq_http_client::responses::DeprecationPhase; use rabbitmq_http_client::{api::Client, commons::QueueType, requests::QueueParams}; mod test_helpers; -use crate::test_helpers::{async_testing_against_3_13_x, endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, async_testing_against_3_13_x, endpoint}; #[tokio::test] async fn test_async_list_all_deprecated_features() { @@ -25,10 +25,11 @@ async fn test_async_list_all_deprecated_features() { assert!(result.is_ok()); let vec = result.unwrap(); - assert!(vec - .0 - .into_iter() - .any(|df| df.deprecation_phase == DeprecationPhase::PermittedByDefault)); + assert!( + vec.0 + .into_iter() + .any(|df| df.deprecation_phase == DeprecationPhase::PermittedByDefault) + ); } #[tokio::test] @@ -51,10 +52,11 @@ async fn test_async_list_deprecated_features_in_use() { let result2 = rc.list_deprecated_features_in_use().await; assert!(result2.is_ok()); let vec = result2.unwrap(); - assert!(vec - .0 - .into_iter() - .any(|df| df.deprecation_phase == DeprecationPhase::PermittedByDefault)); + assert!( + vec.0 + .into_iter() + .any(|df| df.deprecation_phase == DeprecationPhase::PermittedByDefault) + ); rc.delete_queue(vh, q, true).await.unwrap(); } diff --git a/tests/async_dynamic_shovel_tests.rs b/tests/async_dynamic_shovel_tests.rs index 97bfdbf..84746b8 100644 --- a/tests/async_dynamic_shovel_tests.rs +++ b/tests/async_dynamic_shovel_tests.rs @@ -13,15 +13,15 @@ // limitations under the License. use rabbitmq_http_client::commons::MessageTransferAcknowledgementMode; use rabbitmq_http_client::requests::{ - Amqp091ShovelDestinationParams, Amqp091ShovelParams, Amqp091ShovelSourceParams, - Amqp10ShovelDestinationParams, Amqp10ShovelParams, Amqp10ShovelSourceParams, QueueParams, + Amqp10ShovelDestinationParams, Amqp10ShovelParams, Amqp10ShovelSourceParams, + Amqp091ShovelDestinationParams, Amqp091ShovelParams, Amqp091ShovelSourceParams, QueueParams, }; use rabbitmq_http_client::{api::Client, requests::VirtualHostParams}; mod test_helpers; use crate::test_helpers::{ - amqp10_endpoint_with_vhost, amqp_endpoint_with_vhost, async_testing_against_3_13_x, - await_metric_emission, endpoint, PASSWORD, USERNAME, + PASSWORD, USERNAME, amqp_endpoint_with_vhost, amqp10_endpoint_with_vhost, + async_testing_against_3_13_x, await_metric_emission, endpoint, }; #[tokio::test] diff --git a/tests/async_exchange_tests.rs b/tests/async_exchange_tests.rs index c82809a..5776411 100644 --- a/tests/async_exchange_tests.rs +++ b/tests/async_exchange_tests.rs @@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. use rabbitmq_http_client::{api::Client, error::Error as APIClientError, requests::ExchangeParams}; -use serde_json::{json, Map, Value}; +use serde_json::{Map, Value, json}; mod test_helpers; -use crate::test_helpers::{async_testing_against_3_13_x, endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, async_testing_against_3_13_x, endpoint}; use rabbitmq_http_client::commons::ExchangeType; diff --git a/tests/async_feature_flag_tests.rs b/tests/async_feature_flag_tests.rs index 9e8b013..5721e54 100644 --- a/tests/async_feature_flag_tests.rs +++ b/tests/async_feature_flag_tests.rs @@ -17,7 +17,7 @@ use rabbitmq_http_client::{ }; mod test_helpers; -use crate::test_helpers::{async_testing_against_3_13_x, endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, async_testing_against_3_13_x, endpoint}; #[tokio::test] async fn test_async_list_feature_flags() { @@ -31,10 +31,11 @@ async fn test_async_list_feature_flags() { let result = rc.list_feature_flags().await; assert!(result.is_ok()); let vec = result.unwrap(); - assert!(vec - .0 - .into_iter() - .any(|ff| ff.name == "rabbitmq_4.0.0" && ff.stability == FeatureFlagStability::Stable)); + assert!( + vec.0 + .into_iter() + .any(|ff| ff.name == "rabbitmq_4.0.0" && ff.stability == FeatureFlagStability::Stable) + ); } #[tokio::test] @@ -54,10 +55,11 @@ async fn test_async_enable_a_feature_flag() { assert!(result2.is_ok()); let vec = result2.unwrap(); - assert!(vec - .0 - .into_iter() - .any(|ff| ff.name == ff_name && ff.state == FeatureFlagState::Enabled)); + assert!( + vec.0 + .into_iter() + .any(|ff| ff.name == ff_name && ff.state == FeatureFlagState::Enabled) + ); } #[tokio::test] @@ -77,8 +79,9 @@ async fn test_async_enable_all_stable_feature_flags() { assert!(result2.is_ok()); let vec = result2.unwrap(); - assert!(vec - .0 - .into_iter() - .any(|ff| ff.name == ff_name && ff.state == FeatureFlagState::Enabled)); + assert!( + vec.0 + .into_iter() + .any(|ff| ff.name == ff_name && ff.state == FeatureFlagState::Enabled) + ); } diff --git a/tests/async_health_checks_tests.rs b/tests/async_health_checks_tests.rs index e47fcc8..bb7bbca 100644 --- a/tests/async_health_checks_tests.rs +++ b/tests/async_health_checks_tests.rs @@ -14,7 +14,7 @@ use rabbitmq_http_client::{api::Client, commons::SupportedProtocol}; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[tokio::test] async fn test_async_health_check_cluster_wide_alarms() { diff --git a/tests/async_leader_rebalancing_tests.rs b/tests/async_leader_rebalancing_tests.rs index 909f115..0ed8c21 100644 --- a/tests/async_leader_rebalancing_tests.rs +++ b/tests/async_leader_rebalancing_tests.rs @@ -14,7 +14,7 @@ use rabbitmq_http_client::api::Client; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[tokio::test] async fn test_async_leader_rebalancing() { diff --git a/tests/async_message_tests.rs b/tests/async_message_tests.rs index 28b5349..ef769b1 100644 --- a/tests/async_message_tests.rs +++ b/tests/async_message_tests.rs @@ -16,10 +16,10 @@ use rabbitmq_http_client::{ requests::{self, QueueParams}, responses::{GetMessage, MessageProperties, MessageRouted}, }; -use serde_json::{json, Map, Value}; +use serde_json::{Map, Value, json}; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[tokio::test] async fn test_async_publish_and_get() { diff --git a/tests/async_node_memory_footprint_tests.rs b/tests/async_node_memory_footprint_tests.rs index 0d1ac75..ba20aa2 100644 --- a/tests/async_node_memory_footprint_tests.rs +++ b/tests/async_node_memory_footprint_tests.rs @@ -14,7 +14,7 @@ use rabbitmq_http_client::api::Client; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; use regex::Regex; diff --git a/tests/async_node_tests.rs b/tests/async_node_tests.rs index 18e38d1..5509302 100644 --- a/tests/async_node_tests.rs +++ b/tests/async_node_tests.rs @@ -14,7 +14,7 @@ use rabbitmq_http_client::api::Client; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[tokio::test] async fn test_async_list_nodes() { diff --git a/tests/async_overview_tests.rs b/tests/async_overview_tests.rs index a4bf90a..4d50a76 100644 --- a/tests/async_overview_tests.rs +++ b/tests/async_overview_tests.rs @@ -15,7 +15,7 @@ use rabbitmq_http_client::api::Client; mod test_helpers; -use crate::test_helpers::{endpoint, generate_activity, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint, generate_activity}; #[tokio::test] async fn test_async_overview() { diff --git a/tests/async_permission_tests.rs b/tests/async_permission_tests.rs index 4ad1d9f..ffd9469 100644 --- a/tests/async_permission_tests.rs +++ b/tests/async_permission_tests.rs @@ -16,7 +16,7 @@ use rabbitmq_http_client::responses; use rabbitmq_http_client::{api::Client, requests::Permissions}; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[tokio::test] async fn test_async_list_permissions() { diff --git a/tests/async_policy_tests.rs b/tests/async_policy_tests.rs index f59398e..2654f05 100644 --- a/tests/async_policy_tests.rs +++ b/tests/async_policy_tests.rs @@ -17,9 +17,9 @@ use rabbitmq_http_client::{ requests::{PolicyParams, VirtualHostParams}, }; -use serde_json::{json, Map, Value}; +use serde_json::{Map, Value, json}; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[tokio::test] async fn test_async_message_ttl_policy() { @@ -138,10 +138,11 @@ async fn test_an_operator_policy(rc: &Client<&str, &str, &str>, policy: &PolicyP assert_eq!(fetched_policy.definition.0.unwrap(), policy.definition); // delete it - assert!(rc - .delete_operator_policy(policy.vhost, policy.name) - .await - .is_ok()); + assert!( + rc.delete_operator_policy(policy.vhost, policy.name) + .await + .is_ok() + ); // there should be no such policy anymore let policies = rc.list_operator_policies().await.unwrap(); diff --git a/tests/async_queue_federation_tests.rs b/tests/async_queue_federation_tests.rs index d17d70b..313efc3 100644 --- a/tests/async_queue_federation_tests.rs +++ b/tests/async_queue_federation_tests.rs @@ -15,7 +15,7 @@ use rabbitmq_http_client::requests::{FederationUpstreamParams, QueueFederationPa use rabbitmq_http_client::{api::Client, requests::VirtualHostParams}; mod test_helpers; -use crate::test_helpers::{amqp_endpoint_with_vhost, endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, amqp_endpoint_with_vhost, endpoint}; #[tokio::test] async fn test_async_declare_a_federation_upstream_with_queue_federation_parameters() { diff --git a/tests/async_queue_tests.rs b/tests/async_queue_tests.rs index 0aefe25..096aaf6 100644 --- a/tests/async_queue_tests.rs +++ b/tests/async_queue_tests.rs @@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. use rabbitmq_http_client::{api::Client, commons::QueueType, requests::QueueParams}; -use serde_json::{json, Map, Value}; +use serde_json::{Map, Value, json}; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[tokio::test] async fn test_async_declare_and_redeclare_a_classic_queue() { diff --git a/tests/async_runtime_parameter_tests.rs b/tests/async_runtime_parameter_tests.rs index 69b3f28..e5b57d9 100644 --- a/tests/async_runtime_parameter_tests.rs +++ b/tests/async_runtime_parameter_tests.rs @@ -16,11 +16,11 @@ use rabbitmq_http_client::requests::{ }; use rabbitmq_http_client::responses::RuntimeParameter; use rabbitmq_http_client::{api::Client, requests::VirtualHostParams}; -use serde_json::{json, Map, Value}; +use serde_json::{Map, Value, json}; mod test_helpers; use crate::test_helpers::{ - async_await_metric_emission, cluster_tags, endpoint, PASSWORD, USERNAME, + PASSWORD, USERNAME, async_await_metric_emission, cluster_tags, endpoint, }; #[tokio::test] @@ -75,12 +75,14 @@ async fn test_async_list_all_runtime_parameters() { let result3 = rc.list_runtime_parameters().await; assert!(result3.is_ok()); - assert!(result3 - .unwrap() - .iter() - .filter(|rp| rp.component == "vhost-limits" && rp.vhost == *vh_params.name) - .map(|rp| rp.value.get("max-connections").unwrap().as_u64().unwrap()) - .any(|n| n == 9988)); + assert!( + result3 + .unwrap() + .iter() + .filter(|rp| rp.component == "vhost-limits" && rp.vhost == *vh_params.name) + .map(|rp| rp.value.get("max-connections").unwrap().as_u64().unwrap()) + .any(|n| n == 9988) + ); let _ = rc .clear_runtime_parameter(rpf.component, rpf.vhost, rpf.name) @@ -108,11 +110,13 @@ async fn test_async_list_runtime_parameters_of_component_in_a_vhost() { .list_runtime_parameters_of_component_in("vhost-limits", vh_params.name) .await; assert!(result3.is_ok()); - assert!(result3 - .unwrap() - .iter() - .map(|rp| rp.value.get("max-connections").unwrap().as_u64().unwrap()) - .any(|n| n == 9988)); + assert!( + result3 + .unwrap() + .iter() + .map(|rp| rp.value.get("max-connections").unwrap().as_u64().unwrap()) + .any(|n| n == 9988) + ); let _ = rc .clear_runtime_parameter(rpf.component, rpf.vhost, rpf.name) @@ -146,9 +150,10 @@ async fn test_async_clear_runtime_parameter() { "list_runtime_parameters returned {result4:?}" ); let vec = result4.unwrap(); - assert!(!vec - .iter() - .any(|p| p.component == "vhost-limits" && p.vhost == *vh_params.name)); + assert!( + !vec.iter() + .any(|p| p.component == "vhost-limits" && p.vhost == *vh_params.name) + ); let _ = rc.delete_vhost(vh_params.name, false).await; } diff --git a/tests/async_stream_consumer_tests.rs b/tests/async_stream_consumer_tests.rs index f5a422d..49fb134 100644 --- a/tests/async_stream_consumer_tests.rs +++ b/tests/async_stream_consumer_tests.rs @@ -14,7 +14,7 @@ use rabbitmq_http_client::api::Client; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[tokio::test] async fn test_async_list_stream_consumers() { diff --git a/tests/async_stream_publisher_tests.rs b/tests/async_stream_publisher_tests.rs index 7958d86..d74f4c2 100644 --- a/tests/async_stream_publisher_tests.rs +++ b/tests/async_stream_publisher_tests.rs @@ -14,7 +14,7 @@ use rabbitmq_http_client::api::Client; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[tokio::test] async fn test_async_list_stream_publishers() { diff --git a/tests/async_stream_tests.rs b/tests/async_stream_tests.rs index a282a4d..6172bf0 100644 --- a/tests/async_stream_tests.rs +++ b/tests/async_stream_tests.rs @@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. use rabbitmq_http_client::{api::Client, requests::StreamParams}; -use serde_json::{json, Map, Value}; +use serde_json::{Map, Value, json}; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[tokio::test] async fn test_async_declare_stream() { diff --git a/tests/async_user_limit_tests.rs b/tests/async_user_limit_tests.rs index 8d5a075..a09a13c 100644 --- a/tests/async_user_limit_tests.rs +++ b/tests/async_user_limit_tests.rs @@ -19,7 +19,7 @@ use rabbitmq_http_client::{ }; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[tokio::test] async fn test_async_list_all_user_limits() { @@ -48,13 +48,15 @@ async fn test_async_list_all_user_limits() { assert!(vec.iter().any(|it| it.username == params.name)); let key1 = UserLimitTarget::MaxConnections; - assert!(!vec - .iter() - .any(|it| it.username == params.name && it.limits.get(key1.as_ref()).is_some())); + assert!( + !vec.iter() + .any(|it| it.username == params.name && it.limits.get(key1.as_ref()).is_some()) + ); let key2 = UserLimitTarget::MaxChannels; - assert!(vec - .iter() - .any(|it| it.username == params.name && it.limits.get(key2.as_ref()).is_some())); + assert!( + vec.iter() + .any(|it| it.username == params.name && it.limits.get(key2.as_ref()).is_some()) + ); rc.delete_user(params.name, false).await.unwrap(); } @@ -85,13 +87,15 @@ async fn test_async_list_user_limits() { let vec = result3.unwrap(); let key1 = UserLimitTarget::MaxChannels; - assert!(vec - .iter() - .any(|it| it.username == params.name && it.limits.get(key1.as_ref()).is_some())); + assert!( + vec.iter() + .any(|it| it.username == params.name && it.limits.get(key1.as_ref()).is_some()) + ); let key2 = UserLimitTarget::MaxConnections; - assert!(!vec - .iter() - .any(|it| it.username == params.name && it.limits.get(key2.as_ref()).is_some())); + assert!( + !vec.iter() + .any(|it| it.username == params.name && it.limits.get(key2.as_ref()).is_some()) + ); rc.delete_user(params.name, false).await.unwrap(); } diff --git a/tests/async_user_tests.rs b/tests/async_user_tests.rs index 5171261..1473d54 100644 --- a/tests/async_user_tests.rs +++ b/tests/async_user_tests.rs @@ -14,7 +14,7 @@ use rabbitmq_http_client::{api::Client, password_hashing, requests::UserParams}; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[tokio::test] async fn test_async_list_users() { diff --git a/tests/async_virtual_host_limit_tests.rs b/tests/async_virtual_host_limit_tests.rs index 5130b3a..21fbdda 100644 --- a/tests/async_virtual_host_limit_tests.rs +++ b/tests/async_virtual_host_limit_tests.rs @@ -18,7 +18,7 @@ use rabbitmq_http_client::{ }; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[tokio::test] async fn test_async_list_all_vhost_limits() { @@ -39,13 +39,15 @@ async fn test_async_list_all_vhost_limits() { assert!(vec.iter().any(|it| it.vhost == vh_params.name)); let key1 = VirtualHostLimitTarget::MaxConnections; - assert!(!vec - .iter() - .any(|it| it.vhost == vh_params.name && it.limits.get(key1.as_ref()).is_some())); + assert!( + !vec.iter() + .any(|it| it.vhost == vh_params.name && it.limits.get(key1.as_ref()).is_some()) + ); let key2 = VirtualHostLimitTarget::MaxQueues; - assert!(vec - .iter() - .any(|it| it.vhost == vh_params.name && it.limits.get(key2.as_ref()).is_some())); + assert!( + vec.iter() + .any(|it| it.vhost == vh_params.name && it.limits.get(key2.as_ref()).is_some()) + ); rc.delete_vhost(vh_params.name, false).await.unwrap(); } @@ -68,13 +70,15 @@ async fn test_async_list_vhost_limits() { let vec = result3.unwrap(); let key1 = VirtualHostLimitTarget::MaxConnections; - assert!(vec - .iter() - .any(|it| it.vhost == vh_params.name && it.limits.get(key1.as_ref()).is_some())); + assert!( + vec.iter() + .any(|it| it.vhost == vh_params.name && it.limits.get(key1.as_ref()).is_some()) + ); let key2 = VirtualHostLimitTarget::MaxQueues; - assert!(!vec - .iter() - .any(|it| it.vhost == vh_params.name && it.limits.get(key2.as_ref()).is_some())); + assert!( + !vec.iter() + .any(|it| it.vhost == vh_params.name && it.limits.get(key2.as_ref()).is_some()) + ); rc.delete_vhost(vh_params.name, false).await.unwrap(); } diff --git a/tests/async_virtual_host_tests.rs b/tests/async_virtual_host_tests.rs index 6e28639..b1c01ef 100644 --- a/tests/async_virtual_host_tests.rs +++ b/tests/async_virtual_host_tests.rs @@ -14,7 +14,7 @@ use rabbitmq_http_client::{api::Client, commons::QueueType, requests::VirtualHostParams}; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[tokio::test] async fn test_async_list_vhosts() { diff --git a/tests/blocking_auth_configuration_tests.rs b/tests/blocking_auth_configuration_tests.rs index 880ccca..b8bb137 100644 --- a/tests/blocking_auth_configuration_tests.rs +++ b/tests/blocking_auth_configuration_tests.rs @@ -14,7 +14,7 @@ use rabbitmq_http_client::blocking_api::Client; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; // // Authentication configuration info diff --git a/tests/blocking_binding_tests.rs b/tests/blocking_binding_tests.rs index 84f1fb1..c74b182 100644 --- a/tests/blocking_binding_tests.rs +++ b/tests/blocking_binding_tests.rs @@ -18,7 +18,7 @@ use rabbitmq_http_client::{ }; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[test] fn test_blocking_list_all_bindings() { @@ -38,16 +38,18 @@ fn test_blocking_list_all_bindings() { let result3 = rc.list_bindings(); assert!(result3.is_ok(), "list_bindings returned {result3:?}"); let vec = result3.unwrap(); - assert!(vec - .iter() - .any(|b| b.destination == cq && b.source == fanout)); + assert!( + vec.iter() + .any(|b| b.destination == cq && b.source == fanout) + ); let result4 = rc.list_bindings_in(vh_name); assert!(result4.is_ok(), "list_bindings_in returned {result4:?}"); let vec = result4.unwrap(); - assert!(vec - .iter() - .any(|vh| vh.vhost == vh_name && vh.source == fanout)); + assert!( + vec.iter() + .any(|vh| vh.vhost == vh_name && vh.source == fanout) + ); let _ = rc.delete_queue(vh_name, cq, false); } @@ -70,12 +72,13 @@ fn test_blocking_list_only_queue_bindings() { let result3 = rc.list_queue_bindings(vh_name, cq); assert!(result3.is_ok(), "list_queue_bindings returned {result3:?}"); let vec = result3.unwrap(); - assert!(vec - .iter() - .any(|b| b.destination_type == BindingDestinationType::Queue - && b.vhost == vh_name - && b.destination == cq - && b.source == fanout)); + assert!( + vec.iter() + .any(|b| b.destination_type == BindingDestinationType::Queue + && b.vhost == vh_name + && b.destination == cq + && b.source == fanout) + ); let _ = rc.delete_queue(vh_name, cq, false); } @@ -111,15 +114,17 @@ fn test_blocking_list_only_exchange_bindings() { "list_exchange_bindings_with_source returned {result5:?}" ); let vec = result5.unwrap(); - assert!(!vec - .iter() - .any(|b| b.destination_type == BindingDestinationType::Queue)); - assert!(vec - .iter() - .any(|b| b.destination_type == BindingDestinationType::Exchange - && b.vhost == vh_name - && b.destination == fanout1 - && b.source == fanout2)); + assert!( + !vec.iter() + .any(|b| b.destination_type == BindingDestinationType::Queue) + ); + assert!( + vec.iter() + .any(|b| b.destination_type == BindingDestinationType::Exchange + && b.vhost == vh_name + && b.destination == fanout1 + && b.source == fanout2) + ); let result6 = rc.list_exchange_bindings_with_destination(vh_name, fanout1); assert!( @@ -127,15 +132,17 @@ fn test_blocking_list_only_exchange_bindings() { "list_exchange_bindings_with_destination returned {result6:?}" ); let vec = result6.unwrap(); - assert!(!vec - .iter() - .any(|b| b.destination_type == BindingDestinationType::Queue)); - assert!(vec - .iter() - .any(|b| b.destination_type == BindingDestinationType::Exchange - && b.vhost == vh_name - && b.destination == fanout1 - && b.source == fanout2)); + assert!( + !vec.iter() + .any(|b| b.destination_type == BindingDestinationType::Queue) + ); + assert!( + vec.iter() + .any(|b| b.destination_type == BindingDestinationType::Exchange + && b.vhost == vh_name + && b.destination == fanout1 + && b.source == fanout2) + ); let _ = rc.delete_queue(vh_name, cq, false); let _ = rc.delete_exchange(vh_name, fanout2, false); @@ -159,12 +166,13 @@ fn test_blocking_delete_queue_bindings() { let result3 = rc.list_queue_bindings(vh_name, cq); assert!(result3.is_ok(), "list_queue_bindings returned {result3:?}"); let vec = result3.unwrap(); - assert!(vec - .iter() - .any(|b| b.destination_type == BindingDestinationType::Queue - && b.vhost == vh_name - && b.destination == cq - && b.source == fanout)); + assert!( + vec.iter() + .any(|b| b.destination_type == BindingDestinationType::Queue + && b.vhost == vh_name + && b.destination == cq + && b.source == fanout) + ); let m: serde_json::Map = serde_json::Map::new(); let result4 = rc.delete_binding( @@ -180,12 +188,13 @@ fn test_blocking_delete_queue_bindings() { let result5 = rc.list_queue_bindings(vh_name, cq); assert!(result5.is_ok(), "list_queue_bindings returned {result5:?}"); let vec = result5.unwrap(); - assert!(!vec - .iter() - .any(|b| b.destination_type == BindingDestinationType::Queue - && b.vhost == vh_name - && b.destination == cq - && b.source == fanout)); + assert!( + !vec.iter() + .any(|b| b.destination_type == BindingDestinationType::Queue + && b.vhost == vh_name + && b.destination == cq + && b.source == fanout) + ); let _ = rc.delete_queue(vh_name, cq, false); } @@ -208,12 +217,13 @@ fn test_blocking_delete_exchange_bindings() { "list_exchange_bindings_with_destination returned {result3:?}" ); let vec = result3.unwrap(); - assert!(vec - .iter() - .any(|b| b.destination_type == BindingDestinationType::Exchange - && b.vhost == vh_name - && b.destination == direct - && b.source == fanout)); + assert!( + vec.iter() + .any(|b| b.destination_type == BindingDestinationType::Exchange + && b.vhost == vh_name + && b.destination == direct + && b.source == fanout) + ); let m: serde_json::Map = serde_json::Map::new(); let result4 = rc.delete_binding( @@ -232,10 +242,11 @@ fn test_blocking_delete_exchange_bindings() { "list_exchange_bindings_with_destination returned {result5:?}" ); let vec = result5.unwrap(); - assert!(!vec - .iter() - .any(|b| b.destination_type == BindingDestinationType::Exchange - && b.vhost == vh_name - && b.destination == direct - && b.source == fanout)); + assert!( + !vec.iter() + .any(|b| b.destination_type == BindingDestinationType::Exchange + && b.vhost == vh_name + && b.destination == direct + && b.source == fanout) + ); } diff --git a/tests/blocking_channel_tests.rs b/tests/blocking_channel_tests.rs index ad74f14..715ce3e 100644 --- a/tests/blocking_channel_tests.rs +++ b/tests/blocking_channel_tests.rs @@ -14,7 +14,7 @@ use rabbitmq_http_client::blocking_api::Client; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[test] fn test_blocking_list_channels() { diff --git a/tests/blocking_cluster_metadata_tests.rs b/tests/blocking_cluster_metadata_tests.rs index 90f21a3..e545923 100644 --- a/tests/blocking_cluster_metadata_tests.rs +++ b/tests/blocking_cluster_metadata_tests.rs @@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. use rabbitmq_http_client::blocking_api::Client; -use serde_json::{json, Map, Value}; +use serde_json::{Map, Value, json}; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[test] fn test_blocking_get_cluster_name() { diff --git a/tests/blocking_connection_tests.rs b/tests/blocking_connection_tests.rs index 3eb8264..4687527 100644 --- a/tests/blocking_connection_tests.rs +++ b/tests/blocking_connection_tests.rs @@ -15,7 +15,7 @@ use rabbitmq_http_client::blocking_api::Client; use rabbitmq_http_client::requests::VirtualHostParams; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[test] fn test_blocking_list_connections() { diff --git a/tests/blocking_consumer_tests.rs b/tests/blocking_consumer_tests.rs index 5220493..bb2a1e7 100644 --- a/tests/blocking_consumer_tests.rs +++ b/tests/blocking_consumer_tests.rs @@ -14,7 +14,7 @@ use rabbitmq_http_client::{blocking_api::Client, requests::VirtualHostParams}; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[test] fn test_blocking_list_consumers() { diff --git a/tests/blocking_definitions_tests.rs b/tests/blocking_definitions_tests.rs index 8c20d8b..79b478e 100644 --- a/tests/blocking_definitions_tests.rs +++ b/tests/blocking_definitions_tests.rs @@ -15,13 +15,13 @@ use rabbitmq_http_client::blocking_api::Client; mod test_helpers; use crate::test_helpers::{ - await_metric_emission, await_queue_metric_emission, endpoint, PASSWORD, USERNAME, + PASSWORD, USERNAME, await_metric_emission, await_queue_metric_emission, endpoint, }; use rabbitmq_http_client::commons::PolicyTarget; use rabbitmq_http_client::requests::{ ExchangeParams, PolicyParams, QueueParams, VirtualHostParams, }; -use serde_json::{json, Map, Value}; +use serde_json::{Map, Value, json}; #[test] fn test_blocking_export_definitions_as_string() { diff --git a/tests/blocking_deprecated_feature_tests.rs b/tests/blocking_deprecated_feature_tests.rs index db70acb..4cef0a6 100644 --- a/tests/blocking_deprecated_feature_tests.rs +++ b/tests/blocking_deprecated_feature_tests.rs @@ -15,7 +15,7 @@ use rabbitmq_http_client::responses::DeprecationPhase; use rabbitmq_http_client::{blocking_api::Client, commons::QueueType, requests::QueueParams}; mod test_helpers; -use crate::test_helpers::{endpoint, testing_against_3_13_x, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint, testing_against_3_13_x}; #[test] fn test_blocking_list_all_deprecated_features() { @@ -25,10 +25,11 @@ fn test_blocking_list_all_deprecated_features() { assert!(result.is_ok()); let vec = result.unwrap(); - assert!(vec - .0 - .into_iter() - .any(|df| df.deprecation_phase == DeprecationPhase::PermittedByDefault)); + assert!( + vec.0 + .into_iter() + .any(|df| df.deprecation_phase == DeprecationPhase::PermittedByDefault) + ); } #[test] @@ -51,10 +52,11 @@ fn test_blocking_list_deprecated_features_in_use() { let result2 = rc.list_deprecated_features_in_use(); assert!(result2.is_ok()); let vec = result2.unwrap(); - assert!(vec - .0 - .into_iter() - .any(|df| df.deprecation_phase == DeprecationPhase::PermittedByDefault)); + assert!( + vec.0 + .into_iter() + .any(|df| df.deprecation_phase == DeprecationPhase::PermittedByDefault) + ); rc.delete_queue(vh, q, true).unwrap(); } diff --git a/tests/blocking_dynamic_shovel_tests.rs b/tests/blocking_dynamic_shovel_tests.rs index 88ce6c2..bbc7648 100644 --- a/tests/blocking_dynamic_shovel_tests.rs +++ b/tests/blocking_dynamic_shovel_tests.rs @@ -13,15 +13,15 @@ // limitations under the License. use rabbitmq_http_client::commons::MessageTransferAcknowledgementMode; use rabbitmq_http_client::requests::{ - Amqp091ShovelDestinationParams, Amqp091ShovelParams, Amqp091ShovelSourceParams, - Amqp10ShovelDestinationParams, Amqp10ShovelParams, Amqp10ShovelSourceParams, QueueParams, + Amqp10ShovelDestinationParams, Amqp10ShovelParams, Amqp10ShovelSourceParams, + Amqp091ShovelDestinationParams, Amqp091ShovelParams, Amqp091ShovelSourceParams, QueueParams, }; use rabbitmq_http_client::{blocking_api::Client, requests::VirtualHostParams}; mod test_helpers; use crate::test_helpers::{ - amqp10_endpoint_with_vhost, amqp_endpoint_with_vhost, await_metric_emission, endpoint, - testing_against_3_13_x, PASSWORD, USERNAME, + PASSWORD, USERNAME, amqp_endpoint_with_vhost, amqp10_endpoint_with_vhost, + await_metric_emission, endpoint, testing_against_3_13_x, }; #[test] diff --git a/tests/blocking_exchange_tests.rs b/tests/blocking_exchange_tests.rs index c787983..03d527a 100644 --- a/tests/blocking_exchange_tests.rs +++ b/tests/blocking_exchange_tests.rs @@ -14,10 +14,10 @@ use rabbitmq_http_client::{ blocking_api::Client, error::Error as APIClientError, requests::ExchangeParams, }; -use serde_json::{json, Map, Value}; +use serde_json::{Map, Value, json}; mod test_helpers; -use crate::test_helpers::{endpoint, testing_against_3_13_x, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint, testing_against_3_13_x}; use rabbitmq_http_client::commons::ExchangeType; diff --git a/tests/blocking_feature_flag_tests.rs b/tests/blocking_feature_flag_tests.rs index 9d92bd0..853eba5 100644 --- a/tests/blocking_feature_flag_tests.rs +++ b/tests/blocking_feature_flag_tests.rs @@ -17,7 +17,7 @@ use rabbitmq_http_client::{ }; mod test_helpers; -use crate::test_helpers::{endpoint, testing_against_3_13_x, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint, testing_against_3_13_x}; #[test] fn test_blocking_list_feature_flags() { @@ -31,10 +31,11 @@ fn test_blocking_list_feature_flags() { let result = rc.list_feature_flags(); assert!(result.is_ok()); let vec = result.unwrap(); - assert!(vec - .0 - .into_iter() - .any(|ff| ff.name == "rabbitmq_4.0.0" && ff.stability == FeatureFlagStability::Stable)); + assert!( + vec.0 + .into_iter() + .any(|ff| ff.name == "rabbitmq_4.0.0" && ff.stability == FeatureFlagStability::Stable) + ); } #[test] @@ -54,10 +55,11 @@ fn test_blocking_enable_a_feature_flag() { assert!(result2.is_ok()); let vec = result2.unwrap(); - assert!(vec - .0 - .into_iter() - .any(|ff| ff.name == ff_name && ff.state == FeatureFlagState::Enabled)); + assert!( + vec.0 + .into_iter() + .any(|ff| ff.name == ff_name && ff.state == FeatureFlagState::Enabled) + ); } #[test] @@ -77,8 +79,9 @@ fn test_blocking_enable_all_stable_feature_flags() { assert!(result2.is_ok()); let vec = result2.unwrap(); - assert!(vec - .0 - .into_iter() - .any(|ff| ff.name == ff_name && ff.state == FeatureFlagState::Enabled)); + assert!( + vec.0 + .into_iter() + .any(|ff| ff.name == ff_name && ff.state == FeatureFlagState::Enabled) + ); } diff --git a/tests/blocking_health_checks_tests.rs b/tests/blocking_health_checks_tests.rs index 3f3235a..ec648b8 100644 --- a/tests/blocking_health_checks_tests.rs +++ b/tests/blocking_health_checks_tests.rs @@ -14,7 +14,7 @@ use rabbitmq_http_client::{blocking_api::Client, commons::SupportedProtocol}; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[test] fn test_blocking_health_check_cluster_wide_alarms() { diff --git a/tests/blocking_leader_rebalancing_tests.rs b/tests/blocking_leader_rebalancing_tests.rs index 0c3bbac..b67ef60 100644 --- a/tests/blocking_leader_rebalancing_tests.rs +++ b/tests/blocking_leader_rebalancing_tests.rs @@ -14,7 +14,7 @@ use rabbitmq_http_client::blocking_api::Client; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[test] fn test_blocking_leader_rebalancing() { diff --git a/tests/blocking_message_tests.rs b/tests/blocking_message_tests.rs index b43693b..5c0bde5 100644 --- a/tests/blocking_message_tests.rs +++ b/tests/blocking_message_tests.rs @@ -16,10 +16,10 @@ use rabbitmq_http_client::{ requests::{self, QueueParams}, responses::{GetMessage, MessageProperties, MessageRouted}, }; -use serde_json::{json, Map, Value}; +use serde_json::{Map, Value, json}; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[test] fn test_blocking_publish_and_get() { diff --git a/tests/blocking_node_memory_footprint_tests.rs b/tests/blocking_node_memory_footprint_tests.rs index 87de85f..dac028e 100644 --- a/tests/blocking_node_memory_footprint_tests.rs +++ b/tests/blocking_node_memory_footprint_tests.rs @@ -14,7 +14,7 @@ use rabbitmq_http_client::blocking_api::Client; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; use regex::Regex; diff --git a/tests/blocking_node_tests.rs b/tests/blocking_node_tests.rs index c3c4a9c..21d18c3 100644 --- a/tests/blocking_node_tests.rs +++ b/tests/blocking_node_tests.rs @@ -14,7 +14,7 @@ use rabbitmq_http_client::blocking_api::Client; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[test] fn test_blocking_list_nodes() { diff --git a/tests/blocking_overview_tests.rs b/tests/blocking_overview_tests.rs index c3764d0..352e3d1 100644 --- a/tests/blocking_overview_tests.rs +++ b/tests/blocking_overview_tests.rs @@ -14,7 +14,7 @@ use rabbitmq_http_client::blocking_api::Client; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[test] fn test_blocking_overview() { diff --git a/tests/blocking_permission_tests.rs b/tests/blocking_permission_tests.rs index 7b85232..f6ab4c7 100644 --- a/tests/blocking_permission_tests.rs +++ b/tests/blocking_permission_tests.rs @@ -16,7 +16,7 @@ use rabbitmq_http_client::responses; use rabbitmq_http_client::{blocking_api::Client, requests::Permissions}; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[test] fn test_blocking_list_permissions() { diff --git a/tests/blocking_policy_tests.rs b/tests/blocking_policy_tests.rs index 46ccac3..4bbcdc5 100644 --- a/tests/blocking_policy_tests.rs +++ b/tests/blocking_policy_tests.rs @@ -17,9 +17,9 @@ use rabbitmq_http_client::{ requests::{PolicyParams, VirtualHostParams}, }; -use serde_json::{json, Map, Value}; +use serde_json::{Map, Value, json}; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[test] fn test_blocking_message_ttl_policy() { diff --git a/tests/blocking_queue_federation_tests.rs b/tests/blocking_queue_federation_tests.rs index b9970b2..0583f5f 100644 --- a/tests/blocking_queue_federation_tests.rs +++ b/tests/blocking_queue_federation_tests.rs @@ -15,7 +15,7 @@ use rabbitmq_http_client::requests::{FederationUpstreamParams, QueueFederationPa use rabbitmq_http_client::{blocking_api::Client, requests::VirtualHostParams}; mod test_helpers; -use crate::test_helpers::{amqp_endpoint_with_vhost, endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, amqp_endpoint_with_vhost, endpoint}; #[test] fn test_blocking_declare_a_federation_upstream_with_queue_federation_parameters() { diff --git a/tests/blocking_queue_tests.rs b/tests/blocking_queue_tests.rs index 4ffcb05..0649d09 100644 --- a/tests/blocking_queue_tests.rs +++ b/tests/blocking_queue_tests.rs @@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. use rabbitmq_http_client::{blocking_api::Client, commons::QueueType, requests::QueueParams}; -use serde_json::{json, Map, Value}; +use serde_json::{Map, Value, json}; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[test] fn test_blocking_declare_and_redeclare_a_classic_queue() { diff --git a/tests/blocking_runtime_parameter_tests.rs b/tests/blocking_runtime_parameter_tests.rs index 1018fe5..18a173b 100644 --- a/tests/blocking_runtime_parameter_tests.rs +++ b/tests/blocking_runtime_parameter_tests.rs @@ -14,10 +14,10 @@ use rabbitmq_http_client::requests::{RuntimeParameterDefinition, RuntimeParameterValue}; use rabbitmq_http_client::responses::RuntimeParameter; use rabbitmq_http_client::{blocking_api::Client, requests::VirtualHostParams}; -use serde_json::{json, Map, Value}; +use serde_json::{Map, Value, json}; mod test_helpers; -use crate::test_helpers::{await_metric_emission, endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, await_metric_emission, endpoint}; #[test] fn test_blocking_upsert_runtime_parameter() { @@ -68,12 +68,14 @@ fn test_blocking_list_all_runtime_parameters() { let result3 = rc.list_runtime_parameters(); assert!(result3.is_ok()); - assert!(result3 - .unwrap() - .iter() - .filter(|rp| rp.component == "vhost-limits" && rp.vhost == *vh_params.name) - .map(|rp| rp.value.get("max-connections").unwrap().as_u64().unwrap()) - .any(|n| n == 9988)); + assert!( + result3 + .unwrap() + .iter() + .filter(|rp| rp.component == "vhost-limits" && rp.vhost == *vh_params.name) + .map(|rp| rp.value.get("max-connections").unwrap().as_u64().unwrap()) + .any(|n| n == 9988) + ); let _ = rc.clear_runtime_parameter(rpf.component, rpf.vhost, rpf.name); let _ = rc.delete_vhost(vh_params.name, false); @@ -97,11 +99,13 @@ fn test_blocking_list_runtime_parameters_of_component_in_a_vhost() { let result3 = rc.list_runtime_parameters_of_component_in("vhost-limits", vh_params.name); assert!(result3.is_ok()); - assert!(result3 - .unwrap() - .iter() - .map(|rp| rp.value.get("max-connections").unwrap().as_u64().unwrap()) - .any(|n| n == 9988)); + assert!( + result3 + .unwrap() + .iter() + .map(|rp| rp.value.get("max-connections").unwrap().as_u64().unwrap()) + .any(|n| n == 9988) + ); let _ = rc.clear_runtime_parameter(rpf.component, rpf.vhost, rpf.name); let _ = rc.delete_vhost(vh_params.name, false); @@ -131,9 +135,10 @@ fn test_blocking_clear_runtime_parameter() { "list_runtime_parameters returned {result4:?}" ); let vec = result4.unwrap(); - assert!(!vec - .iter() - .any(|p| p.component == "vhost-limits" && p.vhost == *vh_params.name)); + assert!( + !vec.iter() + .any(|p| p.component == "vhost-limits" && p.vhost == *vh_params.name) + ); let _ = rc.delete_vhost(vh_params.name, false); } diff --git a/tests/blocking_stream_consumer_tests.rs b/tests/blocking_stream_consumer_tests.rs index 9cce499..a194da0 100644 --- a/tests/blocking_stream_consumer_tests.rs +++ b/tests/blocking_stream_consumer_tests.rs @@ -14,7 +14,7 @@ use rabbitmq_http_client::blocking_api::Client; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[test] fn test_blocking_list_stream_consumers() { diff --git a/tests/blocking_stream_publisher_tests.rs b/tests/blocking_stream_publisher_tests.rs index 72ea952..9941307 100644 --- a/tests/blocking_stream_publisher_tests.rs +++ b/tests/blocking_stream_publisher_tests.rs @@ -14,7 +14,7 @@ use rabbitmq_http_client::blocking_api::Client; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[test] fn test_blocking_list_stream_publishers() { diff --git a/tests/blocking_stream_tests.rs b/tests/blocking_stream_tests.rs index cd1ae74..3ec0c67 100644 --- a/tests/blocking_stream_tests.rs +++ b/tests/blocking_stream_tests.rs @@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. use rabbitmq_http_client::{blocking_api::Client, requests::StreamParams}; -use serde_json::{json, Map, Value}; +use serde_json::{Map, Value, json}; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[test] fn test_blocking_declare_stream() { diff --git a/tests/blocking_user_limit_tests.rs b/tests/blocking_user_limit_tests.rs index 2e44577..0314458 100644 --- a/tests/blocking_user_limit_tests.rs +++ b/tests/blocking_user_limit_tests.rs @@ -19,7 +19,7 @@ use rabbitmq_http_client::{ }; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[test] fn test_blocking_list_all_user_limits() { @@ -48,13 +48,15 @@ fn test_blocking_list_all_user_limits() { assert!(vec.iter().any(|it| it.username == params.name)); let key1 = UserLimitTarget::MaxConnections; - assert!(!vec - .iter() - .any(|it| it.username == params.name && it.limits.get(key1.as_ref()).is_some())); + assert!( + !vec.iter() + .any(|it| it.username == params.name && it.limits.get(key1.as_ref()).is_some()) + ); let key2 = UserLimitTarget::MaxChannels; - assert!(vec - .iter() - .any(|it| it.username == params.name && it.limits.get(key2.as_ref()).is_some())); + assert!( + vec.iter() + .any(|it| it.username == params.name && it.limits.get(key2.as_ref()).is_some()) + ); rc.delete_user(params.name, false).unwrap(); } @@ -85,13 +87,15 @@ fn test_blocking_list_user_limits() { let vec = result3.unwrap(); let key1 = UserLimitTarget::MaxChannels; - assert!(vec - .iter() - .any(|it| it.username == params.name && it.limits.get(key1.as_ref()).is_some())); + assert!( + vec.iter() + .any(|it| it.username == params.name && it.limits.get(key1.as_ref()).is_some()) + ); let key2 = UserLimitTarget::MaxConnections; - assert!(!vec - .iter() - .any(|it| it.username == params.name && it.limits.get(key2.as_ref()).is_some())); + assert!( + !vec.iter() + .any(|it| it.username == params.name && it.limits.get(key2.as_ref()).is_some()) + ); rc.delete_user(params.name, false).unwrap(); } diff --git a/tests/blocking_user_tests.rs b/tests/blocking_user_tests.rs index 3bfd562..0179685 100644 --- a/tests/blocking_user_tests.rs +++ b/tests/blocking_user_tests.rs @@ -14,7 +14,7 @@ use rabbitmq_http_client::{blocking_api::Client, password_hashing, requests::UserParams}; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[test] fn test_blocking_list_users() { diff --git a/tests/blocking_virtual_host_limit_tests.rs b/tests/blocking_virtual_host_limit_tests.rs index acf9918..25a77e8 100644 --- a/tests/blocking_virtual_host_limit_tests.rs +++ b/tests/blocking_virtual_host_limit_tests.rs @@ -18,7 +18,7 @@ use rabbitmq_http_client::{ }; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[test] fn test_blocking_list_all_vhost_limits() { @@ -39,13 +39,15 @@ fn test_blocking_list_all_vhost_limits() { assert!(vec.iter().any(|it| it.vhost == vh_params.name)); let key1 = VirtualHostLimitTarget::MaxConnections; - assert!(!vec - .iter() - .any(|it| it.vhost == vh_params.name && it.limits.get(key1.as_ref()).is_some())); + assert!( + !vec.iter() + .any(|it| it.vhost == vh_params.name && it.limits.get(key1.as_ref()).is_some()) + ); let key2 = VirtualHostLimitTarget::MaxQueues; - assert!(vec - .iter() - .any(|it| it.vhost == vh_params.name && it.limits.get(key2.as_ref()).is_some())); + assert!( + vec.iter() + .any(|it| it.vhost == vh_params.name && it.limits.get(key2.as_ref()).is_some()) + ); rc.delete_vhost(vh_params.name, false).unwrap(); } @@ -68,13 +70,15 @@ fn test_blocking_list_vhost_limits() { let vec = result3.unwrap(); let key1 = VirtualHostLimitTarget::MaxConnections; - assert!(vec - .iter() - .any(|it| it.vhost == vh_params.name && it.limits.get(key1.as_ref()).is_some())); + assert!( + vec.iter() + .any(|it| it.vhost == vh_params.name && it.limits.get(key1.as_ref()).is_some()) + ); let key2 = VirtualHostLimitTarget::MaxQueues; - assert!(!vec - .iter() - .any(|it| it.vhost == vh_params.name && it.limits.get(key2.as_ref()).is_some())); + assert!( + !vec.iter() + .any(|it| it.vhost == vh_params.name && it.limits.get(key2.as_ref()).is_some()) + ); rc.delete_vhost(vh_params.name, false).unwrap(); } diff --git a/tests/blocking_virtual_host_tests.rs b/tests/blocking_virtual_host_tests.rs index 350b108..4bcf3b5 100644 --- a/tests/blocking_virtual_host_tests.rs +++ b/tests/blocking_virtual_host_tests.rs @@ -14,7 +14,7 @@ use rabbitmq_http_client::{blocking_api::Client, commons::QueueType, requests::VirtualHostParams}; mod test_helpers; -use crate::test_helpers::{endpoint, PASSWORD, USERNAME}; +use crate::test_helpers::{PASSWORD, USERNAME, endpoint}; #[test] fn test_blocking_list_vhosts() { diff --git a/tests/test_helpers.rs b/tests/test_helpers.rs index 8fd9be7..7eb24c0 100644 --- a/tests/test_helpers.rs +++ b/tests/test_helpers.rs @@ -17,12 +17,12 @@ use rabbitmq_http_client::blocking_api::Client as BlockingClient; use std::env; use std::time::Duration; +use amqprs::BasicProperties; use amqprs::channel::BasicPublishArguments; use amqprs::connection::{Connection, OpenConnectionArguments}; -use amqprs::BasicProperties; use rabbitmq_http_client::api::Client as AsyncClient; use regex::Regex; -use serde_json::{json, Map, Value}; +use serde_json::{Map, Value, json}; use tokio::time; // // Common diff --git a/tests/unit_policy_tests.rs b/tests/unit_policy_tests.rs index ca66363..21b2401 100644 --- a/tests/unit_policy_tests.rs +++ b/tests/unit_policy_tests.rs @@ -15,7 +15,7 @@ mod test_helpers; use rabbitmq_http_client::commons::PolicyTarget; use rabbitmq_http_client::responses::{OptionalArgumentSourceOps, Policy, PolicyDefinition}; -use serde_json::{json, Map}; +use serde_json::{Map, json}; #[test] fn test_unit_policy_definition_has_cmq_keys_case1() { diff --git a/tests/unit_queue_tests.rs b/tests/unit_queue_tests.rs index 6379c09..913801b 100644 --- a/tests/unit_queue_tests.rs +++ b/tests/unit_queue_tests.rs @@ -17,7 +17,7 @@ use rabbitmq_http_client::commons::{PolicyTarget, QueueType}; use rabbitmq_http_client::responses::{ NamedPolicyTargetObject, Policy, PolicyDefinition, QueueInfo, QueueOps, }; -use serde_json::{json, Map}; +use serde_json::{Map, json}; #[test] fn test_unit_queue_type_from_str() { From f572551d776c19d10346068ce021a6018a6835c5 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 11 Jul 2025 15:59:50 -0400 Subject: [PATCH 23/47] cargo clippy --fix --- src/responses.rs | 25 +++++++++++-------------- src/transformers.rs | 24 ++++++++++++------------ 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/responses.rs b/src/responses.rs index ed00223..792fd8c 100644 --- a/src/responses.rs +++ b/src/responses.rs @@ -966,12 +966,11 @@ impl QueueDefinition { value: &str, new_value: &str, ) -> &mut Self { - if let Some(val) = self.arguments.get(argument) { - if let Some(s) = val.as_str() { - if s == value { - self.arguments.insert(argument.to_owned(), json!(new_value)); - } - } + if let Some(val) = self.arguments.get(argument) + && let Some(s) = val.as_str() + && s == value + { + self.arguments.insert(argument.to_owned(), json!(new_value)); } self @@ -1283,14 +1282,12 @@ impl PolicyDefinition { value: &str, new_value: &str, ) -> &mut Self { - if let Some(m) = &self.0 { - if let Some(raw_val) = m.get(argument) { - if let Some(s) = raw_val.as_str() { - if s == value { - self.insert(argument.to_owned(), json!(new_value)); - } - } - } + if let Some(m) = &self.0 + && let Some(raw_val) = m.get(argument) + && let Some(s) = raw_val.as_str() + && s == value + { + self.insert(argument.to_owned(), json!(new_value)); } self diff --git a/src/transformers.rs b/src/transformers.rs index 8acdb52..8218be3 100644 --- a/src/transformers.rs +++ b/src/transformers.rs @@ -60,13 +60,13 @@ impl DefinitionSetTransformer for PrepareForQuorumQueueMigration { // Queue x-arguments: // replace x-overflow values that are equal to "reject-publish-dlx" let f3 = Box::new(|mut qd: QueueDefinition| { - if let Some(val) = qd.arguments.get(X_ARGUMENT_KEY_X_OVERFLOW) { - if val.as_str().unwrap_or(OVERFLOW_REJECT_PUBLISH) == OVERFLOW_REJECT_PUBLISH_DLX { - qd.arguments.insert( - X_ARGUMENT_KEY_X_OVERFLOW.to_owned(), - json!(OverflowBehavior::RejectPublish), - ); - } + if let Some(val) = qd.arguments.get(X_ARGUMENT_KEY_X_OVERFLOW) + && val.as_str().unwrap_or(OVERFLOW_REJECT_PUBLISH) == OVERFLOW_REJECT_PUBLISH_DLX + { + qd.arguments.insert( + X_ARGUMENT_KEY_X_OVERFLOW.to_owned(), + json!(OverflowBehavior::RejectPublish), + ); } qd }); @@ -76,11 +76,11 @@ impl DefinitionSetTransformer for PrepareForQuorumQueueMigration { // replace x-overflow values that are equal to "reject-publish-dlx" let f4 = Box::new(|mut p: Policy| { let key = "overflow"; - if let Some(val) = p.definition.get(key) { - if val.as_str().unwrap_or(OVERFLOW_REJECT_PUBLISH) == OVERFLOW_REJECT_PUBLISH_DLX { - p.definition - .insert(key.to_owned(), json!(OverflowBehavior::RejectPublish)); - } + if let Some(val) = p.definition.get(key) + && val.as_str().unwrap_or(OVERFLOW_REJECT_PUBLISH) == OVERFLOW_REJECT_PUBLISH_DLX + { + p.definition + .insert(key.to_owned(), json!(OverflowBehavior::RejectPublish)); } p }); From 62ad12ff45c7c1c8f22cdfb79af0af7640c2b6b2 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 14 Jul 2025 12:00:41 -0400 Subject: [PATCH 24/47] Support for a new deprecated feature state column References rabbitmq-server#14227 --- src/responses.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/responses.rs b/src/responses.rs index 792fd8c..94f2887 100644 --- a/src/responses.rs +++ b/src/responses.rs @@ -2174,6 +2174,8 @@ pub struct DeprecatedFeature { pub deprecation_phase: DeprecationPhase, pub doc_url: String, pub provided_by: String, + #[cfg_attr(feature = "tabled", tabled(display = "display_option"))] + pub state: Option } #[derive(Debug, Serialize, Deserialize, Clone)] From b107a8f6accd92f6ad6d5d9f6fd193caec0dbee7 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 14 Jul 2025 12:22:48 -0400 Subject: [PATCH 25/47] Change log update --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1e4550..c2e154f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,9 @@ ## v0.39.0 (in development) -No changes yet. +### Enhancements + + * Support for a new deprecated feature flag state column, introduced in [rabbitmq/rabbitmq-server#14227](https://github.com/rabbitmq/rabbitmq-server/pull/14227) ## v0.38.0 (Jul 11, 2025) From cfda18dae26c6af0caceaa250f23307f5ba5c03e Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 14 Jul 2025 14:29:30 -0400 Subject: [PATCH 26/47] New helper fns for declaring and deleting multiple policies purely for convenience. --- CHANGELOG.md | 5 +- src/api.rs | 51 ++++++++++++++ src/blocking_api.rs | 48 ++++++++++++++ src/requests.rs | 4 +- src/responses.rs | 2 +- tests/async_policy_tests.rs | 118 +++++++++++++++++++++++++++++++++ tests/blocking_policy_tests.rs | 114 +++++++++++++++++++++++++++++++ 7 files changed, 338 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2e154f..f650749 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,10 @@ ### Enhancements * Support for a new deprecated feature flag state column, introduced in [rabbitmq/rabbitmq-server#14227](https://github.com/rabbitmq/rabbitmq-server/pull/14227) - + * `Client#declare_policies` and `Client#declare_operator_policies` are two new helper functions for declaring multiple policies at once. + Note that both functions will still issue the same number of API requests, so it only exists for convenience + * `Client#delete_policies_in` and `Client#delete_operator_policies_in` are two new helper functions for deleting multiple policies at once. + Note that both functions will still issue the same number of API requests, so it only exists for convenience ## v0.38.0 (Jul 11, 2025) diff --git a/src/api.rs b/src/api.rs index 08432a3..9b93a0d 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1193,12 +1193,15 @@ where Ok(response) } + /// Lists all policies in the cluster (across all virtual hosts), taking the user's + /// permissions into account. pub async fn list_policies(&self) -> Result> { let response = self.http_get("policies", None, None).await?; let response = response.json().await?; Ok(response) } + /// Lists policies in a virtual host. pub async fn list_policies_in(&self, vhost: &str) -> Result> { let response = self.http_get(path!("policies", vhost), None, None).await?; let response = response.json().await?; @@ -1217,6 +1220,17 @@ where Ok(()) } + /// Declares multiple policies. Note that this function will still issue + /// as many HTTP API requests as there are policies to declare. + pub async fn declare_policies(&self, params: Vec<&PolicyParams<'_>>) -> Result<()> { + for p in params { + let _response = self + .http_put(path!("policies", p.vhost, p.name), p, None, None) + .await?; + } + Ok(()) + } + pub async fn delete_policy(&self, vhost: &str, name: &str) -> Result<()> { let _response = self .http_delete( @@ -1228,6 +1242,21 @@ where Ok(()) } + /// Deletes multiple policies. Note that this function will still issue + /// as many HTTP API requests as there are policies to delete. + pub async fn delete_policies_in(&self, vhost: &str, names: Vec<&str>) -> Result<()> { + for name in names { + let _response = self + .http_delete( + path!("policies", vhost, name), + Some(StatusCode::NOT_FOUND), + None, + ) + .await?; + } + Ok(()) + } + pub async fn get_operator_policy(&self, vhost: &str, name: &str) -> Result { let response = self .http_get(path!("operator-policies", vhost, name), None, None) @@ -1262,6 +1291,15 @@ where Ok(()) } + pub async fn declare_operator_policies(&self, params: Vec<&PolicyParams<'_>>) -> Result<()> { + for p in params { + let _response = self + .http_put(path!("operator-policies", p.vhost, p.name), p, None, None) + .await?; + } + Ok(()) + } + pub async fn delete_operator_policy(&self, vhost: &str, name: &str) -> Result<()> { let _response = self .http_delete( @@ -1273,6 +1311,19 @@ where Ok(()) } + pub async fn delete_operator_policies_in(&self, vhost: &str, names: Vec<&str>) -> Result<()> { + for name in names { + let _response = self + .http_delete( + path!("operator-policies", vhost, name), + Some(StatusCode::NOT_FOUND), + None, + ) + .await?; + } + Ok(()) + } + pub async fn list_permissions(&self) -> Result> { let response = self.http_get("permissions", None, None).await?; let response = response.json().await?; diff --git a/src/blocking_api.rs b/src/blocking_api.rs index 5ae2820..746d4eb 100644 --- a/src/blocking_api.rs +++ b/src/blocking_api.rs @@ -1048,12 +1048,15 @@ where Ok(response) } + /// Lists all policies in the cluster (across all virtual hosts), taking the user's + /// permissions into account. pub fn list_policies(&self) -> Result> { let response = self.http_get("policies", None, None)?; let response = response.json()?; Ok(response) } + /// Lists policies in a virtual host. pub fn list_policies_in(&self, vhost: &str) -> Result> { let response = self.http_get(path!("policies", vhost), None, None)?; let response = response.json()?; @@ -1070,6 +1073,15 @@ where Ok(()) } + /// Declares multiple policies. Note that this function will still issue + /// as many HTTP API requests as there are policies to declare. + pub fn declare_policies(&self, params: Vec<&PolicyParams>) -> Result<()> { + for p in params { + let _response = self.http_put(path!("policies", p.vhost, p.name), p, None, None)?; + } + Ok(()) + } + pub fn delete_policy(&self, vhost: &str, name: &str) -> Result<()> { let _response = self.http_delete( path!("policies", vhost, name), @@ -1079,6 +1091,19 @@ where Ok(()) } + /// Deletes multiple policies. Note that this function will still issue + /// as many HTTP API requests as there are policies to delete. + pub fn delete_policies_in(&self, vhost: &str, names: Vec<&str>) -> Result<()> { + for name in names { + let _response = self.http_delete( + path!("policies", vhost, name), + Some(StatusCode::NOT_FOUND), + None, + )?; + } + Ok(()) + } + pub fn get_operator_policy(&self, vhost: &str, name: &str) -> Result { let response = self.http_get(path!("operator-policies", vhost, name), None, None)?; let response = response.json()?; @@ -1107,6 +1132,16 @@ where Ok(()) } + /// Declares multiple operator policies. Note that this function will still issue + /// as many HTTP API requests as there are operator policies to declare. + pub fn declare_operator_policies(&self, params: Vec<&PolicyParams>) -> Result<()> { + for p in params { + let _response = + self.http_put(path!("operator-policies", p.vhost, p.name), p, None, None)?; + } + Ok(()) + } + pub fn delete_operator_policy(&self, vhost: &str, name: &str) -> Result<()> { let _response = self.http_delete( path!("operator-policies", vhost, name), @@ -1116,6 +1151,19 @@ where Ok(()) } + /// Deletes multiple operator policies. Note that this function will still issue + /// as many HTTP API requests as there are operator policies to delete. + pub fn delete_operator_policies_in(&self, vhost: &str, names: Vec<&str>) -> Result<()> { + for name in names { + let _response = self.http_delete( + path!("operator-policies", vhost, name), + Some(StatusCode::NOT_FOUND), + None, + )?; + } + Ok(()) + } + pub fn list_permissions(&self) -> Result> { let response = self.http_get("permissions", None, None)?; let response = response.json()?; diff --git a/src/requests.rs b/src/requests.rs index 985af7a..07de6a9 100644 --- a/src/requests.rs +++ b/src/requests.rs @@ -404,7 +404,7 @@ impl From for PolicyDefinition { } /// Represents a [policy](https://rabbitmq.com/docs/parameters/#policies). -#[derive(Serialize)] +#[derive(Serialize, Debug)] pub struct PolicyParams<'a> { pub vhost: &'a str, pub name: &'a str, @@ -429,7 +429,7 @@ impl<'a> From<&'a Policy> for PolicyParams<'a> { } /// Represents a user's [permission in a particular virtual host](https://rabbitmq.com/docs/access-control/). -#[derive(Serialize)] +#[derive(Serialize, Debug)] pub struct Permissions<'a> { pub user: &'a str, pub vhost: &'a str, diff --git a/src/responses.rs b/src/responses.rs index 94f2887..d117d2a 100644 --- a/src/responses.rs +++ b/src/responses.rs @@ -2175,7 +2175,7 @@ pub struct DeprecatedFeature { pub doc_url: String, pub provided_by: String, #[cfg_attr(feature = "tabled", tabled(display = "display_option"))] - pub state: Option + pub state: Option, } #[derive(Debug, Serialize, Deserialize, Clone)] diff --git a/tests/async_policy_tests.rs b/tests/async_policy_tests.rs index 2654f05..9c054f8 100644 --- a/tests/async_policy_tests.rs +++ b/tests/async_policy_tests.rs @@ -75,6 +75,61 @@ async fn test_async_dlx_policy() { let _ = rc.delete_vhost(vh_params.name, false).await; } +#[tokio::test] +async fn test_async_multiple_policies_case1() { + let endpoint = endpoint(); + let rc = Client::new(endpoint.as_str(), USERNAME, PASSWORD); + + let mut map1 = Map::::new(); + map1.insert("dead-letter-exchange".to_owned(), json!("my-dlx")); + let policy_definition1 = map1.clone(); + + let mut map2 = Map::::new(); + map2.insert("message-ttl".to_owned(), json!(10_000)); + let policy_definition2 = map2.clone(); + + let vh_params = VirtualHostParams::named("test_blocking_multiple_policies_case1"); + let _ = rc.delete_vhost(vh_params.name, false).await; + let result1 = rc.create_vhost(&vh_params).await; + assert!(result1.is_ok()); + + let dlx_policy = PolicyParams { + vhost: vh_params.name, + name: "dlx_policy", + pattern: ".*", + apply_to: PolicyTarget::QuorumQueues, + priority: 3, + definition: policy_definition1, + }; + let message_ttl_policy = PolicyParams { + vhost: vh_params.name, + name: "message_ttl_policy", + pattern: ".*", + apply_to: PolicyTarget::QuorumQueues, + priority: 3, + definition: policy_definition2, + }; + + let result1 = rc + .declare_policies(vec![&dlx_policy, &message_ttl_policy]) + .await; + assert!(result1.is_ok()); + + let result2 = rc.list_policies_in(vh_params.name).await; + assert!(result2.is_ok()); + assert_eq!(result2.unwrap().len(), 2); + + let result3 = rc + .delete_policies_in( + vh_params.name, + vec![dlx_policy.name, message_ttl_policy.name], + ) + .await; + assert!(result3.is_ok()); + + let _ = rc.delete_vhost(vh_params.name, false).await; +} + #[tokio::test] async fn test_async_operator_policy() { let endpoint = endpoint(); @@ -102,6 +157,69 @@ async fn test_async_operator_policy() { let _ = rc.delete_vhost(vh_params.name, true).await; } +#[tokio::test] +async fn test_async_multiple_operator_policies_case1() { + let endpoint = endpoint(); + let rc = Client::new(endpoint.as_str(), USERNAME, PASSWORD); + + let mut map1 = Map::::new(); + map1.insert("delivery-limit".to_owned(), json!(13)); + let policy_definition1 = map1.clone(); + + let mut map2 = Map::::new(); + map2.insert("delivery-limit".to_owned(), json!(67)); + let policy_definition2 = map2.clone(); + + let vh_params = VirtualHostParams::named("test_async_multiple_operator_policies_case1"); + let _ = rc.delete_vhost(vh_params.name, false).await; + let result0 = rc.create_vhost(&vh_params).await; + assert!(result0.is_ok()); + + let dlx_policy = PolicyParams { + vhost: vh_params.name, + name: "operator_policy.1", + pattern: ".*", + apply_to: PolicyTarget::QuorumQueues, + priority: 2, + definition: policy_definition1, + }; + let message_ttl_policy = PolicyParams { + vhost: vh_params.name, + name: "message_ttl_policy", + pattern: ".*", + apply_to: PolicyTarget::QuorumQueues, + priority: 3, + definition: policy_definition2, + }; + + let result1 = rc + .declare_operator_policies(vec![&dlx_policy, &message_ttl_policy]) + .await; + assert!(result1.is_ok()); + + let result2 = rc.list_operator_policies_in(vh_params.name).await; + assert!(result2.is_ok()); + assert_eq!(result2.unwrap().len(), 2); + + let result3 = rc + .delete_operator_policies_in( + vh_params.name, + vec![dlx_policy.name, message_ttl_policy.name], + ) + .await; + assert!(result3.is_ok()); + + let result4 = rc.list_operator_policies_in(vh_params.name).await; + assert!(result4.is_ok()); + assert_eq!(result4.unwrap().len(), 0); + + let _ = rc.delete_vhost(vh_params.name, false).await; +} + +// +// Implementation +// + async fn test_a_policy(rc: &Client<&str, &str, &str>, policy: &PolicyParams<'_>) { // initially, there should be no such policy let policies = rc.list_policies_in(policy.vhost).await.unwrap(); diff --git a/tests/blocking_policy_tests.rs b/tests/blocking_policy_tests.rs index 4bbcdc5..9426891 100644 --- a/tests/blocking_policy_tests.rs +++ b/tests/blocking_policy_tests.rs @@ -75,6 +75,61 @@ fn test_blocking_dlx_policy() { let _ = rc.delete_vhost(vh_params.name, false); } +#[test] +fn test_blocking_multiple_policies_case1() { + let endpoint = endpoint(); + let rc = Client::new(endpoint.as_str(), USERNAME, PASSWORD); + + let mut map1 = Map::::new(); + map1.insert("dead-letter-exchange".to_owned(), json!("my-dlx")); + let policy_definition1 = map1.clone(); + + let mut map2 = Map::::new(); + map2.insert("message-ttl".to_owned(), json!(10_000)); + let policy_definition2 = map2.clone(); + + let vh_params = VirtualHostParams::named("test_blocking_multiple_policies_case1"); + let _ = rc.delete_vhost(vh_params.name, false); + let result0 = rc.create_vhost(&vh_params); + assert!(result0.is_ok()); + + let dlx_policy = PolicyParams { + vhost: vh_params.name, + name: "dlx_policy", + pattern: ".*", + apply_to: PolicyTarget::QuorumQueues, + priority: 3, + definition: policy_definition1, + }; + let message_ttl_policy = PolicyParams { + vhost: vh_params.name, + name: "message_ttl_policy", + pattern: ".*", + apply_to: PolicyTarget::QuorumQueues, + priority: 3, + definition: policy_definition2, + }; + + let result1 = rc.declare_policies(vec![&dlx_policy, &message_ttl_policy]); + assert!(result1.is_ok()); + + let result2 = rc.list_policies_in(vh_params.name); + assert!(result2.is_ok()); + assert_eq!(result2.unwrap().len(), 2); + + let result3 = rc.delete_policies_in( + vh_params.name, + vec![dlx_policy.name, message_ttl_policy.name], + ); + assert!(result3.is_ok()); + + let result4 = rc.list_policies_in(vh_params.name); + assert!(result4.is_ok()); + assert_eq!(result4.unwrap().len(), 0); + + let _ = rc.delete_vhost(vh_params.name, false); +} + #[test] fn test_blocking_operator_policy() { let endpoint = endpoint(); @@ -102,6 +157,65 @@ fn test_blocking_operator_policy() { let _ = rc.delete_vhost(vh_params.name, true); } +#[test] +fn test_blocking_multiple_operator_policies_case1() { + let endpoint = endpoint(); + let rc = Client::new(endpoint.as_str(), USERNAME, PASSWORD); + + let mut map1 = Map::::new(); + map1.insert("delivery-limit".to_owned(), json!(13)); + let policy_definition1 = map1.clone(); + + let mut map2 = Map::::new(); + map2.insert("delivery-limit".to_owned(), json!(67)); + let policy_definition2 = map2.clone(); + + let vh_params = VirtualHostParams::named("test_blocking_multiple_operator_policies_case1"); + let _ = rc.delete_vhost(vh_params.name, false); + let result0 = rc.create_vhost(&vh_params); + assert!(result0.is_ok()); + + let dlx_policy = PolicyParams { + vhost: vh_params.name, + name: "operator_policy.1", + pattern: ".*", + apply_to: PolicyTarget::QuorumQueues, + priority: 2, + definition: policy_definition1, + }; + let message_ttl_policy = PolicyParams { + vhost: vh_params.name, + name: "message_ttl_policy", + pattern: ".*", + apply_to: PolicyTarget::QuorumQueues, + priority: 3, + definition: policy_definition2, + }; + + let result1 = rc.declare_operator_policies(vec![&dlx_policy, &message_ttl_policy]); + assert!(result1.is_ok()); + + let result2 = rc.list_operator_policies_in(vh_params.name); + assert!(result2.is_ok()); + assert_eq!(result2.unwrap().len(), 2); + + let result3 = rc.delete_operator_policies_in( + vh_params.name, + vec![dlx_policy.name, message_ttl_policy.name], + ); + assert!(result3.is_ok()); + + let result4 = rc.list_operator_policies_in(vh_params.name); + assert!(result4.is_ok()); + assert_eq!(result4.unwrap().len(), 0); + + let _ = rc.delete_vhost(vh_params.name, false); +} + +// +// Implementation +// + fn test_a_policy(rc: &Client<&str, &str, &str>, policy: &PolicyParams) { // initially, there should be no such policy let policies = rc.list_policies_in(policy.vhost).unwrap(); From 96793c0a122b1765d4d21fb7d2cfecc485811faf Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 14 Jul 2025 14:31:47 -0400 Subject: [PATCH 27/47] 0.39.0 --- CHANGELOG.md | 6 +++++- README.md | 8 ++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f650749..b5670e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Rust Client for the RabbitMQ HTTP API Change Log -## v0.39.0 (in development) +## v0.40.0 (in development) + +No changes yet. + +## v0.39.0 (Jul 14, 2025) ### Enhancements diff --git a/README.md b/README.md index d191c1e..edb8f22 100644 --- a/README.md +++ b/README.md @@ -14,25 +14,25 @@ This library is relatively young, breaking API changes are possible. ### Blocking Client ```toml -rabbitmq_http_client = { version = "0.38.0", features = ["core", "blocking"] } +rabbitmq_http_client = { version = "0.39.0", features = ["core", "blocking"] } ``` ### Async Client ```toml -rabbitmq_http_client = { version = "0.38.0", features = ["core", "async"] } +rabbitmq_http_client = { version = "0.39.0", features = ["core", "async"] } ``` ### Blocking Client with Tabled Support ```toml -rabbitmq_http_client = { version = "0.38.0", features = ["core", "blocking", "tabled"] } +rabbitmq_http_client = { version = "0.39.0", features = ["core", "blocking", "tabled"] } ``` ### Async Client with Tabled Support ```toml -rabbitmq_http_client = { version = "0.38.0", features = ["core", "async", "tabled"] } +rabbitmq_http_client = { version = "0.39.0", features = ["core", "async", "tabled"] } ``` From 137d45c8e92b330231fe05406bb625ff92f55c70 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 14 Jul 2025 14:33:37 -0400 Subject: [PATCH 28/47] Bump dev version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 46aadca..a38744b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rabbitmq_http_client" -version = "0.39.0" +version = "0.40.0" edition = "2024" description = "RabbitMQ HTTP API client" From 9f976cf4195e7df9adb572261bca014563cfff6d Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 14 Jul 2025 20:01:33 -0400 Subject: [PATCH 29/47] Refactor to use assert_eq! --- tests/async_virtual_host_tests.rs | 8 ++++---- tests/blocking_virtual_host_tests.rs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/async_virtual_host_tests.rs b/tests/async_virtual_host_tests.rs index b1c01ef..c80172d 100644 --- a/tests/async_virtual_host_tests.rs +++ b/tests/async_virtual_host_tests.rs @@ -36,7 +36,7 @@ async fn test_async_get_vhost() { assert!(result.is_ok()); let vh = result.unwrap(); - assert!(vh.name == name); + assert_eq!(vh.name, name); } #[tokio::test] @@ -64,7 +64,7 @@ async fn test_async_create_vhost() { let result3 = rc.get_vhost(name).await; assert!(result3.is_ok()); let vh2 = result3.unwrap(); - assert!(vh2.name == name); + assert_eq!(vh2.name, name); let _ = rc.delete_vhost(name, false).await; } @@ -94,7 +94,7 @@ async fn test_async_create_vhost_without_dqt() { let result3 = rc.get_vhost(name).await; assert!(result3.is_ok()); let vh2 = result3.unwrap(); - assert!(vh2.name == name); + assert_eq!(vh2.name, name); let _ = rc.delete_vhost(name, false).await; } @@ -132,7 +132,7 @@ async fn test_async_update_vhost() { let result4 = rc.get_vhost(name).await; assert!(result4.is_ok()); let vh = result4.unwrap(); - assert!(vh.description.unwrap() == alt_desc); + assert_eq!(vh.description.unwrap(), alt_desc); let _ = rc.delete_vhost(name, false).await; } diff --git a/tests/blocking_virtual_host_tests.rs b/tests/blocking_virtual_host_tests.rs index 4bcf3b5..588e6c9 100644 --- a/tests/blocking_virtual_host_tests.rs +++ b/tests/blocking_virtual_host_tests.rs @@ -36,7 +36,7 @@ fn test_blocking_get_vhost() { assert!(result.is_ok()); let vh = result.unwrap(); - assert!(vh.name == name); + assert_eq!(vh.name, name); } #[test] @@ -64,7 +64,7 @@ fn test_blocking_create_vhost() { let result3 = rc.get_vhost(name); assert!(result3.is_ok()); let vh2 = result3.unwrap(); - assert!(vh2.name == name); + assert_eq!(vh2.name, name); let _ = rc.delete_vhost(name, false); } @@ -94,7 +94,7 @@ fn test_blocking_create_vhost_without_dqt() { let result3 = rc.get_vhost(name); assert!(result3.is_ok()); let vh2 = result3.unwrap(); - assert!(vh2.name == name); + assert_eq!(vh2.name, name); let _ = rc.delete_vhost(name, false); } @@ -132,7 +132,7 @@ fn test_blocking_update_vhost() { let result4 = rc.get_vhost(name); assert!(result4.is_ok()); let vh = result4.unwrap(); - assert!(vh.description.unwrap() == alt_desc); + assert_eq!(vh.description.unwrap(), alt_desc); let _ = rc.delete_vhost(name, false); } From a40c681b5783d739b14c04c9fb5a6b2f7958b5b8 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 14 Jul 2025 20:24:16 -0400 Subject: [PATCH 30/47] Refactoring plus drop two test assertions that are non-essential but make the tests fail if before_build.sh wasn't called recently enough. --- src/api.rs | 219 ++++++++------------- src/blocking_api.rs | 295 ++++++++++------------------ tests/async_definitions_tests.rs | 3 - tests/blocking_definitions_tests.rs | 3 - 4 files changed, 179 insertions(+), 341 deletions(-) diff --git a/src/api.rs b/src/api.rs index 9b93a0d..0d0fba9 100644 --- a/src/api.rs +++ b/src/api.rs @@ -229,48 +229,32 @@ where /// Lists cluster nodes. pub async fn list_nodes(&self) -> Result> { - let response = self.http_get("nodes", None, None).await?; - let response = response.json().await?; - Ok(response) + self.get_api_request("nodes").await } /// Lists virtual hosts in the cluster. pub async fn list_vhosts(&self) -> Result> { - let response = self.http_get("vhosts", None, None).await?; - let response = response.json().await?; - Ok(response) + self.get_api_request("vhosts").await } /// Lists users in the internal database. pub async fn list_users(&self) -> Result> { - let response = self.http_get("users", None, None).await?; - let response = response.json().await?; - Ok(response) + self.get_api_request("users").await } /// Lists users in the internal database that do not have access /// to any virtual hosts. pub async fn list_users_without_permissions(&self) -> Result> { - let response = self - .http_get("users/without-permissions", None, None) - .await?; - let response = response.json().await?; - Ok(response) + self.get_api_request("users/without-permissions").await } /// Lists all AMQP 1.0 and 0-9-1 client connections across the cluster. pub async fn list_connections(&self) -> Result> { - let response = self.http_get("connections", None, None).await?; - let response = response.json().await?; - Ok(response) + self.get_api_request("connections").await } pub async fn get_connection_info(&self, name: &str) -> Result { - let response = self - .http_get(path!("connections", name), None, None) - .await?; - let response = response.json().await?; - Ok(response) + self.get_api_request(path!("connections", name)).await } pub async fn get_stream_connection_info( @@ -278,15 +262,8 @@ where virtual_host: &str, name: &str, ) -> Result { - let response = self - .http_get( - path!("stream", "connections", virtual_host, name), - None, - None, - ) - .await?; - let response = response.json().await?; - Ok(response) + self.get_api_request(path!("stream", "connections", virtual_host, name)) + .await } pub async fn close_connection(&self, name: &str, reason: Option<&str>) -> Result<()> { @@ -341,11 +318,8 @@ where &self, virtual_host: &str, ) -> Result> { - let response = self - .http_get(path!("vhosts", virtual_host, "connections"), None, None) - .await?; - let response = response.json().await?; - Ok(response) + self.get_api_request(path!("vhosts", virtual_host, "connections")) + .await } /// Lists all connections of a specific user. @@ -353,18 +327,13 @@ where &self, username: &str, ) -> Result> { - let response = self - .http_get(path!("connections", "username", username), None, None) - .await?; - let response = response.json().await?; - Ok(response) + self.get_api_request(path!("connections", "username", username)) + .await } /// Lists all RabbitMQ Stream Protocol client connections across the cluster. pub async fn list_stream_connections(&self) -> Result> { - let response = self.http_get("stream/connections", None, None).await?; - let response = response.json().await?; - Ok(response) + self.get_api_request("stream/connections").await } /// Lists RabbitMQ Stream Protocol client connections in the given virtual host. @@ -372,27 +341,19 @@ where &self, virtual_host: &str, ) -> Result> { - let response = self - .http_get(path!("stream", "connections", virtual_host), None, None) - .await?; - let response = response.json().await?; - Ok(response) + self.get_api_request(path!("stream", "connections", virtual_host)) + .await } /// Lists all channels across the cluster. pub async fn list_channels(&self) -> Result> { - let response = self.http_get("channels", None, None).await?; - let response = response.json().await?; - Ok(response) + self.get_api_request("channels").await } /// Lists all channels in the given virtual host. pub async fn list_channels_in(&self, virtual_host: &str) -> Result> { - let response = self - .http_get(path!("vhosts", virtual_host, "channels"), None, None) - .await?; - let response = response.json().await?; - Ok(response) + self.get_api_request(path!("vhosts", virtual_host, "channels")) + .await } /// Lists all stream publishers across the cluster. @@ -680,33 +641,21 @@ where /// /// See [`VirtualHostParams`] pub async fn update_vhost(&self, params: &VirtualHostParams<'_>) -> Result<()> { - let _response = self - .http_put(path!("vhosts", params.name), params, None, None) - .await?; - Ok(()) + self.put_api_request(path!("vhosts", params.name), params) + .await } /// Adds a user to the internal database. /// /// See [`UserParams`] and [`crate::password_hashing`]. pub async fn create_user(&self, params: &UserParams<'_>) -> Result<()> { - let _response = self - .http_put(path!("users", params.name), params, None, None) - .await?; - Ok(()) + self.put_api_request(path!("users", params.name), params) + .await } pub async fn declare_permissions(&self, params: &Permissions<'_>) -> Result<()> { - let _response = self - .http_put( - // /api/permissions/vhost/user - path!("permissions", params.vhost, params.user), - params, - None, - None, - ) - .await?; - Ok(()) + self.put_api_request(path!("permissions", params.vhost, params.user), params) + .await } pub async fn grant_permissions(&self, vhost: &str, user: &str) -> Result<()> { @@ -717,10 +666,8 @@ where } pub async fn declare_queue(&self, vhost: &str, params: &QueueParams<'_>) -> Result<()> { - let _response = self - .http_put(path!("queues", vhost, params.name), params, None, None) - .await?; - Ok(()) + self.put_api_request(path!("queues", vhost, params.name), params) + .await } pub async fn declare_stream(&self, vhost: &str, params: &StreamParams<'_>) -> Result<()> { @@ -745,10 +692,8 @@ where } pub async fn declare_exchange(&self, vhost: &str, params: &ExchangeParams<'_>) -> Result<()> { - let _response = self - .http_put(path!("exchanges", vhost, params.name), params, None, None) - .await?; - Ok(()) + self.put_api_request(path!("exchanges", vhost, params.name), params) + .await } pub async fn bind_queue( @@ -806,27 +751,13 @@ where } pub async fn delete_vhost(&self, vhost: &str, idempotently: bool) -> Result<()> { - let excludes = if idempotently { - Some(StatusCode::NOT_FOUND) - } else { - None - }; - let _response = self - .http_delete(path!("vhosts", vhost), excludes, None) - .await?; - Ok(()) + self.delete_api_request_with_optional_not_found(path!("vhosts", vhost), idempotently) + .await } pub async fn delete_user(&self, username: &str, idempotently: bool) -> Result<()> { - let excludes = if idempotently { - Some(StatusCode::NOT_FOUND) - } else { - None - }; - let _response = self - .http_delete(path!("users", username), excludes, None) - .await?; - Ok(()) + self.delete_api_request_with_optional_not_found(path!("users", username), idempotently) + .await } pub async fn delete_users(&self, usernames: Vec<&str>) -> Result<()> { @@ -855,15 +786,8 @@ where } pub async fn delete_queue(&self, vhost: &str, name: &str, idempotently: bool) -> Result<()> { - let excludes = if idempotently { - Some(StatusCode::NOT_FOUND) - } else { - None - }; - let _response = self - .http_delete(path!("queues", vhost, name), excludes, None) - .await?; - Ok(()) + self.delete_api_request_with_optional_not_found(path!("queues", vhost, name), idempotently) + .await } pub async fn delete_stream(&self, vhost: &str, name: &str, idempotently: bool) -> Result<()> { @@ -871,15 +795,11 @@ where } pub async fn delete_exchange(&self, vhost: &str, name: &str, idempotently: bool) -> Result<()> { - let excludes = if idempotently { - Some(StatusCode::NOT_FOUND) - } else { - None - }; - let _response = self - .http_delete(path!("exchanges", vhost, name), excludes, None) - .await?; - Ok(()) + self.delete_api_request_with_optional_not_found( + path!("exchanges", vhost, name), + idempotently, + ) + .await } pub async fn delete_binding( @@ -1224,9 +1144,7 @@ where /// as many HTTP API requests as there are policies to declare. pub async fn declare_policies(&self, params: Vec<&PolicyParams<'_>>) -> Result<()> { for p in params { - let _response = self - .http_put(path!("policies", p.vhost, p.name), p, None, None) - .await?; + self.declare_policy(p).await?; } Ok(()) } @@ -1246,13 +1164,7 @@ where /// as many HTTP API requests as there are policies to delete. pub async fn delete_policies_in(&self, vhost: &str, names: Vec<&str>) -> Result<()> { for name in names { - let _response = self - .http_delete( - path!("policies", vhost, name), - Some(StatusCode::NOT_FOUND), - None, - ) - .await?; + self.delete_policy(vhost, name).await?; } Ok(()) } @@ -1293,9 +1205,7 @@ where pub async fn declare_operator_policies(&self, params: Vec<&PolicyParams<'_>>) -> Result<()> { for p in params { - let _response = self - .http_put(path!("operator-policies", p.vhost, p.name), p, None, None) - .await?; + self.declare_operator_policy(p).await?; } Ok(()) } @@ -1313,23 +1223,52 @@ where pub async fn delete_operator_policies_in(&self, vhost: &str, names: Vec<&str>) -> Result<()> { for name in names { - let _response = self - .http_delete( - path!("operator-policies", vhost, name), - Some(StatusCode::NOT_FOUND), - None, - ) - .await?; + self.delete_operator_policy(vhost, name).await?; } Ok(()) } pub async fn list_permissions(&self) -> Result> { - let response = self.http_get("permissions", None, None).await?; + self.get_api_request("permissions").await + } + + // Helper methods for common patterns + async fn get_api_request(&self, path: S) -> Result + where + T: serde::de::DeserializeOwned, + S: AsRef, + { + let response = self.http_get(path, None, None).await?; let response = response.json().await?; Ok(response) } + async fn delete_api_request_with_optional_not_found( + &self, + path: S, + idempotent: bool, + ) -> Result<()> + where + S: AsRef, + { + let excludes = if idempotent { + Some(StatusCode::NOT_FOUND) + } else { + None + }; + self.http_delete(path, excludes, None).await?; + Ok(()) + } + + async fn put_api_request(&self, path: S, payload: &T) -> Result<()> + where + S: AsRef, + T: Serialize, + { + self.http_put(path, payload, None, None).await?; + Ok(()) + } + pub async fn list_permissions_in(&self, vhost: &str) -> Result> { let response = self .http_get(path!("vhosts", vhost, "permissions"), None, None) diff --git a/src/blocking_api.rs b/src/blocking_api.rs index 746d4eb..06bd2cb 100644 --- a/src/blocking_api.rs +++ b/src/blocking_api.rs @@ -230,44 +230,32 @@ where /// Lists cluster nodes. pub fn list_nodes(&self) -> Result> { - let response = self.http_get("nodes", None, None)?; - let response = response.json()?; - Ok(response) + self.get_api_request("nodes") } /// Lists virtual hosts in the cluster. pub fn list_vhosts(&self) -> Result> { - let response = self.http_get("vhosts", None, None)?; - let response = response.json()?; - Ok(response) + self.get_api_request("vhosts") } /// Lists users in the internal database. pub fn list_users(&self) -> Result> { - let response = self.http_get("users", None, None)?; - let response = response.json()?; - Ok(response) + self.get_api_request("users") } /// Lists users in the internal database that do not have access /// to any virtual hosts. pub fn list_users_without_permissions(&self) -> Result> { - let response = self.http_get("users/without-permissions", None, None)?; - let response = response.json()?; - Ok(response) + self.get_api_request("users/without-permissions") } /// Lists all AMQP 1.0 and 0-9-1 client connections across the cluster. pub fn list_connections(&self) -> Result> { - let response = self.http_get("connections", None, None)?; - let response = response.json()?; - Ok(response) + self.get_api_request("connections") } pub fn get_connection_info(&self, name: &str) -> Result { - let response = self.http_get(path!("connections", name), None, None)?; - let response = response.json()?; - Ok(response) + self.get_api_request(path!("connections", name)) } pub fn get_stream_connection_info( @@ -275,13 +263,7 @@ where virtual_host: &str, name: &str, ) -> Result { - let response = self.http_get( - path!("stream", "connections", virtual_host, name), - None, - None, - )?; - let response = response.json()?; - Ok(response) + self.get_api_request(path!("stream", "connections", virtual_host, name)) } pub fn close_connection(&self, name: &str, reason: Option<&str>) -> Result<()> { @@ -325,23 +307,17 @@ where /// Lists all connections in the given virtual host. pub fn list_connections_in(&self, virtual_host: &str) -> Result> { - let response = self.http_get(path!("vhosts", virtual_host, "connections"), None, None)?; - let response = response.json()?; - Ok(response) + self.get_api_request(path!("vhosts", virtual_host, "connections")) } /// Lists all connections of a specific user. pub fn list_user_connections(&self, username: &str) -> Result> { - let response = self.http_get(path!("connections", "username", username), None, None)?; - let response = response.json()?; - Ok(response) + self.get_api_request(path!("connections", "username", username)) } /// Lists all RabbitMQ Stream Protocol client connections across the cluster. pub fn list_stream_connections(&self) -> Result> { - let response = self.http_get("stream/connections", None, None)?; - let response = response.json()?; - Ok(response) + self.get_api_request("stream/connections") } /// Lists RabbitMQ Stream Protocol client connections in the given virtual host. @@ -349,32 +325,22 @@ where &self, virtual_host: &str, ) -> Result> { - let response = self.http_get(path!("stream", "connections", virtual_host), None, None)?; - let response = response.json()?; - Ok(response) + self.get_api_request(path!("stream", "connections", virtual_host)) } /// Lists all channels across the cluster. pub fn list_channels(&self) -> Result> { - let response = self.http_get("channels", None, None)?; - let response = response.json()?; - Ok(response) + self.get_api_request("channels") } /// Lists all channels in the given virtual host. pub fn list_channels_in(&self, virtual_host: &str) -> Result> { - let response = self.http_get(path!("vhosts", virtual_host, "channels"), None, None)?; - - let response = response.json()?; - Ok(response) + self.get_api_request(path!("vhosts", virtual_host, "channels")) } /// Lists all stream publishers across the cluster. pub fn list_stream_publishers(&self) -> Result> { - let response = self.http_get(path!("stream", "publishers"), None, None)?; - - let response = response.json()?; - Ok(response) + self.get_api_request(path!("stream", "publishers")) } /// Lists stream publishers publishing to the given stream. @@ -382,10 +348,7 @@ where &self, virtual_host: &str, ) -> Result> { - let response = self.http_get(path!("stream", "publishers", virtual_host), None, None)?; - - let response = response.json()?; - Ok(response) + self.get_api_request(path!("stream", "publishers", virtual_host)) } /// Lists stream publishers of the given stream. @@ -394,14 +357,7 @@ where virtual_host: &str, name: &str, ) -> Result> { - let response = self.http_get( - path!("stream", "publishers", virtual_host, name), - None, - None, - )?; - - let response = response.json()?; - Ok(response) + self.get_api_request(path!("stream", "publishers", virtual_host, name)) } /// Lists stream publishers on the given stream connection. @@ -410,22 +366,18 @@ where virtual_host: &str, name: &str, ) -> Result> { - let response = self.http_get( - path!("stream", "connections", virtual_host, name, "publishers"), - None, - None, - )?; - - let response = response.json()?; - Ok(response) + self.get_api_request(path!( + "stream", + "connections", + virtual_host, + name, + "publishers" + )) } /// Lists all stream consumers across the cluster. pub fn list_stream_consumers(&self) -> Result> { - let response = self.http_get(path!("stream", "consumers"), None, None)?; - - let response = response.json()?; - Ok(response) + self.get_api_request(path!("stream", "consumers")) } /// Lists stream consumers on connections in the given virtual host. @@ -433,10 +385,7 @@ where &self, virtual_host: &str, ) -> Result> { - let response = self.http_get(path!("stream", "consumers", virtual_host), None, None)?; - - let response = response.json()?; - Ok(response) + self.get_api_request(path!("stream", "consumers", virtual_host)) } /// Lists stream consumers on the given stream connection. @@ -445,56 +394,43 @@ where virtual_host: &str, name: &str, ) -> Result> { - let response = self.http_get( - path!("stream", "connections", virtual_host, name, "consumers"), - None, - None, - )?; - - let response = response.json()?; - Ok(response) + self.get_api_request(path!( + "stream", + "connections", + virtual_host, + name, + "consumers" + )) } /// Lists all queues and streams across the cluster. pub fn list_queues(&self) -> Result> { - let response = self.http_get("queues", None, None)?; - let response = response.json()?; - Ok(response) + self.get_api_request("queues") } /// Lists all queues and streams in the given virtual host. pub fn list_queues_in(&self, virtual_host: &str) -> Result> { - let response = self.http_get(path!("queues", virtual_host), None, None)?; - let response = response.json()?; - Ok(response) + self.get_api_request(path!("queues", virtual_host)) } /// Lists all exchanges across the cluster. pub fn list_exchanges(&self) -> Result> { - let response = self.http_get("exchanges", None, None)?; - let response = response.json()?; - Ok(response) + self.get_api_request("exchanges") } /// Lists all exchanges in the given virtual host. pub fn list_exchanges_in(&self, virtual_host: &str) -> Result> { - let response = self.http_get(path!("exchanges", virtual_host), None, None)?; - let response = response.json()?; - Ok(response) + self.get_api_request(path!("exchanges", virtual_host)) } /// Lists all bindings (both queue-to-exchange and exchange-to-exchange ones) across the cluster. pub fn list_bindings(&self) -> Result> { - let response = self.http_get("bindings", None, None)?; - let response = response.json()?; - Ok(response) + self.get_api_request("bindings") } /// Lists all bindings (both queue-to-exchange and exchange-to-exchange ones) in the given virtual host. pub fn list_bindings_in(&self, virtual_host: &str) -> Result> { - let response = self.http_get(path!("bindings", virtual_host), None, None)?; - let response = response.json()?; - Ok(response) + self.get_api_request(path!("bindings", virtual_host)) } /// Lists all bindings of a specific queue. @@ -503,10 +439,7 @@ where virtual_host: &str, queue: &str, ) -> Result> { - let response = - self.http_get(path!("queues", virtual_host, queue, "bindings"), None, None)?; - let response = response.json()?; - Ok(response) + self.get_api_request(path!("queues", virtual_host, queue, "bindings")) } /// Lists all bindings of a specific exchange where it is the source. @@ -537,51 +470,37 @@ where /// Lists all consumers across the cluster. pub fn list_consumers(&self) -> Result> { - let response = self.http_get("consumers", None, None)?; - let response = response.json()?; - Ok(response) + self.get_api_request("consumers") } /// Lists all consumers in the given virtual host. pub fn list_consumers_in(&self, virtual_host: &str) -> Result> { - let response = self.http_get(path!("consumers", virtual_host), None, None)?; - let response = response.json()?; - Ok(response) + self.get_api_request(path!("consumers", virtual_host)) } /// Returns information about a cluster node. pub fn get_node_info(&self, name: &str) -> Result { - let response = self.http_get(path!("nodes", name), None, None)?; - let response = response.json()?; - Ok(response) + self.get_api_request(path!("nodes", name)) } /// Returns information about a cluster node. pub fn get_node_memory_footprint(&self, name: &str) -> Result { - let response = self.http_get(path!("nodes", name, "memory"), None, None)?; - let response = response.json()?; - Ok(response) + self.get_api_request(path!("nodes", name, "memory")) } /// Returns information about a virtual host. pub fn get_vhost(&self, name: &str) -> Result { - let response = self.http_get(path!("vhosts", name), None, None)?; - let response = response.json()?; - Ok(response) + self.get_api_request(path!("vhosts", name)) } /// Returns information about a user in the internal database. pub fn get_user(&self, name: &str) -> Result { - let response = self.http_get(path!("users", name), None, None)?; - let response = response.json()?; - Ok(response) + self.get_api_request(path!("users", name)) } /// Returns information about a queue or stream. pub fn get_queue_info(&self, virtual_host: &str, name: &str) -> Result { - let response = self.http_get(path!("queues", virtual_host, name), None, None)?; - let response = response.json()?; - Ok(response) + self.get_api_request(path!("queues", virtual_host, name)) } /// Returns information about a stream. @@ -595,9 +514,7 @@ where virtual_host: &str, name: &str, ) -> Result { - let response = self.http_get(path!("exchanges", virtual_host, name), None, None)?; - let response = response.json()?; - Ok(response) + self.get_api_request(path!("exchanges", virtual_host, name)) } /// Creates a virtual host. @@ -611,36 +528,59 @@ where /// /// See [`VirtualHostParams`] pub fn update_vhost(&self, params: &VirtualHostParams) -> Result<()> { - let _response = self.http_put(path!("vhosts", params.name), params, None, None)?; - Ok(()) + self.put_api_request(path!("vhosts", params.name), params) } /// Adds a user to the internal database. /// /// See [`UserParams`] and [`crate::password_hashing`]. pub fn create_user(&self, params: &UserParams) -> Result<()> { - let _response = self.http_put(path!("users", params.name), params, None, None)?; - Ok(()) + self.put_api_request(path!("users", params.name), params) } pub fn declare_permissions(&self, params: &Permissions) -> Result<()> { - let _response = self.http_put( - // /api/permissions/vhost/user - path!("permissions", params.vhost, params.user), - params, - None, - None, - )?; - Ok(()) + self.put_api_request(path!("permissions", params.vhost, params.user), params) } pub fn grant_permissions(&self, vhost: &str, user: &str) -> Result<()> { - let _response = self.http_delete(path!("permissions", vhost, user), None, None)?; + self.http_delete(path!("permissions", vhost, user), None, None)?; Ok(()) } pub fn declare_queue(&self, vhost: &str, params: &QueueParams) -> Result<()> { - let _response = self.http_put(path!("queues", vhost, params.name), params, None, None)?; + self.put_api_request(path!("queues", vhost, params.name), params) + } + + // Helper methods for common patterns + fn get_api_request(&self, path: S) -> Result + where + T: serde::de::DeserializeOwned, + S: AsRef, + { + let response = self.http_get(path, None, None)?; + let response = response.json()?; + Ok(response) + } + + fn delete_api_request_with_optional_not_found(&self, path: S, idempotent: bool) -> Result<()> + where + S: AsRef, + { + let excludes = if idempotent { + Some(StatusCode::NOT_FOUND) + } else { + None + }; + self.http_delete(path, excludes, None)?; + Ok(()) + } + + fn put_api_request(&self, path: S, payload: &T) -> Result<()> + where + S: AsRef, + T: Serialize, + { + self.http_put(path, payload, None, None)?; Ok(()) } @@ -665,9 +605,7 @@ where } pub fn declare_exchange(&self, vhost: &str, params: &ExchangeParams) -> Result<()> { - let _response = - self.http_put(path!("exchanges", vhost, params.name), params, None, None)?; - Ok(()) + self.put_api_request(path!("exchanges", vhost, params.name), params) } pub fn bind_queue( @@ -721,23 +659,11 @@ where } pub fn delete_vhost(&self, vhost: &str, idempotently: bool) -> Result<()> { - let excludes = if idempotently { - Some(StatusCode::NOT_FOUND) - } else { - None - }; - let _response = self.http_delete(path!("vhosts", vhost), excludes, None)?; - Ok(()) + self.delete_api_request_with_optional_not_found(path!("vhosts", vhost), idempotently) } pub fn delete_user(&self, username: &str, idempotently: bool) -> Result<()> { - let excludes = if idempotently { - Some(StatusCode::NOT_FOUND) - } else { - None - }; - let _response = self.http_delete(path!("users", username), excludes, None)?; - Ok(()) + self.delete_api_request_with_optional_not_found(path!("users", username), idempotently) } pub fn delete_users(&self, usernames: Vec<&str>) -> Result<()> { @@ -747,23 +673,14 @@ where } pub fn clear_permissions(&self, vhost: &str, username: &str, idempotently: bool) -> Result<()> { - let excludes = if idempotently { - Some(StatusCode::NOT_FOUND) - } else { - None - }; - let _response = self.http_delete(path!("permissions", vhost, username), excludes, None)?; - Ok(()) + self.delete_api_request_with_optional_not_found( + path!("permissions", vhost, username), + idempotently, + ) } pub fn delete_queue(&self, vhost: &str, name: &str, idempotently: bool) -> Result<()> { - let excludes = if idempotently { - Some(StatusCode::NOT_FOUND) - } else { - None - }; - let _response = self.http_delete(path!("queues", vhost, name), excludes, None)?; - Ok(()) + self.delete_api_request_with_optional_not_found(path!("queues", vhost, name), idempotently) } pub fn delete_stream(&self, vhost: &str, name: &str, idempotently: bool) -> Result<()> { @@ -771,13 +688,10 @@ where } pub fn delete_exchange(&self, vhost: &str, name: &str, idempotently: bool) -> Result<()> { - let excludes = if idempotently { - Some(StatusCode::NOT_FOUND) - } else { - None - }; - let _response = self.http_delete(path!("exchanges", vhost, name), excludes, None)?; - Ok(()) + self.delete_api_request_with_optional_not_found( + path!("exchanges", vhost, name), + idempotently, + ) } pub fn delete_binding( @@ -1077,7 +991,7 @@ where /// as many HTTP API requests as there are policies to declare. pub fn declare_policies(&self, params: Vec<&PolicyParams>) -> Result<()> { for p in params { - let _response = self.http_put(path!("policies", p.vhost, p.name), p, None, None)?; + self.declare_policy(p)?; } Ok(()) } @@ -1095,11 +1009,7 @@ where /// as many HTTP API requests as there are policies to delete. pub fn delete_policies_in(&self, vhost: &str, names: Vec<&str>) -> Result<()> { for name in names { - let _response = self.http_delete( - path!("policies", vhost, name), - Some(StatusCode::NOT_FOUND), - None, - )?; + self.delete_policy(vhost, name)?; } Ok(()) } @@ -1136,8 +1046,7 @@ where /// as many HTTP API requests as there are operator policies to declare. pub fn declare_operator_policies(&self, params: Vec<&PolicyParams>) -> Result<()> { for p in params { - let _response = - self.http_put(path!("operator-policies", p.vhost, p.name), p, None, None)?; + self.declare_operator_policy(p)?; } Ok(()) } @@ -1155,11 +1064,7 @@ where /// as many HTTP API requests as there are operator policies to delete. pub fn delete_operator_policies_in(&self, vhost: &str, names: Vec<&str>) -> Result<()> { for name in names { - let _response = self.http_delete( - path!("operator-policies", vhost, name), - Some(StatusCode::NOT_FOUND), - None, - )?; + self.delete_operator_policy(vhost, name)?; } Ok(()) } diff --git a/tests/async_definitions_tests.rs b/tests/async_definitions_tests.rs index be91bff..67796f8 100644 --- a/tests/async_definitions_tests.rs +++ b/tests/async_definitions_tests.rs @@ -104,9 +104,6 @@ async fn test_async_export_cluster_wide_definitions_as_data() { "expected more than zero exchanges in definitions" ); - let u_found = defs.users.iter().any(|x| x.name == "rust3"); - assert!(u_found, "expected to find user {} in definitions", "rust3"); - let x_found = defs.exchanges.iter().any(|x| x.name == x_name); assert!(x_found, "expected to find exchange {x_name} in definitions"); diff --git a/tests/blocking_definitions_tests.rs b/tests/blocking_definitions_tests.rs index 79b478e..23f00f8 100644 --- a/tests/blocking_definitions_tests.rs +++ b/tests/blocking_definitions_tests.rs @@ -97,9 +97,6 @@ fn test_blocking_export_cluster_wide_definitions_as_data() { "expected more than zero exchanges in definitions" ); - let u_found = defs.users.iter().any(|x| x.name == "rust3"); - assert!(u_found, "expected to find user {} in definitions", "rust3"); - let x_found = defs.exchanges.iter().any(|x| x.name == x_name); assert!(x_found, "expected to find exchange {x_name} in definitions"); From 1c4366e75346bcc6f49ab24aff1bf137dd586aff Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 14 Jul 2025 20:32:04 -0400 Subject: [PATCH 31/47] Bump dependencies --- Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a38744b..16632d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,12 +29,12 @@ reqwest = { version = "0.12", default-features = false, features = [ ], optional = true } backtrace = { version = "0.3", optional = true } thiserror = { version = "2", optional = true } -tokio = "1.44" -time = { version = "0.3.40", features = ["serde-human-readable"] } +tokio = "1.46" +time = { version = "0.3.41", features = ["serde-human-readable"] } [dev-dependencies] amqprs = { version = "2" } -cargo-nextest = "0.9.92" +cargo-nextest = "0.9.101" [features] default = ["blocking", "default-tls"] From 5df5e37f1c9f1f5ec10ee14b12cba4be7c6c454b Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 14 Jul 2025 20:40:23 -0400 Subject: [PATCH 32/47] Add .github/dependabot.yml --- .github/dependabot.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..90a0d1c --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +version: 2 +updates: + - package-ecosystem: "cargo" + directory: "/" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + reviewers: + - "michaelklishin" + assignees: + - "michaelklishin" From 7c7f50796b57437ef8505ae12892474eb52ba361 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 14 Jul 2025 22:19:44 -0400 Subject: [PATCH 33/47] Refactoring --- src/formatting.rs | 197 +++++++++++++++------------------------------- 1 file changed, 62 insertions(+), 135 deletions(-) diff --git a/src/formatting.rs b/src/formatting.rs index 56fc0f8..8a1ee3a 100644 --- a/src/formatting.rs +++ b/src/formatting.rs @@ -29,8 +29,7 @@ impl Display for ObjectTotals { impl Display for Rate { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - writeln!(f, "{:.2}", self.rate)?; - Ok(()) + write!(f, "{:.2}", self.rate) } } @@ -97,10 +96,9 @@ impl Display for TagMap { impl Display for DeprecatedFeatureList { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for df in &self.0 { - writeln!(f, "{df}")?; + for name in &self.0 { + writeln!(f, "{name}")?; } - Ok(()) } } @@ -141,30 +139,30 @@ impl Display for FeatureFlag { impl Display for FeatureFlagList { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for ff in &self.0 { - writeln!(f, "{ff}")?; + for item in &self.0 { + writeln!(f, "{item}")?; } - Ok(()) } } impl Display for MessageList { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for msg in &self.0 { - writeln!(f, "{msg}")?; + for item in &self.0 { + writeln!(f, "{item}")?; } - Ok(()) } } impl Display for MessageRouted { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.routed { - true => write!(f, "Message published and routed successfully"), - false => write!(f, "Message published but NOT routed"), - } + let message = if self.routed { + "Message published and routed successfully" + } else { + "Message published but NOT routed" + }; + write!(f, "{}", message) } } @@ -188,28 +186,24 @@ impl Display for GetMessage { impl Display for SchemaDefinitionSyncState { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - SchemaDefinitionSyncState::Recover => writeln!(f, "recover")?, - SchemaDefinitionSyncState::Connected => writeln!(f, "connected")?, - SchemaDefinitionSyncState::PublisherInitialized => { - writeln!(f, "publisher initialized")? - } - SchemaDefinitionSyncState::Syncing => writeln!(f, "syncing")?, - SchemaDefinitionSyncState::Disconnected => writeln!(f, "disconnected")?, - } - - Ok(()) + let state = match self { + SchemaDefinitionSyncState::Recover => "recover", + SchemaDefinitionSyncState::Connected => "connected", + SchemaDefinitionSyncState::PublisherInitialized => "publisher initialized", + SchemaDefinitionSyncState::Syncing => "syncing", + SchemaDefinitionSyncState::Disconnected => "disconnected", + }; + write!(f, "{}", state) } } impl Display for OperatingMode { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - OperatingMode::Upstream => writeln!(f, "upstream")?, - OperatingMode::Downstream => writeln!(f, "downstream")?, - } - - Ok(()) + let mode = match self { + OperatingMode::Upstream => "upstream", + OperatingMode::Downstream => "downstream", + }; + write!(f, "{}", mode) } } @@ -219,75 +213,31 @@ impl Display for HostnamePortPairs { } } -#[allow(dead_code)] -pub fn fmt_list_as_json_array(f: &mut fmt::Formatter<'_>, xs: &[String]) -> fmt::Result { - match xs.len() { - 0 => { - write!(f, "[]") - } - _ => { - write!(f, "[")?; - let mut xs = xs.to_owned(); - let last_element = xs.pop().unwrap(); - for elem in xs { - write!(f, "{elem}, ")?; - } - write!(f, "{last_element}")?; - write!(f, "]")?; - Ok(()) +pub fn fmt_list( + f: &mut fmt::Formatter<'_>, + items: &[T], + separator: &str, + prefix: &str, +) -> fmt::Result { + for (i, item) in items.iter().enumerate() { + if i > 0 { + write!(f, "{}", separator)?; } + write!(f, "{}{}", prefix, item)?; } + Ok(()) } pub fn fmt_comma_separated_list(f: &mut fmt::Formatter<'_>, xs: &[String]) -> fmt::Result { - match xs.len() { - 0 => { - write!(f, "") - } - _ => { - let mut xs = xs.to_owned(); - let last_element = xs.pop().unwrap(); - for elem in xs { - write!(f, "{elem}, ")?; - } - write!(f, "{last_element}")?; - Ok(()) - } - } + fmt_list(f, xs, ", ", "") } pub fn fmt_vertical_list_with_bullets(f: &mut fmt::Formatter<'_>, xs: &[String]) -> fmt::Result { - match xs.len() { - 0 => { - write!(f, "") - } - _ => { - let mut xs = xs.to_owned(); - let last_element = xs.pop().unwrap(); - for elem in xs { - writeln!(f, "* {elem}")?; - } - write!(f, "* {last_element}")?; - Ok(()) - } - } + fmt_list(f, xs, "\n", "* ") } pub fn fmt_vertical_list_without_bullets(f: &mut fmt::Formatter<'_>, xs: &[String]) -> fmt::Result { - match xs.len() { - 0 => { - write!(f, "") - } - _ => { - let mut xs = xs.to_owned(); - let last_element = xs.pop().unwrap(); - for elem in xs { - writeln!(f, "{elem}")?; - } - write!(f, "{last_element}")?; - Ok(()) - } - } + fmt_list(f, xs, "\n", "") } pub fn fmt_map_as_colon_separated_pairs( @@ -301,61 +251,38 @@ pub fn fmt_map_as_colon_separated_pairs( Ok(()) } -pub fn display_option(opt: &Option) -> String -where - T: Display, -{ - match opt { - None => "".to_owned(), - Some(val) => format!("{val}").to_owned(), - } +pub fn display_option(opt: &Option) -> String { + opt.as_ref().map_or_else(String::new, |val| val.to_string()) } pub fn display_option_details_rate(opt: &Option) -> String { - match opt { - None => "".to_owned(), - Some(val) => format!("{}", val.rate).to_owned(), - } + opt.as_ref() + .map_or_else(String::new, |val| val.rate.to_string()) } pub fn display_arg_table(xs: &XArguments) -> String { - let mut s = String::new(); - for (k, v) in xs.0.iter() { - let line = format!("{k}: {v}\n"); - s += line.as_str() - } - - s.clone() + xs.0.iter() + .map(|(k, v)| format!("{k}: {v}")) + .collect::>() + .join("\n") } pub fn display_tag_map_option(opt: &Option) -> String { - match opt { - Some(val) => { - let mut s = String::new(); - let iter = val.0.clone().into_iter(); - for (k, v) in iter { - let line = format!("\"{k}\": {v}\n"); - s += line.as_str() - } - - s.clone() - } - None => "".to_owned(), - } + opt.as_ref().map_or_else(String::new, |val| { + val.0 + .iter() + .map(|(k, v)| format!("\"{k}\": {v}")) + .collect::>() + .join("\n") + }) } pub fn display_tag_list_option(opt: &Option) -> String { - match opt { - Some(val) => { - let mut s = String::new(); - let iter = val.0.clone().into_iter(); - for t in iter { - let line = format!("{t}\n"); - s += line.as_str() - } - - s.clone() - } - None => "".to_owned(), - } + opt.as_ref().map_or_else(String::new, |val| { + val.0 + .iter() + .map(|t| t.to_string()) + .collect::>() + .join("\n") + }) } From d8ce52a8db7081014823d57390a2de0f14c64acc Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 14 Jul 2025 22:31:17 -0400 Subject: [PATCH 34/47] Refactoring --- src/commons.rs | 85 +++++------------------------------------ src/password_hashing.rs | 32 ++++++++++------ 2 files changed, 29 insertions(+), 88 deletions(-) diff --git a/src/commons.rs b/src/commons.rs index a85095a..1e09e93 100644 --- a/src/commons.rs +++ b/src/commons.rs @@ -143,7 +143,7 @@ impl From<&str> for SupportedProtocol { impl From for SupportedProtocol { fn from(value: String) -> Self { - SupportedProtocol::from(value.as_str()) + Self::from(value.as_str()) } } @@ -190,49 +190,13 @@ impl From for String { impl From<&SupportedProtocol> for String { fn from(value: &SupportedProtocol) -> Self { - match value { - SupportedProtocol::Clustering => SUPPORTED_PROTOCOL_CLUSTERING.to_owned(), - SupportedProtocol::AMQP => SUPPORTED_PROTOCOL_AMQP.to_owned(), - SupportedProtocol::AMQPWithTLS => SUPPORTED_PROTOCOL_AMQP_WITH_TLS.to_owned(), - SupportedProtocol::Stream => SUPPORTED_PROTOCOL_STREAM.to_owned(), - SupportedProtocol::StreamWithTLS => SUPPORTED_PROTOCOL_STREAM_WITH_TLS.to_owned(), - SupportedProtocol::MQTT => SUPPORTED_PROTOCOL_MQTT.to_owned(), - SupportedProtocol::MQTTWithTLS => SUPPORTED_PROTOCOL_MQTT_WITH_TLS.to_owned(), - SupportedProtocol::STOMP => SUPPORTED_PROTOCOL_STOMP.to_owned(), - SupportedProtocol::STOMPWithTLS => SUPPORTED_PROTOCOL_STOMP_WITH_TLS.to_owned(), - SupportedProtocol::AMQPOverWebSockets => { - SUPPORTED_PROTOCOL_AMQP_OVER_WEBSOCKETS.to_owned() - } - SupportedProtocol::AMQPOverWebSocketsWithTLS => { - SUPPORTED_PROTOCOL_AMQP_OVER_WEBSOCKETS_WITH_TLS.to_owned() - } - SupportedProtocol::MQTTOverWebSockets => { - SUPPORTED_PROTOCOL_MQTT_OVER_WEBSOCKETS.to_owned() - } - SupportedProtocol::MQTTOverWebSocketsWithTLS => { - SUPPORTED_PROTOCOL_MQTT_OVER_WEBSOCKETS_WITH_TLS.to_owned() - } - SupportedProtocol::STOMPOverWebsockets => { - SUPPORTED_PROTOCOL_STOMP_OVER_WEBSOCKETS.to_owned() - } - SupportedProtocol::STOMPOverWebsocketsWithTLS => { - SUPPORTED_PROTOCOL_STOMP_OVER_WEBSOCKETS_WITH_TLS.to_owned() - } - SupportedProtocol::Prometheus => SUPPORTED_PROTOCOL_PROMETHEUS.to_owned(), - SupportedProtocol::PrometheusWithTLS => { - SUPPORTED_PROTOCOL_PROMETHEUS_WITH_TLS.to_owned() - } - SupportedProtocol::HTTP => SUPPORTED_PROTOCOL_HTTP.to_owned(), - SupportedProtocol::HTTPWithTLS => SUPPORTED_PROTOCOL_HTTP_WITH_TLS.to_owned(), - SupportedProtocol::Other(s) => (*s).clone(), - } + value.clone().into() } } impl fmt::Display for SupportedProtocol { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let proto: String = self.into(); - write!(f, "{proto}") + write!(f, "{}", String::from(self)) } } @@ -316,7 +280,7 @@ impl From<&str> for ExchangeType { impl From for ExchangeType { fn from(value: String) -> Self { - ExchangeType::from(value.as_str()) + Self::from(value.as_str()) } } @@ -381,13 +345,7 @@ impl From<&str> for QueueType { impl From for QueueType { fn from(value: String) -> Self { - let val = value.to_ascii_lowercase(); - match val.as_str() { - "classic" => QueueType::Classic, - "quorum" => QueueType::Quorum, - "stream" => QueueType::Stream, - _ => QueueType::Unsupported(value), - } + Self::from(value.as_str()) } } @@ -444,11 +402,7 @@ impl From<&str> for BindingDestinationType { impl From for BindingDestinationType { fn from(value: String) -> Self { - match value.as_str() { - "queue" => BindingDestinationType::Queue, - "exchange" => BindingDestinationType::Exchange, - _ => BindingDestinationType::Queue, - } + Self::from(value.as_str()) } } @@ -568,20 +522,7 @@ impl From<&str> for PolicyTarget { impl From for PolicyTarget { fn from(value: String) -> Self { - match value.as_str() { - "queues" => PolicyTarget::Queues, - "queue" => PolicyTarget::Queues, - "classic_queues" => PolicyTarget::ClassicQueues, - "classic_queue" => PolicyTarget::ClassicQueues, - "quorum_queues" => PolicyTarget::QuorumQueues, - "quorum_queue" => PolicyTarget::QuorumQueues, - "streams" => PolicyTarget::Streams, - "stream" => PolicyTarget::Streams, - "exchanges" => PolicyTarget::Exchanges, - "exchange" => PolicyTarget::Exchanges, - "all" => PolicyTarget::All, - _ => PolicyTarget::Queues, - } + Self::from(value.as_str()) } } @@ -626,11 +567,7 @@ impl From<&str> for VirtualHostLimitTarget { impl From for VirtualHostLimitTarget { fn from(value: String) -> Self { - match value.as_str() { - "max-connections" => VirtualHostLimitTarget::MaxConnections, - "max-queues" => VirtualHostLimitTarget::MaxQueues, - _ => VirtualHostLimitTarget::MaxConnections, - } + Self::from(value.as_str()) } } @@ -668,11 +605,7 @@ impl From<&str> for UserLimitTarget { impl From for UserLimitTarget { fn from(value: String) -> Self { - match value.as_str() { - "max-connections" => UserLimitTarget::MaxConnections, - "max-channels" => UserLimitTarget::MaxChannels, - _ => UserLimitTarget::MaxConnections, - } + Self::from(value.as_str()) } } diff --git a/src/password_hashing.rs b/src/password_hashing.rs index 7dd6b04..988572b 100644 --- a/src/password_hashing.rs +++ b/src/password_hashing.rs @@ -45,14 +45,28 @@ pub fn salted_password_hash_sha512(salt: &[u8], password: &str) -> Vec { salted_password_hash(salt, password, &SHA512) } +/// Produces a Base64-encoded, salted password hash using the specified algorithm. /// -/// Produces a Base64-encoded, SHA-256 hashed, salted passowrd hash that can be passed +/// See the [Credentials and Passwords guide](https://rabbitmq.com/docs/passwords/). +pub fn base64_encoded_salted_password_hash( + salt: &[u8], + password: &str, + algorithm: &HashingAlgorithm, +) -> String { + let salted = match algorithm { + HashingAlgorithm::SHA256 => salted_password_hash_sha256(salt, password), + HashingAlgorithm::SHA512 => salted_password_hash_sha512(salt, password), + }; + rbase64::encode(salted.as_slice()) +} + +/// +/// Produces a Base64-encoded, SHA-256 hashed, salted password hash that can be passed /// as [`crate::requests::UserParams::password_hash`] when adding a user with [`crate::blocking_api::Client::create_user`]. /// /// See the [Credentials and Passwords guide](https://rabbitmq.com/docs/passwords/). pub fn base64_encoded_salted_password_hash_sha256(salt: &[u8], password: &str) -> String { - let salted = salted_password_hash_sha256(salt, password); - rbase64::encode(salted.as_slice()) + base64_encoded_salted_password_hash(salt, password, &HashingAlgorithm::SHA256) } /// @@ -61,8 +75,7 @@ pub fn base64_encoded_salted_password_hash_sha256(salt: &[u8], password: &str) - /// /// See the [Credentials and Passwords guide](https://rabbitmq.com/docs/passwords/). pub fn base64_encoded_salted_password_hash_sha512(salt: &[u8], password: &str) -> String { - let salted = salted_password_hash_sha512(salt, password); - rbase64::encode(salted.as_slice()) + base64_encoded_salted_password_hash(salt, password, &HashingAlgorithm::SHA512) } #[derive(Clone, Default, PartialEq, Eq, Hash, Debug)] @@ -109,13 +122,8 @@ pub enum HashingError { } impl HashingAlgorithm { - pub fn salt_and_hash(&self, salt: &[u8], password: &str) -> Result, HashingError> { - let hash = match self { - HashingAlgorithm::SHA256 => salted_password_hash_sha256(salt, password), - HashingAlgorithm::SHA512 => salted_password_hash_sha512(salt, password), - }; - let encoded = rbase64::encode(hash.as_slice()); - Ok(encoded.as_bytes().to_vec()) + pub fn salt_and_hash(&self, salt: &[u8], password: &str) -> Result { + Ok(base64_encoded_salted_password_hash(salt, password, self)) } } From 87f611d0ac7584d21d7882eba551b4f43cb90a9f Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 16 Jul 2025 13:41:35 -0400 Subject: [PATCH 35/47] Minor doc improvements --- .cargo/config.toml | 2 ++ src/password_hashing.rs | 56 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 .cargo/config.toml diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..d329003 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[doc] +all-features = true diff --git a/src/password_hashing.rs b/src/password_hashing.rs index 988572b..413e2a6 100644 --- a/src/password_hashing.rs +++ b/src/password_hashing.rs @@ -11,6 +11,16 @@ // 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. + +//! Functions that calculate salted password hash values the same way RabbitMQ +//! nodes do it. +//! +//! Use this module if you need to calculate a password hash for a `crate::requests::UserParams` +//! object that you pass to [`crate::api::Client::create_user`] or [`crate::blocking_api::Client::create_user`]. +//! +//! See the [Credentials and Passwords guide](https://rabbitmq.com/docs/passwords/). +//! + use rand::RngCore; use ring::digest::{Context, SHA256, SHA512}; use std::fmt; @@ -78,10 +88,19 @@ pub fn base64_encoded_salted_password_hash_sha512(salt: &[u8], password: &str) - base64_encoded_salted_password_hash(salt, password, &HashingAlgorithm::SHA512) } +/// Supported hashing algorithms for password salting and hashing. +/// +/// This enum represents the cryptographic hash algorithms that can be used +/// for password hashing in RabbitMQ user management. SHA-256 is the default +/// algorithm and is recommended for most use cases. +/// +/// See the [Credentials and Passwords guide](https://rabbitmq.com/docs/passwords/). #[derive(Clone, Default, PartialEq, Eq, Hash, Debug)] pub enum HashingAlgorithm { + /// SHA-256 hashing algorithm (default) #[default] SHA256, + /// SHA-512 hashing algorithm SHA512, // Unlike RabbitMQ that accepts module implementations via configuration, // we cannot support salting and hashing for arbitrary algorithm names, @@ -98,6 +117,13 @@ impl fmt::Display for HashingAlgorithm { } impl From<&str> for HashingAlgorithm { + /// Converts a string slice to a `HashingAlgorithm`. + /// + /// Supported string values (case-insensitive): + /// - "SHA256" or "SHA-256" → `HashingAlgorithm::SHA256` + /// - "SHA512" or "SHA-512" → `HashingAlgorithm::SHA512` + /// + /// Any other value defaults to `HashingAlgorithm::SHA256`. fn from(s: &str) -> Self { match s.to_uppercase().as_str() { "SHA256" => HashingAlgorithm::SHA256, @@ -115,13 +141,43 @@ impl From for HashingAlgorithm { } } +/// Errors that can occur during password hashing operations. #[derive(Error, Debug)] pub enum HashingError { + /// The specified hashing algorithm is not supported. #[error("Provided algorithm is not supported")] UnsupportedAlgorithm, } impl HashingAlgorithm { + /// Generates a Base64-encoded, salted password hash from a clear text password value. + /// Use this function to produce a password hash to be passed to `` + /// + /// This method combines the salt with the password and applies the hash algorithm + /// specified by this enum variant, then returns the result as a Base64-encoded string. + /// + /// # Arguments + /// + /// * `salt`: a byte slice containing the salt to use for hashing + /// * `password`: the plaintext password to hash + /// + /// # Returns + /// + /// A `Result` containing either: + /// - `Ok(String)`: the Base64-encoded salted password hash + /// - `Err(HashingError)`: tn error if the algorithm is not supported + /// + /// # Examples + /// + /// ```rust + /// use rabbitmq_http_client::password_hashing::{HashingAlgorithm, salt}; + /// + /// let salt = salt(); + /// let algorithm = HashingAlgorithm::SHA256; + /// let hash = algorithm.salt_and_hash(&salt, "a_cleartext_password").unwrap(); + /// ``` + /// + /// See the [Credentials and Passwords guide](https://rabbitmq.com/docs/passwords/). pub fn salt_and_hash(&self, salt: &[u8], password: &str) -> Result { Ok(base64_encoded_salted_password_hash(salt, password, self)) } From 3b4f8f773c55bf6f919345efecddc0a9c2581bfd Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 17 Jul 2025 12:57:22 -0400 Subject: [PATCH 36/47] Implement Default for a number of structs in responses without these defaults, a request that hits a freshly booted RabbitMQ node would panic because one of the metrics/rates fields would be missing, because some statistics tracking events haven't yet happened. --- src/responses.rs | 41 +++++++++++++++++++++---------------- tests/unit_default_tests.rs | 24 ++++++++++++++++++++++ 2 files changed, 47 insertions(+), 18 deletions(-) create mode 100644 tests/unit_default_tests.rs diff --git a/src/responses.rs b/src/responses.rs index d117d2a..a52a08a 100644 --- a/src/responses.rs +++ b/src/responses.rs @@ -1864,7 +1864,8 @@ pub struct MessageRouted { #[serde(transparent)] pub struct MessageProperties(pub Map); -#[derive(Debug, Deserialize, Clone, Eq, PartialEq)] +#[derive(Debug, Deserialize, Clone, Eq, PartialEq, Default)] +#[serde(default)] #[cfg_attr(feature = "tabled", derive(Tabled))] pub struct ChurnRates { pub connection_created: u32, @@ -1876,13 +1877,15 @@ pub struct ChurnRates { pub channel_closed: u32, } -#[derive(Debug, Deserialize, Clone, PartialEq, PartialOrd)] +#[derive(Debug, Deserialize, Clone, PartialEq, PartialOrd, Default)] +#[serde(default)] #[cfg_attr(feature = "tabled", derive(Tabled))] pub struct Rate { pub rate: f64, } -#[derive(Debug, Deserialize, Clone, Eq, PartialEq)] +#[derive(Debug, Deserialize, Clone, Eq, PartialEq, Default)] +#[serde(default)] #[cfg_attr(feature = "tabled", derive(Tabled))] pub struct ObjectTotals { pub connections: u64, @@ -1892,50 +1895,51 @@ pub struct ObjectTotals { pub consumers: u64, } -#[derive(Debug, Deserialize, Clone, PartialEq)] +#[derive(Debug, Deserialize, Clone, PartialEq, Default)] +#[serde(default)] #[cfg_attr(feature = "tabled", derive(Tabled))] pub struct QueueTotals { pub messages: u64, - #[serde(rename = "messages_ready")] + #[serde(rename = "messages_ready", default)] pub messages_ready_for_delivery: u64, - #[serde(rename = "messages_unacknowledged")] + #[serde(rename = "messages_unacknowledged", default)] pub messages_delivered_but_unacknowledged_by_consumers: u64, pub messages_details: Rate, - #[serde(rename = "messages_ready_details")] + #[serde(rename = "messages_ready_details", default)] pub messages_ready_for_delivery_details: Rate, - #[serde(rename = "messages_unacknowledged_details")] + #[serde(rename = "messages_unacknowledged_details", default)] pub messages_delivered_but_unacknowledged_by_consumers_details: Rate, } -#[derive(Debug, Deserialize, Clone, PartialEq)] +#[derive(Debug, Deserialize, Clone, PartialEq, Default)] #[cfg_attr(feature = "tabled", derive(Tabled))] pub struct MessageStats { /// Consumer delivery rate plus polling (via 'basic.get') rate - #[serde(rename = "deliver_get_details")] + #[serde(rename = "deliver_get_details", default)] #[cfg_attr(feature = "tabled", tabled(display = "display_option"))] pub delivery_details: Option, - #[serde(rename = "publish_details")] + #[serde(rename = "publish_details", default)] #[cfg_attr(feature = "tabled", tabled(display = "display_option"))] pub publishing_details: Option, - #[serde(rename = "deliver_no_ack_details")] + #[serde(rename = "deliver_no_ack_details", default)] #[cfg_attr(feature = "tabled", tabled(display = "display_option"))] pub delivery_with_automatic_acknowledgement_details: Option, - #[serde(rename = "redeliver_details")] + #[serde(rename = "redeliver_details", default)] #[cfg_attr(feature = "tabled", tabled(display = "display_option"))] pub redelivery_details: Option, - #[serde(rename = "confirm_details")] + #[serde(rename = "confirm_details", default)] #[cfg_attr(feature = "tabled", tabled(display = "display_option"))] pub publisher_confirmation_details: Option, - #[serde(rename = "ack_details")] + #[serde(rename = "ack_details", default)] #[cfg_attr(feature = "tabled", tabled(display = "display_option"))] pub consumer_acknowledgement_details: Option, - #[serde(rename = "drop_unroutable_details")] + #[serde(rename = "drop_unroutable_details", default)] #[cfg_attr(feature = "tabled", tabled(display = "display_option"))] pub unroutable_dropped_message_details: Option, - #[serde(rename = "return_unroutable_details")] + #[serde(rename = "return_unroutable_details", default)] #[cfg_attr(feature = "tabled", tabled(display = "display_option"))] pub unroutable_returned_message_details: Option, } @@ -1954,7 +1958,8 @@ pub struct Listener { #[serde(transparent)] pub struct TagMap(pub Map); -#[derive(Debug, Deserialize, Clone, PartialEq)] +#[derive(Debug, Deserialize, Clone, PartialEq, Default)] +#[serde(default)] #[cfg_attr(feature = "tabled", derive(Tabled))] pub struct Overview { pub cluster_name: String, diff --git a/tests/unit_default_tests.rs b/tests/unit_default_tests.rs new file mode 100644 index 0000000..5841586 --- /dev/null +++ b/tests/unit_default_tests.rs @@ -0,0 +1,24 @@ +// Copyright (C) 2023-2025 RabbitMQ Core Team (teamrabbitmq@gmail.com) +// +// Licensed 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. +mod test_helpers; + +use rabbitmq_http_client::responses::Rate; + +#[test] +fn test_unit_default_rate() { + let def = Rate::default(); + + // Specifically for this test, we don't really need to use `approx` + assert_eq!(def.rate, 0.0); +} \ No newline at end of file From 49d596923d1b017d45d4bdc84e3aa7ae6d82ef21 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 17 Jul 2025 12:58:32 -0400 Subject: [PATCH 37/47] 0.40.0 --- CHANGELOG.md | 12 +++++++++++- README.md | 8 ++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5670e4..1fc2b90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,19 @@ # Rust Client for the RabbitMQ HTTP API Change Log -## v0.40.0 (in development) +## v0.41.0 (in development) No changes yet. + +## v0.40.0 (Jul 17, 2025) + +### Enhancements + + * Several structs in `responses` now implement `Default`, in particular for deserialization, + and can handle the cases with certain metrics missing at request time on a freshly booted + RabbitMQ node + + ## v0.39.0 (Jul 14, 2025) ### Enhancements diff --git a/README.md b/README.md index edb8f22..748c0bc 100644 --- a/README.md +++ b/README.md @@ -14,25 +14,25 @@ This library is relatively young, breaking API changes are possible. ### Blocking Client ```toml -rabbitmq_http_client = { version = "0.39.0", features = ["core", "blocking"] } +rabbitmq_http_client = { version = "0.40.0", features = ["core", "blocking"] } ``` ### Async Client ```toml -rabbitmq_http_client = { version = "0.39.0", features = ["core", "async"] } +rabbitmq_http_client = { version = "0.40.0", features = ["core", "async"] } ``` ### Blocking Client with Tabled Support ```toml -rabbitmq_http_client = { version = "0.39.0", features = ["core", "blocking", "tabled"] } +rabbitmq_http_client = { version = "0.40.0", features = ["core", "blocking", "tabled"] } ``` ### Async Client with Tabled Support ```toml -rabbitmq_http_client = { version = "0.39.0", features = ["core", "async", "tabled"] } +rabbitmq_http_client = { version = "0.40.0", features = ["core", "async", "tabled"] } ``` From 94507dfcc4f35b45f8f2e5ef78fd9a4fc8acfbaf Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 17 Jul 2025 19:31:05 -0400 Subject: [PATCH 38/47] Fix cargo fmt --all --check --- tests/unit_default_tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit_default_tests.rs b/tests/unit_default_tests.rs index 5841586..ae8a393 100644 --- a/tests/unit_default_tests.rs +++ b/tests/unit_default_tests.rs @@ -21,4 +21,4 @@ fn test_unit_default_rate() { // Specifically for this test, we don't really need to use `approx` assert_eq!(def.rate, 0.0); -} \ No newline at end of file +} From 20bffbb79fb068909b16edd1513651a36eacbb2b Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 4 Aug 2025 12:50:54 -0400 Subject: [PATCH 39/47] Minor test improvements GET /api/deprecated-features/used can return a value this library won't be able to parse at the moment, but the period of time is very short. The same feature is tested by `rabbitmqadmin`, so we can afford to modify the test to be less brittle. --- tests/async_definitions_tests.rs | 18 ++++++++------ tests/async_deprecated_feature_tests.rs | 29 +++++++++++++--------- tests/blocking_definitions_tests.rs | 10 ++++---- tests/blocking_deprecated_feature_tests.rs | 22 +++++++++------- 4 files changed, 46 insertions(+), 33 deletions(-) diff --git a/tests/async_definitions_tests.rs b/tests/async_definitions_tests.rs index 67796f8..4362a4c 100644 --- a/tests/async_definitions_tests.rs +++ b/tests/async_definitions_tests.rs @@ -214,12 +214,13 @@ async fn test_async_export_vhost_definitions_as_data() { async fn test_async_import_cluster_definitions() { let endpoint = endpoint(); let rc = Client::new(&endpoint, USERNAME, PASSWORD); - let _ = rc.delete_queue("/", "imported_queue", false).await; + let queue_name = "test_async_import_cluster_definitions"; + let _ = rc.delete_queue("/", queue_name, false).await; let defs = json!({ "queues": [ { "auto_delete": false, "durable": true, - "name": "imported_queue", + "name": queue_name, "vhost": "/" } ]}); @@ -230,8 +231,11 @@ async fn test_async_import_cluster_definitions() { "import_cluster_wide_definitions returned {result:?}" ); - let result1 = rc.get_queue_info("/", "imported_queue").await; - assert!(result1.is_ok(), "can't get the imported queue: {result1:?}"); + let result1 = rc.get_queue_info("/", queue_name).await; + assert!( + result1.is_ok(), + "an important queue '{queue_name}' is missing: {result1:?}" + ); } #[tokio::test] @@ -245,12 +249,12 @@ async fn test_async_import_vhost_definitions() { let vh_params = VirtualHostParams::named(vh); rc.create_vhost(&vh_params).await.unwrap(); - let q = "imported_queue"; + let queue_name = "test_async_import_vhost_definitions"; let defs = json!({ "queues": [ { "auto_delete": false, "durable": true, - "name": q, + "name": queue_name, } ]}); @@ -262,7 +266,7 @@ async fn test_async_import_vhost_definitions() { await_queue_metric_emission(); - let result1 = rc.get_queue_info(vh, q).await; + let result1 = rc.get_queue_info(vh, queue_name).await; assert!(result1.is_ok(), "can't get the imported queue: {result1:?}"); rc.delete_vhost(vh, true).await.unwrap(); diff --git a/tests/async_deprecated_feature_tests.rs b/tests/async_deprecated_feature_tests.rs index ffb4212..3836884 100644 --- a/tests/async_deprecated_feature_tests.rs +++ b/tests/async_deprecated_feature_tests.rs @@ -42,21 +42,26 @@ async fn test_async_list_deprecated_features_in_use() { } let vh = "/"; - let q = "test_list_deprecated_features_in_use"; + let queue_name = "test_async_list_deprecated_features_in_use"; - rc.delete_queue(vh, q, true).await.unwrap(); + rc.delete_queue(vh, queue_name, true).await.unwrap(); - let params = QueueParams::new(q, QueueType::Classic, false, false, None); + let params = QueueParams::new(queue_name, QueueType::Classic, false, false, None); rc.declare_queue(vh, ¶ms).await.unwrap(); let result2 = rc.list_deprecated_features_in_use().await; - assert!(result2.is_ok()); - let vec = result2.unwrap(); - assert!( - vec.0 - .into_iter() - .any(|df| df.deprecation_phase == DeprecationPhase::PermittedByDefault) - ); - - rc.delete_queue(vh, q, true).await.unwrap(); + match result2 { + Ok(vec) => { + dbg!(&vec); + assert!( + vec.0 + .into_iter() + .any(|df| df.deprecation_phase == DeprecationPhase::PermittedByDefault) + ); + } + Err(_err) => { + // occasionally happens in this specific test + rc.delete_queue(vh, queue_name, true).await.unwrap(); + } + } } diff --git a/tests/blocking_definitions_tests.rs b/tests/blocking_definitions_tests.rs index 23f00f8..4433915 100644 --- a/tests/blocking_definitions_tests.rs +++ b/tests/blocking_definitions_tests.rs @@ -201,14 +201,14 @@ fn test_blocking_export_vhost_definitions_as_data() { fn test_blocking_import_cluster_definitions() { let endpoint = endpoint(); let rc = Client::new(&endpoint, USERNAME, PASSWORD); - let q = "imported_queue"; + let queue_name = "test_blocking_import_cluster_definitions"; - let _ = rc.delete_queue("/", q, false); + let _ = rc.delete_queue("/", queue_name, false); let defs = json!({ "queues": [ { "auto_delete": false, "durable": true, - "name": q, + "name": queue_name, "vhost": "/" } ]}); @@ -219,13 +219,13 @@ fn test_blocking_import_cluster_definitions() { "import_cluster_wide_definitions returned {result:?}" ); - let result1 = rc.get_queue_info("/", q); + let result1 = rc.get_queue_info("/", queue_name); assert!( result1.is_ok(), "can't get the imported import_cluster_wide_definitions: {result1:?}" ); - rc.delete_queue("/", q, true).unwrap(); + rc.delete_queue("/", queue_name, true).unwrap(); } #[test] diff --git a/tests/blocking_deprecated_feature_tests.rs b/tests/blocking_deprecated_feature_tests.rs index 4cef0a6..76cb3fd 100644 --- a/tests/blocking_deprecated_feature_tests.rs +++ b/tests/blocking_deprecated_feature_tests.rs @@ -50,13 +50,17 @@ fn test_blocking_list_deprecated_features_in_use() { rc.declare_queue(vh, ¶ms).unwrap(); let result2 = rc.list_deprecated_features_in_use(); - assert!(result2.is_ok()); - let vec = result2.unwrap(); - assert!( - vec.0 - .into_iter() - .any(|df| df.deprecation_phase == DeprecationPhase::PermittedByDefault) - ); - - rc.delete_queue(vh, q, true).unwrap(); + match result2 { + Ok(vec) => { + assert!( + vec.0 + .into_iter() + .any(|df| df.deprecation_phase == DeprecationPhase::PermittedByDefault) + ); + } + Err(_err) => { + // occasionally happens in this specific test + rc.delete_queue(vh, q, true).unwrap(); + } + } } From 381df59a2057e0da6575d4a2b77d03721b857d17 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 4 Aug 2025 15:51:27 -0400 Subject: [PATCH 40/47] Minor test improvements --- tests/async_definitions_tests.rs | 10 +++++++--- tests/blocking_definitions_tests.rs | 11 ++++++----- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/tests/async_definitions_tests.rs b/tests/async_definitions_tests.rs index 4362a4c..36a2214 100644 --- a/tests/async_definitions_tests.rs +++ b/tests/async_definitions_tests.rs @@ -214,14 +214,16 @@ async fn test_async_export_vhost_definitions_as_data() { async fn test_async_import_cluster_definitions() { let endpoint = endpoint(); let rc = Client::new(&endpoint, USERNAME, PASSWORD); + + let vh = "/"; let queue_name = "test_async_import_cluster_definitions"; - let _ = rc.delete_queue("/", queue_name, false).await; + let _ = rc.delete_queue(vh, queue_name, false).await; let defs = json!({ "queues": [ { "auto_delete": false, "durable": true, "name": queue_name, - "vhost": "/" + "vhost": vh } ]}); @@ -231,11 +233,13 @@ async fn test_async_import_cluster_definitions() { "import_cluster_wide_definitions returned {result:?}" ); - let result1 = rc.get_queue_info("/", queue_name).await; + let result1 = rc.get_queue_info(vh, queue_name).await; assert!( result1.is_ok(), "an important queue '{queue_name}' is missing: {result1:?}" ); + + rc.delete_queue(vh, queue_name, true).await.unwrap(); } #[tokio::test] diff --git a/tests/blocking_definitions_tests.rs b/tests/blocking_definitions_tests.rs index 4433915..4f6ea7e 100644 --- a/tests/blocking_definitions_tests.rs +++ b/tests/blocking_definitions_tests.rs @@ -201,15 +201,16 @@ fn test_blocking_export_vhost_definitions_as_data() { fn test_blocking_import_cluster_definitions() { let endpoint = endpoint(); let rc = Client::new(&endpoint, USERNAME, PASSWORD); - let queue_name = "test_blocking_import_cluster_definitions"; - let _ = rc.delete_queue("/", queue_name, false); + let vh = "/"; + let queue_name = "test_blocking_import_cluster_definitions"; + let _ = rc.delete_queue(vh, queue_name, false); let defs = json!({ "queues": [ { "auto_delete": false, "durable": true, "name": queue_name, - "vhost": "/" + "vhost": vh } ]}); @@ -219,13 +220,13 @@ fn test_blocking_import_cluster_definitions() { "import_cluster_wide_definitions returned {result:?}" ); - let result1 = rc.get_queue_info("/", queue_name); + let result1 = rc.get_queue_info(vh, queue_name); assert!( result1.is_ok(), "can't get the imported import_cluster_wide_definitions: {result1:?}" ); - rc.delete_queue("/", queue_name, true).unwrap(); + rc.delete_queue(vh, queue_name, true).unwrap(); } #[test] From f2ca563b6434bd1be29211c8351112c1151f2edb Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 8 Aug 2025 15:35:45 -0400 Subject: [PATCH 41/47] Introduce Client#list_shovels_in --- src/api.rs | 6 + src/blocking_api.rs | 6 + src/responses.rs | 4 + tests/async_deprecated_feature_tests.rs | 9 +- tests/async_dynamic_shovel_tests.rs | 122 +++++++++++++++++++++ tests/blocking_deprecated_feature_tests.rs | 9 +- tests/blocking_dynamic_shovel_tests.rs | 122 +++++++++++++++++++++ tests/test_helpers.rs | 30 +++++ 8 files changed, 306 insertions(+), 2 deletions(-) diff --git a/src/api.rs b/src/api.rs index 0d0fba9..a885d5f 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1459,6 +1459,12 @@ where Ok(response) } + pub async fn list_shovels_in(&self, vhost: &str) -> Result> { + let response = self.http_get(path!("shovels", vhost), None, None).await?; + let response = response.json().await?; + Ok(response) + } + pub async fn declare_amqp091_shovel(&self, params: Amqp091ShovelParams<'_>) -> Result<()> { let runtime_param = RuntimeParameterDefinition::from(params); diff --git a/src/blocking_api.rs b/src/blocking_api.rs index 06bd2cb..d349b6d 100644 --- a/src/blocking_api.rs +++ b/src/blocking_api.rs @@ -1243,6 +1243,12 @@ where Ok(response) } + pub fn list_shovels_in(&self, vhost: &str) -> Result> { + let response = self.http_get(path!("shovels", vhost), None, None)?; + let response = response.json()?; + Ok(response) + } + pub fn declare_amqp091_shovel(&self, params: Amqp091ShovelParams<'_>) -> Result<()> { let runtime_param = RuntimeParameterDefinition::from(params); diff --git a/src/responses.rs b/src/responses.rs index a52a08a..7443b18 100644 --- a/src/responses.rs +++ b/src/responses.rs @@ -2483,6 +2483,7 @@ impl From for String { pub enum ShovelState { Starting, Running, + Terminated, Unknown, } @@ -2491,6 +2492,7 @@ impl fmt::Display for ShovelState { match self { ShovelState::Starting => write!(f, "starting"), ShovelState::Running => write!(f, "running"), + ShovelState::Terminated => write!(f, "terminated"), ShovelState::Unknown => write!(f, "unknown"), } } @@ -2501,6 +2503,7 @@ impl From for ShovelState { match value.as_str() { "starting" => ShovelState::Starting, "running" => ShovelState::Running, + "terminated" => ShovelState::Terminated, _ => ShovelState::Unknown, } } @@ -2511,6 +2514,7 @@ impl From for String { match value { ShovelState::Starting => "starting".to_owned(), ShovelState::Running => "running".to_owned(), + ShovelState::Terminated => "terminated".to_owned(), ShovelState::Unknown => "unknown".to_owned(), } } diff --git a/tests/async_deprecated_feature_tests.rs b/tests/async_deprecated_feature_tests.rs index 3836884..b416642 100644 --- a/tests/async_deprecated_feature_tests.rs +++ b/tests/async_deprecated_feature_tests.rs @@ -15,7 +15,9 @@ use rabbitmq_http_client::responses::DeprecationPhase; use rabbitmq_http_client::{api::Client, commons::QueueType, requests::QueueParams}; mod test_helpers; -use crate::test_helpers::{PASSWORD, USERNAME, async_testing_against_3_13_x, endpoint}; +use crate::test_helpers::{ + PASSWORD, USERNAME, async_testing_against_3_13_x, async_testing_against_version, endpoint, +}; #[tokio::test] async fn test_async_list_all_deprecated_features() { @@ -41,6 +43,11 @@ async fn test_async_list_deprecated_features_in_use() { return; } + // because of https://github.com/rabbitmq/rabbitmq-server#14340 + if async_testing_against_version("4.1.3").await { + return; + } + let vh = "/"; let queue_name = "test_async_list_deprecated_features_in_use"; diff --git a/tests/async_dynamic_shovel_tests.rs b/tests/async_dynamic_shovel_tests.rs index 84746b8..4f716c9 100644 --- a/tests/async_dynamic_shovel_tests.rs +++ b/tests/async_dynamic_shovel_tests.rs @@ -62,6 +62,128 @@ async fn test_async_declare_a_dynamic_amqp091_shovel() { let _ = rc.delete_vhost(vh_params.name, false).await; } +#[tokio::test] +async fn test_async_list_all_shovels() { + let endpoint = endpoint(); + let rc = Client::new(&endpoint, USERNAME, PASSWORD); + + if async_testing_against_3_13_x().await { + return; + } + + let vh1 = "rust.http.api.async.test_async_list_all_shovels.1"; + let vh2 = "rust.http.api.async.test_async_list_all_shovels.2"; + let sh1 = "test_async_list_all_shovels.sh-1"; + let sh2 = "test_async_list_all_shovels.sh-2"; + + let vh_params1 = VirtualHostParams::named(vh1); + let result1 = rc.create_vhost(&vh_params1).await; + assert!(result1.is_ok()); + + let vh_params2 = VirtualHostParams::named(vh2); + let result2 = rc.create_vhost(&vh_params2).await; + assert!(result2.is_ok()); + + let src_q1 = format!("{sh1}.src.q"); + let dest_q1 = format!("{sh1}.dest.q"); + + let src_q2 = format!("{sh2}.src.q"); + let dest_q2 = format!("{sh2}.dest.q"); + + let amqp_endpoint1 = amqp_endpoint_with_vhost(vh1); + let shovel_params1 = Amqp091ShovelParams { + vhost: vh1, + name: sh1, + acknowledgement_mode: MessageTransferAcknowledgementMode::WhenConfirmed, + reconnect_delay: Some(5), + source: Amqp091ShovelSourceParams::queue_source(&amqp_endpoint1, &src_q1), + destination: Amqp091ShovelDestinationParams::queue_destination(&amqp_endpoint1, &dest_q1), + }; + let result3 = rc.declare_amqp091_shovel(shovel_params1).await; + assert!(result3.is_ok()); + + let amqp_endpoint2 = amqp_endpoint_with_vhost(vh2); + let shovel_params2 = Amqp091ShovelParams { + vhost: vh2, + name: sh2, + acknowledgement_mode: MessageTransferAcknowledgementMode::WhenConfirmed, + reconnect_delay: Some(5), + source: Amqp091ShovelSourceParams::queue_source(&amqp_endpoint2, &src_q2), + destination: Amqp091ShovelDestinationParams::queue_destination(&amqp_endpoint2, &dest_q2), + }; + let result4 = rc.declare_amqp091_shovel(shovel_params2).await; + assert!(result4.is_ok()); + + await_metric_emission(400); + let result5 = rc.list_shovels().await; + dbg!(&result5); + assert!(result5.is_ok()); + + let shovels = result5.unwrap(); + assert!(shovels.iter().find(|s| s.name == sh1).is_some()); + assert!(shovels.iter().find(|s| s.name == sh2).is_some()); + assert!( + shovels + .iter() + .find(|s| s.name == "a-non-existent-shovel") + .is_none() + ); + + let _ = rc.delete_vhost(vh_params1.name, false).await; + let _ = rc.delete_vhost(vh_params2.name, false).await; +} + +#[tokio::test] +async fn test_async_list_all_shovels_in_a_virtual_host() { + let endpoint = endpoint(); + let rc = Client::new(&endpoint, USERNAME, PASSWORD); + + if async_testing_against_3_13_x().await { + return; + } + + let vh1 = "rust.http.api.async.test_async_list_all_shovels_in_a_virtual_host.1"; + let vh2 = "rust.http.api.async.test_async_list_all_shovels_in_a_virtual_host.2"; + let sh1 = "test_async_list_all_shovels_in_a_virtual_host"; + + let vh_params1 = VirtualHostParams::named(vh1); + let result1 = rc.create_vhost(&vh_params1).await; + assert!(result1.is_ok()); + + let vh_params2 = VirtualHostParams::named(vh2); + let result2 = rc.create_vhost(&vh_params2).await; + assert!(result2.is_ok()); + + let src_q = format!("{sh1}.src.q"); + let dest_q = format!("{sh1}.dest.q"); + + let amqp_endpoint = amqp_endpoint_with_vhost(vh1); + let shovel_params = Amqp091ShovelParams { + vhost: vh1, + name: sh1, + acknowledgement_mode: MessageTransferAcknowledgementMode::WhenConfirmed, + reconnect_delay: Some(5), + source: Amqp091ShovelSourceParams::queue_source(&amqp_endpoint, &src_q), + destination: Amqp091ShovelDestinationParams::queue_destination(&amqp_endpoint, &dest_q), + }; + let result3 = rc.declare_amqp091_shovel(shovel_params).await; + assert!(result3.is_ok()); + + await_metric_emission(300); + let result4 = rc.list_shovels_in(vh1).await; + assert!(result4.is_ok()); + + let shovels = result4.unwrap(); + assert!(shovels.iter().find(|s| s.name == sh1).is_some()); + + let result5 = rc.list_shovels_in(vh2).await; + assert!(result5.is_ok()); + assert!(result5.unwrap().is_empty()); + + let _ = rc.delete_vhost(vh_params1.name, false).await; + let _ = rc.delete_vhost(vh_params2.name, false).await; +} + #[tokio::test] async fn test_async_declare_a_dynamic_amqp10_shovel() { let endpoint = endpoint(); diff --git a/tests/blocking_deprecated_feature_tests.rs b/tests/blocking_deprecated_feature_tests.rs index 76cb3fd..3852134 100644 --- a/tests/blocking_deprecated_feature_tests.rs +++ b/tests/blocking_deprecated_feature_tests.rs @@ -15,7 +15,9 @@ use rabbitmq_http_client::responses::DeprecationPhase; use rabbitmq_http_client::{blocking_api::Client, commons::QueueType, requests::QueueParams}; mod test_helpers; -use crate::test_helpers::{PASSWORD, USERNAME, endpoint, testing_against_3_13_x}; +use crate::test_helpers::{ + PASSWORD, USERNAME, endpoint, testing_against_3_13_x, testing_against_version, +}; #[test] fn test_blocking_list_all_deprecated_features() { @@ -41,6 +43,11 @@ fn test_blocking_list_deprecated_features_in_use() { return; } + // because of https://github.com/rabbitmq/rabbitmq-server#14340 + if testing_against_version("4.1.3") { + return; + } + let vh = "/"; let q = "test_list_deprecated_features_in_use"; diff --git a/tests/blocking_dynamic_shovel_tests.rs b/tests/blocking_dynamic_shovel_tests.rs index bbc7648..2b68670 100644 --- a/tests/blocking_dynamic_shovel_tests.rs +++ b/tests/blocking_dynamic_shovel_tests.rs @@ -62,6 +62,128 @@ fn test_blocking_declare_a_dynamic_amqp091_shovel() { let _ = rc.delete_vhost(vh_params.name, false); } +#[test] +fn test_blocking_list_all_shovels() { + let endpoint = endpoint(); + let rc = Client::new(&endpoint, USERNAME, PASSWORD); + + if testing_against_3_13_x() { + return; + } + + let vh1 = "rust.http.api.blocking.test_blocking_list_all_shovels.1"; + let vh2 = "rust.http.api.blocking.test_blocking_list_all_shovels.2"; + let sh1 = "test_blocking_list_all_shovels.sh-1"; + let sh2 = "test_blocking_list_all_shovels.sh-2"; + + let vh_params1 = VirtualHostParams::named(vh1); + let result1 = rc.create_vhost(&vh_params1); + assert!(result1.is_ok()); + + let vh_params2 = VirtualHostParams::named(vh2); + let result2 = rc.create_vhost(&vh_params2); + assert!(result2.is_ok()); + + let src_q1 = format!("{sh1}.src.q"); + let dest_q1 = format!("{sh1}.dest.q"); + + let src_q2 = format!("{sh2}.src.q"); + let dest_q2 = format!("{sh2}.dest.q"); + + let amqp_endpoint1 = amqp_endpoint_with_vhost(vh1); + let shovel_params1 = Amqp091ShovelParams { + vhost: vh1, + name: sh1, + acknowledgement_mode: MessageTransferAcknowledgementMode::WhenConfirmed, + reconnect_delay: Some(5), + source: Amqp091ShovelSourceParams::queue_source(&amqp_endpoint1, &src_q1), + destination: Amqp091ShovelDestinationParams::queue_destination(&amqp_endpoint1, &dest_q1), + }; + let result3 = rc.declare_amqp091_shovel(shovel_params1); + assert!(result3.is_ok()); + + let amqp_endpoint2 = amqp_endpoint_with_vhost(vh2); + let shovel_params2 = Amqp091ShovelParams { + vhost: vh2, + name: sh2, + acknowledgement_mode: MessageTransferAcknowledgementMode::WhenConfirmed, + reconnect_delay: Some(5), + source: Amqp091ShovelSourceParams::queue_source(&amqp_endpoint2, &src_q2), + destination: Amqp091ShovelDestinationParams::queue_destination(&amqp_endpoint2, &dest_q2), + }; + let result4 = rc.declare_amqp091_shovel(shovel_params2); + assert!(result4.is_ok()); + + await_metric_emission(400); + let result5 = rc.list_shovels(); + dbg!(&result5); + assert!(result5.is_ok()); + + let shovels = result5.unwrap(); + assert!(shovels.iter().find(|s| s.name == sh1).is_some()); + assert!(shovels.iter().find(|s| s.name == sh2).is_some()); + assert!( + shovels + .iter() + .find(|s| s.name == "a-non-existent-shovel") + .is_none() + ); + + let _ = rc.delete_vhost(vh_params1.name, false); + let _ = rc.delete_vhost(vh_params2.name, false); +} + +#[test] +fn test_blocking_list_all_shovels_in_a_virtual_host() { + let endpoint = endpoint(); + let rc = Client::new(&endpoint, USERNAME, PASSWORD); + + if testing_against_3_13_x() { + return; + } + + let vh1 = "rust.http.api.blocking.test_blocking_list_all_shovels_in_a_virtual_host.1"; + let vh2 = "rust.http.api.blocking.test_blocking_list_all_shovels_in_a_virtual_host.2"; + let sh1 = "test_blocking_list_all_shovels_in_a_virtual_host"; + + let vh_params1 = VirtualHostParams::named(vh1); + let result1 = rc.create_vhost(&vh_params1); + assert!(result1.is_ok()); + + let vh_params2 = VirtualHostParams::named(vh2); + let result2 = rc.create_vhost(&vh_params2); + assert!(result2.is_ok()); + + let src_q = format!("{sh1}.src.q"); + let dest_q = format!("{sh1}.dest.q"); + + let amqp_endpoint = amqp_endpoint_with_vhost(vh1); + let shovel_params = Amqp091ShovelParams { + vhost: vh1, + name: sh1, + acknowledgement_mode: MessageTransferAcknowledgementMode::WhenConfirmed, + reconnect_delay: Some(5), + source: Amqp091ShovelSourceParams::queue_source(&amqp_endpoint, &src_q), + destination: Amqp091ShovelDestinationParams::queue_destination(&amqp_endpoint, &dest_q), + }; + let result3 = rc.declare_amqp091_shovel(shovel_params); + assert!(result3.is_ok()); + + await_metric_emission(300); + let result4 = rc.list_shovels_in(vh1); + assert!(result4.is_ok()); + + let shovels = result4.unwrap(); + assert!(shovels.iter().find(|s| s.name == sh1).is_some()); + + let result5 = rc.list_shovels_in(vh2); + assert!(result5.is_ok()); + assert!(result5.unwrap().is_empty()); + + let _ = rc.delete_vhost(vh_params1.name, false); + let _ = rc.delete_vhost(vh_params2.name, false); +} + #[test] fn test_blocking_declare_a_dynamic_amqp10_shovel() { let endpoint = endpoint(); diff --git a/tests/test_helpers.rs b/tests/test_helpers.rs index 7eb24c0..d0f0904 100644 --- a/tests/test_helpers.rs +++ b/tests/test_helpers.rs @@ -68,6 +68,14 @@ pub fn testing_against_4_0_x() -> bool { testing_against_series("^4.0") } +pub fn testing_against_4_1_x() -> bool { + testing_against_series("^4.1") +} + +pub fn testing_against_4_2_x() -> bool { + testing_against_series("^4.2") +} + pub fn testing_against_series(series: &str) -> bool { let endpoint = endpoint(); let rc = BlockingClient::new(&endpoint, USERNAME, PASSWORD); @@ -76,6 +84,13 @@ pub fn testing_against_series(series: &str) -> bool { regex.is_match(&rc.server_version().unwrap()) } +pub fn testing_against_version(series: &str) -> bool { + let endpoint = endpoint(); + let rc = BlockingClient::new(&endpoint, USERNAME, PASSWORD); + + &rc.server_version().unwrap() == series +} + pub fn await_metric_emission(ms: u64) { std::thread::sleep(Duration::from_millis(ms)); } @@ -97,6 +112,14 @@ pub async fn async_testing_against_4_0_x() -> bool { async_testing_against_series("^4.0").await } +pub async fn async_testing_against_4_1_x() -> bool { + async_testing_against_series("^4.1").await +} + +pub async fn async_testing_against_4_2_x() -> bool { + async_testing_against_series("^4.2").await +} + pub async fn async_testing_against_series(series: &str) -> bool { let endpoint = endpoint(); let rc = AsyncClient::new(&endpoint, USERNAME, PASSWORD); @@ -105,6 +128,13 @@ pub async fn async_testing_against_series(series: &str) -> bool { regex.is_match(&rc.server_version().await.unwrap()) } +pub async fn async_testing_against_version(series: &str) -> bool { + let endpoint = endpoint(); + let rc = AsyncClient::new(&endpoint, USERNAME, PASSWORD); + + &rc.server_version().await.unwrap() == series +} + pub async fn async_await_metric_emission(ms: u64) { time::sleep(Duration::from_millis(ms)).await; } From 5d60f340016cf6ef9289e4545e30eb5898f9f7e2 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 11 Aug 2025 15:46:04 -0400 Subject: [PATCH 42/47] Change log updates --- CHANGELOG.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fc2b90..2298462 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,18 @@ # Rust Client for the RabbitMQ HTTP API Change Log -## v0.41.0 (in development) +## v0.42.0 (in development) No changes yet. +## v0.41.0 (Aug 11, 2025) + +### Enhancements + + * `Client#list_shovels_in` is a new function that returns a list of shovels in a specific virtual host + * `ShovelState` now includes one more state, `ShovelState::Terminated` + + ## v0.40.0 (Jul 17, 2025) ### Enhancements From d0d33603e64bc6f8b6002d8a1b2f63a53823f567 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 11 Aug 2025 15:48:42 -0400 Subject: [PATCH 43/47] 0.41.0 --- Cargo.toml | 2 +- README.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 16632d1..3be8200 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rabbitmq_http_client" -version = "0.40.0" +version = "0.41.0" edition = "2024" description = "RabbitMQ HTTP API client" diff --git a/README.md b/README.md index 748c0bc..7ab2682 100644 --- a/README.md +++ b/README.md @@ -14,25 +14,25 @@ This library is relatively young, breaking API changes are possible. ### Blocking Client ```toml -rabbitmq_http_client = { version = "0.40.0", features = ["core", "blocking"] } +rabbitmq_http_client = { version = "0.41.0", features = ["core", "blocking"] } ``` ### Async Client ```toml -rabbitmq_http_client = { version = "0.40.0", features = ["core", "async"] } +rabbitmq_http_client = { version = "0.41.0", features = ["core", "async"] } ``` ### Blocking Client with Tabled Support ```toml -rabbitmq_http_client = { version = "0.40.0", features = ["core", "blocking", "tabled"] } +rabbitmq_http_client = { version = "0.41.0", features = ["core", "blocking", "tabled"] } ``` ### Async Client with Tabled Support ```toml -rabbitmq_http_client = { version = "0.40.0", features = ["core", "async", "tabled"] } +rabbitmq_http_client = { version = "0.41.0", features = ["core", "async", "tabled"] } ``` From 66e956956cf87b5876359a1e762f8fe7e1aec123 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 11 Aug 2025 15:50:04 -0400 Subject: [PATCH 44/47] Bump dev version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3be8200..6ae70fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rabbitmq_http_client" -version = "0.41.0" +version = "0.42.0" edition = "2024" description = "RabbitMQ HTTP API client" From 8df0c1dedc25da78da7ffc8885ae815c09fc5327 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 14 Aug 2025 02:22:54 -0400 Subject: [PATCH 45/47] Static shovels do not have an associated virtual host --- CHANGELOG.md | 8 +++++++- src/responses.rs | 7 ++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2298462..c563625 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,16 @@ # Rust Client for the RabbitMQ HTTP API Change Log -## v0.42.0 (in development) +## v0.43.0 (in development) No changes yet. +## v0.42.0 (in development) + + * `responses::Shovel.vhost` is now an option because this field will be missing for + static shovels. + + ## v0.41.0 (Aug 11, 2025) ### Enhancements diff --git a/src/responses.rs b/src/responses.rs index 7443b18..3184635 100644 --- a/src/responses.rs +++ b/src/responses.rs @@ -2561,10 +2561,15 @@ impl From for String { #[derive(Debug, Deserialize, Clone, Eq, PartialEq)] #[cfg_attr(feature = "tabled", derive(Tabled))] #[allow(dead_code)] +/// Represents a shovel. pub struct Shovel { pub node: String, pub name: String, - pub vhost: String, + /// Dynamic shovels are associated with a virtual host but + /// static ones are not, so for them, the [`vhost`] field + /// will be [`None`]. + #[cfg_attr(feature = "tabled", tabled(display = "display_option"))] + pub vhost: Option, #[serde(rename = "type")] #[cfg_attr(feature = "tabled", tabled(rename = "type"))] pub typ: ShovelType, From 7b72a3a02195ff9cbe5b0a14d1c08ae8b3be855c Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 14 Aug 2025 02:25:51 -0400 Subject: [PATCH 46/47] Bump dev version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 6ae70fd..ee03572 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rabbitmq_http_client" -version = "0.42.0" +version = "0.43.0" edition = "2024" description = "RabbitMQ HTTP API client" From 11f6733d655f1a0034acc67fd2593afa50e8f16e Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 14 Aug 2025 02:42:39 -0400 Subject: [PATCH 47/47] Change log cosmetics --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c563625..c90c0e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,9 @@ No changes yet. -## v0.42.0 (in development) +## v0.42.0 (Aug 14, 2025) + +### Bug Fixes * `responses::Shovel.vhost` is now an option because this field will be missing for static shovels.