use std::sync::Mutex;
use secrecy::{ExposeSecret, SecretString};
use crate::error::OlError;
use super::{CredentialStore, ERR_NO_CREDENTIALS};
pub struct InMemoryCredentialStore {
inner: Mutex<Option<String>>,
}
impl InMemoryCredentialStore {
pub fn new() -> Self {
Self {
inner: Mutex::new(None),
}
}
}
impl Default for InMemoryCredentialStore {
fn default() -> Self {
Self::new()
}
}
impl CredentialStore for InMemoryCredentialStore {
fn store(&self, key: SecretString) -> Result<(), OlError> {
let mut guard = self.inner.lock().unwrap();
*guard = Some(key.expose_secret().to_string());
Ok(())
}
fn retrieve(&self) -> Result<SecretString, OlError> {
let guard = self.inner.lock().unwrap();
match &*guard {
Some(val) => Ok(SecretString::from(val.clone())),
None => Err(OlError::new(ERR_NO_CREDENTIALS, "No credential stored")),
}
}
fn delete(&self) -> Result<(), OlError> {
let mut guard = self.inner.lock().unwrap();
*guard = None;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use secrecy::ExposeSecret;
#[test]
fn test_in_memory_store_then_retrieve_returns_same_value() {
let store = InMemoryCredentialStore::new();
store
.store(SecretString::from("test-api-key".to_string()))
.unwrap();
let retrieved = store.retrieve().unwrap();
assert_eq!(retrieved.expose_secret(), "test-api-key");
}
#[test]
fn test_in_memory_delete_then_retrieve_returns_err() {
let store = InMemoryCredentialStore::new();
store
.store(SecretString::from("some-key".to_string()))
.unwrap();
store.delete().unwrap();
let result = store.retrieve();
assert!(result.is_err());
assert_eq!(result.unwrap_err().code, ERR_NO_CREDENTIALS);
}
#[test]
fn test_in_memory_retrieve_on_empty_store_returns_err() {
let store = InMemoryCredentialStore::new();
let result = store.retrieve();
assert!(result.is_err());
assert_eq!(result.unwrap_err().code, ERR_NO_CREDENTIALS);
}
#[test]
fn test_in_memory_store_overwrites_existing() {
let store = InMemoryCredentialStore::new();
store
.store(SecretString::from("first".to_string()))
.unwrap();
store
.store(SecretString::from("second".to_string()))
.unwrap();
let retrieved = store.retrieve().unwrap();
assert_eq!(retrieved.expose_secret(), "second");
}
}