Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(e2e-tests): support protocol test matrix, implement icp protocol #1035

Merged
merged 13 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 79 additions & 25 deletions .github/workflows/e2e_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,13 @@ 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

- name: Build apps
run: |
export SWARM_HOST=$(ifconfig | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | head -n 1)
echo "$SWARM_HOST"

./apps/kv-store/build.sh

- name: Build contracts
Expand All @@ -45,6 +46,52 @@ 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]}"
SWARM_HOST=$(ifconfig | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | head -n 1)

echo "SWARM_PORT=$SWARM_PORT" >> $GITHUB_OUTPUT
echo "SERVER_PORT=$SERVER_PORT" >> $GITHUB_OUTPUT
echo "ICP_PORT=$ICP_PORT" >> $GITHUB_OUTPUT
echo "SWARM_HOST=$SWARM_HOST" >> $GITHUB_OUTPUT

# Update JSON file with jq
jq --arg swarmPort "$SWARM_PORT" \
--arg serverPort "$SERVER_PORT" \
--arg icpPort "$ICP_PORT" \
--arg swarmHost "$SWARM_HOST" \
'.network.swarmHost = ($swarmHost) |
.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
cd ../../..

- name: Run e2e tests
env:
NO_COLOR: '1'
Expand All @@ -53,34 +100,41 @@ 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 \
--output-format markdown >> $GITHUB_STEP_SUMMARY
--meroctl-binary ./target/debug/meroctl

- name: Run e2e tests
- name: Get PR number
id: pr_number
if: success() || failure()
env:
GH_TOKEN: ${{ github.token }}
GH_REF: ${{ github.ref }}
shell: bash
run: |
LOGS_DIR=./e2e-tests/corpus/logs
if [ ! -d "$LOGS_DIR" ]; then
echo "Directory $LOGS_DIR does not exist."
exit 1
fi
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

echo "# Node logs 📋" >> $GITHUB_STEP_SUMMARY

