Skip to content

Commit

Permalink
Merge pull request #10 from opencomputeproject/fix/cleanup_api
Browse files Browse the repository at this point in the history
fix/cleanup api
  • Loading branch information
mimir-d authored Oct 9, 2024
2 parents d7e482d + 71bcce6 commit 115c9fe
Show file tree
Hide file tree
Showing 12 changed files with 350 additions and 311 deletions.
57 changes: 16 additions & 41 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ license = "MIT"
edition = "2021"

[dependencies]
async-trait = "0.1.83"
chrono = "0.4.38"
chrono-tz = "0.10.0"
derive_more = { version = "1.0.0", features = ["full"] }
serde = { version = "1.0.210", features = ["derive"] }
serde_json = "1.0.128"
thiserror = "1.0.64"
Expand All @@ -23,6 +23,7 @@ tokio = { version = "1.40.0", features = [
"fs",
"sync",
] }
unwrap-infallible = "0.1.5"

[dev-dependencies]
anyhow = "1.0.89"
Expand Down
30 changes: 18 additions & 12 deletions src/output/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@

use std::path::Path;
use std::sync::Arc;

use tokio::sync::Mutex;

use crate::output::emitter;
use crate::output as tv;
use crate::output::writer::{self, BufferWriter, FileWriter, StdoutWriter, WriterType};

/// The configuration repository for the TestRun.
pub struct Config {
pub(crate) timestamp_provider: Box<dyn TimestampProvider + Send + Sync + 'static>,
pub(crate) writer: emitter::WriterType,
pub(crate) writer: WriterType,
}

