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