Skip to content

Commit 3bc8d5d

Browse files
committed
moved tests and made them more thorough
1 parent b52d4a1 commit 3bc8d5d

4 files changed

Lines changed: 232 additions & 51 deletions

File tree

rust/operator-binary/src/controller.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,18 @@ pub(crate) mod test_support {
672672
use super::{ValidatedCluster, dereference::DereferencedObjects, validate::validate};
673673
use crate::crd::{authentication::ResolvedAuthenticationClasses, v1alpha1};
674674

675+
/// The expected `app.kubernetes.io/version` label value for the given product version.
676+
///
677+
/// The `-stackable` suffix carries the operator's own version, which is `0.0.0-dev` on main
678+
/// but rewritten by the release process — so tests must derive it rather than hardcode it,
679+
/// or they fail on release branches.
680+
pub fn app_version_label(product_version: &str) -> String {
681+
format!(
682+
"{product_version}-stackable{}",
683+
crate::built_info::PKG_VERSION
684+
)
685+
}
686+
675687
pub fn minimal_kafka(yaml: &str) -> v1alpha1::KafkaCluster {
676688
yaml_from_str_singleton_map(yaml).expect("invalid test KafkaCluster YAML")
677689
}

rust/operator-binary/src/controller/build/mod.rs

Lines changed: 9 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,6 @@ pub fn build(cluster: &ValidatedCluster) -> Result<KubernetesResources, Error> {
151151

152152
#[cfg(test)]
153153
mod tests {
154-
use std::collections::BTreeMap;
155-
156154
use stackable_operator::kube::Resource;
157155

158156
use super::build;
@@ -266,6 +264,15 @@ mod tests {
266264
sorted_names(&resources.pod_disruption_budgets),
267265
["simple-kafka-broker", "simple-kafka-controller"]
268266
);
267+
// The cluster-shared RBAC pair.
268+
assert_eq!(
269+
sorted_names(&resources.service_accounts),
270+
["simple-kafka-serviceaccount"]
271+
);
272+
assert_eq!(
273+
sorted_names(&resources.role_bindings),
274+
["simple-kafka-rolebinding"]
275+
);
269276
}
270277

271278
/// ZooKeeper mode has no `controller` role, so `build()` emits no controller resources while
@@ -295,53 +302,4 @@ mod tests {
295302
["simple-kafka-broker"]
296303
);
297304
}
298-
299-
/// Locks the RBAC resource names, the roleRef, and the recommended label set against
300-
/// accidental drift. The fixture's cluster name deliberately differs from the product name so
301-
/// that swapped `name`/`instance` label values cannot pass unnoticed.
302-
#[test]
303-
fn build_produces_rbac() {
304-
let cluster = kraft_cluster();
305-
let resources = build(&cluster).expect("build succeeds");
306-
307-
assert_eq!(
308-
sorted_names(&resources.service_accounts),
309-
["simple-kafka-serviceaccount"]
310-
);
311-
assert_eq!(
312-
sorted_names(&resources.role_bindings),
313-
["simple-kafka-rolebinding"]
314-
);
315-
316-
let expected_labels = BTreeMap::from(
317-
[
318-
("app.kubernetes.io/component", "none"),
319-
("app.kubernetes.io/instance", "simple-kafka"),
320-
(
321-
"app.kubernetes.io/managed-by",
322-
"kafka.stackable.tech_kafkacluster",
323-
),
324-
("app.kubernetes.io/name", "kafka"),
325-
("app.kubernetes.io/role-group", "none"),
326-
("app.kubernetes.io/version", "3.9.2-stackable0.0.0-dev"),
327-
("stackable.tech/vendor", "Stackable"),
328-
]
329-
.map(|(key, value)| (key.to_string(), value.to_string())),
330-
);
331-
let service_account = resources
332-
.service_accounts
333-
.first()
334-
.expect("a ServiceAccount is built");
335-
assert_eq!(
336-
service_account.metadata.labels,
337-
Some(expected_labels.clone())
338-
);
339-
340-
let role_binding = resources
341-
.role_bindings
342-
.first()
343-
.expect("a RoleBinding is built");
344-
assert_eq!(role_binding.metadata.labels, Some(expected_labels));
345-
assert_eq!(role_binding.role_ref.name, "kafka-clusterrole");
346-
}
347305
}

