Repository: kroxylicious/kroxylicious
Pull request #2108: [System Tests] refactored kroxylicious image repo
Author: login: franvila
Labels: name: test/system-test
description: Relates to System Tests
Created: 2025-04-30T06:11:17Z | Merged: 2025-05-02T11:19:59Z

### Type of change

- Enhancement / new feature

### Description

These changes are required to be able to include the operator image for PRs. With this we can run system tests for PRs included the changes in the operator as well.

### Additional Context


### Checklist

_Please go through this checklist and make sure all applicable tasks have been done_

- [x] PR raised from a fork of this repository and made from a branch rather than main. 
- [x] Write tests
- [x] Update documentation
- [x] Make sure all unit/integration tests pass
- [x] Make sure all Sonarcloud warnings are addressed or are justifiably ignored.
- [x] If applicable to the change, [trigger the system test suite](../blob/main/DEV_GUIDE.md#jenkins-pipeline-for-system-tests).  Make sure tests pass.
- [x] If applicable to the change, [trigger the performance test suite](../blob/main/PERFORMANCE.md#jenkins-pipeline-for-performance). Ensure that any degradations to performance numbers are understood and justified.
- [x] Ensure the PR references relevant issue(s) so they are closed on merging.
- [x] For user facing changes, update CHANGELOG.md (remember to include changes affecting the API of the test artefacts too).

> **_NOTE:_**  You must be a member of `@kroxylicious/developers` to trigger the system test and performance test suites.  If you are not part of this group, comment on the PR requesting a trigger, tagging `@kroxylicious/developers`.



Diff:
diff --git a/DEV_GUIDE.md b/DEV_GUIDE.md
index 6ca1c17727..fdf385f12d 100644
--- a/DEV_GUIDE.md
+++ b/DEV_GUIDE.md
@@ -333,8 +333,14 @@ has been applied ineffectively.
 * [OPTIONAL] aws cli ([install guide](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)): in case an AWS Cloud account is used for KMS.
 
 ### Environment variables
-* `KROXYLICIOUS_IMAGE_REPO`: url to the image of kroxylicious to be used. Default value: `quay.io/kroxylicious/kroxylicious`
+* `KROXYLICIOUS_REGISTRY`: url to the registry where the image of kroxylicious is located. Default value: `quay.io`
+* `KROXYLICIOUS_ORG`: name of the organisation in the registry where kroxylicious is located. Default value: `kroxylicious`
+* `KROXYLICIOUS_IMAGE_NAME`: name of the image of kroxylicious to be used. Default value: `kroxylicious`
+* `KROXYLICIOUS_OPERATOR_REGISTRY`: url to the registry where the image of kroxylicious operator is located. Default value: `quay.io`
+* `KROXYLICIOUS_OPERATOR_ORG`: name of the organisation in the registry where kroxylicious operator is located. Default value: `kroxylicious`
+* `KROXYLICIOUS_OPERATOR_IMAGE_NAME`: name of the image of kroxylicious operator to be used. Default value: `operator`
 * `KROXYLICIOUS_VERSION`: version of kroxylicious to be used. Default value: `${project.version}` in pom file
+* `KROXYLICIOUS_OPERATOR_VERSION`: version of kroxylicious operator to be used. Default value: `${project.version}` in pom file
 * `KAFKA_VERSION`: kafka version to be used. Default value: `${kafka.version}` in pom file
 * `STRIMZI_VERSION`: strimzi version to be used. Default value: `${strimzi.version}` in pom file
 * `STRIMZI_NAMESPACE`: namespace used for strimzi cluster operator installation. Useful when strimzi is previously installed. Default value: `kafka`
diff --git a/kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/Environment.java b/kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/Environment.java
index 4ea39b6797..a89e1c3d25 100644
--- a/kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/Environment.java
+++ b/kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/Environment.java
@@ -34,8 +34,14 @@ private Environment() {
      * Env. variables names
      */
     private static final String KAFKA_VERSION_ENV = "KAFKA_VERSION";
-    private static final String KROXY_VERSION_ENV = "KROXYLICIOUS_VERSION";
-    private static final String KROXY_IMAGE_REPO_ENV = "KROXYLICIOUS_IMAGE_REPO";
+    private static final String KROXYLICIOUS_OPERATOR_IMAGE_ENV = "KROXYLICIOUS_OPERATOR_IMAGE_NAME";
+    private static final String KROXYLICIOUS_IMAGE_ENV = "KROXYLICIOUS_IMAGE_NAME";
+    private static final String KROXYLICIOUS_ORG_ENV = "KROXYLICIOUS_ORG";
+    private static final String KROXYLICIOUS_OPERATOR_ORG_ENV = "KROXYLICIOUS_OPERATOR_ORG";
+    private static final String KROXYLICIOUS_REGISTRY_ENV = "KROXYLICIOUS_REGISTRY";
+    private static final String KROXYLICIOUS_OPERATOR_REGISTRY_ENV = "KROXYLICIOUS_OPERATOR_REGISTRY";
+    private static final String KROXYLICIOUS_VERSION_ENV = "KROXYLICIOUS_VERSION";
+    private static final String KROXYLICIOUS_OPERATOR_VERSION_ENV = "KROXYLICIOUS_OPERATOR_VERSION";
     private static final String SKIP_TEARDOWN_ENV = "SKIP_TEARDOWN";
     private static final String CONTAINER_CONFIG_PATH_ENV = "CONTAINER_CONFIG_PATH";
     private static final String SKIP_STRIMZI_INSTALL_ENV = "SKIP_STRIMZI_INSTALL";
@@ -49,9 +55,6 @@ private Environment() {
     private static final String AWS_KROXYLICIOUS_ACCESS_KEY_ID_ENV = "AWS_KROXYLICIOUS_ACCESS_KEY_ID";
     private static final String AWS_KROXYLICIOUS_SECRET_ACCESS_KEY_ENV = "AWS_KROXYLICIOUS_SECRET_ACCESS_KEY";
     private static final String AWS_REGION_ENV = "AWS_REGION";
-    private static final String KROXY_ORG_ENV = "DOCKER_ORG";
-    private static final String KROXY_REGISTRY_ENV = "DOCKER_REGISTRY";
-    private static final String KROXY_TAG_ENV = "DOCKER_TAG";
 
     /**
      * The kafka version default value
@@ -65,10 +68,10 @@ private Environment() {
     /**
      * The kroxy version default value
      */
-    private static final String KROXY_VERSION_DEFAULT;
+    private static final String KROXYLICIOUS_VERSION_DEFAULT;
 
     static {
-        KROXY_VERSION_DEFAULT = determineKroxyliciousVersion();
+        KROXYLICIOUS_VERSION_DEFAULT = determineKroxyliciousVersion();
     }
 
     /**
@@ -83,15 +86,19 @@ private Environment() {
     /**
      * The url where kroxylicious image lives to be downloaded.
      */
-    private static final String KROXY_IMAGE_REPO_DEFAULT = "quay.io/kroxylicious/kroxylicious";
+    private static final String KROXYLICIOUS_IMAGE_REPO_DEFAULT = "quay.io/kroxylicious/kroxylicious";
+    private static final String KROXYLICIOUS_OPERATOR_IMAGE_REPO_DEFAULT = "quay.io/kroxylicious/operator";
 
     /**
      * The default value for skipping the teardown locally.
      */
     private static final boolean SKIP_TEARDOWN_DEFAULT = false;
-    public static final String KROXY_ORG_DEFAULT = KROXY_IMAGE_REPO_DEFAULT.split("/")[1];
-    public static final String KROXY_TAG_DEFAULT = "latest";
-    public static final String KROXY_REGISTRY_DEFAULT = KROXY_IMAGE_REPO_DEFAULT.split("/")[0];
+    public static final String KROXYLICIOUS_IMAGE_DEFAULT = KROXYLICIOUS_IMAGE_REPO_DEFAULT.split("/")[2];
+    public static final String KROXYLICIOUS_OPERATOR_IMAGE_DEFAULT = KROXYLICIOUS_OPERATOR_IMAGE_REPO_DEFAULT.split("/")[2];
+    public static final String KROXYLICIOUS_ORG_DEFAULT = KROXYLICIOUS_IMAGE_REPO_DEFAULT.split("/")[1];
+    public static final String KROXYLICIOUS_OPERATOR_ORG_DEFAULT = KROXYLICIOUS_OPERATOR_IMAGE_REPO_DEFAULT.split("/")[1];
+    public static final String KROXYLICIOUS_REGISTRY_DEFAULT = KROXYLICIOUS_IMAGE_REPO_DEFAULT.split("/")[0];
+    public static final String KROXYLICIOUS_OPERATOR_REGISTRY_DEFAULT = KROXYLICIOUS_OPERATOR_IMAGE_REPO_DEFAULT.split("/")[0];
     private static final String CONTAINER_CONFIG_PATH_DEFAULT = System.getProperty("user.home") + "/.docker/config.json";
     private static final boolean SKIP_STRIMZI_INSTALL_DEFAULT = false;
     private static final String KAFKA_CLIENT_DEFAULT = "strimzi_test_client";
@@ -109,14 +116,11 @@ private Environment() {
     public static final String KAFKA_VERSION = ENVIRONMENT_VARIABLES.getOrDefault(KAFKA_VERSION_ENV, KAFKA_VERSION_DEFAULT);
 
     /**
-     * KROXY_VERSION env variable assignment
+     * KROXYLICIOUS_VERSION env variable assignment
      */
-    public static final String KROXY_VERSION = ENVIRONMENT_VARIABLES.getOrDefault(KROXY_VERSION_ENV, KROXY_VERSION_DEFAULT);
+    public static final String KROXYLICIOUS_VERSION = ENVIRONMENT_VARIABLES.getOrDefault(KROXYLICIOUS_VERSION_ENV, KROXYLICIOUS_VERSION_DEFAULT);
+    public static final String KROXYLICIOUS_OPERATOR_VERSION = ENVIRONMENT_VARIABLES.getOrDefault(KROXYLICIOUS_OPERATOR_VERSION_ENV, KROXYLICIOUS_VERSION_DEFAULT);
 
-    /**
-     * KROXY_IMAGE_REPO env variable assignment
-     */
-    public static final String KROXY_IMAGE_REPO = ENVIRONMENT_VARIABLES.getOrDefault(KROXY_IMAGE_REPO_ENV, KROXY_IMAGE_REPO_DEFAULT);
     /**
      * SKIP_TEARDOWN env variable assignment.
      */
@@ -148,9 +152,13 @@ private Environment() {
 
     public static final String AWS_REGION = ENVIRONMENT_VARIABLES.getOrDefault(AWS_REGION_ENV, AWS_REGION_DEFAULT);
 
-    public static final String KROXY_ORG = ENVIRONMENT_VARIABLES.getOrDefault(KROXY_ORG_ENV, KROXY_ORG_DEFAULT);
-    public static final String KROXY_TAG = ENVIRONMENT_VARIABLES.getOrDefault(KROXY_TAG_ENV, KROXY_TAG_DEFAULT);
-    public static final String KROXY_REGISTRY = ENVIRONMENT_VARIABLES.getOrDefault(KROXY_REGISTRY_ENV, KROXY_REGISTRY_DEFAULT);
+    public static final String KROXYLICIOUS_IMAGE = ENVIRONMENT_VARIABLES.getOrDefault(KROXYLICIOUS_IMAGE_ENV, KROXYLICIOUS_IMAGE_DEFAULT);
+    public static final String KROXYLICIOUS_OPERATOR_IMAGE = ENVIRONMENT_VARIABLES.getOrDefault(KROXYLICIOUS_OPERATOR_IMAGE_ENV, KROXYLICIOUS_OPERATOR_IMAGE_DEFAULT);
+    public static final String KROXYLICIOUS_ORG = ENVIRONMENT_VARIABLES.getOrDefault(KROXYLICIOUS_ORG_ENV, KROXYLICIOUS_ORG_DEFAULT);
+    public static final String KROXYLICIOUS_OPERATOR_ORG = ENVIRONMENT_VARIABLES.getOrDefault(KROXYLICIOUS_OPERATOR_ORG_ENV, KROXYLICIOUS_OPERATOR_ORG_DEFAULT);
+    public static final String KROXYLICIOUS_REGISTRY = ENVIRONMENT_VARIABLES.getOrDefault(KROXYLICIOUS_REGISTRY_ENV, KROXYLICIOUS_REGISTRY_DEFAULT);
+    public static final String KROXYLICIOUS_OPERATOR_REGISTRY = ENVIRONMENT_VARIABLES.getOrDefault(KROXYLICIOUS_OPERATOR_REGISTRY_ENV,
+            KROXYLICIOUS_OPERATOR_REGISTRY_DEFAULT);
 
     private static String readMetadataProperty(String property) {
         var p = new Properties();
diff --git a/kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/resources/operator/KroxyliciousOperatorBundleInstaller.java b/kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/resources/operator/KroxyliciousOperatorBundleInstaller.java
index ceab83fa83..8894c3d3b0 100644
--- a/kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/resources/operator/KroxyliciousOperatorBundleInstaller.java
+++ b/kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/resources/operator/KroxyliciousOperatorBundleInstaller.java
@@ -30,13 +30,13 @@
 import io.skodjob.testframe.enums.InstallType;
 import io.skodjob.testframe.installation.InstallationMethod;
 import io.skodjob.testframe.resources.KubeResourceManager;
-import io.skodjob.testframe.utils.ImageUtils;
 import io.skodjob.testframe.utils.TestFrameUtils;
 
 import io.kroxylicious.systemtests.Constants;
 import io.kroxylicious.systemtests.Environment;
 import io.kroxylicious.systemtests.k8s.KubeClusterResource;
 import io.kroxylicious.systemtests.utils.DeploymentUtils;
+import io.kroxylicious.systemtests.utils.TestUtils;
 
 import static io.kroxylicious.systemtests.k8s.KubeClusterResource.kubeClient;
 
@@ -138,7 +138,8 @@ private void applyDeploymentFile() {
                 .endMetadata()
                 .editSpec()
                 .editFirstContainer()
-                .withImage(ImageUtils.changeRegistryOrgAndTag(deploymentImage, Environment.KROXY_REGISTRY, Environment.KROXY_ORG, Environment.KROXY_TAG))
+                .withImage(TestUtils.changeRegistryOrgImageAndTag(deploymentImage, Environment.KROXYLICIOUS_OPERATOR_REGISTRY,
+                        Environment.KROXYLICIOUS_OPERATOR_ORG, Environment.KROXYLICIOUS_OPERATOR_IMAGE, Environment.KROXYLICIOUS_OPERATOR_VERSION))
                 .withImagePullPolicy(Constants.PULL_IMAGE_IF_NOT_PRESENT)
                 .endContainer()
                 .withImagePullSecrets(new LocalObjectReferenceBuilder()
diff --git a/kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/templates/metrics/ScraperTemplates.java b/kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/templates/metrics/ScraperTemplates.java
index 04483dee25..aa505c21c7 100644
--- a/kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/templates/metrics/ScraperTemplates.java
+++ b/kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/templates/metrics/ScraperTemplates.java
@@ -26,8 +26,9 @@ public static DeploymentBuilder scraperPod(String namespaceName, String podName)
 
         label.put(Constants.SCRAPER_LABEL_KEY, Constants.SCRAPER_LABEL_VALUE);
         label.put(Constants.DEPLOYMENT_TYPE, Constants.SCRAPER_NAME);
-        String kroxyRepoUrl = Environment.KROXY_IMAGE_REPO + (Environment.KROXY_IMAGE_REPO.endsWith(":") ? "" : ":");
-        String scraperImage = kroxyRepoUrl + Environment.KROXY_VERSION;
+        String kroxyRepoUrl = Environment.KROXYLICIOUS_REGISTRY + "/" + Environment.KROXYLICIOUS_ORG + "/" + Environment.KROXYLICIOUS_IMAGE
+                + (Environment.KROXYLICIOUS_IMAGE.endsWith(":") ? "" : ":");
+        String scraperImage = kroxyRepoUrl + Environment.KROXYLICIOUS_VERSION;
 
         return new DeploymentBuilder()
                 .withNewMetadata()
diff --git a/kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/utils/TestUtils.java b/kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/utils/TestUtils.java
index c52b1aed0d..7e79770ac0 100644
--- a/kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/utils/TestUtils.java
+++ b/kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/utils/TestUtils.java
@@ -16,6 +16,11 @@
 import java.nio.file.attribute.PosixFilePermission;
 import java.nio.file.attribute.PosixFilePermissions;
 import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 
@@ -26,7 +31,10 @@
  * The type Test utils.
  */
 public class TestUtils {
+    private static final Logger LOGGER = LoggerFactory.getLogger(TestUtils.class);
     private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+    private static final Pattern IMAGE_PATTERN_FULL_PATH = Pattern.compile("^(?<registry>[^/]*)/(?<org>[^/]*)/(?<image>[^:]*):(?<tag>.*)$");
+    private static final Pattern IMAGE_PATTERN = Pattern.compile("^(?<org>[^/]*)/(?<image>[^:]*):(?<tag>.*)$");
 
     private TestUtils() {
     }
@@ -104,4 +112,50 @@ public static String getJsonFileContent(String fileName) {
             throw new UncheckedIOException(e);
         }
     }
+
+    // TO BE REMOVED when introduced in ImageUtils from TestFrame project
+
+    /**
+     * Change registry org image and tag.
+     *
+     * @param imageRepo the image repo
+     * @param newRegistry the new registry
+     * @param newOrg the new org
+     * @param newImage the new image
+     * @param newTag the new tag
+     * @return the string
+     */
+    public static String changeRegistryOrgImageAndTag(String imageRepo, String newRegistry, String newOrg, String newImage, String newTag) {
+        Matcher m = IMAGE_PATTERN_FULL_PATH.matcher(imageRepo);
+        if (m.find()) {
+            String registry = setImagePropertiesIfNeeded(m.group("registry"), newRegistry);
+            String org = setImagePropertiesIfNeeded(m.group("org"), newOrg);
+            String tag = setImagePropertiesIfNeeded(m.group("tag"), newTag);
+            String image = setImagePropertiesIfNeeded(m.group("image"), newImage);
+
+            String newImageRepo = registry + "/" + org + "/" + image + ":" + tag;
+            LOGGER.info("Updating container image to {}", newImageRepo);
+            return newImageRepo;
+        }
+        else {
+            m = IMAGE_PATTERN.matcher(imageRepo);
+            if (m.find()) {
+                String registry = newRegistry != null ? newRegistry + "/" : "";
+                String org = setImagePropertiesIfNeeded(m.group("org"), newOrg);
+                String tag = setImagePropertiesIfNeeded(m.group("tag"), newTag);
+                String image = setImagePropertiesIfNeeded(m.group("image"), newImage);
+
+                String newImageRepo = registry + org + "/" + image + ":" + tag;
+                LOGGER.info("Updating container image to {}", newImageRepo);
+                return newImageRepo;
+            }
+            else {
+                return imageRepo;
+            }
+        }
+    }
+
+    private static String setImagePropertiesIfNeeded(String currentValue, String newValue) {
+        return newValue != null && !newValue.isEmpty() && !currentValue.equals(newValue) ? newValue : currentValue;
+    }
 }


Reviews:
user: login: k-wall
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-02T08:53:57Z
user: login: franvila
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-02T08:56:11Z
user: login: k-wall
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-02T08:58:50Z
user: login: franvila
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-02T09:02:22Z
user: login: k-wall
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-02T09:04:15Z
user: login: k-wall
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-02T09:05:41Z
user: login: k-wall
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-02T09:15:05Z
user: login: franvila
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-02T09:19:18Z
user: login: k-wall
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-02T09:22:11Z
user: login: franvila
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-02T09:29:26Z
user: login: franvila
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-02T09:30:09Z
user: login: k-wall
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-02T09:36:18Z
user: login: k-wall
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-02T11:05:13Z
user: login: k-wall
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-02T11:06:44Z
user: login: franvila
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-02T11:08:59Z
user: login: k-wall
body: Approving to allow forward progress to be made.
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-02T11:11:12Z
user: login: k-wall
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-02T11:15:20Z

Review comments:
diff_hunk: @@ -34,8 +34,11 @@ private Environment() {
      * Env. variables names
      */
     private static final String KAFKA_VERSION_ENV = "KAFKA_VERSION";
+    private static final String KROXY_OPERATOR_IMAGE_ENV = "KROXYLICIOUS_OPERATOR_IMAGE_NAME";
path: kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/Environment.java
user: login: k-wall
body: nit: can we use the full name KROXYLICIOUS rather than KROXY. The name Kroxy belongs to someone else. 
created_at: 2025-05-02T08:53:57Z
author_association: MEMBER
diff_hunk: @@ -34,8 +34,11 @@ private Environment() {
      * Env. variables names
      */
     private static final String KAFKA_VERSION_ENV = "KAFKA_VERSION";
+    private static final String KROXY_OPERATOR_IMAGE_ENV = "KROXYLICIOUS_OPERATOR_IMAGE_NAME";
path: kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/Environment.java
user: login: franvila
body: sure, I'll change that

created_at: 2025-05-02T08:56:11Z
author_association: MEMBER
diff_hunk: @@ -89,8 +89,9 @@ private Environment() {
      * The default value for skipping the teardown locally.
      */
     private static final boolean SKIP_TEARDOWN_DEFAULT = false;
+    public static final String KROXY_IMAGE_DEFAULT = KROXY_IMAGE_REPO_DEFAULT.split("/")[2];
+    public static final String KROXY_OPERATOR_IMAGE_DEFAULT = "operator";
path: kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/Environment.java
user: login: k-wall
body: Why do you handle the default for the kroxylicious operand image and the operator image in a different way?
created_at: 2025-05-02T08:58:50Z
author_association: MEMBER
diff_hunk: @@ -89,8 +89,9 @@ private Environment() {
      * The default value for skipping the teardown locally.
      */
     private static final boolean SKIP_TEARDOWN_DEFAULT = false;
+    public static final String KROXY_IMAGE_DEFAULT = KROXY_IMAGE_REPO_DEFAULT.split("/")[2];
+    public static final String KROXY_OPERATOR_IMAGE_DEFAULT = "operator";
path: kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/Environment.java
user: login: franvila
body: because we don't have a default image repo for operator as it comes from the yaml file of the operator installation.
created_at: 2025-05-02T09:02:22Z
author_association: MEMBER
diff_hunk: @@ -138,7 +138,8 @@ private void applyDeploymentFile() {
                 .endMetadata()
                 .editSpec()
                 .editFirstContainer()
-                .withImage(ImageUtils.changeRegistryOrgAndTag(deploymentImage, Environment.KROXY_REGISTRY, Environment.KROXY_ORG, Environment.KROXY_TAG))
+                .withImage(TestUtils.changeRegistryOrgImageAndTag(deploymentImage, Environment.KROXY_REGISTRY,
path: kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/resources/operator/KroxyliciousOperatorBundleInstaller.java
user: login: k-wall
body: I think it would be better if the operator and operand image were fully independent of one and other.  Here you are building the operator image from parts of the operand image url.
created_at: 2025-05-02T09:04:15Z
author_association: MEMBER
diff_hunk: @@ -89,8 +89,9 @@ private Environment() {
      * The default value for skipping the teardown locally.
      */
     private static final boolean SKIP_TEARDOWN_DEFAULT = false;
+    public static final String KROXY_IMAGE_DEFAULT = KROXY_IMAGE_REPO_DEFAULT.split("/")[2];
path: kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/Environment.java
user: login: k-wall
body: Maybe if you adopted the naming:

KROXYLICIOUS_OPERATOR...
KROXYLICIOUS_OPERAND...

it would be really clear which is which.


created_at: 2025-05-02T09:05:41Z
author_association: MEMBER
diff_hunk: @@ -104,4 +112,50 @@ public static String getJsonFileContent(String fileName) {
             throw new UncheckedIOException(e);
         }
     }
+
+    // TO BE REMOVED when introduced in ImageUtils from TestFrame project
path: kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/utils/TestUtils.java
user: login: k-wall
body: Non blocking: DockerImageName from Testcontainers is has a much nicer API and. is more functionally complete than the class from TestFrame.
created_at: 2025-05-02T09:15:04Z
author_association: MEMBER
diff_hunk: @@ -138,7 +138,8 @@ private void applyDeploymentFile() {
                 .endMetadata()
                 .editSpec()
                 .editFirstContainer()
-                .withImage(ImageUtils.changeRegistryOrgAndTag(deploymentImage, Environment.KROXY_REGISTRY, Environment.KROXY_ORG, Environment.KROXY_TAG))
+                .withImage(TestUtils.changeRegistryOrgImageAndTag(deploymentImage, Environment.KROXY_REGISTRY,
path: kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/resources/operator/KroxyliciousOperatorBundleInstaller.java
user: login: franvila
body: I supposed that both operator and operand images would be in the same repository, but if that couldn't be the case we should split it yes

created_at: 2025-05-02T09:19:18Z
author_association: MEMBER
diff_hunk: @@ -138,7 +138,8 @@ private void applyDeploymentFile() {
                 .endMetadata()
                 .editSpec()
                 .editFirstContainer()
-                .withImage(ImageUtils.changeRegistryOrgAndTag(deploymentImage, Environment.KROXY_REGISTRY, Environment.KROXY_ORG, Environment.KROXY_TAG))
+                .withImage(TestUtils.changeRegistryOrgImageAndTag(deploymentImage, Environment.KROXY_REGISTRY,
path: kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/resources/operator/KroxyliciousOperatorBundleInstaller.java
user: login: k-wall
body: It is better if we split them.  As a developer you want the flexibility.  You might be testing a home spun operator with a published operand.  
created_at: 2025-05-02T09:22:11Z
author_association: MEMBER
diff_hunk: @@ -89,8 +89,9 @@ private Environment() {
      * The default value for skipping the teardown locally.
      */
     private static final boolean SKIP_TEARDOWN_DEFAULT = false;
+    public static final String KROXY_IMAGE_DEFAULT = KROXY_IMAGE_REPO_DEFAULT.split("/")[2];
path: kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/Environment.java
user: login: franvila
body: I would prefer to remain old names to avoid refactoring all Jenkins jobs to adapt it to that new change.
created_at: 2025-05-02T09:29:26Z
author_association: MEMBER
diff_hunk: @@ -104,4 +112,50 @@ public static String getJsonFileContent(String fileName) {
             throw new UncheckedIOException(e);
         }
     }
+
+    // TO BE REMOVED when introduced in ImageUtils from TestFrame project
path: kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/utils/TestUtils.java
user: login: franvila
body: Maybe we can add this functionality of test containers to the test frame as well
created_at: 2025-05-02T09:30:09Z
author_association: MEMBER
diff_hunk: @@ -89,8 +89,9 @@ private Environment() {
      * The default value for skipping the teardown locally.
      */
     private static final boolean SKIP_TEARDOWN_DEFAULT = false;
+    public static final String KROXY_IMAGE_DEFAULT = KROXY_IMAGE_REPO_DEFAULT.split("/")[2];
+    public static final String KROXY_OPERATOR_IMAGE_DEFAULT = "operator";
path: kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/Environment.java
user: login: k-wall
body: You are much closer to the problem than me, but I _think_ I have the system tests unconditionally replace the image reference in the deployment.  That we we can point the system tests at any operator image and any operand image.

In my mind the system tests should have just two environment inputs:

KROXYLICIOUS_OPERATOR_IMAGE
KROXYLICIOUS_OPERAND_IMAGE

which default to quay.....:latest, so the system tests run from the IDE without change.
Jenkins PR builds both images and sets the two env vars.



created_at: 2025-05-02T09:36:18Z
author_association: MEMBER
diff_hunk: @@ -89,8 +89,9 @@ private Environment() {
      * The default value for skipping the teardown locally.
      */
     private static final boolean SKIP_TEARDOWN_DEFAULT = false;
+    public static final String KROXY_IMAGE_DEFAULT = KROXY_IMAGE_REPO_DEFAULT.split("/")[2];
path: kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/Environment.java
user: login: k-wall
body: Okay.
created_at: 2025-05-02T11:05:13Z
author_association: MEMBER
diff_hunk: @@ -104,4 +112,50 @@ public static String getJsonFileContent(String fileName) {
             throw new UncheckedIOException(e);
         }
     }
+
+    // TO BE REMOVED when introduced in ImageUtils from TestFrame project
path: kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/utils/TestUtils.java
user: login: k-wall
body: Yeah, that's probably what I would do.  Testframe's API fluent style API is much nicer.  static methods are to be avoided.
created_at: 2025-05-02T11:06:44Z
author_association: MEMBER
diff_hunk: @@ -104,4 +112,50 @@ public static String getJsonFileContent(String fileName) {
             throw new UncheckedIOException(e);
         }
     }
+
+    // TO BE REMOVED when introduced in ImageUtils from TestFrame project
path: kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/utils/TestUtils.java
user: login: franvila
body: The change maintaining the way it is coded in Test frame is done and merged, but to remove the code added in this PR we need to wait until a new version of Test Frame is released
created_at: 2025-05-02T11:08:59Z
author_association: MEMBER
diff_hunk: @@ -89,8 +89,9 @@ private Environment() {
      * The default value for skipping the teardown locally.
      */
     private static final boolean SKIP_TEARDOWN_DEFAULT = false;
+    public static final String KROXY_IMAGE_DEFAULT = KROXY_IMAGE_REPO_DEFAULT.split("/")[2];
+    public static final String KROXY_OPERATOR_IMAGE_DEFAULT = "operator";
path: kroxylicious-systemtests/src/main/java/io/kroxylicious/systemtests/Environment.java
user: login: k-wall
body: In general it is worth minimizing the number of switches/levers any system has. The number of paths through the system explodes and it makes (my) brain hurt. So. I think evolving to a simpler API would be desirable, in long term. (non-blocking).
created_at: 2025-05-02T11:15:20Z
author_association: MEMBER

PR comments:
user: login: franvila
created_at: 2025-04-30T06:12:48Z
body: @kroxylicious-robot run system tests
author_association: MEMBER
user: login: kroxylicious-robot
created_at: 2025-04-30T07:04:39Z
body: :arrow_forward: **Build started** - check Jenkins for more info. :arrow_forward:
author_association: CONTRIBUTOR
user: login: kroxylicious-robot
created_at: 2025-04-30T07:46:37Z
body: ### :heavy_check_mark: Test Summary :heavy_check_mark:
**BUILD NUMBER:** 2
**KAFKA VERSION:** 3.9.0
**TOTAL:** 31
**PASS:** 21
**FAIL:** 0
**SKIP:** 10

author_association: CONTRIBUTOR
user: login: kroxylicious-robot
created_at: 2025-04-30T08:13:58Z
body: :arrow_forward: **Build started** - check Jenkins for more info. :arrow_forward:
author_association: CONTRIBUTOR
user: login: kroxylicious-robot
created_at: 2025-04-30T08:24:03Z
body: :heavy_exclamation_mark: **System tests Failed (no tests results are present)** :heavy_exclamation_mark:
author_association: CONTRIBUTOR
user: login: kroxylicious-robot
created_at: 2025-04-30T08:59:30Z
body: :arrow_forward: **Build started** - check Jenkins for more info. :arrow_forward:
author_association: CONTRIBUTOR
user: login: kroxylicious-robot
created_at: 2025-04-30T09:43:34Z
body: ### :heavy_check_mark: Test Summary :heavy_check_mark:
**BUILD NUMBER:** 5
**KAFKA VERSION:** 3.9.0
**TOTAL:** 31
**PASS:** 21
**FAIL:** 0
**SKIP:** 10

author_association: CONTRIBUTOR
user: login: franvila
created_at: 2025-05-02T10:20:47Z
body: @kroxylicious-robot run system tests
author_association: MEMBER
user: login: kroxylicious-robot
created_at: 2025-05-02T10:22:12Z
body: :arrow_forward: **Build started** - check Jenkins for more info. :arrow_forward:
author_association: CONTRIBUTOR
user: login: kroxylicious-robot
created_at: 2025-05-02T10:23:47Z
body: :arrow_forward: **Build started** - check Jenkins for more info. :arrow_forward:
author_association: CONTRIBUTOR
user: login: sonarqubecloud[bot]
created_at: 2025-05-02T10:45:46Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=kroxylicious_kroxylicious&pullRequest=2108) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=kroxylicious_kroxylicious&pullRequest=2108&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=kroxylicious_kroxylicious&pullRequest=2108&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=kroxylicious_kroxylicious&pullRequest=2108&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=kroxylicious_kroxylicious&pullRequest=2108&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=kroxylicious_kroxylicious&pullRequest=2108&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=kroxylicious_kroxylicious&pullRequest=2108)


author_association: NONE
user: login: kroxylicious-robot
created_at: 2025-05-02T11:05:40Z
body: ### :heavy_check_mark: Test Summary :heavy_check_mark:
**BUILD NUMBER:** 1
**KAFKA VERSION:** 3.9.0
**TOTAL:** 31
**PASS:** 21
**FAIL:** 0
**SKIP:** 10

author_association: CONTRIBUTOR
user: login: kroxylicious-robot
created_at: 2025-05-02T11:27:37Z
body: ### :x: Test Summary :x:
**BUILD NUMBER:** 226
**KAFKA VERSION:** 3.9.0
**TOTAL:** 31
**PASS:** 17
**FAIL:** 4
**SKIP:** 10
### :heavy_exclamation_mark: Test Failures :heavy_exclamation_mark:
- kroxyliciousMetricsBeforeSendingMessages in io.kroxylicious.systemtests.MetricsST
- produceAndConsumeMessageWithRotatedKEK(String, TestKmsFacade) KubeLocalStackTestKmsFacade in io.kroxylicious.systemtests.RecordEncryptionST

**Re-run command**:
@strimzi-ci run system tests
author_association: CONTRIBUTOR