testcontainers_modules/kwok/
mod.rs1use testcontainers::{
2 core::{ContainerPort, WaitFor},
3 Image,
4};
5
6const NAME: &str = "registry.k8s.io/kwok/cluster";
7const TAG: &str = "v0.5.2-k8s.v1.29.2";
8const DEFAULT_WAIT: u64 = 3000;
9pub const KWOK_CLUSTER_PORT: ContainerPort = ContainerPort::Tcp(8080);
14
15#[derive(Debug, Default, Clone)]
36pub struct KwokCluster {
37 _priv: (),
41}
42
43impl Image for KwokCluster {
44 fn name(&self) -> &str {
45 NAME
46 }
47
48 fn tag(&self) -> &str {
49 TAG
50 }
51
52 fn ready_conditions(&self) -> Vec<WaitFor> {
53 vec![
54 WaitFor::message_on_stdout("Starting to serve on [::]:8080"),
55 WaitFor::millis(DEFAULT_WAIT),
56 ]
57 }
58
59 fn expose_ports(&self) -> &[ContainerPort] {
60 &[KWOK_CLUSTER_PORT]
61 }
62}
63
64#[cfg(test)]
65mod test {
66 use k8s_openapi::api::core::v1::Namespace;
67 use kube::{
68 api::ListParams,
69 client::Client,
70 config::{AuthInfo, Cluster, KubeConfigOptions, Kubeconfig, NamedAuthInfo, NamedCluster},
71 Api, Config,
72 };
73 use rustls::crypto::CryptoProvider;
74 use testcontainers::core::IntoContainerPort;
75
76 use crate::{kwok::KwokCluster, testcontainers::runners::AsyncRunner};
77
78 const CLUSTER_NAME: &str = "kwok-kwok";
79 const CONTEXT_NAME: &str = "kwok-kwok";
80 const CLUSTER_USER: &str = "kwok-kwok";
81
82 #[tokio::test]
83 async fn test_kwok_image() -> Result<(), Box<dyn std::error::Error + 'static>> {
84 if CryptoProvider::get_default().is_none() {
85 rustls::crypto::ring::default_provider()
86 .install_default()
87 .expect("Error initializing rustls provider");
88 }
89
90 let node = KwokCluster::default().start().await?;
91 let host_port = node.get_host_port_ipv4(8080.tcp()).await?;
92
93 let kubeconfig = Kubeconfig {
95 clusters: vec![NamedCluster {
96 name: String::from(CLUSTER_NAME),
97 cluster: Some(Cluster {
98 server: Some(format!("http://localhost:{host_port}")), ..Default::default()
100 }),
101 }],
102 contexts: vec![kube::config::NamedContext {
103 name: CONTEXT_NAME.to_string(),
104 context: Option::from(kube::config::Context {
105 cluster: CLUSTER_NAME.to_string(),
106 user: Some(String::from(CLUSTER_USER)),
107 ..Default::default()
108 }),
109 }],
110 auth_infos: vec![NamedAuthInfo {
111 name: String::from(CLUSTER_USER),
112 auth_info: Some(AuthInfo {
113 token: None,
114 ..Default::default()
115 }),
116 }],
117 current_context: Some(CONTEXT_NAME.to_string()),
118 ..Default::default()
119 };
120 let kubeconfigoptions = KubeConfigOptions {
121 context: Some(CONTEXT_NAME.to_string()),
122 cluster: Some(CLUSTER_NAME.to_string()),
123 user: None,
124 };
125
126 let config = Config::from_custom_kubeconfig(kubeconfig, &kubeconfigoptions)
128 .await
129 .unwrap();
130
131 let client = Client::try_from(config).unwrap();
133
134 let api: Api<Namespace> = Api::all(client);
135 let namespaces = api.list(&ListParams::default()).await.unwrap();
136 assert_eq!(namespaces.items.len(), 4);
137 let namespace_names: Vec<&str> = namespaces
138 .items
139 .iter()
140 .map(|namespace| namespace.metadata.name.as_deref().unwrap())
141 .collect();
142 assert_eq!(
143 namespace_names,
144 vec!["default", "kube-node-lease", "kube-public", "kube-system"]
145 );
146
147 Ok(())
148 }
149}