//! Mock verifying application for Marshaled wrapper tests. //! //! This module provides a generic mock application that implements the //! `Application` trait, suitable for testing the `Marshaled` wrapper in //! both standard and coding variants. use crate::{marshal::ancestry::Ancestry, CertifiableBlock, Epochable}; use commonware_runtime::deterministic; use commonware_utils::{ channel::{fallible::OneshotExt, oneshot}, sync::Mutex, }; use std::{marker::PhantomData, sync::Arc}; /// A mock application that implements `Application` for testing. /// /// This mock: /// - Returns the configured block (if any) from `propose()` /// - Returns a configurable result from `verify()` #[derive(Clone)] pub struct MockVerifyingApp { /// The block returned by `propose`. If `None`, `propose` returns `None`. pub propose_result: Option, /// The result returned by `verify`. pub verify_result: bool, _phantom: PhantomData, } impl MockVerifyingApp { /// Create a new mock verifying application. pub fn new() -> Self { Self { propose_result: None, verify_result: true, _phantom: PhantomData, } } /// Create a new mock verifying application with a fixed verify result. pub fn with_verify_result(verify_result: bool) -> Self { Self { propose_result: None, verify_result, _phantom: PhantomData, } } /// Configure the block returned by `propose`. pub fn with_propose_result(mut self, block: B) -> Self { self.propose_result = Some(block); self } } impl Default for MockVerifyingApp { fn default() -> Self { Self { propose_result: None, verify_result: true, _phantom: PhantomData, } } } impl crate::Application for MockVerifyingApp where B: CertifiableBlock + Clone + Send + Sync + 'static, B::Context: Epochable + Clone + Send + Sync + 'static, S: commonware_cryptography::certificate::Scheme + Clone + Send + Sync + 'static, { type Block = B; type Context = B::Context; type SigningScheme = S; async fn propose( &mut self, _context: (deterministic::Context, Self::Context), _ancestry: impl Ancestry, ) -> Option { self.propose_result.clone() } async fn verify( &mut self, _context: (deterministic::Context, Self::Context), _ancestry: impl Ancestry, ) -> bool { self.verify_result } } /// A verifying mock application whose `verify()` signals `started` on entry and /// blocks until `release` is received. Used to deterministically control when /// the application verdict races with marshal shutdown. #[derive(Clone)] pub struct GatedVerifyingApp { started: Arc>>>, release: Arc>>>, _phantom: PhantomData<(B, S)>, } impl GatedVerifyingApp { /// Returns the gated app, a `started` receiver fired when `verify()` is entered, /// and a `release` sender that unblocks `verify()` once signaled. pub fn new() -> (Self, oneshot::Receiver<()>, oneshot::Sender<()>) { let (started_tx, started_rx) = oneshot::channel(); let (release_tx, release_rx) = oneshot::channel(); ( Self { started: Arc::new(Mutex::new(Some(started_tx))), release: Arc::new(Mutex::new(Some(release_rx))), _phantom: PhantomData, }, started_rx, release_tx, ) } } impl crate::Application for GatedVerifyingApp where B: CertifiableBlock + Clone + Send + Sync + 'static, B::Context: Epochable + Clone + Send + Sync + 'static, S: commonware_cryptography::certificate::Scheme + Clone + Send + Sync + 'static, { type Block = B; type Context = B::Context; type SigningScheme = S; async fn propose( &mut self, _context: (deterministic::Context, Self::Context), _ancestry: impl Ancestry, ) -> Option { None } async fn verify( &mut self, _context: (deterministic::Context, Self::Context), _ancestry: impl Ancestry, ) -> bool { if let Some(started) = self.started.lock().take() { started.send_lossy(()); } let release = self .release .lock() .take() .expect("release receiver missing"); let _ = release.await; true } }