diff --git a/Cargo.lock b/Cargo.lock index f550368..2af905e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/logos/runtime/ext/src/scenario/mod.rs b/logos/runtime/ext/src/scenario/mod.rs index 50c976d..564e46c 100644 --- a/logos/runtime/ext/src/scenario/mod.rs +++ b/logos/runtime/ext/src/scenario/mod.rs @@ -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; pub type ScenarioBuilderWith = - testing_framework_core::scenario::CoreBuilder; + testing_framework_core::scenario::internal::CoreBuilder; pub trait CoreBuilderExt: Sized { fn deployment_with(f: impl FnOnce(DeploymentBuilder) -> DeploymentBuilder) -> Self; diff --git a/testing-framework/core/src/scenario/builder_ext.rs b/testing-framework/core/src/scenario/builder_ext.rs index b771c2e..f5003b7 100644 --- a/testing-framework/core/src/scenario/builder_ext.rs +++ b/testing-framework/core/src/scenario/builder_ext.rs @@ -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"; diff --git a/testing-framework/core/src/scenario/common_builder_ext.rs b/testing-framework/core/src/scenario/common_builder_ext.rs index 76b7f49..f0842c3 100644 --- a/testing-framework/core/src/scenario/common_builder_ext.rs +++ b/testing-framework/core/src/scenario/common_builder_ext.rs @@ -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}; diff --git a/testing-framework/core/src/scenario/definition.rs b/testing-framework/core/src/scenario/definition/builder.rs similarity index 59% rename from testing-framework/core/src/scenario/definition.rs rename to testing-framework/core/src/scenario/definition/builder.rs index 0aa2350..fe5b861 100644 --- a/testing-framework/core/src/scenario/definition.rs +++ b/testing-framework/core/src/scenario/definition/builder.rs @@ -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 { - deployment: E::Deployment, - workloads: Vec>>, - expectations: Vec>>, - duration: Duration, - expectation_cooldown: Duration, - deployment_policy: DeploymentPolicy, - sources: ScenarioSources, - source_orchestration_plan: SourceOrchestrationPlan, - capabilities: Caps, -} - -impl Scenario { - fn new( - deployment: E::Deployment, - workloads: Vec>>, - expectations: Vec>>, - 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>] { - &self.workloads - } - - #[must_use] - pub fn expectations(&self) -> &[Box>] { - &self.expectations - } - - #[must_use] - pub fn expectations_mut(&mut self) -> &mut [Box>] { - &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 { - deployment_provider: Box>, - topology_seed: Option, - workloads: Vec>>, - expectations: Vec>>, - duration: Duration, - expectation_cooldown: Option, - deployment_policy: DeploymentPolicy, - sources: ScenarioSources, - capabilities: Caps, + pub(super) deployment_provider: Box>, + pub(super) topology_seed: Option, + pub(super) workloads: Vec>>, + pub(super) expectations: Vec>>, + pub(super) duration: Duration, + pub(super) expectation_cooldown: Option, + pub(super) deployment_policy: DeploymentPolicy, + pub(super) sources: ScenarioSources, + pub(super) capabilities: Caps, } pub struct ScenarioBuilder { - inner: Builder, + pub(super) inner: Builder, } pub struct NodeControlScenarioBuilder { - inner: Builder, + pub(super) inner: Builder, } pub struct ObservabilityScenarioBuilder { - inner: Builder, + pub(super) inner: Builder, } macro_rules! impl_common_builder_methods { @@ -432,10 +296,6 @@ impl ScenarioBuilder { self.with_observability() } - pub fn build(self) -> Result, ScenarioBuildError> { - self.inner.build() - } - pub(crate) fn with_observability_capability( self, observability: ObservabilityCapability, @@ -447,27 +307,15 @@ impl ScenarioBuilder { } impl_common_builder_methods!(ScenarioBuilder); - -impl NodeControlScenarioBuilder { - pub fn build(self) -> Result, ScenarioBuildError> { - self.inner.build() - } -} - impl_common_builder_methods!(NodeControlScenarioBuilder); +impl_common_builder_methods!(ObservabilityScenarioBuilder); impl ObservabilityScenarioBuilder { - pub fn build(self) -> Result, ScenarioBuildError> { - self.inner.build() - } - pub(crate) fn capabilities_mut(&mut self) -> &mut ObservabilityCapability { self.inner.capabilities_mut() } } -impl_common_builder_methods!(ObservabilityScenarioBuilder); - impl Builder { #[must_use] /// Transform the existing deployment provider while preserving all @@ -521,36 +369,6 @@ impl Builder { } } - #[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 { - 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 BuilderParts { } } -fn build_source_orchestration_plan( - sources: &ScenarioSources, -) -> Result { - SourceOrchestrationPlan::try_from_sources(sources).map_err(source_plan_error_to_build_error) -} - -fn validate_source_contract(sources: &ScenarioSources) -> Result<(), ScenarioBuildError> -where - Caps: RequiresNodeControl, -{ - validate_external_only_sources(sources)?; - - validate_node_control_profile::(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(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 Builder { #[must_use] pub fn with_node_control(self) -> Builder { @@ -875,132 +637,3 @@ impl Builder { self.with_observability() } } - -fn initialize_components( - descriptors: &E::Deployment, - run_metrics: &RunMetrics, - workloads: &mut [Box>], - expectations: &mut [Box>], -) -> Result<(), ScenarioBuildError> { - initialize_workloads(descriptors, run_metrics, workloads)?; - - initialize_expectations(descriptors, run_metrics, expectations)?; - - Ok(()) -} - -fn initialize_workloads( - descriptors: &E::Deployment, - run_metrics: &RunMetrics, - workloads: &mut [Box>], -) -> 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( - descriptors: &E::Deployment, - run_metrics: &RunMetrics, - expectations: &mut [Box>], -) -> 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 { - 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::(&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::(&sources) - .expect("existing cluster should be considered controllable"); - } -} diff --git a/testing-framework/core/src/scenario/definition/mod.rs b/testing-framework/core/src/scenario/definition/mod.rs new file mode 100644 index 0000000..a0e3514 --- /dev/null +++ b/testing-framework/core/src/scenario/definition/mod.rs @@ -0,0 +1,8 @@ +mod builder; +mod model; +mod validation; + +pub use builder::{ + Builder, NodeControlScenarioBuilder, ObservabilityScenarioBuilder, ScenarioBuilder, +}; +pub use model::{Scenario, ScenarioBuildError}; diff --git a/testing-framework/core/src/scenario/definition/model.rs b/testing-framework/core/src/scenario/definition/model.rs new file mode 100644 index 0000000..ca6ecc6 --- /dev/null +++ b/testing-framework/core/src/scenario/definition/model.rs @@ -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 { + deployment: E::Deployment, + workloads: Vec>>, + expectations: Vec>>, + duration: Duration, + expectation_cooldown: Duration, + deployment_policy: DeploymentPolicy, + sources: ScenarioSources, + source_orchestration_plan: SourceOrchestrationPlan, + capabilities: Caps, +} + +impl Scenario { + pub(super) fn new( + deployment: E::Deployment, + workloads: Vec>>, + expectations: Vec>>, + 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>] { + &self.workloads + } + + #[must_use] + pub fn expectations(&self) -> &[Box>] { + &self.expectations + } + + #[must_use] + pub fn expectations_mut(&mut self) -> &mut [Box>] { + &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 super::builder::ScenarioBuilder { + pub fn build(self) -> Result, ScenarioBuildError> { + self.inner.build() + } +} + +impl super::builder::NodeControlScenarioBuilder { + pub fn build( + self, + ) -> Result, ScenarioBuildError> { + self.inner.build() + } +} + +impl super::builder::ObservabilityScenarioBuilder { + pub fn build( + self, + ) -> Result, ScenarioBuildError> { + self.inner.build() + } +} + +impl Builder { + #[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 { + 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 + } +} diff --git a/testing-framework/core/src/scenario/definition/validation.rs b/testing-framework/core/src/scenario/definition/validation.rs new file mode 100644 index 0000000..463f6cb --- /dev/null +++ b/testing-framework/core/src/scenario/definition/validation.rs @@ -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::try_from_sources(sources).map_err(source_plan_error_to_build_error) +} + +pub(super) fn validate_source_contract( + sources: &ScenarioSources, +) -> Result<(), ScenarioBuildError> +where + Caps: RequiresNodeControl, +{ + validate_external_only_sources(sources)?; + validate_node_control_profile::(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( + descriptors: &E::Deployment, + run_metrics: &RunMetrics, + workloads: &mut [Box>], + expectations: &mut [Box>], +) -> Result<(), ScenarioBuildError> { + initialize_workloads(descriptors, run_metrics, workloads)?; + initialize_expectations(descriptors, run_metrics, expectations)?; + Ok(()) +} + +fn initialize_workloads( + descriptors: &E::Deployment, + run_metrics: &RunMetrics, + workloads: &mut [Box>], +) -> 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( + descriptors: &E::Deployment, + run_metrics: &RunMetrics, + expectations: &mut [Box>], +) -> 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 { + 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(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::(&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::(&sources) + .expect("existing cluster should be considered controllable"); + } +} diff --git a/testing-framework/core/src/scenario/internal.rs b/testing-framework/core/src/scenario/internal.rs new file mode 100644 index 0000000..deeb2dd --- /dev/null +++ b/testing-framework/core/src/scenario/internal.rs @@ -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, +}; diff --git a/testing-framework/core/src/scenario/mod.rs b/testing-framework/core/src/scenario/mod.rs index 4089111..52306de 100644 --- a/testing-framework/core/src/scenario/mod.rs +++ b/testing-framework/core/src/scenario/mod.rs @@ -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; 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, diff --git a/testing-framework/core/src/scenario/runtime/internal/mod.rs b/testing-framework/core/src/scenario/runtime/internal/mod.rs new file mode 100644 index 0000000..4042969 --- /dev/null +++ b/testing-framework/core/src/scenario/runtime/internal/mod.rs @@ -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, +}; diff --git a/testing-framework/core/src/scenario/runtime/orchestration/mod.rs b/testing-framework/core/src/scenario/runtime/internal/orchestration/mod.rs similarity index 100% rename from testing-framework/core/src/scenario/runtime/orchestration/mod.rs rename to testing-framework/core/src/scenario/runtime/internal/orchestration/mod.rs diff --git a/testing-framework/core/src/scenario/runtime/orchestration/source_orchestration_plan.rs b/testing-framework/core/src/scenario/runtime/internal/orchestration/source_orchestration_plan.rs similarity index 100% rename from testing-framework/core/src/scenario/runtime/orchestration/source_orchestration_plan.rs rename to testing-framework/core/src/scenario/runtime/internal/orchestration/source_orchestration_plan.rs diff --git a/testing-framework/core/src/scenario/runtime/orchestration/source_resolver.rs b/testing-framework/core/src/scenario/runtime/internal/orchestration/source_resolver.rs similarity index 92% rename from testing-framework/core/src/scenario/runtime/orchestration/source_resolver.rs rename to testing-framework/core/src/scenario/runtime/internal/orchestration/source_resolver.rs index d6f822b..7c6895b 100644 --- a/testing-framework/core/src/scenario/runtime/orchestration/source_resolver.rs +++ b/testing-framework/core/src/scenario/runtime/internal/orchestration/source_resolver.rs @@ -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, }, }, }; diff --git a/testing-framework/core/src/scenario/runtime/providers/attach_provider.rs b/testing-framework/core/src/scenario/runtime/internal/providers/attach_provider.rs similarity index 100% rename from testing-framework/core/src/scenario/runtime/providers/attach_provider.rs rename to testing-framework/core/src/scenario/runtime/internal/providers/attach_provider.rs diff --git a/testing-framework/core/src/scenario/runtime/providers/external_provider.rs b/testing-framework/core/src/scenario/runtime/internal/providers/external_provider.rs similarity index 100% rename from testing-framework/core/src/scenario/runtime/providers/external_provider.rs rename to testing-framework/core/src/scenario/runtime/internal/providers/external_provider.rs diff --git a/testing-framework/core/src/scenario/runtime/providers/managed_provider.rs b/testing-framework/core/src/scenario/runtime/internal/providers/managed_provider.rs similarity index 97% rename from testing-framework/core/src/scenario/runtime/providers/managed_provider.rs rename to testing-framework/core/src/scenario/runtime/internal/providers/managed_provider.rs index 5eea666..a5ef529 100644 --- a/testing-framework/core/src/scenario/runtime/providers/managed_provider.rs +++ b/testing-framework/core/src/scenario/runtime/internal/providers/managed_provider.rs @@ -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)] diff --git a/testing-framework/core/src/scenario/runtime/providers/mod.rs b/testing-framework/core/src/scenario/runtime/internal/providers/mod.rs similarity index 100% rename from testing-framework/core/src/scenario/runtime/providers/mod.rs rename to testing-framework/core/src/scenario/runtime/internal/providers/mod.rs diff --git a/testing-framework/core/src/scenario/runtime/providers/source_providers.rs b/testing-framework/core/src/scenario/runtime/internal/providers/source_providers.rs similarity index 100% rename from testing-framework/core/src/scenario/runtime/providers/source_providers.rs rename to testing-framework/core/src/scenario/runtime/internal/providers/source_providers.rs diff --git a/testing-framework/core/src/scenario/runtime/mod.rs b/testing-framework/core/src/scenario/runtime/mod.rs index 33420c3..c5cfa01 100644 --- a/testing-framework/core/src/scenario/runtime/mod.rs +++ b/testing-framework/core/src/scenario/runtime/mod.rs @@ -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, diff --git a/testing-framework/core/src/workloads/chaos.rs b/testing-framework/core/src/workloads/chaos.rs index 38fba98..6c6be9b 100644 --- a/testing-framework/core/src/workloads/chaos.rs +++ b/testing-framework/core/src/workloads/chaos.rs @@ -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, }; diff --git a/testing-framework/deployers/compose/src/deployer/attach_provider.rs b/testing-framework/deployers/compose/src/deployer/attach_provider.rs index 24c16d6..2b35207 100644 --- a/testing-framework/deployers/compose/src/deployer/attach_provider.rs +++ b/testing-framework/deployers/compose/src/deployer/attach_provider.rs @@ -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; diff --git a/testing-framework/deployers/compose/src/deployer/clients.rs b/testing-framework/deployers/compose/src/deployer/clients.rs index 665acc3..0574391 100644 --- a/testing-framework/deployers/compose/src/deployer/clients.rs +++ b/testing-framework/deployers/compose/src/deployer/clients.rs @@ -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::{ diff --git a/testing-framework/deployers/compose/src/deployer/mod.rs b/testing-framework/deployers/compose/src/deployer/mod.rs index 9771a9a..3624563 100644 --- a/testing-framework/deployers/compose/src/deployer/mod.rs +++ b/testing-framework/deployers/compose/src/deployer/mod.rs @@ -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}; diff --git a/testing-framework/deployers/compose/src/deployer/orchestrator.rs b/testing-framework/deployers/compose/src/deployer/orchestrator.rs index 554db9b..3084bf6 100644 --- a/testing-framework/deployers/compose/src/deployer/orchestrator.rs +++ b/testing-framework/deployers/compose/src/deployer/orchestrator.rs @@ -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, }; diff --git a/testing-framework/deployers/compose/src/infrastructure/environment.rs b/testing-framework/deployers/compose/src/infrastructure/environment.rs index 2c98c50..b4bb6bd 100644 --- a/testing-framework/deployers/compose/src/infrastructure/environment.rs +++ b/testing-framework/deployers/compose/src/infrastructure/environment.rs @@ -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}; diff --git a/testing-framework/deployers/compose/src/lifecycle/block_feed.rs b/testing-framework/deployers/compose/src/lifecycle/block_feed.rs index ff72aae..a16dd84 100644 --- a/testing-framework/deployers/compose/src/lifecycle/block_feed.rs +++ b/testing-framework/deployers/compose/src/lifecycle/block_feed.rs @@ -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}; diff --git a/testing-framework/deployers/compose/src/lifecycle/cleanup.rs b/testing-framework/deployers/compose/src/lifecycle/cleanup.rs index 33e9cdc..2a640a2 100644 --- a/testing-framework/deployers/compose/src/lifecycle/cleanup.rs +++ b/testing-framework/deployers/compose/src/lifecycle/cleanup.rs @@ -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::{ diff --git a/testing-framework/deployers/k8s/src/deployer/attach_provider.rs b/testing-framework/deployers/k8s/src/deployer/attach_provider.rs index bdfa1fe..dbc1bcc 100644 --- a/testing-framework/deployers/k8s/src/deployer/attach_provider.rs +++ b/testing-framework/deployers/k8s/src/deployer/attach_provider.rs @@ -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; diff --git a/testing-framework/deployers/k8s/src/deployer/orchestrator.rs b/testing-framework/deployers/k8s/src/deployer/orchestrator.rs index 83ba257..279f035 100644 --- a/testing-framework/deployers/k8s/src/deployer/orchestrator.rs +++ b/testing-framework/deployers/k8s/src/deployer/orchestrator.rs @@ -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, }; diff --git a/testing-framework/deployers/k8s/src/infrastructure/cluster.rs b/testing-framework/deployers/k8s/src/infrastructure/cluster.rs index fa3ee24..66574d4 100644 --- a/testing-framework/deployers/k8s/src/infrastructure/cluster.rs +++ b/testing-framework/deployers/k8s/src/infrastructure/cluster.rs @@ -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; diff --git a/testing-framework/deployers/k8s/src/lifecycle/block_feed.rs b/testing-framework/deployers/k8s/src/lifecycle/block_feed.rs index d50351e..527a285 100644 --- a/testing-framework/deployers/k8s/src/lifecycle/block_feed.rs +++ b/testing-framework/deployers/k8s/src/lifecycle/block_feed.rs @@ -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}; diff --git a/testing-framework/deployers/k8s/src/lifecycle/cleanup.rs b/testing-framework/deployers/k8s/src/lifecycle/cleanup.rs index 6d64ebe..71c86ae 100644 --- a/testing-framework/deployers/k8s/src/lifecycle/cleanup.rs +++ b/testing-framework/deployers/k8s/src/lifecycle/cleanup.rs @@ -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}, diff --git a/testing-framework/deployers/local/src/deployer/orchestrator.rs b/testing-framework/deployers/local/src/deployer/orchestrator.rs index 5af3d2e..c17f54f 100644 --- a/testing-framework/deployers/local/src/deployer/orchestrator.rs +++ b/testing-framework/deployers/local/src/deployer/orchestrator.rs @@ -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, };