use std::pin::Pin;
use std::time::Duration;
use std::{future::Future, sync::Arc};
use anyhow::{anyhow, Context as _, Result};
use async_nats::{Client as NatsClient, ServerAddr};
use nkeys::KeyPair;
use url::Url;
use wasmcloud_control_interface::{Client as WasmcloudCtlClient, ClientBuilder};
use wasmcloud_host::wasmbus::host_config::PolicyService;
use wasmcloud_host::wasmbus::{Features, Host, HostConfig};
pub async fn assert_put_label(
client: impl AsRef<WasmcloudCtlClient>,
host_id: impl AsRef<str>,
key: impl AsRef<str>,
value: impl AsRef<str>,
) -> Result<()> {
let client = client.as_ref();
let host_id = host_id.as_ref();
let key = key.as_ref();
let value = value.as_ref();
client
.put_label(host_id, key, value)
.await
.map(|_| ())
.map_err(|e| anyhow!(e).context("failed to put label"))
}
pub async fn assert_delete_label(
client: impl AsRef<WasmcloudCtlClient>,
host_id: impl AsRef<str>,
key: impl AsRef<str>,
) -> Result<()> {
let client = client.as_ref();
let host_id = host_id.as_ref();
let key = key.as_ref();
client
.delete_label(host_id, key)
.await
.map(|_| ())
.map_err(|e| anyhow!(e).context("failed to put label"))
}
#[allow(unused)]
pub struct WasmCloudTestHost {
cluster_key: Arc<KeyPair>,
host_key: Arc<KeyPair>,
nats_url: ServerAddr,
lattice_name: String,
host: Arc<Host>,
shutdown_hook: Pin<Box<dyn Future<Output = Result<()>>>>,
}
#[allow(unused)]
impl WasmCloudTestHost {
pub async fn start(nats_url: impl AsRef<str>, lattice_name: impl AsRef<str>) -> Result<Self> {
Self::start_custom(nats_url, lattice_name, None, None, None, None, None).await
}
pub async fn start_custom(
nats_url: impl AsRef<str>,
lattice_name: impl AsRef<str>,
cluster_key: Option<KeyPair>,
host_key: Option<KeyPair>,
policy_service_config: Option<PolicyService>,
secrets_topic_prefix: Option<String>,
experimental_features: Option<Features>,
) -> Result<Self> {
let nats_url = Url::try_from(nats_url.as_ref()).context("failed to parse NATS URL")?;
let lattice_name = lattice_name.as_ref();
let cluster_key = Arc::new(cluster_key.unwrap_or(KeyPair::new_cluster()));
let host_key = Arc::new(host_key.unwrap_or(KeyPair::new_server()));
let experimental_features = experimental_features.unwrap_or_else(|| {
Features::new()
.enable_builtin_http_client()
.enable_builtin_http_server()
.enable_builtin_messaging_nats()
.enable_wasmcloud_messaging_v3()
});
let mut host_config = HostConfig {
ctl_nats_url: nats_url.clone(),
rpc_nats_url: nats_url.clone(),
lattice: lattice_name.into(),
host_key: Some(Arc::clone(&host_key)),
provider_shutdown_delay: Some(Duration::from_millis(300)),
allow_file_load: true,
secrets_topic_prefix,
experimental_features,
..Default::default()
};
if let Some(psc) = policy_service_config {
host_config.policy_service_config = psc;
}
let (host, shutdown_hook) = Host::new(host_config)
.await
.context("failed to initialize host")?;
Ok(Self {
cluster_key,
host_key,
nats_url: ServerAddr::from_url(nats_url.clone())
.context("failed to build NATS server address from URL")?,
lattice_name: lattice_name.into(),
host,
shutdown_hook: Box::pin(shutdown_hook),
})
}
pub async fn stop(self) -> Result<()> {
self.shutdown_hook
.await
.context("failed to perform shutdown hook")
}
pub async fn get_ctl_client(
&self,
nats_client: Option<NatsClient>,
) -> Result<WasmcloudCtlClient> {
let nats_client = match nats_client {
Some(c) => c,
None => async_nats::connect(self.nats_url.clone())
.await
.context("failed to connect to NATS client via URL used at test host creation")?,
};
Ok(ClientBuilder::new(nats_client.clone())
.lattice(self.lattice_name.to_string())
.build())
}
#[must_use]
pub fn host_key(&self) -> Arc<KeyPair> {
self.host_key.clone()
}
#[must_use]
pub fn cluster_key(&self) -> Arc<KeyPair> {
self.cluster_key.clone()
}
#[must_use]
pub fn lattice_name(&self) -> &str {
self.lattice_name.as_ref()
}
#[must_use]
pub fn host_id(&self) -> String {
self.host_key().public_key()
}
}