#[cfg(test)]
mod scope_tests {
use http::{Request, Response, StatusCode};
use k8s_openapi::api::core::v1::{ConfigMap, Node};
use kube::Client;
use kube::client::Body;
use serde_json::json;
use tower_test::mock;
use crate::scope::{ApiScope, Cluster, Namespaced};
type MockHandle = mock::Handle<Request<Body>, Response<Body>>;
fn mock_client() -> (Client, MockHandle) {
let (svc, handle) = mock::pair::<Request<Body>, Response<Body>>();
(Client::new(svc, "default"), handle)
}
fn ok_list_response(kind: &str) -> Response<Body> {
let body = json!({
"apiVersion": "v1",
"kind": kind,
"metadata": {},
"items": []
});
Response::builder()
.status(StatusCode::OK)
.header("Content-Type", "application/json")
.body(Body::from(serde_json::to_vec(&body).unwrap()))
.unwrap()
}
#[test]
fn cluster_namespace_returns_none() {
assert_eq!(ApiScope::<Node>::namespace(&Cluster), None);
}
#[test]
fn namespaced_namespace_returns_the_inner_str() {
assert_eq!(
ApiScope::<ConfigMap>::namespace(&Namespaced("my-ns")),
Some("my-ns")
);
}
#[test]
fn namespaced_namespace_returns_exact_str_including_edge_cases() {
assert_eq!(ApiScope::<ConfigMap>::namespace(&Namespaced("")), Some(""));
assert_eq!(
ApiScope::<ConfigMap>::namespace(&Namespaced("kube-system")),
Some("kube-system")
);
assert_eq!(
ApiScope::<ConfigMap>::namespace(&Namespaced("a-b-c-123")),
Some("a-b-c-123")
);
}
#[test]
fn cluster_is_copy() {
let a = Cluster;
let b = a; let _ = a; let _ = b;
}
#[test]
fn cluster_is_clone() {
let a = Cluster;
let b = a.clone();
let _ = b;
}
#[test]
fn namespaced_is_copy() {
let a = Namespaced("ns");
let b = a; let _ = a; let _ = b;
}
#[test]
fn namespaced_is_clone() {
let a = Namespaced("ns");
let b = a.clone();
assert_eq!(ApiScope::<ConfigMap>::namespace(&b), Some("ns"));
}
#[tokio::test]
async fn cluster_into_api_produces_all_api_without_namespace_segment() {
let (client, mut handle) = mock_client();
let server = tokio::spawn(async move {
let (req, send) = handle.next_request().await.unwrap();
let uri = req.uri().to_string();
assert!(
uri.contains("/api/v1/nodes"),
"expected cluster-scoped nodes URI, got: {uri}"
);
assert!(
!uri.contains("namespaces"),
"Api::all must not contain a namespace segment, got: {uri}"
);
send.send_response(ok_list_response("NodeList"));
});
let api = ApiScope::<Node>::into_api(Cluster, client);
api.list(&Default::default()).await.unwrap();
server.await.unwrap();
}
#[tokio::test]
async fn namespaced_into_api_produces_namespaced_api_with_correct_namespace() {
let (client, mut handle) = mock_client();
let server = tokio::spawn(async move {
let (req, send) = handle.next_request().await.unwrap();
let uri = req.uri().to_string();
assert!(
uri.contains("/namespaces/prod/configmaps"),
"expected namespace-scoped configmaps URI, got: {uri}"
);
send.send_response(ok_list_response("ConfigMapList"));
});
let api = ApiScope::<ConfigMap>::into_api(Namespaced("prod"), client);
api.list(&Default::default()).await.unwrap();
server.await.unwrap();
}
#[tokio::test]
async fn namespaced_into_api_uses_exact_namespace_string() {
let (client, mut handle) = mock_client();
let server = tokio::spawn(async move {
let (req, send) = handle.next_request().await.unwrap();
let uri = req.uri().to_string();
assert!(
uri.contains("/namespaces/kube-system/configmaps"),
"uri={uri}"
);
send.send_response(ok_list_response("ConfigMapList"));
});
let api = ApiScope::<ConfigMap>::into_api(Namespaced("kube-system"), client);
api.list(&Default::default()).await.unwrap();
server.await.unwrap();
}
fn assert_api_scope<K, S: ApiScope<K>>()
where
K: kube::Resource<DynamicType = ()>
+ Clone
+ serde::Serialize
+ serde::de::DeserializeOwned
+ 'static,
{
}
#[test]
fn cluster_implements_api_scope_for_cluster_scoped_resources() {
assert_api_scope::<Node, Cluster>();
}
#[test]
fn cluster_implements_api_scope_for_namespaced_resources() {
assert_api_scope::<ConfigMap, Cluster>();
}
#[test]
fn namespaced_implements_api_scope_for_namespaced_resources() {
assert_api_scope::<ConfigMap, Namespaced<'_>>();
}
#[test]
fn namespaced_clone_preserves_namespace_value() {
let original = Namespaced("staging");
let cloned = original.clone();
assert_eq!(
ApiScope::<ConfigMap>::namespace(&original),
ApiScope::<ConfigMap>::namespace(&cloned),
);
}
#[test]
fn cluster_clone_namespace_is_still_none() {
let original = Cluster;
let cloned = original.clone();
assert_eq!(
ApiScope::<Node>::namespace(&original),
ApiScope::<Node>::namespace(&cloned),
);
}
}