Skip to content
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

feat: add integration tests for query-queue #197

Merged
merged 5 commits into from
Jun 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,56 @@ jobs:
exit 1
fi

contract_query_queue:
name: contract_query_queue
runs-on: ubuntu-latest
env:
working-directory: ./contracts/query-queue
queue-directory: ./contracts/queue
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: 1.57.0
target: wasm32-unknown-unknown
profile: minimal
override: true
- name: Cache cargo
uses: actions/cache@v2
with:
path: ~/.cargo
key: cargocache-v2-contract_query_queue-rust:1.57.0-${{ hashFiles('Cargo.lock') }}
- name: Version information
run: rustc --version; cargo --version; rustup --version; rustup target list --installed
- name: Add wasm32 target
run: rustup target add wasm32-unknown-unknown && rustup target list --installed
- name: Build wasm binary
working-directory: ${{env.working-directory}}
run: cargo wasm --locked
- name: Unit tests
working-directory: ${{env.working-directory}}
run: cargo unit-test --locked
- name: Build queue wasm binary for integration tests
working-directory: ${{env.queue-directory}}
run: cargo wasm --locked
- name: Integration tests (singlepass backend)
working-directory: ${{env.working-directory}}
run: cargo integration-test --locked --no-default-features
- name: Build and run schema generator
working-directory: ${{env.working-directory}}
run: cargo schema --locked
- name: Ensure schemas are up-to-date
working-directory: ${{env.working-directory}}
run: |
CHANGES_IN_REPO=$(git status --porcelain)
if [[ -n "$CHANGES_IN_REPO" ]]; then
echo "Repository is dirty. Showing 'git status' and 'git --no-pager diff' for debugging now:"
git status && git --no-pager diff
exit 1
fi

contract_reflect:
name: contract_reflect
runs-on: ubuntu-latest
Expand Down Expand Up @@ -595,6 +645,9 @@ jobs:
- name: Check formatting of contract queue
working-directory: ${{env.root-directory}}/queue
run: cargo fmt -- --check
- name: Check formatting of contract query-queue
working-directory: ${{env.root-directory}}/query-queue
run: cargo fmt -- --check
- name: Check formatting of contract staking
working-directory: ${{env.root-directory}}/staking
run: cargo fmt -- --check
Expand Down Expand Up @@ -687,6 +740,12 @@ jobs:
mkdir -p target/wasm32-unknown-unknown/release
touch target/wasm32-unknown-unknown/release/queue.wasm
cargo clippy --tests -- -D warnings
- name: Clippy linting on query-queue
working-directory: ${{env.contracts}}/query-queue
run: |
mkdir -p target/wasm32-unknown-unknown/release
touch target/wasm32-unknown-unknown/release/query_queue.wasm
cargo clippy --tests -- -D warnings
- name: Clippy linting on reflect
working-directory: ${{env.contracts}}/reflect
run: |
Expand Down
12 changes: 8 additions & 4 deletions contracts/query-queue/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,9 @@ fn query_raw(deps: Deps, key: u8) -> StdResult<RawResponse> {
.querier
.query_wasm_raw(address, (vec![key]).as_slice())?;
let response_string = std::str::from_utf8(response.unwrap_or_default().as_slice())?.to_string();
Ok(RawResponse { response: response_string })
Ok(RawResponse {
response: response_string,
})
}

