Skip to content
This repository has been archived by the owner on Jan 11, 2024. It is now read-only.

Integration tests #143

Merged
merged 16 commits into from
Apr 3, 2023
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ build:
cargo build -Z unstable-options --release --out-dir ./bin

test:
cargo test --release --workspace
cargo test --release --workspace --lib # only run unit tests
Copy link
Contributor

Choose a reason for hiding this comment

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

The problem with this is that it will prevent all integration tests from running, for example it will stop the ipld/resolver/tests/smoke.rs as well, which does not rely on a cluster to be set up.

Looking at the ref-fvm CI workflow, they use cargo test --exclude to prevent multiple tests from running. This only works on the crate level I think, which is why the integration tests are in a separate create within the workspace.

Other options would be to put these tests behind a feature flag and only switch them on when you want to run the end to end tests.

Copy link
Contributor

Choose a reason for hiding this comment

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

All of them work for me, at this point I would suggest doing whatever is easier and less cumbersome for users while keeping the door open to eventually integrating it on CI.

Copy link
Contributor

Choose a reason for hiding this comment

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

They might work locally, but not on CI with make test. Compare the first passing commit to the last commit:

The first runs the smoke test:

     Running unittests src/lib.rs (target/release/deps/ipc_ipld_resolver-e87f2ddc0fd49dee)

running 9 tests
test hash::tests::vector_hashing ... ok
test behaviour::content::tests::non_ephemeral_addr ... ok
test limiter::tests::basics ... ok
test provider_cache::tests::prop_providers_pruned ... ok
test provider_cache::tests::prop_providers_listed ... ok
test provider_cache::tests::prop_subnets_pinned ... ok
test provider_cache::tests::prop_subnets_pruned ... ok
test provider_record::tests::prop_tamper_proof ... ok
test provider_record::tests::prop_roundtrip ... ok

test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.12s

     Running tests/smoke.rs (target/release/deps/smoke-20edbb0b97145a65)

running 1 test
test single_bootstrap_single_provider_resolve_one ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.03s

The second only runs the top section, not the bottom one.

IMO we should not let CI fall back on running the tests that it can run in the name of convenience of just not having to organise code better.

OTOH maybe it would be better to move the resolver into its own repository, since it doesn't rely on the IPC agent library at all, IIRC.

Copy link
Contributor

Choose a reason for hiding this comment

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

Here's a PR to move it; I don't think it's any less convenient: #153


clean:
cargo clean
Expand Down
31 changes: 20 additions & 11 deletions src/cli/commands/manager/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,13 @@ use crate::jsonrpc::{JsonRpcClient, JsonRpcClientImpl};
use crate::server::create::{CreateSubnetParams, CreateSubnetResponse};

/// The command to create a new subnet actor.
pub(crate) struct CreateSubnet;

