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

chore(iota): Add shell tests #5256

Merged
merged 7 commits into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from 2 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
12 changes: 12 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions crates/iota/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ assert_cmd = "2.0.6"
expect-test.workspace = true
fs_extra.workspace = true
insta.workspace = true
insta-cmd = "0.6"
prometheus.workspace = true
serde_json.workspace = true
shlex = "1.3.0"
Expand All @@ -127,6 +128,10 @@ test = false
name = "ptb_files_tests"
harness = false

[[test]]
name = "shell_tests"
harness = false

[features]
gas-profiler = ["iota-types/gas-profiler", "iota-execution/gas-profiler"]
indexer = ["dep:diesel", "dep:iota-indexer", "dep:iota-graphql-rpc"]
Expand Down
90 changes: 0 additions & 90 deletions crates/iota/tests/cli_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,43 +418,6 @@ async fn test_ptb_publish() -> Result<(), anyhow::Error> {
Ok(())
}

// fixing issue https://github.com/iotaledger/iota/issues/6546
#[tokio::test]
async fn test_regression_6546() -> Result<(), anyhow::Error> {
let mut test_cluster = TestClusterBuilder::new().build().await;
let address = test_cluster.get_address_0();
let context = &mut test_cluster.wallet;

let IotaClientCommandResult::Objects(coins) = IotaClientCommands::Objects {
address: Some(KeyIdentity::Address(address)),
}
.execute(context)
.await?
else {
panic!()
};
let config_path = test_cluster.swarm.dir().join(IOTA_CLIENT_CONFIG);

test_with_iota_binary(&[
"client",
"--client.config",
config_path.to_str().unwrap(),
"call",
"--package",
"0x2",
"--module",
"iota",
"--function",
"transfer",
"--args",
&coins.first().unwrap().object()?.object_id.to_string(),
&test_cluster.get_address_1().to_string(),
"--gas-budget",
"100000000",
])
.await
}

