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
+8 -8
View File
@@ -1,7 +1,8 @@
use crate::command::preview_command; use crate::command::preview_command;
use anyhow::{Context, Result, anyhow}; use anyhow::{Context, Result, anyhow};
use clap_complete::CompletionCandidate;
use futures::future::join_all; use futures::future::join_all;
use gman::config::{load_config, Config, RunConfig}; use gman::config::{Config, RunConfig, load_config};
use log::{debug, error}; use log::{debug, error};
use regex::Regex; use regex::Regex;
use std::collections::HashMap; use std::collections::HashMap;
@@ -9,7 +10,6 @@ use std::ffi::{OsStr, OsString};
use std::fs; use std::fs;
use std::path::PathBuf; use std::path::PathBuf;
use std::process::Command; use std::process::Command;
use clap_complete::CompletionCandidate;
use tokio::runtime::Handle; use tokio::runtime::Handle;
const ARG_FORMAT_PLACEHOLDER_KEY: &str = "{{key}}"; const ARG_FORMAT_PLACEHOLDER_KEY: &str = "{{key}}";
@@ -290,7 +290,8 @@ pub fn secrets_completer(current: &OsStr) -> Vec<CompletionCandidate> {
}; };
let secrets_provider = provider_config.extract_provider(); let secrets_provider = provider_config.extract_provider();
let h = Handle::current(); let h = Handle::current();
tokio::task::block_in_place(|| h.block_on(secrets_provider.list_secrets())).unwrap_or_default() tokio::task::block_in_place(|| h.block_on(secrets_provider.list_secrets()))
.unwrap_or_default()
.into_iter() .into_iter()
.filter(|s| s.starts_with(&*cur)) .filter(|s| s.starts_with(&*cur))
.map(CompletionCandidate::new) .map(CompletionCandidate::new)
@@ -402,11 +403,10 @@ mod tests {
..Config::default() ..Config::default()
}; };
// Capture stderr for dry_run preview
let tokens = vec![OsString::from("echo"), OsString::from("hello")]; let tokens = vec![OsString::from("echo"), OsString::from("hello")];
// Best-effort: ensure function does not error under dry_run let err = wrap_and_run_command(None, &cfg, tokens, None, true)
let res = wrap_and_run_command(None, &cfg, tokens, None, true).await; .await
assert!(res.is_ok()); .expect_err("expected failed secret resolution in dry_run");
// Not asserting output text to keep test platform-agnostic assert!(err.to_string().contains("Failed to fetch"));
} }
} }
+3 -3
View File
@@ -3,12 +3,12 @@ use crate::cli::secrets_completer;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use clap::Subcommand; use clap::Subcommand;
use clap::{ 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 clap_complete::{ArgValueCompleter, CompleteEnv};
use crossterm::execute; use crossterm::execute;
use crossterm::terminal::{disable_raw_mode, LeaveAlternateScreen}; use crossterm::terminal::{LeaveAlternateScreen, disable_raw_mode};
use gman::config::{get_config_file_path, load_config, Config}; use gman::config::{Config, get_config_file_path, load_config};
use std::ffi::OsString; use std::ffi::OsString;
use std::io::{self, IsTerminal, Read, Write}; use std::io::{self, IsTerminal, Read, Write};
use std::panic::PanicHookInfo; use std::panic::PanicHookInfo;
+1
View File
@@ -11,6 +11,7 @@
//! //!
//! let rc = RunConfig{ //! let rc = RunConfig{
//! name: Some("echo".into()), //! name: Some("echo".into()),
//! provider: None,
//! secrets: Some(vec!["api_key".into()]), //! secrets: Some(vec!["api_key".into()]),
//! files: None, //! files: None,
//! flag: None, //! flag: None,
+2 -2
View File
@@ -18,14 +18,14 @@ use validator::Validate;
/// ///
/// Example /// Example
/// ```no_run /// ```no_run
/// use gman::providers::local::GopassProvider; /// use gman::providers::gopass::GopassProvider;
/// use gman::providers::{SecretProvider, SupportedProvider}; /// use gman::providers::{SecretProvider, SupportedProvider};
/// use gman::config::Config; /// use gman::config::Config;
/// ///
/// let provider = GopassProvider::default(); /// let provider = GopassProvider::default();
/// let _ = provider.set_secret("MY_SECRET", "value"); /// 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)] #[serde(deny_unknown_fields)]
pub struct GopassProvider { pub struct GopassProvider {
pub store: Option<String>, pub store: Option<String>,
+1 -1
View File
@@ -6,7 +6,7 @@ pub mod aws_secrets_manager;
pub mod azure_key_vault; pub mod azure_key_vault;
pub mod gcp_secret_manager; pub mod gcp_secret_manager;
mod git_sync; mod git_sync;
mod gopass; pub mod gopass;
pub mod local; pub mod local;
use crate::providers::gopass::GopassProvider; use crate::providers::gopass::GopassProvider;
+53
View File
@@ -0,0 +1,53 @@
use gman::config::{Config, ProviderConfig};
use gman::providers::{SecretProvider, SupportedProvider};
use pretty_assertions::{assert_eq, assert_str_eq};
use validator::Validate;
#[test]
fn test_gopass_supported_provider_display_and_validate_from_yaml() {
// Build a SupportedProvider via YAML to avoid direct type import
let yaml = r#"---
type: gopass
store: personal
"#;
let sp: SupportedProvider = serde_yaml::from_str(yaml).expect("valid supported provider yaml");
// Validate delegates to inner provider (no required fields)
assert!(sp.validate().is_ok());
// Display formatting for the enum variant
assert_eq!(sp.to_string(), "gopass");
}
#[test]
fn test_provider_config_with_gopass_deserialize_and_extract() {
// Minimal ProviderConfig YAML using the gopass variant
let yaml = r#"---
name: gopass
type: gopass
"#;
let pc: ProviderConfig = serde_yaml::from_str(yaml).expect("valid provider config yaml");
// Gopass has no required fields, so validation should pass
assert!(pc.validate().is_ok());
// Extract the provider and inspect its name via the trait
let mut pc_owned = pc.clone();
let provider: &mut dyn SecretProvider = pc_owned.extract_provider();
assert_str_eq!(provider.name(), "GopassProvider");
// Round-trip through Config with default_provider
let cfg_yaml = r#"---
default_provider: gopass
providers:
- name: gopass
type: gopass
store: personal
"#;
let cfg: Config = serde_yaml::from_str(cfg_yaml).expect("valid config yaml");
assert!(cfg.validate().is_ok());
let extracted = cfg
.extract_provider_config(None)
.expect("should find default provider");
assert_eq!(extracted.name.as_deref(), Some("gopass"));
}
+1
View File
@@ -1,5 +1,6 @@
mod aws_secrets_manager_tests; mod aws_secrets_manager_tests;
mod azure_key_vault_tests; mod azure_key_vault_tests;
mod gcp_secret_manager_tests; mod gcp_secret_manager_tests;
mod gopass_tests;
mod local_tests; mod local_tests;
mod provider_tests; mod provider_tests;