Repository: CosmWasm/cw-multi-test
Pull request #10 (2022-11-18 16:50:22)

Fixes and tests for stargate messages
Follow up of #9 

* Added couple more bounds in multi-tests where defaults were taken in place of IBC/Gov
* Added dispatching of Gov messages
* Tests for both IBC and Gov messages


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b8da270..70f8695 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,10 @@
 Until `v0.16.0`, this project lived in a different repo with other projects. The below
 changelog will be noisy - not everything is relevant to `cw-multi-test` there.
 
+## Unreleased
+
+- Modules for Stargate (IBC and Gov) messages - failing by default, but possible to exchange
+
 ## [v0.16.0](https://github.com/CosmWasm/cw-plus/tree/v0.16.0) (2022-10-14)
 
 [Full Changelog](https://github.com/CosmWasm/cw-plus/compare/v0.15.1...v0.16.0)
diff --git a/src/app.rs b/src/app.rs
index 805c32a..6a8349a 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -118,8 +118,8 @@ where
     AppBuilder::new_custom().build(init_fn)
 }
 
-impl<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT> Querier
-    for App<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT>
+impl<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT> Querier
+    for App<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
 where
     CustomT::ExecT: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static,
     CustomT::QueryT: CustomQuery + DeserializeOwned + 'static,
@@ -130,6 +130,8 @@ where
     CustomT: Module,
     StakingT: Staking,
     DistrT: Distribution,
+    IbcT: Ibc,
+    GovT: Gov,
 {
     fn raw_query(&self, bin_request: &[u8]) -> QuerierResult {
         self.router
@@ -138,8 +140,8 @@ where
     }
 }
 
-impl<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT> Executor<CustomT::ExecT>
-    for App<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT>
+impl<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT> Executor<CustomT::ExecT>
+    for App<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
 where
     CustomT::ExecT: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static,
     CustomT::QueryT: CustomQuery + DeserializeOwned + 'static,
@@ -150,6 +152,8 @@ where
     CustomT: Module,
     StakingT: Staking,
     DistrT: Distribution,
