-
Notifications
You must be signed in to change notification settings - Fork 355
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implementing all messages handling in mutlitest App #398
Conversation
f96a7ba
to
c1ee67b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good.
Handling this into two separate MRs (builder pattern for App
, and custom messages handling) would have made reviewing easy for me.
/// Also `ExecC` is the custom message which is handled by custom message handler. | ||
/// | ||
/// `QueryC` is custom query message handled by custom message handler. | ||
pub struct App<ExecC = Empty, QueryC = Empty> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a detail, but why not naming these E
, Q
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am basically enemy of single letter names, they are semanticless. Sometimes in very obvious cases T
makes its jobs, but besides I find it wasting more time reading, that saving writing.
let bank = BankKeeper::new(); | ||
|
||
App::new(api, env.block, bank, MockStorage::new()) | ||
AppBuilder::new().build() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍🏼
|
||
#[derive(Debug, Clone, Serialize, Deserialize, Derivative)] | ||
#[derivative(Default(bound = "", new = "true"))] | ||
pub struct Message<ExecC> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pub struct Message<ExecC> | |
pub struct Message<ExecC = Empty> |
? (not sure that's possible / useful).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is possible for sure and I think it is even used. Empty message is still a message, good enough for testing purposes.
Yea, it went bigger than I expected :/ I wanted to start with all other messages (stargate and so), but I decided that I will wait for this to be reviewed as it would be too much spam. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general, this looks good. I like the builder pattern and thanks for adding some Custom support.
I am rather strongly against using mockall here, as we will not need that in any real usage of multitest (a proper mock object should be provided by one chain). I support a minimal implementation of a custom handler (without mockall) that is just pub(crate)
and used for the internal tests.
Each blockchain can provide a proper implementation along with the bindings where they define CosmosMsg and QueryRequest extensions.
|
||
/// Simplified version of `CustomHandler` having only arguments which are not app internals - they | ||
/// are just discarded. Usefull for simpler mocking. | ||
#[automock(type QueryResult = Binary;)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would feel happier removing this and just implementing the 2 needed methods, then mockall can be a dev-dependency only.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In reality, we will likely have much larger blockchain specific logic in the custom handlers and just applying mocks here doesn't make too much sense usually.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically this is the idea - specific blockchain impl just adds its own implementation. Auto-generated mock is just to make internal testing easier, but I will get rid of this in this place.
self | ||
} | ||
|
||
pub fn build(self) -> App<ExecC, QueryC> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice way to provide defaults that can be overridden
/// Overwrites default wasm executor. Panic if already set. | ||
#[track_caller] | ||
pub fn with_wasm(mut self, wasm: impl Wasm<ExecC, QueryC> + 'static) -> Self { | ||
assert!(self.wasm.is_none(), "Wasm executor already overwritten"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't allow overriding it twice? I guess no need, but seems odd to enforce.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you overwrite something twice in your builder then you made some mistake. Better to catch early.
pub wasm: Box<dyn Wasm<C>>, | ||
pub bank: Box<dyn Bank>, | ||
pub struct Router<ExecC, QueryC> { | ||
pub(crate) wasm: Box<dyn Wasm<ExecC, QueryC>>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would actually leave these public. But that can be a different PR when there is a need.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why? Any reason why user of this crate should in any point get access to internals of structure?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not now, I have an idea, but the need will show up in a future PR, and we can discuss there.
Out of scope here. For now pub(crate) is good.
fn query(&self, block: &BlockInfo, msg: QueryC) -> AnyResult<Binary>; | ||
} | ||
|
||
impl<ExecC, QueryC, T: SimpleCustomHandler<ExecC, QueryC>> CustomHandler<ExecC, QueryC> for T { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would just have this implementation return error (so you can test it works). For any real usage, we will have time to build a module to define the semantics of this. We will want to mock out the real blockchain behaviour, so I would tend against one-off mocks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or maybe a FailingCustomHandler, which returns a pre-defined error (set in new?)
And SuccessCustomHandler, which returns a fixed response (set in new?)
One or both just to help in your testing in other packages, but those don't even have to be public outside of this crate.
/// code is in-memory lookup that stands in for wasm code | ||
/// this can only be edited on the WasmRouter, and just read in caches | ||
codes: HashMap<usize, Box<dyn Contract<C>>>, | ||
codes: HashMap<usize, Box<dyn Contract<ExecC>>>, | ||
/// Just marker to make type elision fork when using it as `Wasm` trait |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, the contract should have QueryC in it's type.
Update: I looked at this code (also in cosmwasm-std) and it seems the query types are not enforced in DepsMut (which is where they are used). This is proper here, but maybe we can look at making cosmwasm-std more type safe
(TODO: @ethanfrey make an issue on cosmwasm-std)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks better.
I would still hide some more types (make them pub(crate)
) to ensure/signal they are only for internal testing of multi-test
/// is implemented, custom messages should not be send. | ||
pub struct PanickingCustomHandler; | ||
|
||
impl<ExecC, QueryC> SimpleCustomHandler<ExecC, QueryC> for PanickingCustomHandler |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why even have the SimpleCustomHandler
trait? Why not just implement CustomHandler
directly?
Also, I think CustomHandler
is the only type in this file that should be pub
(rather than pub(crate)
). These other types are only meaningful for us to test multi-test itself (not for blockchains that actually use custom types)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, probably in contract we should not use in contracts tests. SimpleCustomHandler
is here to make implementations kind of simpler as I assume that app
is somehow accessible on the side, but it may be an overkill.
@@ -1594,6 +1582,13 @@ mod test { | |||
&[], | |||
) | |||
.unwrap(); | |||
|
|||
assert_eq!( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks nice.
Closes #388