Skip to content
Snippets Groups Projects
Commit a1dc9fd3 authored by Éloïs's avatar Éloïs
Browse files

chore: refactor end2end tests archi, detect node readiness with logs

parent 5f41c4e6
No related branches found
No related tags found
1 merge request!29chore: refactor end2end tests archi, detect node readiness with logs
Showing
with 304 additions and 159 deletions
[alias] [alias]
cucumber = "test -p duniter-integration-tests --test cucumber_tests --" cucumber = "test -p duniter-end2end-tests --test cucumber_tests --"
tu = "test --workspace --exclude duniter-integration-tests" tu = "test --workspace --exclude duniter-end2end-tests"
...@@ -20,3 +20,9 @@ build ...@@ -20,3 +20,9 @@ build
# Temporary files # Temporary files
tmp tmp
# Local chain spec
*local-spec*.json
# Log files
*.log
...@@ -93,7 +93,7 @@ build_debug_with_cache: ...@@ -93,7 +93,7 @@ build_debug_with_cache:
build_release: build_release:
extends: .env extends: .env
rules: rules:
- if: '$CI_COMMIT_TAG || $CI_COMMIT_BRANCH =~ /^release/' - if: "$CI_COMMIT_TAG || $CI_COMMIT_BRANCH =~ /^release/"
- when: never - when: never
stage: build stage: build
script: script:
...@@ -117,9 +117,9 @@ tests_debug: ...@@ -117,9 +117,9 @@ tests_debug:
stage: tests stage: tests
variables: variables:
DUNITER_BINARY_PATH: "../build/duniter" DUNITER_BINARY_PATH: "../build/duniter"
DUNITER_INTEGRATION_TESTS_SPAWN_NODE_DURATION: "20" DUNITER_END2END_TESTS_SPAWN_NODE_TIMEOUT: "20"
script: script:
- cargo test --workspace --exclude duniter-integration-tests - cargo test --workspace --exclude duniter-end2end-tests
- cargo cucumber -i balance* - cargo cucumber -i balance*
- cargo cucumber -i monetary* - cargo cucumber -i monetary*
- cargo cucumber -i transfer* - cargo cucumber -i transfer*
...@@ -127,14 +127,14 @@ tests_debug: ...@@ -127,14 +127,14 @@ tests_debug:
tests_release: tests_release:
extends: .env extends: .env
rules: rules:
- if: '$CI_COMMIT_TAG || $CI_COMMIT_BRANCH =~ /^release/' - if: "$CI_COMMIT_TAG || $CI_COMMIT_BRANCH =~ /^release/"
- when: never - when: never
stage: tests stage: tests
variables: variables:
DUNITER_BINARY_PATH: "../build/duniter" DUNITER_BINARY_PATH: "../build/duniter"
DUNITER_INTEGRATION_TESTS_SPAWN_NODE_DURATION: "10" DUNITER_INTEGRATION_TESTS_SPAWN_NODE_DURATION: "10"
script: script:
- cargo test --workspace --exclude duniter-integration-tests - cargo test --workspace --exclude duniter-end2end-tests
- cargo cucumber -i monetary* - cargo cucumber -i monetary*
- cargo cucumber -i *transfer* - cargo cucumber -i *transfer*
dependencies: dependencies:
......
This diff is collapsed.
...@@ -106,7 +106,7 @@ substrate-frame-rpc-system = { git = "https://github.com/librelois/substrate.git ...@@ -106,7 +106,7 @@ substrate-frame-rpc-system = { git = "https://github.com/librelois/substrate.git
resolver = "2" resolver = "2"
members = [ members = [
'integration-tests', 'end2end-tests',
'pallets/certification', 'pallets/certification',
'pallets/duniter-test-parameters', 'pallets/duniter-test-parameters',
'pallets/duniter-test-parameters/macro', 'pallets/duniter-test-parameters/macro',
......
[package] [package]
authors = ['Axiom-Team Developers <https://axiom-team.fr>'] authors = ['Axiom-Team Developers <https://axiom-team.fr>']
description = 'duniter integration tests.' description = 'duniter end2end tests.'
edition = '2018' edition = '2018'
homepage = 'https://substrate.dev' homepage = 'https://substrate.dev'
license = 'AGPL-3.0' license = 'AGPL-3.0'
name = 'duniter-integration-tests' name = 'duniter-end2end-tests'
repository = 'https://git.duniter.org/nodes/rust/duniter-v2s' repository = 'https://git.duniter.org/nodes/rust/duniter-v2s'
version = '3.0.0' version = '3.0.0'
...@@ -12,6 +12,7 @@ version = '3.0.0' ...@@ -12,6 +12,7 @@ version = '3.0.0'
async-trait = "0.1" async-trait = "0.1"
cucumber = "0.11" cucumber = "0.11"
env_logger = "0.9.0" env_logger = "0.9.0"
notify = "4.0"
parity-scale-codec = "2.3.1" parity-scale-codec = "2.3.1"
portpicker = "0.1.1" portpicker = "0.1.1"
serde_json = "1.0.64" serde_json = "1.0.64"
......
File moved
File moved
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>. // along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.
#![allow(clippy::enum_variant_names)] #![allow(clippy::enum_variant_names, dead_code, unused_imports)]
pub mod balances; pub mod balances;
...@@ -23,7 +23,9 @@ pub mod node_runtime {} ...@@ -23,7 +23,9 @@ pub mod node_runtime {}
use serde_json::Value; use serde_json::Value;
use sp_keyring::AccountKeyring; use sp_keyring::AccountKeyring;
use std::io::prelude::*;
use std::process::Command; use std::process::Command;
use std::str::FromStr;
use subxt::{ClientBuilder, DefaultConfig, DefaultExtra}; use subxt::{ClientBuilder, DefaultConfig, DefaultExtra};
pub type Api = node_runtime::RuntimeApi<DefaultConfig, DefaultExtra<DefaultConfig>>; pub type Api = node_runtime::RuntimeApi<DefaultConfig, DefaultExtra<DefaultConfig>>;
...@@ -40,41 +42,23 @@ impl Drop for Process { ...@@ -40,41 +42,23 @@ impl Drop for Process {
} }
} }
struct FullNode {
process: Process,
p2p_port: u16,
ws_port: u16,
}
pub async fn spawn_node() -> (Api, Client, Process) { pub async fn spawn_node() -> (Api, Client, Process) {
let duniter_binary_path = std::env::var("DUNITER_BINARY_PATH") let duniter_binary_path = std::env::var("DUNITER_BINARY_PATH")
.unwrap_or_else(|_| "../target/debug/duniter".to_owned()); .unwrap_or_else(|_| "../target/debug/duniter".to_owned());
let FullNode {
let p2p_port = portpicker::pick_unused_port().expect("No ports free"); process,
let rpc_port = portpicker::pick_unused_port().expect("No ports free"); p2p_port: _,
let ws_port = portpicker::pick_unused_port().expect("No ports free"); ws_port,
let process = Process( } = spawn_full_node(
Command::new(duniter_binary_path) &duniter_binary_path,
.args([ &["--dev", "--execution=Native", "--sealing=manual"],
"--execution=Native",
"--no-telemetry",
"--no-prometheus",
"--dev",
"--sealing=manual",
"--tmp",
"--port",
&p2p_port.to_string(),
"--rpc-port",
&rpc_port.to_string(),
"--ws-port",
&ws_port.to_string(),
])
.spawn()
.expect("failed to spawn node"),
); );
let duration_secs = if let Ok(duration_string) =
std::env::var("DUNITER_INTEGRATION_TESTS_SPAWN_NODE_DURATION")
{
duration_string.parse().unwrap_or(4)
} else {
4
};
std::thread::sleep(std::time::Duration::from_secs(duration_secs));
let client = ClientBuilder::new() let client = ClientBuilder::new()
.set_url(format!("ws://127.0.0.1:{}", ws_port)) .set_url(format!("ws://127.0.0.1:{}", ws_port))
.build() .build()
...@@ -128,3 +112,84 @@ pub async fn create_block_with_extrinsic( ...@@ -128,3 +112,84 @@ pub async fn create_block_with_extrinsic(
.await .await
.map_err(Into::into) .map_err(Into::into)
} }
fn spawn_full_node(duniter_binary_path: &str, args: &[&str]) -> FullNode {
let p2p_port = portpicker::pick_unused_port().expect("No ports free");
let rpc_port = portpicker::pick_unused_port().expect("No ports free");
let ws_port = portpicker::pick_unused_port().expect("No ports free");
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 process = Process(
Command::new(duniter_binary_path)
.args(
[
"--no-telemetry",
"--no-prometheus",
"--tmp",
"--port",
&p2p_port.to_string(),
"--rpc-port",
&rpc_port.to_string(),
"--ws-port",
&ws_port.to_string(),
]
.iter()
.chain(args),
)
.stdout(std::process::Stdio::null())
.stderr(log_file)
.spawn()
.expect("failed to spawn node"),
);
let timeout =
if let Ok(duration_string) = std::env::var("DUNITER_END2END_TESTS_SPAWN_NODE_TIMEOUT") {
duration_string.parse().unwrap_or(4)
} else {
4
};
wait_until_log_line(
"***** Duniter has fully started *****",
&log_file_path,
std::time::Duration::from_secs(timeout),
);
FullNode {
process,
p2p_port,
ws_port,
}
}
fn wait_until_log_line(expected_log_line: &str, log_file_path: &str, timeout: std::time::Duration) {
let (tx, rx) = std::sync::mpsc::channel();
let mut watcher = notify::watcher(tx, std::time::Duration::from_millis(100)).unwrap();
use notify::Watcher as _;
watcher
.watch(&log_file_path, notify::RecursiveMode::NonRecursive)
.unwrap();
let mut pos = 0;
loop {
match rx.recv_timeout(timeout) {
Ok(notify::DebouncedEvent::Write(_)) => {
let mut file = std::fs::File::open(&log_file_path).unwrap();
file.seek(std::io::SeekFrom::Start(pos)).unwrap();
pos = file.metadata().unwrap().len();
let reader = std::io::BufReader::new(file);
for line in reader.lines() {
if line.expect("fail to read line").contains(expected_log_line) {
return;
}
}
}
Ok(_) => {}
Err(err) => {
eprintln!("Error: {:?}", err);
std::process::exit(1);
}
}
}
}
...@@ -170,6 +170,6 @@ async fn main() { ...@@ -170,6 +170,6 @@ async fn main() {
DuniterWorld::cucumber() DuniterWorld::cucumber()
//.fail_on_skipped() //.fail_on_skipped()
.max_concurrent_scenarios(4) .max_concurrent_scenarios(4)
.run_and_exit("features") .run_and_exit("cucumber-features")
.await; .await;
} }
...@@ -206,7 +206,7 @@ fn gen_genesis_conf( ...@@ -206,7 +206,7 @@ fn gen_genesis_conf(
assert!(initial_smiths_len <= initial_identities_len); assert!(initial_smiths_len <= initial_identities_len);
assert!(initial_authorities_len <= initial_smiths_len); assert!(initial_authorities_len <= initial_smiths_len);
let babe_epoch_duration = get_env_u32("DUNITER_BABE_EPOCH_DURATION", 600) as u64; let babe_epoch_duration = get_env_u32("DUNITER_BABE_EPOCH_DURATION", 30) as u64;
let cert_validity_period = get_env_u32("DUNITER_CERT_VALIDITY_PERIOD", 1_000); let cert_validity_period = get_env_u32("DUNITER_CERT_VALIDITY_PERIOD", 1_000);
let membership_period = get_env_u32("DUNITER_MEMBERSHIP_PERIOD", 1_000); let membership_period = get_env_u32("DUNITER_MEMBERSHIP_PERIOD", 1_000);
let membership_renewable_period = get_env_u32("DUNITER_MEMBERSHIP_RENEWABLE_PERIOD", 50); let membership_renewable_period = get_env_u32("DUNITER_MEMBERSHIP_RENEWABLE_PERIOD", 50);
......
...@@ -648,5 +648,8 @@ where ...@@ -648,5 +648,8 @@ where
} }
network_starter.start_network(); network_starter.start_network();
log::info!("***** Duniter has fully started *****");
Ok(task_manager) Ok(task_manager)
} }
No preview for this file type
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment