test: Added tests for the new gopass provider

This commit is contained in:
2025-09-29 17:28:04 -06:00
parent 1b83d9b199
commit a64f4dbf79
8 changed files with 121 additions and 66 deletions
+46 -46
View File
@@ -1,7 +1,8 @@
use crate::command::preview_command;
use anyhow::{Context, Result, anyhow};
use clap_complete::CompletionCandidate;
use futures::future::join_all;
use gman::config::{load_config, Config, RunConfig};
use gman::config::{Config, RunConfig, load_config};
use log::{debug, error};
use regex::Regex;
use std::collections::HashMap;
@@ -9,7 +10,6 @@ use std::ffi::{OsStr, OsString};
use std::fs;
use std::path::PathBuf;
use std::process::Command;
use clap_complete::CompletionCandidate;
use tokio::runtime::Handle;
const ARG_FORMAT_PLACEHOLDER_KEY: &str = "{{key}}";
@@ -256,48 +256,49 @@ pub fn parse_args(
}
pub fn run_config_completer(current: &OsStr) -> Vec<CompletionCandidate> {
let cur = current.to_string_lossy();
match load_config() {
Ok(config) => {
if let Some(run_configs) = config.run_configs {
run_configs
.iter()
.filter(|rc| {
rc.name
.as_ref()
.expect("run config has no name")
.starts_with(&*cur)
})
.map(|rc| {
CompletionCandidate::new(rc.name.as_ref().expect("run config has no name"))
})
.collect()
} else {
vec![]
}
}
Err(_) => vec![],
}
let cur = current.to_string_lossy();
match load_config() {
Ok(config) => {
if let Some(run_configs) = config.run_configs {
run_configs
.iter()
.filter(|rc| {
rc.name
.as_ref()
.expect("run config has no name")
.starts_with(&*cur)
})
.map(|rc| {
CompletionCandidate::new(rc.name.as_ref().expect("run config has no name"))
})
.collect()
} else {
vec![]
}
}
Err(_) => vec![],
}
}
pub fn secrets_completer(current: &OsStr) -> Vec<CompletionCandidate> {
let cur = current.to_string_lossy();
match load_config() {
Ok(config) => {
let mut provider_config = match config.extract_provider_config(None) {
Ok(pc) => pc,
Err(_) => return vec![],
};
let secrets_provider = provider_config.extract_provider();
let h = Handle::current();
tokio::task::block_in_place(|| h.block_on(secrets_provider.list_secrets())).unwrap_or_default()
.into_iter()
.filter(|s| s.starts_with(&*cur))
.map(CompletionCandidate::new)
.collect()
}
Err(_) => vec![],
}
let cur = current.to_string_lossy();
match load_config() {
Ok(config) => {
let mut provider_config = match config.extract_provider_config(None) {
Ok(pc) => pc,
Err(_) => return vec![],
};
let secrets_provider = provider_config.extract_provider();
let h = Handle::current();
tokio::task::block_in_place(|| h.block_on(secrets_provider.list_secrets()))
.unwrap_or_default()
.into_iter()
.filter(|s| s.starts_with(&*cur))
.map(CompletionCandidate::new)
.collect()
}
Err(_) => vec![],
}
}
#[cfg(test)]
@@ -402,11 +403,10 @@ mod tests {
..Config::default()
};
// Capture stderr for dry_run preview
let tokens = vec![OsString::from("echo"), OsString::from("hello")];
// Best-effort: ensure function does not error under dry_run
let res = wrap_and_run_command(None, &cfg, tokens, None, true).await;
assert!(res.is_ok());
// Not asserting output text to keep test platform-agnostic
let err = wrap_and_run_command(None, &cfg, tokens, None, true)
.await
.expect_err("expected failed secret resolution in dry_run");
assert!(err.to_string().contains("Failed to fetch"));
}
}
+6 -6
View File
@@ -3,12 +3,12 @@ use crate::cli::secrets_completer;
use anyhow::{Context, Result};
use clap::Subcommand;
use clap::{
crate_authors, crate_description, crate_name, crate_version, CommandFactory, Parser, ValueEnum,
CommandFactory, Parser, ValueEnum, crate_authors, crate_description, crate_name, crate_version,
};
use clap_complete::{ArgValueCompleter, CompleteEnv};
use crossterm::execute;
use crossterm::terminal::{disable_raw_mode, LeaveAlternateScreen};
use gman::config::{get_config_file_path, load_config, Config};
use crossterm::terminal::{LeaveAlternateScreen, disable_raw_mode};
use gman::config::{Config, get_config_file_path, load_config};
use std::ffi::OsString;
use std::io::{self, IsTerminal, Read, Write};
use std::panic::PanicHookInfo;
@@ -87,7 +87,7 @@ enum Commands {
#[clap(alias = "show")]
Get {
/// Name of the secret to retrieve
#[arg(add = ArgValueCompleter::new(secrets_completer))]
#[arg(add = ArgValueCompleter::new(secrets_completer))]
name: String,
},
@@ -95,7 +95,7 @@ enum Commands {
/// If a provider does not support updating secrets, this command will return an error.
Update {
/// Name of the secret to update
#[arg(add = ArgValueCompleter::new(secrets_completer))]
#[arg(add = ArgValueCompleter::new(secrets_completer))]
name: String,
},
@@ -103,7 +103,7 @@ enum Commands {
#[clap(aliases = &["remove", "rm"])]
Delete {
/// Name of the secret to delete
#[arg(add = ArgValueCompleter::new(secrets_completer))]
#[arg(add = ArgValueCompleter::new(secrets_completer))]
name: String,
},
+1
View File
@@ -11,6 +11,7 @@
//!
//! let rc = RunConfig{
//! name: Some("echo".into()),
//! provider: None,
//! secrets: Some(vec!["api_key".into()]),
//! files: None,
//! flag: None,
+2 -2
View File
@@ -18,14 +18,14 @@ use validator::Validate;
///
/// Example
/// ```no_run
/// use gman::providers::local::GopassProvider;
/// use gman::providers::gopass::GopassProvider;
/// use gman::providers::{SecretProvider, SupportedProvider};
/// use gman::config::Config;
///
/// let provider = GopassProvider::default();
/// let _ = provider.set_secret("MY_SECRET", "value");
/// ```
#[derive(Debug, Clone, Validate, Serialize, Deserialize, PartialEq, Eq)]
#[derive(Debug, Default, Clone, Validate, Serialize, Deserialize, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct GopassProvider {
pub store: Option<String>,
+1 -1
View File
@@ -6,7 +6,7 @@ pub mod aws_secrets_manager;
pub mod azure_key_vault;
pub mod gcp_secret_manager;
mod git_sync;
mod gopass;
pub mod gopass;
pub mod local;
use crate::providers::gopass::GopassProvider;