Repository: streamshub/console
Pull request #1585: [ST] Add strimzi setup class, reverse coverage logic, add test-frame snapshot
Author: login: jankalinic
Created: 2025-03-28T08:38:24Z | Merged: 2025-04-01T16:42:05Z

- This PR adds basic strimzi cluster operator setup. 
- Also it would be overwhelming to exclude, so this PR includes a reverse logic -> including UTs instead of excluding files.
- PR adds test-frame snapshot repo which helps cover newly found and fixed items. + PR updates depricated methods to a newly enforced ones.
- PR switches pioneer for a powermock for a smoother system environment variables mocking without unchecked operations.
- PR switches environment variable nulls for empty strings, which makes the string checks shorter and if statements more readable
- PR adds Constants, labels and resourcekinds


Diff:
diff --git a/coverage/pom.xml b/coverage/pom.xml
index 8e7dcb2e4..01df153ed 100644
--- a/coverage/pom.xml
+++ b/coverage/pom.xml
@@ -56,13 +56,7 @@
                                 <exclude>**/com/github/streamshub/console/api/v1alpha1/**/*Builder.class</exclude>
                                 <exclude>**/com/github/streamshub/console/api/v1alpha1/**/*Fluent.class</exclude>
                                 <exclude>**/com/github/streamshub/console/api/v1alpha1/**/*Nested.class</exclude>
-                                <!-- Systemtests -->
-                                <exclude>**/com/github/streamshub/systemtests/constants/*.class</exclude>
-                                <exclude>**/com/github/streamshub/systemtests/enums/*.class</exclude>
-                                <exclude>**/com/github/streamshub/systemtests/Environment.class</exclude>
-                                <exclude>**/com/github/streamshub/systemtests/logs/*.class</exclude>
-                                <exclude>**/com/github/streamshub/systemtests/unit/*.class</exclude>
-                                <exclude>**/com/github/streamshub/systemtests/exceptions/*.class</exclude>
+                                <exclude>**/com/github/streamshub/systemtests/**/*.class</exclude>
                             </excludes>
                             <outputDirectory>${project.build.directory}/coverage</outputDirectory>
                         </configuration>
diff --git a/systemtests/pom.xml b/systemtests/pom.xml
index d5c424eb0..25ad29c28 100644
--- a/systemtests/pom.xml
+++ b/systemtests/pom.xml
@@ -23,15 +23,29 @@
         <playwright.version>1.47.0</playwright.version>
         <!-- Mocking environment -->
         <mockito.version>5.15.2</mockito.version>
-        <junit-pioneer.version>2.3.0</junit-pioneer.version>
+        <powermock.version>2.0.9</powermock.version>
         <!-- Used for test-frame -->
-        <test-frame.version>0.8.0</test-frame.version>
+        <test-frame.version>0.11.0-SNAPSHOT</test-frame.version>
         <!-- Allows skipping tests - unit, system or both types -->
         <skipTests>false</skipTests>
         <skipUTs>${skipTests}</skipUTs>
         <skipSTs>${skipTests}</skipSTs>
     </properties>
 
+    <repositories>
+      <repository>
+        <name>Central Portal Snapshots</name>
+        <id>central-portal-snapshots</id>
+        <url>https://central.sonatype.com/repository/maven-snapshots/</url>
+        <releases>
+          <enabled>false</enabled>
+        </releases>
+        <snapshots>
+          <enabled>true</enabled>
+        </snapshots>
+      </repository>
+    </repositories>
+
     <dependencies>
         <dependency>
             <groupId>commons-io</groupId>
@@ -90,6 +104,12 @@
             <artifactId>test-frame-log-collector</artifactId>
             <version>${test-frame.version}</version>
         </dependency>
+        <!-- JUnit 5 Jupiter API and Engine -->
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-params</artifactId>
+            <scope>test</scope>
+        </dependency>
         <!-- Mocking environment -->
         <dependency>
             <groupId>org.mockito</groupId>
@@ -97,10 +117,11 @@
             <version>${mockito.version}</version>
             <scope>test</scope>
         </dependency>
+        <!-- Allows final static field reflection -->
         <dependency>
-            <groupId>org.junit-pioneer</groupId>
-            <artifactId>junit-pioneer</artifactId>
-            <version>${junit-pioneer.version}</version>
+            <groupId>org.powermock</groupId>
+            <artifactId>powermock-reflect</artifactId>
+            <version>${powermock.version}</version>
             <scope>test</scope>
         </dependency>
         <!-- Logger -->
diff --git a/systemtests/src/main/java/com/github/streamshub/systemtests/Environment.java b/systemtests/src/main/java/com/github/streamshub/systemtests/Environment.java
index d458abc50..efdcdb69d 100644
--- a/systemtests/src/main/java/com/github/streamshub/systemtests/Environment.java
+++ b/systemtests/src/main/java/com/github/streamshub/systemtests/Environment.java
@@ -15,24 +15,23 @@ public class Environment {
     public static final String BROWSER_TYPE = ENVS.getOrDefault("BROWSER_TYPE", BrowserTypes.CHROMIUM.toString());
     public static final String CONSOLE_DEPLOYMENT_NAME = ENVS.getOrDefault("CONSOLE_DEPLOYMENT_NAME", "streamshub-console");
     public static final String STRIMZI_OPERATOR_NAME = ENVS.getOrDefault("STRIMZI_OPERATOR_NAME", "strimzi-cluster-operator");
-    public static final String STRIMZI_OPERATOR_CRDS_URL = ENVS.getOrDefault("STRIMZI_OPERATOR_CRDS_URL", null);
+    public static final String STRIMZI_OPERATOR_CRDS_URL = ENVS.getOrDefault("STRIMZI_OPERATOR_CRDS_URL", "");
     public static final String CONSOLE_OPERATOR_BUNDLE_URL = USER_PATH + "/" + ENVS.getOrDefault("CONSOLE_OPERATOR_BUNDLE_URL", "../install/console-operator/non-olm/console-operator.yaml");
     public static final String CONSOLE_CATALOG_SOURCE_NAME = ENVS.getOrDefault("CONSOLE_CATALOG_SOURCE_NAME", "streamshub-console-catalog");
     public static final String TEST_LOG_DIR = ENVS.getOrDefault("TEST_LOG_DIR",  USER_PATH + "/target/logs/");
     public static final String TEST_FILE_LOG_LEVEL = ENVS.getOrDefault("TEST_FILE_LOG_LEVEL",  "INFO");
     public static final String TEST_CONSOLE_LOG_LEVEL = ENVS.getOrDefault("TEST_CONSOLE_LOG_LEVEL",  "");
     public static final boolean SKIP_TEARDOWN = ENVS.getOrDefault("SKIP_TEARDOWN", Boolean::parseBoolean, false);
-    public static final String ST_KAFKA_VERSION = ENVS.getOrDefault("ST_KAFKA_VERSION", null);
+    public static final String ST_KAFKA_VERSION = ENVS.getOrDefault("ST_KAFKA_VERSION", "");
     public static final String CONSOLE_OLM_PACKAGE_NAME = ENVS.getOrDefault("CONSOLE_OLM_PACKAGE_NAME", "streamshub-console-operator");
     public static final boolean SKIP_STRIMZI_INSTALLATION = ENVS.getOrDefault("SKIP_STRIMZI_INSTALLATION", Boolean::parseBoolean, false);
-    public static final String CONSOLE_API_IMAGE = ENVS.getOrDefault("CONSOLE_API_IMAGE", null);
-    public static final String CONSOLE_UI_IMAGE = ENVS.getOrDefault("CONSOLE_UI_IMAGE", null);
-    public static final String CONSOLE_OPERATOR_IMAGE = ENVS.getOrDefault("CONSOLE_OPERATOR_IMAGE", null);
+    public static final String CONSOLE_API_IMAGE = ENVS.getOrDefault("CONSOLE_API_IMAGE", "");
+    public static final String CONSOLE_UI_IMAGE = ENVS.getOrDefault("CONSOLE_UI_IMAGE", "");
+    public static final String CONSOLE_OPERATOR_IMAGE = ENVS.getOrDefault("CONSOLE_OPERATOR_IMAGE", "");
     public static final boolean RUN_HEADLESS = ENVS.getOrDefault("RUN_HEADLESS", Boolean::parseBoolean, true);
     public static final String SCREENSHOTS_DIR_PATH = ENVS.getOrDefault("SCREENSHOTS_DIR_PATH", USER_PATH + "/screenshots");
     public static final boolean INSTALL_USING_OLM = ENVS.getOrDefault("INSTALL_USING_OLM", Boolean::parseBoolean, false);
-    public static final String TEST_CLIENTS_IMAGE = ENVS.getOrDefault("TEST_CLIENTS_IMAGE", null);
-    public static final String TEST_CLIENTS_IMAGE_PULL_SECRET = ENVS.getOrDefault("TEST_CLIENTS_IMAGE_PULL_SECRET", null);
+    public static final String TEST_CLIENTS_IMAGE = ENVS.getOrDefault("TEST_CLIENTS_IMAGE", "");
     public static final String OLM_OPERATOR_CHANNEL = ENVS.getOrDefault("OLM_OPERATOR_CHANNEL", "alpha");
     // ------------------------------------------------------------------------------------------------------------------------------------------------------------
     // Deny instantiation
diff --git a/systemtests/src/main/java/com/github/streamshub/systemtests/TestExecutionWatcher.java b/systemtests/src/main/java/com/github/streamshub/systemtests/TestExecutionWatcher.java
index 4152dedbb..11a6cb100 100644
--- a/systemtests/src/main/java/com/github/streamshub/systemtests/TestExecutionWatcher.java
+++ b/systemtests/src/main/java/com/github/streamshub/systemtests/TestExecutionWatcher.java
@@ -10,7 +10,7 @@
 import org.opentest4j.TestAbortedException;
 
 public class TestExecutionWatcher implements TestExecutionExceptionHandler, LifecycleMethodExecutionExceptionHandler {
-    private final TestLogCollector logCollector = TestLogCollector.getInstance();
+    private static final TestLogCollector LOG_COLLECTOR = TestLogCollector.getInstance();
     private static final Logger LOGGER = LogWrapper.getLogger(TestExecutionWatcher.class);
 
     @Override
@@ -20,7 +20,7 @@ public void handleTestExecutionException(ExtensionContext extensionContext, Thro
             final String testClass = extensionContext.getRequiredTestClass().getName();
             final String testMethod = extensionContext.getRequiredTestMethod().getName();
 
-            logCollector.collectLogs(testClass, testMethod);
+            LOG_COLLECTOR.collectLogs(testClass, testMethod);
         }
         throw throwable;
     }
@@ -31,7 +31,7 @@ public void handleBeforeAllMethodExecutionException(ExtensionContext extensionCo
         if (!(throwable instanceof TestAbortedException || throwable instanceof ClusterUnreachableException)) {
             final String testClass = extensionContext.getRequiredTestClass().getName();
 
-            logCollector.collectLogs(testClass);
+            LOG_COLLECTOR.collectLogs(testClass);
         }
         throw throwable;
     }
@@ -43,7 +43,7 @@ public void handleBeforeEachMethodExecutionException(ExtensionContext extensionC
             final String testClass = extensionContext.getRequiredTestClass().getName();
             final String testMethod = extensionContext.getRequiredTestMethod().getName();
 
-            logCollector.collectLogs(testClass, testMethod);
+            LOG_COLLECTOR.collectLogs(testClass, testMethod);
         }
         throw throwable;
     }
@@ -55,7 +55,7 @@ public void handleAfterEachMethodExecutionException(ExtensionContext extensionCo
             final String testClass = extensionContext.getRequiredTestClass().getName();
             final String testMethod = extensionContext.getRequiredTestMethod().getName();
 
-            logCollector.collectLogs(testClass, testMethod);
+            LOG_COLLECTOR.collectLogs(testClass, testMethod);
         }
         throw throwable;
     }
@@ -66,7 +66,7 @@ public void handleAfterAllMethodExecutionException(ExtensionContext extensionCon
         if (!(throwable instanceof ClusterUnreachableException)) {
             final String testClass = extensionContext.getRequiredTestClass().getName();
 
-            logCollector.collectLogs(testClass);
+            LOG_COLLECTOR.collectLogs(testClass);
         }
         throw throwable;
     }
diff --git a/systemtests/src/main/java/com/github/streamshub/systemtests/constants/Constants.java b/systemtests/src/main/java/com/github/streamshub/systemtests/constants/Constants.java
new file mode 100644
index 000000000..1018d492f
--- /dev/null
+++ b/systemtests/src/main/java/com/github/streamshub/systemtests/constants/Constants.java
@@ -0,0 +1,74 @@
+package com.github.streamshub.systemtests.constants;
+
+import com.github.streamshub.console.api.v1alpha1.Console;
+import io.fabric8.kubernetes.api.model.HasMetadata;
+
+public class Constants {
+    private Constants() {}
+
+    // --------------------------------
+    // ------------ General -----------
+    // --------------------------------
+    /**
+     * Namespaces
+     */
+    public static final String CO_NAMESPACE = "co-namespace";
+    public static final String OPENSHIFT_MARKETPLACE_NAMESPACE = "openshift-marketplace";
+
+    /**
+     * Test values
+     */
+    public static final String USER_USERNAME = "Anonymous";
+
+    /**
+     * Messages
+     */
+    public static final int MESSAGE_COUNT = 1000;
+
+    /**
+     * CRDs
+     */
+    public static final String RBAC_AUTH_API_GROUP = "rbac.authorization.k8s.io";
+
+
+    // --------------------------------
+    // ----------- Strimzi ------------
+    // --------------------------------
+    public static final String STRIMZI_NAME = "strimzi";
+    public static final String STRIMZI_CO_NAME = STRIMZI_NAME + "-cluster-operator";
+    public static final String STRIMZI_NAMESPACE_KEY = "STRIMZI_NAMESPACE";
+    public static final String STRIMZI_WATCH_ALL_NAMESPACES = "*";
+
+    /**
+     * Clients
+     */
+    public static final String PRODUCER = "producer";
+    public static final String CONSUMER = "consumer";
+
+    /**
+     * Topics
+     */
+    public static final String KAFKA_TOPIC_PREFIX = "kt";
+    public static final String CONSUMER_OFFSETS_TOPIC_NAME = "__consumer_offsets";
+
+    /**
+     *  Kafka
+     */
+    public static final String KAFKA_USER_PREFIX = "user";
+    public static final String KAFKA_CLUSTER_PREFIX = "kc";
+    public static final String BROKER_ROLE_PREFIX = "brk";
+    public static final String CONTROLLER_ROLE_PREFIX = "ctrl";
+    public static final int REGULAR_BROKER_REPLICAS = 3;
+
+
+     // --------------------------------
+    // ------------ Console -----------
+    // --------------------------------
+    /**
+     * CRDs
+     */
+    public static final String CONSOLE_CRD_API_NAME = HasMetadata.getFullResourceName(Console.class);
+    public static final String CONSOLE_CRD_API_VERSION = HasMetadata.getGroup(Console.class) + "/" + HasMetadata.getVersion(Console.class);
+    public static final String CONSOLE_OPERATOR_GROUP_NAME = "streamshub-operators";
+    public static final String CONSOLE_INSTANCE = "console-instance";
+}
diff --git a/systemtests/src/main/java/com/github/streamshub/systemtests/constants/Labels.java b/systemtests/src/main/java/com/github/streamshub/systemtests/constants/Labels.java
index d38f0dfcc..69ea7d406 100644
--- a/systemtests/src/main/java/com/github/streamshub/systemtests/constants/Labels.java
+++ b/systemtests/src/main/java/com/github/streamshub/systemtests/constants/Labels.java
@@ -1,6 +1,47 @@
 package com.github.streamshub.systemtests.constants;
 
+import com.github.streamshub.systemtests.exceptions.UnsupportedKafkaRoleException;
+import io.fabric8.kubernetes.api.model.LabelSelector;
+import io.fabric8.kubernetes.api.model.LabelSelectorBuilder;
+import io.strimzi.api.ResourceLabels;
+import io.strimzi.api.kafka.model.kafka.Kafka;
+import io.strimzi.api.kafka.model.nodepool.ProcessRoles;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
 public class Labels {
     private Labels() {}
+
+    // ------------
+    // General
+    // ------------
     public static final String COLLECT_ST_LOGS = "streamshub-st";
+
+    // ------------
+    // Strimzi
+    // ------------
+    public static final String STRIMZI_POOL_NAME_LABEL = ResourceLabels.STRIMZI_DOMAIN + "pool-name";
+    public static final String STRIMZI_BROKER_ROLE_LABEL = ResourceLabels.STRIMZI_DOMAIN + "broker-role";
+    public static final String STRIMZI_CONTROLLER_ROLE_LABEL = ResourceLabels.STRIMZI_DOMAIN + "controller-role";
+
+    // ------------
+    // Label selectors
+    // ------------
+    public static LabelSelector getKnpLabelSelector(String clusterName, String poolName, ProcessRoles processRole) {
+        Map<String, String> matchLabels = new HashMap<>();
+
+        matchLabels.put(ResourceLabels.STRIMZI_CLUSTER_LABEL, clusterName);
+        matchLabels.put(ResourceLabels.STRIMZI_KIND_LABEL, Kafka.RESOURCE_KIND.toLowerCase(Locale.ENGLISH));
+        matchLabels.put(Labels.STRIMZI_POOL_NAME_LABEL, poolName);
+
+        switch (processRole) {
+            case BROKER -> matchLabels.put(Labels.STRIMZI_BROKER_ROLE_LABEL, "true");
+            case CONTROLLER -> matchLabels.put(Labels.STRIMZI_CONTROLLER_ROLE_LABEL, "true");
+            default -> throw new UnsupportedKafkaRoleException("KafkaNodePool without specified Broker or Controller role is unsupported");
+        }
+
+        return new LabelSelectorBuilder().withMatchLabels(matchLabels).build();
+    }
 }
diff --git a/systemtests/src/main/java/com/github/streamshub/systemtests/constants/ResourceKinds.java b/systemtests/src/main/java/com/github/streamshub/systemtests/constants/ResourceKinds.java
deleted file mode 100644
index d924a8f1b..000000000
--- a/systemtests/src/main/java/com/github/streamshub/systemtests/constants/ResourceKinds.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.github.streamshub.systemtests.constants;
-
-public class ResourceKinds {
-    private ResourceKinds() {}
-
-    // ----------
-    // K8s
-    // ----------
-    public static final String CUSTOM_RESOURCE_DEFINITION = "customresourcedefinition";
-    public static final String CONFIG_MAP = "configmap";
-    public static final String DEPLOYMENT = "deployment";
-    public static final String DEPLOYMENT_CONFIG = "deploymentconfig";
-    public static final String POD = "pod";
-    public static final String SERVICE = "service";
-    public static final String SECRET = "secret";
-    public static final String CLUSTER_ROLE = "clusterrole";
-    public static final String CLUSTER_ROLE_BINDING = "clusterrolebinding";
-    public static final String ROLE_BINDING = "rolebinding";
-    public static final String SERVICE_ACCOUNT = "serviceaccount";
-    public static final String JOB = "job";
-    public static final String NAMESPACE = "namespace";
-    // ----------
-    // Openshift
-    // ----------
-    public static final String CATALOG_SOURCE = "catalogsource";
-    public static final String SUBSCRIPTION = "subscription";
-    public static final String INSTALL_PLAN = "installplan";
-    public static final String CLUSTER_SERVICE_VERSION = "clusterserviceversion";
-    public static final String OPERATOR_GROUP = "operatorgroup";
-    public static final String OPERATOR = "operator";
-    // ----------
-    // Kafka
-    // ----------
-    public static final String KAFKA_TOPIC = "kafkatopic";
-    public static final String KAFKA = "kafka";
-    public static final String KAFKA_USER = "kafkauser";
-    public static final String KAFKA_NODE_POOL = "kafkanodepool";
-    // ----------
-    // Console
-    // ----------
-    public static final String CONSOLE = "console";
-}
diff --git a/systemtests/src/main/java/com/github/streamshub/systemtests/exceptions/UnsupportedKafkaRoleException.java b/systemtests/src/main/java/com/github/streamshub/systemtests/exceptions/UnsupportedKafkaRoleException.java
new file mode 100644
index 000000000..aa6d98003
--- /dev/null
+++ b/systemtests/src/main/java/com/github/streamshub/systemtests/exceptions/UnsupportedKafkaRoleException.java
@@ -0,0 +1,7 @@
+package com.github.streamshub.systemtests.exceptions;
+
+public class UnsupportedKafkaRoleException extends RuntimeException {
+    public UnsupportedKafkaRoleException(String message) {
+        super(message);
+    }
+}
diff --git a/systemtests/src/main/java/com/github/streamshub/systemtests/logs/TestLogCollector.java b/systemtests/src/main/java/com/github/streamshub/systemtests/logs/TestLogCollector.java
index 0d6a41d98..56adc17c4 100644
--- a/systemtests/src/main/java/com/github/streamshub/systemtests/logs/TestLogCollector.java
+++ b/systemtests/src/main/java/com/github/streamshub/systemtests/logs/TestLogCollector.java
@@ -1,14 +1,25 @@
 package com.github.streamshub.systemtests.logs;
 
+import com.github.streamshub.console.api.v1alpha1.Console;
 import com.github.streamshub.systemtests.Environment;
 import com.github.streamshub.systemtests.constants.Labels;
-import com.github.streamshub.systemtests.constants.ResourceKinds;
+import io.fabric8.kubernetes.api.model.HasMetadata;
 import io.fabric8.kubernetes.api.model.LabelSelectorBuilder;