impl Config {
Expand All @@ -33,14 +35,14 @@ impl Config {
/// The builder for the [`Config`] object.
pub struct ConfigBuilder {
timestamp_provider: Box<dyn TimestampProvider + Send + Sync + 'static>,
writer: Option<emitter::WriterType>,
writer: Option<WriterType>,
}

impl ConfigBuilder {
fn new() -> Self {
Self {
timestamp_provider: Box::new(ConfiguredTzProvider { tz: chrono_tz::UTC }),
writer: Some(emitter::WriterType::Stdout(emitter::StdoutWriter::new())),
writer: Some(WriterType::Stdout(StdoutWriter::new())),
}
}

Expand All @@ -58,28 +60,32 @@ impl ConfigBuilder {
}

pub fn with_buffer_output(mut self, buffer: Arc<Mutex<Vec<String>>>) -> Self {
self.writer = Some(emitter::WriterType::Buffer(emitter::BufferWriter::new(
buffer,
)));
self.writer = Some(WriterType::Buffer(BufferWriter::new(buffer)));
self
}

pub async fn with_file_output<P: AsRef<Path>>(
mut self,
path: P,
) -> Result<Self, emitter::WriterError> {
self.writer = Some(emitter::WriterType::File(
emitter::FileWriter::new(path).await?,
));
) -> Result<Self, tv::OcptvError> {
self.writer = Some(WriterType::File(FileWriter::new(path).await?));
Ok(self)
}

pub fn with_custom_output(
mut self,
custom: Box<dyn writer::Writer + Send + Sync + 'static>,
) -> Self {
self.writer = Some(WriterType::Custom(custom));
self
}

pub fn build(self) -> Config {
Config {
timestamp_provider: self.timestamp_provider,
writer: self
.writer
.unwrap_or(emitter::WriterType::Stdout(emitter::StdoutWriter::new())),
.unwrap_or(WriterType::Stdout(StdoutWriter::new())),
}
}
}
Expand Down
107 changes: 22 additions & 85 deletions src/output/emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,97 +4,29 @@
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

use core::fmt::Debug;
use std::clone::Clone;
use std::io;
use std::io::Write;
use std::path::Path;
use std::sync::atomic::{self, Ordering};
use std::sync::Arc;

use tokio::fs::File;
use tokio::io::AsyncWriteExt;
use tokio::sync::Mutex;
use unwrap_infallible::UnwrapInfallible;

use crate::output::config;
use crate::output::{
config,
writer::{self, WriterType},
};
use crate::spec;

#[derive(Debug, thiserror::Error, derive_more::Display)]
#[non_exhaustive]
pub enum WriterError {
IoError(#[from] io::Error),
}

pub(crate) enum WriterType {
Stdout(StdoutWriter),
File(FileWriter),
Buffer(BufferWriter),
}

pub struct FileWriter {
file: Arc<Mutex<File>>,
}

impl FileWriter {
pub async fn new<P: AsRef<Path>>(path: P) -> Result<Self, WriterError> {
let file = File::create(path).await.map_err(WriterError::IoError)?;
Ok(FileWriter {
file: Arc::new(Mutex::new(file)),
})
}

async fn write(&self, s: &str) -> Result<(), WriterError> {
let mut handle = self.file.lock().await;
let mut buf = Vec::<u8>::new();
writeln!(buf, "{}", s)?;
handle.write_all(&buf).await.map_err(WriterError::IoError)?;
handle.flush().await.map_err(WriterError::IoError)?;
Ok(())
}
}

#[derive(Debug)]
pub struct BufferWriter {
buffer: Arc<Mutex<Vec<String>>>,
}

impl BufferWriter {
pub fn new(buffer: Arc<Mutex<Vec<String>>>) -> Self {
Self { buffer }
}

async fn write(&self, s: &str) -> Result<(), WriterError> {
self.buffer.lock().await.push(s.to_string());
Ok(())
}
}

#[derive(Debug, Clone)]
pub struct StdoutWriter {}

#[allow(clippy::new_without_default)]
impl StdoutWriter {
pub fn new() -> Self {
StdoutWriter {}
}

async fn write(&self, s: &str) -> Result<(), WriterError> {
println!("{}", s);
Ok(())
}
}

pub struct JsonEmitter {
// HACK: public for tests, but this should come from config directly to where needed
pub(crate) timestamp_provider: Box<dyn config::TimestampProvider + Send + Sync + 'static>,
writer: WriterType,
writer: writer::WriterType,
seqno: Arc<atomic::AtomicU64>,
}

impl JsonEmitter {
pub(crate) fn new(
timestamp_provider: Box<dyn config::TimestampProvider + Send + Sync + 'static>,
writer: WriterType,
writer: writer::WriterType,
) -> Self {
JsonEmitter {
timestamp_provider,
Expand All @@ -116,13 +48,17 @@ impl JsonEmitter {
self.seqno.fetch_add(1, Ordering::AcqRel)
}

pub async fn emit(&self, object: &spec::RootImpl) -> Result<(), WriterError> {
let serialized = self.serialize_artifact(object);
match self.writer {
WriterType::File(ref file) => file.write(&serialized.to_string()).await?,
WriterType::Stdout(ref stdout) => stdout.write(&serialized.to_string()).await?,
WriterType::Buffer(ref buffer) => buffer.write(&serialized.to_string()).await?,
pub async fn emit(&self, object: &spec::RootImpl) -> Result<(), io::Error> {
let s = self.serialize_artifact(object).to_string();

match &self.writer {
WriterType::File(file) => file.write(&s).await?,
WriterType::Stdout(stdout) => stdout.write(&s).await.unwrap_infallible(),
WriterType::Buffer(buffer) => buffer.write(&s).await.unwrap_infallible(),

WriterType::Custom(custom) => custom.write(&s).await?,
}

Ok(())
}
}
Expand All @@ -132,6 +68,7 @@ mod tests {
use anyhow::{anyhow, Result};
use assert_json_diff::assert_json_include;
use serde_json::json;
use tokio::sync::Mutex;

use super::*;

Expand All @@ -146,10 +83,10 @@ mod tests {
});

let buffer = Arc::new(Mutex::new(vec![]));
let writer = BufferWriter::new(buffer.clone());
let writer = writer::BufferWriter::new(buffer.clone());
let emitter = JsonEmitter::new(
Box::new(config::NullTimestampProvider {}),
WriterType::Buffer(writer),
writer::WriterType::Buffer(writer),
);

emitter
Expand Down Expand Up @@ -184,10 +121,10 @@ mod tests {
});

let buffer = Arc::new(Mutex::new(vec![]));
let writer = BufferWriter::new(buffer.clone());
let writer = writer::BufferWriter::new(buffer.clone());
let emitter = JsonEmitter::new(
Box::new(config::NullTimestampProvider {}),
WriterType::Buffer(writer),
writer::WriterType::Buffer(writer),
);

let version = spec::RootImpl::SchemaVersion(spec::SchemaVersion::default());
Expand Down
Loading

0 comments on commit 115c9fe

Please sign in to comment.