Skip to content

Commit

Permalink
sns-testing: init
Browse files Browse the repository at this point in the history
Init the new sns-testing project.

Currently, this crate provides CLI to bootstrap NNS on the provided
PocketIC instance.
  • Loading branch information
rvem committed Jan 29, 2025
1 parent 4d2625d commit 4214bb7
Show file tree
Hide file tree
Showing 9 changed files with 309 additions and 0 deletions.
15 changes: 15 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ members = [
"rs/sns/swap",
"rs/sns/swap/proto_library",
"rs/sns/test_utils",
"rs/sns/testing",
"rs/starter",
"rs/state_manager",
"rs/state_machine_tests",
Expand Down
92 changes: 92 additions & 0 deletions rs/sns/testing/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_library", "rust_test")

package(default_visibility = ["//visibility:public"])

DEPENDENCIES = [
"//packages/pocket-ic",
"//rs/nervous_system/integration_tests:nervous_system_integration_tests",
"//rs/nns/test_utils",
"//rs/nns/constants",
"//rs/rust_canisters/canister_test",
"@crate_index//:candid",
"@crate_index//:clap",
"@crate_index//:reqwest",
"@crate_index//:tokio",
]

MACRO_DEPENDENCIES = []

ALIASES = {}

DEV_DATA = [
"//rs/ledger_suite/icp/archive:ledger-archive-node-canister-wasm",
"//rs/ledger_suite/icp/index:ic-icp-index-canister",
"//rs/ledger_suite/icp/ledger:ledger-canister-wasm",
"//rs/ledger_suite/icp/ledger:ledger-canister-wasm-notify-method",
"//rs/ledger_suite/icrc1/archive:archive_canister",
"//rs/ledger_suite/icrc1/index-ng:index_ng_canister",
"//rs/ledger_suite/icrc1/ledger:ledger_canister",
"//rs/nns/cmc:cycles-minting-canister",
"//rs/nns/governance:governance-canister",
"//rs/nns/handlers/root/impl:root-canister",
"//rs/nns/sns-wasm:sns-wasm-canister",
"//rs/pocket_ic_server:pocket-ic-server",
"//rs/registry/canister:registry-canister",
"//rs/sns/governance:sns-governance-canister",
"//rs/sns/root:sns-root-canister",
"//rs/sns/swap:sns-swap-canister",
"@nns_dapp_canister//file",
"@sns_aggregator//file",
"@ii_dev_canister//file",
]

DEV_ENV = {
"CYCLES_MINTING_CANISTER_WASM_PATH": "$(rootpath //rs/nns/cmc:cycles-minting-canister)",
"GOVERNANCE_CANISTER_WASM_PATH": "$(rootpath //rs/nns/governance:governance-canister)",
"REGISTRY_CANISTER_WASM_PATH": "$(rootpath //rs/registry/canister:registry-canister)",
"IC_ICRC1_ARCHIVE_WASM_PATH": "$(rootpath //rs/ledger_suite/icrc1/archive:archive_canister)",
"IC_ICRC1_INDEX_NG_WASM_PATH": "$(rootpath //rs/ledger_suite/icrc1/index-ng:index_ng_canister)",
"IC_ICRC1_LEDGER_WASM_PATH": "$(rootpath //rs/ledger_suite/icrc1/ledger:ledger_canister)",
"IC_ICP_INDEX_WASM_PATH": "$(rootpath //rs/ledger_suite/icp/index:ic-icp-index-canister)",
"LEDGER_CANISTER_WASM_PATH": "$(rootpath //rs/ledger_suite/icp/ledger:ledger-canister-wasm)",
"LEDGER_CANISTER_NOTIFY_METHOD_WASM_PATH": "$(rootpath //rs/ledger_suite/icp/ledger:ledger-canister-wasm-notify-method)",
"LEDGER_ARCHIVE_NODE_CANISTER_WASM_PATH": "$(rootpath //rs/ledger_suite/icp/archive:ledger-archive-node-canister-wasm)",
"SNS_WASM_CANISTER_WASM_PATH": "$(rootpath //rs/nns/sns-wasm:sns-wasm-canister)",
"SNS_GOVERNANCE_CANISTER_WASM_PATH": "$(rootpath //rs/sns/governance:sns-governance-canister)",
"SNS_ROOT_CANISTER_WASM_PATH": "$(rootpath //rs/sns/root:sns-root-canister)",
"SNS_SWAP_CANISTER_WASM_PATH": "$(rootpath //rs/sns/swap:sns-swap-canister)",
"ROOT_CANISTER_WASM_PATH": "$(rootpath //rs/nns/handlers/root/impl:root-canister)",
"POCKET_IC_BIN": "$(rootpath //rs/pocket_ic_server:pocket-ic-server)",
"NNS_DAPP_WASM_PATH": "$(rootpath @nns_dapp_canister//file)",
"SNS_AGGREGATOR_WASM_PATH": "$(rootpath @sns_aggregator//file)",
"INTERNET_IDENTITY_WASM_PATH": "$(rootpath @ii_dev_canister//file)",
}

rust_binary(
name = "cli",
testonly = True,
srcs = ["src/main.rs"],
env = DEV_ENV,
data = DEV_DATA,
deps = DEPENDENCIES + [
":sns_testing",
],
)

rust_library(
name = "sns_testing",
testonly = True,
srcs = glob(["src/**/*.rs"]),
crate_name = "ic_sns_testing",
deps = DEPENDENCIES,
)

rust_test(
name = "sns_testing_ci",
srcs = ["tests/sns_testing_ci.rs"],
data = DEV_DATA,
env = DEV_ENV,
deps = DEPENDENCIES + [
":sns_testing",
],
)
26 changes: 26 additions & 0 deletions rs/sns/testing/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[package]
name = "ic-sns-testing"
version.workspace = true
authors.workspace = true
description.workspace = true
documentation.workspace = true
edition.workspace = true

[[bin]]
name = "sns"
path = "src/main.rs"

[lib]
path = "src/lib.rs"

[dependencies]
candid = { workspace = true }
canister-test = { path = "../../rust_canisters/canister_test" }
clap = { workspace = true }
ic-nervous-system-integration-tests = { path = "../../nervous_system/integration_tests" }
ic-nns-constants = { path = "../../nns/constants" }
ic-nns-test-utils = { path = "../../nns/test_utils" }
pocket-ic = { path = "../../../packages/pocket-ic" }
reqwest = { workspace = true }
tokio = { workspace = true }

8 changes: 8 additions & 0 deletions rs/sns/testing/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# SNS testing

To run the scenario on the local PocketIC instance:
1) Launch PocketIC server: `bazel run //rs/pocket_ic_server:pocket-ic-server -- --ttl 6000 --port 8888`
2) Launch SNS testing scenario on it: `bazel run //rs/sns/testing:cli -- --server-url "http://127.0.0.1:8888"`

