@@ -756,6 +756,159 @@ mod tests {
756756 assert ! ( cm. contains_key( "vector.yaml" ) ) ;
757757 }
758758
759+ #[ test]
760+ fn test_vector_config_absent_when_agent_disabled ( ) {
761+ // Default logging has the Vector agent disabled, so no `vector.yaml` is added to the
762+ // ConfigMap. Pins the negative branch alongside `test_vector_agent_adds_vector_config`.
763+ let zookeeper_yaml = r#"
764+ apiVersion: zookeeper.stackable.tech/v1alpha1
765+ kind: ZookeeperCluster
766+ metadata:
767+ name: simple-zookeeper
768+ spec:
769+ image:
770+ productVersion: "3.9.5"
771+ servers:
772+ roleGroups:
773+ default:
774+ replicas: 3
775+ "# ;
776+ let cm = build_config_map ( zookeeper_yaml) . data . unwrap ( ) ;
777+ assert ! ( !cm. contains_key( "vector.yaml" ) ) ;
778+ }
779+
780+ #[ test]
781+ fn test_logback_default_structure ( ) {
782+ // Pins the structural parts of the rendered `logback.xml` that this operator controls (log
783+ // dir + file name, console conversion pattern, max file size, appender wiring). This is the
784+ // source of truth that used to live in the kuttl smoke `14-assert` heredoc; the levels are
785+ // covered separately by `test_logback_renders_zookeeper_container_log_levels`.
786+ let zookeeper_yaml = r#"
787+ apiVersion: zookeeper.stackable.tech/v1alpha1
788+ kind: ZookeeperCluster
789+ metadata:
790+ name: simple-zookeeper
791+ spec:
792+ image:
793+ productVersion: "3.9.5"
794+ servers:
795+ roleGroups:
796+ default:
797+ replicas: 3
798+ "# ;
799+ let cm = build_config_map ( zookeeper_yaml) . data . unwrap ( ) ;
800+ let logback = cm. get ( "logback.xml" ) . unwrap ( ) ;
801+
802+ // Console appender + the operator's conversion pattern.
803+ assert ! (
804+ logback. contains(
805+ r#"<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">"#
806+ ) ,
807+ "{logback}"
808+ ) ;
809+ assert ! (
810+ logback. contains(
811+ "<pattern>%d{ISO8601} [myid:%X{myid}] - %-5p [%t:%C{1}@%L] - %m%n</pattern>"
812+ ) ,
813+ "{logback}"
814+ ) ;
815+
816+ // Rolling file appender writing to the operator's log dir + file name.
817+ assert ! (
818+ logback. contains(
819+ r#"<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">"#
820+ ) ,
821+ "{logback}"
822+ ) ;
823+ assert ! (
824+ logback. contains( "<File>/stackable/log/zookeeper/zookeeper.log4j.xml</File>" ) ,
825+ "{logback}"
826+ ) ;
827+ assert ! (
828+ logback. contains(
829+ "<FileNamePattern>/stackable/log/zookeeper/zookeeper.log4j.xml.%i</FileNamePattern>"
830+ ) ,
831+ "{logback}"
832+ ) ;
833+ // 10 MiB total across 2 files -> 5MB per file (derived from MAX_ZK_LOG_FILES_SIZE).
834+ assert ! (
835+ logback. contains( "<MaxFileSize>5MB</MaxFileSize>" ) ,
836+ "{logback}"
837+ ) ;
838+
839+ // Root wires both appenders and defaults to INFO.
840+ assert ! ( logback. contains( r#"<root level="INFO">"# ) , "{logback}" ) ;
841+ assert ! (
842+ logback. contains( r#"<appender-ref ref="CONSOLE" />"# )
843+ && logback. contains( r#"<appender-ref ref="FILE" />"# ) ,
844+ "{logback}"
845+ ) ;
846+ }
847+
848+ #[ test]
849+ fn test_logback_renders_zookeeper_container_log_levels ( ) {
850+ // The zookeeper container's automatic log config drives `logback.xml`: the console and file
851+ // appender ThresholdFilter levels, per-logger levels, and the root level. (The `prepare` and
852+ // `vector` container levels do NOT affect `logback.xml` — they flow into those containers'
853+ // own config via upstream behavior — so only the zookeeper container is set here.)
854+ let zookeeper_yaml = r#"
855+ apiVersion: zookeeper.stackable.tech/v1alpha1
856+ kind: ZookeeperCluster
857+ metadata:
858+ name: simple-zookeeper
859+ spec:
860+ image:
861+ productVersion: "3.9.5"
862+ servers:
863+ roleGroups:
864+ default:
865+ replicas: 1
866+ config:
867+ logging:
868+ containers:
869+ zookeeper:
870+ console:
871+ level: DEBUG
872+ file:
873+ level: WARN
874+ loggers:
875+ ROOT:
876+ level: ERROR
877+ org.apache.zookeeper:
878+ level: TRACE
879+ "# ;
880+ let cm = build_config_map ( zookeeper_yaml) . data . unwrap ( ) ;
881+ let logback = cm. get ( "logback.xml" ) . unwrap ( ) ;
882+
883+ // The console and file appenders share the same ThresholdFilter element, so split on the
884+ // FILE appender to tie each level to its appender: console -> DEBUG, file -> WARN.
885+ let ( console_part, file_part) = logback
886+ . split_once ( r#"name="FILE""# )
887+ . unwrap_or_else ( || panic ! ( "FILE appender present: {logback}" ) ) ;
888+ assert ! (
889+ console_part. contains( "<level>DEBUG</level>" ) ,
890+ "console appender level should be DEBUG: {logback}"
891+ ) ;
892+ assert ! (
893+ !console_part. contains( "<level>WARN</level>" ) ,
894+ "console appender level should not be WARN: {logback}"
895+ ) ;
896+ assert ! (
897+ file_part. contains( "<level>WARN</level>" ) ,
898+ "file appender level should be WARN: {logback}"
899+ ) ;
900+
901+ // The ROOT logger level maps to the `<root>` element; a named logger renders its own entry.
902+ assert ! (
903+ logback. contains( r#"<root level="ERROR">"# ) ,
904+ "root level should be ERROR: {logback}"
905+ ) ;
906+ assert ! (
907+ logback. contains( r#"<logger name="org.apache.zookeeper" level="TRACE" />"# ) ,
908+ "named logger should render at TRACE: {logback}"
909+ ) ;
910+ }
911+
759912 // ---------------------------------------------------------------------------------------------
760913 // TLS x client-auth matrix (candidate #1 in unit-tests.md).
761914 //
0 commit comments