Skip to content

Commit

Permalink
fix(e2e-tests): fix merod port issue, pass PR number to update PR com…
Browse files Browse the repository at this point in the history
…ment step
  • Loading branch information
fbozic committed Jan 10, 2025
1 parent 7d5010d commit d9aa3f6
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 68 deletions.
84 changes: 60 additions & 24 deletions .github/workflows/e2e_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ jobs:
uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
cache-all-crates: true # due to candid-extractor

- name: Install dfx
uses: dfinity/setup-dfx@main
Expand All @@ -45,8 +46,43 @@ jobs:
run: |
cargo build -p meroctl -p merod -p e2e-tests
- name: Prepare e2e-tests config
id: prepare_e2e_tests_config
run: |
# Generate 4 unique random numbers
random_numbers=()
while [ ${#random_numbers[@]} -lt 3 ]; do
num=$((RANDOM%37001 + 3000))
if [[ ! " ${random_numbers[@]} " =~ " ${num} " ]]; then
random_numbers+=($num)
fi
done
# Export random numbers to environment variables
SWARM_PORT="${random_numbers[0]}"
SERVER_PORT="${random_numbers[1]}"
ICP_PORT="${random_numbers[2]}"
echo "SWARM_PORT=$SWARM_PORT" >> $GITHUB_OUTPUT
echo "SERVER_PORT=$SERVER_PORT" >> $GITHUB_OUTPUT
echo "ICP_PORT=$ICP_PORT" >> $GITHUB_OUTPUT
# Update JSON file with jq
jq --arg swarmPort "$SWARM_PORT" \
--arg serverPort "$SERVER_PORT" \
--arg icpPort "${random_numbers[2]}" \
'.network.startSwarmPort = ($swarmPort | tonumber) |
.network.startServerPort = ($serverPort | tonumber) |
.protocolSandboxes[1].config.rpcUrl = "http://127.0.0.1:\($icpPort)"
' e2e-tests/config/config.json > updated_config.json
mv updated_config.json e2e-tests/config/config.json
- name: Deploy ICP local devnet
env:
ICP_PORT: ${{ steps.prepare_e2e_tests_config.outputs.ICP_PORT }}
run: |
echo "ICP_PORT=$ICP_PORT"
cargo install candid-extractor
cd ./contracts/icp/context-config
./deploy_devnet.sh
Expand All @@ -60,39 +96,39 @@ jobs:
export SWARM_HOST=$(ifconfig | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | head -n 1)
echo "Running e2e tests, check job summary for details"
echo "# E2E tests 🏗️" >> $GITHUB_STEP_SUMMARY
./target/debug/e2e-tests \
--input-dir ./e2e-tests/config \
--output-dir ./e2e-tests/corpus \
--merod-binary ./target/debug/merod \
--meroctl-binary ./target/debug/meroctl
- name: Update pull request comment
- name: Get PR number
id: pr_number
if: success() || failure()
env:
GH_TOKEN: ${{ github.token }}
GH_REF: ${{ github.ref }}
shell: bash
run: |
echo "PR_NUMBER=$(gh pr list \
--repo ${{ github.repository }} \
--state open \
--head "${GH_REF#refs/heads/}" \
--base master \
--json number \
-q '.[0].number')" >> $GITHUB_OUTPUT
- name: Update pull request comment
if: (success() || failure()) && steps.pr_number.outputs.PR_NUMBER != ''
uses: thollander/actions-comment-pull-request@v3
with:
file-path: ./e2e-tests/corpus/report.md
pr-number: ${{ steps.pr_number.outputs.PR_NUMBER }}

- name: Show node logs
- name: Upload artifacts
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
uses: actions/upload-artifact@v4
with:
name: e2e-tests-corpus
path: e2e-tests/corpus/
retention-days: 2
2 changes: 1 addition & 1 deletion contracts/icp/context-config/deploy_devnet.sh
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ RECIPIENT_PRINCIPAL=$(dfx identity get-principal)
dfx identity use default

# Start dfx with clean state
dfx start --clean --background
dfx start --clean --background --host 127.0.0.1:"${ICP_PORT:-4943}"

# Create initial identity if needed
dfx identity new --storage-mode=plaintext minting || true
Expand Down
68 changes: 41 additions & 27 deletions e2e-tests/src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,18 +59,18 @@ impl<'a> TestContext<'a> {
pub struct Driver {
environment: TestEnvironment,
config: Config,
meroctl: Meroctl,
merods: HashMap<String, Merod>,
}

pub struct Mero {
ctl: Meroctl,
ds: HashMap<String, Merod>,
}

impl Driver {
pub fn new(environment: TestEnvironment, config: Config) -> Self {
let meroctl = Meroctl::new(&environment);
Self {
environment,
config,
meroctl,
merods: HashMap::new(),
}
}

Expand All @@ -96,9 +96,11 @@ impl Driver {
self.environment
.output_writer
.write_header(&format!("Running protocol {}", sandbox.name()), 1);
self.boot_merods(sandbox).await?;
report = self.run_scenarios(report, sandbox.name()).await?;
self.stop_merods().await;

let mero = self.setup_mero(sandbox).await?;
report = self.run_scenarios(&mero, report, sandbox.name()).await?;
self.stop_merods(&mero.ds).await;

self.environment
.output_writer
.write_header(&format!("Finished protocol {}", sandbox.name()), 1);
Expand All @@ -122,14 +124,16 @@ impl Driver {
report.result()
}

async fn boot_merods(&mut self, sandbox: &ProtocolSandboxEnvironment) -> EyreResult<()> {
async fn setup_mero(&mut self, sandbox: &ProtocolSandboxEnvironment) -> EyreResult<Mero> {
self.environment
.output_writer
.write_header("Starting merod nodes", 2);

let mut merods = HashMap::new();

for i in 0..self.config.network.node_count {
let node_name = format!("node{}", i + 1);
if !self.merods.contains_key(&node_name) {
if !merods.contains_key(&node_name) {
let mut args = vec![format!(
"discovery.rendezvous.namespace=\"calimero/e2e-tests/{}\"",
self.environment.test_id
Expand All @@ -140,7 +144,13 @@ impl Driver {
let mut config_args = vec![];
config_args.extend(args.iter().map(|arg| &**arg));

let merod = Merod::new(node_name.clone(), &self.environment);
let merod = Merod::new(
node_name.clone(),
self.environment.nodes_dir.join(sandbox.name()),
self.environment.logs_dir.join(sandbox.name()),
self.environment.merod_binary.clone(),
self.environment.output_writer,
);

let swarm_host = match env::var(&self.config.network.swarm_host_env) {
Ok(host) => host,
Expand All @@ -158,28 +168,34 @@ impl Driver {

merod.run().await?;

drop(self.merods.insert(node_name, merod));
drop(merods.insert(node_name, merod));
}
}

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

Ok(())
Ok(Mero {
ctl: Meroctl::new(
self.environment.nodes_dir.join(sandbox.name()),
self.environment.meroctl_binary.clone(),
self.environment.output_writer,
),
ds: merods,
})
}

async fn stop_merods(&mut self) {
for (_, merod) in self.merods.iter() {
async fn stop_merods(&mut self, merods: &HashMap<String, Merod>) {
for (_, merod) in merods.iter() {
if let Err(err) = merod.stop().await {
eprintln!("Error stopping merod: {:?}", err);
}
}

self.merods.clear();
}

async fn run_scenarios(
&self,
mero: &Mero,
mut report: TestRunReport,
protocol_name: String,
) -> EyreResult<TestRunReport> {
Expand All @@ -193,6 +209,7 @@ impl Driver {
if test_file_path.exists() {
let scenario_report = self
.run_scenario(
mero,
path.file_name()
.ok_or_eyre("failed")?
.to_str()
Expand All @@ -217,6 +234,7 @@ impl Driver {

async fn run_scenario(
&self,
mero: &Mero,
scenarion_name: &str,
file_path: PathBuf,
) -> EyreResult<TestScenarioReport> {
Expand All @@ -233,7 +251,7 @@ impl Driver {
.output_writer
.write_string(format!("Steps count: {}", scenario.steps.len()));

let (inviter, invitees) = match self.pick_inviter_node() {
let (inviter, invitees) = match self.pick_inviter_node(&mero.ds) {
Some((inviter, invitees)) => (inviter, invitees),
None => bail!("Not enough nodes to run the test"),
};
Expand All @@ -245,12 +263,8 @@ impl Driver {
.output_writer
.write_string(format!("Picked invitees: {:?}", invitees));

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

let mut report = TestScenarioReport::new(scenarion_name.to_owned());

Expand All @@ -271,8 +285,8 @@ impl Driver {
Ok(report)
}

fn pick_inviter_node(&self) -> Option<(String, Vec<String>)> {
let mut node_names: Vec<String> = self.merods.keys().cloned().collect();
fn pick_inviter_node(&self, merods: &HashMap<String, Merod>) -> Option<(String, Vec<String>)> {
let mut node_names: Vec<String> = merods.keys().cloned().collect();
if node_names.len() < 1 {
None
} else {
Expand Down Expand Up @@ -357,7 +371,7 @@ impl TestRunReport {
.steps
.iter()
.find(|step| &step.step_name == step_name)
.map_or(":interrobang:", |step| {
.map_or("N/A", |step| {
if step.result.is_ok() {
":white_check_mark:"
} else {
Expand Down
13 changes: 6 additions & 7 deletions e2e-tests/src/meroctl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,19 @@ use eyre::{bail, eyre, OptionExt, Result as EyreResult};
use tokio::process::Command;

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

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

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

Expand Down Expand Up @@ -142,7 +141,7 @@ impl Meroctl {
async fn run_cmd(&self, node_name: &str, args: &[&str]) -> EyreResult<serde_json::Value> {
let mut root_args = vec![
"--home",
self.nodes_dir.as_str(),
self.home_dir.as_str(),
"--node-name",
node_name,
"--output-format",
Expand Down
23 changes: 14 additions & 9 deletions e2e-tests/src/merod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,31 @@ use tokio::io::copy;
use tokio::process::{Child, Command};

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

pub struct Merod {
pub name: String,
process: RefCell<Option<Child>>,
nodes_dir: Utf8PathBuf,
home_dir: Utf8PathBuf,
log_dir: Utf8PathBuf,
binary: Utf8PathBuf,
output_writer: OutputWriter,
}

impl Merod {
pub fn new(name: String, environment: &TestEnvironment) -> Self {
pub fn new(
name: String,
home_dir: Utf8PathBuf,
logs_dir: Utf8PathBuf,
binary: Utf8PathBuf,
output_writer: OutputWriter,
) -> Self {
Self {
process: RefCell::new(None),
nodes_dir: environment.nodes_dir.clone(),
log_dir: environment.logs_dir.join(&name),
binary: environment.merod_binary.clone(),
home_dir,
log_dir: logs_dir.join(&name),
binary,
name,
output_writer: environment.output_writer,
output_writer,
}
}

Expand All @@ -38,7 +43,7 @@ impl Merod {
server_port: u32,
args: &[&str],
) -> EyreResult<()> {
create_dir_all(&self.nodes_dir.join(&self.name)).await?;
create_dir_all(&self.home_dir.join(&self.name)).await?;
create_dir_all(&self.log_dir).await?;

let mut child = self
Expand Down Expand Up @@ -96,7 +101,7 @@ impl Merod {
}

async fn run_cmd(&self, args: &[&str], log_suffix: &str) -> EyreResult<Child> {
let mut root_args = vec!["--home", self.nodes_dir.as_str(), "--node-name", &self.name];
let mut root_args = vec!["--home", self.home_dir.as_str(), "--node-name", &self.name];

root_args.extend(args);

Expand Down

0 comments on commit d9aa3f6

Please sign in to comment.