168 lines
4.5 KiB
Rust
Raw Normal View History

2026-01-19 08:34:17 +01:00
use testing_framework_core::{
manual::ManualClusterHandle,
2026-01-19 08:34:17 +01:00
nodes::ApiClient,
scenario::{DynError, NodeControlHandle, StartNodeOptions, StartedNode},
2026-01-19 08:34:17 +01:00
topology::{
config::{TopologyBuildError, TopologyBuilder, TopologyConfig},
readiness::{ReadinessCheck, ReadinessError},
},
};
use thiserror::Error;
use crate::node_control::{LocalNodeManager, LocalNodeManagerError, ReadinessNode};
2026-01-19 08:34:17 +01:00
mod readiness;
use readiness::ManualNetworkReadiness;
#[derive(Debug, Error)]
pub enum ManualClusterError {
#[error("failed to build topology: {source}")]
Build {
#[source]
source: TopologyBuildError,
},
#[error(transparent)]
Dynamic(#[from] LocalNodeManagerError),
2026-01-19 08:34:17 +01:00
}
/// Imperative, in-process cluster that can start nodes on demand.
pub struct LocalManualCluster {
nodes: LocalNodeManager,
2026-01-19 08:34:17 +01:00
}
impl LocalManualCluster {
pub(crate) fn from_builder(builder: TopologyBuilder) -> Result<Self, ManualClusterError> {
2026-01-19 08:34:17 +01:00
let descriptors = builder
.build()
.map_err(|source| ManualClusterError::Build { source })?;
let nodes = LocalNodeManager::new(
2026-01-19 08:34:17 +01:00
descriptors,
testing_framework_core::scenario::NodeClients::default(),
);
2026-01-19 08:34:17 +01:00
Ok(Self { nodes })
}
pub(crate) fn from_config(config: TopologyConfig) -> Result<Self, ManualClusterError> {
let builder = TopologyBuilder::new(config);
Self::from_builder(builder)
}
2026-01-19 08:34:17 +01:00
#[must_use]
pub fn node_client(&self, name: &str) -> Option<ApiClient> {
self.nodes.node_client(name)
}
#[must_use]
pub fn node_pid(&self, name: &str) -> Option<u32> {
self.nodes.node_pid(name)
}
2026-01-26 08:26:15 +01:00
pub async fn start_node(&self, name: &str) -> Result<StartedNode, ManualClusterError> {
2026-01-19 08:34:17 +01:00
Ok(self
.nodes
2026-01-26 08:26:15 +01:00
.start_node_with(name, StartNodeOptions::default())
2026-01-19 08:34:17 +01:00
.await?)
}
2026-01-26 08:26:15 +01:00
pub async fn start_node_with(
2026-01-19 08:34:17 +01:00
&self,
name: &str,
options: StartNodeOptions,
) -> Result<StartedNode, ManualClusterError> {
2026-01-26 08:26:15 +01:00
Ok(self.nodes.start_node_with(name, options).await?)
2026-01-19 08:34:17 +01:00
}
pub fn stop_all(&self) {
self.nodes.stop_all();
}
pub async fn restart_node(&self, name: &str) -> Result<(), ManualClusterError> {
Ok(self.nodes.restart_node(name).await?)
}
pub async fn stop_node(&self, name: &str) -> Result<(), ManualClusterError> {
Ok(self.nodes.stop_node(name).await?)
}
2026-01-19 08:34:17 +01:00
pub async fn wait_network_ready(&self) -> Result<(), ReadinessError> {
let nodes = self.nodes.readiness_nodes();
if self.is_singleton(&nodes) {
return Ok(());
}
self.wait_nodes_ready(nodes).await
}
fn is_singleton(&self, nodes: &[ReadinessNode]) -> bool {
nodes.len() <= 1
}
async fn wait_nodes_ready(&self, nodes: Vec<ReadinessNode>) -> Result<(), ReadinessError> {
ManualNetworkReadiness::new(nodes).wait().await
}
}
2026-01-19 10:05:58 +01:00
impl Drop for LocalManualCluster {
2026-01-19 10:05:58 +01:00
fn drop(&mut self) {
self.stop_all();
}
}
#[async_trait::async_trait]
impl NodeControlHandle for LocalManualCluster {
async fn restart_node(&self, name: &str) -> Result<(), DynError> {
self.nodes
.restart_node(name)
.await
.map_err(|err| err.into())
}
async fn stop_node(&self, name: &str) -> Result<(), DynError> {
self.nodes.stop_node(name).await.map_err(|err| err.into())
}
async fn start_node(&self, name: &str) -> Result<StartedNode, DynError> {
self.start_node_with(name, StartNodeOptions::default())
.await
.map_err(|err| err.into())
}
async fn start_node_with(
&self,
name: &str,
options: StartNodeOptions,
) -> Result<StartedNode, DynError> {
self.start_node_with(name, options)
.await
.map_err(|err| err.into())
}
fn node_client(&self, name: &str) -> Option<ApiClient> {
self.node_client(name)
}
fn node_pid(&self, name: &str) -> Option<u32> {
self.node_pid(name)
}
}
#[async_trait::async_trait]
impl ManualClusterHandle for LocalManualCluster {
2026-01-26 08:26:15 +01:00
async fn start_node_with(
&self,
name: &str,
options: StartNodeOptions,
) -> Result<StartedNode, DynError> {
2026-01-26 08:26:15 +01:00
self.start_node_with(name, options)
.await
.map_err(|err| err.into())
}
async fn wait_network_ready(&self) -> Result<(), DynError> {
self.wait_network_ready().await.map_err(|err| err.into())
}
}