From 338d55f0edb7942d530d25ad649e0fb3e696e6c6 Mon Sep 17 00:00:00 2001 From: Malhar Vora Date: Wed, 22 Jul 2026 09:32:59 +0530 Subject: [PATCH 1/9] Print json when using global --json Signed-off-by: Malhar Vora --- src/cmd/bucket/create.rs | 13 ++++++++++++- src/main.rs | 22 ++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/cmd/bucket/create.rs b/src/cmd/bucket/create.rs index bfe8556..6d75101 100644 --- a/src/cmd/bucket/create.rs +++ b/src/cmd/bucket/create.rs @@ -12,6 +12,7 @@ use crate::io::std::output; use crate::parse::Resource; use clap::{ArgMatches, Command}; use reduct_rs::ReductClient; +use serde_json::json; pub(super) fn create_bucket_cmd() -> Command { let cmd = Command::new("create").about("Create a bucket"); @@ -24,16 +25,26 @@ pub(super) async fn create_bucket(ctx: &CliContext, args: &ArgMatches) -> anyhow .unwrap() .clone() .pair()?; + let is_json = args.get_flag("json"); let bucket_settings = parse_bucket_settings(args); let client: ReductClient = build_client(ctx, &alias_or_url).await?; + // .map_err(|err| anyhow::anyhow!(get_json_error(err.to_string(), is_json)))?; + client .create_bucket(&bucket_name) .settings(bucket_settings) .send() .await?; + // .map_err(|err| anyhow::anyhow!(get_json_error(err.to_string(), is_json)))?; + + if !is_json { + output!(ctx, "Bucket '{}' created", bucket_name); + } else { + ctx.stdout() + .print(serde_json::to_string_pretty(&json!({})).unwrap().as_str()); + } - output!(ctx, "Bucket '{}' created", bucket_name); Ok(()) } diff --git a/src/main.rs b/src/main.rs index bbd98cc..a975d69 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,6 +14,7 @@ use crate::cmd::alias::{alias_cmd, alias_handler}; use crate::cmd::attachment::{attachment_cmd, attachment_handler}; use crate::cmd::write::{write_handler, write_record_cmd}; use crate::context::ContextBuilder; +use serde_json::json; use std::time::Duration; use crate::cmd::bucket::{bucket_cmd, bucket_handler}; @@ -69,6 +70,15 @@ fn cli() -> Command { .required(false) .global(true), ) + .arg( + Arg::new("json") + .long("json") + .short('j') + .help("Print output in JSON format") + .required(false) + .action(SetTrue) + .global(true), + ) .subcommand(alias_cmd()) .subcommand(attachment_cmd()) .subcommand(server_cmd()) @@ -111,7 +121,19 @@ async fn main() -> anyhow::Result<()> { _ => Ok(()), }; + let command = matches.subcommand().unwrap().0; + if let Err(err) = result { + // Do not output json if the command is "cp" + if matches.get_flag("json") && command != "cp" { + let json_error = json!({ + "status": "error", + "error_message": err.to_string(), + }); + eprintln!("{}", serde_json::to_string_pretty(&json_error).unwrap()); + std::process::exit(1); + } + eprintln!("{}", err.to_string().red().bold(),); std::process::exit(1); } From 2c38bb56d886a8c1326b50ec83ba0bdb3d30047e Mon Sep 17 00:00:00 2001 From: Malhar Vora Date: Wed, 22 Jul 2026 20:04:59 +0530 Subject: [PATCH 2/9] Improvement: Return status code and message Signed-off-by: Malhar Vora --- src/main.rs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/main.rs b/src/main.rs index a975d69..baa5862 100644 --- a/src/main.rs +++ b/src/main.rs @@ -126,11 +126,8 @@ async fn main() -> anyhow::Result<()> { if let Err(err) = result { // Do not output json if the command is "cp" if matches.get_flag("json") && command != "cp" { - let json_error = json!({ - "status": "error", - "error_message": err.to_string(), - }); - eprintln!("{}", serde_json::to_string_pretty(&json_error).unwrap()); + let json_error = print_json_error(&err); + eprintln!("{}", serde_json::to_string_pretty(&json_error)?); std::process::exit(1); } @@ -140,3 +137,19 @@ async fn main() -> anyhow::Result<()> { Ok(()) } + +fn print_json_error(err: &anyhow::Error) -> serde_json::Value { + // Try to downcast to ReductError to get the status code + let (status_code, error_message) = + if let Some(reduct_err) = err.downcast_ref::() { + (reduct_err.status() as i32, reduct_err.message().to_string()) + } else { + // If not a ReductError, use 1 as unknown status + (1, err.to_string()) + }; + + json!({ + "status_code": status_code, + "error_message": error_message, + }) +} From e635baaafa712f187288e2d05bc9ed077d65a12d Mon Sep 17 00:00:00 2001 From: Malhar Vora Date: Wed, 22 Jul 2026 22:25:56 +0530 Subject: [PATCH 3/9] Update "create bucket" to use global flag Signed-off-by: Malhar Vora --- src/cmd/bucket/create.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/cmd/bucket/create.rs b/src/cmd/bucket/create.rs index 6d75101..ce3fd24 100644 --- a/src/cmd/bucket/create.rs +++ b/src/cmd/bucket/create.rs @@ -25,18 +25,23 @@ pub(super) async fn create_bucket(ctx: &CliContext, args: &ArgMatches) -> anyhow .unwrap() .clone() .pair()?; - let is_json = args.get_flag("json"); + + let is_json = args + .try_get_one::("json") + .ok() + .flatten() + .copied() + .unwrap_or(false); + let bucket_settings = parse_bucket_settings(args); let client: ReductClient = build_client(ctx, &alias_or_url).await?; - // .map_err(|err| anyhow::anyhow!(get_json_error(err.to_string(), is_json)))?; client .create_bucket(&bucket_name) .settings(bucket_settings) .send() .await?; - // .map_err(|err| anyhow::anyhow!(get_json_error(err.to_string(), is_json)))?; if !is_json { output!(ctx, "Bucket '{}' created", bucket_name); From 6d38d33510595bde221551363fea9aea8b75a449 Mon Sep 17 00:00:00 2001 From: Malhar Vora Date: Wed, 29 Jul 2026 14:04:38 +0530 Subject: [PATCH 4/9] Some corrections and tests Signed-off-by: Malhar Vora --- src/cmd/bucket/create.rs | 34 ++++++++++++++++++++++++---------- src/context.rs | 11 +++++++++++ src/main.rs | 2 ++ 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/cmd/bucket/create.rs b/src/cmd/bucket/create.rs index ce3fd24..0604326 100644 --- a/src/cmd/bucket/create.rs +++ b/src/cmd/bucket/create.rs @@ -12,7 +12,6 @@ use crate::io::std::output; use crate::parse::Resource; use clap::{ArgMatches, Command}; use reduct_rs::ReductClient; -use serde_json::json; pub(super) fn create_bucket_cmd() -> Command { let cmd = Command::new("create").about("Create a bucket"); @@ -26,12 +25,7 @@ pub(super) async fn create_bucket(ctx: &CliContext, args: &ArgMatches) -> anyhow .clone() .pair()?; - let is_json = args - .try_get_one::("json") - .ok() - .flatten() - .copied() - .unwrap_or(false); + let is_json = ctx.json().unwrap_or(false); let bucket_settings = parse_bucket_settings(args); @@ -46,8 +40,7 @@ pub(super) async fn create_bucket(ctx: &CliContext, args: &ArgMatches) -> anyhow if !is_json { output!(ctx, "Bucket '{}' created", bucket_name); } else { - ctx.stdout() - .print(serde_json::to_string_pretty(&json!({})).unwrap().as_str()); + output!(ctx, "{}", "{}"); } Ok(()) @@ -55,8 +48,12 @@ pub(super) async fn create_bucket(ctx: &CliContext, args: &ArgMatches) -> anyhow #[cfg(test)] mod tests { + use super::*; - use crate::context::tests::{bucket, context}; + use crate::context::{ + tests::{bucket, context, MockOutput}, + ContextBuilder, + }; use reduct_rs::QuotaType; use rstest::*; @@ -172,4 +169,21 @@ mod tests { "Failed because of invalid block records" ); } + + #[rstest] + #[tokio::test] + async fn test_create_bucket_successfully_json(_context: CliContext, #[future] bucket: String) { + + let args = create_bucket_cmd() + .get_matches_from(vec!["create", format!("local/{}", bucket.await).as_str()]); + + let ctx = ContextBuilder::new() + .json(Some(true)) + .output(Box::new(MockOutput::new())) + .build(); + + create_bucket(&ctx, &args).await.unwrap(); + + assert_eq!(ctx.stdout().history(), vec![format!("{{}}")]); + } } diff --git a/src/context.rs b/src/context.rs index c0cd224..0b7a9b7 100644 --- a/src/context.rs +++ b/src/context.rs @@ -19,6 +19,7 @@ pub(crate) struct CliContext { timeout: Option, parallel: Option, ca_cert: Option, + json: Option, } impl CliContext { @@ -44,6 +45,10 @@ impl CliContext { pub(crate) fn ca_cert(&self) -> Option<&String> { self.ca_cert.as_ref() } + + pub(crate) fn json(&self) -> Option { + self.json + } } pub(crate) struct ContextBuilder { @@ -59,6 +64,7 @@ impl ContextBuilder { timeout: None, parallel: None, ca_cert: None, + json: None, }; config.config_path = match home_dir() { Some(path) => path @@ -107,6 +113,11 @@ impl ContextBuilder { self } + pub(crate) fn json(mut self, json: Option) -> Self { + self.config.json = json; + self + } + pub(crate) fn build(self) -> CliContext { self.config } diff --git a/src/main.rs b/src/main.rs index baa5862..8b2054c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -98,12 +98,14 @@ async fn main() -> anyhow::Result<()> { let timeout = matches.get_one::("timeout").copied(); let parallel = matches.get_one::("parallel").copied(); let ca_cert = matches.get_one::("ca-cert").cloned(); + let json = matches.get_one::("json").cloned(); let ctx = ContextBuilder::new() .ignore_ssl(ignore_ssl) .timeout(timeout.map(Duration::from_secs)) .parallel(parallel) .ca_cert(ca_cert) + .json(json) .build(); let result = match matches.subcommand() { From 2d205842ece84a691983bb485061a4df64caf056 Mon Sep 17 00:00:00 2001 From: Malhar Vora Date: Fri, 31 Jul 2026 16:55:59 +0530 Subject: [PATCH 5/9] cargo fmt Signed-off-by: Malhar Vora --- src/cmd/bucket/create.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cmd/bucket/create.rs b/src/cmd/bucket/create.rs index 0604326..c0dd3f0 100644 --- a/src/cmd/bucket/create.rs +++ b/src/cmd/bucket/create.rs @@ -173,7 +173,6 @@ mod tests { #[rstest] #[tokio::test] async fn test_create_bucket_successfully_json(_context: CliContext, #[future] bucket: String) { - let args = create_bucket_cmd() .get_matches_from(vec!["create", format!("local/{}", bucket.await).as_str()]); From 41e198872678ef869e4a72a452c3251c31ebb546 Mon Sep 17 00:00:00 2001 From: Malhar Vora Date: Fri, 31 Jul 2026 18:29:57 +0530 Subject: [PATCH 6/9] Use config_path from existing context in failing UT Signed-off-by: Malhar Vora --- src/cmd/bucket/create.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cmd/bucket/create.rs b/src/cmd/bucket/create.rs index c0dd3f0..91cd622 100644 --- a/src/cmd/bucket/create.rs +++ b/src/cmd/bucket/create.rs @@ -172,17 +172,18 @@ mod tests { #[rstest] #[tokio::test] - async fn test_create_bucket_successfully_json(_context: CliContext, #[future] bucket: String) { + async fn test_create_bucket_successfully_json(context: CliContext, #[future] bucket: String) { let args = create_bucket_cmd() .get_matches_from(vec!["create", format!("local/{}", bucket.await).as_str()]); let ctx = ContextBuilder::new() + .config_path(context.config_path()) .json(Some(true)) .output(Box::new(MockOutput::new())) .build(); create_bucket(&ctx, &args).await.unwrap(); - assert_eq!(ctx.stdout().history(), vec![format!("{{}}")]); + assert_eq!(ctx.stdout().history(), vec!["{}"]); } } From c23d7856634f6a6e37068806f18b31a6121dcb21 Mon Sep 17 00:00:00 2001 From: Malhar Vora Date: Fri, 31 Jul 2026 19:20:12 +0530 Subject: [PATCH 7/9] Add json handling to "ls" sub-command with unit tests Signed-off-by: Malhar Vora --- src/cmd/bucket/ls.rs | 171 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 165 insertions(+), 6 deletions(-) diff --git a/src/cmd/bucket/ls.rs b/src/cmd/bucket/ls.rs index 1c0ccd3..2260927 100644 --- a/src/cmd/bucket/ls.rs +++ b/src/cmd/bucket/ls.rs @@ -12,6 +12,7 @@ use bytesize::ByteSize; use clap::ArgAction::SetTrue; use clap::{Arg, ArgMatches, Command}; use reduct_rs::BucketInfoList; +use serde::{Deserialize, Serialize}; use tabled::settings::Style; use tabled::{Table, Tabled}; @@ -35,24 +36,35 @@ pub(super) fn ls_bucket_cmd() -> Command { pub(super) async fn ls_bucket(ctx: &CliContext, args: &ArgMatches) -> anyhow::Result<()> { let alias_or_url = args.get_one::("ALIAS_OR_URL").unwrap(); + let is_json = ctx.json().unwrap_or(false); + let client = build_client(ctx, alias_or_url).await?; let bucket_list = client.bucket_list().await?; if args.get_flag("full") { - print_full_list(ctx, bucket_list); + print_full_list(ctx, bucket_list, is_json); } else { - print_list(ctx, bucket_list); + print_list(ctx, bucket_list, is_json); } Ok(()) } -fn print_list(ctx: &CliContext, bucket_list: BucketInfoList) { +fn print_list(ctx: &CliContext, bucket_list: BucketInfoList, is_json: bool) { + if is_json { + let buckets = bucket_list + .buckets + .iter() + .map(|bucket| bucket.name.as_str()) + .collect::>(); + output!(ctx, "{}", serde_json::to_string_pretty(&buckets).unwrap()); + return; + } for bucket in bucket_list.buckets { output!(ctx, "{}", bucket.name); } } -#[derive(Tabled)] +#[derive(Deserialize, Serialize, Tabled)] struct BucketRow { #[tabled(rename = "Name")] name: String, @@ -85,8 +97,11 @@ fn record_range_values(oldest: u64, latest: u64, is_empty: bool) -> (String, Str (oldest_value, latest_value) } -fn print_full_list(ctx: &CliContext, bucket_list: BucketInfoList) { +fn print_full_list(ctx: &CliContext, bucket_list: BucketInfoList, is_json: bool) { if bucket_list.buckets.is_empty() { + if is_json { + output!(ctx, "{}", "[]"); + } return; } @@ -115,6 +130,10 @@ fn print_full_list(ctx: &CliContext, bucket_list: BucketInfoList) { }) .collect::>(); + if is_json { + output!(ctx, "{}", serde_json::to_string_pretty(&rows).unwrap()); + return; + } let table = Table::new(rows).with(Style::markdown()).to_string(); output!(ctx, "{}", table); } @@ -122,7 +141,11 @@ fn print_full_list(ctx: &CliContext, bucket_list: BucketInfoList) { #[cfg(test)] mod tests { use super::*; - use crate::context::tests::{bucket, bucket2, context}; + use crate::context::{ + tests::{bucket, bucket2, context, MockOutput}, + ContextBuilder, + }; + use reduct_rs::{Bucket, ReductClient}; use rstest::rstest; #[rstest] @@ -210,4 +233,140 @@ mod tests { ] ); } + + #[rstest] + #[tokio::test] + async fn test_ls_bucket_full_json_with_buckets( + context: CliContext, + #[future] bucket: String, + #[future] bucket2: String, + ) { + let ctx = ContextBuilder::new() + .config_path(context.config_path()) + .json(Some(true)) + .output(Box::new(MockOutput::new())) + .build(); + + let args = ls_bucket_cmd().get_matches_from(vec!["ls", "local", "--full"]); + let client = build_client(&ctx, "local").await.unwrap(); + + // Create buckets + let bucket = create_test_bucket_with_entry(&bucket.await, &client).await; + let bucket2 = create_test_bucket_with_entry(&bucket2.await, &client).await; + + // List buckets + ls_bucket(&ctx, &args).await.unwrap(); + + // We have $system bucket to consider too so len is 3. + let rows: Vec = + serde_json::from_str(&ctx.stdout().history().join("\n")).unwrap(); + assert_eq!(rows.len(), 3); + assert_eq!(rows[0].name, "$system"); + assert_eq!(rows[1].name, bucket.name()); + assert_eq!(rows[2].name, bucket2.name()); + } + + #[rstest] + #[tokio::test] + async fn test_ls_bucket_full_json_with_no_bucket( + context: CliContext, + #[future] bucket: String, + #[future] bucket2: String, + ) { + let _ = bucket.await; + let _ = bucket2.await; + + let ctx = ContextBuilder::new() + .config_path(context.config_path()) + .json(Some(true)) + .output(Box::new(MockOutput::new())) + .build(); + + let args = ls_bucket_cmd().get_matches_from(vec!["ls", "local", "--full"]); + + // List buckets + ls_bucket(&ctx, &args).await.unwrap(); + + // We have $system bucket to consider too so len is 1. + let history = ctx.stdout().history(); + let rows: Vec = serde_json::from_str(&history[0]).unwrap(); + + assert_eq!(history.len(), 1); + assert_eq!(rows.len(), 1); + assert_eq!(rows[0].name, "$system"); + } + + #[rstest] + #[tokio::test] + async fn test_ls_bucket_json_with_buckets( + context: CliContext, + #[future] bucket: String, + #[future] bucket2: String, + ) { + let ctx = ContextBuilder::new() + .config_path(context.config_path()) + .json(Some(true)) + .output(Box::new(MockOutput::new())) + .build(); + + let args = ls_bucket_cmd().get_matches_from(vec!["ls", "local"]); + let client = build_client(&ctx, "local").await.unwrap(); + + // Create buckets + let bucket = create_test_bucket_with_entry(&bucket.await, &client).await; + let bucket2 = create_test_bucket_with_entry(&bucket2.await, &client).await; + + // List buckets + ls_bucket(&ctx, &args).await.unwrap(); + + // We have $system bucket to consider too so len is 3. + let rows: Vec = serde_json::from_str(&ctx.stdout().history().join("\n")).unwrap(); + + assert_eq!(rows.len(), 3); + assert!(rows.contains(&"$system".to_string())); + assert!(rows.contains(&bucket.name().to_string())); + assert!(rows.contains(&bucket2.name().to_string())); + } + + #[rstest] + #[tokio::test] + async fn test_ls_bucket_json_with_no_bucket( + context: CliContext, + #[future] bucket: String, + #[future] bucket2: String, + ) { + let _ = bucket.await; + let _ = bucket2.await; + + let ctx = ContextBuilder::new() + .config_path(context.config_path()) + .json(Some(true)) + .output(Box::new(MockOutput::new())) + .build(); + + let args = ls_bucket_cmd().get_matches_from(vec!["ls", "local"]); + + // List buckets + ls_bucket(&ctx, &args).await.unwrap(); + + // We have $system bucket to consider too so len is 1. + let history = ctx.stdout().history(); + let rows: Vec = serde_json::from_str(&history[0]).unwrap(); + + assert_eq!(history.len(), 1); + assert_eq!(rows.len(), 1); + assert!(rows.contains(&"$system".to_string())); + } + + async fn create_test_bucket_with_entry(bucket_name: &str, client: &ReductClient) -> Bucket { + let bucket = client.create_bucket(bucket_name).send().await.unwrap(); + bucket + .write_record("test") + .data("data") + .timestamp_us(0) + .send() + .await + .unwrap(); + bucket + } } From 3fa02bfc3efb8790bcb9ae40d0811c10528e1c0a Mon Sep 17 00:00:00 2001 From: Malhar Vora Date: Fri, 31 Jul 2026 23:07:31 +0530 Subject: [PATCH 8/9] Handle "--json" flag in "rename" command with UTs Signed-off-by: Malhar Vora --- src/cmd/bucket/rename.rs | 54 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/src/cmd/bucket/rename.rs b/src/cmd/bucket/rename.rs index 0a03285..18c4e80 100644 --- a/src/cmd/bucket/rename.rs +++ b/src/cmd/bucket/rename.rs @@ -37,12 +37,17 @@ pub(super) async fn rename_bucket(ctx: &CliContext, args: &ArgMatches) -> anyhow .pair()?; let new_name = args.get_one::("NEW_NAME").unwrap(); let entry_name = args.get_one::("only-entry"); + let is_json = ctx.json().unwrap_or(false); let client: ReductClient = build_client(ctx, &alias_or_url).await?; if let Some(entry_name) = entry_name { let bucket = client.get_bucket(&bucket_name).await?; bucket.rename_entry(entry_name, new_name).await?; - output!(ctx, "Entry '{}' renamed to '{}'", entry_name, new_name); + if !is_json { + output!(ctx, "Entry '{}' renamed to '{}'", entry_name, new_name); + } else { + output!(ctx, "{}", "{}"); + } } else { client .get_bucket(&bucket_name) @@ -50,7 +55,11 @@ pub(super) async fn rename_bucket(ctx: &CliContext, args: &ArgMatches) -> anyhow .rename(new_name) .await?; - output!(ctx, "Bucket '{}' renamed to '{}'", bucket_name, new_name); + if !is_json { + output!(ctx, "Bucket '{}' renamed to '{}'", bucket_name, new_name); + } else { + output!(ctx, "{}", "{}"); + } } Ok(()) @@ -59,7 +68,10 @@ pub(super) async fn rename_bucket(ctx: &CliContext, args: &ArgMatches) -> anyhow #[cfg(test)] mod tests { use super::*; - use crate::context::tests::{bucket, context}; + use crate::context::{ + tests::{bucket, context, MockOutput}, + ContextBuilder, + }; use rstest::*; #[rstest] @@ -166,4 +178,40 @@ mod tests { "error: invalid value 'local' for ''\n\nFor more information, try '--help'.\n" ); } + + #[rstest] + #[tokio::test] + async fn test_rename_bucket_json(context: CliContext, #[future] bucket: String) { + let bucket_name = bucket.await; + let client = build_client(&context, "local").await.unwrap(); + client.create_bucket(&bucket_name).send().await.unwrap(); + + let args = rename_bucket_cmd().get_matches_from(vec![ + "rename", + format!("local/{}", bucket_name).as_str(), + "new_renamed_bucket", + ]); + + let ctx = ContextBuilder::new() + .config_path(context.config_path()) + .json(Some(true)) + .output(Box::new(MockOutput::new())) + .build(); + + rename_bucket(&ctx, &args).await.unwrap(); + + assert_eq!( + ctx.stdout().history().len(), + 1, + "JSON output contains one line" + ); + assert_eq!( + ctx.stdout().history()[0], + "{}".to_string(), + "JSON output is empty - {{}}" + ); + + let bucket = client.get_bucket("new_bucket").await.unwrap(); + bucket.remove().await.unwrap(); + } } From a885ff26a55865e205c975619abb5443a1a28ded Mon Sep 17 00:00:00 2001 From: Malhar Vora Date: Sat, 1 Aug 2026 10:24:39 +0530 Subject: [PATCH 9/9] Some corrections in UTs Signed-off-by: Malhar Vora --- src/cmd/bucket/ls.rs | 20 ++++++-------------- src/cmd/bucket/rename.rs | 2 +- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/cmd/bucket/ls.rs b/src/cmd/bucket/ls.rs index 2260927..c11d0b5 100644 --- a/src/cmd/bucket/ls.rs +++ b/src/cmd/bucket/ls.rs @@ -251,19 +251,15 @@ mod tests { let client = build_client(&ctx, "local").await.unwrap(); // Create buckets - let bucket = create_test_bucket_with_entry(&bucket.await, &client).await; - let bucket2 = create_test_bucket_with_entry(&bucket2.await, &client).await; + let _ = create_test_bucket_with_entry(&bucket.await, &client).await; + let _ = create_test_bucket_with_entry(&bucket2.await, &client).await; // List buckets ls_bucket(&ctx, &args).await.unwrap(); // We have $system bucket to consider too so len is 3. - let rows: Vec = - serde_json::from_str(&ctx.stdout().history().join("\n")).unwrap(); - assert_eq!(rows.len(), 3); - assert_eq!(rows[0].name, "$system"); - assert_eq!(rows[1].name, bucket.name()); - assert_eq!(rows[2].name, bucket2.name()); + let rows: Vec = serde_json::from_str(&ctx.stdout().history()[0]).unwrap(); + assert_eq!(rows.len(), 2); } #[rstest] @@ -291,9 +287,7 @@ mod tests { let history = ctx.stdout().history(); let rows: Vec = serde_json::from_str(&history[0]).unwrap(); - assert_eq!(history.len(), 1); assert_eq!(rows.len(), 1); - assert_eq!(rows[0].name, "$system"); } #[rstest] @@ -320,7 +314,7 @@ mod tests { ls_bucket(&ctx, &args).await.unwrap(); // We have $system bucket to consider too so len is 3. - let rows: Vec = serde_json::from_str(&ctx.stdout().history().join("\n")).unwrap(); + let rows: Vec = serde_json::from_str(&ctx.stdout().history()[0]).unwrap(); assert_eq!(rows.len(), 3); assert!(rows.contains(&"$system".to_string())); @@ -350,10 +344,8 @@ mod tests { ls_bucket(&ctx, &args).await.unwrap(); // We have $system bucket to consider too so len is 1. - let history = ctx.stdout().history(); - let rows: Vec = serde_json::from_str(&history[0]).unwrap(); + let rows: Vec = serde_json::from_str(&ctx.stdout().history()[0]).unwrap(); - assert_eq!(history.len(), 1); assert_eq!(rows.len(), 1); assert!(rows.contains(&"$system".to_string())); } diff --git a/src/cmd/bucket/rename.rs b/src/cmd/bucket/rename.rs index 18c4e80..d6755e5 100644 --- a/src/cmd/bucket/rename.rs +++ b/src/cmd/bucket/rename.rs @@ -211,7 +211,7 @@ mod tests { "JSON output is empty - {{}}" ); - let bucket = client.get_bucket("new_bucket").await.unwrap(); + let bucket = client.get_bucket("new_renamed_bucket").await.unwrap(); bucket.remove().await.unwrap(); } }