Skip to content

Commit

Permalink
refactor(blueprint-test-utils)!: remove Opts boilerplate
Browse files Browse the repository at this point in the history
  • Loading branch information
Serial-ATA committed Dec 6, 2024
1 parent 57fe0e9 commit e87eee1
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 119 deletions.
18 changes: 1 addition & 17 deletions Cargo.lock

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

18 changes: 2 additions & 16 deletions blueprint-test-utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,23 +363,9 @@ pub fn inject_random_key<P: AsRef<Path>>(keystore_path: P) -> color_eyre::Result
Ok(())
}

/// Returns the output of "git rev-parse --show-toplevel" to get the root of the git repository as a PathBuf.
/// If it's not in a git repo, default to return the current directory
pub fn get_blueprint_base_dir() -> PathBuf {
let output = std::process::Command::new("git")
.arg("rev-parse")
.arg("--show-toplevel")
.output()
.expect("Failed to run git command");

if output.status.success() {
let path = std::str::from_utf8(&output.stdout)
.expect("Failed to convert output to string")
.trim();
PathBuf::from(path)
} else {
std::env::current_dir().expect("Failed to get current directory")
}
// TODO: Walk up to find the closest manifest. This only work if `cargo test` is run from the project root.
std::env::current_dir().expect("Failed to get current directory")
}