fn query_count(deps: Deps, msg: QueryMsg) -> StdResult<CountResponse> {
Expand Down Expand Up @@ -141,7 +143,7 @@ mod tests {

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
struct RawQueryResponse {
value: u32
value: u32,
}

fn create_contract() -> OwnedDeps<MockStorage, MockApi, MockQuerier> {
Expand All @@ -150,7 +152,7 @@ mod tests {
let res = instantiate(
deps.as_mut(),
mock_env(),
info.clone(),
info,
InstantiateMsg {
queue_address: QUEUE_ADDRESS.to_string(),
},
Expand Down Expand Up @@ -190,7 +192,9 @@ mod tests {
WasmQuery::Raw {
contract_addr: _,
key: _,
} => SystemResult::Ok(ContractResult::Ok(to_binary(&RawQueryResponse{value: 42}).unwrap())),
} => SystemResult::Ok(ContractResult::Ok(
to_binary(&RawQueryResponse { value: 42 }).unwrap(),
)),
_ => SystemResult::Err(SystemError::Unknown {}),
});
deps
Expand Down
215 changes: 215 additions & 0 deletions contracts/query-queue/tests/integration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
//! This integration test tries to run and call the generated wasm.
//! It depends on a Wasm build being available, which you can create with `cargo wasm`.
//! Then running `cargo integration-test` will validate we can properly call into that generated Wasm.
//!
//! You can easily convert unit tests to integration tests as follows:
//! 1. Copy them over verbatim
//! 2. Then change
//! let mut deps = mock_dependencies(20, &[]);
//! to
//! let mut deps = mock_instance(WASM, &[]);
//! 3. If you access raw storage, where ever you see something like:
//! deps.storage.get(CONFIG_KEY).expect("no data stored");
//! replace it with:
//! deps.with_storage(|store| {
//! let data = store.get(CONFIG_KEY).expect("no data stored");
//! //...
//! });
//! 4. Anywhere you see query(&deps, ...) you must replace it with query(&mut deps, ...)

use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use cosmwasm_std::{
from_binary, from_slice, to_binary, Binary, ContractResult, MessageInfo, Response, SystemError,
SystemResult, WasmQuery,
};
use cosmwasm_vm::{
testing::{
execute, instantiate, mock_env, mock_info, mock_instance_with_gas_limit, query, MockApi,
MockQuerier, MockStorage,
},
Backend, Instance, InstanceOptions, Storage, VmResult,
};

use query_queue::contract::{RawResponse, SumResponse};
use query_queue::msg::{ExecuteMsg, InstantiateMsg, QueryMsg};

static WASM: &[u8] = include_bytes!("../target/wasm32-unknown-unknown/release/query_queue.wasm");
static QUEUE_WASM: &[u8] =
include_bytes!("../../queue/target/wasm32-unknown-unknown/release/queue.wasm");

fn create_contract() -> (Instance<MockApi, MockStorage, MockQuerier>, MessageInfo) {
let gas_limit = 500_000_000; // enough for many executions within one instance
let instance_options = InstanceOptions {
gas_limit,
print_debug: false,
};
let mut deps = Backend {
api: MockApi::default(),
storage: MockStorage::new(),
querier: MockQuerier::new(&[]),
};
let info = mock_info("creator", &[]);
deps.querier.update_wasm(|query_msg| match query_msg {
WasmQuery::Smart { contract_addr, msg } => {
if contract_addr != "queue_address" {
return SystemResult::Err(SystemError::NoSuchContract {
addr: contract_addr.to_string(),
});
};
let q_msg: QueryMsg = from_slice(msg).unwrap();
match q_msg {
QueryMsg::Sum {} => SystemResult::Ok(ContractResult::Ok(
to_binary(&SumResponse { sum: 42 }).unwrap(),
)),
_ => SystemResult::Err(SystemError::Unknown {}),
}
}
_ => SystemResult::Err(SystemError::Unknown {}),
});
let mut instance = Instance::from_code(WASM, deps, instance_options, None).unwrap();
let res: Response = instantiate(
&mut instance,
mock_env(),
info.clone(),
loloicci marked this conversation as resolved.
Show resolved Hide resolved
InstantiateMsg {
queue_address: "queue_address".to_string(),
},
)
.unwrap();
assert_eq!(0, res.messages.len());
(instance, info)
}

#[test]
fn instantiate_and_query() {
let (mut instance, _) = create_contract();
let data = query(&mut instance, mock_env(), QueryMsg::Sum {}).unwrap();
let res: SumResponse = from_binary(&data).unwrap();
assert_eq!(res.sum, 42);
}

#[test]
fn instantiate_and_change_queue_address() {
let (mut instance, info) = create_contract();
let _: Response = execute(
&mut instance,
mock_env(),
info,
ExecuteMsg::ChangeAddress {
queue_address: "non_existing_address".to_string(),
},
)
.unwrap();
let res = query(&mut instance, mock_env(), QueryMsg::Sum {});
let expected = ContractResult::Err(
"Generic error: Querier system error: No such contract: non_existing_address".to_string(),
);
assert_eq!(res, expected);
}

fn create_queue_contract_and_push_42() -> (Instance<MockApi, MockStorage, MockQuerier>, MessageInfo)
{
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
struct InstantiateMsg {}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
enum ExecuteMsg {
Enqueue { value: i32 },
}

let gas_limit = 500_000_000; // enough for many executions within one instance
let mut deps = mock_instance_with_gas_limit(QUEUE_WASM, gas_limit);
let creator = String::from("creator");
let info = mock_info(&creator, &[]);
let res: Response =
instantiate(&mut deps, mock_env(), info.clone(), InstantiateMsg {}).unwrap();
assert_eq!(0, res.messages.len());
let res: Response = execute(
&mut deps,
mock_env(),
info.clone(),
ExecuteMsg::Enqueue { value: 42 },
)
.unwrap();
assert_eq!(0, res.messages.len());
(deps, info)
}

fn create_integrated_query_contract() -> (Instance<MockApi, MockStorage, MockQuerier>, MessageInfo)
{
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueryMsg {
Count {},
Sum {},
Reducer {},
List {},
}

let gas_limit = 500_000_000; // enough for many executions within one instance
let instance_options = InstanceOptions {
gas_limit,
print_debug: false,
};
let mut deps = Backend {
api: MockApi::default(),
storage: MockStorage::new(),
querier: MockQuerier::new(&[]),
};
let info = mock_info("creator", &[]);
deps.querier.update_wasm(|query_msg| {
let (mut queue_instance, _) = create_queue_contract_and_push_42();
match query_msg {
WasmQuery::Smart { contract_addr, msg } => {
if contract_addr != "queue_address" {
return SystemResult::Err(SystemError::NoSuchContract {
addr: contract_addr.to_string(),
});
};
let q_msg: QueryMsg = from_slice(msg).unwrap();
let res = query(&mut queue_instance, mock_env(), q_msg);
SystemResult::Ok(res)
}
WasmQuery::Raw { contract_addr, key } => {
if contract_addr != "queue_address" {
return SystemResult::Err(SystemError::NoSuchContract {
addr: contract_addr.to_string(),
});
};
let data = queue_instance
.with_storage(|storage| VmResult::Ok(storage.get(key).0.unwrap()))
.unwrap();
if data.is_none() {
return SystemResult::Err(SystemError::Unknown {});
};
SystemResult::Ok(ContractResult::Ok(Binary::from(data.unwrap())))
}
_ => SystemResult::Err(SystemError::Unknown {}),
}
});
let mut instance = Instance::from_code(WASM, deps, instance_options, None).unwrap();
let res: Response = instantiate(
&mut instance,
mock_env(),
info.clone(),
InstantiateMsg {
queue_address: "queue_address".to_string(),
},
)
.unwrap();
assert_eq!(0, res.messages.len());
(instance, info)
}

#[test]
fn integration_query_contract_queue() {
let (mut query_instance, _) = create_integrated_query_contract();
let data = query(&mut query_instance, mock_env(), QueryMsg::Sum {}).unwrap();
let res: SumResponse = from_binary(&data).unwrap();
assert_eq!(res.sum, 42);
let data = query(&mut query_instance, mock_env(), QueryMsg::Raw { key: 0 }).unwrap();
let res: RawResponse = from_binary(&data).unwrap();
assert_eq!(res.response, "{\"value\":42}".to_string());
}