Skip to content

Commit

Permalink
Introduce end-to-end testing crate (#1557)
Browse files Browse the repository at this point in the history
  • Loading branch information
agryaznov authored Feb 18, 2025
1 parent d432500 commit d10c12b
Show file tree
Hide file tree
Showing 16 changed files with 288 additions and 19 deletions.
1 change: 1 addition & 0 deletions .github/workflows/pr-test-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
if: false
test-basic:
runs-on: [self-hosted, integration]
timeout-minutes: 90
Expand Down
14 changes: 14 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ members = [
"tc-subxt/metadata",
"tss",
"utils/generate-bags",
"e2e-tests",
]
default-members = [
"chronicle",
Expand All @@ -59,6 +60,7 @@ serde_json = { version = "1.0.117", default-features = false }
simple-mermaid = "0.1"
tokio = "1.38.0"
tracing = "0.1.40"
tracing-subscriber = "0.3.19"

# substrate support libs
scale-codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive" ] }
Expand Down
2 changes: 1 addition & 1 deletion chronicle/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ schnorr-evm = { version = "0.1.0" }
sha3 = { version = "0.10" }
tide = { version = "0.16.0", default-features = false, features = ["h1-server"] }
tracing-panic = "0.1.1"
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
tracing-subscriber = { workspace = true, features = ["env-filter"] }

[dev-dependencies]
ed25519-dalek = "2.1.1"
Expand Down
48 changes: 48 additions & 0 deletions config/envs/local/local-evm-e2e.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
config:
chronicle_funds: 10.
timechain_url: 'ws://localhost:9944'
prices_path: 'prices.csv'
contracts:
evm:
additional_params: "factory/additional_config.json"
proxy: "contracts/GatewayProxy.sol/GatewayProxy.json"
gateway: "contracts/Gateway.sol/Gateway.json"
tester: "contracts/GmpProxy.sol/GmpProxy.json"
networks:
2:
backend: "evm"
blockchain: "anvil"
network: "dev"
url: "ws://localhost:8545"
admin_funds: 100.
gateway_funds: 1.
chronicle_funds: 1.
batch_size: 64
batch_offset: 0
batch_gas_limit: 10000000
gmp_margin: 0.0
shard_task_limit: 50
route_gas_limit: 10000000
route_base_fee: 1400000000
shard_size: 1
shard_threshold: 1
3:
backend: "evm"
blockchain: "anvil"
network: "dev"
url: "ws://localhost:8546"
admin_funds: 100.
gateway_funds: 1.
chronicle_funds: 1.
batch_size: 64
batch_offset: 0
batch_gas_limit: 10000000
gmp_margin: 0.0
shard_task_limit: 50
route_gas_limit: 10000000
route_base_fee: 1400000000
shard_size: 1
shard_threshold: 1
chronicles:
- http://localhost:8080
- http://localhost:8081
11 changes: 11 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,11 @@ services:
- 'anvil -b 2 --steps-tracing --base-fee 0'
environment:
ANVIL_IP_ADDR: '0.0.0.0'
ports:
- 8545:8545
profiles:
- evm
- bridge

chronicle-2-evm:
image: 'analoglabs/chronicle-develop'
Expand All @@ -98,15 +101,20 @@ services:
environment:
RUST_LOG: 'tc_subxt=debug,chronicle=debug,tss=debug,gmp_evm=info'
RUST_BACKTRACE: 1
ports:
- 8080:8080
profiles:
- evm
- bridge

chain-3-evm:
image: 'ghcr.io/foundry-rs/foundry:latest'
command:
- 'anvil -b 2 --steps-tracing --base-fee 0'
environment:
ANVIL_IP_ADDR: '0.0.0.0'
ports:
- 8546:8545
profiles:
- evm

Expand All @@ -124,12 +132,15 @@ services:
environment:
RUST_LOG: 'tc_subxt=debug,chronicle=debug,tss=debug,gmp_evm=info'
RUST_BACKTRACE: 1
ports:
- 8081:8080
profiles:
- evm

tc-cli:
image: 'analoglabs/tc-cli-develop'
environment:
RUST_BACKTRACE: 1
RUST_LOG: 'gmp_evm=info'
profiles:
- never
19 changes: 19 additions & 0 deletions e2e-tests/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
name = "e2e-tests"
authors.workspace = true
edition.workspace = true
version.workspace = true
homepage.workspace = true
license.workspace = true
readme.workspace = true
repository.workspace = true

[dev-dependencies]
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
anyhow.workspace = true
futures.workspace = true
time-primitives = { workspace = true, features = ["testnet", "develop"] }
tc-cli= { path = "../tc-cli", features = ["testnet", "develop"] }
tracing.workspace = true
tracing-subscriber.workspace = true
hex.workspace = true
1 change: 1 addition & 0 deletions e2e-tests/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

99 changes: 99 additions & 0 deletions e2e-tests/tests/common.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
use anyhow::{Context, Result};
use std::path::Path;
use std::process;
use tc_cli::{Sender, Tc};
use time_primitives::{Address, NetworkId};

pub struct TestEnv {
pub tc: Tc,
}

const CONFIG: &str = "local-evm-e2e.yaml";
const ENV: &str = "../config/envs/local";

impl TestEnv {
async fn new() -> Result<Self> {
let sender = Sender::new();
let tc = Tc::new(Path::new(ENV).to_path_buf(), CONFIG, sender)
.await
.context("Error creating Tc client")?;
Ok(TestEnv { tc })
}

/// spawns new testing env
pub async fn spawn(build: bool) -> Result<Self> {
if build && !build_containers()? {
anyhow::bail!("Failed to build containers");
}

if !docker_up()? {
anyhow::bail!("Failed to start containers");
}
Self::new().await
}

/// sets up test
pub async fn setup(&self, src: NetworkId, dest: NetworkId) -> Result<(Address, Address)> {
self.tc.setup_test(src, dest).await
}

/// restart container
pub async fn restart(&self, containers: Vec<&str>) -> Result<bool> {
docker_restart(containers)
}
}

impl Drop for TestEnv {
/// Tear-down logic for the tests
fn drop(&mut self) {
if !docker_down().expect("Failed to stop containers") {
println!(
"Failed to stop containers, please stop by hand with:\n\
\t $> docker compose --profile=ethereum down"
);
};
}
}

fn build_containers() -> Result<bool> {
let mut cmd = process::Command::new(Path::new("../scripts/build_docker.sh"));
let mut child = cmd.spawn().context("Error building containers")?;

child.wait().map(|c| c.success()).context("Error building containers: {e}")
}

fn docker_up() -> Result<bool> {
let mut cmd = process::Command::new("docker");

cmd.arg("compose").arg("--profile=evm").arg("up").arg("-d").arg("--wait");

let mut child = cmd.spawn().context("Error starting containers")?;

// Wait for all containers to start
child.wait().map(|c| c.success()).context("Error starting containers")
}

fn docker_down() -> Result<bool> {
let mut cmd = process::Command::new("docker");

cmd.arg("compose").arg("--profile=evm").arg("down");

let mut child = cmd.spawn().context("Error stopping containers")?;

// Wait for all containers to start
child.wait().map(|c| c.success()).context("Error stopping containers: {e}")
}

fn docker_restart(containers: Vec<&str>) -> Result<bool> {
let mut cmd = process::Command::new("docker");
cmd.arg("compose").arg("stop").args(containers.as_slice());

let mut child = cmd.spawn().context("Error stopping containers")?;
// wait for the containers to stop
child.wait().map(|c| c.success()).context("Error stopping containers")?;
let mut cmd = process::Command::new("docker");
cmd.arg("compose").arg("start").args(containers.as_slice());
let mut child = cmd.spawn().context("Error stopping containers")?;
// wait for the containers to start
child.wait().map(|c| c.success()).context("Error starting containers")
}
74 changes: 74 additions & 0 deletions e2e-tests/tests/smoke.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use futures::StreamExt;
use tc_cli::Tc;
use tracing_subscriber::filter::EnvFilter;

mod common;

use common::TestEnv;
use time_primitives::{Address, NetworkId};

const SRC: NetworkId = 2;
const DEST: NetworkId = 3;

async fn run_smoke(tc: &Tc, src_addr: Address, dest_addr: Address) {
let mut blockstream = tc.finality_notification_stream();
let (_, start) = blockstream.next().await.expect("expected block");
let gas_limit = tc
.estimate_message_gas_limit(DEST, dest_addr, SRC, src_addr, vec![])
.await
.unwrap();
let gas_cost = tc.estimate_message_cost(SRC, DEST, gas_limit, vec![]).await.unwrap();

let msg_id = tc
.send_message(SRC, src_addr, DEST, dest_addr, gas_limit, gas_cost, vec![])
.await
.unwrap();

let mut id = None;
let (exec, end) = loop {
let (_, end) = blockstream.next().await.expect("expected block");
let trace = tc.message_trace(SRC, msg_id).await.unwrap();
let exec = trace.exec.as_ref().map(|t| t.task);
tracing::info!(target: "smoke_test", "waiting for message {}", hex::encode(msg_id));
id = Some(tc.print_table(id, "message", vec![trace]).await.unwrap());
if let Some(exec) = exec {
break (exec, end);
}
};
let blocks = tc.read_events_blocks(exec).await.unwrap();
let msgs = tc.messages(DEST, dest_addr, blocks).await.unwrap();
let msg = msgs
.into_iter()
.find(|msg| msg.message_id() == msg_id)
.expect("failed to find message");
tc.print_table(None, "message", vec![msg]).await.unwrap();
tc.println(None, format!("received message after {} blocks", end - start))
.await
.unwrap();
}

#[tokio::test]
// Resembles tc-cli smoke test
async fn smoke() {
let filter = EnvFilter::from_default_env()
.add_directive("tc_cli=info".parse().unwrap())
.add_directive("gmp_evm=info".parse().unwrap())
.add_directive("smoke_test=info".parse().unwrap());
tracing_subscriber::fmt().with_env_filter(filter).init();

let env = TestEnv::spawn(true).await.expect("Failed to spawn Test Environment");

let (src_addr, dest_addr) = env.setup(SRC, DEST).await.expect("failed to setup test");

// Run smoke test
run_smoke(&env.tc, src_addr, dest_addr).await;

// Restart chronicles
assert!(env
.restart(vec!["chronicle-2-evm", "chronicle-3-evm"])
.await
.expect("Failed to restart chronicles"));

// Re-run smoke test: should still work
run_smoke(&env.tc, src_addr, dest_addr).await;
}
2 changes: 1 addition & 1 deletion gmp/grpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ serde_json = "1.0.133"
time-primitives = { workspace = true, features = ["std"] }
tokio = { workspace = true, features = ["macros", "signal"] }
tonic = { version = "0.12.3", features = ["transport", "tls", "tls-roots"] }
tracing-subscriber = "0.3.19"
tracing-subscriber.workspace = true

[build-dependencies]
tonic-build = "0.12.2"
20 changes: 12 additions & 8 deletions scripts/build_docker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
set -e
set -x

SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
WORKSPACE_ROOT=$SCRIPT_DIR/../
cd $WORKSPACE_ROOT

# Check for 'uname' and abort if it is not available.
uname -v > /dev/null 2>&1 || { echo >&2 "ERROR - requires 'uname' to identify the platform."; exit 1; }

Expand Down Expand Up @@ -65,19 +69,19 @@ cargo build -p timechain-node -p chronicle -p tc-cli -p gmp-grpc --target "$rust

forge build --root analog-gmp

mkdir -p target/docker/tc-cli
rm -rf target/docker/tc-cli/envs
cp -rL config/envs target/docker/tc-cli/envs
rm -rf target/docker/tc-cli/analog-gmp
cp -r analog-gmp target/docker/tc-cli/analog-gmp
mkdir -p $WORKSPACE_ROOT/target/docker/tc-cli
rm -rf $WORKSPACE_ROOT/target/docker/tc-cli/envs
cp -rL $WORKSPACE_ROOT/config/envs target/docker/tc-cli/envs
rm -rf $WORKSPACE_ROOT/target/docker/tc-cli/analog-gmp
cp -r $WORKSPACE_ROOT/analog-gmp $WORKSPACE_ROOT/target/docker/tc-cli/analog-gmp

build_image () {
local TARGET="target/$rustTarget/$profile/$1"
local CONTEXT="target/docker/$1"
local TARGET=$WORKSPACE_ROOT"target/$rustTarget/$profile/$1"
local CONTEXT=$WORKSPACE_ROOT"target/docker/$1"
mkdir -p $CONTEXT
if ! cmp -s $TARGET "$CONTEXT/$1"; then
cp $TARGET $CONTEXT
docker build $CONTEXT -f "config/docker/Dockerfile.$1" -t "analoglabs/$1-$environment"
docker build $CONTEXT -f $WORKSPACE_ROOT"config/docker/Dockerfile.$1" -t "analoglabs/$1-$environment"
fi
}

Expand Down
Loading

0 comments on commit d10c12b

Please sign in to comment.