Skip to content

Commit

Permalink
Merge pull request #96 from paritytech/refactor/provider-trait
Browse files Browse the repository at this point in the history
Refactor of ```Provider``` trait into ```Provider```, ```ProviderNamespace``` and ```ProviderNode```
  • Loading branch information
l0r1s authored Sep 26, 2023
2 parents fe91d05 + 7f72964 commit 656f56c
Show file tree
Hide file tree
Showing 19 changed files with 3,071 additions and 1,191 deletions.
11 changes: 8 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,12 @@ jobs:
- name: Build
run: cargo build

- name: Tests
run: cargo test
- name: Tests (except provider crate)
run: cargo test --workspace --exclude provider

- name: Tests (provider crate)
# there should be a unique test thread for native provider tests (asserting spawned processes count)
run: cargo test -p provider -- --test-threads 1

coverage:
name: Zombienet SDK - coverage
Expand All @@ -60,7 +64,8 @@ jobs:
uses: taiki-e/install-action@cargo-llvm-cov

- name: Collect coverage data
run: cargo llvm-cov nextest --lcov --output-path lcov.info
# there should be a unique test thread for native provider tests (asserting spawned processes count)
run: cargo llvm-cov nextest -j 1 --lcov --output-path lcov.info

- name: Report code coverage
uses: Nef10/[email protected]
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/documentation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,15 @@ jobs:
cargo doc --no-deps
echo "<meta http-equiv=\"refresh\" content=\"0; url=configuration\">" > target/doc/index.html
- name: Move docs
run: |
mkdir -p ./doc
mv ./target/doc/* ./doc
git config user.email "[email protected]"
git config user.name "GitHub Action"
git config user.password ${{ secrets.GH_PAGES_TOKEN }}
git config user.password "${{ secrets.GH_PAGES_TOKEN }}"
git checkout --orphan gh-pages
mkdir to_delete
shopt -s extglob
Expand Down
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,6 @@ regex = "1.8"
lazy_static = "1.4"
multiaddr = "0.18"
url = "2.3"
uuid = "1.4"
nix = "0.27"
procfs = "0.15"
2 changes: 2 additions & 0 deletions crates/configuration/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ pub use hrmp_channel::{HrmpChannelConfig, HrmpChannelConfigBuilder};
pub use network::{NetworkConfig, NetworkConfigBuilder};
pub use parachain::{ParachainConfig, ParachainConfigBuilder};
pub use relaychain::{RelaychainConfig, RelaychainConfigBuilder};
// re-export shared
pub use shared::{node::NodeConfig, types};
22 changes: 17 additions & 5 deletions crates/provider/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,23 @@ edition = "2021"
[dependencies]
support = { path = "../support" }
configuration = { path = "../configuration" }
async-trait = {workspace = true }
futures = {workspace = true }
async-trait = { workspace = true }
futures = { workspace = true }
#napi = { version="2.12.7", features=["async"]}
#napi-derive = "2.12.5"
serde = { workspace = true, features = ["derive"] }
serde_json = {workspace = true}
tokio = { workspace = true, features = ["process", "macros", "fs", "time", "rt"] }
thiserror = {workspace = true}
serde_json = { workspace = true }
tokio = { workspace = true, features = [
"process",
"macros",
"fs",
"time",
"rt",
] }
thiserror = { workspace = true }
anyhow = { workspace = true }
uuid = { workspace = true, features = ["v4"] }
nix = { workspace = true, features = ["signal"] }

[dev-dependencies]
procfs = { workspace = true }
45 changes: 0 additions & 45 deletions crates/provider/src/errors.rs

This file was deleted.

204 changes: 121 additions & 83 deletions crates/provider/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,94 +1,132 @@
mod errors;
mod native;
mod shared;
pub mod native;
pub mod shared;

use std::{net::IpAddr, path::PathBuf};
use std::{
collections::HashMap, net::IpAddr, path::PathBuf, process::ExitStatus, sync::Arc,
time::Duration,
};

use async_trait::async_trait;
use errors::ProviderError;
use shared::types::{FileMap, NativeRunCommandOptions, PodDef, Port, RunCommandResponse};
use shared::types::{
GenerateFileCommand, GenerateFilesOptions, ProviderCapabilities, RunCommandOptions,
RunScriptOptions, SpawnNodeOptions,
};
use support::fs::FileSystemError;

use crate::shared::types::Port;

#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum ProviderError {
#[error("Failed to spawn node '{0}': {1}")]
NodeSpawningFailed(String, anyhow::Error),

#[error("Error running command '{0}': {1}")]
RunCommandError(String, anyhow::Error),

#[error("Duplicated node name: {0}")]
DuplicatedNodeName(String),

#[error(transparent)]
FileSystemError(#[from] FileSystemError),

#[error("Invalid script path for {0}")]
InvalidScriptPath(anyhow::Error),

#[error("Script with path {0} not found")]
ScriptNotFound(PathBuf),

#[error("File generation failed: {0}")]
FileGenerationFailed(anyhow::Error),

#[error("Failed to retrieve process ID for node '{0}'")]
ProcessIdRetrievalFailed(String),

#[error("Failed to pause node '{0}'")]
PauseNodeFailed(String),

#[error("Failed to resume node '{0}'")]
ResumeNodeFaied(String),

#[error("Failed to kill node '{0}'")]
KillNodeFailed(String),
}

#[async_trait]
pub trait Provider {
async fn create_namespace(&mut self) -> Result<(), ProviderError>;
async fn get_node_ip(&self) -> Result<IpAddr, ProviderError>;
async fn get_port_mapping(
&mut self,
port: Port,
pod_name: String,
) -> Result<Port, ProviderError>;
async fn get_node_info(&mut self, pod_name: String) -> Result<(IpAddr, Port), ProviderError>;
fn capabilities(&self) -> &ProviderCapabilities;

async fn namespaces(&self) -> HashMap<String, DynNamespace>;

async fn create_namespace(&self) -> Result<DynNamespace, ProviderError>;
}

pub type DynProvider = Arc<dyn Provider>;

#[async_trait]
pub trait ProviderNamespace {
fn id(&self) -> &str;

fn base_dir(&self) -> &PathBuf;

async fn nodes(&self) -> HashMap<String, DynNode>;

async fn spawn_node(&self, options: SpawnNodeOptions) -> Result<DynNode, ProviderError>;

async fn generate_files(&self, options: GenerateFilesOptions) -> Result<(), ProviderError>;

async fn destroy(&self) -> Result<(), ProviderError>;

async fn static_setup(&self) -> Result<(), ProviderError>;
}

pub type DynNamespace = Arc<dyn ProviderNamespace>;

type ExecutionResult = Result<String, (ExitStatus, String)>;

#[async_trait]
pub trait ProviderNode {
fn name(&self) -> &str;

fn base_dir(&self) -> &PathBuf;

fn config_dir(&self) -> &PathBuf;

fn data_dir(&self) -> &PathBuf;

fn scripts_dir(&self) -> &PathBuf;

fn log_path(&self) -> &PathBuf;

async fn endpoint(&self) -> Result<(IpAddr, Port), ProviderError>;

async fn mapped_port(&self, port: Port) -> Result<Port, ProviderError>;

async fn logs(&self) -> Result<String, ProviderError>;

async fn dump_logs(&self, local_dest: PathBuf) -> Result<(), ProviderError>;

async fn run_command(
&self,
args: Vec<String>,
opts: NativeRunCommandOptions,
) -> Result<RunCommandResponse, ProviderError>;
async fn run_script(
&mut self,
identifier: String,
script_path: String,
args: Vec<String>,
) -> Result<RunCommandResponse, ProviderError>;
async fn spawn_from_def(
&mut self,
pod_def: PodDef,
files_to_copy: Vec<FileMap>,
keystore: String,
chain_spec_id: String,
db_snapshot: String,
) -> Result<(), ProviderError>;
async fn copy_file_from_pod(
&mut self,
pod_file_path: PathBuf,
local_file_path: PathBuf,
) -> Result<(), ProviderError>;
async fn create_resource(
&mut self,
resource_def: PodDef,
scoped: bool,
wait_ready: bool,
) -> Result<(), ProviderError>;
async fn wait_node_ready(&mut self, node_name: String) -> Result<(), ProviderError>;
async fn get_node_logs(&mut self, node_name: String) -> Result<String, ProviderError>;
async fn dump_logs(&mut self, path: String, pod_name: String) -> Result<(), ProviderError>;
fn get_pause_args(&mut self, name: String) -> Vec<String>;
fn get_resume_args(&mut self, name: String) -> Vec<String>;
async fn restart_node(&mut self, name: String, timeout: u64) -> Result<bool, ProviderError>;
async fn get_help_info(&mut self) -> Result<(), ProviderError>;
async fn destroy_namespace(&mut self) -> Result<(), ProviderError>;
async fn get_logs_command(&mut self, name: String) -> Result<String, ProviderError>;
async fn put_local_magic_file(
options: RunCommandOptions,
) -> Result<ExecutionResult, ProviderError>;

async fn run_script(&self, options: RunScriptOptions)
-> Result<ExecutionResult, ProviderError>;

async fn copy_file_from_node(
&self,
_name: String,
_container: Option<String>,
) -> Result<(), ProviderError> {
Ok(())
}
fn is_pod_monitor_available() -> Result<bool, ProviderError> {
Ok(false)
}
async fn spawn_introspector() -> Result<(), ProviderError> {
Ok(())
}

async fn static_setup() -> Result<(), ProviderError> {
Ok(())
}
async fn create_static_resource() -> Result<(), ProviderError> {
Ok(())
}
async fn create_pod_monitor() -> Result<(), ProviderError> {
Ok(())
}
async fn setup_cleaner() -> Result<(), ProviderError> {
Ok(())
}

#[allow(clippy::diverging_sub_expression)]
async fn upsert_cron_job() -> Result<(), ProviderError> {
unimplemented!();
}
remote_src: PathBuf,
local_dest: PathBuf,
) -> Result<(), ProviderError>;

async fn pause(&self) -> Result<(), ProviderError>;

async fn resume(&self) -> Result<(), ProviderError>;

async fn restart(&self, after: Option<Duration>) -> Result<(), ProviderError>;

async fn destroy(&self) -> Result<(), ProviderError>;
}

// re-exports
pub use native::NativeProvider;
pub type DynNode = Arc<dyn ProviderNode + Send + Sync>;
Loading

0 comments on commit 656f56c

Please sign in to comment.