Open local NNS dapp instance: http://qoctq-giaaa-aaaaa-aaaea-cai.localhost:8080/proposals/?u=qoctq-giaaa-aaaaa-aaaea-cai.
You should be able to see executed proposals to add SNS WASM to SNS-W canisters (since currently used NNS dapp is slightly outdated, make sure to clear topic filters).
1 change: 1 addition & 0 deletions rs/sns/testing/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod pocket_ic;
26 changes: 26 additions & 0 deletions rs/sns/testing/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use clap::Parser;
use ic_sns_testing::pocket_ic::bootstrap_nns;
use pocket_ic::PocketIcBuilder;
use reqwest::Url;

#[derive(Debug, Parser)]
struct SnsTestingOpts {
#[arg(long)]
server_url: Url,
}

#[tokio::main]
async fn main() {
let opts = SnsTestingOpts::parse();
let mut pocket_ic = PocketIcBuilder::new()
.with_server_url(opts.server_url)
.with_nns_subnet()
.with_sns_subnet()
.with_ii_subnet()
.with_application_subnet()
.build_async()
.await;
let endpoint = pocket_ic.make_live(Some(8080)).await;
println!("PocketIC endpoint: {}", endpoint);
bootstrap_nns(&pocket_ic).await;
}
126 changes: 126 additions & 0 deletions rs/sns/testing/src/pocket_ic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
use candid::{CandidType, Encode};
use canister_test::Wasm;
use ic_nervous_system_integration_tests::pocket_ic_helpers::{
add_wasms_to_sns_wasm, install_all_nns_canisters, install_canister_with_controllers,
};
use ic_nns_constants::{
CYCLES_MINTING_CANISTER_ID, GOVERNANCE_CANISTER_ID, IDENTITY_CANISTER_ID, LEDGER_CANISTER_ID,
LEDGER_INDEX_CANISTER_ID, NNS_UI_CANISTER_ID, ROOT_CANISTER_ID, SNS_AGGREGATOR_CANISTER_ID,
SNS_WASM_CANISTER_ID,
};
use pocket_ic::nonblocking::PocketIc;

pub async fn bootstrap_nns(pocket_ic: &PocketIc) {
// TODO @rvem: at some point in the future we might want to use
// non-empty 'initial_balances' as well as 'neurons_fund_hotkeys' to provide
// tokens and neuron hotkeys for user-provided indentities.
install_all_nns_canisters(pocket_ic, vec![], false, None, vec![]).await;
install_frontend_nns_canisters(pocket_ic).await;
add_wasms_to_sns_wasm(pocket_ic, false).await.unwrap();
}

