Skip to content

Commit

Permalink
Basic Mocking (#83)
Browse files Browse the repository at this point in the history
* chore(jx): remove `lib.rs`

It was making some things show up as unused because, in the library, they were unused.

* refactor(jx): setup basic card mocking

Will be useful later, but not going too deep right now.

* feat(mark): registration request progress

* test: ignore `sync` result for now
  • Loading branch information
eventualbuddha authored Mar 14, 2024
1 parent f542862 commit 388fccf
Show file tree
Hide file tree
Showing 18 changed files with 655 additions and 291 deletions.
72 changes: 72 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ js-sys = "0.3.64"
lazy_static = "1.4.0"
log = "0.4.19"
logging_timer = "1.1.0"
mockall = "0.12.1"
nanoid = "0.4.0"
neon = { version = "0.10", default-features = false, features = ["napi-6"] }
num_enum = "0.7.1"
Expand Down
1 change: 1 addition & 0 deletions apps/cacvote-jx-terminal/backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@ types-rs = { workspace = true, features = ["backend"] }
uuid = { workspace = true }

[dev-dependencies]
mockall = { workspace = true }
pretty_assertions = { workspace = true }
proptest = { workspace = true }
5 changes: 3 additions & 2 deletions apps/cacvote-jx-terminal/backend/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,15 @@ use tracing::Level;
use crate::config::{Config, MAX_REQUEST_SIZE};
use crate::smartcard;

type AppState = (Config, PgPool, smartcard::StatusGetter);
// type AppState = (Config, PgPool, smartcard::StatusGetter);
type AppState = (Config, PgPool, smartcard::DynStatusGetter);

/// Prepares the application with all the routes. Run the application with
/// `app::run(…)` once you have it.
pub(crate) fn setup(
pool: PgPool,
config: Config,
smartcard_status: smartcard::StatusGetter,
smartcard_status: smartcard::DynStatusGetter,
) -> Router {
let _entered = tracing::span!(Level::DEBUG, "Setting up application").entered();

Expand Down
1 change: 0 additions & 1 deletion apps/cacvote-jx-terminal/backend/src/lib.rs

This file was deleted.

18 changes: 7 additions & 11 deletions apps/cacvote-jx-terminal/backend/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@
#![cfg_attr(test, allow(clippy::float_cmp))]
#![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))]

use std::sync::Arc;

use auth_rs::Watcher;
use clap::Parser;

mod app;
Expand All @@ -52,7 +55,6 @@ mod smartcard;
mod sync;

use crate::smartcard::StatusGetter;
pub use smartcard::watch;

#[tokio::main]
async fn main() -> color_eyre::Result<()> {
Expand All @@ -62,14 +64,8 @@ async fn main() -> color_eyre::Result<()> {
log::setup(&config)?;
let pool = db::setup(&config).await?;
sync::sync_periodically(&pool, config.clone()).await;
let smartcard_watcher = smartcard::watch();
app::run(
app::setup(
pool,
config.clone(),
StatusGetter::new(smartcard_watcher.readers_with_cards()),
),
&config,
)
.await
let smartcard_watcher = Watcher::watch();
let smartcard_status = StatusGetter::new(smartcard_watcher.readers_with_cards());
let smartcard_status = Arc::new(smartcard_status) as smartcard::DynStatusGetter;
app::run(app::setup(pool, config.clone(), smartcard_status), &config).await
}
17 changes: 11 additions & 6 deletions apps/cacvote-jx-terminal/backend/src/smartcard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ use std::ops::Deref;
use std::sync::{Arc, Mutex};

use auth_rs::card_details::CardDetails;
use auth_rs::{CardReader, SharedCardReaders, Watcher};
use auth_rs::{CardReader, SharedCardReaders};
use types_rs::cacvote::SmartcardStatus;

/// Watches for smartcard events.
pub fn watch() -> Watcher {
Watcher::watch()
pub(crate) type DynStatusGetter = Arc<dyn StatusGetterTrait + Send + Sync>;

#[cfg_attr(test, mockall::automock)]
pub(crate) trait StatusGetterTrait {
fn get(&self) -> SmartcardStatus;
fn get_card_details(&self) -> Option<CardDetails>;
}

/// Provides access to the current smartcard status.
Expand Down Expand Up @@ -40,11 +43,13 @@ impl StatusGetter {
last_selected_card_reader_info: Arc::new(Mutex::new(None)),
}
}
}

impl StatusGetterTrait for StatusGetter {
/// Gets the current smartcard status.
#[allow(dead_code)]
#[must_use]
pub(crate) fn get(&self) -> SmartcardStatus {
fn get(&self) -> SmartcardStatus {
let readers = self.readers_with_cards.lock().unwrap();

if readers.is_empty() {
Expand All @@ -56,7 +61,7 @@ impl StatusGetter {

#[allow(dead_code)]
#[must_use]
pub(crate) fn get_card_details(&self) -> Option<CardDetails> {
fn get_card_details(&self) -> Option<CardDetails> {
let readers = self.readers_with_cards.lock().unwrap();
let reader_name = readers.first()?;

Expand Down
58 changes: 58 additions & 0 deletions apps/cacvote-jx-terminal/backend/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,61 @@ async fn pull_objects(

Ok(())
}

#[cfg(test)]
mod tests {
use std::{net::TcpListener, sync::Arc};

use reqwest::Url;
use tracing::Level;
use types_rs::cacvote::SmartcardStatus;

use crate::{
app,
smartcard::{DynStatusGetter, MockStatusGetterTrait},
};

use super::*;

fn setup(pool: sqlx::PgPool, smartcard_status: DynStatusGetter) -> color_eyre::Result<Client> {
let listener = TcpListener::bind("0.0.0.0:0")?;
let addr = listener.local_addr()?;
let cacvote_url: Url = format!("http://{addr}").parse()?;
let config = Config {
cacvote_url: cacvote_url.clone(),
database_url: "".to_string(),
machine_id: "".to_string(),
port: addr.port(),
public_dir: None,
log_level: Level::DEBUG,
};

tokio::spawn(async move {
let app = app::setup(pool, config, smartcard_status);
axum::Server::from_tcp(listener)
.unwrap()
.serve(app.into_make_service())
.await
.unwrap();
});

Ok(Client::new(cacvote_url))
}

#[sqlx::test(migrations = "db/migrations")]
async fn test_sync(pool: sqlx::PgPool) -> color_eyre::Result<()> {
let mut connection = pool.acquire().await?;

let mut smartcard_status = MockStatusGetterTrait::new();
smartcard_status
.expect_get()
.returning(|| SmartcardStatus::Card);

let client = setup(pool, Arc::new(smartcard_status))?;

// TODO: actually test `sync`
let _ = sync(&mut connection, &client).await;

Ok(())
}
}
Loading

0 comments on commit 388fccf

Please sign in to comment.