+    IbcT: Ibc,
+    GovT: Gov,
 {
     fn execute(
         &mut self,
@@ -668,7 +672,7 @@ where
 
 // Helper functions to call some custom WasmKeeper logic.
 // They show how we can easily add such calls to other custom keepers (CustomT, StakingT, etc)
-impl<BankT, ApiT, StorageT, CustomT, StakingT, DistrT>
+impl<BankT, ApiT, StorageT, CustomT, StakingT, DistrT, IbcT, GovT>
     App<
         BankT,
         ApiT,
@@ -677,6 +681,8 @@ impl<BankT, ApiT, StorageT, CustomT, StakingT, DistrT>
         WasmKeeper<CustomT::ExecT, CustomT::QueryT>,
         StakingT,
         DistrT,
+        IbcT,
+        GovT,
     >
 where
     BankT: Bank,
@@ -685,6 +691,8 @@ where
     CustomT: Module,
     StakingT: Staking,
     DistrT: Distribution,
+    IbcT: Ibc,
+    GovT: Gov,
     CustomT::ExecT: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static,
     CustomT::QueryT: CustomQuery + DeserializeOwned + 'static,
 {
@@ -705,8 +713,8 @@ where
     }
 }
 
-impl<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT>
-    App<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT>
+impl<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
+    App<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
 where
     CustomT::ExecT: std::fmt::Debug + PartialEq + Clone + JsonSchema + DeserializeOwned + 'static,
     CustomT::QueryT: CustomQuery + DeserializeOwned + 'static,
@@ -717,6 +725,8 @@ where
     CustomT: Module,
     StakingT: Staking,
     DistrT: Distribution,
+    IbcT: Ibc,
+    GovT: Gov,
 {
     pub fn set_block(&mut self, block: BlockInfo) {
         self.block = block;
@@ -939,6 +949,7 @@ where
                 .distribution
                 .execute(api, storage, self, block, sender, msg),
             CosmosMsg::Ibc(msg) => self.ibc.execute(api, storage, self, block, sender, msg),
+            CosmosMsg::Gov(msg) => self.gov.execute(api, storage, self, block, sender, msg),
             _ => bail!("Cannot execute {:?}", msg),
         }
     }
diff --git a/src/gov.rs b/src/gov.rs
index 0569cb4..cce65de 100644
--- a/src/gov.rs
+++ b/src/gov.rs
@@ -5,3 +5,115 @@ use crate::{FailingModule, Module};
 pub trait Gov: Module<ExecT = GovMsg, QueryT = Empty, SudoT = Empty> {}
 
 impl Gov for FailingModule<GovMsg, Empty, Empty> {}
+
+#[cfg(test)]
+mod test {
+    use cosmwasm_std::{Addr, Binary, Empty, GovMsg};
+
+    use crate::test_helpers::contracts::stargate::{contract, ExecMsg};
+    use crate::{App, AppBuilder, AppResponse, Executor, Module};
+
+    use super::Gov;
+
+    struct AcceptingModule;
+
+    impl Module for AcceptingModule {
+        type ExecT = GovMsg;
+        type QueryT = Empty;
+        type SudoT = Empty;
+
+        fn execute<ExecC, QueryC>(
+            &self,
+            _api: &dyn cosmwasm_std::Api,
+            _storage: &mut dyn cosmwasm_std::Storage,
+            _router: &dyn crate::CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
+            _block: &cosmwasm_std::BlockInfo,
+            _sender: cosmwasm_std::Addr,
+            _msg: Self::ExecT,
+        ) -> anyhow::Result<crate::AppResponse>
+        where
+            ExecC: std::fmt::Debug
+                + Clone
+                + PartialEq
+                + schemars::JsonSchema
+                + serde::de::DeserializeOwned
+                + 'static,
+            QueryC: cosmwasm_std::CustomQuery + serde::de::DeserializeOwned + 'static,
+        {
+            Ok(AppResponse::default())
+        }
+
+        fn sudo<ExecC, QueryC>(
+            &self,
+            _api: &dyn cosmwasm_std::Api,
+            _storage: &mut dyn cosmwasm_std::Storage,
+            _router: &dyn crate::CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
+            _block: &cosmwasm_std::BlockInfo,
+            _msg: Self::SudoT,
+        ) -> anyhow::Result<crate::AppResponse>
+        where
+            ExecC: std::fmt::Debug
+                + Clone
+                + PartialEq
+                + schemars::JsonSchema
+                + serde::de::DeserializeOwned
+                + 'static,
+            QueryC: cosmwasm_std::CustomQuery + serde::de::DeserializeOwned + 'static,
+        {
+            Ok(AppResponse::default())
+        }
+
+        fn query(
+            &self,
+            _api: &dyn cosmwasm_std::Api,
+            _storage: &dyn cosmwasm_std::Storage,
+            _querier: &dyn cosmwasm_std::Querier,
+            _block: &cosmwasm_std::BlockInfo,
+            _request: Self::QueryT,
+        ) -> anyhow::Result<cosmwasm_std::Binary> {
+            Ok(Binary::default())
+        }
+    }
+
+    impl Gov for AcceptingModule {}
+
+    #[test]
+    fn default_gov() {
+        let mut app = App::default();
+        let code = app.store_code(contract());
+        let contract = app
+            .instantiate_contract(
+                code,
+                Addr::unchecked("owner"),
+                &Empty {},
+                &[],
+                "contract",
+                None,
+            )
+            .unwrap();
+
+        app.execute_contract(Addr::unchecked("owner"), contract, &ExecMsg::Gov {}, &[])
+            .unwrap_err();
+    }
+
+    #[test]
+    fn subsituting_gov() {
+        let mut app = AppBuilder::new()
+            .with_gov(AcceptingModule)
+            .build(|_, _, _| ());
+        let code = app.store_code(contract());
+        let contract = app
+            .instantiate_contract(
+                code,
+                Addr::unchecked("owner"),
+                &Empty {},
+                &[],
+                "contract",
+                None,
+            )
+            .unwrap();
+
+        app.execute_contract(Addr::unchecked("owner"), contract, &ExecMsg::Gov {}, &[])
+            .unwrap();
+    }
+}
diff --git a/src/ibc.rs b/src/ibc.rs
index 65c552d..f54d811 100644
--- a/src/ibc.rs
+++ b/src/ibc.rs
@@ -5,3 +5,115 @@ use crate::{FailingModule, Module};
 pub trait Ibc: Module<ExecT = IbcMsg, QueryT = IbcQuery, SudoT = Empty> {}
 
 impl Ibc for FailingModule<IbcMsg, IbcQuery, Empty> {}
+
+#[cfg(test)]
+mod test {
+    use cosmwasm_std::{Addr, Binary, Empty, IbcMsg, IbcQuery};
+
+    use crate::test_helpers::contracts::stargate::{contract, ExecMsg};
+    use crate::{App, AppBuilder, AppResponse, Executor, Module};
+
+    use super::Ibc;
+
+    struct AcceptingModule;
+
+    impl Module for AcceptingModule {
+        type ExecT = IbcMsg;
+        type QueryT = IbcQuery;
+        type SudoT = Empty;
+
+        fn execute<ExecC, QueryC>(
+            &self,
+            _api: &dyn cosmwasm_std::Api,
+            _storage: &mut dyn cosmwasm_std::Storage,
+            _router: &dyn crate::CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
+            _block: &cosmwasm_std::BlockInfo,
+            _sender: cosmwasm_std::Addr,
+            _msg: Self::ExecT,
+        ) -> anyhow::Result<crate::AppResponse>
+        where
+            ExecC: std::fmt::Debug
+                + Clone
+                + PartialEq
+                + schemars::JsonSchema
+                + serde::de::DeserializeOwned
+                + 'static,
+            QueryC: cosmwasm_std::CustomQuery + serde::de::DeserializeOwned + 'static,
+        {
+            Ok(AppResponse::default())
+        }
+
+        fn sudo<ExecC, QueryC>(
+            &self,
+            _api: &dyn cosmwasm_std::Api,
+            _storage: &mut dyn cosmwasm_std::Storage,
+            _router: &dyn crate::CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
+            _block: &cosmwasm_std::BlockInfo,
+            _msg: Self::SudoT,
+        ) -> anyhow::Result<crate::AppResponse>
+        where
+            ExecC: std::fmt::Debug
+                + Clone
+                + PartialEq
+                + schemars::JsonSchema
+                + serde::de::DeserializeOwned
+                + 'static,
+            QueryC: cosmwasm_std::CustomQuery + serde::de::DeserializeOwned + 'static,
+        {
+            Ok(AppResponse::default())
+        }
+
+        fn query(
+            &self,
+            _api: &dyn cosmwasm_std::Api,
+            _storage: &dyn cosmwasm_std::Storage,
+            _querier: &dyn cosmwasm_std::Querier,
+            _block: &cosmwasm_std::BlockInfo,
+            _request: Self::QueryT,
+        ) -> anyhow::Result<cosmwasm_std::Binary> {
+            Ok(Binary::default())
+        }
+    }
+
+    impl Ibc for AcceptingModule {}
+
+    #[test]
+    fn default_ibc() {
+        let mut app = App::default();
+        let code = app.store_code(contract());
+        let contract = app
+            .instantiate_contract(
+                code,
+                Addr::unchecked("owner"),
+                &Empty {},
+                &[],
+                "contract",
+                None,
+            )
+            .unwrap();
+
+        app.execute_contract(Addr::unchecked("owner"), contract, &ExecMsg::Ibc {}, &[])
+            .unwrap_err();
+    }
+
+    #[test]
+    fn subsituting_ibc() {
+        let mut app = AppBuilder::new()
+            .with_ibc(AcceptingModule)
+            .build(|_, _, _| ());
+        let code = app.store_code(contract());
+        let contract = app
+            .instantiate_contract(
+                code,
+                Addr::unchecked("owner"),
+                &Empty {},
+                &[],
+                "contract",
+                None,
+            )
+            .unwrap();
+
+        app.execute_contract(Addr::unchecked("owner"), contract, &ExecMsg::Ibc {}, &[])
+            .unwrap();
+    }
+}


Test patch:
diff --git a/src/test_helpers/contracts.rs b/src/test_helpers/contracts.rs
index 68babbf..3b495e0 100644
--- a/src/test_helpers/contracts.rs
+++ b/src/test_helpers/contracts.rs
@@ -6,3 +6,4 @@ pub mod error;
 pub mod hackatom;
 pub mod payout;
 pub mod reflect;
+pub mod stargate;
diff --git a/src/test_helpers/contracts/stargate.rs b/src/test_helpers/contracts/stargate.rs
new file mode 100644
index 0000000..d5f4f2e
--- /dev/null
+++ b/src/test_helpers/contracts/stargate.rs
@@ -0,0 +1,43 @@
+use cosmwasm_std::{
+    Binary, CosmosMsg, Deps, DepsMut, Empty, Env, GovMsg, IbcMsg, MessageInfo, Response, StdResult,
+};
+use serde::{Deserialize, Serialize};
+
+use crate::{Contract, ContractWrapper};
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum ExecMsg {
+    Ibc {},
+    Gov {},
+}
+
+fn instantiate(_deps: DepsMut, _env: Env, _info: MessageInfo, _msg: Empty) -> StdResult<Response> {
+    Ok(Response::new())
+}
+
+fn execute(_deps: DepsMut, _env: Env, _info: MessageInfo, msg: ExecMsg) -> StdResult<Response> {
+    let msg: CosmosMsg = if let ExecMsg::Ibc {} = msg {
+        IbcMsg::CloseChannel {
+            channel_id: "channel".to_string(),
+        }
+        .into()
+    } else {
+        GovMsg::Vote {
+            proposal_id: 1,
+            vote: cosmwasm_std::VoteOption::No,
+        }
+        .into()
+    };
+
+    let resp = Response::new().add_message(msg);
+    Ok(resp)
+}
+
+fn query(_deps: Deps, _env: Env, _msg: Empty) -> StdResult<Binary> {
+    Ok(Binary::default())
+}
+
+pub fn contract() -> Box<dyn Contract<Empty>> {
+    let contract = ContractWrapper::new(execute, instantiate, query);
+    Box::new(contract)
+}