Skip to content
Snippets Groups Projects
Commit 422cb565 authored by Pascal Engélibert's avatar Pascal Engélibert :bicyclist: Committed by Pascal Engélibert
Browse files

test(distance): WiP end2end test

parent a9cdbdbe
No related branches found
No related tags found
1 merge request!105Distance Oracle
Feature: Distance
Scenario: Alice certifies Eve
When alice sends 6 ĞD to dave
When 15 blocks later
When alice creates identity for dave
Then dave identity should be created
Then dave should be certified by alice
When dave confirms his identity with pseudo "dave"
Then dave identity should be confirmed
When bob certifies dave
Then dave should be certified by bob
When alice requests distance evaluation for dave
Then dave should have distance result in 2 sessions
When 30 blocks later
Then dave should have distance result in 1 session
When distance oracle runs
Then dave should have distance result in 1 session
When 30 blocks later
Then dave should have distance result in 0 session
Then dave should have distance ok
When alice validates dave identity
When 3 blocks later
Then dave identity should be validated
// Copyright 2023 Axiom-Team
//
// This file is part of Duniter-v2S.
//
// Duniter-v2S is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, version 3 of the License.
//
// Duniter-v2S is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>.
use super::gdev;
use super::gdev::runtime_types::pallet_identity;
use super::*;
use crate::DuniterWorld;
use sp_keyring::AccountKeyring;
use subxt::tx::PairSigner;
pub async fn request_evaluation(client: &Client, from: AccountKeyring, to: u32) -> Result<()> {
let from = PairSigner::new(from.pair());
let _events = create_block_with_extrinsic(
client,
client
.tx()
.create_signed(
&gdev::tx().distance().evaluate_distance(to),
&from,
BaseExtrinsicParamsBuilder::new(),
)
.await?,
)
.await?;
Ok(())
}
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
pub mod balances; pub mod balances;
pub mod cert; pub mod cert;
pub mod distance;
pub mod identity; pub mod identity;
pub mod oneshot; pub mod oneshot;
...@@ -86,6 +87,7 @@ impl Process { ...@@ -86,6 +87,7 @@ impl Process {
} }
} }
pub const DISTANCE_ORACLE_LOCAL_PATH: &str = "../target/debug/distance-oracle";
const DUNITER_DOCKER_PATH: &str = "/usr/local/bin/duniter"; const DUNITER_DOCKER_PATH: &str = "/usr/local/bin/duniter";
const DUNITER_LOCAL_PATH: &str = "../target/debug/duniter"; const DUNITER_LOCAL_PATH: &str = "../target/debug/duniter";
...@@ -95,7 +97,7 @@ struct FullNode { ...@@ -95,7 +97,7 @@ struct FullNode {
ws_port: u16, ws_port: u16,
} }
pub async fn spawn_node(maybe_genesis_conf_file: Option<PathBuf>) -> (Client, Process) { pub async fn spawn_node(maybe_genesis_conf_file: Option<PathBuf>) -> (Client, Process, u16) {
println!("maybe_genesis_conf_file={:?}", maybe_genesis_conf_file); println!("maybe_genesis_conf_file={:?}", maybe_genesis_conf_file);
let duniter_binary_path = std::env::var("DUNITER_BINARY_PATH").unwrap_or_else(|_| { let duniter_binary_path = std::env::var("DUNITER_BINARY_PATH").unwrap_or_else(|_| {
if std::path::Path::new(DUNITER_DOCKER_PATH).exists() { if std::path::Path::new(DUNITER_DOCKER_PATH).exists() {
...@@ -118,7 +120,7 @@ pub async fn spawn_node(maybe_genesis_conf_file: Option<PathBuf>) -> (Client, Pr ...@@ -118,7 +120,7 @@ pub async fn spawn_node(maybe_genesis_conf_file: Option<PathBuf>) -> (Client, Pr
.await .await
.expect("fail to connect to node"); .expect("fail to connect to node");
(client, process) (client, process, ws_port)
} }
pub async fn create_empty_block(client: &Client) -> Result<()> { pub async fn create_empty_block(client: &Client) -> Result<()> {
...@@ -174,6 +176,9 @@ fn spawn_full_node( ...@@ -174,6 +176,9 @@ fn spawn_full_node(
let log_file_path = format!("duniter-v2s-{}.log", ws_port); let log_file_path = format!("duniter-v2s-{}.log", ws_port);
let log_file = std::fs::File::create(&log_file_path).expect("fail to create log file"); let log_file = std::fs::File::create(&log_file_path).expect("fail to create log file");
// Clean previous data
std::fs::remove_dir_all("/tmp/duniter-cucumber").ok();
// Command // Command
let process = Process( let process = Process(
Command::new(duniter_binary_path) Command::new(duniter_binary_path)
...@@ -181,13 +186,14 @@ fn spawn_full_node( ...@@ -181,13 +186,14 @@ fn spawn_full_node(
[ [
"--no-telemetry", "--no-telemetry",
"--no-prometheus", "--no-prometheus",
"--tmp",
"--port", "--port",
&p2p_port.to_string(), &p2p_port.to_string(),
"--rpc-port", "--rpc-port",
&rpc_port.to_string(), &rpc_port.to_string(),
"--ws-port", "--ws-port",
&ws_port.to_string(), &ws_port.to_string(),
"--base-path",
"/tmp/duniter-cucumber",
] ]
.iter() .iter()
.chain(args), .chain(args),
...@@ -280,3 +286,22 @@ fn has_log_line(log_file_path: &str, expected_log_line: &str) -> bool { ...@@ -280,3 +286,22 @@ fn has_log_line(log_file_path: &str, expected_log_line: &str) -> bool {
} }
false false
} }
pub fn spawn_distance_oracle(distance_oracle_binary_path: &str, duniter_rpc_port: u16) {
Command::new(distance_oracle_binary_path)
.args(
[
"-u",
&format!("ws://127.0.0.1:{duniter_rpc_port}"),
"-d",
"/tmp/duniter-cucumber/chains/gdev/distance",
"-c",
"2",
]
.iter(),
)
.spawn()
.expect("failed to spawn distance oracle")
.wait()
.unwrap();
}
...@@ -120,12 +120,17 @@ impl World for DuniterWorld { ...@@ -120,12 +120,17 @@ impl World for DuniterWorld {
struct DuniterWorldInner { struct DuniterWorldInner {
client: Client, client: Client,
process: Process, process: Process,
ws_port: u16,
} }
impl DuniterWorldInner { impl DuniterWorldInner {
async fn new(maybe_genesis_conf_file: Option<PathBuf>) -> Self { async fn new(maybe_genesis_conf_file: Option<PathBuf>) -> Self {
let (client, process) = spawn_node(maybe_genesis_conf_file).await; let (client, process, ws_port) = spawn_node(maybe_genesis_conf_file).await;
DuniterWorldInner { client, process } DuniterWorldInner {
client,
process,
ws_port,
}
} }
fn kill(&mut self) { fn kill(&mut self) {
self.process.kill(); self.process.kill();
...@@ -322,6 +327,28 @@ async fn validate_identity(world: &mut DuniterWorld, from: String, to: String) - ...@@ -322,6 +327,28 @@ async fn validate_identity(world: &mut DuniterWorld, from: String, to: String) -
common::identity::validate_identity(world.client(), from, to).await common::identity::validate_identity(world.client(), from, to).await
} }
#[when(regex = r#"([a-zA-Z]+) requests distance evaluation for ([a-zA-Z]+)"#)]
async fn request_distance_evaluation(
world: &mut DuniterWorld,
from: String,
to: String,
) -> Result<()> {
// input names to keyrings
let from = AccountKeyring::from_str(&from).expect("unknown from");
let to: u32 = common::identity::get_identity_index(world, to).await?;
common::distance::request_evaluation(world.client(), from, to).await
}
#[when(regex = r#"distance oracle runs"#)]
async fn run_distance_oracle(world: &mut DuniterWorld) -> Result<()> {
common::spawn_distance_oracle(
common::DISTANCE_ORACLE_LOCAL_PATH,
world.inner.as_ref().unwrap().ws_port,
);
Ok(())
}
// ===== then ==== // ===== then ====
#[then(regex = r"([a-zA-Z]+) should have (\d+) (ĞD|cĞD)")] #[then(regex = r"([a-zA-Z]+) should have (\d+) (ĞD|cĞD)")]
...@@ -437,6 +464,66 @@ async fn should_be_certified_by( ...@@ -437,6 +464,66 @@ async fn should_be_certified_by(
} }
} }
#[then(regex = r"([a-zA-Z]+) should have distance result in (\d+) sessions?")]
async fn should_have_distance_result_in_sessions(
world: &mut DuniterWorld,
who: String,
sessions: u32,
) -> Result<()> {
assert!(sessions < 3, "Session number must be < 3");
let who = AccountKeyring::from_str(&who).unwrap().to_account_id();
let idty_id = world
.read(&gdev::storage().identity().identity_index_of(&who))
.await?
.unwrap();
let current_session = world
.read(&gdev::storage().session().current_index())
.await?
.unwrap_or_default();
let pool = world
.read(&match (current_session + sessions) % 3 {
0 => gdev::storage().distance().evaluation_pool0(),
1 => gdev::storage().distance().evaluation_pool1(),
2 => gdev::storage().distance().evaluation_pool2(),
_ => unreachable!("n%3<3"),
})
.await
.unwrap()
.ok_or_else(|| anyhow::anyhow!("given pool is empty"))?;
for (sample_idty, _) in pool.0 .0 {
if sample_idty == idty_id {
return Ok(());
}
}
Err(anyhow::anyhow!("no evaluation in given pool").into())
}
#[then(regex = r"([a-zA-Z]+) should have distance ok")]
async fn should_have_distance_ok(world: &mut DuniterWorld, who: String) -> Result<()> {
let who = AccountKeyring::from_str(&who).unwrap().to_account_id();
let idty_id = world
.read(&gdev::storage().identity().identity_index_of(&who))
.await?
.unwrap();
if world
.read(&gdev::storage().distance().distance_ok_identities(&idty_id))
.await?
.unwrap()
{
Ok(())
} else {
Err(anyhow::anyhow!("no evaluation in given pool").into())
}
}
use gdev::runtime_types::pallet_identity::types::IdtyStatus; use gdev::runtime_types::pallet_identity::types::IdtyStatus;
// status from string // status from string
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment