src/keys.rs (85 lines of code) (raw):
use serde_json::{from_str, Value};
use slog::Logger;
use std::collections::HashSet;
use std::fs::read_to_string;
use std::path::PathBuf;
pub fn load(file_path: PathBuf, app_log: Logger) -> HashSet<String> {
let mut keys: HashSet<String> = HashSet::new();
match read_to_string(file_path) {
Ok(contents) => match from_str::<Value>(&contents) {
Ok(json_value) => {
if let Some(array) = json_value.as_array() {
for item in array {
if let Value::String(string) = &item {
keys.insert(string.to_string());
}
}
}
}
Err(err) => {
slog::error!(app_log, "Error parsing api keys file. {}", err)
}
},
Err(err) => {
slog::error!(app_log, "Error reading api keys file. {}", err)
}
}
keys
}
#[cfg(test)]
mod tests {
use crate::keys::load;
use slog::Drain;
use slog::{OwnedKVList, Record};
use std::{
fs,
path::PathBuf,
sync::{Arc, Mutex},
};
struct VecDrain {
logs: Arc<Mutex<Vec<String>>>,
}
impl Drain for VecDrain {
type Ok = ();
type Err = slog::Never;
fn log(&self, record: &Record, _values: &OwnedKVList) -> Result<Self::Ok, Self::Err> {
if let Ok(mut logs) = self.logs.lock() {
logs.push(record.level().to_string() + " / " + &record.msg().to_string());
}
Ok(())
}
}
#[test]
fn test_load() {
// setup
let logs = Arc::new(Mutex::new(Vec::new()));
let logger =
slog::Logger::root(slog::Fuse::new(VecDrain { logs: logs.clone() }), slog::o!());
let missing_file: PathBuf = "./missing_file.json".into();
let corrupt_file: PathBuf = "./corrupt_file.json".into();
let good_file: PathBuf = "./good_file.json".into();
let _ = fs::remove_file(missing_file.clone());
let _ = fs::write(corrupt_file.clone(), "[\"foo\"]z");
let _ = fs::write(good_file.clone(), "[\"foo\"]");
// tests
let missing_set = load(missing_file.clone(), logger.clone());
assert!(missing_set.is_empty());
assert!(logs
.lock()
.unwrap()
.pop()
.unwrap()
.starts_with("ERRO / Error reading api keys file"));
let corrupt_set = load(corrupt_file.clone(), logger.clone());
assert!(corrupt_set.is_empty());
assert!(logs
.lock()
.unwrap()
.pop()
.unwrap()
.starts_with("ERRO / Error parsing api keys file"));
let good_set = load(good_file.clone(), logger.clone());
assert!(good_set.len() == 1);
assert!(logs.lock().unwrap().pop().is_none());
// cleanup
let _ = fs::remove_file(corrupt_file);
let _ = fs::remove_file(good_file);
}
}