-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a778d59
commit be734ab
Showing
20 changed files
with
432 additions
and
15 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
[package] | ||
name = "trycp_wind_tunnel_runner" | ||
version = "0.2.0-alpha.2" | ||
description = "Customises the wind_tunnel_runner for Holochain testing" | ||
license = "MIT" | ||
authors = ["ThetaSinner"] | ||
edition = "2021" | ||
categories = ["development-tools::testing", "development-tools::profiling"] | ||
homepage = "https://github.com/holochain/wind-tunnel" | ||
repository = "https://github.com/holochain/wind-tunnel" | ||
|
||
[dependencies] | ||
clap = { workspace = true } | ||
anyhow = { workspace = true } | ||
derive_more = { workspace = true } | ||
serde = { workspace = true } | ||
serde_yaml = { workspace = true } | ||
env_logger = { workspace = true } | ||
log = { workspace = true } | ||
|
||
wind_tunnel_runner = { workspace = true } | ||
trycp_client_instrumented = { workspace = true } | ||
holochain_client = { workspace = true } | ||
holochain_types = { workspace = true } | ||
wind_tunnel_core = { workspace = true } | ||
|
||
[lints] | ||
workspace = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
use clap::Parser; | ||
use serde::Deserialize; | ||
use std::path::PathBuf; | ||
use wind_tunnel_runner::parse_agent_behaviour; | ||
use wind_tunnel_runner::prelude::{ReporterOpt, WindTunnelScenarioCli}; | ||
|
||
#[derive(Deserialize)] | ||
struct Targets { | ||
nodes: Vec<String>, | ||
} | ||
|
||
#[derive(Parser)] | ||
#[command(about, long_about = None)] | ||
pub struct WindTunnelTryCPScenarioCli { | ||
/// Path to the targets file to use. | ||
/// | ||
/// Should be a YAML file with a `nodes` field containing a list of TryCP targets. | ||
#[clap(long)] | ||
pub targets: PathBuf, | ||
|
||
/// Assign a behaviour to a number of agents. Specify the behaviour and number of agents to assign | ||
/// it to in the format `behaviour:count`. For example `--behaviour=login:5`. | ||
/// | ||
/// Specifying the count is optional and will default to 1. This is a useful default if you want to | ||
/// run distributed tests and want a single agent to use a single behaviour on that node. | ||
/// | ||
/// You can specify multiple behaviours by using the flag multiple times. For example `--behaviour=add_to_list:5 --behaviour=favourite_items:5`. | ||
/// | ||
/// For however many agents you assign to behaviours in total, it must be less than or equal to the total number of agents for this scenario. | ||
/// If it is less than the total number of agents then the remaining agents will be assigned the default behaviour. | ||
/// | ||
/// If the configuration is invalid then the scenario will fail to start. | ||
#[clap(long, short, value_parser = parse_agent_behaviour)] | ||
pub behaviour: Vec<(String, usize)>, | ||
|
||
/// The number of seconds to run the scenario for | ||
#[clap(long)] | ||
pub duration: Option<u64>, | ||
|
||
/// Run this test as a soak test, ignoring any configured duration and continuing to run until stopped | ||
#[clap(long, default_value = "false")] | ||
pub soak: bool, | ||
|
||
/// Do not show a progress bar on the CLI. | ||
/// | ||
/// This is recommended for CI/CD environments where the progress bar isn't being looked at by anyone and is just adding noise to the logs. | ||
#[clap(long, default_value = "false")] | ||
pub no_progress: bool, | ||
|
||
/// The reporter to use. | ||
#[arg(long, value_enum, default_value_t = ReporterOpt::InMemory)] | ||
pub reporter: ReporterOpt, | ||
} | ||
|
||
impl TryInto<WindTunnelScenarioCli> for WindTunnelTryCPScenarioCli { | ||
type Error = anyhow::Error; | ||
|
||
fn try_into(self) -> Result<WindTunnelScenarioCli, Self::Error> { | ||
let targets = std::fs::read_to_string(&self.targets)?; | ||
let targets: Targets = serde_yaml::from_str(&targets)?; | ||
|
||
Ok(WindTunnelScenarioCli { | ||
// Connection string is already forwarded but is supposed to be a single value. | ||
// Pack values together and extract by agent id in helpers. | ||
connection_string: targets.nodes.join(","), | ||
agents: Some(targets.nodes.len()), | ||
behaviour: self.behaviour, | ||
duration: self.duration, | ||
soak: self.soak, | ||
no_progress: self.no_progress, | ||
reporter: self.reporter, | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
use crate::context::TryCPAgentContext; | ||
use crate::runner_context::TryCPRunnerContext; | ||
use std::sync::Arc; | ||
use trycp_client_instrumented::prelude::TryCPClient; | ||
use wind_tunnel_runner::prelude::{AgentContext, HookResult, UserValuesConstraint}; | ||
|
||
/// Connects to a TryCP server using the current agent index and the list of targets. | ||
/// | ||
/// Call this function as follows: | ||
/// ```rust | ||
/// use std::path::Path; | ||
/// use trycp_wind_tunnel_runner::prelude::{AgentContext, connect_trycp_client, HookResult, TryCPAgentContext, TryCPRunnerContext}; | ||
/// | ||
/// fn agent_setup(ctx: &mut AgentContext<TryCPRunnerContext, TryCPAgentContext>) -> HookResult { | ||
/// connect_trycp_client(ctx)?; | ||
/// Ok(()) | ||
/// } | ||
/// ``` | ||
pub fn connect_trycp_client<SV: UserValuesConstraint>( | ||
ctx: &mut AgentContext<TryCPRunnerContext, TryCPAgentContext<SV>>, | ||
) -> HookResult { | ||
let agent_index = ctx.agent_index(); | ||
|
||
let target = ctx | ||
.runner_context() | ||
.get_connection_string() | ||
.split(',') | ||
.nth(agent_index); | ||
|
||
// This should never happen because the behaviour assignment should have checked that there were enough agents. | ||
let target = target | ||
.ok_or_else(|| anyhow::anyhow!("Not enough targets to pick a target URL for agent",))?; | ||
|
||
let signer = Arc::new(holochain_client::ClientAgentSigner::default()); | ||
let reporter = ctx.runner_context().reporter(); | ||
|
||
let client = ctx.runner_context().executor().execute_in_place({ | ||
let signer = signer.clone(); | ||
async move { Ok(TryCPClient::connect(target, signer.clone(), reporter).await?) } | ||
})?; | ||
|
||
ctx.get_mut().trycp_client = Some(client); | ||
ctx.get_mut().signer = Some(signer); | ||
|
||
Ok(()) | ||
} | ||
|
||
pub fn reset_trycp_remote( | ||
ctx: &mut AgentContext<TryCPRunnerContext, TryCPAgentContext>, | ||
) -> HookResult { | ||
let client = ctx.get().trycp_client(); | ||
|
||
ctx.runner_context() | ||
.executor() | ||
.execute_in_place(async move { | ||
client.reset(None).await?; | ||
Ok(()) | ||
})?; | ||
|
||
Ok(()) | ||
} | ||
|
||
pub fn disconnect_trycp_client<SV: UserValuesConstraint>( | ||
ctx: &mut AgentContext<TryCPRunnerContext, TryCPAgentContext<SV>>, | ||
) -> HookResult { | ||
let client = ctx.get_mut().take_trycp_client(); | ||
|
||
ctx.runner_context() | ||
.executor() | ||
.execute_in_place(async move { | ||
// The drop implementation requires launching a new task, so drop inside an async context. | ||
// Could also do a `runtime.enter` here but that's deliberately not exposed by the runner. | ||
drop(client); | ||
Ok(()) | ||
})?; | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
use holochain_client::ClientAgentSigner; | ||
use std::collections::HashMap; | ||
use std::fmt::Debug; | ||
use std::sync::Arc; | ||
use trycp_client_instrumented::prelude::TryCPClient; | ||
use trycp_client_instrumented::TryCPClientInstrumented; | ||
use wind_tunnel_runner::prelude::UserValuesConstraint; | ||
|
||
#[derive(Debug, Default)] | ||
pub struct DefaultScenarioValues { | ||
pub values: HashMap<String, String>, | ||
} | ||
|
||
impl UserValuesConstraint for DefaultScenarioValues {} | ||
|
||
/// Holochain-specific context values for the [wind_tunnel_runner::prelude::AgentContext]. | ||
#[derive(Default, Debug)] | ||
pub struct TryCPAgentContext<T: UserValuesConstraint = DefaultScenarioValues> { | ||
pub(crate) signer: Option<Arc<ClientAgentSigner>>, | ||
pub(crate) trycp_client: Option<TryCPClient>, | ||
pub scenario_values: T, | ||
} | ||
|
||
impl<T: UserValuesConstraint> UserValuesConstraint for TryCPAgentContext<T> {} | ||
|
||
impl<T: UserValuesConstraint> TryCPAgentContext<T> { | ||
/// Get the [ClientAgentSigner] that was configured during agent setup. | ||
pub fn signer(&self) -> Arc<ClientAgentSigner> { | ||
self.signer.clone().expect( | ||
"signer is not set, did you forget to call `connect_trycp_client` in your agent_setup?", | ||
) | ||
} | ||
|
||
/// Get the [TryCPClient] that was configured during agent setup. | ||
pub fn trycp_client(&self) -> TryCPClient { | ||
self.trycp_client.clone().expect( | ||
"trycp_client is not set, did you forget to call `connect_trycp_client` in your agent_setup?", | ||
) | ||
} | ||
|
||
/// Close the TryCP client by dropping it. | ||
/// | ||
/// Calling [TryCPAgentContext::trycp_client] after this function, or this function again after, will panic. | ||
pub fn take_trycp_client(&mut self) -> TryCPClientInstrumented { | ||
self.trycp_client.take().expect("trycp_client is not set") | ||
} | ||
} |
Oops, something went wrong.