diff --git a/testing-framework/core/src/scenario/definition.rs b/testing-framework/core/src/scenario/definition.rs index b16b6a7..15c7ea9 100644 --- a/testing-framework/core/src/scenario/definition.rs +++ b/testing-framework/core/src/scenario/definition.rs @@ -117,6 +117,16 @@ impl Scenario { &self.sources } + #[must_use] + pub fn attached_source(&self) -> Option<&AttachSource> { + self.sources.attached_source() + } + + #[must_use] + pub fn external_nodes(&self) -> &[ExternalNodeSource] { + self.sources.external_nodes() + } + #[must_use] pub const fn source_orchestration_plan(&self) -> &SourceOrchestrationPlan { &self.source_orchestration_plan diff --git a/testing-framework/core/src/scenario/sources/model.rs b/testing-framework/core/src/scenario/sources/model.rs index 98c60ad..5b0ec2c 100644 --- a/testing-framework/core/src/scenario/sources/model.rs +++ b/testing-framework/core/src/scenario/sources/model.rs @@ -43,6 +43,38 @@ impl AttachSource { services, } } + + #[must_use] + pub fn compose_project(&self) -> Option<&str> { + match self { + Self::Compose { project, .. } => project.as_deref(), + Self::K8s { .. } => None, + } + } + + #[must_use] + pub fn compose_services(&self) -> Option<&[String]> { + match self { + Self::Compose { services, .. } => Some(services), + Self::K8s { .. } => None, + } + } + + #[must_use] + pub fn k8s_namespace(&self) -> Option<&str> { + match self { + Self::K8s { namespace, .. } => namespace.as_deref(), + Self::Compose { .. } => None, + } + } + + #[must_use] + pub fn k8s_label_selector(&self) -> Option<&str> { + match self { + Self::K8s { label_selector, .. } => Some(label_selector), + Self::Compose { .. } => None, + } + } } /// Static external node endpoint that should be included in the runtime @@ -140,6 +172,14 @@ impl ScenarioSources { Self::ExternalOnly { external } } + #[must_use] + pub fn attached_source(&self) -> Option<&AttachSource> { + match self { + Self::Attached { attach, .. } => Some(attach), + Self::Managed { .. } | Self::ExternalOnly { .. } => None, + } + } + #[must_use] pub fn external_nodes(&self) -> &[ExternalNodeSource] { match self { diff --git a/testing-framework/deployers/compose/src/deployer/attach_provider.rs b/testing-framework/deployers/compose/src/deployer/attach_provider.rs index 87358aa..06c8d61 100644 --- a/testing-framework/deployers/compose/src/deployer/attach_provider.rs +++ b/testing-framework/deployers/compose/src/deployer/attach_provider.rs @@ -87,14 +87,15 @@ fn to_discovery_error(source: DynError) -> AttachProviderError { fn compose_attach_request( source: &AttachSource, ) -> Result, AttachProviderError> { - let AttachSource::Compose { project, services } = source else { - return Err(AttachProviderError::UnsupportedSource { - attach_source: source.clone(), - }); - }; + let services = + source + .compose_services() + .ok_or_else(|| AttachProviderError::UnsupportedSource { + attach_source: source.clone(), + })?; - let project = project - .as_deref() + let project = source + .compose_project() .ok_or_else(|| AttachProviderError::Discovery { source: ComposeAttachDiscoveryError::MissingProjectName.into(), })?; @@ -173,13 +174,12 @@ impl ClusterWaitHandle for ComposeAttachedClusterWait } fn compose_wait_request(source: &AttachSource) -> Result, DynError> { - let AttachSource::Compose { project, services } = source else { - return Err("compose cluster wait requires a compose attach source".into()); - }; - - let project = project - .as_deref() - .ok_or(ComposeAttachDiscoveryError::MissingProjectName)?; + let project = source + .compose_project() + .ok_or_else(|| DynError::from("compose cluster wait requires a compose attach source"))?; + let services = source + .compose_services() + .ok_or_else(|| DynError::from("compose cluster wait requires a compose attach source"))?; Ok(ComposeAttachRequest { project, services }) } diff --git a/testing-framework/deployers/compose/src/deployer/orchestrator.rs b/testing-framework/deployers/compose/src/deployer/orchestrator.rs index ddd88f0..c4fdc4f 100644 --- a/testing-framework/deployers/compose/src/deployer/orchestrator.rs +++ b/testing-framework/deployers/compose/src/deployer/orchestrator.rs @@ -6,9 +6,9 @@ use testing_framework_core::{ ApplicationExternalProvider, AttachSource, CleanupGuard, ClusterWaitHandle, DeploymentPolicy, FeedHandle, FeedRuntime, HttpReadinessRequirement, Metrics, NodeClients, NodeControlHandle, ObservabilityCapabilityProvider, ObservabilityInputs, - RequiresNodeControl, RunContext, Runner, Scenario, ScenarioSources, - SourceOrchestrationPlan, SourceProviders, StaticManagedProvider, - build_source_orchestration_plan, orchestrate_sources_with_providers, + RequiresNodeControl, RunContext, Runner, Scenario, SourceOrchestrationPlan, + SourceProviders, StaticManagedProvider, build_source_orchestration_plan, + orchestrate_sources_with_providers, }, topology::DeploymentDescriptor, }; @@ -214,21 +214,15 @@ impl DeploymentOrchestrator { return Ok(None); } - let ScenarioSources::Attached { attach, .. } = scenario.sources() else { - return Err(ComposeRunnerError::InternalInvariant { + let attach = scenario + .attached_source() + .ok_or(ComposeRunnerError::InternalInvariant { message: "attached node control requested outside attached source mode", - }); - }; + })?; - let AttachSource::Compose { project, .. } = attach else { - return Err(ComposeRunnerError::InternalInvariant { - message: "compose deployer requires compose attach source for node control", - }); - }; - - let Some(project_name) = project - .as_ref() - .map(|value| value.trim()) + let Some(project_name) = attach + .compose_project() + .map(str::trim) .filter(|value| !value.is_empty()) else { return Err(ComposeRunnerError::InternalInvariant { @@ -248,11 +242,11 @@ impl DeploymentOrchestrator { where Caps: Send + Sync, { - let ScenarioSources::Attached { attach, .. } = scenario.sources() else { - return Err(ComposeRunnerError::InternalInvariant { + let attach = scenario + .attached_source() + .ok_or(ComposeRunnerError::InternalInvariant { message: "compose attached cluster wait requested outside attached source mode", - }); - }; + })?; Ok(Arc::new(ComposeAttachedClusterWait::::new( compose_runner_host(), @@ -378,13 +372,10 @@ where E: ComposeDeployEnv, Caps: Send + Sync, { - let project_name = match scenario.sources() { - ScenarioSources::Attached { - attach: AttachSource::Compose { project, .. }, - .. - } => project.clone(), - _ => None, - }; + let project_name = scenario + .attached_source() + .and_then(|attach| attach.compose_project()) + .map(ToOwned::to_owned); ComposeDeploymentMetadata { project_name } } diff --git a/testing-framework/deployers/k8s/src/deployer/attach_provider.rs b/testing-framework/deployers/k8s/src/deployer/attach_provider.rs index b10a24a..bae5692 100644 --- a/testing-framework/deployers/k8s/src/deployer/attach_provider.rs +++ b/testing-framework/deployers/k8s/src/deployer/attach_provider.rs @@ -91,11 +91,7 @@ fn to_discovery_error(source: DynError) -> AttachProviderError { } fn k8s_attach_request(source: &AttachSource) -> Result, AttachProviderError> { - let AttachSource::K8s { - namespace, - label_selector, - } = source - else { + let Some(label_selector) = source.k8s_label_selector() else { return Err(AttachProviderError::UnsupportedSource { attach_source: source.clone(), }); @@ -108,7 +104,7 @@ fn k8s_attach_request(source: &AttachSource) -> Result, Att } Ok(K8sAttachRequest { - namespace: namespace.as_deref().unwrap_or("default"), + namespace: source.k8s_namespace().unwrap_or("default"), label_selector, }) } @@ -247,20 +243,16 @@ impl ClusterWaitHandle for K8sAttachedClusterWait { } fn k8s_wait_request(source: &AttachSource) -> Result, DynError> { - let AttachSource::K8s { - namespace, - label_selector, - } = source - else { - return Err("k8s cluster wait requires a k8s attach source".into()); - }; + let label_selector = source + .k8s_label_selector() + .ok_or_else(|| DynError::from("k8s cluster wait requires a k8s attach source"))?; if label_selector.trim().is_empty() { return Err(K8sAttachDiscoveryError::EmptyLabelSelector.into()); } Ok(K8sAttachRequest { - namespace: namespace.as_deref().unwrap_or("default"), + namespace: source.k8s_namespace().unwrap_or("default"), label_selector, }) } diff --git a/testing-framework/deployers/k8s/src/deployer/orchestrator.rs b/testing-framework/deployers/k8s/src/deployer/orchestrator.rs index eb39b33..ec1cb80 100644 --- a/testing-framework/deployers/k8s/src/deployer/orchestrator.rs +++ b/testing-framework/deployers/k8s/src/deployer/orchestrator.rs @@ -5,12 +5,11 @@ use kube::Client; use reqwest::Url; use testing_framework_core::{ scenario::{ - Application, ApplicationExternalProvider, AttachSource, CleanupGuard, ClusterWaitHandle, - Deployer, DynError, FeedHandle, FeedRuntime, HttpReadinessRequirement, Metrics, - MetricsError, NodeClients, ObservabilityCapabilityProvider, ObservabilityInputs, - RequiresNodeControl, RunContext, Runner, Scenario, ScenarioSources, - SourceOrchestrationPlan, SourceProviders, StaticManagedProvider, - build_source_orchestration_plan, orchestrate_sources_with_providers, + Application, ApplicationExternalProvider, CleanupGuard, ClusterWaitHandle, Deployer, + DynError, FeedHandle, FeedRuntime, HttpReadinessRequirement, Metrics, MetricsError, + NodeClients, ObservabilityCapabilityProvider, ObservabilityInputs, RequiresNodeControl, + RunContext, Runner, Scenario, SourceOrchestrationPlan, SourceProviders, + StaticManagedProvider, build_source_orchestration_plan, orchestrate_sources_with_providers, }, topology::DeploymentDescriptor, }; @@ -250,22 +249,18 @@ where E: K8sDeployEnv, Caps: Send + Sync, { - match scenario.sources() { - ScenarioSources::Attached { - attach: - AttachSource::K8s { - namespace, - label_selector, - }, - .. - } => K8sDeploymentMetadata { - namespace: namespace.clone(), - label_selector: Some(label_selector.clone()), - }, - _ => K8sDeploymentMetadata { - namespace: None, - label_selector: None, - }, + let namespace = scenario + .attached_source() + .and_then(|attach| attach.k8s_namespace()) + .map(ToOwned::to_owned); + let label_selector = scenario + .attached_source() + .and_then(|attach| attach.k8s_label_selector()) + .map(ToOwned::to_owned); + + K8sDeploymentMetadata { + namespace, + label_selector, } } @@ -277,11 +272,11 @@ where E: K8sDeployEnv, Caps: Send + Sync, { - let ScenarioSources::Attached { attach, .. } = scenario.sources() else { - return Err(K8sRunnerError::InternalInvariant { + let attach = scenario + .attached_source() + .ok_or_else(|| K8sRunnerError::InternalInvariant { message: "k8s attached cluster wait requested outside attached source mode".to_owned(), - }); - }; + })?; Ok(Arc::new(K8sAttachedClusterWait::::new( client,