for FOLDER in "$LOGS_DIR"/*; do
if [ -d "$FOLDER" ]; then
- 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 }}
comment-tag: e2e-tests-report
mode: recreate
fbozic marked this conversation as resolved.
Show resolved Hide resolved

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
- name: Upload artifacts
if: success() || failure()
uses: actions/upload-artifact@v4
with:
name: e2e-tests-corpus
path: e2e-tests/corpus/
retention-days: 2
1 change: 1 addition & 0 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ float_cmp_const = "deny"
fn_to_numeric_cast_any = "deny"
format_push_string = "deny"
get_unwrap = "deny"
impl_trait_in_params = "deny"
# impl_trait_in_params = "deny"
integer_division = "deny"
lossy_float_literal = "deny"
mem_forget = "deny"
Expand Down
34 changes: 16 additions & 18 deletions contracts/icp/context-config/deploy_devnet.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/bin/bash
set -e
set -ex

# Function to generate a new identity and return its principal
generate_identity() {
Expand Down Expand Up @@ -80,9 +80,7 @@ RECIPIENT_PRINCIPAL=$(dfx identity get-principal)
dfx identity use default

# Start dfx with clean state
dfx start --clean --background

dfx identity use default
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 Expand Up @@ -118,20 +116,20 @@ cd ../context-proxy
cd ../context-config

# Prepare ledger initialization argument
LEDGER_INIT_ARG="(variant { Init = record {
minting_account = \"${MINTING_ACCOUNT}\";
initial_values = vec {
record { \"${INITIAL_ACCOUNT}\"; record { e8s = 100_000_000_000 } }
};
send_whitelist = vec {};
transfer_fee = opt record { e8s = 10_000 };
token_symbol = opt \"LICP\";
token_name = opt \"Local Internet Computer Protocol Token\";
archive_options = opt record {
trigger_threshold = 2000;
num_blocks_to_archive = 1000;
controller_id = principal \"${ARCHIVE_PRINCIPAL}\"
};
LEDGER_INIT_ARG="(variant { Init = record {
minting_account = \"${MINTING_ACCOUNT}\";
initial_values = vec {
record { \"${INITIAL_ACCOUNT}\"; record { e8s = 100_000_000_000 } }
};
send_whitelist = vec {};
transfer_fee = opt record { e8s = 10_000 };
token_symbol = opt \"LICP\";
token_name = opt \"Local Internet Computer Protocol Token\";
archive_options = opt record {
trigger_threshold = 2000;
num_blocks_to_archive = 1000;
controller_id = principal \"${ARCHIVE_PRINCIPAL}\"
};
} })"

# Build and install canisters
Expand Down
12 changes: 6 additions & 6 deletions crates/meroctl/src/cli/bootstrap/start.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ impl StartBootstrapCommand {
nodes_dir.clone(),
log_dir.clone(),
node_name.clone(),
&[
[
"init",
"--swarm-port",
&swarm_port.to_string().as_str(),
Expand All @@ -251,7 +251,7 @@ impl StartBootstrapCommand {
}

let mut child = self
.run_cmd(nodes_dir, log_dir, node_name.clone(), &["config"], "config")
.run_cmd(nodes_dir, log_dir, node_name.clone(), ["config"], "config")
.await?;
let result = child.wait().await?;
if !result.success() {
Expand All @@ -267,7 +267,7 @@ impl StartBootstrapCommand {
node_name: String,
) -> EyreResult<Child> {
Ok(self
.run_cmd(nodes_dir, log_dir, node_name, &["run"], "run")
.run_cmd(nodes_dir, log_dir, node_name, ["run"], "run")
.await?)
}

Expand Down Expand Up @@ -309,17 +309,17 @@ impl StartBootstrapCommand {
nodes_dir: Utf8PathBuf,
log_dir: Utf8PathBuf,
node_name: String,
args: &[&str],
args: impl IntoIterator<Item = &str>,
log_suffix: &str,
) -> EyreResult<Child> {
let mut root_args = vec!["--home", &nodes_dir.as_str(), "--node-name", &node_name];
root_args.extend(args);
let root_args = ["--home", &nodes_dir.as_str(), "--node-name", &node_name];

let log_file = log_dir.join(format!("{}.log", log_suffix));
let mut log_file = File::create(&log_file).await?;

let mut child = Command::new(&self.merod_path)
.args(root_args)
.args(args)
.stdout(Stdio::piped())
.spawn()?;

Expand Down
1 change: 1 addition & 0 deletions e2e-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ rand.workspace = true
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
tokio = { workspace = true, features = ["fs", "io-util", "macros", "process", "rt", "rt-multi-thread", "time"] }
url = { workspace = true }

[lints]
workspace = true
25 changes: 20 additions & 5 deletions e2e-tests/config/config.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,30 @@
{
"network": {
"nodeCount": 2,
"swarmHostEnv": "SWARM_HOST",
"swarmHost": "0.0.0.0",
"startSwarmPort": 2427,
"startServerPort": 2527
},
"merod": {
"args": []
},
"near": {
"contextConfigContract": "./contracts/near/context-config/res/calimero_context_config_near.wasm",
"proxyLibContract": "./contracts/near/context-proxy/res/calimero_context_proxy_near.wasm"
}
"protocolSandboxes": [
{
"protocol": "near",
"config": {
"contextConfigContract": "./contracts/near/context-config/res/calimero_context_config_near.wasm",
"proxyLibContract": "./contracts/near/context-proxy/res/calimero_context_proxy_near.wasm"
}
},
{
"protocol": "icp",
"config": {
"contextConfigContractId": "bkyz2-fmaaa-aaaaa-qaaaq-cai",
"rpcUrl": "http://127.0.0.1:4943",
"accountId": "fph2z-lxdui-xq3o6-6kuqy-rgkwi-hq7us-gkwlq-gxfgs-irrcq-hnm4e-6qe",
"publicKey": "e3a22f0dbbde552188995641e1fa48cab2e06b94d24462281dace13d02",
"secretKey": "c9a8e56920efd1c7b6694dce6ce871b661ae3922d5045d4a9f04e131eaa34164"
}
}
]
}
6 changes: 3 additions & 3 deletions e2e-tests/config/scenarios/kv-store/test.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@
"contextCreate": null
},
{
"jsonRpcCall": {
"call": {
"methodName": "set",
"argsJson": { "key": "foo", "value": "bar" },
"expectedResultJson": null,
"target": "inviter"
}
},
{
"jsonRpcCall": {
"call": {
"methodName": "get",
"argsJson": { "key": "foo" },
"expectedResultJson": "bar",
Expand All @@ -29,7 +29,7 @@
"contextInviteJoin": null
},
{
"jsonRpcCall": {
"call": {
"methodName": "get",
"argsJson": { "key": "foo" },
"expectedResultJson": "bar",
Expand Down
16 changes: 9 additions & 7 deletions e2e-tests/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
use camino::Utf8PathBuf;
use serde::{Deserialize, Serialize};

use crate::protocol::icp::IcpProtocolConfig;
use crate::protocol::near::NearProtocolConfig;

#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Config {
pub network: Network,
pub merod: MerodConfig,
pub near: Near,
pub protocol_sandboxes: Box<[ProtocolSandboxConfig]>,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Network {
pub node_count: u32,
pub swarm_host_env: String,
pub swarm_host: String,
pub start_swarm_port: u32,
pub start_server_port: u32,
}
Expand All @@ -25,8 +27,8 @@ pub struct MerodConfig {
}

#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Near {
pub context_config_contract: Utf8PathBuf,
pub proxy_lib_contract: Utf8PathBuf,
#[serde(tag = "protocol", content = "config", rename_all = "camelCase")]
pub enum ProtocolSandboxConfig {
Near(NearProtocolConfig),
Icp(IcpProtocolConfig),
}
Loading
Loading