Skip to content

Commit

Permalink
Refactor to split the MockApplication type
Browse files Browse the repository at this point in the history
Create a separate `MockApplicationInstance` that does not share the
expected calls list. This means that now the application forwards the
list to the created instance, and each instance has a separate call
list.

This tests if the instances are reused or not. If they are not reused,
session calls will always fail.
  • Loading branch information
jvff committed Jan 16, 2024
1 parent 1ef1424 commit b6c3b38
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 46 deletions.
2 changes: 1 addition & 1 deletion linera-execution/tests/test_execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -938,7 +938,7 @@ async fn test_multiple_messages_from_different_applications() -> anyhow::Result<
pub async fn register_mock_applications<C>(
state: &mut ExecutionStateView<C>,
count: u64,
) -> anyhow::Result<vec::IntoIter<(UserApplicationId, MockApplication<()>)>>
) -> anyhow::Result<vec::IntoIter<(UserApplicationId, MockApplication)>>
where
C: Context<Extra = TestExecutionRuntimeContext> + Clone + Send + Sync + 'static,
ViewError: From<C::Error>,
Expand Down
88 changes: 43 additions & 45 deletions linera-execution/tests/utils/mock_application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,54 +14,45 @@ use linera_execution::{
use std::{
collections::VecDeque,
fmt::{self, Display, Formatter},
mem,
sync::{Arc, Mutex},
};

/// A mocked implementation of a user application.
///
/// Implements [`UserContractModule`], [`UserServiceModule`], [`UserContract`] and [`UserService`].
#[derive(Clone)]
pub struct MockApplication<Runtime> {
runtime: Runtime,
/// Should be configured with any expected calls, and can then be used to create a
/// [`MockApplicationInstance`] that implements [`UserContract`] and [`UserService`].
#[derive(Clone, Default)]
pub struct MockApplication {
expected_calls: Arc<Mutex<VecDeque<ExpectedCall>>>,
}

impl Default for MockApplication<()> {
fn default() -> Self {
MockApplication {
runtime: (),
expected_calls: Arc::new(Mutex::new(VecDeque::new())),
}
}
}

impl MockApplication<()> {
/// Configures the `runtime` to use with the [`MockApplication`] instance.
pub fn with_runtime<NewRuntime>(self, runtime: NewRuntime) -> MockApplication<NewRuntime> {
MockApplication {
runtime,
expected_calls: self.expected_calls,
}
}
/// A mocked implementation of a user application instance.
///
/// Will expect certain calls previously configured through [`MockApplication`].
pub struct MockApplicationInstance<Runtime> {
expected_calls: VecDeque<ExpectedCall>,
runtime: Runtime,
}

impl<Runtime> MockApplication<Runtime> {
impl MockApplication {
/// Queues an expected call to the [`MockApplication`].
pub fn expect_call(&self, expected_call: ExpectedCall) {
self.expected_calls
.lock()
.expect("Mutex is poisoned")
.push_back(expected_call);
}
}

impl<Runtime> MockApplication<Runtime> {
/// Retrieves the next [`ExpectedCall`] in the queue.
fn next_expected_call(&mut self) -> Option<ExpectedCall> {
self.expected_calls
.lock()
.expect("Mutex is poisoned")
.pop_front()
/// Creates a new [`MockApplicationInstance`], forwarding the configured expected calls.
pub fn create_mock_instance<Runtime>(
&self,
runtime: Runtime,
) -> MockApplicationInstance<Runtime> {
MockApplicationInstance {
expected_calls: mem::take(&mut self.expected_calls.lock().expect("Mutex is poisoned")),
runtime,
}
}
}

Expand Down Expand Up @@ -119,7 +110,7 @@ type HandleQueryHandler = Box<
+ Sync,
>;

/// An expected call to a [`MockApplication`].
/// An expected call to a [`MockApplicationInstance`].
pub enum ExpectedCall {
/// An expected call to [`UserContract::initialize`].
Initialize(InitializeHandler),
Expand Down Expand Up @@ -151,8 +142,8 @@ impl Display for ExpectedCall {
}

impl ExpectedCall {
/// Creates an [`ExpectedCall`] to the [`MockApplication`]'s [`UserContract::initialize`]
/// implementation, which is handled by the provided `handler`.
/// Creates an [`ExpectedCall`] to the [`MockApplicationInstance`]'s
/// [`UserContract::initialize`] implementation, which is handled by the provided `handler`.
pub fn initialize(
handler: impl FnOnce(
&mut ContractSyncRuntime,
Expand All @@ -166,7 +157,7 @@ impl ExpectedCall {
ExpectedCall::Initialize(Box::new(handler))
}

/// Creates an [`ExpectedCall`] to the [`MockApplication`]'s
/// Creates an [`ExpectedCall`] to the [`MockApplicationInstance`]'s
/// [`UserContract::execute_operation`] implementation, which is handled by the provided
/// `handler`.
pub fn execute_operation(
Expand All @@ -182,7 +173,7 @@ impl ExpectedCall {
ExpectedCall::ExecuteOperation(Box::new(handler))
}

/// Creates an [`ExpectedCall`] to the [`MockApplication`]'s
/// Creates an [`ExpectedCall`] to the [`MockApplicationInstance`]'s
/// [`UserContract::execute_message`] implementation, which is handled by the provided
/// `handler`.
pub fn execute_message(
Expand All @@ -198,7 +189,7 @@ impl ExpectedCall {
ExpectedCall::ExecuteMessage(Box::new(handler))
}

/// Creates an [`ExpectedCall`] to the [`MockApplication`]'s
/// Creates an [`ExpectedCall`] to the [`MockApplicationInstance`]'s
/// [`UserContract::handle_application_call`] implementation, which is handled by the provided
/// `handler`.
pub fn handle_application_call(
Expand All @@ -215,7 +206,7 @@ impl ExpectedCall {
ExpectedCall::HandleApplicationCall(Box::new(handler))
}

/// Creates an [`ExpectedCall`] to the [`MockApplication`]'s
/// Creates an [`ExpectedCall`] to the [`MockApplicationInstance`]'s
/// [`UserContract::handle_session_call`] implementation, which is handled by the provided
/// `handler`.
pub fn handle_session_call(
Expand All @@ -233,8 +224,8 @@ impl ExpectedCall {
ExpectedCall::HandleSessionCall(Box::new(handler))
}

/// Creates an [`ExpectedCall`] to the [`MockApplication`]'s [`UserService::handle_query`]
/// implementation, which is handled by the provided `handler`.
/// Creates an [`ExpectedCall`] to the [`MockApplicationInstance`]'s
/// [`UserService::handle_query`] implementation, which is handled by the provided `handler`.
pub fn handle_query(
handler: impl FnOnce(
&mut ServiceSyncRuntime,
Expand All @@ -249,25 +240,32 @@ impl ExpectedCall {
}
}

impl UserContractModule for MockApplication<()> {
impl UserContractModule for MockApplication {
fn instantiate(
&self,
runtime: ContractSyncRuntime,
) -> Result<Box<dyn UserContract + Send + Sync + 'static>, ExecutionError> {
Ok(Box::new(self.clone().with_runtime(runtime)))
Ok(Box::new(self.create_mock_instance(runtime)))
}
}

impl UserServiceModule for MockApplication<()> {
impl UserServiceModule for MockApplication {
fn instantiate(
&self,
runtime: ServiceSyncRuntime,
) -> Result<Box<dyn UserService + Send + Sync + 'static>, ExecutionError> {
Ok(Box::new(self.clone().with_runtime(runtime)))
Ok(Box::new(self.create_mock_instance(runtime)))
}
}

impl<Runtime> MockApplicationInstance<Runtime> {
/// Retrieves the next [`ExpectedCall`] in the queue.
fn next_expected_call(&mut self) -> Option<ExpectedCall> {
self.expected_calls.pop_front()
}
}

impl UserContract for MockApplication<ContractSyncRuntime> {
impl UserContract for MockApplicationInstance<ContractSyncRuntime> {
fn initialize(
&mut self,
context: OperationContext,
Expand Down Expand Up @@ -352,7 +350,7 @@ impl UserContract for MockApplication<ContractSyncRuntime> {
}
}

impl UserService for MockApplication<ServiceSyncRuntime> {
impl UserService for MockApplicationInstance<ServiceSyncRuntime> {
fn handle_query(
&mut self,
context: QueryContext,
Expand Down

0 comments on commit b6c3b38

Please sign in to comment.