Skip to content

Commit c9cb354

Browse files
authored
Merge pull request #1620 from nik-suri/mock-ibc-querier
Add mocking capabilities for ibc querying
2 parents e5969a1 + c19953d commit c9cb354

File tree

1 file changed

+188
-3
lines changed

1 file changed

+188
-3
lines changed

packages/std/src/testing/mock.rs

Lines changed: 188 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ use crate::timestamp::Timestamp;
3333
use crate::traits::{Api, Querier, QuerierResult};
3434
use crate::types::{BlockInfo, ContractInfo, Env, MessageInfo, TransactionInfo};
3535
use crate::Attribute;
36+
#[cfg(feature = "stargate")]
37+
use crate::{ChannelResponse, IbcQuery, ListChannelsResponse, PortIdResponse};
3638

3739
use super::riffle_shuffle;
3840

@@ -435,6 +437,8 @@ pub struct MockQuerier<C: DeserializeOwned = Empty> {
435437
#[cfg(feature = "staking")]
436438
staking: StakingQuerier,
437439
wasm: WasmQuerier,
440+
#[cfg(feature = "stargate")]
441+
ibc: IbcQuerier,
438442
/// A handler to handle custom queries. This is set to a dummy handler that
439443
/// always errors by default. Update it via `with_custom_handler`.
440444
///
@@ -449,6 +453,8 @@ impl<C: DeserializeOwned> MockQuerier<C> {
449453
#[cfg(feature = "staking")]
450454
staking: StakingQuerier::default(),
451455
wasm: WasmQuerier::default(),
456+
#[cfg(feature = "stargate")]
457+
ibc: IbcQuerier::default(),
452458
// strange argument notation suggested as a workaround here: https://github.com/rust-lang/rust/issues/41078#issuecomment-294296365
453459
custom_handler: Box::from(|_: &_| -> MockQuerierCustomHandlerResult {
454460
SystemResult::Err(SystemError::UnsupportedRequest {
@@ -477,6 +483,11 @@ impl<C: DeserializeOwned> MockQuerier<C> {
477483
self.staking = StakingQuerier::new(denom, validators, delegations);
478484
}
479485

486+
#[cfg(feature = "stargate")]
487+
pub fn update_ibc(&mut self, port_id: &str, channels: &[IbcChannel]) {
488+
self.ibc = IbcQuerier::new(port_id, channels);
489+
}
490+
480491
pub fn update_wasm<WH: 'static>(&mut self, handler: WH)
481492
where
482493
WH: Fn(&WasmQuery) -> QuerierResult,
@@ -527,9 +538,7 @@ impl<C: CustomQuery + DeserializeOwned> MockQuerier<C> {
527538
kind: "Stargate".to_string(),
528539
}),
529540
#[cfg(feature = "stargate")]
530-
QueryRequest::Ibc(_) => SystemResult::Err(SystemError::UnsupportedRequest {
531-
kind: "Ibc".to_string(),
532-
}),
541+
QueryRequest::Ibc(msg) => self.ibc.query(msg),
533542
}
534543
}
535544
}
@@ -675,6 +684,70 @@ impl BankQuerier {
675684
}
676685
}
677686

687+
#[cfg(feature = "stargate")]
688+
#[derive(Clone, Default)]
689+
pub struct IbcQuerier {
690+
port_id: String,
691+
channels: Vec<IbcChannel>,
692+
}
693+
694+
#[cfg(feature = "stargate")]
695+
impl IbcQuerier {
696+
/// Create a mock querier where:
697+
/// - port_id is the port the "contract" is bound to
698+
/// - channels are a list of ibc channels
699+
pub fn new(port_id: &str, channels: &[IbcChannel]) -> Self {
700+
IbcQuerier {
701+
port_id: port_id.to_string(),
702+
channels: channels.to_vec(),
703+
}
704+
}
705+
706+
pub fn query(&self, request: &IbcQuery) -> QuerierResult {
707+
let contract_result: ContractResult<Binary> = match request {
708+
IbcQuery::Channel {
709+
channel_id,
710+
port_id,
711+
} => {
712+
let channel = self
713+
.channels
714+
.iter()
715+
.find(|c| match port_id {
716+
Some(p) => c.endpoint.channel_id.eq(channel_id) && c.endpoint.port_id.eq(p),
717+
None => {
718+
c.endpoint.channel_id.eq(channel_id)
719+
&& c.endpoint.port_id == self.port_id
720+
}
721+
})
722+
.cloned();
723+
let res = ChannelResponse { channel };
724+
to_binary(&res).into()
725+
}
726+
IbcQuery::ListChannels { port_id } => {
727+
let channels = self
728+
.channels
729+
.iter()
730+
.filter(|c| match port_id {
731+
Some(p) => c.endpoint.port_id.eq(p),
732+
None => c.endpoint.port_id == self.port_id,
733+
})
734+
.cloned()
735+
.collect();
736+
let res = ListChannelsResponse { channels };
737+
to_binary(&res).into()
738+
}
739+
IbcQuery::PortId {} => {
740+
let res = PortIdResponse {
741+
port_id: self.port_id.clone(),
742+
};
743+
to_binary(&res).into()
744+
}
745+
};
746+
// system result is always ok in the mock implementation
747+
SystemResult::Ok(contract_result)
748+
}
749+
}
750+
678751
#[cfg(feature = "staking")]
679752
#[derive(Clone, Default)]
680753
pub struct StakingQuerier {
@@ -1189,6 +1262,118 @@ mod tests {
11891262
assert_eq!(res.amount, coin(0, "ELF"));
11901263
}
11911264

1265+
#[cfg(feature = "stargate")]
1266+
#[test]
1267+
fn ibc_querier_channel_existing() {
1268+
let chan1 = mock_ibc_channel("channel-0", IbcOrder::Ordered, "ibc");
1269+
let chan2 = mock_ibc_channel("channel-1", IbcOrder::Ordered, "ibc");
1270+
1271+
let ibc = IbcQuerier::new("myport", &[chan1.clone(), chan2]);
1272+
1273+
// query existing
1274+
let query = &IbcQuery::Channel {
1275+
channel_id: "channel-0".to_string(),
1276+
port_id: Some("my_port".to_string()),
1277+
};
1278+
let raw = ibc.query(query).unwrap().unwrap();
1279+
let chan: ChannelResponse = from_binary(&raw).unwrap();
1280+
assert_eq!(chan.channel, Some(chan1));
1281+
}
1282+
1283+
#[cfg(feature = "stargate")]
1284+
#[test]
1285+
fn ibc_querier_channel_existing_no_port() {
1286+
let chan1 = IbcChannel {
1287+
endpoint: IbcEndpoint {
1288+
port_id: "myport".to_string(),
1289+
channel_id: "channel-0".to_string(),
1290+
},
1291+
counterparty_endpoint: IbcEndpoint {
1292+
port_id: "their_port".to_string(),
1293+
channel_id: "channel-7".to_string(),
1294+
},
1295+
order: IbcOrder::Ordered,
1296+
version: "ibc".to_string(),
1297+
connection_id: "connection-2".to_string(),
1298+
};
1299+
let chan2 = mock_ibc_channel("channel-1", IbcOrder::Ordered, "ibc");
1300+
1301+
let ibc = IbcQuerier::new("myport", &[chan1.clone(), chan2]);
1302+
1303+
// query existing
1304+
let query = &IbcQuery::Channel {
1305+
channel_id: "channel-0".to_string(),
1306+
port_id: Some("myport".to_string()),
1307+
};
1308+
let raw = ibc.query(query).unwrap().unwrap();
1309+
let chan: ChannelResponse = from_binary(&raw).unwrap();
1310+
assert_eq!(chan.channel, Some(chan1));
1311+
}
1312+
1313+
#[cfg(feature = "stargate")]
1314+
#[test]
1315+
fn ibc_querier_channel_none() {
1316+
let chan1 = mock_ibc_channel("channel-0", IbcOrder::Ordered, "ibc");
1317+
let chan2 = mock_ibc_channel("channel-1", IbcOrder::Ordered, "ibc");
1318+
1319+
let ibc = IbcQuerier::new("myport", &[chan1, chan2]);
1320+
1321+
// query non-existing
1322+
let query = &IbcQuery::Channel {
1323+
channel_id: "channel-0".to_string(),
1324+
port_id: None,
1325+
};
1326+
let raw = ibc.query(query).unwrap().unwrap();
1327+
let chan: ChannelResponse = from_binary(&raw).unwrap();
1328+
assert_eq!(chan.channel, None);
1329+
}
1330+
1331+
#[cfg(feature = "stargate")]
1332+
#[test]
1333+
fn ibc_querier_channels_matching() {
1334+
let chan1 = mock_ibc_channel("channel-0", IbcOrder::Ordered, "ibc");
1335+
let chan2 = mock_ibc_channel("channel-1", IbcOrder::Ordered, "ibc");
1336+
1337+
let ibc = IbcQuerier::new("myport", &[chan1.clone(), chan2.clone()]);
1338+
1339+
// query channels matching "my_port" (should match both above)
1340+
let query = &&IbcQuery::ListChannels {
1341+
port_id: Some("my_port".to_string()),
1342+
};
1343+
let raw = ibc.query(query).unwrap().unwrap();
1344+
let res: ListChannelsResponse = from_binary(&raw).unwrap();
1345+
assert_eq!(res.channels, vec![chan1, chan2]);
1346+
}
1347+
1348+
#[cfg(feature = "stargate")]
1349+
#[test]
1350+
fn ibc_querier_channels_no_matching() {
1351+
let chan1 = mock_ibc_channel("channel-0", IbcOrder::Ordered, "ibc");
1352+
let chan2 = mock_ibc_channel("channel-1", IbcOrder::Ordered, "ibc");
1353+
1354+
let ibc = IbcQuerier::new("myport", &[chan1, chan2]);
1355+
1356+
// query channels matching "myport" (should be none)
1357+
let query = &&IbcQuery::ListChannels { port_id: None };
1358+
let raw = ibc.query(query).unwrap().unwrap();
1359+
let res: ListChannelsResponse = from_binary(&raw).unwrap();
1360+
assert_eq!(res.channels, vec![]);
1361+
}
1362+
1363+
#[cfg(feature = "stargate")]
1364+
#[test]
1365+
fn ibc_querier_port() {
1366+
let chan1 = mock_ibc_channel("channel-0", IbcOrder::Ordered, "ibc");
1367+
1368+
let ibc = IbcQuerier::new("myport", &[chan1]);
1369+
1370+
// query channels matching "myport" (should be none)
1371+
let query = &&IbcQuery::PortId {};
1372+
let raw = ibc.query(query).unwrap().unwrap();
1373+
let res: PortIdResponse = from_binary(&raw).unwrap();
1374+
assert_eq!(res.port_id, "myport");
1375+
}
1376+
11921377
#[cfg(feature = "staking")]
11931378
#[test]
11941379
fn staking_querier_all_validators() {

0 commit comments

Comments
 (0)