This repository has been archived by the owner on Aug 30, 2022. It is now read-only.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Description
The main tasks, ie that tasks that implement most of the business logic are
aggregator::Service
for the aggregator andcoordinator::Service
for the coordinator. This is where we'll focus our effort for testing at the beginning. In order to test these twoService
, we need to control their inputs and outputs.Let's focus on the coordinator, since the situation is pretty similar for the aggregator anyway. The question is: what are the sources of IO. We have:
However, two of these are not direct sources of the
Service
. The API and RPC server layers are already isolated and run in their own task. They communicate with theService
via aHandle
as illustrated below:We already control these handles and we can use them to send requests to the service. Thus, there is no need to mock the API and RPC server and our system under test can already be simplified:
The RPC client is the only remaining piece, and the idea of the PR is to mock it away so that our system under test is finally fully under our control:
Implementation
For the mocking itself, we use the
mockall
crate. The idea is to leverage rust's conditional compilation to replace therpc::Client
by our mock when runningcargo test
. For this, we use the#[cfg(test)]
and#[cfg(not(test))]
attributes.The mock itself doesn't expose the exact same API than the
rpc::Client
: the types in some of the function signatures are slightly simpler. That's works well in Rust because most APIs are designed around traits.For instance the real
rpc::Client::select
method looks like this:Thus, the return type is _some type that implements
Future<Output=io::Result<Result<(), ()>>>
, and an anonymous lifetime (the'_
part). But in our mock, the return type is an actual concrete type:It works, because that concrete type satisfies the
Future<Output = Result<Result<(), ()>>> + '_
trait bound.