+import io.fabric8.kubernetes.api.model.Secret;
+import io.fabric8.kubernetes.api.model.apps.Deployment;
+import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroup;
+import io.fabric8.openshift.api.model.operatorhub.v1alpha1.ClusterServiceVersion;
+import io.fabric8.openshift.api.model.operatorhub.v1alpha1.InstallPlan;
+import io.fabric8.openshift.api.model.operatorhub.v1alpha1.Subscription;
 import io.skodjob.testframe.LogCollector;
 import io.skodjob.testframe.LogCollectorBuilder;
 import io.skodjob.testframe.clients.KubeClient;
 import io.skodjob.testframe.clients.cmdClient.Kubectl;
 import io.skodjob.testframe.resources.KubeResourceManager;
+import io.strimzi.api.kafka.model.kafka.Kafka;
+import io.strimzi.api.kafka.model.nodepool.KafkaNodePool;
+import io.strimzi.api.kafka.model.topic.KafkaTopic;
+import io.strimzi.api.kafka.model.user.KafkaUser;
 import org.apache.logging.log4j.Logger;
 
 import java.io.File;
@@ -44,21 +55,21 @@ public static TestLogCollector getInstance() {
 
     private LogCollector defaultLogCollector() {
         List<String> resources = new ArrayList<>(List.of(
-            ResourceKinds.SECRET,
-            ResourceKinds.DEPLOYMENT,
-            ResourceKinds.KAFKA,
-            ResourceKinds.KAFKA_NODE_POOL,
-            ResourceKinds.KAFKA_TOPIC,
-            ResourceKinds.KAFKA_USER,
-            ResourceKinds.CONSOLE
+            HasMetadata.getKind(Secret.class),
+            HasMetadata.getKind(Deployment.class),
+            HasMetadata.getKind(Console.class),
+            Kafka.RESOURCE_KIND,
+            KafkaNodePool.RESOURCE_KIND,
+            KafkaTopic.RESOURCE_KIND,
+            KafkaUser.RESOURCE_KIND
         ));
 
         if (Environment.INSTALL_USING_OLM) {
             resources.addAll(List.of(
-                ResourceKinds.OPERATOR_GROUP,
-                ResourceKinds.SUBSCRIPTION,
-                ResourceKinds.INSTALL_PLAN,
-                ResourceKinds.CLUSTER_SERVICE_VERSION
+                HasMetadata.getKind(OperatorGroup.class),
+                HasMetadata.getKind(Subscription.class),
+                HasMetadata.getKind(InstallPlan.class),
+                HasMetadata.getKind(ClusterServiceVersion.class)
             ));
         }
 
@@ -111,8 +122,8 @@ private Path buildFullPathToLogs(String testClass, String testCase) {
 
     public void collectLogs() {
         collectLogs(
-            KubeResourceManager.getTestContext().getRequiredTestClass().getName(),
-            KubeResourceManager.getTestContext().getRequiredTestMethod().getName()
+            KubeResourceManager.get().getTestContext().getRequiredTestClass().getName(),
+            KubeResourceManager.get().getTestContext().getRequiredTestMethod().getName()
         );
     }
 
diff --git a/systemtests/src/main/java/com/github/streamshub/systemtests/setup/StrimziOperatorSetup.java b/systemtests/src/main/java/com/github/streamshub/systemtests/setup/StrimziOperatorSetup.java
new file mode 100644
index 000000000..0d2a62d1c
--- /dev/null
+++ b/systemtests/src/main/java/com/github/streamshub/systemtests/setup/StrimziOperatorSetup.java
@@ -0,0 +1,291 @@
+package com.github.streamshub.systemtests.setup;
+
+import com.github.streamshub.systemtests.Environment;
+import com.github.streamshub.systemtests.constants.Constants;
+import com.github.streamshub.systemtests.logs.LogWrapper;
+import com.github.streamshub.systemtests.utils.ResourceUtils;
+import com.github.streamshub.systemtests.utils.SetupUtils;
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
+import io.fabric8.kubernetes.api.model.HasMetadata;
+import io.fabric8.kubernetes.api.model.ServiceAccount;
+import io.fabric8.kubernetes.api.model.ServiceAccountBuilder;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinitionBuilder;
+import io.fabric8.kubernetes.api.model.apps.Deployment;
+import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRole;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBuilder;
+import io.fabric8.kubernetes.api.model.rbac.RoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.RoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.SubjectBuilder;
+import io.skodjob.testframe.resources.KubeResourceManager;
+import io.skodjob.testframe.utils.TestFrameUtils;
+import org.apache.logging.log4j.Logger;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class StrimziOperatorSetup {
+    private static final Logger LOGGER = LogWrapper.getLogger(StrimziOperatorSetup.class);
+
+    private final List<File> strimziResources = fetchStrimziYamlFiles();
+    private final String deploymentNamespace;
+    private final String deploymentName;
+
+    public StrimziOperatorSetup(String deploymentNamespace) {
+        this.deploymentNamespace = deploymentNamespace;
+        this.deploymentName = Environment.STRIMZI_OPERATOR_NAME;
+    }
+
+    public void setup() {
+        LOGGER.info("----------- Setup Strimzi Cluster Operator -----------");
+        // Watch all namespaces CRB
+        // https://strimzi.io/docs/operators/latest/deploying#deploying-cluster-operator-to-watch-whole-cluster-str
+        KubeResourceManager.get().createResourceWithWait(getStrimziWatchAllCrbs());
+
+        if (Environment.SKIP_STRIMZI_INSTALLATION || ResourceUtils.getKubeResource(Deployment.class, this.deploymentNamespace, this.deploymentName) != null) {
+            LOGGER.warn("Skipping Strimzi installation. It is already installed or env to skip installation was set to `true`!");
+            return;
+        }
+
+        LOGGER.info("Install Strimzi Cluster Operator in namespace: {}", this.deploymentNamespace);
+        KubeResourceManager.get().createResourceWithoutWait(getBundleCrds());
+        KubeResourceManager.get().createResourceWithoutWait(getBundleClusterRoles());
+        KubeResourceManager.get().createResourceWithoutWait(getBundleServiceAccount());
+        KubeResourceManager.get().createResourceWithoutWait(getBundleRoleBindings());
+        KubeResourceManager.get().createResourceWithoutWait(getBundleClusterRoleBindings());
+        KubeResourceManager.get().createResourceWithoutWait(getBundleConfigMap());
+        KubeResourceManager.get().createResourceWithWait(getBundleDeployment());
+    }
+
+    public void teardown() {
+        LOGGER.info("----------- Teardown Strimzi Cluster Operator -----------");
+        if (Environment.SKIP_STRIMZI_INSTALLATION || ResourceUtils.getKubeResource(Deployment.class, this.deploymentNamespace, this.deploymentName) == null) {
+            LOGGER.warn("Skipping Strimzi deletion. It is already deleted or installation was skipped!");
+            return;
+        }
+
+        // Watch all namespaces CRB
+        KubeResourceManager.get().deleteResource(getStrimziWatchAllCrbs());
+        KubeResourceManager.get().deleteResource(getBundleCrds());
+        KubeResourceManager.get().deleteResource(getBundleClusterRoles());
+        KubeResourceManager.get().deleteResource(getBundleServiceAccount());
+        KubeResourceManager.get().deleteResource(getBundleRoleBindings());
+        KubeResourceManager.get().deleteResource(getBundleClusterRoleBindings());
+        KubeResourceManager.get().deleteResource(getBundleConfigMap());
+        KubeResourceManager.get().deleteResource(getBundleDeployment());
+    }
+
+    private ClusterRoleBinding[] getStrimziWatchAllCrbs() {
+        return new ClusterRoleBinding[]{
+            new ClusterRoleBindingBuilder()
+                .withNewMetadata()
+                    .withName(Constants.STRIMZI_CO_NAME + "-namespaced")
+                .endMetadata()
+                .withNewRoleRef()
+                    .withApiGroup(Constants.RBAC_AUTH_API_GROUP)
+                    .withKind(HasMetadata.getKind(ClusterRole.class))
+                    .withName(Constants.STRIMZI_CO_NAME + "-namespaced")
+                .endRoleRef()
+                .withSubjects(new SubjectBuilder()
+                    .withKind(HasMetadata.getKind(ServiceAccount.class))
+                    .withName(Constants.STRIMZI_CO_NAME)
+                    .withNamespace(this.deploymentNamespace)
+                    .build())
+                .build(),
+            new ClusterRoleBindingBuilder()
+                .withNewMetadata()
+                    .withName(Constants.STRIMZI_CO_NAME  + "-entity-operator")
+                .endMetadata()
+                .withNewRoleRef()
+                    .withApiGroup(Constants.RBAC_AUTH_API_GROUP)
+                    .withKind(HasMetadata.getKind(ClusterRole.class))
+                    .withName(Constants.STRIMZI_CO_NAME  + "-entity-operator")
+                .endRoleRef()
+                .withSubjects(new SubjectBuilder()
+                    .withKind(HasMetadata.getKind(ServiceAccount.class))
+                    .withName(Constants.STRIMZI_CO_NAME)
+                    .withNamespace(this.deploymentNamespace)
+                    .build())
+                .build(),
+            new ClusterRoleBindingBuilder()
+                .withNewMetadata()
+                    .withName(Constants.STRIMZI_CO_NAME + "-watched")
+                .endMetadata()
+                .withNewRoleRef()
+                    .withApiGroup(Constants.RBAC_AUTH_API_GROUP)
+                    .withKind(HasMetadata.getKind(ClusterRole.class))
+                    .withName(Constants.STRIMZI_CO_NAME + "-watched")
+                .endRoleRef()
+                .withSubjects(new SubjectBuilder()
+                    .withKind(HasMetadata.getKind(ServiceAccount.class))
+                    .withName(Constants.STRIMZI_CO_NAME)
+                    .withNamespace(this.deploymentNamespace)
+                    .build())
+                .build()
+        };
+    }
+
+    private ConfigMap getBundleConfigMap() {
+        return new ConfigMapBuilder(TestFrameUtils.configFromYaml(strimziResources.stream()
+            .filter(file -> file.getName().startsWith("050-ConfigMap")).toList().get(0), ConfigMap.class))
+            .editMetadata()
+                .withNamespace(this.deploymentNamespace)
+                .withName(this.deploymentName)
+            .endMetadata()
+            .build();
+    }
+
+    private ServiceAccount getBundleServiceAccount() {
+        return new ServiceAccountBuilder(TestFrameUtils.configFromYaml(strimziResources.stream()
+            .filter(file -> file.getName().startsWith("010-ServiceAccount")).toList().get(0), ServiceAccount.class))
+            .editMetadata()
+                .withNamespace(this.deploymentNamespace)
+            .endMetadata()
+            .build();
+    }
+
+    private Deployment getBundleDeployment() {
+        return new DeploymentBuilder(TestFrameUtils.configFromYaml(strimziResources.stream()
+            .filter(file -> file.getName().startsWith("060-Deployment")).toList().get(0), Deployment.class))
+            .editMetadata()
+                .withNamespace(this.deploymentNamespace)
+                .withName(this.deploymentName)
+            .endMetadata()
+            .editSpec()
+                .editTemplate()
+                    .editSpec()
+                        .editFirstContainer()
+                            .removeMatchingFromEnv(e -> e.getName().equals(Constants.STRIMZI_NAMESPACE_KEY))
+                            .addNewEnv()
+                                .withName(Constants.STRIMZI_NAMESPACE_KEY)
+                                .withValue(Constants.STRIMZI_WATCH_ALL_NAMESPACES)
+                            .endEnv()
+                        .endContainer()
+                    .endSpec()
+                .endTemplate()
+            .endSpec()
+            .build();
+    }
+
+    private CustomResourceDefinition[] getBundleCrds() {
+        return strimziResources.stream().filter(file -> file.getName().contains("-Crd-"))
+            .map(crd -> new CustomResourceDefinitionBuilder(TestFrameUtils.configFromYaml(crd, CustomResourceDefinition.class))
+                .editMetadata()
+                    .withNamespace(this.deploymentNamespace)
+                .endMetadata()
+                .build())
+            .toArray(CustomResourceDefinition[]::new);
+    }
+
+    private ClusterRole[] getBundleClusterRoles() {
+        return strimziResources.stream().filter(file -> file.getName().contains("-ClusterRole-"))
+            .map(file -> new ClusterRoleBuilder(TestFrameUtils.configFromYaml(file, ClusterRole.class))
+                .editMetadata()
+                    .withNamespace(this.deploymentNamespace)
+                .endMetadata()
+                .build())
+            .toArray(ClusterRole[]::new);
+    }
+
+    private RoleBinding[] getBundleRoleBindings() {
+        return strimziResources.stream().filter(file -> file.getName().contains("-RoleBinding-"))
+            .map(rb -> new RoleBindingBuilder(TestFrameUtils.configFromYaml(rb, RoleBinding.class))
+                .editMetadata()
+                    .withNamespace(this.deploymentNamespace)
+                .endMetadata()
+                .editFirstSubject()
+                    .withNamespace(this.deploymentNamespace)
+                .endSubject()
+                .build())
+            .toArray(RoleBinding[]::new);
+    }
+
+    private ClusterRoleBinding[] getBundleClusterRoleBindings() {
+        return strimziResources.stream().filter(file -> file.getName().contains("-ClusterRoleBinding-"))
+            .map(crb -> new ClusterRoleBindingBuilder(TestFrameUtils.configFromYaml(crb, ClusterRoleBinding.class))
+                .editMetadata()
+                    .withNamespace(this.deploymentNamespace)
+                .endMetadata()
+                .editFirstSubject()
+                    .withNamespace(this.deploymentNamespace)
+                .endSubject()
+                .build())
+            .toArray(ClusterRoleBinding[]::new);
+    }
+
+    private List<File> fetchStrimziYamlFiles() {
+        List<File> yamlFiles = new ArrayList<>();
+        for (String fileUrl : extractYamlFileLinksFromGithubDir()) {
+            String fileName = fileUrl.substring(fileUrl.lastIndexOf('/') + 1).replace(".yaml", "");
+            LOGGER.debug("Fetching Strimzi YAML file: {}", fileName);
+            Path tempFile = null;
+            try {
+                tempFile = Files.createTempFile(fileName + "-tmp_", ".yaml");
+                Files.write(tempFile, SetupUtils.getYamlFileContent(fileUrl).getBytes());
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+            yamlFiles.add(tempFile.toFile());
+        }
+        return yamlFiles;
+    }
+
+    private List<String> extractYamlFileLinksFromGithubDir() {
+        LOGGER.debug("Extracting Strimzi YAML file links from GitHub url: {}", Environment.STRIMZI_OPERATOR_CRDS_URL);
+        int maxRetries = 10;
+        int attempt = 0;
+
+        while (attempt < maxRetries) {
+            try {
+                BufferedReader htmlWithLinksFromDir = new BufferedReader(
+                    new InputStreamReader(new URL(Environment.STRIMZI_OPERATOR_CRDS_URL).openStream()));
+
+                StringBuilder content = new StringBuilder();
+                String inputLine;
+
+                while ((inputLine = htmlWithLinksFromDir.readLine()) != null) {
+                    content.append(inputLine);
+                }
+
+                htmlWithLinksFromDir.close();
+
+                List<String> yamlFileLinks = new ArrayList<>();
+                Matcher matcher = Pattern.compile("href=\"(\\/[a-zA-Z0-9\\.\\/\\-]+\\/.{3}[a-zA-Z\\-]+\\d?\\.yaml)\"")
+                    .matcher(content.toString());
+
+                while (matcher.find()) {
+                    final String rawUrl = "https://raw.githubusercontent.com" + matcher.group(1)
+                        .replace("/blob/", "/");
+                    if (!yamlFileLinks.contains(rawUrl)) {
+                        yamlFileLinks.add(rawUrl);
+                    }
+                }
+
+                if (!yamlFileLinks.isEmpty()) {
+                    return yamlFileLinks;
+                }
+
+                LOGGER.warn("Attempt {}: Could not get GitHub Strimzi YAML file links, retrying in 3 seconds...", attempt + 1);
+                Thread.sleep(3_000);
+            } catch (IOException | InterruptedException e) {
+                LOGGER.error("Attempt {} failed: {}", attempt + 1, e.getMessage());
+            }
+
+            attempt++;
+        }
+        throw new RuntimeException("Could not retrieve Strimzi CRs from GitHub after " + maxRetries + " attempts");
+    }
+}
diff --git a/systemtests/src/main/java/com/github/streamshub/systemtests/unit/UnitTestUtils.java b/systemtests/src/main/java/com/github/streamshub/systemtests/unit/UnitTestUtils.java
deleted file mode 100644
index 456a2d7ac..000000000
--- a/systemtests/src/main/java/com/github/streamshub/systemtests/unit/UnitTestUtils.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.github.streamshub.systemtests.unit;
-
-import java.lang.reflect.Field;
-import java.util.Map;
-
-public class UnitTestUtils {
-    private UnitTestUtils() {}
-
-    // Utility method to set env variable via reflection
-    @SuppressWarnings("unchecked")
-    public static void setEnv(String key, String value) throws NoSuchFieldException, IllegalAccessException {
-        Map<String, String> env = System.getenv();
-        Field field = env.getClass().getDeclaredField("m");
-        field.setAccessible(true);
-        ((Map<String, String>) field.get(env)).put(key, value);
-    }
-
-    @SuppressWarnings("unchecked")
-    public static void removeEnv(String key) throws NoSuchFieldException, IllegalAccessException {
-        Map<String, String> env = System.getenv();
-        Field field = env.getClass().getDeclaredField("m");
-        field.setAccessible(true);
-        ((Map<String, String>) field.get(env)).remove(key);
-    }
-
-    public static void setField(Object target, String fieldName, Object newValue) throws NoSuchFieldException, IllegalAccessException {
-        Field field;
-        field = target.getClass().getDeclaredField(fieldName);
-        field.setAccessible(true);
-        field.set(target, newValue);
-    }
-}
diff --git a/systemtests/src/main/java/com/github/streamshub/systemtests/utils/ClusterUtils.java b/systemtests/src/main/java/com/github/streamshub/systemtests/utils/ClusterUtils.java
index 4e8d4f6f9..fcfef19f3 100644
--- a/systemtests/src/main/java/com/github/streamshub/systemtests/utils/ClusterUtils.java
+++ b/systemtests/src/main/java/com/github/streamshub/systemtests/utils/ClusterUtils.java
@@ -10,13 +10,13 @@ public class ClusterUtils {
     private ClusterUtils() {}
 
     public static void checkClusterHealth() {
-        ExecResult result = KubeResourceManager.getKubeCmdClient().exec(false, "cluster-info");
+        ExecResult result = KubeResourceManager.get().kubeCmdClient().exec(false, "cluster-info");
         if (!result.exitStatus() || !result.out().contains("Kubernetes control plane is running at") || result.out().toLowerCase(Locale.ENGLISH).contains("error")) {
             throw new ClusterUnreachableException(result);
         }
     }
 
     public static boolean isOcp() {
-        return KubeResourceManager.getKubeCmdClient().exec(false, "api-versions").out().contains("openshift.io");
+        return KubeResourceManager.get().kubeCmdClient().exec(false, "api-versions").out().contains("openshift.io");
     }
 }
diff --git a/systemtests/src/main/java/com/github/streamshub/systemtests/utils/ResourceUtils.java b/systemtests/src/main/java/com/github/streamshub/systemtests/utils/ResourceUtils.java
new file mode 100644
index 000000000..b8d0d91a6
--- /dev/null
+++ b/systemtests/src/main/java/com/github/streamshub/systemtests/utils/ResourceUtils.java
@@ -0,0 +1,19 @@
+package com.github.streamshub.systemtests.utils;
+
+import io.fabric8.kubernetes.api.model.HasMetadata;
+import io.skodjob.testframe.resources.KubeResourceManager;
+
+public class ResourceUtils {
+
+    private ResourceUtils() {}
+
+    // Vanilla k8s
+    public static <T extends HasMetadata> T getKubeResource(Class<T> resourceClass, String namespaceName, String resourceName) {
+        return KubeResourceManager.get().kubeClient().getClient().resources(resourceClass).inNamespace(namespaceName).withName(resourceName).get();
+    }
+
+    public static <T extends HasMetadata> T getKubeResource(Class<T> resourceClass, String resourceName) {
+        return KubeResourceManager.get().kubeClient().getClient().resources(resourceClass).withName(resourceName).get();
+
+    }
+}
diff --git a/systemtests/src/main/java/com/github/streamshub/systemtests/utils/SetupUtils.java b/systemtests/src/main/java/com/github/streamshub/systemtests/utils/SetupUtils.java
new file mode 100644
index 000000000..b26c192c6
--- /dev/null
+++ b/systemtests/src/main/java/com/github/streamshub/systemtests/utils/SetupUtils.java
@@ -0,0 +1,34 @@
+package com.github.streamshub.systemtests.utils;
+
+import com.github.streamshub.systemtests.logs.LogWrapper;
+import org.apache.logging.log4j.Logger;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+
+public class SetupUtils {
+    private static final Logger LOGGER = LogWrapper.getLogger(SetupUtils.class);
+    private SetupUtils() {}
+
+    // ---------------
+    // Yaml config
+    // --------------
+    public static String getYamlFileContent(String fileUrl) {
+        LOGGER.debug("Loading YAML file content from url {}", fileUrl);
+        StringBuilder content;
+        try (BufferedReader in = new BufferedReader(new InputStreamReader(new URL(fileUrl).openStream(), StandardCharsets.UTF_8))) {
+            content = new StringBuilder();
+            String inputLine;
+
+            while ((inputLine = in.readLine()) != null) {
+                content.append(inputLine).append("\n");
+            }
+        } catch (IOException e) {
+            throw new RuntimeException("Cannot download YAML content from url: " + fileUrl, e);
+        }
+        return content.toString();
+    }
+}
diff --git a/systemtests/src/test/java/com/github/streamshub/systemtests/system/AbstractST.java b/systemtests/src/test/java/com/github/streamshub/systemtests/system/AbstractST.java
index 08971a5cb..f77363992 100644
--- a/systemtests/src/test/java/com/github/streamshub/systemtests/system/AbstractST.java
+++ b/systemtests/src/test/java/com/github/streamshub/systemtests/system/AbstractST.java
@@ -1,10 +1,15 @@
 package com.github.streamshub.systemtests.system;
 
 import com.github.streamshub.systemtests.Environment;
+import com.github.streamshub.systemtests.constants.Constants;
 import com.github.streamshub.systemtests.constants.Labels;
-import com.github.streamshub.systemtests.constants.ResourceKinds;
 import com.github.streamshub.systemtests.logs.LogWrapper;
+import com.github.streamshub.systemtests.setup.StrimziOperatorSetup;
 import com.github.streamshub.systemtests.utils.ClusterUtils;
+import com.github.streamshub.systemtests.utils.ResourceUtils;
+import io.fabric8.kubernetes.api.model.HasMetadata;
+import io.fabric8.kubernetes.api.model.Namespace;
+import io.fabric8.kubernetes.api.model.NamespaceBuilder;
 import io.skodjob.testframe.annotations.ResourceManager;
 import io.skodjob.testframe.annotations.TestVisualSeparator;
 import io.skodjob.testframe.resources.ClusterRoleBindingType;
@@ -24,6 +29,7 @@
 import io.skodjob.testframe.resources.SubscriptionType;
 import io.skodjob.testframe.utils.KubeUtils;
 import org.apache.logging.log4j.Logger;
+import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.TestInstance;
@@ -35,10 +41,11 @@
 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
 public abstract class AbstractST {
     private static final Logger LOGGER = LogWrapper.getLogger(AbstractST.class);
-    protected static final KubeResourceManager RESOURCE_MANAGER = KubeResourceManager.getInstance();
+    // Operators
+    protected final StrimziOperatorSetup strimziOperatorSetup = new StrimziOperatorSetup(Constants.CO_NAMESPACE);
 
     static {
-        RESOURCE_MANAGER.setResourceTypes(
+        KubeResourceManager.get().setResourceTypes(
             new CustomResourceDefinitionType(),
             new ClusterRoleBindingType(),
             new ClusterRoleType(),
@@ -54,15 +61,15 @@ public abstract class AbstractST {
             new ServiceType(),
             new SubscriptionType());
 
-        RESOURCE_MANAGER.addCreateCallback(resource -> {
+        KubeResourceManager.get().addCreateCallback(resource -> {
             // Set collect label for every namespace created with TF
-            if (resource.getKind().equalsIgnoreCase(ResourceKinds.NAMESPACE)) {
+            if (resource.getKind().equals(HasMetadata.getKind(Namespace.class))) {
                 KubeUtils.labelNamespace(resource.getMetadata().getName(), Labels.COLLECT_ST_LOGS, "true");
             }
         });
 
-        // Allow storing yaml files
-        KubeResourceManager.setStoreYamlPath(Environment.TEST_LOG_DIR);
+        // Allow storing YAML files
+        KubeResourceManager.get().setStoreYamlPath(Environment.TEST_LOG_DIR);
 
         try {
             Environment.saveConfigToFile();
@@ -72,12 +79,27 @@ public abstract class AbstractST {
     }
 
     @BeforeAll
-    void beforeAll() {
-        LOGGER.info("=========== AbstractST - BeforeAll ===========");
+    void setupTestSuite() {
+        LOGGER.info("=========== AbstractST - BeforeAll - Setup TestSuite ===========");
+        if (ResourceUtils.getKubeResource(Namespace.class, Constants.CO_NAMESPACE) == null) {
+            KubeResourceManager.get().createOrUpdateResourceWithWait(new NamespaceBuilder().withNewMetadata().withName(Constants.CO_NAMESPACE).endMetadata().build());
+        }
+        strimziOperatorSetup.setup();
     }
 
     @BeforeEach
-    void beforeEach() {
+    void setupTestCase() {
+        LOGGER.info("=========== AbstractST - BeforeEach - Setup TestCase {} ===========", KubeResourceManager.get().getTestContext().getTestMethod());
         ClusterUtils.checkClusterHealth();
     }
+
+    @AfterAll
+    void tearDownTestSuite() {
+        LOGGER.info("=========== AbstractST - AfterAll - Tear down the TestSuite ===========");
+        if (Environment.SKIP_TEARDOWN) {
+            LOGGER.warn("Teardown was skipped because of SKIP_TEARDOWN env");
+            return;
+        }
+        strimziOperatorSetup.teardown();
+    }
 }
diff --git a/systemtests/src/test/java/com/github/streamshub/systemtests/unit/TestExecutionWatcherTest.java b/systemtests/src/test/java/com/github/streamshub/systemtests/unit/TestExecutionWatcherTest.java
index 73db4b7d6..0ef448cef 100644
--- a/systemtests/src/test/java/com/github/streamshub/systemtests/unit/TestExecutionWatcherTest.java
+++ b/systemtests/src/test/java/com/github/streamshub/systemtests/unit/TestExecutionWatcherTest.java
@@ -10,6 +10,7 @@
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtensionContext;
 import org.opentest4j.TestAbortedException;
+import org.powermock.reflect.Whitebox;
 
 import java.lang.reflect.Method;
 
@@ -34,8 +35,8 @@ class TestExecutionWatcherTest {
     private static final Throwable TEST_ABORTED_EXCEPTION = new TestAbortedException("Test was aborted");
 
     @BeforeEach
-    void setUp() throws NoSuchMethodException, NoSuchFieldException, IllegalAccessException {
-        UnitTestUtils.setField(mockWatcher, "logCollector", mockTestLogCollector);
+    void setUp() throws NoSuchMethodException {
+        Whitebox.setInternalState(TestExecutionWatcher.class, "LOG_COLLECTOR", mockTestLogCollector);
         when(mockContext.getRequiredTestClass()).thenReturn((Class) String.class);
         when(mockContext.getRequiredTestMethod()).thenReturn(String.class.getDeclaredMethod("toString"));
         doNothing().when(mockTestLogCollector).collectLogs(anyString(), anyString());
diff --git a/systemtests/src/test/java/com/github/streamshub/systemtests/unit/utils/ClusterUtilsTest.java b/systemtests/src/test/java/com/github/streamshub/systemtests/unit/utils/ClusterUtilsTest.java
index 9c96695b0..2b8fb47ec 100644
--- a/systemtests/src/test/java/com/github/streamshub/systemtests/unit/utils/ClusterUtilsTest.java
+++ b/systemtests/src/test/java/com/github/streamshub/systemtests/unit/utils/ClusterUtilsTest.java
@@ -27,18 +27,20 @@ class ClusterUtilsTest {
 
     private static final KubeCmdClient MOCKED_CMD_CLIENT = mock(KubeCmdClient.class);
     private static final ExecResult MOCKED_EXEC_RESULT = mock(ExecResult.class);
-    private static MockedStatic<KubeResourceManager> mockedKubeResourceManager;
+    private static MockedStatic<KubeResourceManager> staticMockedKubeResourceManager;
+    private static final KubeResourceManager MOCKED_KUBE_RESOURCE_MANAGER = mock(KubeResourceManager.class);
 
     @BeforeEach
     void setup() {
-        mockedKubeResourceManager = mockStatic(KubeResourceManager.class);
-        mockedKubeResourceManager.when(KubeResourceManager::getKubeCmdClient).thenReturn(MOCKED_CMD_CLIENT);
+        staticMockedKubeResourceManager = mockStatic(KubeResourceManager.class);
+        staticMockedKubeResourceManager.when(KubeResourceManager::get).thenReturn(MOCKED_KUBE_RESOURCE_MANAGER);
+        when(MOCKED_KUBE_RESOURCE_MANAGER.kubeCmdClient()).thenReturn(MOCKED_CMD_CLIENT);
         when(MOCKED_CMD_CLIENT.exec(false, "cluster-info")).thenReturn(MOCKED_EXEC_RESULT);
     }
 
     @AfterEach
     void tearDown() {
-        mockedKubeResourceManager.close();
+        staticMockedKubeResourceManager.close();
     }
 
     static Stream<Arguments> clusterHealthTestCases() {
@@ -66,7 +68,7 @@ void testCheckClusterHealth(boolean exitStatus, String output, boolean shouldThr
 
     @Test
     void testIsOcp() {
-        ExecResult methodCall = KubeResourceManager.getKubeCmdClient().exec(false, "api-versions");
+        ExecResult methodCall = KubeResourceManager.get().kubeCmdClient().exec(false, "api-versions");
         when(methodCall).thenReturn(new ExecResult(0, "openshift.io version 1.2.3", ""));
         assertTrue(ClusterUtils.isOcp());
 
diff --git a/systemtests/src/test/java/com/github/streamshub/systemtests/unit/utils/ResourceUtilsTest.java b/systemtests/src/test/java/com/github/streamshub/systemtests/unit/utils/ResourceUtilsTest.java
new file mode 100644
index 000000000..d474e2e8b
--- /dev/null
+++ b/systemtests/src/test/java/com/github/streamshub/systemtests/unit/utils/ResourceUtilsTest.java
@@ -0,0 +1,96 @@
+package com.github.streamshub.systemtests.unit.utils;
+
+import com.github.streamshub.systemtests.utils.ResourceUtils;
+import io.fabric8.kubernetes.api.model.KubernetesResourceList;
+import io.fabric8.kubernetes.api.model.Namespace;
+import io.fabric8.kubernetes.api.model.Pod;
+import io.fabric8.kubernetes.client.KubernetesClient;
+import io.fabric8.kubernetes.client.dsl.MixedOperation;
+import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation;
+import io.fabric8.kubernetes.client.dsl.Resource;
+import io.skodjob.testframe.clients.KubeClient;
+import io.skodjob.testframe.resources.KubeResourceManager;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class ResourceUtilsTest {
+
+    private static MockedStatic<KubeResourceManager> staticMockKubeResourceManager;
+    private static final KubeResourceManager MOCKED_KUBE_RESOURCE_MANAGER = mock(KubeResourceManager.class);
+    private static final KubeClient MOCKED_KUBE_CLIENT = mock(KubeClient.class);
+
+
+
+    @BeforeEach
+    void setUp() {
+        staticMockKubeResourceManager = mockStatic(KubeResourceManager.class);
+        staticMockKubeResourceManager.when(KubeResourceManager::get).thenReturn(MOCKED_KUBE_RESOURCE_MANAGER);
+        when(MOCKED_KUBE_RESOURCE_MANAGER.kubeClient()).thenReturn(MOCKED_KUBE_CLIENT);
+    }
+
+    @AfterEach
+    void tearDown() {
+        staticMockKubeResourceManager.close();
+    }
+
+    @Test
+    void testGetNamespacedKubeResource() {
+        final KubernetesClient mockedK8sClient = mock(KubernetesClient.class);
+        final MixedOperation<Pod, KubernetesResourceList<Pod>, Resource<Pod>> mockedMixedOp = mock(MixedOperation.class);
+        final NonNamespaceOperation<Pod, KubernetesResourceList<Pod>, Resource<Pod>> mockedNonNsOp = mock(NonNamespaceOperation.class);
+        final Resource<Pod> mockedPodResource = mock(Resource.class);
+        final Pod mockedPod = mock(Pod.class);
+
+        when(MOCKED_KUBE_CLIENT.getClient()).thenReturn(mockedK8sClient);
+
+        when(mockedK8sClient.resources(Pod.class)).thenReturn(mockedMixedOp);
+        when(mockedMixedOp.inNamespace(anyString())).thenReturn(mockedNonNsOp);
+        when(mockedNonNsOp.withName(anyString())).thenReturn(mockedPodResource);
+        when(mockedPodResource.get()).thenReturn(mockedPod);
+
+        // Call the method under test
+        Pod result = ResourceUtils.getKubeResource(Pod.class, "my-namespace", "my-pod");
+
+        // Verify the interactions and assertions
+        verify(mockedK8sClient).resources(Pod.class);
+        verify(mockedMixedOp).inNamespace("my-namespace");
+        verify(mockedNonNsOp).withName("my-pod");
+        verify(mockedPodResource).get();
+        assertNotNull(result);
+        assertEquals(mockedPod, result);
+    }
+
+    @Test
+    void testGetNamespacelessKubeResource() {
+        final KubernetesClient mockedK8sClient = mock(KubernetesClient.class);
+        final MixedOperation<Namespace, KubernetesResourceList<Namespace>, Resource<Namespace>> mockedMixedOp = mock(MixedOperation.class);
+        final Resource<Namespace> mockedNsResource = mock(Resource.class);
+        final Namespace mockedNs = mock(Namespace.class);
+
+        when(MOCKED_KUBE_CLIENT.getClient()).thenReturn(mockedK8sClient);
+
+        when(mockedK8sClient.resources(Namespace.class)).thenReturn(mockedMixedOp);
+        when(mockedMixedOp.withName(anyString())).thenReturn(mockedNsResource);
+        when(mockedNsResource.get()).thenReturn(mockedNs);
+
+        // Call the method under test
+        Namespace result = ResourceUtils.getKubeResource(Namespace.class, "my-ns");
+
+        // Verify the interactions and assertions
+        verify(mockedK8sClient).resources(Namespace.class);
+        verify(mockedMixedOp).withName("my-ns");
+        verify(mockedNsResource).get();
+        assertNotNull(result);
+        assertEquals(mockedNs, result);
+    }
+}
diff --git a/systemtests/src/test/java/com/github/streamshub/systemtests/unit/utils/SetupUtilsTest.java b/systemtests/src/test/java/com/github/streamshub/systemtests/unit/utils/SetupUtilsTest.java
new file mode 100644
index 000000000..8cd71574d
--- /dev/null
+++ b/systemtests/src/test/java/com/github/streamshub/systemtests/unit/utils/SetupUtilsTest.java
@@ -0,0 +1,22 @@
+package com.github.streamshub.systemtests.unit.utils;
+
+import com.github.streamshub.systemtests.utils.SetupUtils;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class SetupUtilsTest {
+
+    @Test
+    void testGetYamlFileContent() {
+        String invalidUrl = "http://very-invalid-123.cy/test.yaml";
+        String validUrl = "https://github.com/streamshub/console/releases/download/0.6.3/streamshub-console-operator.yaml";
+
+        Exception exception = assertThrows(RuntimeException.class, () -> SetupUtils.getYamlFileContent(invalidUrl));
+        assertTrue(exception.getMessage().contains("Cannot download YAML content"));
+
+        assertTrue(SetupUtils.getYamlFileContent(validUrl).startsWith("# Generated by Fabric8 CRDGenerator, manual edits might get overwritten!"));
+    }
+}
+


Reviews:
user: login: im-konge
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-31T15:23:23Z
user: login: MikeEdgar
body: First pass, left a few comments/questions.
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-31T15:29:47Z
user: login: im-konge
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-31T15:32:01Z
user: login: jankalinic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T15:39:47Z
user: login: im-konge
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-31T15:44:53Z
user: login: jankalinic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T15:47:05Z
user: login: jankalinic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T15:47:22Z
user: login: jankalinic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T15:49:02Z
user: login: jankalinic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T15:51:03Z
user: login: jankalinic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T16:00:36Z
user: login: im-konge
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-31T16:02:43Z
user: login: jankalinic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T16:17:44Z
user: login: jankalinic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T16:21:53Z
user: login: jankalinic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T16:23:36Z
user: login: im-konge
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-31T16:23:59Z
user: login: jankalinic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T16:26:00Z
user: login: MikeEdgar
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-31T16:30:04Z
user: login: jankalinic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T16:33:13Z
user: login: jankalinic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T17:33:28Z
user: login: im-konge
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-31T17:42:43Z
user: login: jankalinic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T17:52:11Z
user: login: MikeEdgar
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-31T17:54:35Z
user: login: MikeEdgar
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-31T17:59:57Z
user: login: jankalinic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T18:07:37Z
user: login: jankalinic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T09:05:52Z
user: login: MikeEdgar
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-01T09:43:18Z
user: login: MikeEdgar
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-01T09:46:26Z
user: login: jankalinic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T10:46:48Z
user: login: jankalinic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T11:01:42Z
user: login: im-konge
body: LGTM, thanks.
state: APPROVED
author_association: NONE
submitted_at: 2025-04-01T15:54:47Z

Review comments:
path: coverage/pom.xml
user: login: MikeEdgar
body: I'm not so sure mixing includes/excludes will work. The report generated here is for all the modules - API, operator, common, and systemtests - so I suspect listing includes may eliminated all the code in the other modules.
created_at: 2025-03-31T14:53:03Z
author_association: MEMBER
diff_hunk: @@ -23,15 +23,29 @@
         <playwright.version>1.47.0</playwright.version>
         <!-- Mocking environment -->
         <mockito.version>5.15.2</mockito.version>
-        <junit-pioneer.version>2.3.0</junit-pioneer.version>
+        <powermock.version>2.0.9</powermock.version>
         <!-- Used for test-frame -->
-        <test-frame.version>0.8.0</test-frame.version>
+        <test-frame.version>0.11.0-SNAPSHOT</test-frame.version>
path: systemtests/pom.xml
user: login: MikeEdgar
body: Do you know when it will be released? I'm ok merging this to the `systemtests` branch, but we'll want to make sure it's a final version before `systemtests` merged to `main`.
created_at: 2025-03-31T14:54:37Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,306 @@
+package com.github.streamshub.systemtests.setup;
+
+import com.github.streamshub.systemtests.Environment;
+import com.github.streamshub.systemtests.constants.Constants;
+import com.github.streamshub.systemtests.constants.Labels;
+import com.github.streamshub.systemtests.constants.ResourceKinds;
+import com.github.streamshub.systemtests.logs.LogWrapper;
+import com.github.streamshub.systemtests.utils.ResourceUtils;
+import com.github.streamshub.systemtests.utils.SetupUtils;
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
+import io.fabric8.kubernetes.api.model.ServiceAccount;
+import io.fabric8.kubernetes.api.model.ServiceAccountBuilder;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinitionBuilder;
+import io.fabric8.kubernetes.api.model.apps.Deployment;
+import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRole;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBuilder;
+import io.fabric8.kubernetes.api.model.rbac.RoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.RoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.SubjectBuilder;
+import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroup;
+import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroupBuilder;
+import io.skodjob.testframe.resources.KubeResourceManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class StrimziOperatorSetup {
+    private static final Logger LOGGER = LogWrapper.getLogger(StrimziOperatorSetup.class);
+    private static final KubeResourceManager RESOURCE_MANAGER = KubeResourceManager.get();
+
+    private final List<File> strimziResources = fetchStrimziYamlFiles();
+    private final String deploymentNamespace;
+    private final String deploymentName;
+
+    public StrimziOperatorSetup(String deploymentNamespace) {
+        this.deploymentNamespace = deploymentNamespace;
+        this.deploymentName = Environment.STRIMZI_OPERATOR_NAME;
+    }
+
+    public void setup() {
+        LOGGER.info("----------- Setup Strimzi Cluster Operator -----------");
+        // Watch all namespaces CRB
+        // https://strimzi.io/docs/operators/latest/deploying#deploying-cluster-operator-to-watch-whole-cluster-str
+        RESOURCE_MANAGER.createResourceWithWait(getStrimziWatchAllCrbs());
+
+        if (Environment.SKIP_STRIMZI_INSTALLATION || ResourceUtils.getKubeResource(Deployment.class, this.deploymentNamespace, this.deploymentName) != null) {
+            LOGGER.warn("Skipping Strimzi installation. It is already installed or env to skip installation was set to `true`!");
+            return;
+        }
+
+        LOGGER.info("Install Strimzi Cluster Operator in namespace: {}", this.deploymentNamespace);
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleCrds());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleClusterRoles());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleServiceAccount());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleRoleBindings());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleClusterRoleBindings());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleConfigMap());
+        RESOURCE_MANAGER.createResourceWithWait(getBundleDeployment());
+    }
+
+    public void teardown() {
+        LOGGER.info("----------- Teardown Strimzi Cluster Operator -----------");
+        if (Environment.SKIP_STRIMZI_INSTALLATION || ResourceUtils.getKubeResource(Deployment.class, this.deploymentNamespace, this.deploymentName) == null) {
+            LOGGER.warn("Skipping Strimzi deletion. It is already deleted or installation was skipped!");
+            return;
+        }
+
+        // Watch all namespaces CRB
+        RESOURCE_MANAGER.deleteResource(getStrimziOperatorGroup());
+        RESOURCE_MANAGER.deleteResource(getStrimziWatchAllCrbs());
+        RESOURCE_MANAGER.deleteResource(getBundleCrds());
+        RESOURCE_MANAGER.deleteResource(getBundleClusterRoles());
+        RESOURCE_MANAGER.deleteResource(getBundleServiceAccount());
+        RESOURCE_MANAGER.deleteResource(getBundleRoleBindings());
+        RESOURCE_MANAGER.deleteResource(getBundleClusterRoleBindings());
+        RESOURCE_MANAGER.deleteResource(getBundleConfigMap());
+        RESOURCE_MANAGER.deleteResource(getBundleDeployment());
+    }
+
+    private ClusterRoleBinding[] getStrimziWatchAllCrbs() {
+        return new ClusterRoleBinding[]{
+            new ClusterRoleBindingBuilder()
+                .withNewMetadata()
+                    .withName(Constants.STRIMZI_CO_NAME + "-namespaced")
+                .endMetadata()
+                .withNewRoleRef()
+                    .withApiGroup(Constants.RBAC_AUTH_API_GROUP)
+                    .withKind(ResourceKinds.CLUSTER_ROLE)
+                    .withName(Constants.STRIMZI_CO_NAME + "-namespaced")
+                .endRoleRef()
+                .withSubjects(new SubjectBuilder()
+                    .withKind(ResourceKinds.SERVICE_ACCOUNT)
+                    .withName(Constants.STRIMZI_CO_NAME)
+                    .withNamespace(this.deploymentNamespace)
+                    .build())
+                .build(),
+            new ClusterRoleBindingBuilder()
+                .withNewMetadata()
+                    .withName(Constants.STRIMZI_CO_NAME  + "-entity-operator")
+                .endMetadata()
+                .withNewRoleRef()
+                    .withApiGroup(Constants.RBAC_AUTH_API_GROUP)
+                    .withKind(ResourceKinds.CLUSTER_ROLE)
+                    .withName(Constants.STRIMZI_CO_NAME  + "-entity-operator")
+                .endRoleRef()
+                .withSubjects(new SubjectBuilder()
+                    .withKind(ResourceKinds.SERVICE_ACCOUNT)
+                    .withName(Constants.STRIMZI_CO_NAME)
+                    .withNamespace(this.deploymentNamespace)
+                    .build())
+                .build(),
+            new ClusterRoleBindingBuilder()
+                .withNewMetadata()
+                    .withName(Constants.STRIMZI_CO_NAME + "-watched")
+                .endMetadata()
+                .withNewRoleRef()
+                    .withApiGroup(Constants.RBAC_AUTH_API_GROUP)
+                    .withKind(ResourceKinds.CLUSTER_ROLE)
+                    .withName(Constants.STRIMZI_CO_NAME + "-watched")
+                .endRoleRef()
+                .withSubjects(new SubjectBuilder()
+                    .withKind(ResourceKinds.SERVICE_ACCOUNT)
+                    .withName(Constants.STRIMZI_CO_NAME)
+                    .withNamespace(this.deploymentNamespace)
+                    .build())
+                .build()
+        };
+    }
+
+    private OperatorGroup getStrimziOperatorGroup() {
+        return new OperatorGroupBuilder()
+            .editOrNewMetadata()
+                .withName(Constants.CONSOLE_OPERATOR_GROUP_NAME)
+                .withNamespace(this.deploymentNamespace)
+                .withLabels(Collections.singletonMap(Labels.APP, Constants.STRIMZI_NAME))
+            .endMetadata()
+            .build();
+    }
path: systemtests/src/main/java/com/github/streamshub/systemtests/setup/StrimziOperatorSetup.java
user: login: MikeEdgar
body: Is the `OperatorGroup` necessary when installing without OLM?
created_at: 2025-03-31T15:08:09Z
author_association: MEMBER
diff_hunk: @@ -6,37 +6,41 @@ private ResourceKinds() {}
     // ----------
     // K8s
     // ----------
-    public static final String CUSTOM_RESOURCE_DEFINITION = "customresourcedefinition";
-    public static final String CONFIG_MAP = "configmap";
-    public static final String DEPLOYMENT = "deployment";
-    public static final String DEPLOYMENT_CONFIG = "deploymentconfig";
-    public static final String POD = "pod";
-    public static final String SERVICE = "service";
-    public static final String SECRET = "secret";
-    public static final String CLUSTER_ROLE = "clusterrole";
-    public static final String CLUSTER_ROLE_BINDING = "clusterrolebinding";
-    public static final String ROLE_BINDING = "rolebinding";
-    public static final String SERVICE_ACCOUNT = "serviceaccount";
-    public static final String JOB = "job";
-    public static final String NAMESPACE = "namespace";
-    // ----------
-    // Openshift
-    // ----------
-    public static final String CATALOG_SOURCE = "catalogsource";
-    public static final String SUBSCRIPTION = "subscription";
-    public static final String INSTALL_PLAN = "installplan";
-    public static final String CLUSTER_SERVICE_VERSION = "clusterserviceversion";
-    public static final String OPERATOR_GROUP = "operatorgroup";
-    public static final String OPERATOR = "operator";
+    public static final String CUSTOM_RESOURCE_DEFINITION = "CustomResourceDefinition";
+    public static final String CONFIG_MAP = "ConfigMap";
+    public static final String DEPLOYMENT = "Deployment";
+    public static final String DEPLOYMENT_CONFIG = "DeploymentConfig";
+    public static final String POD = "Pod";
+    public static final String SERVICE = "Service";
+    public static final String SECRET = "Secret";
+    public static final String CLUSTER_ROLE = "ClusterRole";
+    public static final String CLUSTER_ROLE_BINDING = "ClusterRoleBinding";
+    public static final String ROLE_BINDING = "RoleBinding";
+    public static final String SERVICE_ACCOUNT = "ServiceAccount";
+    public static final String JOB = "Job";
+    public static final String NAMESPACE = "Namespace";
+
+    // ----------
+    // OpenShift
+    // ----------
+    public static final String CATALOG_SOURCE = "CatalogSource";
+    public static final String SUBSCRIPTION = "Subscription";
+    public static final String INSTALL_PLAN = "InstallPlan";
+    public static final String CLUSTER_SERVICE_VERSION = "ClusterServiceVersion";
+    public static final String OPERATOR_GROUP = "OperatorGroup";
+    public static final String OPERATOR = "Operator";
+
     // ----------
     // Kafka
     // ----------
-    public static final String KAFKA_TOPIC = "kafkatopic";
-    public static final String KAFKA = "kafka";
-    public static final String KAFKA_USER = "kafkauser";
-    public static final String KAFKA_NODE_POOL = "kafkanodepool";
+    public static final String KAFKA_TOPIC = "KafkaTopic";
+    public static final String KAFKA = "Kafka";
+    public static final String KAFKA_USER = "KafkaUser";
+    public static final String KAFKA_NODE_POOL = "KafkaNodePool";
path: systemtests/src/main/java/com/github/streamshub/systemtests/constants/ResourceKinds.java
user: login: im-konge
body: You can use the RESOURCE_KIND from each of the resource from the Strimzi's API module.
created_at: 2025-03-31T15:13:08Z
author_association: NONE
diff_hunk: @@ -6,37 +6,41 @@ private ResourceKinds() {}
     // ----------
     // K8s
     // ----------
-    public static final String CUSTOM_RESOURCE_DEFINITION = "customresourcedefinition";
-    public static final String CONFIG_MAP = "configmap";
-    public static final String DEPLOYMENT = "deployment";
-    public static final String DEPLOYMENT_CONFIG = "deploymentconfig";
-    public static final String POD = "pod";
-    public static final String SERVICE = "service";
-    public static final String SECRET = "secret";
-    public static final String CLUSTER_ROLE = "clusterrole";
-    public static final String CLUSTER_ROLE_BINDING = "clusterrolebinding";
-    public static final String ROLE_BINDING = "rolebinding";
-    public static final String SERVICE_ACCOUNT = "serviceaccount";
-    public static final String JOB = "job";
-    public static final String NAMESPACE = "namespace";
-    // ----------
-    // Openshift
-    // ----------
-    public static final String CATALOG_SOURCE = "catalogsource";
-    public static final String SUBSCRIPTION = "subscription";
-    public static final String INSTALL_PLAN = "installplan";
-    public static final String CLUSTER_SERVICE_VERSION = "clusterserviceversion";
-    public static final String OPERATOR_GROUP = "operatorgroup";
-    public static final String OPERATOR = "operator";
+    public static final String CUSTOM_RESOURCE_DEFINITION = "CustomResourceDefinition";
+    public static final String CONFIG_MAP = "ConfigMap";
+    public static final String DEPLOYMENT = "Deployment";
+    public static final String DEPLOYMENT_CONFIG = "DeploymentConfig";
+    public static final String POD = "Pod";
+    public static final String SERVICE = "Service";
+    public static final String SECRET = "Secret";
+    public static final String CLUSTER_ROLE = "ClusterRole";
+    public static final String CLUSTER_ROLE_BINDING = "ClusterRoleBinding";
+    public static final String ROLE_BINDING = "RoleBinding";
+    public static final String SERVICE_ACCOUNT = "ServiceAccount";
+    public static final String JOB = "Job";
+    public static final String NAMESPACE = "Namespace";
+
+    // ----------
+    // OpenShift
+    // ----------
+    public static final String CATALOG_SOURCE = "CatalogSource";
+    public static final String SUBSCRIPTION = "Subscription";
+    public static final String INSTALL_PLAN = "InstallPlan";
+    public static final String CLUSTER_SERVICE_VERSION = "ClusterServiceVersion";
+    public static final String OPERATOR_GROUP = "OperatorGroup";
+    public static final String OPERATOR = "Operator";
+
     // ----------
     // Kafka
     // ----------
-    public static final String KAFKA_TOPIC = "kafkatopic";
-    public static final String KAFKA = "kafka";
-    public static final String KAFKA_USER = "kafkauser";
-    public static final String KAFKA_NODE_POOL = "kafkanodepool";
+    public static final String KAFKA_TOPIC = "KafkaTopic";
+    public static final String KAFKA = "Kafka";
+    public static final String KAFKA_USER = "KafkaUser";
+    public static final String KAFKA_NODE_POOL = "KafkaNodePool";
+
     // ----------
     // Console
     // ----------
-    public static final String CONSOLE = "console";
+    public static final String CONSOLE = "Console";
path: systemtests/src/main/java/com/github/streamshub/systemtests/constants/ResourceKinds.java
user: login: im-konge
body: Do you have kind in the Console CR?
created_at: 2025-03-31T15:13:32Z
author_association: NONE
diff_hunk: @@ -0,0 +1,306 @@
+package com.github.streamshub.systemtests.setup;
+
+import com.github.streamshub.systemtests.Environment;
+import com.github.streamshub.systemtests.constants.Constants;
+import com.github.streamshub.systemtests.constants.Labels;
+import com.github.streamshub.systemtests.constants.ResourceKinds;
+import com.github.streamshub.systemtests.logs.LogWrapper;
+import com.github.streamshub.systemtests.utils.ResourceUtils;
+import com.github.streamshub.systemtests.utils.SetupUtils;
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
+import io.fabric8.kubernetes.api.model.ServiceAccount;
+import io.fabric8.kubernetes.api.model.ServiceAccountBuilder;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinitionBuilder;
+import io.fabric8.kubernetes.api.model.apps.Deployment;
+import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRole;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBuilder;
+import io.fabric8.kubernetes.api.model.rbac.RoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.RoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.SubjectBuilder;
+import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroup;
+import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroupBuilder;
+import io.skodjob.testframe.resources.KubeResourceManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class StrimziOperatorSetup {
+    private static final Logger LOGGER = LogWrapper.getLogger(StrimziOperatorSetup.class);
+    private static final KubeResourceManager RESOURCE_MANAGER = KubeResourceManager.get();
path: systemtests/src/main/java/com/github/streamshub/systemtests/setup/StrimziOperatorSetup.java
user: login: im-konge
body: out of curiosity, why do you have it as static here?
created_at: 2025-03-31T15:15:07Z
author_association: NONE
diff_hunk: @@ -0,0 +1,306 @@
+package com.github.streamshub.systemtests.setup;
+
+import com.github.streamshub.systemtests.Environment;
+import com.github.streamshub.systemtests.constants.Constants;
+import com.github.streamshub.systemtests.constants.Labels;
+import com.github.streamshub.systemtests.constants.ResourceKinds;
+import com.github.streamshub.systemtests.logs.LogWrapper;
+import com.github.streamshub.systemtests.utils.ResourceUtils;
+import com.github.streamshub.systemtests.utils.SetupUtils;
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
+import io.fabric8.kubernetes.api.model.ServiceAccount;
+import io.fabric8.kubernetes.api.model.ServiceAccountBuilder;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinitionBuilder;
+import io.fabric8.kubernetes.api.model.apps.Deployment;
+import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRole;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBuilder;
+import io.fabric8.kubernetes.api.model.rbac.RoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.RoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.SubjectBuilder;
+import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroup;
+import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroupBuilder;
+import io.skodjob.testframe.resources.KubeResourceManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class StrimziOperatorSetup {
+    private static final Logger LOGGER = LogWrapper.getLogger(StrimziOperatorSetup.class);
+    private static final KubeResourceManager RESOURCE_MANAGER = KubeResourceManager.get();
+
+    private final List<File> strimziResources = fetchStrimziYamlFiles();
+    private final String deploymentNamespace;
+    private final String deploymentName;
+
+    public StrimziOperatorSetup(String deploymentNamespace) {
+        this.deploymentNamespace = deploymentNamespace;
+        this.deploymentName = Environment.STRIMZI_OPERATOR_NAME;
+    }
+
+    public void setup() {
+        LOGGER.info("----------- Setup Strimzi Cluster Operator -----------");
+        // Watch all namespaces CRB
+        // https://strimzi.io/docs/operators/latest/deploying#deploying-cluster-operator-to-watch-whole-cluster-str
+        RESOURCE_MANAGER.createResourceWithWait(getStrimziWatchAllCrbs());
+
+        if (Environment.SKIP_STRIMZI_INSTALLATION || ResourceUtils.getKubeResource(Deployment.class, this.deploymentNamespace, this.deploymentName) != null) {
+            LOGGER.warn("Skipping Strimzi installation. It is already installed or env to skip installation was set to `true`!");
+            return;
+        }
+
+        LOGGER.info("Install Strimzi Cluster Operator in namespace: {}", this.deploymentNamespace);
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleCrds());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleClusterRoles());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleServiceAccount());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleRoleBindings());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleClusterRoleBindings());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleConfigMap());
+        RESOURCE_MANAGER.createResourceWithWait(getBundleDeployment());
+    }
+
+    public void teardown() {
+        LOGGER.info("----------- Teardown Strimzi Cluster Operator -----------");
+        if (Environment.SKIP_STRIMZI_INSTALLATION || ResourceUtils.getKubeResource(Deployment.class, this.deploymentNamespace, this.deploymentName) == null) {
+            LOGGER.warn("Skipping Strimzi deletion. It is already deleted or installation was skipped!");
+            return;
+        }
+
+        // Watch all namespaces CRB
+        RESOURCE_MANAGER.deleteResource(getStrimziOperatorGroup());
+        RESOURCE_MANAGER.deleteResource(getStrimziWatchAllCrbs());
+        RESOURCE_MANAGER.deleteResource(getBundleCrds());
+        RESOURCE_MANAGER.deleteResource(getBundleClusterRoles());
+        RESOURCE_MANAGER.deleteResource(getBundleServiceAccount());
+        RESOURCE_MANAGER.deleteResource(getBundleRoleBindings());
+        RESOURCE_MANAGER.deleteResource(getBundleClusterRoleBindings());
+        RESOURCE_MANAGER.deleteResource(getBundleConfigMap());
+        RESOURCE_MANAGER.deleteResource(getBundleDeployment());
+    }
+
+    private ClusterRoleBinding[] getStrimziWatchAllCrbs() {
+        return new ClusterRoleBinding[]{
+            new ClusterRoleBindingBuilder()
+                .withNewMetadata()
+                    .withName(Constants.STRIMZI_CO_NAME + "-namespaced")
+                .endMetadata()
+                .withNewRoleRef()
+                    .withApiGroup(Constants.RBAC_AUTH_API_GROUP)
+                    .withKind(ResourceKinds.CLUSTER_ROLE)
+                    .withName(Constants.STRIMZI_CO_NAME + "-namespaced")
+                .endRoleRef()
+                .withSubjects(new SubjectBuilder()
+                    .withKind(ResourceKinds.SERVICE_ACCOUNT)
+                    .withName(Constants.STRIMZI_CO_NAME)
+                    .withNamespace(this.deploymentNamespace)
+                    .build())
+                .build(),
+            new ClusterRoleBindingBuilder()
+                .withNewMetadata()
+                    .withName(Constants.STRIMZI_CO_NAME  + "-entity-operator")
+                .endMetadata()
+                .withNewRoleRef()
+                    .withApiGroup(Constants.RBAC_AUTH_API_GROUP)
+                    .withKind(ResourceKinds.CLUSTER_ROLE)
+                    .withName(Constants.STRIMZI_CO_NAME  + "-entity-operator")
+                .endRoleRef()
+                .withSubjects(new SubjectBuilder()
+                    .withKind(ResourceKinds.SERVICE_ACCOUNT)
+                    .withName(Constants.STRIMZI_CO_NAME)
+                    .withNamespace(this.deploymentNamespace)
+                    .build())
+                .build(),
+            new ClusterRoleBindingBuilder()
+                .withNewMetadata()
+                    .withName(Constants.STRIMZI_CO_NAME + "-watched")
+                .endMetadata()
+                .withNewRoleRef()
+                    .withApiGroup(Constants.RBAC_AUTH_API_GROUP)
+                    .withKind(ResourceKinds.CLUSTER_ROLE)
+                    .withName(Constants.STRIMZI_CO_NAME + "-watched")
+                .endRoleRef()
+                .withSubjects(new SubjectBuilder()
+                    .withKind(ResourceKinds.SERVICE_ACCOUNT)
+                    .withName(Constants.STRIMZI_CO_NAME)
+                    .withNamespace(this.deploymentNamespace)
+                    .build())
+                .build()
+        };
+    }
+
+    private OperatorGroup getStrimziOperatorGroup() {
+        return new OperatorGroupBuilder()
+            .editOrNewMetadata()
+                .withName(Constants.CONSOLE_OPERATOR_GROUP_NAME)
+                .withNamespace(this.deploymentNamespace)
+                .withLabels(Collections.singletonMap(Labels.APP, Constants.STRIMZI_NAME))
+            .endMetadata()
+            .build();
+    }
+
+    private ConfigMap getBundleConfigMap() {
+        return new ConfigMapBuilder(SetupUtils.configFromYaml(strimziResources.stream()
+            .filter(file -> file.getName().matches(".*050-ConfigMap-.*\\.yaml")).toList().get(0), ConfigMap.class))
+            .editMetadata()
+                .withNamespace(this.deploymentNamespace)
+                .withName(this.deploymentName)
+            .endMetadata()
+            .build();
+    }
+
+    private ServiceAccount getBundleServiceAccount() {
+        return new ServiceAccountBuilder(SetupUtils.configFromYaml(strimziResources.stream()
+            .filter(file -> file.getName().matches(".*010-ServiceAccount-.*\\.yaml")).toList().get(0), ServiceAccount.class))
+            .editMetadata()
+                .withNamespace(this.deploymentNamespace)
+            .endMetadata()
+            .build();
+    }
+
+    private Deployment getBundleDeployment() {
+        return new DeploymentBuilder(SetupUtils.configFromYaml(strimziResources.stream()
+            .filter(file -> file.getName().matches(".*060-Deployment-.*\\.yaml")).toList().get(0), Deployment.class))
+            .editMetadata()
+                .withNamespace(this.deploymentNamespace)
+                .withName(this.deploymentName)
+            .endMetadata()
+            .editSpec()
+                .editTemplate()
+                    .editSpec()
+                        .editFirstContainer()
+                            .removeMatchingFromEnv(e -> e.getName().equals(Constants.STRIMZI_NAMESPACE_KEY))
+                            .addNewEnv()
+                                .withName(Constants.STRIMZI_NAMESPACE_KEY)
+                                .withValue(Constants.STRIMZI_WATCH_ALL_NAMESPACES)
+                            .endEnv()
+                        .endContainer()
+                    .endSpec()
+                .endTemplate()
+            .endSpec()
+            .build();
+    }
+
+    private CustomResourceDefinition[] getBundleCrds() {
+        return strimziResources.stream().filter(file -> file.getName().matches(".*-Crd-.*\\.yaml"))
+            .map(crd -> new CustomResourceDefinitionBuilder(SetupUtils.configFromYaml(crd, CustomResourceDefinition.class))
+                .editMetadata()
+                    .withNamespace(this.deploymentNamespace)
+                .endMetadata()
+                .build())
+            .toArray(CustomResourceDefinition[]::new);
+    }
+
+    private ClusterRole[] getBundleClusterRoles() {
+        return strimziResources.stream().filter(file -> file.getName().matches(".*-ClusterRole-.*\\.yaml"))
+            .map(file -> new ClusterRoleBuilder(SetupUtils.configFromYaml(file, ClusterRole.class))
+                .editMetadata()
+                    .withNamespace(this.deploymentNamespace)
+                .endMetadata()
+                .build())
+            .toArray(ClusterRole[]::new);
+    }
+
+    private RoleBinding[] getBundleRoleBindings() {
+        return strimziResources.stream().filter(file -> file.getName().matches(".*-RoleBinding-.*\\.yaml"))
+            .map(rb -> new RoleBindingBuilder(SetupUtils.configFromYaml(rb, RoleBinding.class))
+                .editMetadata()
+                    .withNamespace(this.deploymentNamespace)
+                .endMetadata()
+                .editFirstSubject()
+                    .withNamespace(this.deploymentNamespace)
+                .endSubject()
+                .build())
+            .toArray(RoleBinding[]::new);
+    }
+
+    private ClusterRoleBinding[] getBundleClusterRoleBindings() {
+        return strimziResources.stream().filter(file -> file.getName().matches(".*-ClusterRoleBinding-.*\\.yaml"))
+            .map(crb -> new ClusterRoleBindingBuilder(SetupUtils.configFromYaml(crb, ClusterRoleBinding.class))
+                .editMetadata()
+                    .withNamespace(this.deploymentNamespace)
+                .endMetadata()
+                .editFirstSubject()
+                    .withNamespace(this.deploymentNamespace)
+                .endSubject()
+                .build())
+            .toArray(ClusterRoleBinding[]::new);
+    }
+
+    private List<File> fetchStrimziYamlFiles() {
+        List<File> yamlFiles = new ArrayList<>();
+        for (String fileUrl : extractYamlFileLinksFromGithubDir()) {
+            String fileName = fileUrl.substring(fileUrl.lastIndexOf('/') + 1).replace(".yaml", "");
+            LOGGER.debug("Fetching Strimzi YAML file: {}", fileName);
+            Path tempFile = null;
+            try {
+                tempFile = Files.createTempFile(fileName + "-tmp_", ".yaml");
+                Files.write(tempFile, SetupUtils.getYamlFileContent(fileUrl).getBytes());
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+            yamlFiles.add(tempFile.toFile());
+        }
+        return yamlFiles;
+    }
+
+    private List<String> extractYamlFileLinksFromGithubDir() {
path: systemtests/src/main/java/com/github/streamshub/systemtests/setup/StrimziOperatorSetup.java
user: login: im-konge
body: Maybe it's something common that you can use for other operators/components/files as well? IDK if you have something common. There are some things in test-frame as well -> e.g. `TestFrameUtils#getFileFromResourceAsStream` etc.
Maybe it will be useful for you as well?
created_at: 2025-03-31T15:20:58Z
author_association: NONE
diff_hunk: @@ -72,12 +81,28 @@ public abstract class AbstractST {
     }
 
     @BeforeAll
-    void beforeAll() {
-        LOGGER.info("=========== AbstractST - BeforeAll ===========");
+    void setupTestSuite() {
+        LOGGER.info("=========== AbstractST - BeforeAll - Setup TestSuite ===========");
path: systemtests/src/test/java/com/github/streamshub/systemtests/system/AbstractST.java
user: login: im-konge
body: Maybe `TestVisualSeparatorExtension` can be used from test-frame? Depends if you want it that way. Just wanted to mention it, so you are aware of it.
created_at: 2025-03-31T15:23:10Z
author_association: NONE
diff_hunk: @@ -0,0 +1,306 @@
+package com.github.streamshub.systemtests.setup;
+
+import com.github.streamshub.systemtests.Environment;
+import com.github.streamshub.systemtests.constants.Constants;
+import com.github.streamshub.systemtests.constants.Labels;
+import com.github.streamshub.systemtests.constants.ResourceKinds;
+import com.github.streamshub.systemtests.logs.LogWrapper;
+import com.github.streamshub.systemtests.utils.ResourceUtils;
+import com.github.streamshub.systemtests.utils.SetupUtils;
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
+import io.fabric8.kubernetes.api.model.ServiceAccount;
+import io.fabric8.kubernetes.api.model.ServiceAccountBuilder;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinitionBuilder;
+import io.fabric8.kubernetes.api.model.apps.Deployment;
+import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRole;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBuilder;
+import io.fabric8.kubernetes.api.model.rbac.RoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.RoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.SubjectBuilder;
+import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroup;
+import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroupBuilder;
+import io.skodjob.testframe.resources.KubeResourceManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class StrimziOperatorSetup {
+    private static final Logger LOGGER = LogWrapper.getLogger(StrimziOperatorSetup.class);
+    private static final KubeResourceManager RESOURCE_MANAGER = KubeResourceManager.get();
+
+    private final List<File> strimziResources = fetchStrimziYamlFiles();
+    private final String deploymentNamespace;
+    private final String deploymentName;
+
+    public StrimziOperatorSetup(String deploymentNamespace) {
+        this.deploymentNamespace = deploymentNamespace;
+        this.deploymentName = Environment.STRIMZI_OPERATOR_NAME;
+    }
+
+    public void setup() {
+        LOGGER.info("----------- Setup Strimzi Cluster Operator -----------");
+        // Watch all namespaces CRB
+        // https://strimzi.io/docs/operators/latest/deploying#deploying-cluster-operator-to-watch-whole-cluster-str
+        RESOURCE_MANAGER.createResourceWithWait(getStrimziWatchAllCrbs());
+
+        if (Environment.SKIP_STRIMZI_INSTALLATION || ResourceUtils.getKubeResource(Deployment.class, this.deploymentNamespace, this.deploymentName) != null) {
+            LOGGER.warn("Skipping Strimzi installation. It is already installed or env to skip installation was set to `true`!");
+            return;
+        }
+
+        LOGGER.info("Install Strimzi Cluster Operator in namespace: {}", this.deploymentNamespace);
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleCrds());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleClusterRoles());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleServiceAccount());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleRoleBindings());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleClusterRoleBindings());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleConfigMap());
+        RESOURCE_MANAGER.createResourceWithWait(getBundleDeployment());
+    }
+
+    public void teardown() {
+        LOGGER.info("----------- Teardown Strimzi Cluster Operator -----------");
+        if (Environment.SKIP_STRIMZI_INSTALLATION || ResourceUtils.getKubeResource(Deployment.class, this.deploymentNamespace, this.deploymentName) == null) {
+            LOGGER.warn("Skipping Strimzi deletion. It is already deleted or installation was skipped!");
+            return;
+        }
+
+        // Watch all namespaces CRB
+        RESOURCE_MANAGER.deleteResource(getStrimziOperatorGroup());
+        RESOURCE_MANAGER.deleteResource(getStrimziWatchAllCrbs());
+        RESOURCE_MANAGER.deleteResource(getBundleCrds());
+        RESOURCE_MANAGER.deleteResource(getBundleClusterRoles());
+        RESOURCE_MANAGER.deleteResource(getBundleServiceAccount());
+        RESOURCE_MANAGER.deleteResource(getBundleRoleBindings());
+        RESOURCE_MANAGER.deleteResource(getBundleClusterRoleBindings());
+        RESOURCE_MANAGER.deleteResource(getBundleConfigMap());
+        RESOURCE_MANAGER.deleteResource(getBundleDeployment());
+    }
+
+    private ClusterRoleBinding[] getStrimziWatchAllCrbs() {
path: systemtests/src/main/java/com/github/streamshub/systemtests/setup/StrimziOperatorSetup.java
user: login: MikeEdgar
body: Some of these bindings are in the Strimzi resources aren't they? Maybe there are differences that I'm not spotting though.
created_at: 2025-03-31T15:25:24Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,84 @@
+package com.github.streamshub.systemtests.utils;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import com.github.streamshub.systemtests.Environment;
+import com.github.streamshub.systemtests.logs.LogWrapper;
+import io.fabric8.kubernetes.api.model.Secret;
+import io.fabric8.kubernetes.api.model.SecretBuilder;
+import io.skodjob.testframe.resources.KubeResourceManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+
+public class SetupUtils {
+    private static final Logger LOGGER = LogWrapper.getLogger(SetupUtils.class);
+    private SetupUtils() {}
+
+    // ---------------
+    // Yaml config
+    // --------------
+    public static String getYamlFileContent(String fileUrl) {
+        LOGGER.debug("Loading YAML file content from url {}", fileUrl);
+        StringBuilder content;
+        try (BufferedReader in = new BufferedReader(new InputStreamReader(new URL(fileUrl).openStream(), StandardCharsets.UTF_8))) {
+            content = new StringBuilder();
+            String inputLine;
+
+            while ((inputLine = in.readLine()) != null) {
+                content.append(inputLine).append("\n");
+            }
+        } catch (IOException e) {
+            throw new RuntimeException("Cannot download YAML content from url: " + fileUrl, e);
+        }
+        return content.toString();
+    }
+
+    public static <T> T configFromYaml(File yamlFile, Class<T> c) {
+        ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
+        try {
+            return mapper.readValue(yamlFile, c);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    // --------------
+    // Namespace
+    // --------------
+    public static void copyImagePullSecrets(String targetNamespace) {
path: systemtests/src/main/java/com/github/streamshub/systemtests/utils/SetupUtils.java
user: login: MikeEdgar
body: Will there be any private images included in the testing?
created_at: 2025-03-31T15:27:17Z
author_association: MEMBER
diff_hunk: @@ -6,37 +6,41 @@ private ResourceKinds() {}
     // ----------
     // K8s
     // ----------
-    public static final String CUSTOM_RESOURCE_DEFINITION = "customresourcedefinition";
-    public static final String CONFIG_MAP = "configmap";
-    public static final String DEPLOYMENT = "deployment";
-    public static final String DEPLOYMENT_CONFIG = "deploymentconfig";
-    public static final String POD = "pod";
-    public static final String SERVICE = "service";
-    public static final String SECRET = "secret";
-    public static final String CLUSTER_ROLE = "clusterrole";
-    public static final String CLUSTER_ROLE_BINDING = "clusterrolebinding";
-    public static final String ROLE_BINDING = "rolebinding";
-    public static final String SERVICE_ACCOUNT = "serviceaccount";
-    public static final String JOB = "job";
-    public static final String NAMESPACE = "namespace";
-    // ----------
-    // Openshift
-    // ----------
-    public static final String CATALOG_SOURCE = "catalogsource";
-    public static final String SUBSCRIPTION = "subscription";
-    public static final String INSTALL_PLAN = "installplan";
-    public static final String CLUSTER_SERVICE_VERSION = "clusterserviceversion";
-    public static final String OPERATOR_GROUP = "operatorgroup";
-    public static final String OPERATOR = "operator";
+    public static final String CUSTOM_RESOURCE_DEFINITION = "CustomResourceDefinition";
+    public static final String CONFIG_MAP = "ConfigMap";
+    public static final String DEPLOYMENT = "Deployment";
+    public static final String DEPLOYMENT_CONFIG = "DeploymentConfig";
path: systemtests/src/main/java/com/github/streamshub/systemtests/constants/ResourceKinds.java
user: login: MikeEdgar
body: The `DeploymentConfig` might never be used.
created_at: 2025-03-31T15:29:26Z
author_association: MEMBER
diff_hunk: @@ -23,15 +23,29 @@
         <playwright.version>1.47.0</playwright.version>
         <!-- Mocking environment -->
         <mockito.version>5.15.2</mockito.version>
-        <junit-pioneer.version>2.3.0</junit-pioneer.version>
+        <powermock.version>2.0.9</powermock.version>
         <!-- Used for test-frame -->
-        <test-frame.version>0.8.0</test-frame.version>
+        <test-frame.version>0.11.0-SNAPSHOT</test-frame.version>
path: systemtests/pom.xml
user: login: im-konge
body: I guess we will release it soon - this week or next week.
We are doing just some extra testing before releasing it (as we added more things there).
created_at: 2025-03-31T15:32:01Z
author_association: NONE
diff_hunk: @@ -0,0 +1,306 @@
+package com.github.streamshub.systemtests.setup;
+
+import com.github.streamshub.systemtests.Environment;
+import com.github.streamshub.systemtests.constants.Constants;
+import com.github.streamshub.systemtests.constants.Labels;
+import com.github.streamshub.systemtests.constants.ResourceKinds;
+import com.github.streamshub.systemtests.logs.LogWrapper;
+import com.github.streamshub.systemtests.utils.ResourceUtils;
+import com.github.streamshub.systemtests.utils.SetupUtils;
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
+import io.fabric8.kubernetes.api.model.ServiceAccount;
+import io.fabric8.kubernetes.api.model.ServiceAccountBuilder;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinitionBuilder;
+import io.fabric8.kubernetes.api.model.apps.Deployment;
+import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRole;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBuilder;
+import io.fabric8.kubernetes.api.model.rbac.RoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.RoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.SubjectBuilder;
+import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroup;
+import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroupBuilder;
+import io.skodjob.testframe.resources.KubeResourceManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class StrimziOperatorSetup {
+    private static final Logger LOGGER = LogWrapper.getLogger(StrimziOperatorSetup.class);
+    private static final KubeResourceManager RESOURCE_MANAGER = KubeResourceManager.get();
path: systemtests/src/main/java/com/github/streamshub/systemtests/setup/StrimziOperatorSetup.java
user: login: jankalinic
body: For a more simple call usage for the whole class.
created_at: 2025-03-31T15:39:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,306 @@
+package com.github.streamshub.systemtests.setup;
+
+import com.github.streamshub.systemtests.Environment;
+import com.github.streamshub.systemtests.constants.Constants;
+import com.github.streamshub.systemtests.constants.Labels;
+import com.github.streamshub.systemtests.constants.ResourceKinds;
+import com.github.streamshub.systemtests.logs.LogWrapper;
+import com.github.streamshub.systemtests.utils.ResourceUtils;
+import com.github.streamshub.systemtests.utils.SetupUtils;
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
+import io.fabric8.kubernetes.api.model.ServiceAccount;
+import io.fabric8.kubernetes.api.model.ServiceAccountBuilder;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinitionBuilder;
+import io.fabric8.kubernetes.api.model.apps.Deployment;
+import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRole;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBuilder;
+import io.fabric8.kubernetes.api.model.rbac.RoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.RoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.SubjectBuilder;
+import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroup;
+import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroupBuilder;
+import io.skodjob.testframe.resources.KubeResourceManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class StrimziOperatorSetup {
+    private static final Logger LOGGER = LogWrapper.getLogger(StrimziOperatorSetup.class);
+    private static final KubeResourceManager RESOURCE_MANAGER = KubeResourceManager.get();
path: systemtests/src/main/java/com/github/streamshub/systemtests/setup/StrimziOperatorSetup.java
user: login: im-konge
body: It's up to you, but I guess that one get will not make it more readable or something. But yeah, up to you.
created_at: 2025-03-31T15:44:53Z
author_association: NONE
diff_hunk: @@ -6,37 +6,41 @@ private ResourceKinds() {}
     // ----------
     // K8s
     // ----------
-    public static final String CUSTOM_RESOURCE_DEFINITION = "customresourcedefinition";
-    public static final String CONFIG_MAP = "configmap";
-    public static final String DEPLOYMENT = "deployment";
-    public static final String DEPLOYMENT_CONFIG = "deploymentconfig";
-    public static final String POD = "pod";
-    public static final String SERVICE = "service";
-    public static final String SECRET = "secret";
-    public static final String CLUSTER_ROLE = "clusterrole";
-    public static final String CLUSTER_ROLE_BINDING = "clusterrolebinding";
-    public static final String ROLE_BINDING = "rolebinding";
-    public static final String SERVICE_ACCOUNT = "serviceaccount";
-    public static final String JOB = "job";
-    public static final String NAMESPACE = "namespace";
-    // ----------
-    // Openshift
-    // ----------
-    public static final String CATALOG_SOURCE = "catalogsource";
-    public static final String SUBSCRIPTION = "subscription";
-    public static final String INSTALL_PLAN = "installplan";
-    public static final String CLUSTER_SERVICE_VERSION = "clusterserviceversion";
-    public static final String OPERATOR_GROUP = "operatorgroup";
-    public static final String OPERATOR = "operator";
+    public static final String CUSTOM_RESOURCE_DEFINITION = "CustomResourceDefinition";
+    public static final String CONFIG_MAP = "ConfigMap";
+    public static final String DEPLOYMENT = "Deployment";
+    public static final String DEPLOYMENT_CONFIG = "DeploymentConfig";
+    public static final String POD = "Pod";
+    public static final String SERVICE = "Service";
+    public static final String SECRET = "Secret";
+    public static final String CLUSTER_ROLE = "ClusterRole";
+    public static final String CLUSTER_ROLE_BINDING = "ClusterRoleBinding";
+    public static final String ROLE_BINDING = "RoleBinding";
+    public static final String SERVICE_ACCOUNT = "ServiceAccount";
+    public static final String JOB = "Job";
+    public static final String NAMESPACE = "Namespace";
+
+    // ----------
+    // OpenShift
+    // ----------
+    public static final String CATALOG_SOURCE = "CatalogSource";
+    public static final String SUBSCRIPTION = "Subscription";
+    public static final String INSTALL_PLAN = "InstallPlan";
+    public static final String CLUSTER_SERVICE_VERSION = "ClusterServiceVersion";
+    public static final String OPERATOR_GROUP = "OperatorGroup";
+    public static final String OPERATOR = "Operator";
+
     // ----------
     // Kafka
     // ----------
-    public static final String KAFKA_TOPIC = "kafkatopic";
-    public static final String KAFKA = "kafka";
-    public static final String KAFKA_USER = "kafkauser";
-    public static final String KAFKA_NODE_POOL = "kafkanodepool";
+    public static final String KAFKA_TOPIC = "KafkaTopic";
+    public static final String KAFKA = "Kafka";
+    public static final String KAFKA_USER = "KafkaUser";
+    public static final String KAFKA_NODE_POOL = "KafkaNodePool";
+
     // ----------
     // Console
     // ----------
-    public static final String CONSOLE = "console";
+    public static final String CONSOLE = "Console";
path: systemtests/src/main/java/com/github/streamshub/systemtests/constants/ResourceKinds.java
user: login: jankalinic
body: Not that i am aware in ConsoleResource, no.
created_at: 2025-03-31T15:47:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -6,37 +6,41 @@ private ResourceKinds() {}
     // ----------
     // K8s
     // ----------
-    public static final String CUSTOM_RESOURCE_DEFINITION = "customresourcedefinition";
-    public static final String CONFIG_MAP = "configmap";
-    public static final String DEPLOYMENT = "deployment";
-    public static final String DEPLOYMENT_CONFIG = "deploymentconfig";
-    public static final String POD = "pod";
-    public static final String SERVICE = "service";
-    public static final String SECRET = "secret";
-    public static final String CLUSTER_ROLE = "clusterrole";
-    public static final String CLUSTER_ROLE_BINDING = "clusterrolebinding";
-    public static final String ROLE_BINDING = "rolebinding";
-    public static final String SERVICE_ACCOUNT = "serviceaccount";
-    public static final String JOB = "job";
-    public static final String NAMESPACE = "namespace";
-    // ----------
-    // Openshift
-    // ----------
-    public static final String CATALOG_SOURCE = "catalogsource";
-    public static final String SUBSCRIPTION = "subscription";
-    public static final String INSTALL_PLAN = "installplan";
-    public static final String CLUSTER_SERVICE_VERSION = "clusterserviceversion";
-    public static final String OPERATOR_GROUP = "operatorgroup";
-    public static final String OPERATOR = "operator";
+    public static final String CUSTOM_RESOURCE_DEFINITION = "CustomResourceDefinition";
+    public static final String CONFIG_MAP = "ConfigMap";
+    public static final String DEPLOYMENT = "Deployment";
+    public static final String DEPLOYMENT_CONFIG = "DeploymentConfig";
+    public static final String POD = "Pod";
+    public static final String SERVICE = "Service";
+    public static final String SECRET = "Secret";
+    public static final String CLUSTER_ROLE = "ClusterRole";
+    public static final String CLUSTER_ROLE_BINDING = "ClusterRoleBinding";
+    public static final String ROLE_BINDING = "RoleBinding";
+    public static final String SERVICE_ACCOUNT = "ServiceAccount";
+    public static final String JOB = "Job";
+    public static final String NAMESPACE = "Namespace";
+
+    // ----------
+    // OpenShift
+    // ----------
+    public static final String CATALOG_SOURCE = "CatalogSource";
+    public static final String SUBSCRIPTION = "Subscription";
+    public static final String INSTALL_PLAN = "InstallPlan";
+    public static final String CLUSTER_SERVICE_VERSION = "ClusterServiceVersion";
+    public static final String OPERATOR_GROUP = "OperatorGroup";
+    public static final String OPERATOR = "Operator";
+
     // ----------
     // Kafka
     // ----------
-    public static final String KAFKA_TOPIC = "kafkatopic";
-    public static final String KAFKA = "kafka";
-    public static final String KAFKA_USER = "kafkauser";
-    public static final String KAFKA_NODE_POOL = "kafkanodepool";
+    public static final String KAFKA_TOPIC = "KafkaTopic";
+    public static final String KAFKA = "Kafka";
+    public static final String KAFKA_USER = "KafkaUser";
+    public static final String KAFKA_NODE_POOL = "KafkaNodePool";
path: systemtests/src/main/java/com/github/streamshub/systemtests/constants/ResourceKinds.java
user: login: jankalinic
body: Nice, i'll use those from API
created_at: 2025-03-31T15:47:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,306 @@
+package com.github.streamshub.systemtests.setup;
+
+import com.github.streamshub.systemtests.Environment;
+import com.github.streamshub.systemtests.constants.Constants;
+import com.github.streamshub.systemtests.constants.Labels;
+import com.github.streamshub.systemtests.constants.ResourceKinds;
+import com.github.streamshub.systemtests.logs.LogWrapper;
+import com.github.streamshub.systemtests.utils.ResourceUtils;
+import com.github.streamshub.systemtests.utils.SetupUtils;
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
+import io.fabric8.kubernetes.api.model.ServiceAccount;
+import io.fabric8.kubernetes.api.model.ServiceAccountBuilder;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinitionBuilder;
+import io.fabric8.kubernetes.api.model.apps.Deployment;
+import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRole;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBuilder;
+import io.fabric8.kubernetes.api.model.rbac.RoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.RoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.SubjectBuilder;
+import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroup;
+import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroupBuilder;
+import io.skodjob.testframe.resources.KubeResourceManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class StrimziOperatorSetup {
+    private static final Logger LOGGER = LogWrapper.getLogger(StrimziOperatorSetup.class);
+    private static final KubeResourceManager RESOURCE_MANAGER = KubeResourceManager.get();
path: systemtests/src/main/java/com/github/streamshub/systemtests/setup/StrimziOperatorSetup.java
user: login: jankalinic
body: I mean this .get usage does not bother me, can use the singelton get instead, it just feels more right to me this way if that makes sense.
created_at: 2025-03-31T15:49:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,306 @@
+package com.github.streamshub.systemtests.setup;
+
+import com.github.streamshub.systemtests.Environment;
+import com.github.streamshub.systemtests.constants.Constants;
+import com.github.streamshub.systemtests.constants.Labels;
+import com.github.streamshub.systemtests.constants.ResourceKinds;
+import com.github.streamshub.systemtests.logs.LogWrapper;
+import com.github.streamshub.systemtests.utils.ResourceUtils;
+import com.github.streamshub.systemtests.utils.SetupUtils;
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
+import io.fabric8.kubernetes.api.model.ServiceAccount;
+import io.fabric8.kubernetes.api.model.ServiceAccountBuilder;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinitionBuilder;
+import io.fabric8.kubernetes.api.model.apps.Deployment;
+import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRole;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBuilder;
+import io.fabric8.kubernetes.api.model.rbac.RoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.RoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.SubjectBuilder;
+import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroup;
+import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroupBuilder;
+import io.skodjob.testframe.resources.KubeResourceManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class StrimziOperatorSetup {
+    private static final Logger LOGGER = LogWrapper.getLogger(StrimziOperatorSetup.class);
+    private static final KubeResourceManager RESOURCE_MANAGER = KubeResourceManager.get();
+
+    private final List<File> strimziResources = fetchStrimziYamlFiles();
+    private final String deploymentNamespace;
+    private final String deploymentName;
+
+    public StrimziOperatorSetup(String deploymentNamespace) {
+        this.deploymentNamespace = deploymentNamespace;
+        this.deploymentName = Environment.STRIMZI_OPERATOR_NAME;
+    }
+
+    public void setup() {
+        LOGGER.info("----------- Setup Strimzi Cluster Operator -----------");
+        // Watch all namespaces CRB
+        // https://strimzi.io/docs/operators/latest/deploying#deploying-cluster-operator-to-watch-whole-cluster-str
+        RESOURCE_MANAGER.createResourceWithWait(getStrimziWatchAllCrbs());
+
+        if (Environment.SKIP_STRIMZI_INSTALLATION || ResourceUtils.getKubeResource(Deployment.class, this.deploymentNamespace, this.deploymentName) != null) {
+            LOGGER.warn("Skipping Strimzi installation. It is already installed or env to skip installation was set to `true`!");
+            return;
+        }
+
+        LOGGER.info("Install Strimzi Cluster Operator in namespace: {}", this.deploymentNamespace);
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleCrds());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleClusterRoles());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleServiceAccount());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleRoleBindings());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleClusterRoleBindings());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleConfigMap());
+        RESOURCE_MANAGER.createResourceWithWait(getBundleDeployment());
+    }
+
+    public void teardown() {
+        LOGGER.info("----------- Teardown Strimzi Cluster Operator -----------");
+        if (Environment.SKIP_STRIMZI_INSTALLATION || ResourceUtils.getKubeResource(Deployment.class, this.deploymentNamespace, this.deploymentName) == null) {
+            LOGGER.warn("Skipping Strimzi deletion. It is already deleted or installation was skipped!");
+            return;
+        }
+
+        // Watch all namespaces CRB
+        RESOURCE_MANAGER.deleteResource(getStrimziOperatorGroup());
+        RESOURCE_MANAGER.deleteResource(getStrimziWatchAllCrbs());
+        RESOURCE_MANAGER.deleteResource(getBundleCrds());
+        RESOURCE_MANAGER.deleteResource(getBundleClusterRoles());
+        RESOURCE_MANAGER.deleteResource(getBundleServiceAccount());
+        RESOURCE_MANAGER.deleteResource(getBundleRoleBindings());
+        RESOURCE_MANAGER.deleteResource(getBundleClusterRoleBindings());
+        RESOURCE_MANAGER.deleteResource(getBundleConfigMap());
+        RESOURCE_MANAGER.deleteResource(getBundleDeployment());
+    }
+
+    private ClusterRoleBinding[] getStrimziWatchAllCrbs() {
+        return new ClusterRoleBinding[]{
+            new ClusterRoleBindingBuilder()
+                .withNewMetadata()
+                    .withName(Constants.STRIMZI_CO_NAME + "-namespaced")
+                .endMetadata()
+                .withNewRoleRef()
+                    .withApiGroup(Constants.RBAC_AUTH_API_GROUP)
+                    .withKind(ResourceKinds.CLUSTER_ROLE)
+                    .withName(Constants.STRIMZI_CO_NAME + "-namespaced")
+                .endRoleRef()
+                .withSubjects(new SubjectBuilder()
+                    .withKind(ResourceKinds.SERVICE_ACCOUNT)
+                    .withName(Constants.STRIMZI_CO_NAME)
+                    .withNamespace(this.deploymentNamespace)
+                    .build())
+                .build(),
+            new ClusterRoleBindingBuilder()
+                .withNewMetadata()
+                    .withName(Constants.STRIMZI_CO_NAME  + "-entity-operator")
+                .endMetadata()
+                .withNewRoleRef()
+                    .withApiGroup(Constants.RBAC_AUTH_API_GROUP)
+                    .withKind(ResourceKinds.CLUSTER_ROLE)
+                    .withName(Constants.STRIMZI_CO_NAME  + "-entity-operator")
+                .endRoleRef()
+                .withSubjects(new SubjectBuilder()
+                    .withKind(ResourceKinds.SERVICE_ACCOUNT)
+                    .withName(Constants.STRIMZI_CO_NAME)
+                    .withNamespace(this.deploymentNamespace)
+                    .build())
+                .build(),
+            new ClusterRoleBindingBuilder()
+                .withNewMetadata()
+                    .withName(Constants.STRIMZI_CO_NAME + "-watched")
+                .endMetadata()
+                .withNewRoleRef()
+                    .withApiGroup(Constants.RBAC_AUTH_API_GROUP)
+                    .withKind(ResourceKinds.CLUSTER_ROLE)
+                    .withName(Constants.STRIMZI_CO_NAME + "-watched")
+                .endRoleRef()
+                .withSubjects(new SubjectBuilder()
+                    .withKind(ResourceKinds.SERVICE_ACCOUNT)
+                    .withName(Constants.STRIMZI_CO_NAME)
+                    .withNamespace(this.deploymentNamespace)
+                    .build())
+                .build()
+        };
+    }
+
+    private OperatorGroup getStrimziOperatorGroup() {
+        return new OperatorGroupBuilder()
+            .editOrNewMetadata()
+                .withName(Constants.CONSOLE_OPERATOR_GROUP_NAME)
+                .withNamespace(this.deploymentNamespace)
+                .withLabels(Collections.singletonMap(Labels.APP, Constants.STRIMZI_NAME))
+            .endMetadata()
+            .build();
+    }
+
+    private ConfigMap getBundleConfigMap() {
+        return new ConfigMapBuilder(SetupUtils.configFromYaml(strimziResources.stream()
+            .filter(file -> file.getName().matches(".*050-ConfigMap-.*\\.yaml")).toList().get(0), ConfigMap.class))
+            .editMetadata()
+                .withNamespace(this.deploymentNamespace)
+                .withName(this.deploymentName)
+            .endMetadata()
+            .build();
+    }
+
+    private ServiceAccount getBundleServiceAccount() {
+        return new ServiceAccountBuilder(SetupUtils.configFromYaml(strimziResources.stream()
+            .filter(file -> file.getName().matches(".*010-ServiceAccount-.*\\.yaml")).toList().get(0), ServiceAccount.class))
+            .editMetadata()
+                .withNamespace(this.deploymentNamespace)
+            .endMetadata()
+            .build();
+    }
+
+    private Deployment getBundleDeployment() {
+        return new DeploymentBuilder(SetupUtils.configFromYaml(strimziResources.stream()
+            .filter(file -> file.getName().matches(".*060-Deployment-.*\\.yaml")).toList().get(0), Deployment.class))
+            .editMetadata()
+                .withNamespace(this.deploymentNamespace)
+                .withName(this.deploymentName)
+            .endMetadata()
+            .editSpec()
+                .editTemplate()
+                    .editSpec()
+                        .editFirstContainer()
+                            .removeMatchingFromEnv(e -> e.getName().equals(Constants.STRIMZI_NAMESPACE_KEY))
+                            .addNewEnv()
+                                .withName(Constants.STRIMZI_NAMESPACE_KEY)
+                                .withValue(Constants.STRIMZI_WATCH_ALL_NAMESPACES)
+                            .endEnv()
+                        .endContainer()
+                    .endSpec()
+                .endTemplate()
+            .endSpec()
+            .build();
+    }
+
+    private CustomResourceDefinition[] getBundleCrds() {
+        return strimziResources.stream().filter(file -> file.getName().matches(".*-Crd-.*\\.yaml"))
+            .map(crd -> new CustomResourceDefinitionBuilder(SetupUtils.configFromYaml(crd, CustomResourceDefinition.class))
+                .editMetadata()
+                    .withNamespace(this.deploymentNamespace)
+                .endMetadata()
+                .build())
+            .toArray(CustomResourceDefinition[]::new);
+    }
+
+    private ClusterRole[] getBundleClusterRoles() {
+        return strimziResources.stream().filter(file -> file.getName().matches(".*-ClusterRole-.*\\.yaml"))
+            .map(file -> new ClusterRoleBuilder(SetupUtils.configFromYaml(file, ClusterRole.class))
+                .editMetadata()
+                    .withNamespace(this.deploymentNamespace)
+                .endMetadata()
+                .build())
+            .toArray(ClusterRole[]::new);
+    }
+
+    private RoleBinding[] getBundleRoleBindings() {
+        return strimziResources.stream().filter(file -> file.getName().matches(".*-RoleBinding-.*\\.yaml"))
+            .map(rb -> new RoleBindingBuilder(SetupUtils.configFromYaml(rb, RoleBinding.class))
+                .editMetadata()
+                    .withNamespace(this.deploymentNamespace)
+                .endMetadata()
+                .editFirstSubject()
+                    .withNamespace(this.deploymentNamespace)
+                .endSubject()
+                .build())
+            .toArray(RoleBinding[]::new);
+    }
+
+    private ClusterRoleBinding[] getBundleClusterRoleBindings() {
+        return strimziResources.stream().filter(file -> file.getName().matches(".*-ClusterRoleBinding-.*\\.yaml"))
+            .map(crb -> new ClusterRoleBindingBuilder(SetupUtils.configFromYaml(crb, ClusterRoleBinding.class))
+                .editMetadata()
+                    .withNamespace(this.deploymentNamespace)
+                .endMetadata()
+                .editFirstSubject()
+                    .withNamespace(this.deploymentNamespace)
+                .endSubject()
+                .build())
+            .toArray(ClusterRoleBinding[]::new);
+    }
+
+    private List<File> fetchStrimziYamlFiles() {
+        List<File> yamlFiles = new ArrayList<>();
+        for (String fileUrl : extractYamlFileLinksFromGithubDir()) {
+            String fileName = fileUrl.substring(fileUrl.lastIndexOf('/') + 1).replace(".yaml", "");
+            LOGGER.debug("Fetching Strimzi YAML file: {}", fileName);
+            Path tempFile = null;
+            try {
+                tempFile = Files.createTempFile(fileName + "-tmp_", ".yaml");
+                Files.write(tempFile, SetupUtils.getYamlFileContent(fileUrl).getBytes());
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+            yamlFiles.add(tempFile.toFile());
+        }
+        return yamlFiles;
+    }
+
+    private List<String> extractYamlFileLinksFromGithubDir() {
path: systemtests/src/main/java/com/github/streamshub/systemtests/setup/StrimziOperatorSetup.java
user: login: jankalinic
body: I guess i could use configFromYaml then, thanks for bringing that up.
created_at: 2025-03-31T15:51:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,84 @@
+package com.github.streamshub.systemtests.utils;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import com.github.streamshub.systemtests.Environment;
+import com.github.streamshub.systemtests.logs.LogWrapper;
+import io.fabric8.kubernetes.api.model.Secret;
+import io.fabric8.kubernetes.api.model.SecretBuilder;
+import io.skodjob.testframe.resources.KubeResourceManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+
+public class SetupUtils {
+    private static final Logger LOGGER = LogWrapper.getLogger(SetupUtils.class);
+    private SetupUtils() {}
+
+    // ---------------
+    // Yaml config
+    // --------------
+    public static String getYamlFileContent(String fileUrl) {
+        LOGGER.debug("Loading YAML file content from url {}", fileUrl);
+        StringBuilder content;
+        try (BufferedReader in = new BufferedReader(new InputStreamReader(new URL(fileUrl).openStream(), StandardCharsets.UTF_8))) {
+            content = new StringBuilder();
+            String inputLine;
+
+            while ((inputLine = in.readLine()) != null) {
+                content.append(inputLine).append("\n");
+            }
+        } catch (IOException e) {
+            throw new RuntimeException("Cannot download YAML content from url: " + fileUrl, e);
+        }
+        return content.toString();
+    }
+
+    public static <T> T configFromYaml(File yamlFile, Class<T> c) {
+        ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
+        try {
+            return mapper.readValue(yamlFile, c);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    // --------------
+    // Namespace
+    // --------------
+    public static void copyImagePullSecrets(String targetNamespace) {
path: systemtests/src/main/java/com/github/streamshub/systemtests/utils/SetupUtils.java
user: login: jankalinic
body: There is currently a public image in the config.yaml file. This only allowed usage of custom test client with specific kafka version. But i guess for our usage, we could go only the public image, so we can get rid of all of this around test client image being a custom one.
created_at: 2025-03-31T16:00:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,306 @@
+package com.github.streamshub.systemtests.setup;
+
+import com.github.streamshub.systemtests.Environment;
+import com.github.streamshub.systemtests.constants.Constants;
+import com.github.streamshub.systemtests.constants.Labels;
+import com.github.streamshub.systemtests.constants.ResourceKinds;
+import com.github.streamshub.systemtests.logs.LogWrapper;
+import com.github.streamshub.systemtests.utils.ResourceUtils;
+import com.github.streamshub.systemtests.utils.SetupUtils;
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
+import io.fabric8.kubernetes.api.model.ServiceAccount;
+import io.fabric8.kubernetes.api.model.ServiceAccountBuilder;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinitionBuilder;
+import io.fabric8.kubernetes.api.model.apps.Deployment;
+import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRole;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBuilder;
+import io.fabric8.kubernetes.api.model.rbac.RoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.RoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.SubjectBuilder;
+import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroup;
+import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroupBuilder;
+import io.skodjob.testframe.resources.KubeResourceManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class StrimziOperatorSetup {
+    private static final Logger LOGGER = LogWrapper.getLogger(StrimziOperatorSetup.class);
+    private static final KubeResourceManager RESOURCE_MANAGER = KubeResourceManager.get();
path: systemtests/src/main/java/com/github/streamshub/systemtests/setup/StrimziOperatorSetup.java
user: login: im-konge
body: I personally have it in the variable in `AbstractST` so in the STs I'm just doing `kubeResourceManager.create...`.
But in all other classes that are not in the `test` folder I'm using the `KubeResourceManager.get()`

I was mainly curious why you wanted to do it like that in the `StrimziOperatorSetup`. You want to do this in every class you will create or delete something?

(again, I'm just asking, if you want to do it like this, okay. I'm not sure if it can cause some issues or not.)
created_at: 2025-03-31T16:02:42Z
author_association: NONE
diff_hunk: @@ -72,12 +81,28 @@ public abstract class AbstractST {
     }
 
     @BeforeAll
-    void beforeAll() {
-        LOGGER.info("=========== AbstractST - BeforeAll ===========");
+    void setupTestSuite() {
+        LOGGER.info("=========== AbstractST - BeforeAll - Setup TestSuite ===========");
path: systemtests/src/test/java/com/github/streamshub/systemtests/system/AbstractST.java
user: login: jankalinic
body: I already use the TestVisualSeparator via annotation, but it does not differentiate between the scope of a test method. This helps me determine if something fails in the `before junit overriden methods`  - even before the test is executed. I can remove it if you feel like this does not add value to debugging.
<img width="1678" alt="image" src="https://github.com/user-attachments/assets/2890b1e1-5f08-4934-90cd-a9d35b4da042" />


created_at: 2025-03-31T16:17:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,306 @@
+package com.github.streamshub.systemtests.setup;
+
+import com.github.streamshub.systemtests.Environment;
+import com.github.streamshub.systemtests.constants.Constants;
+import com.github.streamshub.systemtests.constants.Labels;
+import com.github.streamshub.systemtests.constants.ResourceKinds;
+import com.github.streamshub.systemtests.logs.LogWrapper;
+import com.github.streamshub.systemtests.utils.ResourceUtils;
+import com.github.streamshub.systemtests.utils.SetupUtils;
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
+import io.fabric8.kubernetes.api.model.ServiceAccount;
+import io.fabric8.kubernetes.api.model.ServiceAccountBuilder;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinitionBuilder;
+import io.fabric8.kubernetes.api.model.apps.Deployment;
+import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRole;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBuilder;
+import io.fabric8.kubernetes.api.model.rbac.RoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.RoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.SubjectBuilder;
+import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroup;
+import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroupBuilder;
+import io.skodjob.testframe.resources.KubeResourceManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class StrimziOperatorSetup {
+    private static final Logger LOGGER = LogWrapper.getLogger(StrimziOperatorSetup.class);
+    private static final KubeResourceManager RESOURCE_MANAGER = KubeResourceManager.get();
path: systemtests/src/main/java/com/github/streamshub/systemtests/setup/StrimziOperatorSetup.java
user: login: jankalinic
body: Sure, let's keep it united everywhere, it might be better to call it then define it all around.
created_at: 2025-03-31T16:21:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -72,12 +81,28 @@ public abstract class AbstractST {
     }
 
     @BeforeAll
-    void beforeAll() {
-        LOGGER.info("=========== AbstractST - BeforeAll ===========");
+    void setupTestSuite() {
+        LOGGER.info("=========== AbstractST - BeforeAll - Setup TestSuite ===========");
path: systemtests/src/test/java/com/github/streamshub/systemtests/system/AbstractST.java
user: login: jankalinic
body: You can see that even when separator logs the method name, it is more visible when the line you marked is logged as well. Or at least that is my opinion.
created_at: 2025-03-31T16:23:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -72,12 +81,28 @@ public abstract class AbstractST {
     }
 
     @BeforeAll
-    void beforeAll() {
-        LOGGER.info("=========== AbstractST - BeforeAll ===========");
+    void setupTestSuite() {
+        LOGGER.info("=========== AbstractST - BeforeAll - Setup TestSuite ===========");
path: systemtests/src/test/java/com/github/streamshub/systemtests/system/AbstractST.java
user: login: im-konge
body: I guess it's up to you then :) 
created_at: 2025-03-31T16:23:59Z
author_association: NONE
path: coverage/pom.xml
user: login: jankalinic
body: Understand, i tried it out to see the results (locally seemed to be working for ST module), but not to break the logic, it might be better to use the exclusion instead. I just felt like there might end up many exclusions.
created_at: 2025-03-31T16:25:59Z
author_association: CONTRIBUTOR
path: coverage/pom.xml
user: login: MikeEdgar
body: It will probably be rare for PRs to change both the application code and the STs, so being aware that ST changes will result in less than 80% coverage is fine with me. We can exclude everything in the ST package if you like, and gradually add things back as tests are running. For the STs, coverage metrics are basically only just helper since we have less concern about untested application functionality.
created_at: 2025-03-31T16:30:04Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,306 @@
+package com.github.streamshub.systemtests.setup;
+
+import com.github.streamshub.systemtests.Environment;
+import com.github.streamshub.systemtests.constants.Constants;
+import com.github.streamshub.systemtests.constants.Labels;
+import com.github.streamshub.systemtests.constants.ResourceKinds;
+import com.github.streamshub.systemtests.logs.LogWrapper;
+import com.github.streamshub.systemtests.utils.ResourceUtils;
+import com.github.streamshub.systemtests.utils.SetupUtils;
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
+import io.fabric8.kubernetes.api.model.ServiceAccount;
+import io.fabric8.kubernetes.api.model.ServiceAccountBuilder;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinitionBuilder;
+import io.fabric8.kubernetes.api.model.apps.Deployment;
+import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRole;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBuilder;
+import io.fabric8.kubernetes.api.model.rbac.RoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.RoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.SubjectBuilder;
+import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroup;
+import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroupBuilder;
+import io.skodjob.testframe.resources.KubeResourceManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class StrimziOperatorSetup {
+    private static final Logger LOGGER = LogWrapper.getLogger(StrimziOperatorSetup.class);
+    private static final KubeResourceManager RESOURCE_MANAGER = KubeResourceManager.get();
+
+    private final List<File> strimziResources = fetchStrimziYamlFiles();
+    private final String deploymentNamespace;
+    private final String deploymentName;
+
+    public StrimziOperatorSetup(String deploymentNamespace) {
+        this.deploymentNamespace = deploymentNamespace;
+        this.deploymentName = Environment.STRIMZI_OPERATOR_NAME;
+    }
+
+    public void setup() {
+        LOGGER.info("----------- Setup Strimzi Cluster Operator -----------");
+        // Watch all namespaces CRB
+        // https://strimzi.io/docs/operators/latest/deploying#deploying-cluster-operator-to-watch-whole-cluster-str
+        RESOURCE_MANAGER.createResourceWithWait(getStrimziWatchAllCrbs());
+
+        if (Environment.SKIP_STRIMZI_INSTALLATION || ResourceUtils.getKubeResource(Deployment.class, this.deploymentNamespace, this.deploymentName) != null) {
+            LOGGER.warn("Skipping Strimzi installation. It is already installed or env to skip installation was set to `true`!");
+            return;
+        }
+
+        LOGGER.info("Install Strimzi Cluster Operator in namespace: {}", this.deploymentNamespace);
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleCrds());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleClusterRoles());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleServiceAccount());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleRoleBindings());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleClusterRoleBindings());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleConfigMap());
+        RESOURCE_MANAGER.createResourceWithWait(getBundleDeployment());
+    }
+
+    public void teardown() {
+        LOGGER.info("----------- Teardown Strimzi Cluster Operator -----------");
+        if (Environment.SKIP_STRIMZI_INSTALLATION || ResourceUtils.getKubeResource(Deployment.class, this.deploymentNamespace, this.deploymentName) == null) {
+            LOGGER.warn("Skipping Strimzi deletion. It is already deleted or installation was skipped!");
+            return;
+        }
+
+        // Watch all namespaces CRB
+        RESOURCE_MANAGER.deleteResource(getStrimziOperatorGroup());
+        RESOURCE_MANAGER.deleteResource(getStrimziWatchAllCrbs());
+        RESOURCE_MANAGER.deleteResource(getBundleCrds());
+        RESOURCE_MANAGER.deleteResource(getBundleClusterRoles());
+        RESOURCE_MANAGER.deleteResource(getBundleServiceAccount());
+        RESOURCE_MANAGER.deleteResource(getBundleRoleBindings());
+        RESOURCE_MANAGER.deleteResource(getBundleClusterRoleBindings());
+        RESOURCE_MANAGER.deleteResource(getBundleConfigMap());
+        RESOURCE_MANAGER.deleteResource(getBundleDeployment());
+    }
+
+    private ClusterRoleBinding[] getStrimziWatchAllCrbs() {
+        return new ClusterRoleBinding[]{
+            new ClusterRoleBindingBuilder()
+                .withNewMetadata()
+                    .withName(Constants.STRIMZI_CO_NAME + "-namespaced")
+                .endMetadata()
+                .withNewRoleRef()
+                    .withApiGroup(Constants.RBAC_AUTH_API_GROUP)
+                    .withKind(ResourceKinds.CLUSTER_ROLE)
+                    .withName(Constants.STRIMZI_CO_NAME + "-namespaced")
+                .endRoleRef()
+                .withSubjects(new SubjectBuilder()
+                    .withKind(ResourceKinds.SERVICE_ACCOUNT)
+                    .withName(Constants.STRIMZI_CO_NAME)
+                    .withNamespace(this.deploymentNamespace)
+                    .build())
+                .build(),
+            new ClusterRoleBindingBuilder()
+                .withNewMetadata()
+                    .withName(Constants.STRIMZI_CO_NAME  + "-entity-operator")
+                .endMetadata()
+                .withNewRoleRef()
+                    .withApiGroup(Constants.RBAC_AUTH_API_GROUP)
+                    .withKind(ResourceKinds.CLUSTER_ROLE)
+                    .withName(Constants.STRIMZI_CO_NAME  + "-entity-operator")
+                .endRoleRef()
+                .withSubjects(new SubjectBuilder()
+                    .withKind(ResourceKinds.SERVICE_ACCOUNT)
+                    .withName(Constants.STRIMZI_CO_NAME)
+                    .withNamespace(this.deploymentNamespace)
+                    .build())
+                .build(),
+            new ClusterRoleBindingBuilder()
+                .withNewMetadata()
+                    .withName(Constants.STRIMZI_CO_NAME + "-watched")
+                .endMetadata()
+                .withNewRoleRef()
+                    .withApiGroup(Constants.RBAC_AUTH_API_GROUP)
+                    .withKind(ResourceKinds.CLUSTER_ROLE)
+                    .withName(Constants.STRIMZI_CO_NAME + "-watched")
+                .endRoleRef()
+                .withSubjects(new SubjectBuilder()
+                    .withKind(ResourceKinds.SERVICE_ACCOUNT)
+                    .withName(Constants.STRIMZI_CO_NAME)
+                    .withNamespace(this.deploymentNamespace)
+                    .build())
+                .build()
+        };
+    }
+
+    private OperatorGroup getStrimziOperatorGroup() {
+        return new OperatorGroupBuilder()
+            .editOrNewMetadata()
+                .withName(Constants.CONSOLE_OPERATOR_GROUP_NAME)
+                .withNamespace(this.deploymentNamespace)
+                .withLabels(Collections.singletonMap(Labels.APP, Constants.STRIMZI_NAME))
+            .endMetadata()
+            .build();
+    }
path: systemtests/src/main/java/com/github/streamshub/systemtests/setup/StrimziOperatorSetup.java
user: login: jankalinic
body: Had to check, but it seems like i should remove it from here. Thanks!
created_at: 2025-03-31T16:33:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,306 @@
+package com.github.streamshub.systemtests.setup;
+
+import com.github.streamshub.systemtests.Environment;
+import com.github.streamshub.systemtests.constants.Constants;
+import com.github.streamshub.systemtests.constants.Labels;
+import com.github.streamshub.systemtests.constants.ResourceKinds;
+import com.github.streamshub.systemtests.logs.LogWrapper;
+import com.github.streamshub.systemtests.utils.ResourceUtils;
+import com.github.streamshub.systemtests.utils.SetupUtils;
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
+import io.fabric8.kubernetes.api.model.ServiceAccount;
+import io.fabric8.kubernetes.api.model.ServiceAccountBuilder;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinitionBuilder;
+import io.fabric8.kubernetes.api.model.apps.Deployment;
+import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRole;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBuilder;
+import io.fabric8.kubernetes.api.model.rbac.RoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.RoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.SubjectBuilder;
+import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroup;
+import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroupBuilder;
+import io.skodjob.testframe.resources.KubeResourceManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class StrimziOperatorSetup {
+    private static final Logger LOGGER = LogWrapper.getLogger(StrimziOperatorSetup.class);
+    private static final KubeResourceManager RESOURCE_MANAGER = KubeResourceManager.get();
+
+    private final List<File> strimziResources = fetchStrimziYamlFiles();
+    private final String deploymentNamespace;
+    private final String deploymentName;
+
+    public StrimziOperatorSetup(String deploymentNamespace) {
+        this.deploymentNamespace = deploymentNamespace;
+        this.deploymentName = Environment.STRIMZI_OPERATOR_NAME;
+    }
+
+    public void setup() {
+        LOGGER.info("----------- Setup Strimzi Cluster Operator -----------");
+        // Watch all namespaces CRB
+        // https://strimzi.io/docs/operators/latest/deploying#deploying-cluster-operator-to-watch-whole-cluster-str
+        RESOURCE_MANAGER.createResourceWithWait(getStrimziWatchAllCrbs());
+
+        if (Environment.SKIP_STRIMZI_INSTALLATION || ResourceUtils.getKubeResource(Deployment.class, this.deploymentNamespace, this.deploymentName) != null) {
+            LOGGER.warn("Skipping Strimzi installation. It is already installed or env to skip installation was set to `true`!");
+            return;
+        }
+
+        LOGGER.info("Install Strimzi Cluster Operator in namespace: {}", this.deploymentNamespace);
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleCrds());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleClusterRoles());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleServiceAccount());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleRoleBindings());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleClusterRoleBindings());
+        RESOURCE_MANAGER.createResourceWithoutWait(getBundleConfigMap());
+        RESOURCE_MANAGER.createResourceWithWait(getBundleDeployment());
+    }
+
+    public void teardown() {
+        LOGGER.info("----------- Teardown Strimzi Cluster Operator -----------");
+        if (Environment.SKIP_STRIMZI_INSTALLATION || ResourceUtils.getKubeResource(Deployment.class, this.deploymentNamespace, this.deploymentName) == null) {
+            LOGGER.warn("Skipping Strimzi deletion. It is already deleted or installation was skipped!");
+            return;
+        }
+
+        // Watch all namespaces CRB
+        RESOURCE_MANAGER.deleteResource(getStrimziOperatorGroup());
+        RESOURCE_MANAGER.deleteResource(getStrimziWatchAllCrbs());
+        RESOURCE_MANAGER.deleteResource(getBundleCrds());
+        RESOURCE_MANAGER.deleteResource(getBundleClusterRoles());
+        RESOURCE_MANAGER.deleteResource(getBundleServiceAccount());
+        RESOURCE_MANAGER.deleteResource(getBundleRoleBindings());
+        RESOURCE_MANAGER.deleteResource(getBundleClusterRoleBindings());
+        RESOURCE_MANAGER.deleteResource(getBundleConfigMap());
+        RESOURCE_MANAGER.deleteResource(getBundleDeployment());
+    }
+
+    private ClusterRoleBinding[] getStrimziWatchAllCrbs() {
path: systemtests/src/main/java/com/github/streamshub/systemtests/setup/StrimziOperatorSetup.java
user: login: jankalinic
body: I think i had to resort to this because of strimzi not watching all namespaces, not by default only using STRIMZI_NAMESPACE:"*" i think. Follows ->
https://strimzi.io/docs/operators/latest/deploying#deploying-cluster-operator-to-watch-whole-cluster-str
created_at: 2025-03-31T17:33:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -6,37 +6,41 @@ private ResourceKinds() {}
     // ----------
     // K8s
     // ----------
-    public static final String CUSTOM_RESOURCE_DEFINITION = "customresourcedefinition";
-    public static final String CONFIG_MAP = "configmap";
-    public static final String DEPLOYMENT = "deployment";
-    public static final String DEPLOYMENT_CONFIG = "deploymentconfig";
-    public static final String POD = "pod";
-    public static final String SERVICE = "service";
-    public static final String SECRET = "secret";
-    public static final String CLUSTER_ROLE = "clusterrole";
-    public static final String CLUSTER_ROLE_BINDING = "clusterrolebinding";
-    public static final String ROLE_BINDING = "rolebinding";
-    public static final String SERVICE_ACCOUNT = "serviceaccount";
-    public static final String JOB = "job";
-    public static final String NAMESPACE = "namespace";
-    // ----------
-    // Openshift
-    // ----------
-    public static final String CATALOG_SOURCE = "catalogsource";
-    public static final String SUBSCRIPTION = "subscription";
-    public static final String INSTALL_PLAN = "installplan";
-    public static final String CLUSTER_SERVICE_VERSION = "clusterserviceversion";
-    public static final String OPERATOR_GROUP = "operatorgroup";
-    public static final String OPERATOR = "operator";
+    public static final String CUSTOM_RESOURCE_DEFINITION = "CustomResourceDefinition";
+    public static final String CONFIG_MAP = "ConfigMap";
+    public static final String DEPLOYMENT = "Deployment";
+    public static final String DEPLOYMENT_CONFIG = "DeploymentConfig";
+    public static final String POD = "Pod";
+    public static final String SERVICE = "Service";
+    public static final String SECRET = "Secret";
+    public static final String CLUSTER_ROLE = "ClusterRole";
+    public static final String CLUSTER_ROLE_BINDING = "ClusterRoleBinding";
+    public static final String ROLE_BINDING = "RoleBinding";
+    public static final String SERVICE_ACCOUNT = "ServiceAccount";
+    public static final String JOB = "Job";
+    public static final String NAMESPACE = "Namespace";
+
+    // ----------
+    // OpenShift
+    // ----------
+    public static final String CATALOG_SOURCE = "CatalogSource";
+    public static final String SUBSCRIPTION = "Subscription";
+    public static final String INSTALL_PLAN = "InstallPlan";
+    public static final String CLUSTER_SERVICE_VERSION = "ClusterServiceVersion";
+    public static final String OPERATOR_GROUP = "OperatorGroup";
+    public static final String OPERATOR = "Operator";
+
     // ----------
     // Kafka
     // ----------
-    public static final String KAFKA_TOPIC = "kafkatopic";
-    public static final String KAFKA = "kafka";
-    public static final String KAFKA_USER = "kafkauser";
-    public static final String KAFKA_NODE_POOL = "kafkanodepool";
+    public static final String KAFKA_TOPIC = "KafkaTopic";
+    public static final String KAFKA = "Kafka";
+    public static final String KAFKA_USER = "KafkaUser";
+    public static final String KAFKA_NODE_POOL = "KafkaNodePool";
+
     // ----------
     // Console
     // ----------
-    public static final String CONSOLE = "console";
+    public static final String CONSOLE = "Console";
path: systemtests/src/main/java/com/github/streamshub/systemtests/constants/ResourceKinds.java
user: login: im-konge
body: @MikeEdgar would it make sense to add the kind here: https://github.com/streamshub/console/blob/main/operator/src/main/java/com/github/streamshub/console/api/v1alpha1/Console.java
?

I mean, the `kind` in the CR is taken from the class name? Usually I saw that these CR classes has the `KIND` or `RESOURCE_KIND` constant just to provide it to users that are also using the API. Or if it should be taken just from the display name of the class (IDK how it is handled in the generation)?


created_at: 2025-03-31T17:42:42Z
author_association: NONE
diff_hunk: @@ -72,12 +81,28 @@ public abstract class AbstractST {
     }
 
     @BeforeAll
-    void beforeAll() {
-        LOGGER.info("=========== AbstractST - BeforeAll ===========");
+    void setupTestSuite() {
+        LOGGER.info("=========== AbstractST - BeforeAll - Setup TestSuite ===========");
path: systemtests/src/test/java/com/github/streamshub/systemtests/system/AbstractST.java
user: login: jankalinic
body: Right, i'd keep this one in.
created_at: 2025-03-31T17:52:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -6,37 +6,41 @@ private ResourceKinds() {}
     // ----------
     // K8s
     // ----------
-    public static final String CUSTOM_RESOURCE_DEFINITION = "customresourcedefinition";
-    public static final String CONFIG_MAP = "configmap";
-    public static final String DEPLOYMENT = "deployment";
-    public static final String DEPLOYMENT_CONFIG = "deploymentconfig";
-    public static final String POD = "pod";
-    public static final String SERVICE = "service";
-    public static final String SECRET = "secret";
-    public static final String CLUSTER_ROLE = "clusterrole";
-    public static final String CLUSTER_ROLE_BINDING = "clusterrolebinding";
-    public static final String ROLE_BINDING = "rolebinding";
-    public static final String SERVICE_ACCOUNT = "serviceaccount";
-    public static final String JOB = "job";
-    public static final String NAMESPACE = "namespace";
-    // ----------
-    // Openshift
-    // ----------
-    public static final String CATALOG_SOURCE = "catalogsource";
-    public static final String SUBSCRIPTION = "subscription";
-    public static final String INSTALL_PLAN = "installplan";
-    public static final String CLUSTER_SERVICE_VERSION = "clusterserviceversion";
-    public static final String OPERATOR_GROUP = "operatorgroup";
-    public static final String OPERATOR = "operator";
+    public static final String CUSTOM_RESOURCE_DEFINITION = "CustomResourceDefinition";
+    public static final String CONFIG_MAP = "ConfigMap";
+    public static final String DEPLOYMENT = "Deployment";
+    public static final String DEPLOYMENT_CONFIG = "DeploymentConfig";
+    public static final String POD = "Pod";
+    public static final String SERVICE = "Service";
+    public static final String SECRET = "Secret";
+    public static final String CLUSTER_ROLE = "ClusterRole";
+    public static final String CLUSTER_ROLE_BINDING = "ClusterRoleBinding";
+    public static final String ROLE_BINDING = "RoleBinding";
+    public static final String SERVICE_ACCOUNT = "ServiceAccount";
+    public static final String JOB = "Job";
+    public static final String NAMESPACE = "Namespace";
+
+    // ----------
+    // OpenShift
+    // ----------
+    public static final String CATALOG_SOURCE = "CatalogSource";
+    public static final String SUBSCRIPTION = "Subscription";
+    public static final String INSTALL_PLAN = "InstallPlan";
+    public static final String CLUSTER_SERVICE_VERSION = "ClusterServiceVersion";
+    public static final String OPERATOR_GROUP = "OperatorGroup";
+    public static final String OPERATOR = "Operator";
+
     // ----------
     // Kafka
     // ----------
-    public static final String KAFKA_TOPIC = "kafkatopic";
-    public static final String KAFKA = "kafka";
-    public static final String KAFKA_USER = "kafkauser";
-    public static final String KAFKA_NODE_POOL = "kafkanodepool";
+    public static final String KAFKA_TOPIC = "KafkaTopic";
+    public static final String KAFKA = "Kafka";
+    public static final String KAFKA_USER = "KafkaUser";
+    public static final String KAFKA_NODE_POOL = "KafkaNodePool";
+
     // ----------
     // Console
     // ----------
-    public static final String CONSOLE = "console";
+    public static final String CONSOLE = "Console";
path: systemtests/src/main/java/com/github/streamshub/systemtests/constants/ResourceKinds.java
user: login: MikeEdgar
body: Yeah it's just the class name - `Class#getSimpleName` would provide it.
created_at: 2025-03-31T17:54:35Z
author_association: MEMBER
diff_hunk: @@ -6,37 +6,41 @@ private ResourceKinds() {}
     // ----------
     // K8s
     // ----------
-    public static final String CUSTOM_RESOURCE_DEFINITION = "customresourcedefinition";
-    public static final String CONFIG_MAP = "configmap";
-    public static final String DEPLOYMENT = "deployment";
-    public static final String DEPLOYMENT_CONFIG = "deploymentconfig";
-    public static final String POD = "pod";
-    public static final String SERVICE = "service";
-    public static final String SECRET = "secret";
-    public static final String CLUSTER_ROLE = "clusterrole";
-    public static final String CLUSTER_ROLE_BINDING = "clusterrolebinding";
-    public static final String ROLE_BINDING = "rolebinding";
-    public static final String SERVICE_ACCOUNT = "serviceaccount";
-    public static final String JOB = "job";
-    public static final String NAMESPACE = "namespace";
-    // ----------
-    // Openshift
-    // ----------
-    public static final String CATALOG_SOURCE = "catalogsource";
-    public static final String SUBSCRIPTION = "subscription";
-    public static final String INSTALL_PLAN = "installplan";
-    public static final String CLUSTER_SERVICE_VERSION = "clusterserviceversion";
-    public static final String OPERATOR_GROUP = "operatorgroup";
-    public static final String OPERATOR = "operator";
+    public static final String CUSTOM_RESOURCE_DEFINITION = "CustomResourceDefinition";
+    public static final String CONFIG_MAP = "ConfigMap";
+    public static final String DEPLOYMENT = "Deployment";
+    public static final String DEPLOYMENT_CONFIG = "DeploymentConfig";
+    public static final String POD = "Pod";
+    public static final String SERVICE = "Service";
+    public static final String SECRET = "Secret";
+    public static final String CLUSTER_ROLE = "ClusterRole";
+    public static final String CLUSTER_ROLE_BINDING = "ClusterRoleBinding";
+    public static final String ROLE_BINDING = "RoleBinding";
+    public static final String SERVICE_ACCOUNT = "ServiceAccount";
+    public static final String JOB = "Job";
+    public static final String NAMESPACE = "Namespace";
+
+    // ----------
+    // OpenShift
+    // ----------
+    public static final String CATALOG_SOURCE = "CatalogSource";
+    public static final String SUBSCRIPTION = "Subscription";
+    public static final String INSTALL_PLAN = "InstallPlan";
+    public static final String CLUSTER_SERVICE_VERSION = "ClusterServiceVersion";
+    public static final String OPERATOR_GROUP = "OperatorGroup";
+    public static final String OPERATOR = "Operator";
+
     // ----------
     // Kafka
     // ----------
-    public static final String KAFKA_TOPIC = "kafkatopic";
-    public static final String KAFKA = "kafka";
-    public static final String KAFKA_USER = "kafkauser";
-    public static final String KAFKA_NODE_POOL = "kafkanodepool";
+    public static final String KAFKA_TOPIC = "KafkaTopic";
+    public static final String KAFKA = "Kafka";
+    public static final String KAFKA_USER = "KafkaUser";
+    public static final String KAFKA_NODE_POOL = "KafkaNodePool";
+
     // ----------
     // Console
     // ----------
-    public static final String CONSOLE = "console";
+    public static final String CONSOLE = "Console";
path: systemtests/src/main/java/com/github/streamshub/systemtests/constants/ResourceKinds.java
user: login: MikeEdgar
body: Fabric8 will also get it for you if you use `HasMetadata.getKind(Console.class)`.
created_at: 2025-03-31T17:59:57Z
author_association: MEMBER
diff_hunk: @@ -6,37 +6,41 @@ private ResourceKinds() {}
     // ----------
     // K8s
     // ----------
-    public static final String CUSTOM_RESOURCE_DEFINITION = "customresourcedefinition";
-    public static final String CONFIG_MAP = "configmap";
-    public static final String DEPLOYMENT = "deployment";
-    public static final String DEPLOYMENT_CONFIG = "deploymentconfig";
-    public static final String POD = "pod";
-    public static final String SERVICE = "service";
-    public static final String SECRET = "secret";
-    public static final String CLUSTER_ROLE = "clusterrole";
-    public static final String CLUSTER_ROLE_BINDING = "clusterrolebinding";
-    public static final String ROLE_BINDING = "rolebinding";
-    public static final String SERVICE_ACCOUNT = "serviceaccount";
-    public static final String JOB = "job";
-    public static final String NAMESPACE = "namespace";
-    // ----------
-    // Openshift
-    // ----------
-    public static final String CATALOG_SOURCE = "catalogsource";
-    public static final String SUBSCRIPTION = "subscription";
-    public static final String INSTALL_PLAN = "installplan";
-    public static final String CLUSTER_SERVICE_VERSION = "clusterserviceversion";
-    public static final String OPERATOR_GROUP = "operatorgroup";
-    public static final String OPERATOR = "operator";
+    public static final String CUSTOM_RESOURCE_DEFINITION = "CustomResourceDefinition";
+    public static final String CONFIG_MAP = "ConfigMap";
+    public static final String DEPLOYMENT = "Deployment";
+    public static final String DEPLOYMENT_CONFIG = "DeploymentConfig";
+    public static final String POD = "Pod";
+    public static final String SERVICE = "Service";
+    public static final String SECRET = "Secret";
+    public static final String CLUSTER_ROLE = "ClusterRole";
+    public static final String CLUSTER_ROLE_BINDING = "ClusterRoleBinding";
+    public static final String ROLE_BINDING = "RoleBinding";
+    public static final String SERVICE_ACCOUNT = "ServiceAccount";
+    public static final String JOB = "Job";
+    public static final String NAMESPACE = "Namespace";
+
+    // ----------
+    // OpenShift
+    // ----------
+    public static final String CATALOG_SOURCE = "CatalogSource";
+    public static final String SUBSCRIPTION = "Subscription";
+    public static final String INSTALL_PLAN = "InstallPlan";
+    public static final String CLUSTER_SERVICE_VERSION = "ClusterServiceVersion";
+    public static final String OPERATOR_GROUP = "OperatorGroup";
+    public static final String OPERATOR = "Operator";
+
     // ----------
     // Kafka
     // ----------
-    public static final String KAFKA_TOPIC = "kafkatopic";
-    public static final String KAFKA = "kafka";
-    public static final String KAFKA_USER = "kafkauser";
-    public static final String KAFKA_NODE_POOL = "kafkanodepool";
+    public static final String KAFKA_TOPIC = "KafkaTopic";
+    public static final String KAFKA = "Kafka";
+    public static final String KAFKA_USER = "KafkaUser";
+    public static final String KAFKA_NODE_POOL = "KafkaNodePool";
+
     // ----------
     // Console
     // ----------
-    public static final String CONSOLE = "console";
+    public static final String CONSOLE = "Console";
path: systemtests/src/main/java/com/github/streamshub/systemtests/constants/ResourceKinds.java
user: login: jankalinic
body: Okay, if it's okay with you HasMetadata suggesting `kind` sounds better.
created_at: 2025-03-31T18:07:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -23,15 +23,29 @@
         <playwright.version>1.47.0</playwright.version>
         <!-- Mocking environment -->
         <mockito.version>5.15.2</mockito.version>
-        <junit-pioneer.version>2.3.0</junit-pioneer.version>
+        <powermock.version>2.0.9</powermock.version>
         <!-- Used for test-frame -->
-        <test-frame.version>0.8.0</test-frame.version>
+        <test-frame.version>0.11.0-SNAPSHOT</test-frame.version>
path: systemtests/pom.xml
user: login: jankalinic
body: I think i can leave it for now, but remove once released.
created_at: 2025-04-01T09:05:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,71 @@
+package com.github.streamshub.systemtests.constants;
+
+public class Constants {
+    private Constants() {}
+
+    // --------------------------------
+    // ------------ General -----------
+    // --------------------------------
+    /**
+     * Namespaces
+     */
+    public static final String CO_NAMESPACE = "co-namespace";
+    public static final String OPENSHIFT_MARKETPLACE_NAMESPACE = "openshift-marketplace";
+
+    /**
+     * Test values
+     */
+    public static final String USER_USERNAME = "Anonymous";
+
+    /**
+     * Messages
+     */
+    public static final int MESSAGE_COUNT = 1000;
+
+    /**
+     * CRDs
+     */
+    public static final String RBAC_AUTH_API_GROUP = "rbac.authorization.k8s.io";
+
+
+    // --------------------------------
+    // ----------- Strimzi ------------
+    // --------------------------------
+    public static final String STRIMZI_NAME = "strimzi";
+    public static final String STRIMZI_CO_NAME = STRIMZI_NAME + "-cluster-operator";
+    public static final String STRIMZI_NAMESPACE_KEY = "STRIMZI_NAMESPACE";
+    public static final String STRIMZI_WATCH_ALL_NAMESPACES = "*";
+
+    /**
+     * Clients
+     */
+    public static final String PRODUCER = "producer";
+    public static final String CONSUMER = "consumer";
+
+    /**
+     * Topics
+     */
+    public static final String KAFKA_TOPIC_PREFIX = "kt";
+    public static final String CONSUMER_OFFSETS_TOPIC_NAME = "__consumer_offsets";
+
+    /**
+     *  Kafka
+     */
+    public static final String KAFKA_USER_PREFIX = "user";
+    public static final String KAFKA_CLUSTER_PREFIX = "kc";
+    public static final String BROKER_ROLE_PREFIX = "brk";
+    public static final String CONTROLLER_ROLE_PREFIX = "ctrl";
+    public static final int REGULAR_BROKER_REPLICAS = 3;
+
+
+     // --------------------------------
+    // ------------ Console -----------
+    // --------------------------------
+    /**
+     * CRDs
+     */
+    public static final String CONSOLE_CRD_API_NAME = "consoles.console.streamshub.github.com";
+    public static final String CONSOLE_CRD_API_VERSION = "console.streamshub.github.com/v1alpha1";
path: systemtests/src/main/java/com/github/streamshub/systemtests/constants/Constants.java
user: login: MikeEdgar
body: Just to mention it, `HasMetadata` also has methods to obtain these if you want. E.g.
```suggestion
    public static final String CONSOLE_CRD_API_NAME = HasMetadata.getFullResourceName(Console.class);
    public static final String CONSOLE_CRD_API_VERSION = HasMetadata.getGroup(Console.class) + "/" + HasMetadata.getVersion(Console.class);
```
created_at: 2025-04-01T09:43:13Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,291 @@
+package com.github.streamshub.systemtests.setup;
+
+import com.github.streamshub.systemtests.Environment;
+import com.github.streamshub.systemtests.constants.Constants;
+import com.github.streamshub.systemtests.constants.ResourceKinds;
+import com.github.streamshub.systemtests.logs.LogWrapper;
+import com.github.streamshub.systemtests.utils.ResourceUtils;
+import com.github.streamshub.systemtests.utils.SetupUtils;
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
+import io.fabric8.kubernetes.api.model.ServiceAccount;
+import io.fabric8.kubernetes.api.model.ServiceAccountBuilder;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinitionBuilder;
+import io.fabric8.kubernetes.api.model.apps.Deployment;
+import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRole;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBuilder;
+import io.fabric8.kubernetes.api.model.rbac.RoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.RoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.SubjectBuilder;
+import io.skodjob.testframe.resources.KubeResourceManager;
+import io.skodjob.testframe.utils.TestFrameUtils;
+import org.apache.logging.log4j.Logger;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class StrimziOperatorSetup {
+    private static final Logger LOGGER = LogWrapper.getLogger(StrimziOperatorSetup.class);
+
+    private final List<File> strimziResources = fetchStrimziYamlFiles();
+    private final String deploymentNamespace;
+    private final String deploymentName;
+
+    public StrimziOperatorSetup(String deploymentNamespace) {
+        this.deploymentNamespace = deploymentNamespace;
+        this.deploymentName = Environment.STRIMZI_OPERATOR_NAME;
+    }
+
+    public void setup() {
+        LOGGER.info("----------- Setup Strimzi Cluster Operator -----------");
+        // Watch all namespaces CRB
+        // https://strimzi.io/docs/operators/latest/deploying#deploying-cluster-operator-to-watch-whole-cluster-str
+        KubeResourceManager.get().createResourceWithWait(getStrimziWatchAllCrbs());
+
+        if (Environment.SKIP_STRIMZI_INSTALLATION || ResourceUtils.getKubeResource(Deployment.class, this.deploymentNamespace, this.deploymentName) != null) {
+            LOGGER.warn("Skipping Strimzi installation. It is already installed or env to skip installation was set to `true`!");
+            return;
+        }
+
+        LOGGER.info("Install Strimzi Cluster Operator in namespace: {}", this.deploymentNamespace);
+        KubeResourceManager.get().createResourceWithoutWait(getBundleCrds());
+        KubeResourceManager.get().createResourceWithoutWait(getBundleClusterRoles());
+        KubeResourceManager.get().createResourceWithoutWait(getBundleServiceAccount());
+        KubeResourceManager.get().createResourceWithoutWait(getBundleRoleBindings());
+        KubeResourceManager.get().createResourceWithoutWait(getBundleClusterRoleBindings());
+        KubeResourceManager.get().createResourceWithoutWait(getBundleConfigMap());
+        KubeResourceManager.get().createResourceWithWait(getBundleDeployment());
+    }
+
+    public void teardown() {
+        LOGGER.info("----------- Teardown Strimzi Cluster Operator -----------");
+        if (Environment.SKIP_STRIMZI_INSTALLATION || ResourceUtils.getKubeResource(Deployment.class, this.deploymentNamespace, this.deploymentName) == null) {
+            LOGGER.warn("Skipping Strimzi deletion. It is already deleted or installation was skipped!");
+            return;
+        }
+
+        // Watch all namespaces CRB
+        KubeResourceManager.get().deleteResource(getStrimziWatchAllCrbs());
+        KubeResourceManager.get().deleteResource(getBundleCrds());
+        KubeResourceManager.get().deleteResource(getBundleClusterRoles());
+        KubeResourceManager.get().deleteResource(getBundleServiceAccount());
+        KubeResourceManager.get().deleteResource(getBundleRoleBindings());
+        KubeResourceManager.get().deleteResource(getBundleClusterRoleBindings());
+        KubeResourceManager.get().deleteResource(getBundleConfigMap());
+        KubeResourceManager.get().deleteResource(getBundleDeployment());
+    }
+
+    private ClusterRoleBinding[] getStrimziWatchAllCrbs() {
+        return new ClusterRoleBinding[]{
+            new ClusterRoleBindingBuilder()
+                .withNewMetadata()
+                    .withName(Constants.STRIMZI_CO_NAME + "-namespaced")
+                .endMetadata()
+                .withNewRoleRef()
+                    .withApiGroup(Constants.RBAC_AUTH_API_GROUP)
+                    .withKind(ResourceKinds.CLUSTER_ROLE)
+                    .withName(Constants.STRIMZI_CO_NAME + "-namespaced")
+                .endRoleRef()
+                .withSubjects(new SubjectBuilder()
+                    .withKind(ResourceKinds.SERVICE_ACCOUNT)
+                    .withName(Constants.STRIMZI_CO_NAME)
+                    .withNamespace(this.deploymentNamespace)
+                    .build())
+                .build(),
+            new ClusterRoleBindingBuilder()
+                .withNewMetadata()
+                    .withName(Constants.STRIMZI_CO_NAME  + "-entity-operator")
+                .endMetadata()
+                .withNewRoleRef()
+                    .withApiGroup(Constants.RBAC_AUTH_API_GROUP)
+                    .withKind(ResourceKinds.CLUSTER_ROLE)
+                    .withName(Constants.STRIMZI_CO_NAME  + "-entity-operator")
+                .endRoleRef()
+                .withSubjects(new SubjectBuilder()
+                    .withKind(ResourceKinds.SERVICE_ACCOUNT)
+                    .withName(Constants.STRIMZI_CO_NAME)
+                    .withNamespace(this.deploymentNamespace)
+                    .build())
+                .build(),
+            new ClusterRoleBindingBuilder()
+                .withNewMetadata()
+                    .withName(Constants.STRIMZI_CO_NAME + "-watched")
+                .endMetadata()
+                .withNewRoleRef()
+                    .withApiGroup(Constants.RBAC_AUTH_API_GROUP)
+                    .withKind(ResourceKinds.CLUSTER_ROLE)
+                    .withName(Constants.STRIMZI_CO_NAME + "-watched")
+                .endRoleRef()
+                .withSubjects(new SubjectBuilder()
+                    .withKind(ResourceKinds.SERVICE_ACCOUNT)
+                    .withName(Constants.STRIMZI_CO_NAME)
+                    .withNamespace(this.deploymentNamespace)
+                    .build())
+                .build()
+        };
+    }
+
+    private ConfigMap getBundleConfigMap() {
+        return new ConfigMapBuilder(TestFrameUtils.configFromYaml(strimziResources.stream()
+            .filter(file -> file.getName().matches(".*050-ConfigMap-.*\\.yaml")).toList().get(0), ConfigMap.class))
path: systemtests/src/main/java/com/github/streamshub/systemtests/setup/StrimziOperatorSetup.java
user: login: MikeEdgar
body: I know it seems silly, but it might be good to change the `matches` to `startsWith` and drop the `yaml` part since these regex were all flagged as a security hotspot.
```suggestion
            .filter(file -> file.getName().startsWith("050-ConfigMap-")).toList().get(0), ConfigMap.class))
```
created_at: 2025-04-01T09:46:25Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,291 @@
+package com.github.streamshub.systemtests.setup;
+
+import com.github.streamshub.systemtests.Environment;
+import com.github.streamshub.systemtests.constants.Constants;
+import com.github.streamshub.systemtests.constants.ResourceKinds;
+import com.github.streamshub.systemtests.logs.LogWrapper;
+import com.github.streamshub.systemtests.utils.ResourceUtils;
+import com.github.streamshub.systemtests.utils.SetupUtils;
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
+import io.fabric8.kubernetes.api.model.ServiceAccount;
+import io.fabric8.kubernetes.api.model.ServiceAccountBuilder;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinitionBuilder;
+import io.fabric8.kubernetes.api.model.apps.Deployment;
+import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRole;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBuilder;
+import io.fabric8.kubernetes.api.model.rbac.RoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.RoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.SubjectBuilder;
+import io.skodjob.testframe.resources.KubeResourceManager;
+import io.skodjob.testframe.utils.TestFrameUtils;
+import org.apache.logging.log4j.Logger;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class StrimziOperatorSetup {
+    private static final Logger LOGGER = LogWrapper.getLogger(StrimziOperatorSetup.class);
+
+    private final List<File> strimziResources = fetchStrimziYamlFiles();
+    private final String deploymentNamespace;
+    private final String deploymentName;
+
+    public StrimziOperatorSetup(String deploymentNamespace) {
+        this.deploymentNamespace = deploymentNamespace;
+        this.deploymentName = Environment.STRIMZI_OPERATOR_NAME;
+    }
+
+    public void setup() {
+        LOGGER.info("----------- Setup Strimzi Cluster Operator -----------");
+        // Watch all namespaces CRB
+        // https://strimzi.io/docs/operators/latest/deploying#deploying-cluster-operator-to-watch-whole-cluster-str
+        KubeResourceManager.get().createResourceWithWait(getStrimziWatchAllCrbs());
+
+        if (Environment.SKIP_STRIMZI_INSTALLATION || ResourceUtils.getKubeResource(Deployment.class, this.deploymentNamespace, this.deploymentName) != null) {
+            LOGGER.warn("Skipping Strimzi installation. It is already installed or env to skip installation was set to `true`!");
+            return;
+        }
+
+        LOGGER.info("Install Strimzi Cluster Operator in namespace: {}", this.deploymentNamespace);
+        KubeResourceManager.get().createResourceWithoutWait(getBundleCrds());
+        KubeResourceManager.get().createResourceWithoutWait(getBundleClusterRoles());
+        KubeResourceManager.get().createResourceWithoutWait(getBundleServiceAccount());
+        KubeResourceManager.get().createResourceWithoutWait(getBundleRoleBindings());
+        KubeResourceManager.get().createResourceWithoutWait(getBundleClusterRoleBindings());
+        KubeResourceManager.get().createResourceWithoutWait(getBundleConfigMap());
+        KubeResourceManager.get().createResourceWithWait(getBundleDeployment());
+    }
+
+    public void teardown() {
+        LOGGER.info("----------- Teardown Strimzi Cluster Operator -----------");
+        if (Environment.SKIP_STRIMZI_INSTALLATION || ResourceUtils.getKubeResource(Deployment.class, this.deploymentNamespace, this.deploymentName) == null) {
+            LOGGER.warn("Skipping Strimzi deletion. It is already deleted or installation was skipped!");
+            return;
+        }
+
+        // Watch all namespaces CRB
+        KubeResourceManager.get().deleteResource(getStrimziWatchAllCrbs());
+        KubeResourceManager.get().deleteResource(getBundleCrds());
+        KubeResourceManager.get().deleteResource(getBundleClusterRoles());
+        KubeResourceManager.get().deleteResource(getBundleServiceAccount());
+        KubeResourceManager.get().deleteResource(getBundleRoleBindings());
+        KubeResourceManager.get().deleteResource(getBundleClusterRoleBindings());
+        KubeResourceManager.get().deleteResource(getBundleConfigMap());
+        KubeResourceManager.get().deleteResource(getBundleDeployment());
+    }
+
+    private ClusterRoleBinding[] getStrimziWatchAllCrbs() {
+        return new ClusterRoleBinding[]{
+            new ClusterRoleBindingBuilder()
+                .withNewMetadata()
+                    .withName(Constants.STRIMZI_CO_NAME + "-namespaced")
+                .endMetadata()
+                .withNewRoleRef()
+                    .withApiGroup(Constants.RBAC_AUTH_API_GROUP)
+                    .withKind(ResourceKinds.CLUSTER_ROLE)
+                    .withName(Constants.STRIMZI_CO_NAME + "-namespaced")
+                .endRoleRef()
+                .withSubjects(new SubjectBuilder()
+                    .withKind(ResourceKinds.SERVICE_ACCOUNT)
+                    .withName(Constants.STRIMZI_CO_NAME)
+                    .withNamespace(this.deploymentNamespace)
+                    .build())
+                .build(),
+            new ClusterRoleBindingBuilder()
+                .withNewMetadata()
+                    .withName(Constants.STRIMZI_CO_NAME  + "-entity-operator")
+                .endMetadata()
+                .withNewRoleRef()
+                    .withApiGroup(Constants.RBAC_AUTH_API_GROUP)
+                    .withKind(ResourceKinds.CLUSTER_ROLE)
+                    .withName(Constants.STRIMZI_CO_NAME  + "-entity-operator")
+                .endRoleRef()
+                .withSubjects(new SubjectBuilder()
+                    .withKind(ResourceKinds.SERVICE_ACCOUNT)
+                    .withName(Constants.STRIMZI_CO_NAME)
+                    .withNamespace(this.deploymentNamespace)
+                    .build())
+                .build(),
+            new ClusterRoleBindingBuilder()
+                .withNewMetadata()
+                    .withName(Constants.STRIMZI_CO_NAME + "-watched")
+                .endMetadata()
+                .withNewRoleRef()
+                    .withApiGroup(Constants.RBAC_AUTH_API_GROUP)
+                    .withKind(ResourceKinds.CLUSTER_ROLE)
+                    .withName(Constants.STRIMZI_CO_NAME + "-watched")
+                .endRoleRef()
+                .withSubjects(new SubjectBuilder()
+                    .withKind(ResourceKinds.SERVICE_ACCOUNT)
+                    .withName(Constants.STRIMZI_CO_NAME)
+                    .withNamespace(this.deploymentNamespace)
+                    .build())
+                .build()
+        };
+    }
+
+    private ConfigMap getBundleConfigMap() {
+        return new ConfigMapBuilder(TestFrameUtils.configFromYaml(strimziResources.stream()
+            .filter(file -> file.getName().matches(".*050-ConfigMap-.*\\.yaml")).toList().get(0), ConfigMap.class))
path: systemtests/src/main/java/com/github/streamshub/systemtests/setup/StrimziOperatorSetup.java
user: login: jankalinic
body: Sure, i think the regex suits better, when there are multiple resources, but knowing that strimzi resources do not stack each release, i think it might be okay just using startsWith and contains.
created_at: 2025-04-01T10:46:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,71 @@
+package com.github.streamshub.systemtests.constants;
+
+public class Constants {
+    private Constants() {}
+
+    // --------------------------------
+    // ------------ General -----------
+    // --------------------------------
+    /**
+     * Namespaces
+     */
+    public static final String CO_NAMESPACE = "co-namespace";
+    public static final String OPENSHIFT_MARKETPLACE_NAMESPACE = "openshift-marketplace";
+
+    /**
+     * Test values
+     */
+    public static final String USER_USERNAME = "Anonymous";
+
+    /**
+     * Messages
+     */
+    public static final int MESSAGE_COUNT = 1000;
+
+    /**
+     * CRDs
+     */
+    public static final String RBAC_AUTH_API_GROUP = "rbac.authorization.k8s.io";
+
+
+    // --------------------------------
+    // ----------- Strimzi ------------
+    // --------------------------------
+    public static final String STRIMZI_NAME = "strimzi";
+    public static final String STRIMZI_CO_NAME = STRIMZI_NAME + "-cluster-operator";
+    public static final String STRIMZI_NAMESPACE_KEY = "STRIMZI_NAMESPACE";
+    public static final String STRIMZI_WATCH_ALL_NAMESPACES = "*";
+
+    /**
+     * Clients
+     */
+    public static final String PRODUCER = "producer";
+    public static final String CONSUMER = "consumer";
+
+    /**
+     * Topics
+     */
+    public static final String KAFKA_TOPIC_PREFIX = "kt";
+    public static final String CONSUMER_OFFSETS_TOPIC_NAME = "__consumer_offsets";
+
+    /**
+     *  Kafka
+     */
+    public static final String KAFKA_USER_PREFIX = "user";
+    public static final String KAFKA_CLUSTER_PREFIX = "kc";
+    public static final String BROKER_ROLE_PREFIX = "brk";
+    public static final String CONTROLLER_ROLE_PREFIX = "ctrl";
+    public static final int REGULAR_BROKER_REPLICAS = 3;
+
+
+     // --------------------------------
+    // ------------ Console -----------
+    // --------------------------------
+    /**
+     * CRDs
+     */
+    public static final String CONSOLE_CRD_API_NAME = "consoles.console.streamshub.github.com";
+    public static final String CONSOLE_CRD_API_VERSION = "console.streamshub.github.com/v1alpha1";
path: systemtests/src/main/java/com/github/streamshub/systemtests/constants/Constants.java
user: login: jankalinic
body: Okay, i'll change even the other resources, if possible, using HasMetadata. Thanks
created_at: 2025-04-01T11:01:42Z
author_association: CONTRIBUTOR

PR comments:
user: login: jankalinic
created_at: 2025-04-01T09:30:40Z
body: Hopefully last commit added all the fixes for the reviewed bits. If you have time, could you please take a look?
author_association: CONTRIBUTOR
user: login: sonarqubecloud[bot]
created_at: 2025-04-01T13:09:20Z
body: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=streamshub_console&pullRequest=1585) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [1 Security Hotspot](https://sonarcloud.io/project/security_hotspots?id=streamshub_console&pullRequest=1585&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=streamshub_console&pullRequest=1585&metric=new_coverage&view=list) (required ≥ 80%)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=streamshub_console&pullRequest=1585)


author_association: NONE
user: login: jankalinic
created_at: 2025-04-01T13:54:29Z
body: @im-konge Would you have anything against the current state?
author_association: CONTRIBUTOR
user: login: im-konge
created_at: 2025-04-01T14:05:05Z
body: Will have a look now. Sorry
author_association: NONE