rust/operator-binary/src/controller/build/resource/rbac.rs

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,120 @@ pub fn build_role_binding(cluster: &ValidatedCluster) -> RoleBinding {
4040
fn rbac_labels(cluster: &ValidatedCluster) -> Labels {
4141
cluster.recommended_labels_for(&NONE_ROLE_NAME, &NONE_ROLE_GROUP_NAME)
4242
}
43+
44+
#[cfg(test)]
45+
mod tests {
46+
use serde_json::json;
47+
48+
use super::*;
49+
use crate::controller::test_support::{app_version_label, minimal_kafka, validated_cluster};
50+
51+
// The fixture's cluster name (`simple-kafka`) deliberately differs from the product name
52+
// (`kafka`), so swapped `name`/`instance` label values cannot pass unnoticed. The RBAC pair
53+
// is mode-independent, so the minimal ZooKeeper-mode cluster suffices.
54+
fn cluster() -> ValidatedCluster {
55+
let kafka = minimal_kafka(
56+
r#"
57+
apiVersion: kafka.stackable.tech/v1alpha1
58+
kind: KafkaCluster
59+
metadata:
60+
name: simple-kafka
61+
namespace: default
62+
uid: 12345678-1234-1234-1234-123456789012
63+
spec:
64+
image:
65+
productVersion: 3.9.2
66+
clusterConfig:
67+
zookeeperConfigMapName: xyz
68+
brokers:
69+
roleGroups:
70+
default:
71+
replicas: 1
72+
"#,
73+
);
74+
validated_cluster(&kafka)
75+
}
76+
77+
#[test]
78+
fn test_service_account() {
79+
let service_account = build_service_account(&cluster());
80+
81+
assert_eq!(
82+
json!({
83+
"apiVersion": "v1",
84+
"kind": "ServiceAccount",
85+
"metadata": {
86+
// The RBAC resources are cluster-shared, so role and role group are `none`.
87+
"labels": {
88+
"app.kubernetes.io/component": "none",
89+
"app.kubernetes.io/instance": "simple-kafka",
90+
"app.kubernetes.io/managed-by": "kafka.stackable.tech_kafkacluster",
91+
"app.kubernetes.io/name": "kafka",
92+
"app.kubernetes.io/role-group": "none",
93+
"app.kubernetes.io/version": app_version_label("3.9.2"),
94+
"stackable.tech/vendor": "Stackable"
95+
},
96+
"name": "simple-kafka-serviceaccount",
97+
"namespace": "default",
98+
"ownerReferences": [
99+
{
100+
"apiVersion": "kafka.stackable.tech/v1alpha1",
101+
"controller": true,
102+
"kind": "KafkaCluster",
103+
"name": "simple-kafka",
104+
"uid": "12345678-1234-1234-1234-123456789012"
105+
}
106+
]
107+
}
108+
}),
109+
serde_json::to_value(service_account).expect("must be serializable")
110+
);
111+
}
112+
113+
#[test]
114+
fn test_role_binding() {
115+
let role_binding = build_role_binding(&cluster());
116+
117+
assert_eq!(
118+
json!({
119+
"apiVersion": "rbac.authorization.k8s.io/v1",
120+
"kind": "RoleBinding",
121+
"metadata": {
122+
"labels": {
123+
"app.kubernetes.io/component": "none",
124+
"app.kubernetes.io/instance": "simple-kafka",
125+
"app.kubernetes.io/managed-by": "kafka.stackable.tech_kafkacluster",
126+
"app.kubernetes.io/name": "kafka",
127+
"app.kubernetes.io/role-group": "none",
128+
"app.kubernetes.io/version": app_version_label("3.9.2"),
129+
"stackable.tech/vendor": "Stackable"
130+
},
131+
"name": "simple-kafka-rolebinding",
132+
"namespace": "default",
133+
"ownerReferences": [
134+
{
135+
"apiVersion": "kafka.stackable.tech/v1alpha1",
136+
"controller": true,
137+
"kind": "KafkaCluster",
138+
"name": "simple-kafka",
139+
"uid": "12345678-1234-1234-1234-123456789012"
140+
}
141+
]
142+
},
143+
"roleRef": {
144+
"apiGroup": "rbac.authorization.k8s.io",
145+
"kind": "ClusterRole",
146+
"name": "kafka-clusterrole"
147+
},
148+
"subjects": [
149+
{
150+
"kind": "ServiceAccount",
151+
"name": "simple-kafka-serviceaccount",
152+
"namespace": "default"
153+
}
154+
]
155+
}),
156+
serde_json::to_value(role_binding).expect("must be serializable")
157+
);
158+
}
159+
}

rust/operator-binary/src/controller/build/resource/service.rs

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,97 @@ fn headless_ports(kafka_security: &ValidatedKafkaSecurity) -> Vec<ServicePort> {
115115
..ServicePort::default()
116116
}]
117117
}
118+
119+
#[cfg(test)]
120+
mod tests {
121+
use serde_json::json;
122+
123+
use super::*;
124+
use crate::controller::test_support::{app_version_label, minimal_kafka, validated_cluster};
125+
126+
/// Every metrics Service must carry the Prometheus scrape label and the
127+
/// `prometheus.io/path|port|scheme|scrape` annotations, or Prometheus stops discovering the
128+
/// endpoints.
129+
#[test]
130+
fn test_rolegroup_metrics_service() {
131+
let kafka = minimal_kafka(
132+
r#"
133+
apiVersion: kafka.stackable.tech/v1alpha1
134+
kind: KafkaCluster
135+
metadata:
136+
name: simple-kafka
137+
namespace: default
138+
uid: 12345678-1234-1234-1234-123456789012
139+
spec:
140+
image:
141+
productVersion: 3.9.2
142+
clusterConfig:
143+
zookeeperConfigMapName: xyz
144+
brokers:
145+
roleGroups:
146+
default:
147+
replicas: 1
148+
"#,
149+
);
150+
let cluster = validated_cluster(&kafka);
151+
let role_group_name: RoleGroupName = "default".parse().expect("valid role group name");
152+
153+
let service =
154+
build_rolegroup_metrics_service(&cluster, &KafkaRole::Broker, &role_group_name);
155+
156+
assert_eq!(
157+
json!({
158+
"apiVersion": "v1",
159+
"kind": "Service",
160+
"metadata": {
161+
"annotations": {
162+
"prometheus.io/path": "/metrics",
163+
"prometheus.io/port": "9606",
164+
"prometheus.io/scheme": "http",
165+
"prometheus.io/scrape": "true"
166+
},
167+
"labels": {
168+
"app.kubernetes.io/component": "broker",
169+
"app.kubernetes.io/instance": "simple-kafka",
170+
"app.kubernetes.io/managed-by": "kafka.stackable.tech_kafkacluster",
171+
"app.kubernetes.io/name": "kafka",
172+
"app.kubernetes.io/role-group": "default",
173+
"app.kubernetes.io/version": app_version_label("3.9.2"),
174+
"prometheus.io/scrape": "true",
175+
"stackable.tech/vendor": "Stackable"
176+
},
177+
"name": "simple-kafka-broker-default-metrics",
178+
"namespace": "default",
179+
"ownerReferences": [
180+
{
181+
"apiVersion": "kafka.stackable.tech/v1alpha1",
182+
"controller": true,
183+
"kind": "KafkaCluster",
184+
"name": "simple-kafka",
185+
"uid": "12345678-1234-1234-1234-123456789012"
186+
}
187+
]
188+
},
189+
"spec": {
190+
"clusterIP": "None",
191+
"ports": [
192+
{
193+
"name": "metrics",
194+
"port": 9606,
195+
"protocol": "TCP"
196+
}
197+
],
198+
"publishNotReadyAddresses": true,
199+
"selector": {
200+
"app.kubernetes.io/component": "broker",
201+
"app.kubernetes.io/instance": "simple-kafka",
202+
"app.kubernetes.io/name": "kafka",
203+
"app.kubernetes.io/role-group": "default"
204+
},
205+
"type": "ClusterIP"
206+
}
207+
}),
208+
serde_json::to_value(service).expect("must be serializable")
209+
);
210+
}
211+
}

0 commit comments

Comments
 (0)