rhaki_cw_mock_http_querier 0.1.0

Cosmwasm mock querier for testing, that can perform http request to public lcd.
Documentation
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde_json::Value;
use std::marker::PhantomData;

use base64::{engine::general_purpose, Engine as _};
use cosmwasm_std::{
    from_slice,
    testing::{MockApi, MockQuerier, MockStorage},
    Binary, Coin, ContractResult, CustomQuery, OwnedDeps, Querier, QuerierResult, QueryRequest,
    SystemError, SystemResult, WasmQuery,
};

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
struct LcdSmartQueryHttpResponse {
    data: Value,
}

pub struct HttpWasmMockQuerier<C: CustomQuery + DeserializeOwned> {
    base: MockQuerier<C>,
    url_lcd: String,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "snake_case")]
pub struct DefaultWasmMockQuerier {}

impl CustomQuery for DefaultWasmMockQuerier {}

impl<C: CustomQuery + DeserializeOwned> HttpWasmMockQuerier<C> {
    pub fn new(
        base: Option<MockQuerier<C>>,
        url_lcd: String,
        balances: Option<&[(&str, &[Coin])]>,
    ) -> Self {
        HttpWasmMockQuerier {
            base: base.unwrap_or_else(|| MockQuerier::new(balances.unwrap_or(&[]))),
            url_lcd,
        }
    }
}

impl<C: CustomQuery + DeserializeOwned> Querier for HttpWasmMockQuerier<C> {
    fn raw_query(&self, bin_request: &[u8]) -> QuerierResult {
        let request: QueryRequest<C> = match from_slice(bin_request) {
            Ok(v) => v,
            Err(e) => {
                return SystemResult::Err(SystemError::InvalidRequest {
                    error: format!("Parsing query request: {}", e),
                    request: bin_request.into(),
                })
            }
        };
        self.handle_query(&request)
    }
}

impl<C: CustomQuery + DeserializeOwned> HttpWasmMockQuerier<C> {
    pub fn handle_query(&self, request: &QueryRequest<C>) -> QuerierResult {
        match request {
            QueryRequest::Wasm(WasmQuery::Smart { contract_addr, msg }) => {
                let str_msg = msg.to_string();

                let mut url = self.url_lcd.clone();
                url.push_str("/cosmwasm/wasm/v1/contract/");
                url.push_str(contract_addr);
                url.push_str("/smart/");
                url.push_str(str_msg.as_str());

                let res: LcdSmartQueryHttpResponse =
                    reqwest::blocking::get(url).unwrap().json().unwrap();
                let encoded_resp: String =
                    general_purpose::STANDARD_NO_PAD.encode(res.data.to_string());
                let binary_resp = Binary::from_base64(encoded_resp.as_str()).unwrap();

                QuerierResult::Ok(ContractResult::Ok(binary_resp))
            }
            _ => self.base.handle_query(request),
        }
    }
}

pub fn create_http_mock<C: CustomQuery + DeserializeOwned>(
    custom_mock: Option<MockQuerier<C>>,
    url_lcd: &str,
    balances: Option<&[(&str, &[Coin])]>,
) -> OwnedDeps<MockStorage, MockApi, HttpWasmMockQuerier<C>> {
    let querier: HttpWasmMockQuerier<C> =
        HttpWasmMockQuerier::new(custom_mock, String::from(url_lcd), balances);

    OwnedDeps {
        storage: MockStorage::default(),
        api: MockApi::default(),
        querier,
        custom_query_type: PhantomData::default(),
    }
}