use std::fmt::Debug;
use std::marker::PhantomData;
use async_trait::async_trait;
use k8s_openapi::NamespaceResourceScope;
use kube::Resource;
use serde::de::DeserializeOwned;
use serde::Serialize;
use crate::cache::ProvideApi;
use crate::Finalize;
pub struct K8sRepository<R, P>
where
R: Resource<Scope = NamespaceResourceScope> + Serialize + DeserializeOwned + Debug + Clone + Send + Sync + 'static,
R::DynamicType: Default,
P: ProvideApi<R>,
{
api_provider: P,
phantom: PhantomData<R>,
}
impl<R, P> K8sRepository<R, P>
where
R: Resource<Scope = NamespaceResourceScope> + Serialize + DeserializeOwned + Debug + Clone + Send + Sync + 'static,
R::DynamicType: Default,
P: ProvideApi<R> + Send + Sync,
{
pub fn new(api_provider: P) -> Self {
K8sRepository {
api_provider,
phantom: PhantomData,
}
}
}
#[async_trait]
impl<R, P> Finalize<R, P> for K8sRepository<R, P>
where
R: Resource<Scope = NamespaceResourceScope> + Serialize + DeserializeOwned + Debug + Clone + Send + Sync + 'static,
R::DynamicType: Default,
P: ProvideApi<R> + Send + Sync,
{
fn api_provider(&self) -> &P {
&self.api_provider
}
}
#[cfg(test)]
mod tests {
use super::*;
use k8s_openapi::api::core::v1::ConfigMap;
use kube::client::Body;
use kube::Client;
use kube::CustomResource;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
use tower_test::mock;
use crate::cache::CachedApiProvider;
use crate::cache::CachingStrategy;
use crate::cache::StaticApiProvider;
fn test_client() -> Client {
let (mock_service, _handle) = mock::pair::<http::Request<Body>, http::Response<hyper::body::Incoming>>();
Client::new(mock_service, "default")
}
#[derive(CustomResource, Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema)]
#[kube(group = "test.kuberator.io", version = "v1", kind = "TestResource", namespaced)]
#[allow(dead_code)]
struct TestResourceSpec {
value: String,
}
#[tokio::test]
async fn test_k8s_repository_new_with_static_provider() {
let client = test_client();
let api_provider = StaticApiProvider::new(client, vec!["default"], CachingStrategy::Strict);
let repo = K8sRepository::<ConfigMap, _>::new(api_provider);
let _ = repo;
}
#[tokio::test]
async fn test_k8s_repository_new_with_cached_provider() {
let client = test_client();
let api_provider = CachedApiProvider::new(client);
let repo = K8sRepository::<ConfigMap, _>::new(api_provider);
let _ = repo;
}
#[tokio::test]
async fn test_k8s_repository_api_provider_returns_reference() {
let client = test_client();
let api_provider = StaticApiProvider::new(client.clone(), vec!["default"], CachingStrategy::Strict);
let repo = K8sRepository::<ConfigMap, _>::new(api_provider);
let returned_provider = repo.api_provider();
let _ = returned_provider.get("default");
}
#[tokio::test]
async fn test_k8s_repository_with_custom_resource() {
let client = test_client();
let api_provider = StaticApiProvider::new(client, vec!["default", "production"], CachingStrategy::Adhoc);
let repo = K8sRepository::<TestResource, _>::new(api_provider);
let provider = repo.api_provider();
let _ = provider.get("default");
let _ = provider.get("production");
}
#[tokio::test]
async fn test_k8s_repository_with_extendable_strategy() {
let client = test_client();
let api_provider = StaticApiProvider::new(client, vec!["default"], CachingStrategy::Extendable);
let repo = K8sRepository::<ConfigMap, _>::new(api_provider);
let provider = repo.api_provider();
let _ = provider.get("default");
let _ = provider.get("new-namespace"); }
#[tokio::test]
async fn test_k8s_repository_finalize_trait_implementation() {
let client = test_client();
let api_provider = StaticApiProvider::new(client, vec!["default"], CachingStrategy::Strict);
let repo = K8sRepository::<ConfigMap, _>::new(api_provider);
let provider_ref = Finalize::api_provider(&repo);
let _ = provider_ref.get("default");
}
#[tokio::test]
async fn test_k8s_repository_multiple_namespaces() {
let client = test_client();
let namespaces = vec!["default", "kube-system", "production", "staging"];
let api_provider = StaticApiProvider::new(client, namespaces.clone(), CachingStrategy::Strict);
let repo = K8sRepository::<ConfigMap, _>::new(api_provider);
let provider = repo.api_provider();
for namespace in namespaces {
let api = provider.get(namespace);
assert!(api.is_ok(), "Should get API for namespace: {}", namespace);
}
}
}