use assert_cmd::prelude::*; use predicates::prelude::*; use std::process::Command; use std::fs; use std::path::PathBuf; fn get_test_vault_path() -> PathBuf { PathBuf::from("/tmp/api-token-vault-test-vault.json") } fn cleanup_test_vault() { let vault_path = get_test_vault_path(); if vault_path.exists() { let _ = fs::remove_file(&vault_path); } } #[test] fn test_cli_help() { let mut cmd = Command::cargo_bin("api-token-vault").unwrap(); cmd.arg("--help"); cmd.assert() .success() .stdout(predicate::str::contains("API Token Vault")); } #[test] fn test_cli_version() { let mut cmd = Command::cargo_bin("api-token-vault").unwrap(); cmd.arg("--version"); cmd.assert() .success() .stdout(predicate::str::contains("0.1.0")); } #[test] fn test_init_command() { cleanup_test_vault(); let mut cmd = Command::cargo_bin("api-token-vault").unwrap(); cmd.arg("init") .arg("--project") .arg("test-init-project") .env("API_VAULT_PROJECT", ""); let assert = cmd.assert(); cleanup_test_vault(); } #[test] fn test_generate_command() { cleanup_test_vault(); let password = "test_password_123"; let project = "test-gen-project"; let vault_dir = PathBuf::from("/tmp/.config/api-token-vault"); let vault_path = vault_dir.join("test-gen-project.json"); if vault_path.exists() { let _ = fs::remove_file(&vault_path); } if !vault_dir.exists() { let _ = fs::create_dir_all(&vault_dir); } let mut init_cmd = Command::cargo_bin("api-token-vault").unwrap(); init_cmd.arg("init") .arg("--master-password") .arg(password) .arg("--project") .arg(project); let _ = init_cmd.output(); let mut gen_cmd = Command::cargo_bin("api-token-vault").unwrap(); gen_cmd.arg("generate") .arg("--name") .arg("test_token") .arg("--master-password") .arg(password) .arg("--project") .arg(project); gen_cmd.assert() .success() .stdout(predicate::str::contains("Generated token")); if vault_path.exists() { let _ = fs::remove_file(&vault_path); } } #[test] fn test_list_command() { cleanup_test_vault(); let password = "test_password"; let project = "test-list-project"; let vault_dir = PathBuf::from("/tmp/.config/api-token-vault"); let vault_path = vault_dir.join("test-list-project.json"); if vault_path.exists() { let _ = fs::remove_file(&vault_path); } if !vault_dir.exists() { let _ = fs::create_dir_all(&vault_dir); } let mut init_cmd = Command::cargo_bin("api-token-vault").unwrap(); init_cmd.arg("init") .arg("--master-password") .arg(password) .arg("--project") .arg(project); let _ = init_cmd.output(); let mut list_cmd = Command::cargo_bin("api-token-vault").unwrap(); list_cmd.arg("list") .arg("--master-password") .arg(password) .arg("--project") .arg(project); list_cmd.assert() .success() .stdout(predicate::str::contains("Tokens in vault")); if vault_path.exists() { let _ = fs::remove_file(&vault_path); } } #[test] fn test_rotate_command() { cleanup_test_vault(); let password = "test_password"; let project = "test-rotate-project"; let vault_dir = PathBuf::from("/tmp/.config/api-token-vault"); let vault_path = vault_dir.join("test-rotate-project.json"); if vault_path.exists() { let _ = fs::remove_file(&vault_path); } if !vault_dir.exists() { let _ = fs::create_dir_all(&vault_dir); } let mut init_cmd = Command::cargo_bin("api-token-vault").unwrap(); init_cmd.arg("init") .arg("--master-password") .arg(password) .arg("--project") .arg(project); let _ = init_cmd.output(); let mut gen_cmd = Command::cargo_bin("api-token-vault").unwrap(); gen_cmd.arg("generate") .arg("--name") .arg("rotate_me") .arg("--master-password") .arg(password) .arg("--project") .arg(project); let _ = gen_cmd.output(); let mut rotate_cmd = Command::cargo_bin("api-token-vault").unwrap(); rotate_cmd.arg("rotate") .arg("--name") .arg("rotate_me") .arg("--force") .arg("--master-password") .arg(password) .arg("--project") .arg(project); rotate_cmd.assert() .success() .stdout(predicate::str::contains("Rotated token")); if vault_path.exists() { let _ = fs::remove_file(&vault_path); } } #[test] fn test_set_rotation_command() { cleanup_test_vault(); let password = "test_password"; let project = "test-set-rotation-project"; let vault_dir = PathBuf::from("/tmp/.config/api-token-vault"); let vault_path = vault_dir.join("test-set-rotation-project.json"); if vault_path.exists() { let _ = fs::remove_file(&vault_path); } if !vault_dir.exists() { let _ = fs::create_dir_all(&vault_dir); } let mut init_cmd = Command::cargo_bin("api-token-vault").unwrap(); init_cmd.arg("init") .arg("--master-password") .arg(password) .arg("--project") .arg(project); let _ = init_cmd.output(); let mut gen_cmd = Command::cargo_bin("api-token-vault").unwrap(); gen_cmd.arg("generate") .arg("--name") .arg("auto_rotate_token") .arg("--master-password") .arg(password) .arg("--project") .arg(project); let _ = gen_cmd.output(); let mut set_cmd = Command::cargo_bin("api-token-vault").unwrap(); set_cmd.arg("set-rotation") .arg("--name") .arg("auto_rotate_token") .arg("--days") .arg("30") .arg("--master-password") .arg(password) .arg("--project") .arg(project); set_cmd.assert() .success() .stdout(predicate::str::contains("Auto-rotation set")); if vault_path.exists() { let _ = fs::remove_file(&vault_path); } } #[test] fn test_check_expired_command() { cleanup_test_vault(); let password = "test_password"; let project = "test-check-expired-project"; let vault_dir = PathBuf::from("/tmp/.config/api-token-vault"); let vault_path = vault_dir.join("test-check-expired-project.json"); if vault_path.exists() { let _ = fs::remove_file(&vault_path); } if !vault_dir.exists() { let _ = fs::create_dir_all(&vault_dir); } let mut init_cmd = Command::cargo_bin("api-token-vault").unwrap(); init_cmd.arg("init") .arg("--master-password") .arg(password) .arg("--project") .arg(project); let _ = init_cmd.output(); let mut gen_cmd = Command::cargo_bin("api-token-vault").unwrap(); gen_cmd.arg("generate") .arg("--name") .arg("expired_token") .arg("--master-password") .arg(password) .arg("--project") .arg(project); let _ = gen_cmd.output(); let mut check_cmd = Command::cargo_bin("api-token-vault").unwrap(); check_cmd.arg("check-expired") .arg("--master-password") .arg(password) .arg("--project") .arg(project); check_cmd.assert() .success(); if vault_path.exists() { let _ = fs::remove_file(&vault_path); } } #[test] fn test_inject_command() { cleanup_test_vault(); let password = "test_password"; let project = "test-inject-project"; let env_path = PathBuf::from("/tmp/test-inject.env"); let vault_dir = PathBuf::from("/tmp/.config/api-token-vault"); let vault_path = vault_dir.join("test-inject-project.json"); if vault_path.exists() { let _ = fs::remove_file(&vault_path); } if !vault_dir.exists() { let _ = fs::create_dir_all(&vault_dir); } if env_path.exists() { let _ = fs::remove_file(&env_path); } let mut init_cmd = Command::cargo_bin("api-token-vault").unwrap(); init_cmd.arg("init") .arg("--master-password") .arg(password) .arg("--project") .arg(project); let _ = init_cmd.output(); let mut gen_cmd = Command::cargo_bin("api-token-vault").unwrap(); gen_cmd.arg("generate") .arg("--name") .arg("injectable_token") .arg("--master-password") .arg(password) .arg("--project") .arg(project); let _ = gen_cmd.output(); let mut inject_cmd = Command::cargo_bin("api-token-vault").unwrap(); inject_cmd.arg("inject") .arg("--env-file") .arg(env_path.to_str().unwrap()) .arg("--master-password") .arg(password) .arg("--project") .arg(project); inject_cmd.assert() .success() .stdout(predicate::str::contains("injected")); if vault_path.exists() { let _ = fs::remove_file(&vault_path); } if env_path.exists() { let _ = fs::remove_file(&env_path); } } #[test] fn test_dry_run_inject() { cleanup_test_vault(); let password = "test_password"; let project = "test-dry-run-project"; let env_path = PathBuf::from("/tmp/test-dry-run.env"); let vault_dir = PathBuf::from("/tmp/.config/api-token-vault"); let vault_path = vault_dir.join("test-dry-run-project.json"); if vault_path.exists() { let _ = fs::remove_file(&vault_path); } if !vault_dir.exists() { let _ = fs::create_dir_all(&vault_dir); } if env_path.exists() { let _ = fs::remove_file(&env_path); } let mut init_cmd = Command::cargo_bin("token-vault").unwrap(); init_cmd.arg("init") .arg("--master-password") .arg(password) .arg("--project") .arg(project); let _ = init_cmd.output(); let mut gen_cmd = Command::cargo_bin("api-token-vault").unwrap(); gen_cmd.arg("generate") .arg("--name") .arg("dry_token") .arg("--master-password") .arg(password) .arg("--project") .arg(project); let _ = gen_cmd.output(); fs::write(&env_path, "EXISTING=value").unwrap(); let mut inject_cmd = Command::cargo_bin("api-token-vault").unwrap(); inject_cmd.arg("inject") .arg("--env-file") .arg(env_path.to_str().unwrap()) .arg("--dry-run") .arg("--master-password") .arg(password) .arg("--project") .arg(project); inject_cmd.assert() .success() .stdout(predicate::str::contains("Dry run")); let content = fs::read_to_string(&env_path).unwrap(); assert_eq!(content.trim(), "EXISTING=value"); if vault_path.exists() { let _ = fs::remove_file(&vault_path); } if env_path.exists() { let _ = fs::remove_file(&env_path); } }