modio-logger 0.5.2

modio-logger Dbus service
Documentation
// Author: D.S. Ljungmark <spider@skuggor.se>, Modio AB
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::error::Error;
use std::path::PathBuf;

use event_listener::Event;
use event_listener::EventListener;

use fsipc::legacy::fsipcProxy;

use super::logger::{Logger, LoggerPing};
use super::timefail::Timefail;
use super::LOGGER_PATH;
use modio_logger_db::{Datastore, SqlitePoolBuilder};

use zbus::Connection;

use tempfile;

#[derive(Clone)]
pub struct TestPaths {
    pub timefail_path: PathBuf,
    pub timeadjust_path: PathBuf,
    pub dbpath: PathBuf,
}

pub struct Tempbase {
    #[allow(dead_code)]
    dir: tempfile::TempDir,
    #[allow(dead_code)]
    dbfile: tempfile::NamedTempFile,
    pub paths: TestPaths,
}

impl Tempbase {
    #[must_use]
    pub fn new() -> Self {
        let dir = tempfile::Builder::new()
            .prefix("modio-logger")
            .tempdir()
            .expect("Error tempdir");

        let dbfile = tempfile::Builder::new()
            .prefix("database")
            .suffix(".sqlite")
            .tempfile_in(dir.path())
            .expect("Error on tempfile");

        let paths = TestPaths {
            dbpath: dbfile.path().to_path_buf(),
            timeadjust_path: dir.path().join("timeadjust"),
            timefail_path: dir.path().join("timefail"),
        };

        Self { dir, dbfile, paths }
    }
}

impl Default for Tempbase {
    fn default() -> Self {
        Self::new()
    }
}

#[allow(dead_code)]
pub async fn test_server_with_paths(
    name: String,
    ready: Event,
    done: EventListener,
    paths: TestPaths,
) {
    let timefail = Timefail::new(paths.timefail_path, paths.timeadjust_path);
    let pool = SqlitePoolBuilder::new()
        .migrate(true)
        .db_path(&paths.dbpath)
        .build()
        .await
        .expect("Error opening database");
    let ds = Datastore::new(pool)
        .await
        .expect("Error initializing datastore");
    let logger = Logger::new(timefail, ds)
        .await
        .expect("Error spawning logger");
    let loggerp = LoggerPing {};
    let conn = Connection::session()
        .await
        .expect("Error connecting to session bus");
    conn.object_server()
        .at(LOGGER_PATH, logger)
        .await
        .expect("Error binding path");
    conn.object_server()
        .at(LOGGER_PATH, loggerp)
        .await
        .expect("Error binding path");
    conn.request_name(name.clone())
        .await
        .expect("Error requesting name");
    // Signal that we are ready and listening
    ready.notify(1);
    // Wait until test-case is done.
    done.await;
    // Release the name so we don't collide with another server task
    conn.release_name(name.clone())
        .await
        .expect("failed to release our name");
}

#[allow(dead_code)]
/// Create a test server with a new tempbase db.
pub async fn test_server(name: String, ready: Event, done: EventListener) {
    let _ = env_logger::builder().is_test(true).try_init();
    let base = Tempbase::new();
    test_server_with_paths(name, ready, done, base.paths).await;
}

#[allow(dead_code)]
pub async fn launch_server(
    line: u32,
) -> Result<
    (
        fsipcProxy<'static>,
        event_listener::Event,
        async_std::task::JoinHandle<()>,
    ),
    Box<dyn Error>,
> {
    let test_complete = event_listener::Event::new();
    let test_waiter = test_complete.listen();

    let server = event_listener::Event::new();
    let server_ready = server.listen();

    let server_name = format!("se.modio.logger.TestCase{}", line);
    dbg!(&server_name);
    let client_name = server_name.clone();
    let task = async_std::task::spawn(test_server(server_name, server, test_waiter));
    server_ready.await;

    let conn = zbus::Connection::session().await?;
    let proxy = fsipcProxy::builder(&conn)
        .path(LOGGER_PATH)?
        .destination(client_name)?
        .build()
        .await?;
    Ok((proxy, test_complete, task))
}