@@ -837,3 +837,175 @@ fn build_prepare_start_command(merged_config: &OpaConfig, container_name: &str)
837837
838838 prepare_container_args
839839}
840+
841+ #[ cfg( test) ]
842+ mod tests {
843+ use serde_json:: json;
844+ use stackable_operator:: {
845+ commons:: networking:: DomainName , k8s_openapi:: api:: core:: v1:: ServiceAccount ,
846+ k8s_openapi:: apimachinery:: pkg:: apis:: meta:: v1:: ObjectMeta ,
847+ } ;
848+
849+ use super :: * ;
850+ use crate :: {
851+ controller:: build:: properties:: test_support:: validated_cluster_from_spec, crd:: OpaRole ,
852+ } ;
853+
854+ fn cluster_info ( ) -> KubernetesClusterInfo {
855+ KubernetesClusterInfo {
856+ cluster_domain : DomainName :: try_from ( "cluster.local" ) . unwrap ( ) ,
857+ }
858+ }
859+
860+ fn service_account ( ) -> ServiceAccount {
861+ ServiceAccount {
862+ metadata : ObjectMeta {
863+ name : Some ( "test-opa-serviceaccount" . to_owned ( ) ) ,
864+ ..Default :: default ( )
865+ } ,
866+ ..Default :: default ( )
867+ }
868+ }
869+
870+ fn build ( cluster : & ValidatedCluster ) -> DaemonSet {
871+ let ( role_group_name, role_group) = cluster. role_group_configs [ & OpaRole :: Server ]
872+ . iter ( )
873+ . next ( )
874+ . expect ( "the default role group should exist" ) ;
875+ build_server_rolegroup_daemonset (
876+ cluster,
877+ role_group_name,
878+ role_group,
879+ "bundle-builder-image" ,
880+ "user-info-fetcher-image" ,
881+ & service_account ( ) ,
882+ & cluster_info ( ) ,
883+ )
884+ . expect ( "the daemonset should build" )
885+ }
886+
887+ fn container_names ( ds : & DaemonSet ) -> Vec < String > {
888+ ds. spec
889+ . as_ref ( )
890+ . unwrap ( )
891+ . template
892+ . spec
893+ . as_ref ( )
894+ . unwrap ( )
895+ . containers
896+ . iter ( )
897+ . map ( |c| c. name . clone ( ) )
898+ . collect ( )
899+ }
900+
901+ fn volume_names ( ds : & DaemonSet ) -> Vec < String > {
902+ ds. spec
903+ . as_ref ( )
904+ . unwrap ( )
905+ . template
906+ . spec
907+ . as_ref ( )
908+ . unwrap ( )
909+ . volumes
910+ . as_ref ( )
911+ . unwrap ( )
912+ . iter ( )
913+ . map ( |v| v. name . clone ( ) )
914+ . collect ( )
915+ }
916+
917+ #[ test]
918+ fn daemonset_has_expected_name_and_rolling_update_strategy ( ) {
919+ let ds = build ( & validated_cluster_from_spec ( json ! ( {
920+ "image" : { "productVersion" : "1.2.3" } ,
921+ "servers" : { "roleGroups" : { "default" : { } } } ,
922+ } ) ) ) ;
923+
924+ assert_eq ! ( ds. metadata. name. as_deref( ) , Some ( "test-opa-server-default" ) ) ;
925+ let strategy = ds. spec . as_ref ( ) . unwrap ( ) . update_strategy . as_ref ( ) . unwrap ( ) ;
926+ assert_eq ! ( strategy. type_. as_deref( ) , Some ( "RollingUpdate" ) ) ;
927+ let rolling_update = strategy. rolling_update . as_ref ( ) . unwrap ( ) ;
928+ // A DaemonSet must never take an OPA pod down before the replacement is ready.
929+ assert_eq ! ( rolling_update. max_unavailable, Some ( IntOrString :: Int ( 0 ) ) ) ;
930+ }
931+
932+ #[ test]
933+ fn daemonset_runs_opa_and_bundle_builder_with_prepare_init_container ( ) {
934+ let ds = build ( & validated_cluster_from_spec ( json ! ( {
935+ "image" : { "productVersion" : "1.2.3" } ,
936+ "servers" : { "roleGroups" : { "default" : { } } } ,
937+ } ) ) ) ;
938+
939+ let containers = container_names ( & ds) ;
940+ assert ! ( containers. contains( & "opa" . to_owned( ) ) ) ;
941+ assert ! ( containers. contains( & "bundle-builder" . to_owned( ) ) ) ;
942+ // No sidecars without the corresponding cluster config.
943+ assert ! ( !containers. contains( & "user-info-fetcher" . to_owned( ) ) ) ;
944+ assert ! ( !containers. contains( & "vector" . to_owned( ) ) ) ;
945+
946+ let pod_spec = ds. spec . as_ref ( ) . unwrap ( ) . template . spec . as_ref ( ) . unwrap ( ) ;
947+ let init_containers: Vec < _ > = pod_spec
948+ . init_containers
949+ . as_ref ( )
950+ . unwrap ( )
951+ . iter ( )
952+ . map ( |c| c. name . clone ( ) )
953+ . collect ( ) ;
954+ assert_eq ! ( init_containers, vec![ "prepare" . to_owned( ) ] ) ;
955+
956+ // The standard volumes are always present; the TLS volume is not (no TLS configured).
957+ let volumes = volume_names ( & ds) ;
958+ for expected in [ "config" , "bundles" , "log" ] {
959+ assert ! (
960+ volumes. contains( & expected. to_owned( ) ) ,
961+ "missing volume {expected}"
962+ ) ;
963+ }
964+ assert ! ( !volumes. contains( & "tls" . to_owned( ) ) ) ;
965+ }
966+
967+ #[ test]
968+ fn daemonset_adds_vector_container_when_agent_enabled ( ) {
969+ let ds = build ( & validated_cluster_from_spec ( json ! ( {
970+ "image" : { "productVersion" : "1.2.3" } ,
971+ "clusterConfig" : { "vectorAggregatorConfigMapName" : "vector-aggregator-discovery" } ,
972+ "servers" : {
973+ "config" : { "logging" : { "enableVectorAgent" : true } } ,
974+ "roleGroups" : { "default" : { } } ,
975+ } ,
976+ } ) ) ) ;
977+
978+ assert ! ( container_names( & ds) . contains( & "vector" . to_owned( ) ) ) ;
979+ }
980+
981+ #[ test]
982+ fn daemonset_adds_user_info_fetcher_container_when_configured ( ) {
983+ let ds = build ( & validated_cluster_from_spec ( json ! ( {
984+ "image" : { "productVersion" : "1.2.3" } ,
985+ "clusterConfig" : {
986+ "userInfo" : {
987+ "backend" : {
988+ "experimentalXfscAas" : {
989+ "hostname" : "aas.default.svc.cluster.local" ,
990+ "port" : 5000 ,
991+ }
992+ }
993+ }
994+ } ,
995+ "servers" : { "roleGroups" : { "default" : { } } } ,
996+ } ) ) ) ;
997+
998+ assert ! ( container_names( & ds) . contains( & "user-info-fetcher" . to_owned( ) ) ) ;
999+ }
1000+
1001+ #[ test]
1002+ fn daemonset_adds_tls_volume_when_tls_enabled ( ) {
1003+ let ds = build ( & validated_cluster_from_spec ( json ! ( {
1004+ "image" : { "productVersion" : "1.2.3" } ,
1005+ "clusterConfig" : { "tls" : { "serverSecretClass" : "tls" } } ,
1006+ "servers" : { "roleGroups" : { "default" : { } } } ,
1007+ } ) ) ) ;
1008+
1009+ assert ! ( volume_names( & ds) . contains( & "tls" . to_owned( ) ) ) ;
1010+ }
1011+ }
0 commit comments