#[derive(CandidType)]
struct SnsAggregatorPayload {
pub update_interval_ms: u64,
pub fast_interval_ms: u64,
}

#[derive(CandidType)]
struct NnsDappPayload {
args: Vec<(String, String)>,
}

async fn install_frontend_nns_canisters(pocket_ic: &PocketIc) {
let features = &[];
let sns_aggregator_wasm =
Wasm::from_location_specified_by_env_var("sns_aggregator", features).unwrap();
let nns_dapp_wasm = Wasm::from_location_specified_by_env_var("nns_dapp", features).unwrap();
let internet_identity_wasm =
Wasm::from_location_specified_by_env_var("internet_identity", features).unwrap();

// Refresh every second so that the NNS dapp is as up-to-date as possible
let sns_aggregator_payload = SnsAggregatorPayload {
update_interval_ms: 1000,
fast_interval_ms: 100,
};
install_canister_with_controllers(
pocket_ic,
"sns_aggregator",
SNS_AGGREGATOR_CANISTER_ID,
Encode!(&sns_aggregator_payload).unwrap(),
sns_aggregator_wasm,
vec![ROOT_CANISTER_ID.get(), SNS_WASM_CANISTER_ID.get()],
)
.await;
let internet_identity_payload: Option<()> = None;
install_canister_with_controllers(
pocket_ic,
"internet-identity",
IDENTITY_CANISTER_ID,
Encode!(&internet_identity_payload).unwrap(),
internet_identity_wasm,
vec![ROOT_CANISTER_ID.get()],
)
.await;
// TODO @rvem: perhaps, we may start using configurable endpoint for the IC http interface
// which should be considered in NNS dapp configuration.
let endpoint = "localhost:8080";
let nns_dapp_payload = NnsDappPayload {
args: vec![
("API_HOST".to_string(), format!("http://{}", endpoint)),
(
"CYCLES_MINTING_CANISTER_ID".to_string(),
CYCLES_MINTING_CANISTER_ID.get().to_string(),
),
("DFX_NETWORK".to_string(), "local".to_string()),
(
"FEATURE_FLAGS".to_string(),
"{\"ENABLE_CKBTC\":false,\"ENABLE_CKTESTBTC\":false}".to_string(),
),
("FETCH_ROOT_KEY".to_string(), "true".to_string()),
(
"GOVERNANCE_CANISTER_ID".to_string(),
GOVERNANCE_CANISTER_ID.get().to_string(),
),
("HOST".to_string(), format!("http://{}", endpoint)),
(
"IDENTITY_SERVICE_URL".to_string(),
format!("http://{}.{}", IDENTITY_CANISTER_ID.get(), endpoint),
),
(
"LEDGER_CANISTER_ID".to_string(),
LEDGER_CANISTER_ID.get().to_string(),
),
(
"OWN_CANISTER_ID".to_string(),
NNS_UI_CANISTER_ID.get().to_string(),
),
(
"ROBOTS".to_string(),
"<meta name=\"robots\" content=\"noindex, nofollow\" />".to_string(),
),
(
"SNS_AGGREGATOR_URL".to_string(),
format!("http://{}.{}", SNS_AGGREGATOR_CANISTER_ID.get(), endpoint),
),
("STATIC_HOST".to_string(), format!("http://{}", endpoint)),
(
"WASM_CANISTER_ID".to_string(),
SNS_WASM_CANISTER_ID.get().to_string(),
),
(
"INDEX_CANISTER_ID".to_string(),
LEDGER_INDEX_CANISTER_ID.get().to_string(),
),
],
};
install_canister_with_controllers(
pocket_ic,
"nns-dapp",
NNS_UI_CANISTER_ID,
Encode!(&nns_dapp_payload).unwrap(),
nns_dapp_wasm,
vec![ROOT_CANISTER_ID.get()],
)
.await;
}
14 changes: 14 additions & 0 deletions rs/sns/testing/tests/sns_testing_ci.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use ic_sns_testing::pocket_ic::bootstrap_nns;
use pocket_ic::PocketIcBuilder;

#[tokio::test]
async fn test_sns_testing_pocket_ic() {
let pocket_ic = PocketIcBuilder::new()
.with_nns_subnet()
.with_sns_subnet()
.with_ii_subnet()
.with_application_subnet()
.build_async()
.await;
bootstrap_nns(&pocket_ic).await;
}

0 comments on commit 4214bb7

Please sign in to comment.