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 CLI tests #216

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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
2,342 changes: 2,079 additions & 263 deletions Cargo.lock

Large diffs are not rendered by default.

12 changes: 8 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[workspace]
resolver = "2"

members = [
members = [
"hello_world",
"increment",
"auth",
Expand All @@ -15,15 +15,19 @@ members = [
"events",
"token",
"logging",
"errors",
"errors",
"timelock",
"atomic_swap",
"atomic_multiswap",
"account",
"alloc",
"test/doc-tests", # include in members for Rust Analyzer
"simple_account",
]

# exclude from `cargo build`
exclude = ["test/doc-tests"]

[profile.release-with-logs]
inherits = "release"
debug-assertions = true
Expand All @@ -41,12 +45,12 @@ lto = true
[workspace.dependencies.soroban-sdk]
version = "0.7.0"
git = "https://github.com/stellar/rs-soroban-sdk"
rev = "29b505cf95f2fd4fbe639fdb163b606c44920837"
rev = "8abd3353c728f09ee1c8a2544f67a853e915afc2"

[workspace.dependencies.soroban-auth]
version = "0.7.0"
git = "https://github.com/stellar/rs-soroban-sdk"
rev = "29b505cf95f2fd4fbe639fdb163b606c44920837"
rev = "8abd3353c728f09ee1c8a2544f67a853e915afc2"

# [patch."https://github.com/stellar/rs-soroban-sdk"]
# soroban-sdk = { path = "../rs-soroban-sdk/soroban-sdk" }
Expand Down
Binary file modified soroban_token_spec.wasm
Binary file not shown.
17 changes: 17 additions & 0 deletions test/doc-tests/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "cli-tests"
version = "0.0.0"
authors = ["Stellar Development Foundation <info@stellar.org>"]
license = "Apache-2.0"
edition = "2021"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not an expert, but shouldn't this be 2023 ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a 2023 edition (yet)? I don't see it listed in the edition guide.

publish = false


[lib]
crate-type = ["cdylib"]
doctest = false

[dev-dependencies]
predicates = "2.1.5"
soroban-test = "0.7.1"
soroban-cli = "0.7.1"
9 changes: 9 additions & 0 deletions test/doc-tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Test CLI commands shown in the docs
===================================

This directory contains tests for all CLI commands currently shown in
https://soroban.stellar.org/docs/category/how-to-guides.

Ideally, the docs themselves would have executable tests on all of their CLI
examples. Perhaps in the future this can be facilitated by co-locating docs and
examples in the same repo with git submodules.
1 change: 1 addition & 0 deletions test/doc-tests/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// empty crate to collect all workspace tests into one binary
100 changes: 100 additions & 0 deletions test/doc-tests/tests/it/auth.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
//! Tests CLI commands from https://soroban.stellar.org/docs/how-to-guides/auth

use soroban_cli::commands::config::identity::address;
use soroban_test::{TestEnv, Wasm};

const WASM: &Wasm = &Wasm::Release("soroban_auth_contract");

const INCREMENT_1: &str = "2";
const INCREMENT_2: &str = "5";

fn account_pk(workspace: &TestEnv, hd_path: u8) -> String {
workspace
.cmd_arr::<address::Cmd>(&["--hd-path", &hd_path.to_string()])
.public_key()
.unwrap()
.to_string()
}

#[test]
fn invoke_and_read() {
TestEnv::with_default(|workspace| {
let account_0_pk = account_pk(workspace, 0);
let account_1_pk = account_pk(workspace, 1);

assert_eq!(
format!("{INCREMENT_1}"),
workspace
.invoke(&[
"--wasm",
&WASM.path().to_string_lossy(),
"--id",
"1",
"--",
"increment",
"--user",
&account_0_pk,
"--value",
&INCREMENT_1,
])
.unwrap(),
);
assert_eq!(
format!("{INCREMENT_2}"),
workspace
.invoke(&[
"--hd-path",
"1",
"--wasm",
&WASM.path().to_string_lossy(),
"--id",
"1",
"--",
"increment",
"--user",
&account_1_pk,
"--value",
&INCREMENT_2,
])
.unwrap(),
);

// `read::Cmd`'s `run` returns `()` & dumps right to STDOUT; need to use assert_cmd
workspace
.new_assert_cmd("contract")
.arg("read")
.args(["--id", "1"])
.assert()
.stderr("")
.stdout(format!(
r#""[""Counter"",""{account_0_pk}""]",{INCREMENT_1}
"[""Counter"",""{account_1_pk}""]",{INCREMENT_2}
"#
));
});
}

#[test]
fn invoke_auth_preview() {
TestEnv::with_default(|workspace| {
let account_0_pk = account_pk(workspace, 0);

// `invoke::Cmd`'s `auth` option prints directly to STDERR; need to test with assert_cmd
workspace.new_assert_cmd("contract")
.arg("invoke")
.arg("--auth")
.arg("--wasm")
.arg(&WASM.path())
.args(["--id", "1"])
.args(["--"])
.arg("increment")
.args(["--user", &account_0_pk])
.args(["--value", &INCREMENT_1])
.assert()
.stdout(format!("{INCREMENT_1}\n"))
.stderr(
r#"Contract auth: [{"address_with_nonce":null,"root_invocation":{"contract_id":"0000000000000000000000000000000000000000000000000000000000000001","function_name":"increment","args":[{"address":{"account":{"public_key_type_ed25519":"d18f0210ff6cc1f2dcf1301fbbd4c30ee11a075820684d471df89d0f1011ea28"}}},{"u32":"#.to_string() + &format!("{INCREMENT_1}") + r#"}],"sub_invocations":[]},"signature_args":[]}]
"#
);
});
}
49 changes: 49 additions & 0 deletions test/doc-tests/tests/it/cross_contract.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//! Tests CLI commands from https://soroban.stellar.org/docs/how-to-guides/cross-contract-call

use soroban_cli::commands::contract::{deploy, install};
use soroban_test::{TestEnv, Wasm};

const WASM_A: &Wasm = &Wasm::Release("soroban_cross_contract_a_contract");
const WASM_B: &Wasm = &Wasm::Release("soroban_cross_contract_b_contract");

#[test]
fn invoke() {
TestEnv::with_default(|workspace| {
let hash_a = WASM_A.hash().unwrap();
workspace
.cmd_arr::<install::Cmd>(&["--wasm", &WASM_A.path().to_string_lossy()])
.run_in_sandbox(WASM_A.bytes())
.unwrap();
workspace
.cmd_arr::<deploy::Cmd>(&["--id", "a", "--wasm-hash", &format!("{hash_a}")])
.run_in_sandbox(hash_a)
.unwrap();

let hash_b = WASM_B.hash().unwrap();
workspace
.cmd_arr::<install::Cmd>(&["--wasm", &WASM_B.path().to_string_lossy()])
.run_in_sandbox(WASM_B.bytes())
.unwrap();
workspace
.cmd_arr::<deploy::Cmd>(&["--id", "b", "--wasm-hash", &format!("{hash_b}")])
.run_in_sandbox(hash_b)
.unwrap();

let res = workspace
.invoke(&[
"--id",
"b",
"--",
"add_with",
"--contract_id",
"a",
"--x",
"5",
"--y",
"7",
])
.unwrap();

assert_eq!(res, "12");
});
}
47 changes: 47 additions & 0 deletions test/doc-tests/tests/it/custom_types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//! Tests CLI commands from https://soroban.stellar.org/docs/how-to-guides/custom-types

use soroban_test::{TestEnv, Wasm};

const WASM: &Wasm = &Wasm::Release("soroban_custom_types_contract");

fn increment_by_5(workspace: &TestEnv) -> String {
workspace
.invoke(&[
"--wasm",
&WASM.path().to_string_lossy(),
"--id",
"1",
"--",
"increment",
"--incr",
"5",
])
.unwrap()
}

#[test]
fn invoke() {
TestEnv::with_default(|workspace| {
assert_eq!("5", increment_by_5(workspace));
});
}

const EXPECTED_READ: &str = r#"STATE,"{""count"":5,""last_incr"":5}"
"#;

#[test]
fn read() {
TestEnv::with_default(|workspace| {
increment_by_5(workspace);

// `read::Cmd`'s `run` returns `()` & dumps right to STDOUT; need to use assert_cmd
workspace
.new_assert_cmd("contract")
.arg("read")
.args(["--id", "1"])
.args(["--key", "STATE"])
.assert()
.stderr("")
.stdout(EXPECTED_READ);
});
}
52 changes: 52 additions & 0 deletions test/doc-tests/tests/it/deployer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//! Tests CLI commands from https://soroban.stellar.org/docs/how-to-guides/deployer

use soroban_cli::commands::contract::install;
use soroban_test::{TestEnv, Wasm};

const WASM_DEPLOYER_TEST: &Wasm = &Wasm::Release("soroban_deployer_test_contract");
const WASM_DEPLOYER: &Wasm = &Wasm::Release("soroban_deployer_contract");

const INIT_VALUE: &str = "5";

#[test]
fn invoke() {
TestEnv::with_default(|workspace| {
let hash = WASM_DEPLOYER_TEST.hash().unwrap();

// install (aka upload) the bytes
let install_ret = workspace
.cmd_arr::<install::Cmd>(&["--wasm", &WASM_DEPLOYER_TEST.path().to_string_lossy()])
.run_in_sandbox(WASM_DEPLOYER_TEST.bytes())
.unwrap();
assert_eq!(hash, install_ret);

// now invoke a 2nd contract, which deploys an instance of the previously-uploaded bytes
let new_contract_info_array = workspace
.invoke(&[
"--wasm",
&WASM_DEPLOYER.path().to_string_lossy(),
"--id",
"0",
"--",
"deploy",
"--salt",
"0000000000000000000000000000000000000000000000000000000000000000",
"--wasm_hash",
&hash.to_string(),
"--init_fn",
"init",
"--init_args",
&format!("[{{\"u32\":{INIT_VALUE}}}]"),
])
.unwrap();

let contract_id = new_contract_info_array.split('"').nth(1).unwrap();

assert_eq!(
format!("{INIT_VALUE}"),
workspace
.invoke(&["--id", contract_id, "--", "value",])
.unwrap()
);
});
}
39 changes: 39 additions & 0 deletions test/doc-tests/tests/it/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//! Tests CLI commands from https://soroban.stellar.org/docs/how-to-guides/errors

use soroban_cli::commands::contract::invoke;
use soroban_test::{TestEnv, Wasm};

const WASM: &Wasm = &Wasm::Release("soroban_errors_contract");

const EXPECTED_ERROR_START: &str = r#"HostError
Value: Status(ContractError(1))
"#;

#[test]
fn invoke() {
TestEnv::with_default(|sandbox| {
let increment = || {
sandbox.invoke(&[
"--wasm",
&WASM.path().to_string_lossy(),
"--id",
"1",
"--",
"increment",
])
};

// works the first five times
assert_eq!(increment().unwrap(), "1");
assert_eq!(increment().unwrap(), "2");
assert_eq!(increment().unwrap(), "3");
assert_eq!(increment().unwrap(), "4");
assert_eq!(increment().unwrap(), "5");

// then errors
let res = increment();

assert!(matches!(res, Err(invoke::Error::Host(_))));
assert!(format!("{res:?}").contains(EXPECTED_ERROR_START));
});
}
25 changes: 25 additions & 0 deletions test/doc-tests/tests/it/events.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//! Tests CLI commands from https://soroban.stellar.org/docs/how-to-guides/events

use soroban_test::{TestEnv, Wasm};

const WASM: &Wasm = &Wasm::Release("soroban_events_contract");

const EXPECTED_EVENT: &str = r#"#0: event: {"ext":"v0","contract_id":"0000000000000000000000000000000000000000000000000000000000000001","type_":"contract","body":{"v0":{"topics":[{"symbol":"COUNTER"},{"symbol":"increment"}],"data":{"u32":1}}}}
"#;

#[test]
fn invoke() {
TestEnv::with_default(|workspace| {
// events get dumped right to STDERR using eprintln; need to test with assert_cmd
workspace
.new_assert_cmd("contract")
.arg("invoke")
.arg("--wasm")
.arg(&WASM.path())
.args(["--id", "1"])
.args(["--", "increment"])
.assert()
.stdout("1\n")
.stderr(EXPECTED_EVENT);
});
}
Loading