mirror of
https://github.com/logos-blockchain/logos-blockchain-testing.git
synced 2026-03-31 08:13:48 +00:00
framework: reorganize core module structure
This commit is contained in:
commit
fadc8632e9
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -3348,7 +3348,7 @@ dependencies = [
|
||||
"rcgen",
|
||||
"ring",
|
||||
"rustls 0.23.36",
|
||||
"rustls-webpki 0.103.9",
|
||||
"rustls-webpki 0.103.10",
|
||||
"thiserror 2.0.18",
|
||||
"x509-parser",
|
||||
"yasna",
|
||||
@ -5953,7 +5953,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"rustls-webpki 0.103.9",
|
||||
"rustls-webpki 0.103.10",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
@ -6001,9 +6001,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.103.9"
|
||||
version = "0.103.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53"
|
||||
checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
|
||||
@ -9,7 +9,7 @@ use lb_framework::{
|
||||
};
|
||||
pub use testing_framework_core::scenario::ObservabilityBuilderExt;
|
||||
use testing_framework_core::{
|
||||
scenario::{NodeControlScenarioBuilder, ObservabilityScenarioBuilder},
|
||||
scenario::internal::{NodeControlScenarioBuilder, ObservabilityScenarioBuilder},
|
||||
topology::{DeploymentProvider, DeploymentSeed, DynTopologyError},
|
||||
};
|
||||
use tracing::warn;
|
||||
@ -18,7 +18,7 @@ use crate::LbcExtEnv;
|
||||
|
||||
pub type ScenarioBuilder = testing_framework_core::scenario::ScenarioBuilder<LbcExtEnv>;
|
||||
pub type ScenarioBuilderWith<Caps = ()> =
|
||||
testing_framework_core::scenario::CoreBuilder<LbcExtEnv, Caps>;
|
||||
testing_framework_core::scenario::internal::CoreBuilder<LbcExtEnv, Caps>;
|
||||
|
||||
pub trait CoreBuilderExt: Sized {
|
||||
fn deployment_with(f: impl FnOnce(DeploymentBuilder) -> DeploymentBuilder) -> Self;
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
use reqwest::Url;
|
||||
|
||||
use super::{Application, ObservabilityCapability, ObservabilityScenarioBuilder, ScenarioBuilder};
|
||||
use super::{
|
||||
Application, ObservabilityCapability, ScenarioBuilder, internal::ObservabilityScenarioBuilder,
|
||||
};
|
||||
|
||||
const METRICS_QUERY_URL_FIELD: &str = "metrics_query_url";
|
||||
const METRICS_OTLP_INGEST_URL_FIELD: &str = "metrics_otlp_ingest_url";
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use super::{
|
||||
Application, CleanupPolicy, CoreBuilderAccess, DeploymentPolicy, Expectation,
|
||||
HttpReadinessRequirement, RetryPolicy, Workload,
|
||||
Application, CleanupPolicy, DeploymentPolicy, Expectation, HttpReadinessRequirement,
|
||||
RetryPolicy, Workload, internal::CoreBuilderAccess,
|
||||
};
|
||||
use crate::topology::{DeploymentProvider, DeploymentSeed};
|
||||
|
||||
|
||||
@ -1,184 +1,48 @@
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
use thiserror::Error;
|
||||
use tracing::{debug, info};
|
||||
use tracing::info;
|
||||
|
||||
use super::{
|
||||
Application, ClusterControlProfile, ClusterMode, DeploymentPolicy, DynError, ExistingCluster,
|
||||
ExternalNodeSource, HttpReadinessRequirement, IntoExistingCluster, NodeControlCapability,
|
||||
ObservabilityCapability, RequiresNodeControl,
|
||||
builder_ops::CoreBuilderAccess,
|
||||
expectation::Expectation,
|
||||
runtime::{
|
||||
context::RunMetrics,
|
||||
orchestration::{SourceOrchestrationPlan, SourceOrchestrationPlanError},
|
||||
model::{Scenario, ScenarioBuildError},
|
||||
validation::{
|
||||
build_source_orchestration_plan, enforce_min_duration, expectation_cooldown_for,
|
||||
initialize_components, validate_source_contract,
|
||||
},
|
||||
sources::ScenarioSources,
|
||||
workload::Workload,
|
||||
};
|
||||
use crate::topology::{DeploymentDescriptor, DeploymentProvider, DeploymentSeed, DynTopologyError};
|
||||
|
||||
const MIN_EXPECTATION_FALLBACK_SECS: u64 = 10;
|
||||
const MIN_RUN_DURATION_SECS: u64 = 10;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ScenarioBuildError {
|
||||
#[error("topology build failed: {0}")]
|
||||
Topology(#[source] DynTopologyError),
|
||||
#[error("workload '{name}' failed to initialize")]
|
||||
WorkloadInit { name: String, source: DynError },
|
||||
#[error("expectation '{name}' failed to initialize")]
|
||||
ExpectationInit { name: String, source: DynError },
|
||||
#[error("invalid scenario source configuration: {message}")]
|
||||
SourceConfiguration { message: String },
|
||||
#[error("scenario source mode '{mode}' is not wired into deployers yet")]
|
||||
SourceModeNotWiredYet { mode: &'static str },
|
||||
}
|
||||
|
||||
/// Immutable scenario definition used by the runner, workloads, and
|
||||
/// expectations.
|
||||
pub struct Scenario<E: Application, Caps = ()> {
|
||||
deployment: E::Deployment,
|
||||
workloads: Vec<Arc<dyn Workload<E>>>,
|
||||
expectations: Vec<Box<dyn Expectation<E>>>,
|
||||
duration: Duration,
|
||||
expectation_cooldown: Duration,
|
||||
deployment_policy: DeploymentPolicy,
|
||||
sources: ScenarioSources,
|
||||
source_orchestration_plan: SourceOrchestrationPlan,
|
||||
capabilities: Caps,
|
||||
}
|
||||
|
||||
impl<E: Application, Caps> Scenario<E, Caps> {
|
||||
fn new(
|
||||
deployment: E::Deployment,
|
||||
workloads: Vec<Arc<dyn Workload<E>>>,
|
||||
expectations: Vec<Box<dyn Expectation<E>>>,
|
||||
duration: Duration,
|
||||
expectation_cooldown: Duration,
|
||||
deployment_policy: DeploymentPolicy,
|
||||
sources: ScenarioSources,
|
||||
source_orchestration_plan: SourceOrchestrationPlan,
|
||||
capabilities: Caps,
|
||||
) -> Self {
|
||||
Self {
|
||||
deployment,
|
||||
workloads,
|
||||
expectations,
|
||||
duration,
|
||||
expectation_cooldown,
|
||||
deployment_policy,
|
||||
sources,
|
||||
source_orchestration_plan,
|
||||
capabilities,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn deployment(&self) -> &E::Deployment {
|
||||
&self.deployment
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn workloads(&self) -> &[Arc<dyn Workload<E>>] {
|
||||
&self.workloads
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn expectations(&self) -> &[Box<dyn Expectation<E>>] {
|
||||
&self.expectations
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn expectations_mut(&mut self) -> &mut [Box<dyn Expectation<E>>] {
|
||||
&mut self.expectations
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn duration(&self) -> Duration {
|
||||
self.duration
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn expectation_cooldown(&self) -> Duration {
|
||||
self.expectation_cooldown
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn http_readiness_requirement(&self) -> HttpReadinessRequirement {
|
||||
self.deployment_policy.readiness_requirement
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn deployment_policy(&self) -> DeploymentPolicy {
|
||||
self.deployment_policy
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn existing_cluster(&self) -> Option<&ExistingCluster> {
|
||||
self.sources.existing_cluster()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn cluster_mode(&self) -> ClusterMode {
|
||||
self.sources.cluster_mode()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn cluster_control_profile(&self) -> ClusterControlProfile {
|
||||
self.sources.control_profile()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[doc(hidden)]
|
||||
pub fn attached_source(&self) -> Option<&ExistingCluster> {
|
||||
self.existing_cluster()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn external_nodes(&self) -> &[ExternalNodeSource] {
|
||||
self.sources.external_nodes()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn has_external_nodes(&self) -> bool {
|
||||
!self.sources.external_nodes().is_empty()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn source_orchestration_plan(&self) -> &SourceOrchestrationPlan {
|
||||
&self.source_orchestration_plan
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn capabilities(&self) -> &Caps {
|
||||
&self.capabilities
|
||||
}
|
||||
}
|
||||
use crate::{
|
||||
scenario::{
|
||||
Application, DeploymentPolicy, DynError, ExistingCluster, ExternalNodeSource,
|
||||
HttpReadinessRequirement, IntoExistingCluster, NodeControlCapability,
|
||||
ObservabilityCapability, RequiresNodeControl, builder_ops::CoreBuilderAccess,
|
||||
expectation::Expectation, runtime::context::RunMetrics, sources::ScenarioSources,
|
||||
workload::Workload,
|
||||
},
|
||||
topology::{DeploymentDescriptor, DeploymentProvider, DeploymentSeed},
|
||||
};
|
||||
|
||||
/// Scenario builder entry point.
|
||||
pub struct Builder<E: Application, Caps = ()> {
|
||||
deployment_provider: Box<dyn DeploymentProvider<E::Deployment>>,
|
||||
topology_seed: Option<DeploymentSeed>,
|
||||
workloads: Vec<Box<dyn Workload<E>>>,
|
||||
expectations: Vec<Box<dyn Expectation<E>>>,
|
||||
duration: Duration,
|
||||
expectation_cooldown: Option<Duration>,
|
||||
deployment_policy: DeploymentPolicy,
|
||||
sources: ScenarioSources,
|
||||
capabilities: Caps,
|
||||
pub(super) deployment_provider: Box<dyn DeploymentProvider<E::Deployment>>,
|
||||
pub(super) topology_seed: Option<DeploymentSeed>,
|
||||
pub(super) workloads: Vec<Box<dyn Workload<E>>>,
|
||||
pub(super) expectations: Vec<Box<dyn Expectation<E>>>,
|
||||
pub(super) duration: Duration,
|
||||
pub(super) expectation_cooldown: Option<Duration>,
|
||||
pub(super) deployment_policy: DeploymentPolicy,
|
||||
pub(super) sources: ScenarioSources,
|
||||
pub(super) capabilities: Caps,
|
||||
}
|
||||
|
||||
pub struct ScenarioBuilder<E: Application> {
|
||||
inner: Builder<E, ()>,
|
||||
pub(super) inner: Builder<E, ()>,
|
||||
}
|
||||
|
||||
pub struct NodeControlScenarioBuilder<E: Application> {
|
||||
inner: Builder<E, NodeControlCapability>,
|
||||
pub(super) inner: Builder<E, NodeControlCapability>,
|
||||
}
|
||||
|
||||
pub struct ObservabilityScenarioBuilder<E: Application> {
|
||||
inner: Builder<E, ObservabilityCapability>,
|
||||
pub(super) inner: Builder<E, ObservabilityCapability>,
|
||||
}
|
||||
|
||||
macro_rules! impl_common_builder_methods {
|
||||
@ -432,10 +296,6 @@ impl<E: Application> ScenarioBuilder<E> {
|
||||
self.with_observability()
|
||||
}
|
||||
|
||||
pub fn build(self) -> Result<Scenario<E>, ScenarioBuildError> {
|
||||
self.inner.build()
|
||||
}
|
||||
|
||||
pub(crate) fn with_observability_capability(
|
||||
self,
|
||||
observability: ObservabilityCapability,
|
||||
@ -447,27 +307,15 @@ impl<E: Application> ScenarioBuilder<E> {
|
||||
}
|
||||
|
||||
impl_common_builder_methods!(ScenarioBuilder);
|
||||
|
||||
impl<E: Application> NodeControlScenarioBuilder<E> {
|
||||
pub fn build(self) -> Result<Scenario<E, NodeControlCapability>, ScenarioBuildError> {
|
||||
self.inner.build()
|
||||
}
|
||||
}
|
||||
|
||||
impl_common_builder_methods!(NodeControlScenarioBuilder);
|
||||
impl_common_builder_methods!(ObservabilityScenarioBuilder);
|
||||
|
||||
impl<E: Application> ObservabilityScenarioBuilder<E> {
|
||||
pub fn build(self) -> Result<Scenario<E, ObservabilityCapability>, ScenarioBuildError> {
|
||||
self.inner.build()
|
||||
}
|
||||
|
||||
pub(crate) fn capabilities_mut(&mut self) -> &mut ObservabilityCapability {
|
||||
self.inner.capabilities_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl_common_builder_methods!(ObservabilityScenarioBuilder);
|
||||
|
||||
impl<E: Application, Caps> Builder<E, Caps> {
|
||||
#[must_use]
|
||||
/// Transform the existing deployment provider while preserving all
|
||||
@ -521,36 +369,6 @@ impl<E: Application, Caps> Builder<E, Caps> {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn capabilities(&self) -> &Caps {
|
||||
&self.capabilities
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn capabilities_mut(&mut self) -> &mut Caps {
|
||||
&mut self.capabilities
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn run_duration(&self) -> Duration {
|
||||
self.duration
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn expectation_cooldown_override(&self) -> Option<Duration> {
|
||||
self.expectation_cooldown
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn http_readiness_requirement(&self) -> HttpReadinessRequirement {
|
||||
self.deployment_policy.readiness_requirement
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn deployment_policy(&self) -> DeploymentPolicy {
|
||||
self.deployment_policy
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_deployment_seed(mut self, seed: DeploymentSeed) -> Self {
|
||||
self.topology_seed = Some(seed);
|
||||
@ -796,62 +614,6 @@ impl<E: Application, Caps> BuilderParts<E, Caps> {
|
||||
}
|
||||
}
|
||||
|
||||
fn build_source_orchestration_plan(
|
||||
sources: &ScenarioSources,
|
||||
) -> Result<SourceOrchestrationPlan, ScenarioBuildError> {
|
||||
SourceOrchestrationPlan::try_from_sources(sources).map_err(source_plan_error_to_build_error)
|
||||
}
|
||||
|
||||
fn validate_source_contract<Caps>(sources: &ScenarioSources) -> Result<(), ScenarioBuildError>
|
||||
where
|
||||
Caps: RequiresNodeControl,
|
||||
{
|
||||
validate_external_only_sources(sources)?;
|
||||
|
||||
validate_node_control_profile::<Caps>(sources)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn source_plan_error_to_build_error(error: SourceOrchestrationPlanError) -> ScenarioBuildError {
|
||||
match error {
|
||||
SourceOrchestrationPlanError::SourceModeNotWiredYet { mode } => {
|
||||
ScenarioBuildError::SourceModeNotWiredYet { mode }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_external_only_sources(sources: &ScenarioSources) -> Result<(), ScenarioBuildError> {
|
||||
if matches!(sources.cluster_mode(), ClusterMode::ExternalOnly)
|
||||
&& sources.external_nodes().is_empty()
|
||||
{
|
||||
return Err(ScenarioBuildError::SourceConfiguration {
|
||||
message: "external-only scenarios require at least one external node".to_owned(),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_node_control_profile<Caps>(sources: &ScenarioSources) -> Result<(), ScenarioBuildError>
|
||||
where
|
||||
Caps: RequiresNodeControl,
|
||||
{
|
||||
let profile = sources.control_profile();
|
||||
|
||||
if Caps::REQUIRED && matches!(profile, ClusterControlProfile::ExternalUncontrolled) {
|
||||
return Err(ScenarioBuildError::SourceConfiguration {
|
||||
message: format!(
|
||||
"node control is not available for cluster mode '{}' with control profile '{}'",
|
||||
sources.cluster_mode().as_str(),
|
||||
profile.as_str(),
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl<E: Application> Builder<E, ()> {
|
||||
#[must_use]
|
||||
pub fn with_node_control(self) -> Builder<E, NodeControlCapability> {
|
||||
@ -875,132 +637,3 @@ impl<E: Application> Builder<E, ()> {
|
||||
self.with_observability()
|
||||
}
|
||||
}
|
||||
|
||||
fn initialize_components<E: Application>(
|
||||
descriptors: &E::Deployment,
|
||||
run_metrics: &RunMetrics,
|
||||
workloads: &mut [Box<dyn Workload<E>>],
|
||||
expectations: &mut [Box<dyn Expectation<E>>],
|
||||
) -> Result<(), ScenarioBuildError> {
|
||||
initialize_workloads(descriptors, run_metrics, workloads)?;
|
||||
|
||||
initialize_expectations(descriptors, run_metrics, expectations)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn initialize_workloads<E: Application>(
|
||||
descriptors: &E::Deployment,
|
||||
run_metrics: &RunMetrics,
|
||||
workloads: &mut [Box<dyn Workload<E>>],
|
||||
) -> Result<(), ScenarioBuildError> {
|
||||
for workload in workloads {
|
||||
debug!(workload = workload.name(), "initializing workload");
|
||||
let name = workload.name().to_owned();
|
||||
|
||||
workload
|
||||
.init(descriptors, run_metrics)
|
||||
.map_err(|source| workload_init_error(name, source))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn initialize_expectations<E: Application>(
|
||||
descriptors: &E::Deployment,
|
||||
run_metrics: &RunMetrics,
|
||||
expectations: &mut [Box<dyn Expectation<E>>],
|
||||
) -> Result<(), ScenarioBuildError> {
|
||||
for expectation in expectations {
|
||||
debug!(expectation = expectation.name(), "initializing expectation");
|
||||
let name = expectation.name().to_owned();
|
||||
|
||||
expectation
|
||||
.init(descriptors, run_metrics)
|
||||
.map_err(|source| expectation_init_error(name, source))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn workload_init_error(name: String, source: DynError) -> ScenarioBuildError {
|
||||
ScenarioBuildError::WorkloadInit { name, source }
|
||||
}
|
||||
|
||||
fn expectation_init_error(name: String, source: DynError) -> ScenarioBuildError {
|
||||
ScenarioBuildError::ExpectationInit { name, source }
|
||||
}
|
||||
|
||||
fn enforce_min_duration(requested: Duration) -> Duration {
|
||||
let min_duration = min_run_duration();
|
||||
|
||||
requested.max(min_duration)
|
||||
}
|
||||
|
||||
fn default_expectation_cooldown() -> Duration {
|
||||
Duration::from_secs(MIN_EXPECTATION_FALLBACK_SECS)
|
||||
}
|
||||
|
||||
fn expectation_cooldown_for(override_value: Option<Duration>) -> Duration {
|
||||
override_value.unwrap_or_else(default_expectation_cooldown)
|
||||
}
|
||||
|
||||
fn min_run_duration() -> Duration {
|
||||
Duration::from_secs(MIN_RUN_DURATION_SECS)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{
|
||||
ScenarioBuildError, validate_external_only_sources, validate_node_control_profile,
|
||||
};
|
||||
use crate::scenario::{
|
||||
ExistingCluster, ExternalNodeSource, NodeControlCapability, sources::ScenarioSources,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn external_only_requires_external_nodes() {
|
||||
let error =
|
||||
validate_external_only_sources(&ScenarioSources::default().into_external_only())
|
||||
.expect_err("external-only without nodes should fail");
|
||||
|
||||
assert!(matches!(
|
||||
error,
|
||||
ScenarioBuildError::SourceConfiguration { .. }
|
||||
));
|
||||
assert_eq!(
|
||||
error.to_string(),
|
||||
"invalid scenario source configuration: external-only scenarios require at least one external node"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn external_only_rejects_node_control_requirement() {
|
||||
let sources = ScenarioSources::default()
|
||||
.with_external_node(ExternalNodeSource::new(
|
||||
"node-0".to_owned(),
|
||||
"http://127.0.0.1:1".to_owned(),
|
||||
))
|
||||
.into_external_only();
|
||||
let error = validate_node_control_profile::<NodeControlCapability>(&sources)
|
||||
.expect_err("external-only should reject node control");
|
||||
|
||||
assert!(matches!(
|
||||
error,
|
||||
ScenarioBuildError::SourceConfiguration { .. }
|
||||
));
|
||||
assert_eq!(
|
||||
error.to_string(),
|
||||
"invalid scenario source configuration: node control is not available for cluster mode 'external-only' with control profile 'external-uncontrolled'"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn existing_cluster_accepts_node_control_requirement() {
|
||||
let sources = ScenarioSources::default()
|
||||
.with_attach(ExistingCluster::for_compose_project("project".to_owned()));
|
||||
|
||||
validate_node_control_profile::<NodeControlCapability>(&sources)
|
||||
.expect("existing cluster should be considered controllable");
|
||||
}
|
||||
}
|
||||
8
testing-framework/core/src/scenario/definition/mod.rs
Normal file
8
testing-framework/core/src/scenario/definition/mod.rs
Normal file
@ -0,0 +1,8 @@
|
||||
mod builder;
|
||||
mod model;
|
||||
mod validation;
|
||||
|
||||
pub use builder::{
|
||||
Builder, NodeControlScenarioBuilder, ObservabilityScenarioBuilder, ScenarioBuilder,
|
||||
};
|
||||
pub use model::{Scenario, ScenarioBuildError};
|
||||
202
testing-framework/core/src/scenario/definition/model.rs
Normal file
202
testing-framework/core/src/scenario/definition/model.rs
Normal file
@ -0,0 +1,202 @@
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
use super::builder::Builder;
|
||||
use crate::{
|
||||
scenario::{
|
||||
Application, ClusterControlProfile, ClusterMode, DeploymentPolicy, DynError,
|
||||
ExistingCluster, ExternalNodeSource, HttpReadinessRequirement, expectation::Expectation,
|
||||
runtime::SourceOrchestrationPlan, sources::ScenarioSources, workload::Workload,
|
||||
},
|
||||
topology::DynTopologyError,
|
||||
};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ScenarioBuildError {
|
||||
#[error("topology build failed: {0}")]
|
||||
Topology(#[source] DynTopologyError),
|
||||
#[error("workload '{name}' failed to initialize")]
|
||||
WorkloadInit { name: String, source: DynError },
|
||||
#[error("expectation '{name}' failed to initialize")]
|
||||
ExpectationInit { name: String, source: DynError },
|
||||
#[error("invalid scenario source configuration: {message}")]
|
||||
SourceConfiguration { message: String },
|
||||
#[error("scenario source mode '{mode}' is not wired into deployers yet")]
|
||||
SourceModeNotWiredYet { mode: &'static str },
|
||||
}
|
||||
|
||||
/// Immutable scenario definition used by the runner, workloads, and
|
||||
/// expectations.
|
||||
pub struct Scenario<E: Application, Caps = ()> {
|
||||
deployment: E::Deployment,
|
||||
workloads: Vec<Arc<dyn Workload<E>>>,
|
||||
expectations: Vec<Box<dyn Expectation<E>>>,
|
||||
duration: Duration,
|
||||
expectation_cooldown: Duration,
|
||||
deployment_policy: DeploymentPolicy,
|
||||
sources: ScenarioSources,
|
||||
source_orchestration_plan: SourceOrchestrationPlan,
|
||||
capabilities: Caps,
|
||||
}
|
||||
|
||||
impl<E: Application, Caps> Scenario<E, Caps> {
|
||||
pub(super) fn new(
|
||||
deployment: E::Deployment,
|
||||
workloads: Vec<Arc<dyn Workload<E>>>,
|
||||
expectations: Vec<Box<dyn Expectation<E>>>,
|
||||
duration: Duration,
|
||||
expectation_cooldown: Duration,
|
||||
deployment_policy: DeploymentPolicy,
|
||||
sources: ScenarioSources,
|
||||
source_orchestration_plan: SourceOrchestrationPlan,
|
||||
capabilities: Caps,
|
||||
) -> Self {
|
||||
Self {
|
||||
deployment,
|
||||
workloads,
|
||||
expectations,
|
||||
duration,
|
||||
expectation_cooldown,
|
||||
deployment_policy,
|
||||
sources,
|
||||
source_orchestration_plan,
|
||||
capabilities,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn deployment(&self) -> &E::Deployment {
|
||||
&self.deployment
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn workloads(&self) -> &[Arc<dyn Workload<E>>] {
|
||||
&self.workloads
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn expectations(&self) -> &[Box<dyn Expectation<E>>] {
|
||||
&self.expectations
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn expectations_mut(&mut self) -> &mut [Box<dyn Expectation<E>>] {
|
||||
&mut self.expectations
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn duration(&self) -> Duration {
|
||||
self.duration
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn expectation_cooldown(&self) -> Duration {
|
||||
self.expectation_cooldown
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn http_readiness_requirement(&self) -> HttpReadinessRequirement {
|
||||
self.deployment_policy.readiness_requirement
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn deployment_policy(&self) -> DeploymentPolicy {
|
||||
self.deployment_policy
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn existing_cluster(&self) -> Option<&ExistingCluster> {
|
||||
self.sources.existing_cluster()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn cluster_mode(&self) -> ClusterMode {
|
||||
self.sources.cluster_mode()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn cluster_control_profile(&self) -> ClusterControlProfile {
|
||||
self.sources.control_profile()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[doc(hidden)]
|
||||
pub fn attached_source(&self) -> Option<&ExistingCluster> {
|
||||
self.existing_cluster()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn external_nodes(&self) -> &[ExternalNodeSource] {
|
||||
self.sources.external_nodes()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn has_external_nodes(&self) -> bool {
|
||||
!self.sources.external_nodes().is_empty()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn source_orchestration_plan(&self) -> &SourceOrchestrationPlan {
|
||||
&self.source_orchestration_plan
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn capabilities(&self) -> &Caps {
|
||||
&self.capabilities
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Application> super::builder::ScenarioBuilder<E> {
|
||||
pub fn build(self) -> Result<Scenario<E>, ScenarioBuildError> {
|
||||
self.inner.build()
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Application> super::builder::NodeControlScenarioBuilder<E> {
|
||||
pub fn build(
|
||||
self,
|
||||
) -> Result<Scenario<E, crate::scenario::NodeControlCapability>, ScenarioBuildError> {
|
||||
self.inner.build()
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Application> super::builder::ObservabilityScenarioBuilder<E> {
|
||||
pub fn build(
|
||||
self,
|
||||
) -> Result<Scenario<E, crate::scenario::ObservabilityCapability>, ScenarioBuildError> {
|
||||
self.inner.build()
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Application, Caps> Builder<E, Caps> {
|
||||
#[must_use]
|
||||
pub const fn capabilities(&self) -> &Caps {
|
||||
&self.capabilities
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn capabilities_mut(&mut self) -> &mut Caps {
|
||||
&mut self.capabilities
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn run_duration(&self) -> Duration {
|
||||
self.duration
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn expectation_cooldown_override(&self) -> Option<Duration> {
|
||||
self.expectation_cooldown
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn http_readiness_requirement(&self) -> HttpReadinessRequirement {
|
||||
self.deployment_policy.readiness_requirement
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn deployment_policy(&self) -> DeploymentPolicy {
|
||||
self.deployment_policy
|
||||
}
|
||||
}
|
||||
196
testing-framework/core/src/scenario/definition/validation.rs
Normal file
196
testing-framework/core/src/scenario/definition/validation.rs
Normal file
@ -0,0 +1,196 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use tracing::debug;
|
||||
|
||||
use super::model::ScenarioBuildError;
|
||||
use crate::scenario::{
|
||||
Application, ClusterControlProfile, ClusterMode, DynError, RequiresNodeControl,
|
||||
expectation::Expectation,
|
||||
runtime::{SourceOrchestrationPlan, SourceOrchestrationPlanError, context::RunMetrics},
|
||||
sources::ScenarioSources,
|
||||
workload::Workload,
|
||||
};
|
||||
|
||||
const MIN_EXPECTATION_FALLBACK_SECS: u64 = 10;
|
||||
const MIN_RUN_DURATION_SECS: u64 = 10;
|
||||
|
||||
pub(super) fn build_source_orchestration_plan(
|
||||
sources: &ScenarioSources,
|
||||
) -> Result<SourceOrchestrationPlan, ScenarioBuildError> {
|
||||
SourceOrchestrationPlan::try_from_sources(sources).map_err(source_plan_error_to_build_error)
|
||||
}
|
||||
|
||||
pub(super) fn validate_source_contract<Caps>(
|
||||
sources: &ScenarioSources,
|
||||
) -> Result<(), ScenarioBuildError>
|
||||
where
|
||||
Caps: RequiresNodeControl,
|
||||
{
|
||||
validate_external_only_sources(sources)?;
|
||||
validate_node_control_profile::<Caps>(sources)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn source_plan_error_to_build_error(error: SourceOrchestrationPlanError) -> ScenarioBuildError {
|
||||
match error {
|
||||
SourceOrchestrationPlanError::SourceModeNotWiredYet { mode } => {
|
||||
ScenarioBuildError::SourceModeNotWiredYet { mode }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn initialize_components<E: Application>(
|
||||
descriptors: &E::Deployment,
|
||||
run_metrics: &RunMetrics,
|
||||
workloads: &mut [Box<dyn Workload<E>>],
|
||||
expectations: &mut [Box<dyn Expectation<E>>],
|
||||
) -> Result<(), ScenarioBuildError> {
|
||||
initialize_workloads(descriptors, run_metrics, workloads)?;
|
||||
initialize_expectations(descriptors, run_metrics, expectations)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn initialize_workloads<E: Application>(
|
||||
descriptors: &E::Deployment,
|
||||
run_metrics: &RunMetrics,
|
||||
workloads: &mut [Box<dyn Workload<E>>],
|
||||
) -> Result<(), ScenarioBuildError> {
|
||||
for workload in workloads {
|
||||
debug!(workload = workload.name(), "initializing workload");
|
||||
let name = workload.name().to_owned();
|
||||
|
||||
workload
|
||||
.init(descriptors, run_metrics)
|
||||
.map_err(|source| workload_init_error(name, source))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn initialize_expectations<E: Application>(
|
||||
descriptors: &E::Deployment,
|
||||
run_metrics: &RunMetrics,
|
||||
expectations: &mut [Box<dyn Expectation<E>>],
|
||||
) -> Result<(), ScenarioBuildError> {
|
||||
for expectation in expectations {
|
||||
debug!(expectation = expectation.name(), "initializing expectation");
|
||||
let name = expectation.name().to_owned();
|
||||
|
||||
expectation
|
||||
.init(descriptors, run_metrics)
|
||||
.map_err(|source| expectation_init_error(name, source))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn workload_init_error(name: String, source: DynError) -> ScenarioBuildError {
|
||||
ScenarioBuildError::WorkloadInit { name, source }
|
||||
}
|
||||
|
||||
fn expectation_init_error(name: String, source: DynError) -> ScenarioBuildError {
|
||||
ScenarioBuildError::ExpectationInit { name, source }
|
||||
}
|
||||
|
||||
pub(super) fn enforce_min_duration(requested: Duration) -> Duration {
|
||||
requested.max(min_run_duration())
|
||||
}
|
||||
|
||||
fn default_expectation_cooldown() -> Duration {
|
||||
Duration::from_secs(MIN_EXPECTATION_FALLBACK_SECS)
|
||||
}
|
||||
|
||||
pub(super) fn expectation_cooldown_for(override_value: Option<Duration>) -> Duration {
|
||||
override_value.unwrap_or_else(default_expectation_cooldown)
|
||||
}
|
||||
|
||||
fn min_run_duration() -> Duration {
|
||||
Duration::from_secs(MIN_RUN_DURATION_SECS)
|
||||
}
|
||||
|
||||
fn validate_external_only_sources(sources: &ScenarioSources) -> Result<(), ScenarioBuildError> {
|
||||
if matches!(sources.cluster_mode(), ClusterMode::ExternalOnly)
|
||||
&& sources.external_nodes().is_empty()
|
||||
{
|
||||
return Err(ScenarioBuildError::SourceConfiguration {
|
||||
message: "external-only scenarios require at least one external node".to_owned(),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_node_control_profile<Caps>(sources: &ScenarioSources) -> Result<(), ScenarioBuildError>
|
||||
where
|
||||
Caps: RequiresNodeControl,
|
||||
{
|
||||
let profile = sources.control_profile();
|
||||
|
||||
if Caps::REQUIRED && matches!(profile, ClusterControlProfile::ExternalUncontrolled) {
|
||||
return Err(ScenarioBuildError::SourceConfiguration {
|
||||
message: format!(
|
||||
"node control is not available for cluster mode '{}' with control profile '{}'",
|
||||
sources.cluster_mode().as_str(),
|
||||
profile.as_str(),
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{
|
||||
ScenarioBuildError, validate_external_only_sources, validate_node_control_profile,
|
||||
};
|
||||
use crate::scenario::{
|
||||
ExistingCluster, ExternalNodeSource, NodeControlCapability, sources::ScenarioSources,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn external_only_requires_external_nodes() {
|
||||
let error =
|
||||
validate_external_only_sources(&ScenarioSources::default().into_external_only())
|
||||
.expect_err("external-only without nodes should fail");
|
||||
|
||||
assert!(matches!(
|
||||
error,
|
||||
ScenarioBuildError::SourceConfiguration { .. }
|
||||
));
|
||||
assert_eq!(
|
||||
error.to_string(),
|
||||
"invalid scenario source configuration: external-only scenarios require at least one external node"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn external_only_rejects_node_control_requirement() {
|
||||
let sources = ScenarioSources::default()
|
||||
.with_external_node(ExternalNodeSource::new(
|
||||
"node-0".to_owned(),
|
||||
"http://127.0.0.1:1".to_owned(),
|
||||
))
|
||||
.into_external_only();
|
||||
let error = validate_node_control_profile::<NodeControlCapability>(&sources)
|
||||
.expect_err("external-only should reject node control");
|
||||
|
||||
assert!(matches!(
|
||||
error,
|
||||
ScenarioBuildError::SourceConfiguration { .. }
|
||||
));
|
||||
assert_eq!(
|
||||
error.to_string(),
|
||||
"invalid scenario source configuration: node control is not available for cluster mode 'external-only' with control profile 'external-uncontrolled'"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn existing_cluster_accepts_node_control_requirement() {
|
||||
let sources = ScenarioSources::default()
|
||||
.with_attach(ExistingCluster::for_compose_project("project".to_owned()));
|
||||
|
||||
validate_node_control_profile::<NodeControlCapability>(&sources)
|
||||
.expect("existing cluster should be considered controllable");
|
||||
}
|
||||
}
|
||||
13
testing-framework/core/src/scenario/internal.rs
Normal file
13
testing-framework/core/src/scenario/internal.rs
Normal file
@ -0,0 +1,13 @@
|
||||
#[doc(hidden)]
|
||||
pub use super::builder_ops::CoreBuilderAccess;
|
||||
#[doc(hidden)]
|
||||
pub use super::definition::{
|
||||
Builder as CoreBuilder, NodeControlScenarioBuilder, ObservabilityScenarioBuilder,
|
||||
};
|
||||
#[doc(hidden)]
|
||||
pub use super::runtime::{
|
||||
ApplicationExternalProvider, AttachProvider, AttachProviderError, AttachedNode, CleanupGuard,
|
||||
FeedHandle, ManagedSource, RuntimeAssembly, SourceOrchestrationPlan, SourceProviders,
|
||||
StaticManagedProvider, build_source_orchestration_plan, orchestrate_sources,
|
||||
orchestrate_sources_with_providers, resolve_sources,
|
||||
};
|
||||
@ -10,6 +10,7 @@ mod control;
|
||||
mod definition;
|
||||
mod deployment_policy;
|
||||
mod expectation;
|
||||
pub mod internal;
|
||||
mod observability;
|
||||
mod runtime;
|
||||
mod sources;
|
||||
@ -18,31 +19,16 @@ mod workload;
|
||||
pub type DynError = Box<dyn Error + Send + Sync + 'static>;
|
||||
|
||||
pub use builder_ext::{BuilderInputError, ObservabilityBuilderExt};
|
||||
#[doc(hidden)]
|
||||
pub use builder_ops::CoreBuilderAccess;
|
||||
pub use capabilities::{
|
||||
NodeControlCapability, ObservabilityCapability, PeerSelection, RequiresNodeControl,
|
||||
StartNodeOptions, StartedNode,
|
||||
};
|
||||
pub use common_builder_ext::CoreBuilderExt;
|
||||
pub use control::{ClusterWaitHandle, NodeControlHandle};
|
||||
#[doc(hidden)]
|
||||
pub use definition::{
|
||||
Builder as CoreBuilder, // internal adapter-facing core builder
|
||||
NodeControlScenarioBuilder,
|
||||
ObservabilityScenarioBuilder,
|
||||
};
|
||||
pub use definition::{Scenario, ScenarioBuildError, ScenarioBuilder};
|
||||
pub use deployment_policy::{CleanupPolicy, DeploymentPolicy, RetryPolicy};
|
||||
pub use expectation::Expectation;
|
||||
pub use observability::{ObservabilityCapabilityProvider, ObservabilityInputs};
|
||||
#[doc(hidden)]
|
||||
pub use runtime::{
|
||||
ApplicationExternalProvider, AttachProvider, AttachProviderError, AttachedNode, CleanupGuard,
|
||||
FeedHandle, ManagedSource, RuntimeAssembly, SourceOrchestrationPlan, SourceProviders,
|
||||
StaticManagedProvider, build_source_orchestration_plan, orchestrate_sources,
|
||||
orchestrate_sources_with_providers, resolve_sources,
|
||||
};
|
||||
pub use runtime::{
|
||||
Deployer, Feed, FeedRuntime, HttpReadinessRequirement, NodeClients, ReadinessError, RunContext,
|
||||
RunHandle, RunMetrics, Runner, ScenarioError, StabilizationConfig,
|
||||
|
||||
13
testing-framework/core/src/scenario/runtime/internal/mod.rs
Normal file
13
testing-framework/core/src/scenario/runtime/internal/mod.rs
Normal file
@ -0,0 +1,13 @@
|
||||
mod orchestration;
|
||||
mod providers;
|
||||
|
||||
pub use orchestration::{
|
||||
ManagedSource, SourceOrchestrationPlan, SourceOrchestrationPlanError,
|
||||
build_source_orchestration_plan, orchestrate_sources, orchestrate_sources_with_providers,
|
||||
resolve_sources,
|
||||
};
|
||||
pub use providers::{
|
||||
ApplicationExternalProvider, AttachProvider, AttachProviderError, AttachedNode, ExternalNode,
|
||||
ExternalProviderError, ManagedProviderError, ManagedProvisionedNode, SourceProviders,
|
||||
StaticManagedProvider,
|
||||
};
|
||||
@ -1,15 +1,13 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::{SourceOrchestrationMode, SourceOrchestrationPlan, SourceOrchestrationPlanError};
|
||||
use crate::scenario::{
|
||||
Application, DynError, NodeClients, Scenario,
|
||||
runtime::{
|
||||
orchestration::{
|
||||
SourceOrchestrationMode, SourceOrchestrationPlan, SourceOrchestrationPlanError,
|
||||
},
|
||||
providers::{
|
||||
ApplicationExternalProvider, AttachProviderError, AttachedNode, ExternalNode,
|
||||
ExternalProviderError, ManagedProviderError, ManagedProvisionedNode, SourceProviders,
|
||||
StaticManagedProvider,
|
||||
ApplicationExternalProvider, AttachProviderError, AttachedNode, SourceProviders,
|
||||
StaticManagedProvider,
|
||||
internal::{
|
||||
ExternalNode, ExternalProviderError, ManagedProviderError, ManagedProvisionedNode,
|
||||
},
|
||||
},
|
||||
};
|
||||
@ -1,6 +1,6 @@
|
||||
use async_trait::async_trait;
|
||||
|
||||
use crate::scenario::{Application, DynError, runtime::orchestration::ManagedSource};
|
||||
use crate::scenario::{Application, DynError, runtime::ManagedSource};
|
||||
|
||||
/// Managed node produced by the managed provider path.
|
||||
#[derive(Clone, Debug)]
|
||||
@ -1,27 +1,23 @@
|
||||
pub mod context;
|
||||
mod deployer;
|
||||
mod internal;
|
||||
mod inventory;
|
||||
pub mod metrics;
|
||||
mod node_clients;
|
||||
pub mod orchestration;
|
||||
pub mod providers;
|
||||
pub mod readiness;
|
||||
mod runner;
|
||||
|
||||
use async_trait::async_trait;
|
||||
pub use context::{CleanupGuard, RunContext, RunHandle, RunMetrics, RuntimeAssembly};
|
||||
pub use deployer::{Deployer, ScenarioError};
|
||||
#[doc(hidden)]
|
||||
pub use internal::{
|
||||
ApplicationExternalProvider, AttachProvider, AttachProviderError, AttachedNode, ManagedSource,
|
||||
SourceOrchestrationPlan, SourceOrchestrationPlanError, SourceProviders, StaticManagedProvider,
|
||||
build_source_orchestration_plan, orchestrate_sources, orchestrate_sources_with_providers,
|
||||
resolve_sources,
|
||||
};
|
||||
pub use node_clients::NodeClients;
|
||||
#[doc(hidden)]
|
||||
pub use orchestration::{
|
||||
ManagedSource, SourceOrchestrationPlan, build_source_orchestration_plan, orchestrate_sources,
|
||||
orchestrate_sources_with_providers, resolve_sources,
|
||||
};
|
||||
#[doc(hidden)]
|
||||
pub use providers::{
|
||||
ApplicationExternalProvider, AttachProvider, AttachProviderError, AttachedNode,
|
||||
SourceProviders, StaticManagedProvider,
|
||||
};
|
||||
pub use readiness::{
|
||||
HttpReadinessRequirement, ReadinessError, StabilizationConfig, wait_for_http_ports,
|
||||
wait_for_http_ports_with_host, wait_for_http_ports_with_host_and_requirement,
|
||||
|
||||
@ -5,7 +5,9 @@ use rand::{Rng as _, seq::SliceRandom as _, thread_rng};
|
||||
use tokio::time::{Instant, sleep};
|
||||
|
||||
use crate::{
|
||||
scenario::{Application, CoreBuilder, DynError, NodeControlCapability, RunContext, Workload},
|
||||
scenario::{
|
||||
Application, DynError, NodeControlCapability, RunContext, Workload, internal::CoreBuilder,
|
||||
},
|
||||
topology::DeploymentDescriptor,
|
||||
};
|
||||
|
||||
|
||||
@ -2,8 +2,9 @@ use std::marker::PhantomData;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use testing_framework_core::scenario::{
|
||||
AttachProvider, AttachProviderError, AttachedNode, ClusterWaitHandle, DynError,
|
||||
ExistingCluster, ExternalNodeSource, HttpReadinessRequirement, wait_http_readiness,
|
||||
ClusterWaitHandle, DynError, ExistingCluster, ExternalNodeSource, HttpReadinessRequirement,
|
||||
internal::{AttachProvider, AttachProviderError, AttachedNode},
|
||||
wait_http_readiness,
|
||||
};
|
||||
use url::Url;
|
||||
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
use std::{fmt::Debug, marker::PhantomData};
|
||||
|
||||
use testing_framework_core::scenario::{Application, FeedHandle, FeedRuntime, NodeClients};
|
||||
use testing_framework_core::scenario::{
|
||||
Application, FeedRuntime, NodeClients, internal::FeedHandle,
|
||||
};
|
||||
use tracing::{info, warn};
|
||||
|
||||
use crate::{
|
||||
|
||||
@ -9,8 +9,9 @@ use std::marker::PhantomData;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use testing_framework_core::scenario::{
|
||||
CleanupGuard, Deployer, DynError, ExistingCluster, FeedHandle, IntoExistingCluster,
|
||||
ObservabilityCapabilityProvider, RequiresNodeControl, Runner, Scenario,
|
||||
Deployer, DynError, ExistingCluster, IntoExistingCluster, ObservabilityCapabilityProvider,
|
||||
RequiresNodeControl, Runner, Scenario,
|
||||
internal::{CleanupGuard, FeedHandle},
|
||||
};
|
||||
|
||||
use crate::{env::ComposeDeployEnv, errors::ComposeRunnerError, lifecycle::cleanup::RunnerCleanup};
|
||||
|
||||
@ -3,12 +3,15 @@ use std::{env, sync::Arc, time::Duration};
|
||||
use reqwest::Url;
|
||||
use testing_framework_core::{
|
||||
scenario::{
|
||||
Application, ApplicationExternalProvider, CleanupGuard, ClusterControlProfile, ClusterMode,
|
||||
ClusterWaitHandle, DeploymentPolicy, DynError, ExistingCluster, FeedHandle, FeedRuntime,
|
||||
HttpReadinessRequirement, Metrics, NodeClients, NodeControlHandle,
|
||||
ObservabilityCapabilityProvider, ObservabilityInputs, RequiresNodeControl, Runner,
|
||||
RuntimeAssembly, Scenario, SourceOrchestrationPlan, SourceProviders, StaticManagedProvider,
|
||||
build_source_orchestration_plan, orchestrate_sources_with_providers,
|
||||
Application, ClusterControlProfile, ClusterMode, ClusterWaitHandle, DeploymentPolicy,
|
||||
DynError, ExistingCluster, FeedRuntime, HttpReadinessRequirement, Metrics, NodeClients,
|
||||
NodeControlHandle, ObservabilityCapabilityProvider, ObservabilityInputs,
|
||||
RequiresNodeControl, Runner, Scenario,
|
||||
internal::{
|
||||
ApplicationExternalProvider, CleanupGuard, FeedHandle, RuntimeAssembly,
|
||||
SourceOrchestrationPlan, SourceProviders, StaticManagedProvider,
|
||||
build_source_orchestration_plan, orchestrate_sources_with_providers,
|
||||
},
|
||||
},
|
||||
topology::DeploymentDescriptor,
|
||||
};
|
||||
|
||||
@ -6,7 +6,7 @@ use std::{
|
||||
|
||||
use anyhow::anyhow;
|
||||
use reqwest::Url;
|
||||
use testing_framework_core::{scenario::CleanupGuard, topology::DeploymentDescriptor};
|
||||
use testing_framework_core::{scenario::internal::CleanupGuard, topology::DeploymentDescriptor};
|
||||
use tokio::{net::TcpStream, process::Command};
|
||||
use tokio_retry::{Retry, strategy::FixedInterval};
|
||||
use tracing::{debug, error, info, warn};
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use testing_framework_core::scenario::{
|
||||
Application, FeedHandle, FeedRuntime, NodeClients, spawn_feed,
|
||||
Application, FeedRuntime, NodeClients, internal::FeedHandle, spawn_feed,
|
||||
};
|
||||
use tokio::time::sleep;
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
@ -4,7 +4,7 @@ use std::{
|
||||
thread,
|
||||
};
|
||||
|
||||
use testing_framework_core::scenario::CleanupGuard;
|
||||
use testing_framework_core::scenario::internal::CleanupGuard;
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
use crate::{
|
||||
|
||||
@ -7,8 +7,9 @@ use kube::{
|
||||
api::{ListParams, ObjectList},
|
||||
};
|
||||
use testing_framework_core::scenario::{
|
||||
AttachProvider, AttachProviderError, AttachedNode, ClusterWaitHandle, DynError,
|
||||
ExistingCluster, ExternalNodeSource, HttpReadinessRequirement, wait_http_readiness,
|
||||
ClusterWaitHandle, DynError, ExistingCluster, ExternalNodeSource, HttpReadinessRequirement,
|
||||
internal::{AttachProvider, AttachProviderError, AttachedNode},
|
||||
wait_http_readiness,
|
||||
};
|
||||
use url::Url;
|
||||
|
||||
|
||||
@ -5,12 +5,15 @@ use kube::Client;
|
||||
use reqwest::Url;
|
||||
use testing_framework_core::{
|
||||
scenario::{
|
||||
Application, ApplicationExternalProvider, CleanupGuard, ClusterControlProfile, ClusterMode,
|
||||
ClusterWaitHandle, Deployer, DynError, ExistingCluster, FeedHandle, FeedRuntime,
|
||||
HttpReadinessRequirement, Metrics, MetricsError, NodeClients,
|
||||
Application, ClusterControlProfile, ClusterMode, ClusterWaitHandle, Deployer, DynError,
|
||||
ExistingCluster, FeedRuntime, HttpReadinessRequirement, Metrics, MetricsError, NodeClients,
|
||||
ObservabilityCapabilityProvider, ObservabilityInputs, RequiresNodeControl, Runner,
|
||||
RuntimeAssembly, Scenario, SourceOrchestrationPlan, SourceProviders, StaticManagedProvider,
|
||||
build_source_orchestration_plan, orchestrate_sources_with_providers,
|
||||
Scenario,
|
||||
internal::{
|
||||
ApplicationExternalProvider, CleanupGuard, FeedHandle, RuntimeAssembly,
|
||||
SourceOrchestrationPlan, SourceProviders, StaticManagedProvider,
|
||||
build_source_orchestration_plan, orchestrate_sources_with_providers,
|
||||
},
|
||||
},
|
||||
topology::DeploymentDescriptor,
|
||||
};
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use kube::Client;
|
||||
use reqwest::Url;
|
||||
use testing_framework_core::scenario::{
|
||||
CleanupGuard, DynError, HttpReadinessRequirement, NodeClients,
|
||||
DynError, HttpReadinessRequirement, NodeClients, internal::CleanupGuard,
|
||||
};
|
||||
use tracing::{debug, info};
|
||||
use url::ParseError;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use testing_framework_core::scenario::{
|
||||
Application, FeedHandle, FeedRuntime, NodeClients, spawn_feed,
|
||||
Application, FeedRuntime, NodeClients, internal::FeedHandle, spawn_feed,
|
||||
};
|
||||
use tracing::{debug, info};
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ use std::{io, process::Output, thread};
|
||||
|
||||
use k8s_openapi::api::core::v1::Namespace;
|
||||
use kube::{Api, Client, api::DeleteParams};
|
||||
use testing_framework_core::scenario::CleanupGuard;
|
||||
use testing_framework_core::scenario::internal::CleanupGuard;
|
||||
use tokio::{
|
||||
process::Command,
|
||||
runtime::{Handle, Runtime},
|
||||
|
||||
@ -10,10 +10,14 @@ use std::{
|
||||
use async_trait::async_trait;
|
||||
use testing_framework_core::{
|
||||
scenario::{
|
||||
Application, CleanupGuard, ClusterControlProfile, ClusterMode, Deployer, DeploymentPolicy,
|
||||
DynError, FeedHandle, FeedRuntime, HttpReadinessRequirement, Metrics, NodeClients,
|
||||
NodeControlCapability, NodeControlHandle, RetryPolicy, Runner, RuntimeAssembly, Scenario,
|
||||
ScenarioError, SourceOrchestrationPlan, build_source_orchestration_plan, spawn_feed,
|
||||
Application, ClusterControlProfile, ClusterMode, Deployer, DeploymentPolicy, DynError,
|
||||
FeedRuntime, HttpReadinessRequirement, Metrics, NodeClients, NodeControlCapability,
|
||||
NodeControlHandle, RetryPolicy, Runner, Scenario, ScenarioError,
|
||||
internal::{
|
||||
CleanupGuard, FeedHandle, RuntimeAssembly, SourceOrchestrationPlan,
|
||||
build_source_orchestration_plan,
|
||||
},
|
||||
spawn_feed,
|
||||
},
|
||||
topology::DeploymentDescriptor,
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user