Skip to content

Commit

Permalink
ci: setup e2e-tests in github workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
fbozic committed Nov 22, 2024
1 parent 7fc10d4 commit 8b512df
Show file tree
Hide file tree
Showing 11 changed files with 173 additions and 25 deletions.
76 changes: 76 additions & 0 deletions .github/workflows/e2e_tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
name: End-to-end tests

on:
push:
branches:
- '**'
paths:
- Cargo.toml
- Cargo.lock
- 'contracts/**'
- 'crates/**'
- 'e2e-tests/**'
- '.github/workflows/e2e_tests.yml'

jobs:
test:
name: Test
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup rust toolchain
run: rustup toolchain install stable --profile minimal

- name: Setup rust cache
uses: Swatinem/rust-cache@v2

- name: Build apps
run: |
./apps/kv-store/build.sh
- name: Build contracts
run: |
./contracts/context-config/build.sh
./contracts/proxy-lib/build.sh
- name: Build binaries
run: |
cargo build -p meroctl -p merod -p e2e-tests
- name: Run e2e tests
run: |
export NO_COLOR=1
echo "# E2E tests 🏗️" >> $GITHUB_STEP_SUMMARY
TEST_REPORT=$(./target/debug/e2e-tests \
--input-dir ./e2e-tests/config \
--output-dir ./e2e-tests/corpus \
--merod-binary ./target/debug/merod \
--meroctl-binary ./target/debug/meroctl)
echo "$TEST_REPORT" >> $GITHUB_STEP_SUMMARY
- name: Run e2e tests
if: success() || failure()
run: |
LOGS_DIR=./e2e-tests/corpus/logs
if [ ! -d "$LOGS_DIR" ]; then
echo "Directory $LOGS_DIR does not exist."
exit 1
fi
echo "# Node logs 📋" >> $GITHUB_STEP_SUMMARY
for FOLDER in "$LOGS_DIR"/*; do
if [ -d "$FOLDER" ]; then
RUN_LOG="$FOLDER/run.log"
if [ -f "$RUN_LOG" ]; then
echo "## Node logs: $(basename $FOLDER) 📋" >> $GITHUB_STEP_SUMMARY
cat "$RUN_LOG" >> $GITHUB_STEP_SUMMARY
else
echo "## No run.log found in $FOLDER ⚠️" >> $GITHUB_STEP_SUMMARY
fi
fi
done
18 changes: 16 additions & 2 deletions e2e-tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,26 @@ Binary crate which runs e2e tests for the merod node.

## Usage

Build the merod and meroctl binaries and run the e2e tests with the following
commands:
First build apps, contracts, and mero binaries. After that run the e2e tests.

Example of running the e2e tests:

```bash
./apps/kv-store/build.sh

./contracts/context-config/build.sh
./contracts/proxy-lib/build.sh

cargo build -p merod
cargo build -p meroctl

export NO_COLOR=1 # Disable color output for merod logs
cargo run -p e2e-tests -- --input-dir ./e2e-tests/config --output-dir ./e2e-tests/corpus --merod-binary ./target/debug/merod --meroctl-binary ./target/debug/meroctl
```

Useful env vars for debugging:

- `RUST_LOG=debug` - enable debug logs
- `RUST_LOG=near_jsonrpc_client=debug` - or more specific logs
- `NEAR_ENABLE_SANDBOX_LOG=1` - enable near sandbox logs
- `NO_COLOR=1` - disable color output
2 changes: 1 addition & 1 deletion e2e-tests/config/scenarios/kv-store/test.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
},
{
"jsonRpcCall": {
"methodName": "set",
"methodName": "sets",
"argsJson": { "key": "foo", "value": "bar" },
"expectedResultJson": null,
"target": "inviter"
Expand Down
44 changes: 28 additions & 16 deletions e2e-tests/src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use tokio::time::sleep;
use crate::config::Config;
use crate::meroctl::Meroctl;
use crate::merod::Merod;
use crate::output::OutputWriter;
use crate::steps::{TestScenario, TestStep};
use crate::TestEnvironment;

Expand All @@ -24,6 +25,7 @@ pub struct TestContext<'a> {
pub context_id: Option<String>,
pub inviter_public_key: Option<String>,
pub invitees_public_keys: HashMap<String, String>,
pub output_writer: OutputWriter,
}

pub trait Test {
Expand All @@ -39,6 +41,7 @@ impl<'a> TestContext<'a> {
context_id: None,
inviter_public_key: None,
invitees_public_keys: HashMap::new(),
output_writer: OutputWriter {},
}
}
}
Expand Down Expand Up @@ -113,7 +116,9 @@ impl Driver {
}

async fn boot_merods(&mut self) -> EyreResult<()> {
println!("========================= Starting nodes ===========================");
self.environment
.output_writer
.write_header("Starting merod nodes", 2);

for i in 0..self.config.network.node_count {
let node_name = format!("node{}", i + 1);
Expand Down Expand Up @@ -178,9 +183,7 @@ impl Driver {
}

// TODO: Implement health check?
sleep(Duration::from_secs(20)).await;

println!("====================================================================");
sleep(Duration::from_secs(10)).await;

Ok(())
}
Expand Down Expand Up @@ -213,35 +216,44 @@ impl Driver {
}

async fn run_scenario(&self, file_path: PathBuf) -> EyreResult<()> {
println!("================= Setting up scenario and context ==================");
self.environment
.output_writer
.write_header("Running scenario", 2);

let scenario: TestScenario = from_slice(&read(&file_path).await?)?;

println!(
"Loaded test scenario from file: {:?}\n{:?}",
file_path, scenario
);
self.environment
.output_writer
.write_string(format!("Source file: {:?}", file_path));
self.environment
.output_writer
.write_string(format!("Steps count: {}", scenario.steps.len()));

let (inviter, invitees) = match self.pick_inviter_node() {
Some((inviter, invitees)) => (inviter, invitees),
None => bail!("Not enough nodes to run the test"),
};

println!("Picked inviter: {}", inviter);
println!("Picked invitees: {:?}", invitees);
self.environment
.output_writer
.write_string(format!("Picked inviter: {}", inviter));
self.environment
.output_writer
.write_string(format!("Picked invitees: {:?}", invitees));

let mut ctx = TestContext::new(inviter, invitees, &self.meroctl);

println!("====================================================================");

for step in scenario.steps.iter() {
println!("======================== Starting step =============================");
println!("Step: {:?}", step);
self.environment
.output_writer
.write_header("Running test step", 3);
self.environment.output_writer.write_json(&step)?;

match step {
TestStep::ContextCreate(step) => step.run_assert(&mut ctx).await?,
TestStep::ContextInviteJoin(step) => step.run_assert(&mut ctx).await?,
TestStep::JsonRpcCall(step) => step.run_assert(&mut ctx).await?,
};
println!("====================================================================");
}

Ok(())
Expand Down
4 changes: 4 additions & 0 deletions e2e-tests/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ use config::Config;
use const_format::concatcp;
use driver::Driver;
use eyre::Result as EyreResult;
use output::OutputWriter;
use rand::Rng;
use tokio::fs::{create_dir_all, read_to_string, remove_dir_all};

mod config;
mod driver;
mod meroctl;
mod merod;
mod output;
mod steps;

pub const EXAMPLES: &str = r"
Expand Down Expand Up @@ -62,6 +64,7 @@ pub struct TestEnvironment {
pub output_dir: Utf8PathBuf,
pub nodes_dir: Utf8PathBuf,
pub logs_dir: Utf8PathBuf,
pub output_writer: OutputWriter,
}

impl Into<TestEnvironment> for Args {
Expand All @@ -76,6 +79,7 @@ impl Into<TestEnvironment> for Args {
output_dir: self.output_dir.clone(),
nodes_dir: self.output_dir.join("nodes"),
logs_dir: self.output_dir.join("logs"),
output_writer: OutputWriter {},
}
}
}
Expand Down
7 changes: 5 additions & 2 deletions e2e-tests/src/meroctl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,20 @@ use camino::Utf8PathBuf;
use eyre::{bail, eyre, OptionExt, Result as EyreResult};
use tokio::process::Command;

use crate::TestEnvironment;
use crate::{output::OutputWriter, TestEnvironment};

pub struct Meroctl {
nodes_dir: Utf8PathBuf,
binary: Utf8PathBuf,
output_writer: OutputWriter,
}

impl Meroctl {
pub fn new(environment: &TestEnvironment) -> Self {
Self {
nodes_dir: environment.nodes_dir.clone(),
binary: environment.meroctl_binary.clone(),
output_writer: environment.output_writer,
}
}

Expand Down Expand Up @@ -148,7 +150,8 @@ impl Meroctl {

root_args.extend(args);

println!("Command: '{:}' {:?}", &self.binary, root_args);
self.output_writer
.write_string(format!("Command: '{:}' {:?}", &self.binary, root_args));

let output = Command::new(&self.binary)
.args(root_args)
Expand Down
6 changes: 5 additions & 1 deletion e2e-tests/src/merod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use tokio::fs::{create_dir_all, File};
use tokio::io::copy;
use tokio::process::{Child, Command};

use crate::output::OutputWriter;
use crate::TestEnvironment;

pub struct Merod {
Expand All @@ -15,6 +16,7 @@ pub struct Merod {
nodes_dir: Utf8PathBuf,
log_dir: Utf8PathBuf,
binary: Utf8PathBuf,
output_writer: OutputWriter,
}

impl Merod {
Expand All @@ -25,6 +27,7 @@ impl Merod {
log_dir: environment.logs_dir.join(&name),
binary: environment.merod_binary.clone(),
name,
output_writer: environment.output_writer,
}
}

Expand Down Expand Up @@ -92,7 +95,8 @@ impl Merod {
let log_file = self.log_dir.join(format!("{}.log", log_suffix));
let mut log_file = File::create(&log_file).await?;

println!("Command: '{:}' {:?}", &self.binary, root_args);
self.output_writer
.write_string(format!("Command: '{:}' {:?}", &self.binary, root_args));

let mut child = Command::new(&self.binary)
.args(root_args)
Expand Down
30 changes: 30 additions & 0 deletions e2e-tests/src/output.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use eyre::Result as EyreResult;
use serde::Serialize;

#[derive(Clone, Copy, Debug)]
pub struct OutputWriter {}

impl OutputWriter {
pub fn write_str(&self, line: &str) {
println!("{} ", line);
}

pub fn write_string(&self, line: String) {
println!("{} ", line);
}

pub fn write_header(&self, header: &str, level: usize) {
let header_prefix = "#".repeat(level);
println!("{} {} ", header_prefix, header);
}

pub fn write_json<T>(&self, json: &T) -> EyreResult<()>
where
T: ?Sized + Serialize,
{
let json = serde_json::to_string_pretty(json)?;
println!("```json\n{}\n```", json);

Ok(())
}
}
5 changes: 4 additions & 1 deletion e2e-tests/src/steps/context_create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ impl Test for CreateContextStep {
ctx.context_id = Some(context_id);
ctx.inviter_public_key = Some(member_public_key);

println!("Report: Created context on '{}' node", &ctx.inviter);
ctx.output_writer.write_string(format!(
"Report: Created context on '{}' node",
&ctx.inviter
));

Ok(())
}
Expand Down
3 changes: 2 additions & 1 deletion e2e-tests/src/steps/context_invite_join.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ impl Test for InviteJoinContextStep {
.insert(invitee.clone(), invitee_public_key),
);

println!("Report: Node '{}' joined the context", invitee)
ctx.output_writer
.write_string(format!("Report: Node '{}' joined the context", invitee));
}

Ok(())
Expand Down
3 changes: 2 additions & 1 deletion e2e-tests/src/steps/jsonrpc_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ impl Test for JsonRpcCallStep {
}
}

println!("Report: Call on '{}' node passed assertion", node)
ctx.output_writer
.write_string(format!("Report: Call on '{}' node passed assertion", node));
}

Ok(())
Expand Down

0 comments on commit 8b512df

Please sign in to comment.