174 lines
4.7 KiB
Rust
Raw Normal View History

2026-01-19 08:34:17 +01:00
use testing_framework_core::{
manual::ManualClusterHandle,
scenario::{
DynError, ExternalNodeSource, NodeClients, NodeControlHandle, ReadinessError,
StartNodeOptions, StartedNode,
},
2026-01-19 08:34:17 +01:00
};
use thiserror::Error;
2026-02-02 07:19:22 +01:00
use crate::{
env::LocalDeployerEnv,
keep_tempdir_from_env,
node_control::{NodeManager, NodeManagerError, NodeManagerSeed},
2026-02-02 07:19:22 +01:00
};
2026-01-19 08:34:17 +01:00
#[derive(Debug, Error)]
pub enum ManualClusterError {
#[error(transparent)]
2026-02-02 07:19:22 +01:00
Dynamic(#[from] NodeManagerError),
2026-01-19 08:34:17 +01:00
}
/// Imperative, in-process cluster that can start nodes on demand.
2026-02-02 07:19:22 +01:00
pub struct ManualCluster<E: LocalDeployerEnv> {
nodes: NodeManager<E>,
2026-01-19 08:34:17 +01:00
}
2026-02-02 07:19:22 +01:00
impl<E: LocalDeployerEnv> ManualCluster<E> {
pub fn from_topology(descriptors: E::Deployment) -> Self {
let nodes = NodeManager::new_with_seed(
2026-01-19 08:34:17 +01:00
descriptors,
testing_framework_core::scenario::NodeClients::default(),
keep_tempdir_from_env(),
NodeManagerSeed::default(),
2026-01-19 08:34:17 +01:00
);
2026-02-05 08:23:14 +02:00
2026-02-02 07:19:22 +01:00
Self { nodes }
2026-02-05 08:23:14 +02:00
}
2026-01-19 08:34:17 +01:00
#[must_use]
2026-02-02 07:19:22 +01:00
pub fn node_client(&self, name: &str) -> Option<E::NodeClient> {
2026-01-19 08:34:17 +01:00
self.nodes.node_client(name)
}
2026-02-05 08:23:14 +02:00
#[must_use]
pub fn node_pid(&self, name: &str) -> Option<u32> {
self.nodes.node_pid(name)
}
2026-02-02 07:19:22 +01:00
pub async fn start_node(&self, name: &str) -> Result<StartedNode<E>, ManualClusterError> {
2026-01-19 08:34:17 +01:00
Ok(self
.nodes
2026-02-02 07:19:22 +01:00
.start_node_with(name, StartNodeOptions::<E>::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,
2026-02-02 07:19:22 +01:00
options: StartNodeOptions<E>,
) -> Result<StartedNode<E>, 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();
}
2026-02-05 08:23:14 +02:00
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> {
2026-02-02 07:19:22 +01:00
self.nodes.wait_network_ready().await
2026-01-19 08:34:17 +01:00
}
pub async fn wait_node_ready(&self, name: &str) -> Result<(), ManualClusterError> {
self.nodes.wait_node_ready(name).await?;
Ok(())
}
#[must_use]
pub fn node_clients(&self) -> NodeClients<E> {
self.nodes.node_clients()
}
pub fn add_external_sources(
&self,
external_sources: impl IntoIterator<Item = ExternalNodeSource>,
) -> Result<(), DynError> {
let node_clients = self.nodes.node_clients();
for source in external_sources {
let client = E::external_node_client(&source)?;
node_clients.add_node(client);
}
Ok(())
}
pub fn add_external_clients(&self, clients: impl IntoIterator<Item = E::NodeClient>) {
let node_clients = self.nodes.node_clients();
for client in clients {
node_clients.add_node(client);
}
}
2026-01-19 08:34:17 +01:00
}
2026-01-19 10:05:58 +01:00
2026-02-02 07:19:22 +01:00
impl<E: LocalDeployerEnv> Drop for ManualCluster<E> {
2026-01-19 10:05:58 +01:00
fn drop(&mut self) {
self.stop_all();
}
}
2026-02-05 08:23:14 +02:00
#[async_trait::async_trait]
2026-02-02 07:19:22 +01:00
impl<E: LocalDeployerEnv> NodeControlHandle<E> for ManualCluster<E> {
2026-02-05 08:23:14 +02:00
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())
}
2026-02-02 07:19:22 +01:00
async fn start_node(&self, name: &str) -> Result<StartedNode<E>, DynError> {
self.nodes
.start_node_with(name, StartNodeOptions::<E>::default())
2026-02-05 08:23:14 +02:00
.await
.map_err(|err| err.into())
}
async fn start_node_with(
&self,
name: &str,
2026-02-02 07:19:22 +01:00
options: StartNodeOptions<E>,
) -> Result<StartedNode<E>, DynError> {
self.nodes
.start_node_with(name, options)
2026-02-05 08:23:14 +02:00
.await
.map_err(|err| err.into())
}
2026-02-02 07:19:22 +01:00
fn node_client(&self, name: &str) -> Option<E::NodeClient> {
2026-02-05 08:23:14 +02:00
self.node_client(name)
}
fn node_pid(&self, name: &str) -> Option<u32> {
self.node_pid(name)
}
}
#[async_trait::async_trait]
2026-02-02 07:19:22 +01:00
impl<E: LocalDeployerEnv> ManualClusterHandle<E> for ManualCluster<E> {
2026-01-26 08:26:15 +01:00
async fn start_node_with(
&self,
name: &str,
2026-02-02 07:19:22 +01:00
options: StartNodeOptions<E>,
) -> Result<StartedNode<E>, DynError> {
self.nodes
.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())
}
}