use std::cmp::min;
use std::path::Path;
use std::str::FromStr;
use std::{
fs::File,
io::{ErrorKind, Seek, Write},
};
use rstest::fixture;
mod test_instant;
pub use test_instant::*;
mod test_connection_checker;
pub use test_connection_checker::*;
use crate::metrics::{KeyedMetricReading, MetricReading, MetricStringKey, MetricTimestamp};
pub struct SizeLimitedFile {
file: File,
limit: usize,
written: usize,
}
impl SizeLimitedFile {
#[allow(dead_code)]
pub fn new(file: File, limit: usize) -> Self {
Self {
file,
limit,
written: 0,
}
}
}
impl Write for SizeLimitedFile {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
let bytes_to_write = buf.len().min(self.limit - self.written);
if bytes_to_write == 0 {
Err(std::io::Error::new(
ErrorKind::WriteZero,
"File size limit reached",
))
} else {
self.written += bytes_to_write;
self.file.write(&buf[..bytes_to_write])
}
}
fn flush(&mut self) -> std::io::Result<()> {
self.file.flush()
}
}
impl Seek for SizeLimitedFile {
fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
self.file.seek(pos)
}
}
pub fn create_file_with_size(path: &Path, size: u64) -> std::io::Result<()> {
let mut file = File::create(path)?;
let buffer = vec![0; min(4096, size as usize)];
let mut remaining = size;
while remaining > 0 {
let bytes_to_write = min(remaining, buffer.len() as u64);
file.write_all(&buffer[..bytes_to_write as usize])?;
remaining -= bytes_to_write;
}
Ok(())
}
pub fn create_file_with_contents(path: &Path, contents: &[u8]) -> std::io::Result<()> {
let mut file = File::create(path)?;
file.write_all(contents)?;
Ok(())
}
#[fixture]
pub fn setup_logger() {
let _ = stderrlog::new().module("memfaultd").verbosity(10).init();
}
macro_rules! set_snapshot_suffix {
($($expr:expr),*) => {
let mut settings = insta::Settings::clone_current();
settings.set_snapshot_suffix(format!($($expr,)*));
let _guard = settings.bind_to_scope();
}
}
#[cfg(test)]
pub fn in_histograms(
metrics: Vec<(&'static str, f64)>,
) -> impl Iterator<Item = KeyedMetricReading> {
metrics
.into_iter()
.enumerate()
.map(|(i, (name, value))| KeyedMetricReading {
name: MetricStringKey::from_str(name).unwrap(),
value: MetricReading::Histogram {
value,
timestamp: MetricTimestamp::from_str("2021-01-01T00:00:00Z").unwrap()
+ chrono::Duration::seconds(i as i64),
},
})
}
#[cfg(test)]
pub fn in_counters(metrics: Vec<(&'static str, f64)>) -> impl Iterator<Item = KeyedMetricReading> {
metrics
.into_iter()
.enumerate()
.map(|(i, (name, value))| KeyedMetricReading {
name: MetricStringKey::from_str(name).unwrap(),
value: MetricReading::Counter {
value,
timestamp: MetricTimestamp::from_str("2021-01-01T00:00:00Z").unwrap()
+ chrono::Duration::seconds(i as i64),
},
})
}
pub fn in_bools(metrics: Vec<(&'static str, bool)>) -> impl Iterator<Item = KeyedMetricReading> {
metrics
.into_iter()
.enumerate()
.map(|(i, (name, value))| KeyedMetricReading {
name: MetricStringKey::from_str(name).unwrap(),
value: MetricReading::Bool {
value,
timestamp: MetricTimestamp::from_str("1991-03-25T00:00:00Z").unwrap()
+ chrono::Duration::seconds(i as i64),
},
})
}
pub(crate) use set_snapshot_suffix;