#[sim_test]
async fn test_custom_genesis() -> Result<(), anyhow::Error> {
// Create and save genesis config file
Expand Down Expand Up @@ -3930,59 +3893,6 @@ async fn test_clever_errors() -> Result<(), anyhow::Error> {
Ok(())
}

#[tokio::test]
async fn test_move_build_bytecode_with_address_resolution() -> Result<(), anyhow::Error> {
let test_cluster = TestClusterBuilder::new().build().await;
let config_path = test_cluster.swarm.dir().join(IOTA_CLIENT_CONFIG);

// Package setup: a simple package depends on another and copied to tmpdir
let mut simple_package_path = PathBuf::from(TEST_DATA_DIR);
simple_package_path.push("simple");

let mut depends_on_simple_package_path = PathBuf::from(TEST_DATA_DIR);
depends_on_simple_package_path.push("depends_on_simple");

let tmp_dir = tempfile::tempdir().unwrap();

fs_extra::dir::copy(
&simple_package_path,
&tmp_dir,
&fs_extra::dir::CopyOptions::default(),
)?;

fs_extra::dir::copy(
&depends_on_simple_package_path,
&tmp_dir,
&fs_extra::dir::CopyOptions::default(),
)?;

// Publish simple package.
let simple_tmp_dir = tmp_dir.path().join("simple");
test_with_iota_binary(&[
"client",
"--client.config",
config_path.to_str().unwrap(),
"publish",
simple_tmp_dir.to_str().unwrap(),
])
.await?;

// Build the package that depends on 'simple' package. Addresses must resolve
// successfully from the `Move.lock` for this command to succeed at all.
let depends_on_simple_tmp_dir = tmp_dir.path().join("depends_on_simple");
test_with_iota_binary(&[
"move",
"--client.config",
config_path.to_str().unwrap(),
"build",
"--dump-bytecode-as-base64",
"--path",
depends_on_simple_tmp_dir.to_str().unwrap(),
])
.await?;
Ok(())
}

#[tokio::test]
async fn test_parse_host_port() {
let input = "127.0.0.0";
Expand Down
97 changes: 97 additions & 0 deletions crates/iota/tests/shell_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright (c) Mysten Labs, Inc.
// Modifications Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use std::{fs, path::Path, process::Command};

use fs_extra::dir::CopyOptions;
use insta_cmd::get_cargo_bin;
use iota_config::IOTA_CLIENT_CONFIG;
use test_cluster::TestClusterBuilder;

// [test_shell_snapshot] is run on every file matching [TEST_PATTERN] in
// [TEST_DIR]. Files in [TEST_NET_DIR] will be run with a [TestCluster]
// configured.
//
// These run the files as shell scripts and compares their output to the
// snapshots; use `cargo insta test --review` to update the snapshots.

const TEST_DIR: &str = "tests/shell_tests";
const TEST_NET_DIR: &str = "tests/shell_tests/with_network";
const TEST_PATTERN: &str = r"\.sh$";

/// run the bash script at [path], comparing its output to the insta snapshot of
/// the same name. The script is run in a temporary working directory that
/// contains a copy of the parent directory of [path], with the `iota` binary on
/// the path.
///
/// If [cluster] is provided, the config file for the cluster is passed as the
/// `CONFIG` environment variable.
#[tokio::main]
async fn test_shell_snapshot(path: &Path) -> datatest_stable::Result<()> {
// set up test cluster
let cluster = if path.starts_with(TEST_NET_DIR) {
Some(TestClusterBuilder::new().build().await)
} else {
None
};

// copy files into temporary directory
let srcdir = path.parent().unwrap();
let tmpdir = tempfile::tempdir()?;
let sandbox = tmpdir.path();

fs_extra::dir::copy(srcdir, sandbox, &CopyOptions::new().content_only(true))?;

// set up command
let mut shell = Command::new("bash");
shell
.env(
"PATH",
format!("{}:{}", get_iota_bin_path(), std::env::var("PATH")?),
)
.current_dir(sandbox)
.arg(path.file_name().unwrap());

if let Some(ref cluster) = cluster {
shell.env("CONFIG", cluster.swarm.dir().join(IOTA_CLIENT_CONFIG));
}

// run it; snapshot test output
let output = shell.output()?;
let result = format!(
"----- script -----\n{}\n----- results -----\nsuccess: {:?}\nexit_code: {}\n----- stdout -----\n{}\n----- stderr -----\n{}",
fs::read_to_string(path)?,
output.status.success(),
output.status.code().unwrap_or(!0),
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);

let snapshot_name: String = path
.strip_prefix("tests/shell_tests")?
.to_string_lossy()
.to_string();

insta::with_settings!({description => path.to_string_lossy(), omit_expression => true}, {
insta::assert_snapshot!(snapshot_name, result);
});

Ok(())
}

/// return the path to the `iota` binary that is currently under test
fn get_iota_bin_path() -> String {
get_cargo_bin("iota")
.parent()
.unwrap()
.to_str()
.expect("directory name is valid UTF-8")
.to_owned()
}

#[cfg(not(msim))]
datatest_stable::harness!(test_shell_snapshot, TEST_DIR, TEST_PATTERN);

#[cfg(msim)]
fn main() {}
9 changes: 9 additions & 0 deletions crates/iota/tests/shell_tests/new_tests/gitignore_exists.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Copyright (c) Mysten Labs, Inc.
# Modifications Copyright (c) 2024 IOTA Stiftung
# SPDX-License-Identifier: Apache-2.0

# check that iota move new correctly updates existing .gitignore
mkdir example
echo "existing_ignore" >> example/.gitignore
iota move new example
cat example/.gitignore
14 changes: 14 additions & 0 deletions crates/iota/tests/shell_tests/new_tests/gitignore_has_build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Copyright (c) Mysten Labs, Inc.
# Modifications Copyright (c) 2024 IOTA Stiftung
# SPDX-License-Identifier: Apache-2.0

# iota move new example when `example/.gitignore` already contains build/*; it should be unchanged
mkdir example
echo "ignore1" >> example/.gitignore
echo "build/*" >> example/.gitignore
echo "ignore2" >> example/.gitignore
iota move new example
cat example/.gitignore
echo
echo ==== files in example/ ====
ls -A example
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Copyright (c) Mysten Labs, Inc.
# Modifications Copyright (c) 2024 IOTA Stiftung
# SPDX-License-Identifier: Apache-2.0

iota move new example
cat example/Move.toml
12 changes: 12 additions & 0 deletions crates/iota/tests/shell_tests/new_tests/new_files.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright (c) Mysten Labs, Inc.
# Modifications Copyright (c) 2024 IOTA Stiftung
# SPDX-License-Identifier: Apache-2.0

# basic test that iota move new outputs correct files
iota move new example
echo ==== files in project ====
ls -A example
echo ==== files in sources ====
ls -A example/sources
echo ==== files in tests =====
ls -A example/tests
19 changes: 19 additions & 0 deletions crates/iota/tests/shell_tests/new_tests/new_then_build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright (c) Mysten Labs, Inc.
# Modifications Copyright (c) 2024 IOTA Stiftung
# SPDX-License-Identifier: Apache-2.0

# tests that iota move new followed by iota move build succeeds

iota move new example

# we mangle the generated toml file to replace the framework dependency with a local dependency
FRAMEWORK_DIR=$(echo $CARGO_MANIFEST_DIR | sed 's#/crates/iota##g')
cat example/Move.toml \
| sed 's#\(Iota = .*\)git = "[^"]*", \(.*\)#\1\2#' \
| sed 's#\(Iota = .*\), rev = "[^"]*"\(.*\)#\1\2#' \
| sed 's#\(Iota = .*\)subdir = "\([^"]*\)"\(.*\)#\1local = "FRAMEWORK/\2"\3#' \
| sed "s#\(Iota = .*\)FRAMEWORK\(.*\)#\1$FRAMEWORK_DIR\2#" \
> Move.toml
mv Move.toml example/Move.toml

cd example && iota move build
18 changes: 18 additions & 0 deletions crates/iota/tests/shell_tests/new_tests/new_then_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright (c) Mysten Labs, Inc.
# Modifications Copyright (c) 2024 IOTA Stiftung
# SPDX-License-Identifier: Apache-2.0

# check that iota move new followed by iota move test succeeds
iota move new example

# we mangle the generated toml file to replace the framework dependency with a local dependency
FRAMEWORK_DIR=$(echo $CARGO_MANIFEST_DIR | sed 's#/crates/iota##g')
cat example/Move.toml \
| sed 's#\(Iota = .*\)git = "[^"]*", \(.*\)#\1\2#' \
| sed 's#\(Iota = .*\), rev = "[^"]*"\(.*\)#\1\2#' \
| sed 's#\(Iota = .*\)subdir = "\([^"]*\)"\(.*\)#\1local = "FRAMEWORK/\2"\3#' \
| sed "s#\(Iota = .*\)FRAMEWORK\(.*\)#\1$FRAMEWORK_DIR\2#" \
> Move.toml
mv Move.toml example/Move.toml

cd example && iota move test
1 change: 1 addition & 0 deletions crates/iota/tests/shell_tests/simple/data/data.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
some unimportant data
8 changes: 8 additions & 0 deletions crates/iota/tests/shell_tests/simple/simple.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Copyright (c) Mysten Labs, Inc.
# Modifications Copyright (c) 2024 IOTA Stiftung
# SPDX-License-Identifier: Apache-2.0

# simple test just to make sure the test runner works
echo "simple test"
cat data/data.txt
iota move new simple_test
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "depends_on_simple"
edition = "2024.beta"

[dependencies]
simple = { local = "../simple" }

[addresses]
depends_on_simple = "0x0"
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright (c) Mysten Labs, Inc.
// Modifications Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

module depends_on_simple::depends_on_simple {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright (c) Mysten Labs, Inc.
# Modifications Copyright (c) 2024 IOTA Stiftung
# SPDX-License-Identifier: Apache-2.0

iota client --client.config $CONFIG \
publish simple \
--json | jq '.effects.status'

iota move --client.config $CONFIG \
build --path depends_on_simple
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "simple"
edition = "2024.beta"

[dependencies]

[addresses]
simple = "0x0"
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright (c) Mysten Labs, Inc.
// Modifications Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

module simple::simple {}
6 changes: 6 additions & 0 deletions crates/iota/tests/shell_tests/with_network/objects.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Copyright (c) Mysten Labs, Inc.
# Modifications Copyright (c) 2024 IOTA Stiftung
# SPDX-License-Identifier: Apache-2.0

# simple test just to make sure the test runner works with the network
iota client --client.config $CONFIG objects --json | jq 'length'
Loading
Loading