#[async_trait]
impl CommandLineHandler for CreateSubnet {
type Arguments = CreateSubnetArgs;

async fn handle(global: &GlobalArguments, arguments: &Self::Arguments) -> anyhow::Result<()> {
log::debug!("create subnet with args: {:?}", arguments);
pub struct CreateSubnet;

impl CreateSubnet {
pub async fn create(
global: &GlobalArguments,
arguments: &CreateSubnetArgs,
) -> anyhow::Result<String> {
let url = get_ipc_agent_url(&arguments.ipc_agent_url, global)?;
let json_rpc_client = JsonRpcClientImpl::new(url, None);

Expand All @@ -36,13 +34,24 @@ impl CommandLineHandler for CreateSubnet {
check_period: arguments.check_period,
};

let address = json_rpc_client
Ok(json_rpc_client
.request::<CreateSubnetResponse>(
json_rpc_methods::CREATE_SUBNET,
serde_json::to_value(params)?,
)
.await?
.address;
.address)
}
}

#[async_trait]
impl CommandLineHandler for CreateSubnet {
type Arguments = CreateSubnetArgs;

async fn handle(global: &GlobalArguments, arguments: &Self::Arguments) -> anyhow::Result<()> {
log::debug!("create subnet with args: {:?}", arguments);

let address = CreateSubnet::create(global, arguments).await?;

log::info!(
"created subnet actor with id: {}/{}",
Expand All @@ -56,7 +65,7 @@ impl CommandLineHandler for CreateSubnet {

#[derive(Debug, Args)]
#[command(about = "Create a new subnet actor")]
pub(crate) struct CreateSubnetArgs {
pub struct CreateSubnetArgs {
#[arg(long, short, help = "The JSON RPC server url for ipc agent")]
pub ipc_agent_url: Option<String>,
#[arg(long, short, help = "The address that creates the subnet")]
Expand Down
4 changes: 2 additions & 2 deletions src/cli/commands/manager/join.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::jsonrpc::{JsonRpcClient, JsonRpcClientImpl};
use crate::server::join::JoinSubnetParams;

/// The command to join a subnet
pub(crate) struct JoinSubnet;
pub struct JoinSubnet;

#[async_trait]
impl CommandLineHandler for JoinSubnet {
Expand Down Expand Up @@ -46,7 +46,7 @@ impl CommandLineHandler for JoinSubnet {

#[derive(Debug, Args)]
#[command(about = "Join a subnet")]
pub(crate) struct JoinSubnetArgs {
pub struct JoinSubnetArgs {
#[arg(long, short, help = "The JSON RPC server url for ipc agent")]
pub ipc_agent_url: Option<String>,
#[arg(long, short, help = "The address that joins the subnet")]
Expand Down
4 changes: 2 additions & 2 deletions src/cli/commands/manager/kill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::jsonrpc::{JsonRpcClient, JsonRpcClientImpl};
use crate::server::kill::KillSubnetParams;

/// The command to kill an existing subnet.
pub(crate) struct KillSubnet;
pub struct KillSubnet;

#[async_trait]
impl CommandLineHandler for KillSubnet {
Expand Down Expand Up @@ -42,7 +42,7 @@ impl CommandLineHandler for KillSubnet {

#[derive(Debug, Args)]
#[command(about = "Kill an existing subnet")]
pub(crate) struct KillSubnetArgs {
pub struct KillSubnetArgs {
#[arg(long, short, help = "The JSON RPC server url for ipc agent")]
pub ipc_agent_url: Option<String>,
#[arg(long, short, help = "The address that kills the subnet")]
Expand Down
4 changes: 2 additions & 2 deletions src/cli/commands/manager/leave.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::jsonrpc::{JsonRpcClient, JsonRpcClientImpl};
use crate::server::leave::LeaveSubnetParams;

/// The command to leave a new subnet.
pub(crate) struct LeaveSubnet;
pub struct LeaveSubnet;

#[async_trait]
impl CommandLineHandler for LeaveSubnet {
Expand Down Expand Up @@ -45,7 +45,7 @@ impl CommandLineHandler for LeaveSubnet {

#[derive(Debug, Args)]
#[command(about = "Leaving a subnet")]
pub(crate) struct LeaveSubnetArgs {
pub struct LeaveSubnetArgs {
#[arg(long, short, help = "The JSON RPC server url for ipc agent")]
pub ipc_agent_url: Option<String>,
#[arg(long, short, help = "The address that leaves the subnet")]
Expand Down
8 changes: 4 additions & 4 deletions src/cli/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ mod manager;

use crate::cli::commands::config::{InitConfig, InitConfigArgs, ReloadConfig, ReloadConfigArgs};
use crate::cli::commands::daemon::{LaunchDaemon, LaunchDaemonArgs};
use crate::cli::commands::manager::create::{CreateSubnet, CreateSubnetArgs};
pub use crate::cli::commands::manager::create::{CreateSubnet, CreateSubnetArgs};
use crate::cli::commands::manager::fund::{Fund, FundArgs};
use crate::cli::commands::manager::join::{JoinSubnet, JoinSubnetArgs};
use crate::cli::commands::manager::kill::{KillSubnet, KillSubnetArgs};
use crate::cli::commands::manager::leave::{LeaveSubnet, LeaveSubnetArgs};
pub use crate::cli::commands::manager::join::{JoinSubnet, JoinSubnetArgs};
pub use crate::cli::commands::manager::kill::{KillSubnet, KillSubnetArgs};
pub use crate::cli::commands::manager::leave::{LeaveSubnet, LeaveSubnetArgs};
use crate::cli::commands::manager::list_checkpoints::{ListCheckpoints, ListCheckpointsArgs};
use crate::cli::commands::manager::list_subnets::{ListSubnets, ListSubnetsArgs};
use crate::cli::commands::manager::net_addr::{SetValidatorNetAddr, SetValidatorNetAddrArgs};
Expand Down
4 changes: 2 additions & 2 deletions src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use clap::Args;
mod commands;

use crate::config::Config;
pub use commands::cli;
pub use commands::*;

const DEFAULT_CONFIG_PATH: &str = ".ipc-agent/config.toml";

Expand All @@ -30,7 +30,7 @@ pub trait CommandLineHandler {
}

/// The global arguments that will be shared by all cli commands.
#[derive(Debug, Args, Clone)]
#[derive(Debug, Args, Clone, Default)]
pub struct GlobalArguments {
#[arg(
short,
Expand Down
11 changes: 11 additions & 0 deletions tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Integration tests
This directory includes a set of tools to perform end-to-end integration tests between the agent and the underlying subnet infrastructure.Before running the test cases, one needs to launch a `lotus` cluster and a `ipc-agent` daemon using the instructions shared in the project's [README](../README).
Once the infrastructure has been setup, the integration tests can be run using:
```shell
cargo test --test <TESTCASE_NAME>

# To run the subnet lifecycle test, perform:
cargo test --test subnet_lifecycle
```

> Note: This is a basic skeleton to showcase how we can run automated end-to-end tests over IPC. In the future, the goal is to automate the deployment of the IPC agent and the infrastructure so all tests can be run automatically.
78 changes: 78 additions & 0 deletions tests/common/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright 2022-2023 Protocol Labs
// SPDX-License-Identifier: MIT
use fvm_shared::address::Address;
use ipc_agent::cli::{
CommandLineHandler, CreateSubnet, CreateSubnetArgs, GlobalArguments, JoinSubnet,
JoinSubnetArgs, KillSubnet, KillSubnetArgs, LeaveSubnet, LeaveSubnetArgs,
};
use ipc_sdk::subnet_id::SubnetID;
use std::str::FromStr;

pub struct TestClient {
json_rpc_url: Option<String>,
}

impl TestClient {
pub fn new(json_rpc_url: Option<String>) -> Self {
Self { json_rpc_url }
}

pub async fn create_subnet(&self, parent: &str) -> anyhow::Result<Address> {
let global = GlobalArguments::default();
let args = CreateSubnetArgs {
ipc_agent_url: self.json_rpc_url.clone(),
from: None,
parent: String::from(parent),
name: "test".to_string(),
min_validator_stake: 1,
min_validators: 0,
finality_threshold: 2,
check_period: 10,
};

let raw = CreateSubnet::create(&global, &args).await?;
Ok(Address::from_str(&raw)?)
}

pub async fn join_subnet(
&self,
subnet_id: &SubnetID,
validator_net_addr: String,
) -> anyhow::Result<()> {
JoinSubnet::handle(
&GlobalArguments::default(),
&JoinSubnetArgs {
ipc_agent_url: self.json_rpc_url.clone(),
from: None,
subnet: subnet_id.to_string(),
collateral: 10,
validator_net_addr,
},
)
.await
}

pub async fn kill_subnet(&self, subnet_id: &SubnetID) -> anyhow::Result<()> {
KillSubnet::handle(
&GlobalArguments::default(),
&KillSubnetArgs {
ipc_agent_url: self.json_rpc_url.clone(),
from: None,
subnet: subnet_id.to_string(),
},
)
.await
}

pub async fn leave_subnet(&self, subnet_id: &SubnetID) -> anyhow::Result<()> {
LeaveSubnet::handle(
&GlobalArguments::default(),
&LeaveSubnetArgs {
ipc_agent_url: self.json_rpc_url.clone(),
from: None,
subnet: subnet_id.to_string(),
},
)
.await
}
}
55 changes: 55 additions & 0 deletions tests/subnet_lifecycle.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright 2022-2023 Protocol Labs
// SPDX-License-Identifier: MIT

use crate::common::TestClient;
use ipc_sdk::subnet_id::{SubnetID, ROOTNET_ID};

mod common;

const IPC_AGENT_JSON_RPC_URL_ENV: &str = "IPC_AGENT_JSON_RPC_URL";

#[tokio::test]
async fn subnet_lifecycle() {
let client = TestClient::new(std::env::var(IPC_AGENT_JSON_RPC_URL_ENV).ok());

// step 1. create the subnet
let address = client
.create_subnet("/root")
.await
.expect("create subnet in root failed");

// obtain the created subnet id
let subnet_id = SubnetID::new_from_parent(&ROOTNET_ID, address);
log::info!("created subnet: {:} in root", subnet_id);

// step 2. join the subnet
client
.join_subnet(&subnet_id, String::from("test_validator"))
.await
.expect("cannot join subnet");
log::info!("joined subnet: {:}", subnet_id);

// step 3. try kill the subnet, fail because not all validators have left
let r = client.kill_subnet(&subnet_id).await;
assert!(
r.is_err(),
"should failed when killing subnet as not all validators have left"
);
log::info!(
"expected cannot kill subnet: {:} when there are validators in subnet",
subnet_id
);

// step 4. leave the subnet
client
.leave_subnet(&subnet_id)
.await
.expect("cannot leave subnet");
log::info!("left subnet: {:}", subnet_id);

// step 5. kill the subnet works now as all validators have left
client
.kill_subnet(&subnet_id)
.await
.expect("cannot kill subnet");
}