@@ -225,6 +225,61 @@ mod tests {
225225 } ;
226226
227227 use super :: * ;
228+ use crate :: {
229+ zk_controller:: {
230+ ZK_CONTROLLER_NAME ,
231+ test_support:: { minimal_zk, validated_cluster} ,
232+ } ,
233+ znode_controller:: {
234+ ZNODE_CONTROLLER_NAME ,
235+ validate:: test_support:: { minimal_znode, validated_znode} ,
236+ } ,
237+ } ;
238+
239+ /// A `ZookeeperCluster` fixture. `test_support`'s auth-free `new_for_tests()` still enables
240+ /// server TLS, so this resolves to the secure client port (2282).
241+ const TLS_ZK : & str = r#"
242+ apiVersion: zookeeper.stackable.tech/v1alpha1
243+ kind: ZookeeperCluster
244+ metadata:
245+ name: test-zk
246+ spec:
247+ image:
248+ productVersion: "3.9.5"
249+ servers:
250+ roleGroups:
251+ default:
252+ replicas: 3
253+ "# ;
254+
255+ /// Same as [`TLS_ZK`] but with `serverSecretClass: null`, disabling server TLS so the insecure
256+ /// client port (2181) is used.
257+ const NON_TLS_ZK : & str = r#"
258+ apiVersion: zookeeper.stackable.tech/v1alpha1
259+ kind: ZookeeperCluster
260+ metadata:
261+ name: test-zk
262+ spec:
263+ image:
264+ productVersion: "3.9.5"
265+ clusterConfig:
266+ tls:
267+ serverSecretClass: null
268+ servers:
269+ roleGroups:
270+ default:
271+ replicas: 3
272+ "# ;
273+
274+ const ZNODE : & str = r#"
275+ apiVersion: zookeeper.stackable.tech/v1alpha1
276+ kind: ZookeeperZnode
277+ metadata:
278+ name: test-znode
279+ spec:
280+ clusterRef:
281+ name: test-zk
282+ "# ;
228283
229284 fn listener ( ingress_addresses : Option < Vec < ListenerIngress > > ) -> Listener {
230285 Listener {
@@ -241,14 +296,26 @@ mod tests {
241296 }
242297 }
243298
244- fn ingress ( port : i32 ) -> ListenerIngress {
299+ fn ingress_at ( address : & str , port : i32 ) -> ListenerIngress {
245300 ListenerIngress {
246- address : "node-0" . to_owned ( ) ,
301+ address : address . to_owned ( ) ,
247302 address_type : AddressType :: Hostname ,
248303 ports : BTreeMap :: from ( [ ( ZOOKEEPER_SERVER_PORT_NAME . to_owned ( ) , port) ] ) ,
249304 }
250305 }
251306
307+ fn ingress ( port : i32 ) -> ListenerIngress {
308+ ingress_at ( "node-0" , port)
309+ }
310+
311+ /// Pulls a `.data` key out of a built ConfigMap.
312+ fn data < ' a > ( cm : & ' a ConfigMap , key : & str ) -> & ' a str {
313+ cm. data
314+ . as_ref ( )
315+ . and_then ( |d| d. get ( key) )
316+ . unwrap_or_else ( || panic ! ( "discovery ConfigMap missing key {key}" ) )
317+ }
318+
252319 #[ test]
253320 fn listener_addresses_returns_host_port_pairs ( ) {
254321 let listener = listener ( Some ( vec ! [ ingress( 2181 ) ] ) ) ;
@@ -285,4 +352,91 @@ mod tests {
285352 Err ( Error :: InvalidPort { .. } )
286353 ) ) ;
287354 }
355+
356+ #[ test]
357+ fn cluster_discovery_cm_data_tls ( ) {
358+ // TLS cluster -> secure client port 2282. The listener exposes the same port, as it does at
359+ // runtime. No chroot, so `ZOOKEEPER` equals `ZOOKEEPER_HOSTS` and `ZOOKEEPER_CHROOT` is `/`.
360+ let validated = validated_cluster ( & minimal_zk ( TLS_ZK ) ) ;
361+ let cm = build_discovery_configmap (
362+ & validated,
363+ ZK_CONTROLLER_NAME ,
364+ listener ( Some ( vec ! [ ingress( 2282 ) ] ) ) ,
365+ )
366+ . expect ( "discovery CM builds" ) ;
367+
368+ assert_eq ! ( data( & cm, "ZOOKEEPER" ) , "node-0:2282" ) ;
369+ assert_eq ! ( data( & cm, "ZOOKEEPER_HOSTS" ) , "node-0:2282" ) ;
370+ assert_eq ! ( data( & cm, "ZOOKEEPER_CLIENT_PORT" ) , "2282" ) ;
371+ assert_eq ! ( data( & cm, "ZOOKEEPER_CHROOT" ) , "/" ) ;
372+ }
373+
374+ #[ test]
375+ fn cluster_discovery_cm_data_non_tls ( ) {
376+ // Server TLS disabled -> insecure client port 2181.
377+ let validated = validated_cluster ( & minimal_zk ( NON_TLS_ZK ) ) ;
378+ let cm = build_discovery_configmap (
379+ & validated,
380+ ZK_CONTROLLER_NAME ,
381+ listener ( Some ( vec ! [ ingress( 2181 ) ] ) ) ,
382+ )
383+ . expect ( "discovery CM builds" ) ;
384+
385+ assert_eq ! ( data( & cm, "ZOOKEEPER" ) , "node-0:2181" ) ;
386+ assert_eq ! ( data( & cm, "ZOOKEEPER_HOSTS" ) , "node-0:2181" ) ;
387+ assert_eq ! ( data( & cm, "ZOOKEEPER_CLIENT_PORT" ) , "2181" ) ;
388+ assert_eq ! ( data( & cm, "ZOOKEEPER_CHROOT" ) , "/" ) ;
389+ }
390+
391+ #[ test]
392+ fn cluster_discovery_cm_joins_multiple_hosts_sorted ( ) {
393+ // Multiple listener ingress addresses are joined into one comma-separated connection string,
394+ // ordered by the `BTreeSet` in `listener_addresses` (i.e. sorted).
395+ let validated = validated_cluster ( & minimal_zk ( TLS_ZK ) ) ;
396+ let cm = build_discovery_configmap (
397+ & validated,
398+ ZK_CONTROLLER_NAME ,
399+ listener ( Some ( vec ! [
400+ ingress_at( "node-1" , 2282 ) ,
401+ ingress_at( "node-0" , 2282 ) ,
402+ ] ) ) ,
403+ )
404+ . expect ( "discovery CM builds" ) ;
405+
406+ assert_eq ! ( data( & cm, "ZOOKEEPER" ) , "node-0:2282,node-1:2282" ) ;
407+ assert_eq ! ( data( & cm, "ZOOKEEPER_HOSTS" ) , "node-0:2282,node-1:2282" ) ;
408+ }
409+
410+ #[ test]
411+ fn znode_discovery_cm_appends_chroot_to_connection_string_only ( ) {
412+ // The chroot is appended to `ZOOKEEPER` (the merged Java client string) but NOT to
413+ // `ZOOKEEPER_HOSTS` (kept separate for clients that don't understand the merged format).
414+ let validated = validated_znode ( & minimal_znode ( ZNODE ) , TLS_ZK ) ;
415+ let cm = build_znode_discovery_configmap (
416+ & validated,
417+ ZNODE_CONTROLLER_NAME ,
418+ listener ( Some ( vec ! [ ingress( 2282 ) ] ) ) ,
419+ "/znode-abc" ,
420+ )
421+ . expect ( "znode discovery CM builds" ) ;
422+
423+ assert_eq ! ( data( & cm, "ZOOKEEPER" ) , "node-0:2282/znode-abc" ) ;
424+ assert_eq ! ( data( & cm, "ZOOKEEPER_HOSTS" ) , "node-0:2282" ) ;
425+ assert_eq ! ( data( & cm, "ZOOKEEPER_CLIENT_PORT" ) , "2282" ) ;
426+ assert_eq ! ( data( & cm, "ZOOKEEPER_CHROOT" ) , "/znode-abc" ) ;
427+ }
428+
429+ #[ test]
430+ fn znode_discovery_cm_rejects_relative_chroot ( ) {
431+ let validated = validated_znode ( & minimal_znode ( ZNODE ) , TLS_ZK ) ;
432+ assert ! ( matches!(
433+ build_znode_discovery_configmap(
434+ & validated,
435+ ZNODE_CONTROLLER_NAME ,
436+ listener( Some ( vec![ ingress( 2282 ) ] ) ) ,
437+ "znode-abc" ,
438+ ) ,
439+ Err ( Error :: RelativeChroot { .. } )
440+ ) ) ;
441+ }
288442}
0 commit comments