From 16dbe3cb1d8ba67124040d648fd63caa7a867ae0 Mon Sep 17 00:00:00 2001 From: Willem Wyndham Date: Thu, 14 Sep 2023 11:22:59 -0400 Subject: [PATCH 01/12] feat: use sim preamble to restore needed entries Currently the test uses a sleep because it has been a struggle to get an entry's expiration --- cmd/soroban-rpc/internal/test/cli_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/soroban-rpc/internal/test/cli_test.go b/cmd/soroban-rpc/internal/test/cli_test.go index 8ceb2f213..844f39891 100644 --- a/cmd/soroban-rpc/internal/test/cli_test.go +++ b/cmd/soroban-rpc/internal/test/cli_test.go @@ -8,6 +8,7 @@ import ( "strconv" "strings" "testing" + "time" "github.com/creachadair/jrpc2" "github.com/creachadair/jrpc2/jhttp" @@ -197,7 +198,7 @@ func runSuccessfulCLICmd(t *testing.T, cmd string) string { return strings.TrimSpace(stdout) } -func runCLICommand(t *testing.T, cmd string) *icmd.Result { +func cliCmd(t *testing.T, cmd string) icmd.Cmd { args := []string{"run", "-q", "--", "--vv"} parsedArgs, err := shlex.Split(cmd) require.NoError(t, err, cmd) @@ -207,7 +208,7 @@ func runCLICommand(t *testing.T, cmd string) *icmd.Result { fmt.Sprintf("SOROBAN_RPC_URL=http://localhost:%d/", sorobanRPCPort), fmt.Sprintf("SOROBAN_NETWORK_PASSPHRASE=%s", StandaloneNetworkPassphrase), ) - return icmd.RunCmd(c) + return c } func getCLIDefaultAccount(t *testing.T) string { From 187fb3a2eca04dd7984602880525d508ab8930b7 Mon Sep 17 00:00:00 2001 From: Alfonso Acosta Date: Thu, 14 Sep 2023 19:41:10 +0200 Subject: [PATCH 02/12] Stop using a magic wait time and clean-up the code --- cmd/soroban-rpc/internal/test/cli_test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cmd/soroban-rpc/internal/test/cli_test.go b/cmd/soroban-rpc/internal/test/cli_test.go index 844f39891..8ceb2f213 100644 --- a/cmd/soroban-rpc/internal/test/cli_test.go +++ b/cmd/soroban-rpc/internal/test/cli_test.go @@ -8,7 +8,6 @@ import ( "strconv" "strings" "testing" - "time" "github.com/creachadair/jrpc2" "github.com/creachadair/jrpc2/jhttp" @@ -198,7 +197,7 @@ func runSuccessfulCLICmd(t *testing.T, cmd string) string { return strings.TrimSpace(stdout) } -func cliCmd(t *testing.T, cmd string) icmd.Cmd { +func runCLICommand(t *testing.T, cmd string) *icmd.Result { args := []string{"run", "-q", "--", "--vv"} parsedArgs, err := shlex.Split(cmd) require.NoError(t, err, cmd) @@ -208,7 +207,7 @@ func cliCmd(t *testing.T, cmd string) icmd.Cmd { fmt.Sprintf("SOROBAN_RPC_URL=http://localhost:%d/", sorobanRPCPort), fmt.Sprintf("SOROBAN_NETWORK_PASSPHRASE=%s", StandaloneNetworkPassphrase), ) - return c + return icmd.RunCmd(c) } func getCLIDefaultAccount(t *testing.T) string { From eabf339525675e658628c7507383359477a6aabf Mon Sep 17 00:00:00 2001 From: Willem Wyndham Date: Thu, 14 Sep 2023 16:00:57 -0400 Subject: [PATCH 03/12] feat: run cargo tests from go First example of using `cargo test` from the go code. --- .../soroban-test/tests/it/contract_sandbox.rs | 31 +++++++++++++------ cmd/crates/soroban-test/tests/it/util.rs | 1 + cmd/soroban-rpc/internal/test/cli_test.go | 16 ++++++++++ 3 files changed, 38 insertions(+), 10 deletions(-) diff --git a/cmd/crates/soroban-test/tests/it/contract_sandbox.rs b/cmd/crates/soroban-test/tests/it/contract_sandbox.rs index 5acfe90d4..fcc5ade2d 100644 --- a/cmd/crates/soroban-test/tests/it/contract_sandbox.rs +++ b/cmd/crates/soroban-test/tests/it/contract_sandbox.rs @@ -7,13 +7,19 @@ use std::path::PathBuf; use crate::util::{ add_test_seed, DEFAULT_PUB_KEY, DEFAULT_PUB_KEY_1, DEFAULT_SECRET_KEY, DEFAULT_SEED_PHRASE, - HELLO_WORLD, + HELLO_WORLD, TEST_SALT, }; #[test] fn install_wasm_then_deploy_contract() { - let hash = HELLO_WORLD.hash().unwrap(); let sandbox = TestEnv::default(); + assert_eq!(deploy_hello(&sandbox), TEST_CONTRACT_ID); +} + +const TEST_CONTRACT_ID: &str = "CBVTIVBYWAO2HNPNGKDCZW4OZYYESTKNGD7IPRTDGQSFJS4QBDQQJX3T"; + +fn deploy_hello(sandbox: &TestEnv) -> String { + let hash = HELLO_WORLD.hash().unwrap(); sandbox .new_assert_cmd("contract") .arg("install") @@ -23,15 +29,18 @@ fn install_wasm_then_deploy_contract() { .success() .stdout(format!("{hash}\n")); - sandbox - .new_assert_cmd("contract") - .arg("deploy") - .arg("--wasm-hash") - .arg(&format!("{hash}")) - .arg("--id=1") - .assert() + let mut cmd: &mut assert_cmd::Command = &mut sandbox.new_assert_cmd("contract"); + + cmd = cmd.arg("deploy").arg("--wasm-hash").arg(&format!("{hash}")); + if std::env::var("SOROBAN_RPC_URL").is_err() { + cmd = cmd.arg("--id").arg(TEST_CONTRACT_ID); + } else { + cmd = cmd.arg("--salt").arg(TEST_SALT); + } + cmd.assert() .success() - .stdout("CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM\n"); + .stdout(format!("{TEST_CONTRACT_ID}\n")); + TEST_CONTRACT_ID.to_string() } #[test] @@ -53,6 +62,8 @@ fn invoke_hello_world_with_deploy_first() { let res = sandbox .new_assert_cmd("contract") .arg("deploy") + .arg("--salt") + .arg(TEST_SALT) .arg("--wasm") .arg(HELLO_WORLD.path()) .assert() diff --git a/cmd/crates/soroban-test/tests/it/util.rs b/cmd/crates/soroban-test/tests/it/util.rs index ecd95ef8a..17df21e70 100644 --- a/cmd/crates/soroban-test/tests/it/util.rs +++ b/cmd/crates/soroban-test/tests/it/util.rs @@ -91,3 +91,4 @@ pub const DEFAULT_PUB_KEY: &str = "GDIY6AQQ75WMD4W46EYB7O6UYMHOCGQHLAQGQTKHDX4J2 pub const DEFAULT_SECRET_KEY: &str = "SC36BWNUOCZAO7DMEJNNKFV6BOTPJP7IG5PSHLUOLT6DZFRU3D3XGIXW"; pub const DEFAULT_PUB_KEY_1: &str = "GCKZUJVUNEFGD4HLFBUNVYM2QY2P5WQQZMGRA3DDL4HYVT5MW5KG3ODV"; +pub const TEST_SALT: &str = "f55ff16f66f43360266b95db6f8fec01d76031054306ae4a4b380598f6cfd114"; diff --git a/cmd/soroban-rpc/internal/test/cli_test.go b/cmd/soroban-rpc/internal/test/cli_test.go index 8ceb2f213..6f59fbc7b 100644 --- a/cmd/soroban-rpc/internal/test/cli_test.go +++ b/cmd/soroban-rpc/internal/test/cli_test.go @@ -21,6 +21,22 @@ import ( "gotest.tools/v3/icmd" ) +func cargoTest(name string) *icmd.Result { + c := icmd.Command("cargo", "test", "--package", "soroban-test", "--test", "it", "--", name, "--exact", "--nocapture") + c.Env = append(os.Environ(), + fmt.Sprintf("SOROBAN_RPC_URL=http://localhost:%d/", sorobanRPCPort), + fmt.Sprintf("SOROBAN_NETWORK_PASSPHRASE=%s", StandaloneNetworkPassphrase), + ) + return icmd.RunCmd(c) +} + +func TestCLIWithCargo(t *testing.T) { + NewCLITest(t) + res := cargoTest("contract_sandbox::invoke_hello_world_with_deploy_first") + stdout, stderr := res.Stdout(), res.Stderr() + println(stdout, stderr) +} + func TestCLIContractInstall(t *testing.T) { NewCLITest(t) output := runSuccessfulCLICmd(t, "contract install --wasm "+helloWorldContractPath) From 364b00e30e5807c496755c0ac98010f588025186 Mon Sep 17 00:00:00 2001 From: Willem Wyndham Date: Fri, 15 Sep 2023 09:50:39 -0400 Subject: [PATCH 04/12] feat: add all tests from hello_world tests --- cmd/crates/soroban-test/src/lib.rs | 6 +- .../soroban-test/tests/it/contract_sandbox.rs | 182 ++++++++---------- cmd/crates/soroban-test/tests/it/util.rs | 20 ++ cmd/soroban-rpc/internal/test/cli_test.go | 69 ++++++- 4 files changed, 171 insertions(+), 106 deletions(-) diff --git a/cmd/crates/soroban-test/src/lib.rs b/cmd/crates/soroban-test/src/lib.rs index 8116e191b..7cf95c5b6 100644 --- a/cmd/crates/soroban-test/src/lib.rs +++ b/cmd/crates/soroban-test/src/lib.rs @@ -124,7 +124,11 @@ impl TestEnv { /// A convenience method for using the invoke command. pub fn invoke>(&self, command_str: &[I]) -> Result { let cmd = contract::invoke::Cmd::parse_arg_vec( - &command_str.iter().map(AsRef::as_ref).collect::>(), + &command_str + .iter() + .map(AsRef::as_ref) + .filter(|s| !s.is_empty()) + .collect::>(), ) .unwrap(); self.invoke_cmd(cmd) diff --git a/cmd/crates/soroban-test/tests/it/contract_sandbox.rs b/cmd/crates/soroban-test/tests/it/contract_sandbox.rs index fcc5ade2d..30ee8c907 100644 --- a/cmd/crates/soroban-test/tests/it/contract_sandbox.rs +++ b/cmd/crates/soroban-test/tests/it/contract_sandbox.rs @@ -6,8 +6,9 @@ use soroban_test::TestEnv; use std::path::PathBuf; use crate::util::{ - add_test_seed, DEFAULT_PUB_KEY, DEFAULT_PUB_KEY_1, DEFAULT_SECRET_KEY, DEFAULT_SEED_PHRASE, - HELLO_WORLD, TEST_SALT, + add_test_seed, is_rpc, network_passphrase, network_passphrase_arg, rpc_url, rpc_url_arg, + DEFAULT_PUB_KEY, DEFAULT_PUB_KEY_1, DEFAULT_SECRET_KEY, DEFAULT_SEED_PHRASE, HELLO_WORLD, + TEST_SALT, }; #[test] @@ -32,10 +33,10 @@ fn deploy_hello(sandbox: &TestEnv) -> String { let mut cmd: &mut assert_cmd::Command = &mut sandbox.new_assert_cmd("contract"); cmd = cmd.arg("deploy").arg("--wasm-hash").arg(&format!("{hash}")); - if std::env::var("SOROBAN_RPC_URL").is_err() { - cmd = cmd.arg("--id").arg(TEST_CONTRACT_ID); - } else { + if is_rpc() { cmd = cmd.arg("--salt").arg(TEST_SALT); + } else { + cmd = cmd.arg("--id").arg(TEST_CONTRACT_ID); } cmd.assert() .success() @@ -45,6 +46,9 @@ fn deploy_hello(sandbox: &TestEnv) -> String { #[test] fn deploy_contract_with_wasm_file() { + if is_rpc() { + return; + } TestEnv::default() .new_assert_cmd("contract") .arg("deploy") @@ -59,17 +63,7 @@ fn deploy_contract_with_wasm_file() { #[test] fn invoke_hello_world_with_deploy_first() { let sandbox = TestEnv::default(); - let res = sandbox - .new_assert_cmd("contract") - .arg("deploy") - .arg("--salt") - .arg(TEST_SALT) - .arg("--wasm") - .arg(HELLO_WORLD.path()) - .assert() - .success(); - let stdout = String::from_utf8(res.get_output().stdout.clone()).unwrap(); - let id = stdout.trim_end(); + let id = deploy_hello(&sandbox); println!("{id}"); sandbox .new_assert_cmd("contract") @@ -87,10 +81,12 @@ fn invoke_hello_world_with_deploy_first() { #[test] fn invoke_hello_world() { let sandbox = TestEnv::default(); + let id = deploy_hello(&sandbox); sandbox .new_assert_cmd("contract") .arg("invoke") - .arg("--id=1") + .arg("--id") + .arg(id) .arg("--wasm") .arg(HELLO_WORLD.path()) .arg("--") @@ -106,10 +102,12 @@ fn invoke_hello_world_from_file() { let sandbox = TestEnv::default(); let tmp_file = sandbox.temp_dir.join("world.txt"); std::fs::write(&tmp_file, "world").unwrap(); + let id = deploy_hello(&sandbox); sandbox .new_assert_cmd("contract") .arg("invoke") - .arg("--id=1") + .arg("--id") + .arg(id) .arg("--wasm") .arg(HELLO_WORLD.path()) .arg("--") @@ -126,10 +124,12 @@ fn invoke_hello_world_from_file_fail() { let sandbox = TestEnv::default(); let tmp_file = sandbox.temp_dir.join("world.txt"); std::fs::write(&tmp_file, "world").unwrap(); + let id = deploy_hello(&sandbox); sandbox .new_assert_cmd("contract") .arg("invoke") - .arg("--id=1") + .arg("--id") + .arg(id) .arg("--wasm") .arg(HELLO_WORLD.path()) .arg("--") @@ -145,12 +145,16 @@ fn invoke_hello_world_from_file_fail() { #[test] fn invoke_hello_world_with_lib() { TestEnv::with_default(|e| { - let cmd = contract::invoke::Cmd { - contract_id: "1".to_string(), - wasm: Some(HELLO_WORLD.path()), + let id = deploy_hello(e); + let mut cmd = contract::invoke::Cmd { + contract_id: id, slop: vec!["hello".into(), "--world=world".into()], ..Default::default() }; + + cmd.config.network.rpc_url = rpc_url(); + cmd.config.network.network_passphrase = network_passphrase(); + let res = e.invoke_cmd(cmd).unwrap(); assert_eq!(res, r#"["Hello","world"]"#); }); @@ -159,16 +163,19 @@ fn invoke_hello_world_with_lib() { #[test] fn invoke_hello_world_with_lib_two() { TestEnv::with_default(|e| { - let res = e - .invoke(&[ - "--id=1", - "--wasm", - &HELLO_WORLD.to_string(), - "--", - "hello", - "--world=world", - ]) - .unwrap(); + let id = deploy_hello(e); + let hello_world = HELLO_WORLD.to_string(); + let mut invoke_args = vec!["--id", &id, "--wasm", hello_world.as_str()]; + let args = vec!["--", "hello", "--world=world"]; + let res = if let (Some(rpc), Some(network_passphrase)) = + (rpc_url_arg(), network_passphrase_arg()) + { + invoke_args.push(&rpc); + invoke_args.push(&network_passphrase); + e.invoke(&[invoke_args, args].concat()).unwrap() + } else { + e.invoke(&[invoke_args, args].concat()).unwrap() + }; assert_eq!(res, r#"["Hello","world"]"#); }); } @@ -183,10 +190,12 @@ fn invoke_hello_world_with_lib_two() { #[test] fn invoke_auth() { let sandbox = TestEnv::default(); + let id = &deploy_hello(&sandbox); sandbox .new_assert_cmd("contract") .arg("invoke") - .arg("--id=1") + .arg("--id") + .arg(id) .arg("--wasm") .arg(HELLO_WORLD.path()) .arg("--") @@ -201,7 +210,8 @@ fn invoke_auth() { sandbox .new_assert_cmd("contract") .arg("invoke") - .arg("--id=1") + .arg("--id") + .arg(id) .arg("--") .arg("auth") .arg(&format!("--addr={DEFAULT_PUB_KEY}")) @@ -214,16 +224,17 @@ fn invoke_auth() { #[tokio::test] async fn invoke_auth_with_identity() { let sandbox = TestEnv::default(); - sandbox .cmd::("test -d ") .run() .await .unwrap(); + let id = deploy_hello(&sandbox); sandbox .new_assert_cmd("contract") .arg("invoke") - .arg("--id=1") + .arg("--id") + .arg(id) .arg("--wasm") .arg(HELLO_WORLD.path()) .arg("--") @@ -238,11 +249,13 @@ async fn invoke_auth_with_identity() { #[test] fn invoke_auth_with_different_test_account() { let sandbox = TestEnv::default(); + let id = deploy_hello(&sandbox); sandbox .new_assert_cmd("contract") .arg("invoke") .arg("--hd-path=1") - .arg("--id=1") + .arg("--id") + .arg(id) .arg("--wasm") .arg(HELLO_WORLD.path()) .arg("--") @@ -256,31 +269,14 @@ fn invoke_auth_with_different_test_account() { #[test] fn contract_data_read_failure() { - let hash = HELLO_WORLD.hash().unwrap(); let sandbox = TestEnv::default(); - sandbox - .new_assert_cmd("contract") - .arg("install") - .arg("--wasm") - .arg(HELLO_WORLD.path()) - .assert() - .success() - .stdout(format!("{hash}\n")); - - sandbox - .new_assert_cmd("contract") - .arg("deploy") - .arg("--wasm-hash") - .arg(&format!("{hash}")) - .arg("--id=1") - .assert() - .success() - .stdout("CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM\n"); + let id = deploy_hello(&sandbox); sandbox .new_assert_cmd("contract") .arg("read") - .arg("--id=1") + .arg("--id") + .arg(id) .arg("--key=COUNTER") .arg("--durability=persistent") .assert() @@ -292,31 +288,14 @@ fn contract_data_read_failure() { #[test] fn contract_data_read() { - let hash = HELLO_WORLD.hash().unwrap(); let sandbox = TestEnv::default(); - sandbox - .new_assert_cmd("contract") - .arg("install") - .arg("--wasm") - .arg(HELLO_WORLD.path()) - .assert() - .success() - .stdout(format!("{hash}\n")); - - sandbox - .new_assert_cmd("contract") - .arg("deploy") - .arg("--wasm-hash") - .arg(&format!("{hash}")) - .arg("--id=1") - .assert() - .success() - .stdout("CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM\n"); + let id = &deploy_hello(&sandbox); sandbox .new_assert_cmd("contract") .arg("invoke") - .arg("--id=1") + .arg("--id") + .arg(id) .arg("--") .arg("inc") .assert() @@ -325,7 +304,8 @@ fn contract_data_read() { sandbox .new_assert_cmd("contract") .arg("read") - .arg("--id=1") + .arg("--id") + .arg(id) .arg("--key=COUNTER") .arg("--durability=persistent") .assert() @@ -335,7 +315,8 @@ fn contract_data_read() { sandbox .new_assert_cmd("contract") .arg("invoke") - .arg("--id=1") + .arg("--id") + .arg(id) .arg("--") .arg("inc") .assert() @@ -344,7 +325,8 @@ fn contract_data_read() { sandbox .new_assert_cmd("contract") .arg("read") - .arg("--id=1") + .arg("--id") + .arg(id) .arg("--key=COUNTER") .arg("--durability=persistent") .assert() @@ -355,12 +337,15 @@ fn contract_data_read() { #[test] fn invoke_auth_with_different_test_account_fail() { let sandbox = TestEnv::default(); - + let id = &deploy_hello(&sandbox); let res = sandbox.invoke(&[ "--hd-path=1", - "--id=1", + "--id", + id, "--wasm", HELLO_WORLD.path().to_str().unwrap(), + &rpc_url_arg().unwrap_or_default(), + &network_passphrase_arg().unwrap_or_default(), "--", "auth", &format!("--addr={DEFAULT_PUB_KEY}"), @@ -402,12 +387,16 @@ fn invoke_with_sk() { } fn invoke_with_source(sandbox: &TestEnv, source: &str) { + let id = &deploy_hello(sandbox); let cmd = sandbox.invoke(&[ "--source-account", source, - "--id=1", + "--id", + id, "--wasm", HELLO_WORLD.path().to_str().unwrap(), + &rpc_url_arg().unwrap_or_default(), + &network_passphrase_arg().unwrap_or_default(), "--", "hello", "--world=world", @@ -418,7 +407,8 @@ fn invoke_with_source(sandbox: &TestEnv, source: &str) { let cmd = sandbox.invoke(&[ "--source-account", source, - "--id=1", + "--id", + id, "--", "hello", "--world=world", @@ -428,9 +418,12 @@ fn invoke_with_source(sandbox: &TestEnv, source: &str) { #[test] fn handles_kebab_case() { - assert!(TestEnv::default() + let e = TestEnv::default(); + let id = deploy_hello(&e); + assert!(e .invoke(&[ - "--id=1", + "--id", + &id, "--wasm", HELLO_WORLD.path().to_str().unwrap(), "--", @@ -440,22 +433,15 @@ fn handles_kebab_case() { .is_ok()); } -#[ignore] #[tokio::test] async fn fetch() { - // TODO: Currently this test fetches a live contract from futurenet. This obviously depends on - // futurenet for the test to work, which is not great. But also means that if we are upgrading - // the XDR ahead of a futurenet upgrade, this test will pass. Oof. :( + if !is_rpc() { + return; + } let e = TestEnv::default(); let f = e.dir().join("contract.wasm"); - let cmd = e.cmd_arr::(&[ - "--id", - "bc074f0f03934d0189653bc15af9a83170411e103b4c48a63888306cfba41ac8", - "--network", - "futurenet", - "--out-file", - f.to_str().unwrap(), - ]); + let id = deploy_hello(&e); + let cmd = e.cmd_arr::(&["--id", &id, "--out-file", f.to_str().unwrap()]); cmd.run().await.unwrap(); assert!(f.exists()); } diff --git a/cmd/crates/soroban-test/tests/it/util.rs b/cmd/crates/soroban-test/tests/it/util.rs index 17df21e70..56990ec54 100644 --- a/cmd/crates/soroban-test/tests/it/util.rs +++ b/cmd/crates/soroban-test/tests/it/util.rs @@ -84,6 +84,10 @@ where }); } +pub fn is_rpc() -> bool { + std::env::var("SOROBAN_RPC_URL").is_ok() +} + pub const DEFAULT_SEED_PHRASE: &str = "coral light army gather adapt blossom school alcohol coral light army giggle"; @@ -92,3 +96,19 @@ pub const DEFAULT_SECRET_KEY: &str = "SC36BWNUOCZAO7DMEJNNKFV6BOTPJP7IG5PSHLUOLT pub const DEFAULT_PUB_KEY_1: &str = "GCKZUJVUNEFGD4HLFBUNVYM2QY2P5WQQZMGRA3DDL4HYVT5MW5KG3ODV"; pub const TEST_SALT: &str = "f55ff16f66f43360266b95db6f8fec01d76031054306ae4a4b380598f6cfd114"; + +pub fn rpc_url() -> Option { + std::env::var("SOROBAN_RPC_URL").ok() +} + +pub fn rpc_url_arg() -> Option { + rpc_url().map(|url| format!("--rpc-url={url}")) +} + +pub fn network_passphrase() -> Option { + std::env::var("SOROBAN_NETWORK_PASSPHRASE").ok() +} + +pub fn network_passphrase_arg() -> Option { + network_passphrase().map(|p| format!("--network-passphrase={p}")) +} diff --git a/cmd/soroban-rpc/internal/test/cli_test.go b/cmd/soroban-rpc/internal/test/cli_test.go index 6f59fbc7b..0d9243005 100644 --- a/cmd/soroban-rpc/internal/test/cli_test.go +++ b/cmd/soroban-rpc/internal/test/cli_test.go @@ -21,20 +21,75 @@ import ( "gotest.tools/v3/icmd" ) -func cargoTest(name string) *icmd.Result { +func cargoTest(t *testing.T, name string) { + NewCLITest(t) c := icmd.Command("cargo", "test", "--package", "soroban-test", "--test", "it", "--", name, "--exact", "--nocapture") c.Env = append(os.Environ(), fmt.Sprintf("SOROBAN_RPC_URL=http://localhost:%d/", sorobanRPCPort), fmt.Sprintf("SOROBAN_NETWORK_PASSPHRASE=%s", StandaloneNetworkPassphrase), ) - return icmd.RunCmd(c) + res := icmd.RunCmd(c) + require.NoError(t, res.Error, res.Stdout(), res.Stderr()) } -func TestCLIWithCargo(t *testing.T) { - NewCLITest(t) - res := cargoTest("contract_sandbox::invoke_hello_world_with_deploy_first") - stdout, stderr := res.Stdout(), res.Stderr() - println(stdout, stderr) +func TestCLIfetch(t *testing.T) { + cargoTest(t, "contract_sandbox::fetch") +} + +func TestCLIinstall_wasm_then_deploy_contract(t *testing.T) { + cargoTest(t, "contract_sandbox::install_wasm_then_deploy_contract") +} +func TestCLIcontract_data_read_failure(t *testing.T) { + cargoTest(t, "contract_sandbox::contract_data_read_failure") +} +func TestCLIinvoke_auth_with_different_test_account(t *testing.T) { + cargoTest(t, "contract_sandbox::invoke_auth_with_different_test_account") +} +func TestCLIinvoke_auth_with_different_test_account_fail(t *testing.T) { + cargoTest(t, "contract_sandbox::invoke_auth_with_different_test_account_fail") +} +func TestCLIhandles_kebab_case(t *testing.T) { + cargoTest(t, "contract_sandbox::handles_kebab_case") +} +func TestCLIinvoke_auth(t *testing.T) { + cargoTest(t, "contract_sandbox::invoke_auth") +} +func TestCLIinvoke_hello_world(t *testing.T) { + cargoTest(t, "contract_sandbox::invoke_hello_world") +} + +func TestCLIcontract_data_read(t *testing.T) { + cargoTest(t, "contract_sandbox::contract_data_read") +} +func TestCLIinvoke_hello_world_from_file(t *testing.T) { + cargoTest(t, "contract_sandbox::invoke_hello_world_from_file") +} +func TestCLIinvoke_hello_world_from_file_fail(t *testing.T) { + cargoTest(t, "contract_sandbox::invoke_hello_world_from_file_fail") +} +func TestCLIinvoke_hello_world_with_deploy_first(t *testing.T) { + cargoTest(t, "contract_sandbox::invoke_hello_world_with_deploy_first") +} +func TestCLIinvoke_hello_world_with_lib_two(t *testing.T) { + cargoTest(t, "contract_sandbox::invoke_hello_world_with_lib_two") +} +func TestCLIinvoke_hello_world_with_lib(t *testing.T) { + cargoTest(t, "contract_sandbox::invoke_hello_world_with_lib") +} +func TestCLIinvoke_hello_world_with_seed(t *testing.T) { + cargoTest(t, "contract_sandbox::invoke_hello_world_with_seed") +} +func TestCLIinvoke_with_sk(t *testing.T) { + cargoTest(t, "contract_sandbox::invoke_with_sk") +} +func TestCLIinvoke_auth_with_identity(t *testing.T) { + cargoTest(t, "contract_sandbox::invoke_auth_with_identity") +} +func TestCLIinvoke_with_id(t *testing.T) { + cargoTest(t, "contract_sandbox::invoke_with_id") +} +func TestCLIinvoke_with_seed(t *testing.T) { + cargoTest(t, "contract_sandbox::invoke_with_seed") } func TestCLIContractInstall(t *testing.T) { From f0578a5cf225ac69e67d1267fd09199a17ea3a87 Mon Sep 17 00:00:00 2001 From: Willem Wyndham Date: Fri, 15 Sep 2023 11:38:46 -0400 Subject: [PATCH 05/12] fix: remove failing and overlapping tests --- .../src/commands/config/identity/generate.rs | 8 ++++---- cmd/soroban-rpc/internal/test/cli_test.go | 19 +------------------ 2 files changed, 5 insertions(+), 22 deletions(-) diff --git a/cmd/soroban-cli/src/commands/config/identity/generate.rs b/cmd/soroban-cli/src/commands/config/identity/generate.rs index c07fe3d21..76a6073d8 100644 --- a/cmd/soroban-cli/src/commands/config/identity/generate.rs +++ b/cmd/soroban-cli/src/commands/config/identity/generate.rs @@ -64,10 +64,10 @@ impl Cmd { self.config_locator.write_identity(&self.name, &secret)?; if !self.network.is_no_network() { let addr = secret.public_key(self.hd_path)?; - self.network - .get(&self.config_locator)? - .fund_address(&addr) - .await?; + let network = self.network.get(&self.config_locator)?; + network.fund_address(&addr).await.unwrap_or_else(|_| { + tracing::warn!("Failed to fund address: {addr} on at {}", network.rpc_url); + }); } Ok(()) } diff --git a/cmd/soroban-rpc/internal/test/cli_test.go b/cmd/soroban-rpc/internal/test/cli_test.go index 0d9243005..f259a8353 100644 --- a/cmd/soroban-rpc/internal/test/cli_test.go +++ b/cmd/soroban-rpc/internal/test/cli_test.go @@ -36,27 +36,13 @@ func TestCLIfetch(t *testing.T) { cargoTest(t, "contract_sandbox::fetch") } -func TestCLIinstall_wasm_then_deploy_contract(t *testing.T) { - cargoTest(t, "contract_sandbox::install_wasm_then_deploy_contract") -} func TestCLIcontract_data_read_failure(t *testing.T) { cargoTest(t, "contract_sandbox::contract_data_read_failure") } -func TestCLIinvoke_auth_with_different_test_account(t *testing.T) { - cargoTest(t, "contract_sandbox::invoke_auth_with_different_test_account") -} -func TestCLIinvoke_auth_with_different_test_account_fail(t *testing.T) { - cargoTest(t, "contract_sandbox::invoke_auth_with_different_test_account_fail") -} -func TestCLIhandles_kebab_case(t *testing.T) { - cargoTest(t, "contract_sandbox::handles_kebab_case") -} + func TestCLIinvoke_auth(t *testing.T) { cargoTest(t, "contract_sandbox::invoke_auth") } -func TestCLIinvoke_hello_world(t *testing.T) { - cargoTest(t, "contract_sandbox::invoke_hello_world") -} func TestCLIcontract_data_read(t *testing.T) { cargoTest(t, "contract_sandbox::contract_data_read") @@ -67,9 +53,6 @@ func TestCLIinvoke_hello_world_from_file(t *testing.T) { func TestCLIinvoke_hello_world_from_file_fail(t *testing.T) { cargoTest(t, "contract_sandbox::invoke_hello_world_from_file_fail") } -func TestCLIinvoke_hello_world_with_deploy_first(t *testing.T) { - cargoTest(t, "contract_sandbox::invoke_hello_world_with_deploy_first") -} func TestCLIinvoke_hello_world_with_lib_two(t *testing.T) { cargoTest(t, "contract_sandbox::invoke_hello_world_with_lib_two") } From 7201f77c4781f8be7a4cfbcb05a7231975454a5b Mon Sep 17 00:00:00 2001 From: Willem Wyndham Date: Fri, 15 Sep 2023 14:36:30 -0400 Subject: [PATCH 06/12] chore: add wrap test to show contract is created successfully --- cmd/soroban-rpc/internal/test/cli_test.go | 24 +++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/cmd/soroban-rpc/internal/test/cli_test.go b/cmd/soroban-rpc/internal/test/cli_test.go index f259a8353..7abc7e985 100644 --- a/cmd/soroban-rpc/internal/test/cli_test.go +++ b/cmd/soroban-rpc/internal/test/cli_test.go @@ -35,15 +35,12 @@ func cargoTest(t *testing.T, name string) { func TestCLIfetch(t *testing.T) { cargoTest(t, "contract_sandbox::fetch") } - func TestCLIcontract_data_read_failure(t *testing.T) { cargoTest(t, "contract_sandbox::contract_data_read_failure") } - func TestCLIinvoke_auth(t *testing.T) { cargoTest(t, "contract_sandbox::invoke_auth") } - func TestCLIcontract_data_read(t *testing.T) { cargoTest(t, "contract_sandbox::contract_data_read") } @@ -56,9 +53,6 @@ func TestCLIinvoke_hello_world_from_file_fail(t *testing.T) { func TestCLIinvoke_hello_world_with_lib_two(t *testing.T) { cargoTest(t, "contract_sandbox::invoke_hello_world_with_lib_two") } -func TestCLIinvoke_hello_world_with_lib(t *testing.T) { - cargoTest(t, "contract_sandbox::invoke_hello_world_with_lib") -} func TestCLIinvoke_hello_world_with_seed(t *testing.T) { cargoTest(t, "contract_sandbox::invoke_hello_world_with_seed") } @@ -75,6 +69,24 @@ func TestCLIinvoke_with_seed(t *testing.T) { cargoTest(t, "contract_sandbox::invoke_with_seed") } +func TestCLIWrapCustom(t *testing.T) { + NewCLITest(t) + testAccount := getCLIDefaultAccount(t) + strkeyContractID := runSuccessfulCLICmd(t, fmt.Sprintf("lab token wrap --asset=deadbeef:%s", testAccount)) + require.Equal(t, "true", runSuccessfulCLICmd(t, fmt.Sprintf("contract invoke --id=%s -- authorized --id=%s", strkeyContractID, testAccount))) + // require.Equal(t, "CAMTHSPKXZJIRTUXQP5QWJIFH3XIDMKLFAWVQOFOXPTKAW5GKV37ZC4N", strkeyContractID) + runSuccessfulCLICmd(t, fmt.Sprintf("contract invoke --id=%s -- mint --to=%s --amount 1", strkeyContractID, testAccount)) +} + +func TestCLIWrapNative(t *testing.T) { + NewCLITest(t) + testAccount := getCLIDefaultAccount(t) + strkeyContractID := runSuccessfulCLICmd(t, fmt.Sprintf("lab token wrap --asset=native:%s", testAccount)) + require.Equal(t, "CAMTHSPKXZJIRTUXQP5QWJIFH3XIDMKLFAWVQOFOXPTKAW5GKV37ZC4N", strkeyContractID) + require.Equal(t, "true", runSuccessfulCLICmd(t, fmt.Sprintf("contract invoke --id=%s -- authorized --id=%s", strkeyContractID, testAccount))) + require.Equal(t, "\"9223372036854775807\"", runSuccessfulCLICmd(t, fmt.Sprintf("contract invoke --id=%s -- balance --id %s", strkeyContractID, testAccount))) +} + func TestCLIContractInstall(t *testing.T) { NewCLITest(t) output := runSuccessfulCLICmd(t, "contract install --wasm "+helloWorldContractPath) From 23503d6db514b181eb6c12c085fd6a312e7874ed Mon Sep 17 00:00:00 2001 From: Willem Wyndham Date: Mon, 18 Sep 2023 07:56:47 -0400 Subject: [PATCH 07/12] chore: remove comment --- cmd/soroban-rpc/internal/test/cli_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/soroban-rpc/internal/test/cli_test.go b/cmd/soroban-rpc/internal/test/cli_test.go index 7abc7e985..d5e182af8 100644 --- a/cmd/soroban-rpc/internal/test/cli_test.go +++ b/cmd/soroban-rpc/internal/test/cli_test.go @@ -74,7 +74,6 @@ func TestCLIWrapCustom(t *testing.T) { testAccount := getCLIDefaultAccount(t) strkeyContractID := runSuccessfulCLICmd(t, fmt.Sprintf("lab token wrap --asset=deadbeef:%s", testAccount)) require.Equal(t, "true", runSuccessfulCLICmd(t, fmt.Sprintf("contract invoke --id=%s -- authorized --id=%s", strkeyContractID, testAccount))) - // require.Equal(t, "CAMTHSPKXZJIRTUXQP5QWJIFH3XIDMKLFAWVQOFOXPTKAW5GKV37ZC4N", strkeyContractID) runSuccessfulCLICmd(t, fmt.Sprintf("contract invoke --id=%s -- mint --to=%s --amount 1", strkeyContractID, testAccount)) } From d6a8ba3078fbe92224bd973878c1f9dcca85a3b0 Mon Sep 17 00:00:00 2001 From: Willem Wyndham Date: Mon, 18 Sep 2023 10:57:22 -0400 Subject: [PATCH 08/12] feat: organize CLI tests so that they can be invoked programatically --- .../soroban-test/tests/it/contract_sandbox.rs | 493 ------------------ .../tests/it/integration_and_sandbox.rs | 225 ++++++++ cmd/crates/soroban-test/tests/it/main.rs | 3 +- cmd/crates/soroban-test/tests/it/util.rs | 27 + cmd/soroban-rpc/internal/test/cli_test.go | 45 +- 5 files changed, 264 insertions(+), 529 deletions(-) delete mode 100644 cmd/crates/soroban-test/tests/it/contract_sandbox.rs create mode 100644 cmd/crates/soroban-test/tests/it/integration_and_sandbox.rs diff --git a/cmd/crates/soroban-test/tests/it/contract_sandbox.rs b/cmd/crates/soroban-test/tests/it/contract_sandbox.rs deleted file mode 100644 index 30ee8c907..000000000 --- a/cmd/crates/soroban-test/tests/it/contract_sandbox.rs +++ /dev/null @@ -1,493 +0,0 @@ -use soroban_cli::commands::{ - config::identity, - contract::{self, fetch}, -}; -use soroban_test::TestEnv; -use std::path::PathBuf; - -use crate::util::{ - add_test_seed, is_rpc, network_passphrase, network_passphrase_arg, rpc_url, rpc_url_arg, - DEFAULT_PUB_KEY, DEFAULT_PUB_KEY_1, DEFAULT_SECRET_KEY, DEFAULT_SEED_PHRASE, HELLO_WORLD, - TEST_SALT, -}; - -#[test] -fn install_wasm_then_deploy_contract() { - let sandbox = TestEnv::default(); - assert_eq!(deploy_hello(&sandbox), TEST_CONTRACT_ID); -} - -const TEST_CONTRACT_ID: &str = "CBVTIVBYWAO2HNPNGKDCZW4OZYYESTKNGD7IPRTDGQSFJS4QBDQQJX3T"; - -fn deploy_hello(sandbox: &TestEnv) -> String { - let hash = HELLO_WORLD.hash().unwrap(); - sandbox - .new_assert_cmd("contract") - .arg("install") - .arg("--wasm") - .arg(HELLO_WORLD.path()) - .assert() - .success() - .stdout(format!("{hash}\n")); - - let mut cmd: &mut assert_cmd::Command = &mut sandbox.new_assert_cmd("contract"); - - cmd = cmd.arg("deploy").arg("--wasm-hash").arg(&format!("{hash}")); - if is_rpc() { - cmd = cmd.arg("--salt").arg(TEST_SALT); - } else { - cmd = cmd.arg("--id").arg(TEST_CONTRACT_ID); - } - cmd.assert() - .success() - .stdout(format!("{TEST_CONTRACT_ID}\n")); - TEST_CONTRACT_ID.to_string() -} - -#[test] -fn deploy_contract_with_wasm_file() { - if is_rpc() { - return; - } - TestEnv::default() - .new_assert_cmd("contract") - .arg("deploy") - .arg("--wasm") - .arg(HELLO_WORLD.path()) - .arg("--id=1") - .assert() - .success() - .stdout("CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM\n"); -} - -#[test] -fn invoke_hello_world_with_deploy_first() { - let sandbox = TestEnv::default(); - let id = deploy_hello(&sandbox); - println!("{id}"); - sandbox - .new_assert_cmd("contract") - .arg("invoke") - .arg("--id") - .arg(id) - .arg("--") - .arg("hello") - .arg("--world=world") - .assert() - .stdout("[\"Hello\",\"world\"]\n") - .success(); -} - -#[test] -fn invoke_hello_world() { - let sandbox = TestEnv::default(); - let id = deploy_hello(&sandbox); - sandbox - .new_assert_cmd("contract") - .arg("invoke") - .arg("--id") - .arg(id) - .arg("--wasm") - .arg(HELLO_WORLD.path()) - .arg("--") - .arg("hello") - .arg("--world=world") - .assert() - .stdout("[\"Hello\",\"world\"]\n") - .success(); -} - -#[test] -fn invoke_hello_world_from_file() { - let sandbox = TestEnv::default(); - let tmp_file = sandbox.temp_dir.join("world.txt"); - std::fs::write(&tmp_file, "world").unwrap(); - let id = deploy_hello(&sandbox); - sandbox - .new_assert_cmd("contract") - .arg("invoke") - .arg("--id") - .arg(id) - .arg("--wasm") - .arg(HELLO_WORLD.path()) - .arg("--") - .arg("hello") - .arg("--world-file-path") - .arg(&tmp_file) - .assert() - .stdout("[\"Hello\",\"world\"]\n") - .success(); -} - -#[test] -fn invoke_hello_world_from_file_fail() { - let sandbox = TestEnv::default(); - let tmp_file = sandbox.temp_dir.join("world.txt"); - std::fs::write(&tmp_file, "world").unwrap(); - let id = deploy_hello(&sandbox); - sandbox - .new_assert_cmd("contract") - .arg("invoke") - .arg("--id") - .arg(id) - .arg("--wasm") - .arg(HELLO_WORLD.path()) - .arg("--") - .arg("hello") - .arg("--world-file-path") - .arg(&tmp_file) - .arg("--world=hello") - .assert() - .stderr(predicates::str::contains("error: the argument '--world-file-path ' cannot be used with '--world '")) - .failure(); -} - -#[test] -fn invoke_hello_world_with_lib() { - TestEnv::with_default(|e| { - let id = deploy_hello(e); - let mut cmd = contract::invoke::Cmd { - contract_id: id, - slop: vec!["hello".into(), "--world=world".into()], - ..Default::default() - }; - - cmd.config.network.rpc_url = rpc_url(); - cmd.config.network.network_passphrase = network_passphrase(); - - let res = e.invoke_cmd(cmd).unwrap(); - assert_eq!(res, r#"["Hello","world"]"#); - }); -} - -#[test] -fn invoke_hello_world_with_lib_two() { - TestEnv::with_default(|e| { - let id = deploy_hello(e); - let hello_world = HELLO_WORLD.to_string(); - let mut invoke_args = vec!["--id", &id, "--wasm", hello_world.as_str()]; - let args = vec!["--", "hello", "--world=world"]; - let res = if let (Some(rpc), Some(network_passphrase)) = - (rpc_url_arg(), network_passphrase_arg()) - { - invoke_args.push(&rpc); - invoke_args.push(&network_passphrase); - e.invoke(&[invoke_args, args].concat()).unwrap() - } else { - e.invoke(&[invoke_args, args].concat()).unwrap() - }; - assert_eq!(res, r#"["Hello","world"]"#); - }); -} -// #[test] -// fn invoke_hello_world_with_lib_three() { -// let sandbox = TestEnv::default(); -// let builder = invoke::CmdBuilder::new().contract_id("1").wasm(HELLO_WORLD.path()).function("hello").slop(["--hello=world"]).build(); -// std::env::set_current_dir(sandbox.dir()).unwrap(); -// assert_eq!(res.run_in_sandbox().unwrap(), r#"["Hello","world"]"#); -// } - -#[test] -fn invoke_auth() { - let sandbox = TestEnv::default(); - let id = &deploy_hello(&sandbox); - sandbox - .new_assert_cmd("contract") - .arg("invoke") - .arg("--id") - .arg(id) - .arg("--wasm") - .arg(HELLO_WORLD.path()) - .arg("--") - .arg("auth") - .arg(&format!("--addr={DEFAULT_PUB_KEY}")) - .arg("--world=world") - .assert() - .stdout(format!("\"{DEFAULT_PUB_KEY}\"\n")) - .success(); - - // Invoke it again without providing the contract, to exercise the deployment - sandbox - .new_assert_cmd("contract") - .arg("invoke") - .arg("--id") - .arg(id) - .arg("--") - .arg("auth") - .arg(&format!("--addr={DEFAULT_PUB_KEY}")) - .arg("--world=world") - .assert() - .stdout(format!("\"{DEFAULT_PUB_KEY}\"\n")) - .success(); -} - -#[tokio::test] -async fn invoke_auth_with_identity() { - let sandbox = TestEnv::default(); - sandbox - .cmd::("test -d ") - .run() - .await - .unwrap(); - let id = deploy_hello(&sandbox); - sandbox - .new_assert_cmd("contract") - .arg("invoke") - .arg("--id") - .arg(id) - .arg("--wasm") - .arg(HELLO_WORLD.path()) - .arg("--") - .arg("auth") - .arg("--addr=test") - .arg("--world=world") - .assert() - .stdout(format!("\"{DEFAULT_PUB_KEY}\"\n")) - .success(); -} - -#[test] -fn invoke_auth_with_different_test_account() { - let sandbox = TestEnv::default(); - let id = deploy_hello(&sandbox); - sandbox - .new_assert_cmd("contract") - .arg("invoke") - .arg("--hd-path=1") - .arg("--id") - .arg(id) - .arg("--wasm") - .arg(HELLO_WORLD.path()) - .arg("--") - .arg("auth") - .arg(&format!("--addr={DEFAULT_PUB_KEY_1}")) - .arg("--world=world") - .assert() - .stdout(format!("\"{DEFAULT_PUB_KEY_1}\"\n")) - .success(); -} - -#[test] -fn contract_data_read_failure() { - let sandbox = TestEnv::default(); - let id = deploy_hello(&sandbox); - - sandbox - .new_assert_cmd("contract") - .arg("read") - .arg("--id") - .arg(id) - .arg("--key=COUNTER") - .arg("--durability=persistent") - .assert() - .failure() - .stderr( - "error: no matching contract data entries were found for the specified contract id\n", - ); -} - -#[test] -fn contract_data_read() { - let sandbox = TestEnv::default(); - let id = &deploy_hello(&sandbox); - - sandbox - .new_assert_cmd("contract") - .arg("invoke") - .arg("--id") - .arg(id) - .arg("--") - .arg("inc") - .assert() - .success(); - - sandbox - .new_assert_cmd("contract") - .arg("read") - .arg("--id") - .arg(id) - .arg("--key=COUNTER") - .arg("--durability=persistent") - .assert() - .success() - .stdout("COUNTER,1,4096\n"); - - sandbox - .new_assert_cmd("contract") - .arg("invoke") - .arg("--id") - .arg(id) - .arg("--") - .arg("inc") - .assert() - .success(); - - sandbox - .new_assert_cmd("contract") - .arg("read") - .arg("--id") - .arg(id) - .arg("--key=COUNTER") - .arg("--durability=persistent") - .assert() - .success() - .stdout("COUNTER,2,4096\n"); -} - -#[test] -fn invoke_auth_with_different_test_account_fail() { - let sandbox = TestEnv::default(); - let id = &deploy_hello(&sandbox); - let res = sandbox.invoke(&[ - "--hd-path=1", - "--id", - id, - "--wasm", - HELLO_WORLD.path().to_str().unwrap(), - &rpc_url_arg().unwrap_or_default(), - &network_passphrase_arg().unwrap_or_default(), - "--", - "auth", - &format!("--addr={DEFAULT_PUB_KEY}"), - "--world=world", - ]); - assert!(res.is_err()); - if let Err(e) = res { - assert!( - matches!(e, contract::invoke::Error::Host(_)), - "Expected host error got {e:?}" - ); - }; -} - -#[test] -fn invoke_hello_world_with_seed() { - let sandbox = TestEnv::default(); - let identity = add_test_seed(sandbox.dir()); - invoke_with_source(&sandbox, &identity); -} - -#[test] -fn invoke_with_seed() { - let sandbox = TestEnv::default(); - invoke_with_source(&sandbox, DEFAULT_SEED_PHRASE); -} - -#[test] -fn invoke_with_id() { - let sandbox = TestEnv::default(); - let identity = add_test_seed(sandbox.dir()); - invoke_with_source(&sandbox, &identity); -} - -#[test] -fn invoke_with_sk() { - let sandbox = TestEnv::default(); - invoke_with_source(&sandbox, DEFAULT_SECRET_KEY); -} - -fn invoke_with_source(sandbox: &TestEnv, source: &str) { - let id = &deploy_hello(sandbox); - let cmd = sandbox.invoke(&[ - "--source-account", - source, - "--id", - id, - "--wasm", - HELLO_WORLD.path().to_str().unwrap(), - &rpc_url_arg().unwrap_or_default(), - &network_passphrase_arg().unwrap_or_default(), - "--", - "hello", - "--world=world", - ]); - assert_eq!(cmd.unwrap(), "[\"Hello\",\"world\"]"); - - // Invoke it again without providing the contract, to exercise the deployment - let cmd = sandbox.invoke(&[ - "--source-account", - source, - "--id", - id, - "--", - "hello", - "--world=world", - ]); - assert_eq!(cmd.unwrap(), "[\"Hello\",\"world\"]"); -} - -#[test] -fn handles_kebab_case() { - let e = TestEnv::default(); - let id = deploy_hello(&e); - assert!(e - .invoke(&[ - "--id", - &id, - "--wasm", - HELLO_WORLD.path().to_str().unwrap(), - "--", - "multi-word-cmd", - "--contract-owner=world", - ]) - .is_ok()); -} - -#[tokio::test] -async fn fetch() { - if !is_rpc() { - return; - } - let e = TestEnv::default(); - let f = e.dir().join("contract.wasm"); - let id = deploy_hello(&e); - let cmd = e.cmd_arr::(&["--id", &id, "--out-file", f.to_str().unwrap()]); - cmd.run().await.unwrap(); - assert!(f.exists()); -} - -#[test] -fn build() { - let sandbox = TestEnv::default(); - - let cargo_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let hello_world_contract_path = - cargo_dir.join("tests/fixtures/test-wasms/hello_world/Cargo.toml"); - sandbox - .new_assert_cmd("contract") - .arg("build") - .arg("--manifest-path") - .arg(hello_world_contract_path) - .arg("--profile") - .arg("test-wasms") - .arg("--package") - .arg("test_hello_world") - .assert() - .success(); -} - -#[test] -fn invoke_prng_u64_in_range_test() { - let sandbox = TestEnv::default(); - let res = sandbox - .new_assert_cmd("contract") - .arg("deploy") - .arg("--wasm") - .arg(HELLO_WORLD.path()) - .assert() - .success(); - let stdout = String::from_utf8(res.get_output().stdout.clone()).unwrap(); - let id = stdout.trim_end(); - println!("{id}"); - sandbox - .new_assert_cmd("contract") - .arg("invoke") - .arg("--id") - .arg(id) - .arg("--") - .arg("prng_u64_in_range") - .arg("--low=0") - .arg("--high=100") - .assert() - .success(); -} diff --git a/cmd/crates/soroban-test/tests/it/integration_and_sandbox.rs b/cmd/crates/soroban-test/tests/it/integration_and_sandbox.rs new file mode 100644 index 000000000..a87e60cb5 --- /dev/null +++ b/cmd/crates/soroban-test/tests/it/integration_and_sandbox.rs @@ -0,0 +1,225 @@ +use soroban_cli::commands::{config::identity, contract::fetch}; +use soroban_test::TestEnv; + +use crate::util::{ + add_test_seed, deploy_hello, is_rpc, network_passphrase_arg, rpc_url_arg, DEFAULT_PUB_KEY, + DEFAULT_SECRET_KEY, DEFAULT_SEED_PHRASE, HELLO_WORLD, TEST_CONTRACT_ID, +}; + +#[test] +fn install_wasm_then_deploy_contract() { + let sandbox = TestEnv::default(); + assert_eq!(deploy_hello(&sandbox), TEST_CONTRACT_ID); +} + +#[test] +fn invoke_hello_world_with_lib_two() { + TestEnv::with_default(|e| { + let id = deploy_hello(e); + let hello_world = HELLO_WORLD.to_string(); + let mut invoke_args = vec!["--id", &id, "--wasm", hello_world.as_str()]; + let args = vec!["--", "hello", "--world=world"]; + let res = if let (Some(rpc), Some(network_passphrase)) = + (rpc_url_arg(), network_passphrase_arg()) + { + invoke_args.push(&rpc); + invoke_args.push(&network_passphrase); + e.invoke(&[invoke_args, args].concat()).unwrap() + } else { + e.invoke(&[invoke_args, args].concat()).unwrap() + }; + assert_eq!(res, r#"["Hello","world"]"#); + }); +} + +#[test] +fn invoke_auth() { + let sandbox = TestEnv::default(); + let id = &deploy_hello(&sandbox); + sandbox + .new_assert_cmd("contract") + .arg("invoke") + .arg("--id") + .arg(id) + .arg("--wasm") + .arg(HELLO_WORLD.path()) + .arg("--") + .arg("auth") + .arg(&format!("--addr={DEFAULT_PUB_KEY}")) + .arg("--world=world") + .assert() + .stdout(format!("\"{DEFAULT_PUB_KEY}\"\n")) + .success(); + + // Invoke it again without providing the contract, to exercise the deployment + sandbox + .new_assert_cmd("contract") + .arg("invoke") + .arg("--id") + .arg(id) + .arg("--") + .arg("auth") + .arg(&format!("--addr={DEFAULT_PUB_KEY}")) + .arg("--world=world") + .assert() + .stdout(format!("\"{DEFAULT_PUB_KEY}\"\n")) + .success(); +} + +#[tokio::test] +async fn invoke_auth_with_identity() { + let sandbox = TestEnv::default(); + sandbox + .cmd::("test -d ") + .run() + .await + .unwrap(); + let id = deploy_hello(&sandbox); + sandbox + .new_assert_cmd("contract") + .arg("invoke") + .arg("--id") + .arg(id) + .arg("--wasm") + .arg(HELLO_WORLD.path()) + .arg("--") + .arg("auth") + .arg("--addr=test") + .arg("--world=world") + .assert() + .stdout(format!("\"{DEFAULT_PUB_KEY}\"\n")) + .success(); +} + +#[test] +fn contract_data_read_failure() { + let sandbox = TestEnv::default(); + let id = deploy_hello(&sandbox); + + sandbox + .new_assert_cmd("contract") + .arg("read") + .arg("--id") + .arg(id) + .arg("--key=COUNTER") + .assert() + .failure() + .stderr( + "error: no matching contract data entries were found for the specified contract id\n", + ); +} + +#[test] +fn contract_data_read() { + let sandbox = TestEnv::default(); + let id = &deploy_hello(&sandbox); + + sandbox + .new_assert_cmd("contract") + .arg("invoke") + .arg("--id") + .arg(id) + .arg("--") + .arg("inc") + .assert() + .success(); + + sandbox + .new_assert_cmd("contract") + .arg("read") + .arg("--id") + .arg(id) + .arg("--key=COUNTER") + .assert() + .success() + .stdout("COUNTER,1\n"); + + sandbox + .new_assert_cmd("contract") + .arg("invoke") + .arg("--id") + .arg(id) + .arg("--") + .arg("inc") + .assert() + .success(); + + sandbox + .new_assert_cmd("contract") + .arg("read") + .arg("--id") + .arg(id) + .arg("--key=COUNTER") + .assert() + .success() + .stdout("COUNTER,2\n"); +} + +#[test] +fn invoke_hello_world_with_seed() { + let sandbox = TestEnv::default(); + let identity = add_test_seed(sandbox.dir()); + invoke_with_source(&sandbox, &identity); +} + +#[test] +fn invoke_with_seed() { + let sandbox = TestEnv::default(); + invoke_with_source(&sandbox, DEFAULT_SEED_PHRASE); +} + +#[test] +fn invoke_with_id() { + let sandbox = TestEnv::default(); + let identity = add_test_seed(sandbox.dir()); + invoke_with_source(&sandbox, &identity); +} + +#[test] +fn invoke_with_sk() { + let sandbox = TestEnv::default(); + invoke_with_source(&sandbox, DEFAULT_SECRET_KEY); +} + +fn invoke_with_source(sandbox: &TestEnv, source: &str) { + let id = &deploy_hello(sandbox); + let cmd = sandbox.invoke(&[ + "--source-account", + source, + "--id", + id, + "--wasm", + HELLO_WORLD.path().to_str().unwrap(), + &rpc_url_arg().unwrap_or_default(), + &network_passphrase_arg().unwrap_or_default(), + "--", + "hello", + "--world=world", + ]); + assert_eq!(cmd.unwrap(), "[\"Hello\",\"world\"]"); + + // Invoke it again without providing the contract, to exercise the deployment + let cmd = sandbox.invoke(&[ + "--source-account", + source, + "--id", + id, + "--", + "hello", + "--world=world", + ]); + assert_eq!(cmd.unwrap(), "[\"Hello\",\"world\"]"); +} + +#[tokio::test] +async fn fetch() { + if !is_rpc() { + return; + } + let e = TestEnv::default(); + let f = e.dir().join("contract.wasm"); + let id = deploy_hello(&e); + let cmd = e.cmd_arr::(&["--id", &id, "--out-file", f.to_str().unwrap()]); + cmd.run().await.unwrap(); + assert!(f.exists()); +} diff --git a/cmd/crates/soroban-test/tests/it/main.rs b/cmd/crates/soroban-test/tests/it/main.rs index 1d3af2cb6..e822b7740 100644 --- a/cmd/crates/soroban-test/tests/it/main.rs +++ b/cmd/crates/soroban-test/tests/it/main.rs @@ -1,9 +1,10 @@ mod arg_parsing; mod config; -mod contract_sandbox; mod custom_types; mod dotenv; +mod hello_world; +mod integration_and_sandbox; mod lab; mod plugin; mod util; diff --git a/cmd/crates/soroban-test/tests/it/util.rs b/cmd/crates/soroban-test/tests/it/util.rs index 56990ec54..68c2e31ac 100644 --- a/cmd/crates/soroban-test/tests/it/util.rs +++ b/cmd/crates/soroban-test/tests/it/util.rs @@ -112,3 +112,30 @@ pub fn network_passphrase() -> Option { pub fn network_passphrase_arg() -> Option { network_passphrase().map(|p| format!("--network-passphrase={p}")) } + +pub const TEST_CONTRACT_ID: &str = "CBVTIVBYWAO2HNPNGKDCZW4OZYYESTKNGD7IPRTDGQSFJS4QBDQQJX3T"; + +pub fn deploy_hello(sandbox: &TestEnv) -> String { + let hash = HELLO_WORLD.hash().unwrap(); + sandbox + .new_assert_cmd("contract") + .arg("install") + .arg("--wasm") + .arg(HELLO_WORLD.path()) + .assert() + .success() + .stdout(format!("{hash}\n")); + + let mut cmd: &mut assert_cmd::Command = &mut sandbox.new_assert_cmd("contract"); + + cmd = cmd.arg("deploy").arg("--wasm-hash").arg(&format!("{hash}")); + if is_rpc() { + cmd = cmd.arg("--salt").arg(TEST_SALT); + } else { + cmd = cmd.arg("--id").arg(TEST_CONTRACT_ID); + } + cmd.assert() + .success() + .stdout(format!("{TEST_CONTRACT_ID}\n")); + TEST_CONTRACT_ID.to_string() +} diff --git a/cmd/soroban-rpc/internal/test/cli_test.go b/cmd/soroban-rpc/internal/test/cli_test.go index d5e182af8..bb3a789ac 100644 --- a/cmd/soroban-rpc/internal/test/cli_test.go +++ b/cmd/soroban-rpc/internal/test/cli_test.go @@ -32,41 +32,16 @@ func cargoTest(t *testing.T, name string) { require.NoError(t, res.Error, res.Stdout(), res.Stderr()) } -func TestCLIfetch(t *testing.T) { - cargoTest(t, "contract_sandbox::fetch") -} -func TestCLIcontract_data_read_failure(t *testing.T) { - cargoTest(t, "contract_sandbox::contract_data_read_failure") -} -func TestCLIinvoke_auth(t *testing.T) { - cargoTest(t, "contract_sandbox::invoke_auth") -} -func TestCLIcontract_data_read(t *testing.T) { - cargoTest(t, "contract_sandbox::contract_data_read") -} -func TestCLIinvoke_hello_world_from_file(t *testing.T) { - cargoTest(t, "contract_sandbox::invoke_hello_world_from_file") -} -func TestCLIinvoke_hello_world_from_file_fail(t *testing.T) { - cargoTest(t, "contract_sandbox::invoke_hello_world_from_file_fail") -} -func TestCLIinvoke_hello_world_with_lib_two(t *testing.T) { - cargoTest(t, "contract_sandbox::invoke_hello_world_with_lib_two") -} -func TestCLIinvoke_hello_world_with_seed(t *testing.T) { - cargoTest(t, "contract_sandbox::invoke_hello_world_with_seed") -} -func TestCLIinvoke_with_sk(t *testing.T) { - cargoTest(t, "contract_sandbox::invoke_with_sk") -} -func TestCLIinvoke_auth_with_identity(t *testing.T) { - cargoTest(t, "contract_sandbox::invoke_auth_with_identity") -} -func TestCLIinvoke_with_id(t *testing.T) { - cargoTest(t, "contract_sandbox::invoke_with_id") -} -func TestCLIinvoke_with_seed(t *testing.T) { - cargoTest(t, "contract_sandbox::invoke_with_seed") +func TestCLICargoTest(t *testing.T) { + names := icmd.RunCmd(icmd.Command("cargo", "-q", "test", "integration_and_sandbox::", "--package", "soroban-test", "--", "--list")) + input := names.Stdout() + lines := strings.Split(input, "\n") + for _, line := range lines { + testName := strings.TrimSuffix(line, ": test") + t.Run(testName, func(t *testing.T) { + cargoTest(t, testName) + }) + } } func TestCLIWrapCustom(t *testing.T) { From a843350fe9698dffa8d5e6d118b94c65b612e6e5 Mon Sep 17 00:00:00 2001 From: Willem Wyndham Date: Thu, 14 Sep 2023 11:22:59 -0400 Subject: [PATCH 09/12] feat: use sim preamble to restore needed entries Currently the test uses a sleep because it has been a struggle to get an entry's expiration --- cmd/soroban-rpc/internal/test/cli_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/soroban-rpc/internal/test/cli_test.go b/cmd/soroban-rpc/internal/test/cli_test.go index bb3a789ac..988382f13 100644 --- a/cmd/soroban-rpc/internal/test/cli_test.go +++ b/cmd/soroban-rpc/internal/test/cli_test.go @@ -8,6 +8,7 @@ import ( "strconv" "strings" "testing" + "time" "github.com/creachadair/jrpc2" "github.com/creachadair/jrpc2/jhttp" @@ -237,7 +238,7 @@ func runSuccessfulCLICmd(t *testing.T, cmd string) string { return strings.TrimSpace(stdout) } -func runCLICommand(t *testing.T, cmd string) *icmd.Result { +func cliCmd(t *testing.T, cmd string) icmd.Cmd { args := []string{"run", "-q", "--", "--vv"} parsedArgs, err := shlex.Split(cmd) require.NoError(t, err, cmd) @@ -247,7 +248,7 @@ func runCLICommand(t *testing.T, cmd string) *icmd.Result { fmt.Sprintf("SOROBAN_RPC_URL=http://localhost:%d/", sorobanRPCPort), fmt.Sprintf("SOROBAN_NETWORK_PASSPHRASE=%s", StandaloneNetworkPassphrase), ) - return icmd.RunCmd(c) + return c } func getCLIDefaultAccount(t *testing.T) string { From 7b18dc7a46f2fe603ee77ac5135d08a987e0b90a Mon Sep 17 00:00:00 2001 From: Alfonso Acosta Date: Thu, 14 Sep 2023 19:41:10 +0200 Subject: [PATCH 10/12] Stop using a magic wait time and clean-up the code --- cmd/soroban-rpc/internal/test/cli_test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cmd/soroban-rpc/internal/test/cli_test.go b/cmd/soroban-rpc/internal/test/cli_test.go index 988382f13..bb3a789ac 100644 --- a/cmd/soroban-rpc/internal/test/cli_test.go +++ b/cmd/soroban-rpc/internal/test/cli_test.go @@ -8,7 +8,6 @@ import ( "strconv" "strings" "testing" - "time" "github.com/creachadair/jrpc2" "github.com/creachadair/jrpc2/jhttp" @@ -238,7 +237,7 @@ func runSuccessfulCLICmd(t *testing.T, cmd string) string { return strings.TrimSpace(stdout) } -func cliCmd(t *testing.T, cmd string) icmd.Cmd { +func runCLICommand(t *testing.T, cmd string) *icmd.Result { args := []string{"run", "-q", "--", "--vv"} parsedArgs, err := shlex.Split(cmd) require.NoError(t, err, cmd) @@ -248,7 +247,7 @@ func cliCmd(t *testing.T, cmd string) icmd.Cmd { fmt.Sprintf("SOROBAN_RPC_URL=http://localhost:%d/", sorobanRPCPort), fmt.Sprintf("SOROBAN_NETWORK_PASSPHRASE=%s", StandaloneNetworkPassphrase), ) - return c + return icmd.RunCmd(c) } func getCLIDefaultAccount(t *testing.T) string { From c4741171c204f919cbed441eb89cef8333f0ff01 Mon Sep 17 00:00:00 2001 From: Willem Wyndham Date: Mon, 18 Sep 2023 11:54:13 -0400 Subject: [PATCH 11/12] fix: remove extraneous test Since other tests will deploy hello_world this adds nothing --- .../soroban-test/tests/it/integration_and_sandbox.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/cmd/crates/soroban-test/tests/it/integration_and_sandbox.rs b/cmd/crates/soroban-test/tests/it/integration_and_sandbox.rs index a87e60cb5..15c6b5795 100644 --- a/cmd/crates/soroban-test/tests/it/integration_and_sandbox.rs +++ b/cmd/crates/soroban-test/tests/it/integration_and_sandbox.rs @@ -3,15 +3,9 @@ use soroban_test::TestEnv; use crate::util::{ add_test_seed, deploy_hello, is_rpc, network_passphrase_arg, rpc_url_arg, DEFAULT_PUB_KEY, - DEFAULT_SECRET_KEY, DEFAULT_SEED_PHRASE, HELLO_WORLD, TEST_CONTRACT_ID, + DEFAULT_SECRET_KEY, DEFAULT_SEED_PHRASE, HELLO_WORLD, }; -#[test] -fn install_wasm_then_deploy_contract() { - let sandbox = TestEnv::default(); - assert_eq!(deploy_hello(&sandbox), TEST_CONTRACT_ID); -} - #[test] fn invoke_hello_world_with_lib_two() { TestEnv::with_default(|e| { From 5380a706c274d53065dfba04dccb8033cba70116 Mon Sep 17 00:00:00 2001 From: Willem Wyndham Date: Fri, 22 Sep 2023 18:11:57 -0400 Subject: [PATCH 12/12] fix: add back hello_world --- .../soroban-test/tests/it/hello_world.rs | 493 ++++++++++++++++++ .../tests/it/integration_and_sandbox.rs | 7 +- 2 files changed, 498 insertions(+), 2 deletions(-) create mode 100644 cmd/crates/soroban-test/tests/it/hello_world.rs diff --git a/cmd/crates/soroban-test/tests/it/hello_world.rs b/cmd/crates/soroban-test/tests/it/hello_world.rs new file mode 100644 index 000000000..30ee8c907 --- /dev/null +++ b/cmd/crates/soroban-test/tests/it/hello_world.rs @@ -0,0 +1,493 @@ +use soroban_cli::commands::{ + config::identity, + contract::{self, fetch}, +}; +use soroban_test::TestEnv; +use std::path::PathBuf; + +use crate::util::{ + add_test_seed, is_rpc, network_passphrase, network_passphrase_arg, rpc_url, rpc_url_arg, + DEFAULT_PUB_KEY, DEFAULT_PUB_KEY_1, DEFAULT_SECRET_KEY, DEFAULT_SEED_PHRASE, HELLO_WORLD, + TEST_SALT, +}; + +#[test] +fn install_wasm_then_deploy_contract() { + let sandbox = TestEnv::default(); + assert_eq!(deploy_hello(&sandbox), TEST_CONTRACT_ID); +} + +const TEST_CONTRACT_ID: &str = "CBVTIVBYWAO2HNPNGKDCZW4OZYYESTKNGD7IPRTDGQSFJS4QBDQQJX3T"; + +fn deploy_hello(sandbox: &TestEnv) -> String { + let hash = HELLO_WORLD.hash().unwrap(); + sandbox + .new_assert_cmd("contract") + .arg("install") + .arg("--wasm") + .arg(HELLO_WORLD.path()) + .assert() + .success() + .stdout(format!("{hash}\n")); + + let mut cmd: &mut assert_cmd::Command = &mut sandbox.new_assert_cmd("contract"); + + cmd = cmd.arg("deploy").arg("--wasm-hash").arg(&format!("{hash}")); + if is_rpc() { + cmd = cmd.arg("--salt").arg(TEST_SALT); + } else { + cmd = cmd.arg("--id").arg(TEST_CONTRACT_ID); + } + cmd.assert() + .success() + .stdout(format!("{TEST_CONTRACT_ID}\n")); + TEST_CONTRACT_ID.to_string() +} + +#[test] +fn deploy_contract_with_wasm_file() { + if is_rpc() { + return; + } + TestEnv::default() + .new_assert_cmd("contract") + .arg("deploy") + .arg("--wasm") + .arg(HELLO_WORLD.path()) + .arg("--id=1") + .assert() + .success() + .stdout("CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM\n"); +} + +#[test] +fn invoke_hello_world_with_deploy_first() { + let sandbox = TestEnv::default(); + let id = deploy_hello(&sandbox); + println!("{id}"); + sandbox + .new_assert_cmd("contract") + .arg("invoke") + .arg("--id") + .arg(id) + .arg("--") + .arg("hello") + .arg("--world=world") + .assert() + .stdout("[\"Hello\",\"world\"]\n") + .success(); +} + +#[test] +fn invoke_hello_world() { + let sandbox = TestEnv::default(); + let id = deploy_hello(&sandbox); + sandbox + .new_assert_cmd("contract") + .arg("invoke") + .arg("--id") + .arg(id) + .arg("--wasm") + .arg(HELLO_WORLD.path()) + .arg("--") + .arg("hello") + .arg("--world=world") + .assert() + .stdout("[\"Hello\",\"world\"]\n") + .success(); +} + +#[test] +fn invoke_hello_world_from_file() { + let sandbox = TestEnv::default(); + let tmp_file = sandbox.temp_dir.join("world.txt"); + std::fs::write(&tmp_file, "world").unwrap(); + let id = deploy_hello(&sandbox); + sandbox + .new_assert_cmd("contract") + .arg("invoke") + .arg("--id") + .arg(id) + .arg("--wasm") + .arg(HELLO_WORLD.path()) + .arg("--") + .arg("hello") + .arg("--world-file-path") + .arg(&tmp_file) + .assert() + .stdout("[\"Hello\",\"world\"]\n") + .success(); +} + +#[test] +fn invoke_hello_world_from_file_fail() { + let sandbox = TestEnv::default(); + let tmp_file = sandbox.temp_dir.join("world.txt"); + std::fs::write(&tmp_file, "world").unwrap(); + let id = deploy_hello(&sandbox); + sandbox + .new_assert_cmd("contract") + .arg("invoke") + .arg("--id") + .arg(id) + .arg("--wasm") + .arg(HELLO_WORLD.path()) + .arg("--") + .arg("hello") + .arg("--world-file-path") + .arg(&tmp_file) + .arg("--world=hello") + .assert() + .stderr(predicates::str::contains("error: the argument '--world-file-path ' cannot be used with '--world '")) + .failure(); +} + +#[test] +fn invoke_hello_world_with_lib() { + TestEnv::with_default(|e| { + let id = deploy_hello(e); + let mut cmd = contract::invoke::Cmd { + contract_id: id, + slop: vec!["hello".into(), "--world=world".into()], + ..Default::default() + }; + + cmd.config.network.rpc_url = rpc_url(); + cmd.config.network.network_passphrase = network_passphrase(); + + let res = e.invoke_cmd(cmd).unwrap(); + assert_eq!(res, r#"["Hello","world"]"#); + }); +} + +#[test] +fn invoke_hello_world_with_lib_two() { + TestEnv::with_default(|e| { + let id = deploy_hello(e); + let hello_world = HELLO_WORLD.to_string(); + let mut invoke_args = vec!["--id", &id, "--wasm", hello_world.as_str()]; + let args = vec!["--", "hello", "--world=world"]; + let res = if let (Some(rpc), Some(network_passphrase)) = + (rpc_url_arg(), network_passphrase_arg()) + { + invoke_args.push(&rpc); + invoke_args.push(&network_passphrase); + e.invoke(&[invoke_args, args].concat()).unwrap() + } else { + e.invoke(&[invoke_args, args].concat()).unwrap() + }; + assert_eq!(res, r#"["Hello","world"]"#); + }); +} +// #[test] +// fn invoke_hello_world_with_lib_three() { +// let sandbox = TestEnv::default(); +// let builder = invoke::CmdBuilder::new().contract_id("1").wasm(HELLO_WORLD.path()).function("hello").slop(["--hello=world"]).build(); +// std::env::set_current_dir(sandbox.dir()).unwrap(); +// assert_eq!(res.run_in_sandbox().unwrap(), r#"["Hello","world"]"#); +// } + +#[test] +fn invoke_auth() { + let sandbox = TestEnv::default(); + let id = &deploy_hello(&sandbox); + sandbox + .new_assert_cmd("contract") + .arg("invoke") + .arg("--id") + .arg(id) + .arg("--wasm") + .arg(HELLO_WORLD.path()) + .arg("--") + .arg("auth") + .arg(&format!("--addr={DEFAULT_PUB_KEY}")) + .arg("--world=world") + .assert() + .stdout(format!("\"{DEFAULT_PUB_KEY}\"\n")) + .success(); + + // Invoke it again without providing the contract, to exercise the deployment + sandbox + .new_assert_cmd("contract") + .arg("invoke") + .arg("--id") + .arg(id) + .arg("--") + .arg("auth") + .arg(&format!("--addr={DEFAULT_PUB_KEY}")) + .arg("--world=world") + .assert() + .stdout(format!("\"{DEFAULT_PUB_KEY}\"\n")) + .success(); +} + +#[tokio::test] +async fn invoke_auth_with_identity() { + let sandbox = TestEnv::default(); + sandbox + .cmd::("test -d ") + .run() + .await + .unwrap(); + let id = deploy_hello(&sandbox); + sandbox + .new_assert_cmd("contract") + .arg("invoke") + .arg("--id") + .arg(id) + .arg("--wasm") + .arg(HELLO_WORLD.path()) + .arg("--") + .arg("auth") + .arg("--addr=test") + .arg("--world=world") + .assert() + .stdout(format!("\"{DEFAULT_PUB_KEY}\"\n")) + .success(); +} + +#[test] +fn invoke_auth_with_different_test_account() { + let sandbox = TestEnv::default(); + let id = deploy_hello(&sandbox); + sandbox + .new_assert_cmd("contract") + .arg("invoke") + .arg("--hd-path=1") + .arg("--id") + .arg(id) + .arg("--wasm") + .arg(HELLO_WORLD.path()) + .arg("--") + .arg("auth") + .arg(&format!("--addr={DEFAULT_PUB_KEY_1}")) + .arg("--world=world") + .assert() + .stdout(format!("\"{DEFAULT_PUB_KEY_1}\"\n")) + .success(); +} + +#[test] +fn contract_data_read_failure() { + let sandbox = TestEnv::default(); + let id = deploy_hello(&sandbox); + + sandbox + .new_assert_cmd("contract") + .arg("read") + .arg("--id") + .arg(id) + .arg("--key=COUNTER") + .arg("--durability=persistent") + .assert() + .failure() + .stderr( + "error: no matching contract data entries were found for the specified contract id\n", + ); +} + +#[test] +fn contract_data_read() { + let sandbox = TestEnv::default(); + let id = &deploy_hello(&sandbox); + + sandbox + .new_assert_cmd("contract") + .arg("invoke") + .arg("--id") + .arg(id) + .arg("--") + .arg("inc") + .assert() + .success(); + + sandbox + .new_assert_cmd("contract") + .arg("read") + .arg("--id") + .arg(id) + .arg("--key=COUNTER") + .arg("--durability=persistent") + .assert() + .success() + .stdout("COUNTER,1,4096\n"); + + sandbox + .new_assert_cmd("contract") + .arg("invoke") + .arg("--id") + .arg(id) + .arg("--") + .arg("inc") + .assert() + .success(); + + sandbox + .new_assert_cmd("contract") + .arg("read") + .arg("--id") + .arg(id) + .arg("--key=COUNTER") + .arg("--durability=persistent") + .assert() + .success() + .stdout("COUNTER,2,4096\n"); +} + +#[test] +fn invoke_auth_with_different_test_account_fail() { + let sandbox = TestEnv::default(); + let id = &deploy_hello(&sandbox); + let res = sandbox.invoke(&[ + "--hd-path=1", + "--id", + id, + "--wasm", + HELLO_WORLD.path().to_str().unwrap(), + &rpc_url_arg().unwrap_or_default(), + &network_passphrase_arg().unwrap_or_default(), + "--", + "auth", + &format!("--addr={DEFAULT_PUB_KEY}"), + "--world=world", + ]); + assert!(res.is_err()); + if let Err(e) = res { + assert!( + matches!(e, contract::invoke::Error::Host(_)), + "Expected host error got {e:?}" + ); + }; +} + +#[test] +fn invoke_hello_world_with_seed() { + let sandbox = TestEnv::default(); + let identity = add_test_seed(sandbox.dir()); + invoke_with_source(&sandbox, &identity); +} + +#[test] +fn invoke_with_seed() { + let sandbox = TestEnv::default(); + invoke_with_source(&sandbox, DEFAULT_SEED_PHRASE); +} + +#[test] +fn invoke_with_id() { + let sandbox = TestEnv::default(); + let identity = add_test_seed(sandbox.dir()); + invoke_with_source(&sandbox, &identity); +} + +#[test] +fn invoke_with_sk() { + let sandbox = TestEnv::default(); + invoke_with_source(&sandbox, DEFAULT_SECRET_KEY); +} + +fn invoke_with_source(sandbox: &TestEnv, source: &str) { + let id = &deploy_hello(sandbox); + let cmd = sandbox.invoke(&[ + "--source-account", + source, + "--id", + id, + "--wasm", + HELLO_WORLD.path().to_str().unwrap(), + &rpc_url_arg().unwrap_or_default(), + &network_passphrase_arg().unwrap_or_default(), + "--", + "hello", + "--world=world", + ]); + assert_eq!(cmd.unwrap(), "[\"Hello\",\"world\"]"); + + // Invoke it again without providing the contract, to exercise the deployment + let cmd = sandbox.invoke(&[ + "--source-account", + source, + "--id", + id, + "--", + "hello", + "--world=world", + ]); + assert_eq!(cmd.unwrap(), "[\"Hello\",\"world\"]"); +} + +#[test] +fn handles_kebab_case() { + let e = TestEnv::default(); + let id = deploy_hello(&e); + assert!(e + .invoke(&[ + "--id", + &id, + "--wasm", + HELLO_WORLD.path().to_str().unwrap(), + "--", + "multi-word-cmd", + "--contract-owner=world", + ]) + .is_ok()); +} + +#[tokio::test] +async fn fetch() { + if !is_rpc() { + return; + } + let e = TestEnv::default(); + let f = e.dir().join("contract.wasm"); + let id = deploy_hello(&e); + let cmd = e.cmd_arr::(&["--id", &id, "--out-file", f.to_str().unwrap()]); + cmd.run().await.unwrap(); + assert!(f.exists()); +} + +#[test] +fn build() { + let sandbox = TestEnv::default(); + + let cargo_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let hello_world_contract_path = + cargo_dir.join("tests/fixtures/test-wasms/hello_world/Cargo.toml"); + sandbox + .new_assert_cmd("contract") + .arg("build") + .arg("--manifest-path") + .arg(hello_world_contract_path) + .arg("--profile") + .arg("test-wasms") + .arg("--package") + .arg("test_hello_world") + .assert() + .success(); +} + +#[test] +fn invoke_prng_u64_in_range_test() { + let sandbox = TestEnv::default(); + let res = sandbox + .new_assert_cmd("contract") + .arg("deploy") + .arg("--wasm") + .arg(HELLO_WORLD.path()) + .assert() + .success(); + let stdout = String::from_utf8(res.get_output().stdout.clone()).unwrap(); + let id = stdout.trim_end(); + println!("{id}"); + sandbox + .new_assert_cmd("contract") + .arg("invoke") + .arg("--id") + .arg(id) + .arg("--") + .arg("prng_u64_in_range") + .arg("--low=0") + .arg("--high=100") + .assert() + .success(); +} diff --git a/cmd/crates/soroban-test/tests/it/integration_and_sandbox.rs b/cmd/crates/soroban-test/tests/it/integration_and_sandbox.rs index 15c6b5795..0beff5a78 100644 --- a/cmd/crates/soroban-test/tests/it/integration_and_sandbox.rs +++ b/cmd/crates/soroban-test/tests/it/integration_and_sandbox.rs @@ -96,6 +96,7 @@ fn contract_data_read_failure() { .arg("--id") .arg(id) .arg("--key=COUNTER") + .arg("--durability=persistent") .assert() .failure() .stderr( @@ -124,9 +125,10 @@ fn contract_data_read() { .arg("--id") .arg(id) .arg("--key=COUNTER") + .arg("--durability=persistent") .assert() .success() - .stdout("COUNTER,1\n"); + .stdout("COUNTER,1,4096\n"); sandbox .new_assert_cmd("contract") @@ -144,9 +146,10 @@ fn contract_data_read() { .arg("--id") .arg(id) .arg("--key=COUNTER") + .arg("--durability=persistent") .assert() .success() - .stdout("COUNTER,2\n"); + .stdout("COUNTER,2,4096\n"); } #[test]