pub fn read_cargo_toml_file<P: AsRef<Path>>(path: P) -> std::io::Result<Manifest> {
Expand Down
82 changes: 15 additions & 67 deletions blueprint-test-utils/src/tangle/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ pub fn run() -> Result<SubstrateNode, Error> {
let tangle_from_env = std::env::var(TANGLE_NODE_ENV).unwrap_or_else(|_| "tangle".to_string());
let builder = SubstrateNode::builder()
.binary_paths([
&tangle_from_env,
"../tangle/target/release/tangle",
"../../tangle/target/release/tangle",
&tangle_from_env,
])
.arg("validator")
.arg_val("rpc-cors", "all")
Expand All @@ -26,55 +26,21 @@ pub fn run() -> Result<SubstrateNode, Error> {
/// A template that makes creating domain-specific macros for tangle-based blueprints easier
macro_rules! tangle_blueprint_test_template {
(
$blueprint_path:expr,
$N:tt,
$test_logic:expr,
) => {
pub use $crate::{
run_test_blueprint_manager,
Opts, setup_log,
tangle, get_blueprint_base_dir, read_cargo_toml_file,
submit_job, wait_for_completion_of_tangle_job, Job, Args,
};

use $crate::test_ext::new_test_ext_blueprint_manager;

#[tokio::test(flavor = "multi_thread")]
#[::gadget_sdk::tokio::test(flavor = "multi_thread", crate = "::gadget_sdk::tokio")]
async fn test_blueprint() {
setup_log();
let tangle_node = tangle::run().expect("Failed to start tangle node");
let mut base_path = get_blueprint_base_dir();
::blueprint_test_utils::setup_log();

let tmp_dir = $crate::tempfile::TempDir::new().unwrap();
let tmp_dir_path = format!("{}", tmp_dir.path().display());

base_path.push($blueprint_path);
base_path
.canonicalize()
.expect("File could not be found/normalized");

let manifest_path = base_path.join("Cargo.toml");
log::info!(target: "gadget", "Manifest path: {manifest_path:?}");
let manifest = read_cargo_toml_file(&manifest_path).expect("Failed to read blueprint's Cargo.toml");
let blueprint_name = manifest.package.as_ref().unwrap().name.clone();

let ws_port = tangle_node.ws_port();
let http_rpc_url = format!("http://127.0.0.1:{ws_port}");
let ws_rpc_url = format!("ws://127.0.0.1:{ws_port}");

let opts = Opts {
pkg_name: Some(blueprint_name),
http_rpc_url,
ws_rpc_url,
manifest_path,
signer: None,
signer_evm: None,
};

new_test_ext_blueprint_manager::<$N, 1, String, _, _>(
let tmp_dir_path = tmp_dir.path().to_string_lossy().into_owned();

::blueprint_test_utils::test_ext::new_test_ext_blueprint_manager::<$N, 1, String, _, _>(
tmp_dir_path,
opts,
run_test_blueprint_manager,
::blueprint_test_utils::run_test_blueprint_manager,
)
.await
.execute_with_async($test_logic)
Expand All @@ -86,44 +52,42 @@ macro_rules! tangle_blueprint_test_template {
#[macro_export]
macro_rules! test_tangle_blueprint {
(
$blueprint_path:expr,
$N:tt,
$T:tt,
$job_id:tt,
[$($inputs:expr),*],
[$($expected_output:expr),*]
) => {
tangle_blueprint_test_template!(
$blueprint_path,
::blueprint_test_utils::tangle_blueprint_test_template!(
$N,
|client, handles, blueprint| async move {
let keypair = handles[0].sr25519_id().clone();
let selected_service = &blueprint.services[0];
let service_id = selected_service.id;

gadget_sdk::info!(
::gadget_sdk::info!(
"Submitting job {} with service ID {service_id}", $job_id
);

let job_args = vec![$($inputs),*];

let job = submit_job(
let job = ::blueprint_test_utils::submit_job(
client,
&keypair,
service_id,
Job::from(0),
$job_id as ::blueprint_test_utils::Job,
job_args,
)
.await
.expect("Failed to submit job");

let call_id = job.call_id;

gadget_sdk::info!(
::gadget_sdk::info!(
"Submitted job {} with service ID {service_id} has call id {call_id}", $job_id
);

let job_results = wait_for_completion_of_tangle_job(client, service_id, call_id, $T)
let job_results = ::blueprint_test_utils::wait_for_completion_of_tangle_job(client, service_id, call_id, $T)
.await
.expect("Failed to wait for job completion");

Expand All @@ -132,7 +96,7 @@ macro_rules! test_tangle_blueprint {

let expected_outputs = vec![$($expected_output),*];
if expected_outputs.is_empty() {
gadget_sdk::info!("No expected outputs specified, skipping verification");
::gadget_sdk::info!("No expected outputs specified, skipping verification");
return
}

Expand All @@ -145,27 +109,11 @@ macro_rules! test_tangle_blueprint {
);
};
(
$blueprint_path:expr,
$N:tt,
$job_id:tt,
[$($input:expr),*],
[$($expected_output:expr),*]
) => {
test_tangle_blueprint!($blueprint_path, $N, $N, $job_id, [$($input),+], [$($expected_output),+]);
::blueprint_test_utils::test_tangle_blueprint!($N, $N, $job_id, [$($input),+], [$($expected_output),+]);
};
}

#[cfg(test)]
mod test_incredible_squaring {
use crate::{InputValue, OutputValue};

const KEYGEN_JOB_ID: usize = 0;
const N: usize = 5;
test_tangle_blueprint!(
"./blueprints/incredible-squaring/", // Path to the blueprint's dir relative to the git repo root, or, if not in a git repo, the current working directory
N, // Number of nodes
KEYGEN_JOB_ID, // Job ID
[InputValue::Uint64(5)], // Inputs
[OutputValue::Uint64(25)] // Expected output: input squared
);
}
32 changes: 30 additions & 2 deletions blueprint-test-utils/src/test_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Tangle. If not, see <http://www.gnu.org/licenses/>.

use crate::PerTestNodeInput;
use crate::{get_blueprint_base_dir, read_cargo_toml_file, PerTestNodeInput};
use alloy_primitives::hex;
use futures::StreamExt;
use blueprint_manager::executor::BlueprintManagerHandle;
Expand All @@ -41,6 +41,7 @@ use gadget_sdk::{error, info, warn};
use gadget_sdk::clients::tangle::services::{RpcServicesWithBlueprint, ServicesClient};
use gadget_sdk::subxt_core::config::Header;
use gadget_sdk::utils::test_utils::get_client;
use crate::tangle::node::SubstrateNode;
use crate::tangle::transactions;

const LOCAL_BIND_ADDR: &str = "127.0.0.1";
Expand All @@ -60,7 +61,6 @@ pub async fn new_test_ext_blueprint_manager<
Fut: SendFuture<'static, BlueprintManagerHandle>,
>(
additional_params: D,
mut opts: Opts,
f: F,
) -> LocalhostTestExt {
assert!(N > 0, "At least one node is required");
Expand All @@ -69,6 +69,31 @@ pub async fn new_test_ext_blueprint_manager<
let span = tracing::info_span!("Integration-Test");
let _span = span.enter();

let base_path = get_blueprint_base_dir();
let base_path = base_path
.canonicalize()
.expect("File could not be normalized");

let manifest_path = base_path.join("Cargo.toml");
tracing::debug!("Manifest path: {}", manifest_path.display());

let manifest =
read_cargo_toml_file(&manifest_path).expect("Failed to read blueprint's Cargo.toml");
let blueprint_name = manifest.package.as_ref().unwrap().name.clone();

tracing::info!("Starting Tangle node...");
let tangle_node = crate::tangle::run().unwrap();
tracing::info!("Tangle node running on port: {}", tangle_node.ws_port());

let mut opts = Opts {
pkg_name: Some(blueprint_name),
http_rpc_url: format!("http://127.0.0.1:{}", tangle_node.ws_port()),
ws_rpc_url: format!("ws://127.0.0.1:{}", tangle_node.ws_port()),
manifest_path,
signer: None,
signer_evm: None,
};

let bind_addrs = (0..N)
.map(|_| find_open_tcp_bind_port())
.map(|port| {
Expand Down Expand Up @@ -323,6 +348,7 @@ pub async fn new_test_ext_blueprint_manager<
drop(_span);

LocalhostTestExt {
_tangle_node: tangle_node,
client,
handles,
span,
Expand All @@ -342,6 +368,8 @@ pub fn find_open_tcp_bind_port() -> u16 {
}

pub struct LocalhostTestExt {
// Unused, stored here to keep it from dropping early
_tangle_node: SubstrateNode,
client: TangleClient,
handles: Vec<BlueprintManagerHandle>,
span: tracing::Span,
Expand Down
20 changes: 3 additions & 17 deletions blueprints/incredible-squaring/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,15 @@ repository.workspace = true
publish = false

[dependencies]
eigensdk = { workspace = true }
tracing = { workspace = true }
async-trait = { workspace = true }
gadget-sdk = { workspace = true, features = ["std"] }
color-eyre = { workspace = true }
lock_api = { workspace = true }
tokio = { workspace = true, default-features = false, features = ["full"] }
tokio-util = { workspace = true }
sp-core = { workspace = true }
subxt-signer = { workspace = true, features = ["sr25519", "subxt", "std"] }
ark-bn254 = { workspace = true }
ark-ff = { workspace = true }
ark-ec = { workspace = true }
parking_lot = { workspace = true }
libp2p = { workspace = true }
ed25519-zebra = { workspace = true, features = ["pkcs8", "default", "der", "std", "serde", "pem"] }
hex = { workspace = true }
k256 = { workspace = true }
serde_json = { workspace = true }

[build-dependencies]
blueprint-metadata = { workspace = true }

[dev-dependencies]
blueprint-test-utils.workspace = true

[features]
default = ["std"]
std = []
Expand Down
11 changes: 11 additions & 0 deletions blueprints/incredible-squaring/tests/e2e.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use blueprint_test_utils::{test_tangle_blueprint, InputValue, OutputValue};

const SQUARING_JOB_ID: usize = 0;
const N: usize = 5;

test_tangle_blueprint!(
N, // Number of nodes
SQUARING_JOB_ID, // Job ID
[InputValue::Uint64(5)], // Inputs
[OutputValue::Uint64(25)] // Expected output: input squared
);

0 comments on commit e87eee1

Please sign in to comment.