Add more tests
This commit is contained in:
parent
16ba3d8f33
commit
21bfe667ea
@ -1,6 +1,8 @@
|
||||
use std::env::VarError;
|
||||
use std::path::PathBuf;
|
||||
|
||||
static CREDENTIALS_DIRECTORY: &str = "CREDENTIALS_DIRECTORY";
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
#[error("Failed to read credential {name} in directory {path:?}: {io}")]
|
||||
@ -11,14 +13,13 @@ pub enum Error {
|
||||
},
|
||||
#[error("Credential {name} in directory {path:?} is empty")]
|
||||
Empty { name: String, path: PathBuf },
|
||||
#[error("Credential {name} in env variable is empty")]
|
||||
NoEnv { name: String, e: VarError },
|
||||
}
|
||||
|
||||
impl PartialEq for Error {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::Read { .. }, Self::Empty { .. }) | (Self::Empty { .. }, Self::Read { .. }) => {
|
||||
false
|
||||
}
|
||||
(Self::Empty { name: na, path: pa }, Self::Empty { name: nb, path: pb })
|
||||
| (
|
||||
Self::Read {
|
||||
@ -28,22 +29,26 @@ impl PartialEq for Error {
|
||||
name: nb, path: pb, ..
|
||||
},
|
||||
) => na == nb && pa == pb,
|
||||
(Self::NoEnv { name: na, e: ea }, Self::NoEnv { name: nb, e: eb }) => {
|
||||
na == nb && ea == eb
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
pub trait CredentialDirectoryPath {
|
||||
fn path(&self) -> std::result::Result<String, VarError>;
|
||||
pub trait ReadEnv {
|
||||
fn read_env(&self, name: &str) -> std::result::Result<String, VarError>;
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct EnvPath;
|
||||
|
||||
impl CredentialDirectoryPath for EnvPath {
|
||||
fn path(&self) -> std::result::Result<String, VarError> {
|
||||
std::env::var("CREDENTIALS_DIRECTORY")
|
||||
impl ReadEnv for EnvPath {
|
||||
fn read_env(&self, name: &str) -> std::result::Result<String, VarError> {
|
||||
std::env::var(name)
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,14 +59,16 @@ pub trait ReadCredential {
|
||||
///
|
||||
/// This function will return an error if reading the secret from the file fails
|
||||
fn read_credential(&self, name: &str) -> Result<Option<String>>;
|
||||
|
||||
fn file_or_env(&self, file_name: &str, env_name: &str) -> Result<String>;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ReadCredDir<R: CredentialDirectoryPath = EnvPath>(R);
|
||||
pub struct ReadCredDir<R: ReadEnv = EnvPath>(R);
|
||||
|
||||
impl<R: CredentialDirectoryPath> ReadCredential for ReadCredDir<R> {
|
||||
impl<R: ReadEnv> ReadCredential for ReadCredDir<R> {
|
||||
fn read_credential(&self, name: &str) -> Result<Option<String>> {
|
||||
let credentials_dir = self.0.path();
|
||||
let credentials_dir = self.0.read_env(CREDENTIALS_DIRECTORY);
|
||||
let Ok(creds_dir) = credentials_dir.map(PathBuf::from) else {
|
||||
tracing::warn!(
|
||||
"CREDENTIALS_DIRECTORY is not set while looking for {} - not running under systemd?",
|
||||
@ -87,43 +94,56 @@ impl<R: CredentialDirectoryPath> ReadCredential for ReadCredDir<R> {
|
||||
|
||||
Ok(Some(pass))
|
||||
}
|
||||
|
||||
fn file_or_env(&self, file_name: &str, env_name: &str) -> Result<String> {
|
||||
match self.read_credential(file_name) {
|
||||
Ok(Some(v)) => Ok(v),
|
||||
Ok(None) => self.0.read_env(env_name).map_err(|e| Error::NoEnv {
|
||||
name: env_name.into(),
|
||||
e,
|
||||
}),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type ReadCredentialDir = ReadCredDir<EnvPath>;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{CredentialDirectoryPath, Error, ReadCredDir, ReadCredential};
|
||||
use crate::{EnvPath, Error, ReadCredDir, ReadCredential, ReadEnv, CREDENTIALS_DIRECTORY};
|
||||
use std::collections::HashMap;
|
||||
use std::env::VarError;
|
||||
use std::io::ErrorKind;
|
||||
use std::path::PathBuf;
|
||||
use test_ext::with_dir;
|
||||
|
||||
struct MemPath(Option<PathBuf>);
|
||||
struct MemPath<'k, 'v>(HashMap<&'k str, &'v str>);
|
||||
|
||||
impl CredentialDirectoryPath for MemPath {
|
||||
fn path(&self) -> Result<String, VarError> {
|
||||
impl<'k, 'v> ReadEnv for MemPath<'k, 'v> {
|
||||
fn read_env(&self, name: &str) -> Result<String, VarError> {
|
||||
Ok(self
|
||||
.0
|
||||
.as_ref()
|
||||
.get(name)
|
||||
.ok_or_else(|| VarError::NotPresent)?
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_var() {
|
||||
let m = MemPath(None);
|
||||
let m = MemPath(HashMap::new());
|
||||
let res = ReadCredDir(m).read_credential("creds.txt");
|
||||
assert_eq!(res, Ok(None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_dir() {
|
||||
test_ext::with_dir(|dir| {
|
||||
with_dir(|dir| {
|
||||
let p = dir.into_path();
|
||||
let m = MemPath(Some(p.clone()));
|
||||
let m = MemPath(HashMap::from([(
|
||||
CREDENTIALS_DIRECTORY,
|
||||
p.to_str().unwrap(),
|
||||
)]));
|
||||
let res = ReadCredDir(m).read_credential("creds.txt");
|
||||
assert_eq!(
|
||||
res,
|
||||
@ -138,9 +158,12 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn empty_file() {
|
||||
test_ext::with_dir(|dir| {
|
||||
with_dir(|dir| {
|
||||
let p = dir.into_path();
|
||||
let m = MemPath(Some(p.clone()));
|
||||
let m = MemPath(HashMap::from([(
|
||||
CREDENTIALS_DIRECTORY,
|
||||
p.to_str().unwrap(),
|
||||
)]));
|
||||
std::fs::write(p.join("creds.txt"), "").unwrap();
|
||||
|
||||
let res = ReadCredDir(m).read_credential("creds.txt");
|
||||
@ -156,13 +179,50 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn file_with_content() {
|
||||
test_ext::with_dir(|dir| {
|
||||
with_dir(|dir| {
|
||||
let p = dir.into_path();
|
||||
let m = MemPath(Some(p.clone()));
|
||||
let m = MemPath(HashMap::from([(
|
||||
CREDENTIALS_DIRECTORY,
|
||||
p.to_str().unwrap(),
|
||||
)]));
|
||||
std::fs::write(p.join("creds.txt"), "ah87shd8ashd87ashd87").unwrap();
|
||||
|
||||
let res = ReadCredDir(m).read_credential("creds.txt");
|
||||
assert_eq!(res, Ok(Some("ah87shd8ashd87ashd87".into())));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_file_and_env() {
|
||||
let res = ReadCredDir(EnvPath).file_or_env("creds.txt", "NO_FILE_AND_ENV");
|
||||
assert_eq!(
|
||||
res,
|
||||
Err(Error::NoEnv {
|
||||
name: "NO_FILE_AND_ENV".to_string(),
|
||||
e: VarError::NotPresent
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_file_and_empty_env() {
|
||||
std::env::set_var("NO_FILE_AND_EMPTY_ENV", "");
|
||||
|
||||
let res = ReadCredDir(EnvPath).file_or_env("creds.txt", "NO_FILE_AND_ENV");
|
||||
assert_eq!(
|
||||
res,
|
||||
Err(Error::NoEnv {
|
||||
name: "NO_FILE_AND_ENV".to_string(),
|
||||
e: VarError::NotPresent
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_from_env() {
|
||||
std::env::set_var("READ_FROM_ENV", "read_from_env");
|
||||
|
||||
let res = ReadCredDir(EnvPath).file_or_env("creds.txt", "READ_FROM_ENV");
|
||||
assert_eq!(res, Ok("read_from_env".into()));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user