From 34ea2ca90fa157482bd3ccad824d70464208d6ea Mon Sep 17 00:00:00 2001 From: jkalinic Date: Fri, 24 Jul 2026 14:11:57 +0200 Subject: [PATCH 1/5] yaml upgrade to head Signed-off-by: jkalinic --- .../streamshub/systemtests/Environment.java | 15 +++ .../systemtests/setup/console/OlmConfig.java | 6 +- .../VersionModificationDataLoader.java | 96 +++++++++++++++++++ .../upgrade/YamlVersionModificationData.java | 8 ++ .../systemtests/utils/FileUtils.java | 24 +++++ .../test/resources/upgrade/YamlUpgrade.yaml | 10 +- 6 files changed, 150 insertions(+), 9 deletions(-) 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 6ba58bbef..87eef2f5f 100644 --- a/systemtests/src/main/java/com/github/streamshub/systemtests/Environment.java +++ b/systemtests/src/main/java/com/github/streamshub/systemtests/Environment.java @@ -3,6 +3,9 @@ import java.io.IOException; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; +import java.util.Locale; +import java.util.Optional; +import java.util.function.Predicate; import org.apache.logging.log4j.Logger; @@ -113,6 +116,18 @@ public static boolean isOlmInstall() { return CONSOLE_INSTALL_TYPE.equals(InstallType.Olm); } + /** + * Resolves the Console Operator version under test: {@link #CONSOLE_OPERATOR_VERSION} if set, + * otherwise the {@code operator.version} system property (populated by the Maven build with + * the current {@code project.version} — see systemtests/pom.xml), lowercased. Empty if neither + * is set. + */ + public static String getConsoleOperatorVersion() { + return Optional.of(CONSOLE_OPERATOR_VERSION) + .filter(Predicate.not(String::isBlank)) + .orElseGet(() -> System.getProperty("operator.version", "").toLowerCase(Locale.ROOT)); + } + public static boolean isTestClientsPullSecretPresent() { return !Environment.TEST_CLIENTS_PULL_SECRET.isEmpty(); } diff --git a/systemtests/src/main/java/com/github/streamshub/systemtests/setup/console/OlmConfig.java b/systemtests/src/main/java/com/github/streamshub/systemtests/setup/console/OlmConfig.java index 3c4b0e6ce..1afb997e9 100644 --- a/systemtests/src/main/java/com/github/streamshub/systemtests/setup/console/OlmConfig.java +++ b/systemtests/src/main/java/com/github/streamshub/systemtests/setup/console/OlmConfig.java @@ -3,7 +3,6 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; @@ -121,10 +120,7 @@ public void delete() { public OlmVersionModificationData getUpgradeData() { maybeCreateCatalogSource(); - String newVersion = Optional.of(Environment.CONSOLE_OPERATOR_VERSION) - .filter(Predicate.not(String::isBlank)) - .orElseGet(() -> System.getProperty("operator.version", "") - .toLowerCase(Locale.ROOT)); + String newVersion = Environment.getConsoleOperatorVersion(); String[] newVersionElements = newVersion.split("[.-]"); var newChannelSemVer = Version.of( diff --git a/systemtests/src/main/java/com/github/streamshub/systemtests/upgrade/VersionModificationDataLoader.java b/systemtests/src/main/java/com/github/streamshub/systemtests/upgrade/VersionModificationDataLoader.java index a1be6a56e..ae080fa10 100644 --- a/systemtests/src/main/java/com/github/streamshub/systemtests/upgrade/VersionModificationDataLoader.java +++ b/systemtests/src/main/java/com/github/streamshub/systemtests/upgrade/VersionModificationDataLoader.java @@ -2,12 +2,21 @@ import java.io.File; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import com.github.streamshub.systemtests.Environment; +import com.github.streamshub.systemtests.exceptions.SetupException; +import com.github.streamshub.systemtests.utils.FileUtils; public class VersionModificationDataLoader { public enum InstallType { @@ -18,6 +27,16 @@ public enum InstallType { private static final String UPGRADE_FILE_PATH = System.getProperty("user.dir") + "/src/test/resources/upgrade/"; private static final String YAML_UPGRADE_FILE = UPGRADE_FILE_PATH + "YamlUpgrade.yaml"; + // Output produced by a normal build in .github/workflows/release.yml, which joins the same two files into release operator YAML bundle. + private static final String OPERATOR_KUBERNETES_DIR = System.getProperty("user.dir") + "/../operator/target/kubernetes/"; + private static final Path OPERATOR_CRD_FILE = Paths.get(OPERATOR_KUBERNETES_DIR, "consoles.console.streamshub.github.com-v1.yml"); + private static final Path OPERATOR_RESOURCES_FILE = Paths.get(OPERATOR_KUBERNETES_DIR, "kubernetes.yml"); + + private static final Pattern VERSION_LABEL_PATTERN = Pattern.compile("app\\.kubernetes\\.io/version:\\s*\"?([\\w.-]+)\"?"); + + // Literal upgrade value for 'newOperatorVersion'/'newOperatorCrdsUrl' in YamlUpgrade.yaml - uses the local build + private static final String HEAD_VERSION = "HEAD"; + private YamlVersionModificationData yamlUpgradeData; public VersionModificationDataLoader(InstallType upgradeType) { @@ -32,6 +51,7 @@ private void loadYamlUpgradeData() { try { ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); this.yamlUpgradeData = mapper.readValue(new File(YAML_UPGRADE_FILE), YamlVersionModificationData.class); + resolveNewOperatorData(yamlUpgradeData); LOGGER.info("Loaded Yaml upgrade data: operator version {} -> {}", yamlUpgradeData.getOldOperatorVersion(), yamlUpgradeData.getNewOperatorVersion()); } catch (IOException e) { @@ -40,6 +60,82 @@ private void loadYamlUpgradeData() { } } + /** + * Resolves {@code newOperatorVersion}/{@code newOperatorCrdsUrl} on the given data object. + * + *

If both are set to the literal value {@value #HEAD_VERSION} in the loaded YAML file, + * they are auto-derived from {@link Environment#getConsoleOperatorVersion()} and the local operator + * build output. If both are set to anything else (non-blank, non-head), they are left untouched. + * Any other combination (blank, missing, or a head explicit mismatch) is treated as a broken config. + */ + private void resolveNewOperatorData(YamlVersionModificationData data) { + String newOperatorVersion = data.getNewOperatorVersion(); + String newOperatorCrdsUrl = data.getNewOperatorCrdsUrl(); + + boolean versionExplicit = newOperatorVersion != null && !newOperatorVersion.isBlank() && !HEAD_VERSION.equals(newOperatorVersion); + boolean urlExplicit = newOperatorCrdsUrl != null && !newOperatorCrdsUrl.isBlank() && !HEAD_VERSION.equals(newOperatorCrdsUrl); + + if (versionExplicit && urlExplicit) { + LOGGER.info("Using explicit new operator version '{}' and bundle '{}' from {}", + newOperatorVersion, newOperatorCrdsUrl, YAML_UPGRADE_FILE); + return; + } + + boolean versionSentinel = HEAD_VERSION.equals(newOperatorVersion); + boolean urlSentinel = HEAD_VERSION.equals(newOperatorCrdsUrl); + + if (!(versionSentinel && urlSentinel)) { + throw new SetupException("YamlUpgrade.yaml's 'newOperatorVersion' and 'newOperatorCrdsUrl' must either both be set to the " + + "literal value '" + HEAD_VERSION + "' (to auto-derive them from the local build) or both be set to explicit. " + + "Found newOperatorVersion='" + newOperatorVersion + "', newOperatorCrdsUrl='" + newOperatorCrdsUrl + "'."); + } + + LOGGER.info("New operator version/bundle set to '{}' in {}, auto-deriving from the local build", HEAD_VERSION, YAML_UPGRADE_FILE); + + String derivedVersion = Environment.getConsoleOperatorVersion(); + if (derivedVersion.isBlank()) { + throw new SetupException("Cannot auto-derive the new Console Operator version: set the CONSOLE_OPERATOR_VERSION environment " + + "variable (or the 'operator.version' system property), or specify 'newOperatorVersion'/'newOperatorCrdsUrl' explicitly in " + + YAML_UPGRADE_FILE); + } + + if (Files.notExists(OPERATOR_CRD_FILE) || Files.notExists(OPERATOR_RESOURCES_FILE)) { + throw new SetupException("Local Console Operator build output not found at '" + OPERATOR_CRD_FILE + "' and '" + + OPERATOR_RESOURCES_FILE + "'. Build the operator module first before running tests."); + } + + String actualVersion; + Path mergedBundle; + try { + actualVersion = extractOperatorVersionLabel(Files.readString(OPERATOR_RESOURCES_FILE)); + mergedBundle = FileUtils.mergeYamlFiles(List.of(OPERATOR_CRD_FILE, OPERATOR_RESOURCES_FILE)); + } catch (IOException e) { + throw new SetupException("Failed to read/merge local Console Operator build output", e); + } + + if (!derivedVersion.equals(actualVersion)) { + throw new SetupException("Local Console Operator build output at '" + OPERATOR_RESOURCES_FILE + + "' has version '" + actualVersion + "' but the expected new operator version is '" + derivedVersion + + "' (from CONSOLE_OPERATOR_VERSION/operator.version). Rebuild the operator module for the expected version."); + } + + data.setNewOperatorVersion(derivedVersion); + data.setNewOperatorCrdsUrl(mergedBundle.toAbsolutePath().toString()); + LOGGER.info("Auto-derived new operator version '{}' from local build bundle '{}'", derivedVersion, mergedBundle); + } + + /** + * Extracts the value of the first {@code app.kubernetes.io/version} label found in the given + * YAML text. Package-private so it can be unit tested directly without a full local build. + */ + static String extractOperatorVersionLabel(String yamlContent) { + Matcher matcher = VERSION_LABEL_PATTERN.matcher(yamlContent); + if (!matcher.find()) { + throw new SetupException("Could not find an 'app.kubernetes.io/version' label in the locally built Console Operator YAML bundle"); + } + return matcher.group(1); + } + public YamlVersionModificationData getYamlUpgradeData() { return yamlUpgradeData; } diff --git a/systemtests/src/main/java/com/github/streamshub/systemtests/upgrade/YamlVersionModificationData.java b/systemtests/src/main/java/com/github/streamshub/systemtests/upgrade/YamlVersionModificationData.java index c4c18e8fd..fc898dfd5 100644 --- a/systemtests/src/main/java/com/github/streamshub/systemtests/upgrade/YamlVersionModificationData.java +++ b/systemtests/src/main/java/com/github/streamshub/systemtests/upgrade/YamlVersionModificationData.java @@ -14,6 +14,10 @@ public String getNewOperatorVersion() { return newOperatorVersion; } + public void setNewOperatorVersion(String newOperatorVersion) { + this.newOperatorVersion = newOperatorVersion; + } + public String getOldOperatorCrdsUrl() { return oldOperatorCrdsUrl; } @@ -21,4 +25,8 @@ public String getOldOperatorCrdsUrl() { public String getNewOperatorCrdsUrl() { return newOperatorCrdsUrl; } + + public void setNewOperatorCrdsUrl(String newOperatorCrdsUrl) { + this.newOperatorCrdsUrl = newOperatorCrdsUrl; + } } diff --git a/systemtests/src/main/java/com/github/streamshub/systemtests/utils/FileUtils.java b/systemtests/src/main/java/com/github/streamshub/systemtests/utils/FileUtils.java index 13ba91570..74ed86ffd 100644 --- a/systemtests/src/main/java/com/github/streamshub/systemtests/utils/FileUtils.java +++ b/systemtests/src/main/java/com/github/streamshub/systemtests/utils/FileUtils.java @@ -182,5 +182,29 @@ public static InputStream loadYamlsFromPath(Path targetPath) throws IOException return new ByteArrayInputStream(combined.toByteArray()); } + + /** + * Concatenates the given files' raw contents, in order, into a single new temporary file — + * equivalent to {@code cat file1 file2 > merged}. Unlike {@link #loadYamlsFromPath(Path)}, this + * does not insert `---` separators between files, since the inputs (e.g. generated Kubernetes + * manifests) already contain their own document separators where needed. + * + * @param files ordered list of files to concatenate + * @return path to the merged temporary file + * @throws IOException if a file cannot be read or the temp file cannot be written + */ + public static Path mergeYamlFiles(List files) throws IOException { + File mergedFile = Files.createTempFile("merged-operator-bundle", ".yaml", getDefaultPosixFilePermissions()).toFile(); + mergedFile.deleteOnExit(); + + try (var out = Files.newOutputStream(mergedFile.toPath())) { + for (Path file : files) { + Files.copy(file, out); + } + } + + LOGGER.debug("Merged {} files into temporary file: {}", files.size(), mergedFile.getAbsolutePath()); + return mergedFile.toPath(); + } } diff --git a/systemtests/src/test/resources/upgrade/YamlUpgrade.yaml b/systemtests/src/test/resources/upgrade/YamlUpgrade.yaml index 6fdc9919b..f1617de4b 100644 --- a/systemtests/src/test/resources/upgrade/YamlUpgrade.yaml +++ b/systemtests/src/test/resources/upgrade/YamlUpgrade.yaml @@ -1,6 +1,8 @@ -# Operator version +# Operator version to upgrade from. oldOperatorVersion: 0.12.6 -newOperatorVersion: 0.13.0 -# Url to generated CRDs Yaml containing operator. +# Url to generated CRDs Yaml containing the old operator version. oldOperatorCrdsUrl: https://github.com/streamshub/console/releases/download/0.12.6/streamshub-console-operator.yaml -newOperatorCrdsUrl: https://github.com/streamshub/console/releases/download/0.13.0/streamshub-console-operator.yaml +# Operator version/bundle to upgrade to. Set both to the literal value 'HEAD' to auto-derive them from +# the local build - see VersionModificationDataLoader - or set both to explicit values to pin them. +newOperatorVersion: HEAD +newOperatorCrdsUrl: HEAD From 942364cd106b308a78f8f51a1304fe900e16b7b7 Mon Sep 17 00:00:00 2001 From: jkalinic Date: Fri, 24 Jul 2026 21:00:58 +0200 Subject: [PATCH 2/5] use env, run tests Signed-off-by: jkalinic --- .github/workflows/pre-release.yml | 11 +-- .../streamshub/systemtests/Environment.java | 5 ++ .../VersionModificationDataLoader.java | 86 ++++++------------- .../upgrade/YamlVersionModificationData.java | 24 +++--- .../upgrade/AbstractUpgradeST.java | 53 +----------- .../systemtests/upgrade/YamlUpgradeST.java | 22 ++--- .../test/resources/upgrade/YamlUpgrade.yaml | 8 -- 7 files changed, 59 insertions(+), 150 deletions(-) delete mode 100644 systemtests/src/test/resources/upgrade/YamlUpgrade.yaml diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml index 7caeb3625..4c4a7dcbf 100644 --- a/.github/workflows/pre-release.yml +++ b/.github/workflows/pre-release.yml @@ -16,19 +16,20 @@ jobs: with: fetch-depth: 0 - - name: Ensure upgrade YAMLs changed + - name: Ensure old operator version was bumped run: | - CHANGED=$(git diff --name-only \ + CHANGED=$(git diff \ ${{ github.event.pull_request.base.sha }} \ ${{ github.event.pull_request.head.sha }} \ - | grep -E "systemtests/src/test/resources/upgrade/(YamlUpgrade.yaml)" || true) + -- systemtests/src/main/java/com/github/streamshub/systemtests/Environment.java \ + | grep -E "^[+-].*OLD_CONSOLE_OPERATOR_VERSION" || true) if [ -z "$CHANGED" ]; then - echo "❌[ERROR]: YamlUpgrade.yaml was not modified in this PR, exiting the flow." + echo "❌[ERROR]: OLD_CONSOLE_OPERATOR_VERSION in Environment.java was not modified in this PR, exiting the flow." exit 1 fi - echo "✔️ Upgrade YAML change detected: $CHANGED" + echo "✔️ OLD_CONSOLE_OPERATOR_VERSION change detected: $CHANGED" - name: Retrieve Project Metadata uses: smallrye/project-metadata-action@62527b4a896343d4c0c6b2a61eff07f6b59fcbd8 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 87eef2f5f..e062d4e72 100644 --- a/systemtests/src/main/java/com/github/streamshub/systemtests/Environment.java +++ b/systemtests/src/main/java/com/github/streamshub/systemtests/Environment.java @@ -44,6 +44,11 @@ public class Environment { // YAML bundle public static final String CONSOLE_OPERATOR_BUNDLE_URL = ENVS.getOrDefault("CONSOLE_OPERATOR_BUNDLE_URL", ""); + public static final String OLD_CONSOLE_OPERATOR_VERSION = ENVS.getOrDefault("OLD_CONSOLE_OPERATOR_VERSION", "0.13.0"); + public static final String OLD_CONSOLE_OPERATOR_CRDS_URL = ENVS.getOrDefault("OLD_CONSOLE_OPERATOR_CRDS_URL", + "https://github.com/streamshub/console/releases/download/" + OLD_CONSOLE_OPERATOR_VERSION + "/streamshub-console-operator.yaml"); + public static final String NEW_CONSOLE_OPERATOR_CRDS_URL = ENVS.getOrDefault("NEW_CONSOLE_OPERATOR_CRDS_URL", ""); + // OLM public static final String CONSOLE_OLM_CATALOG_SOURCE_NAME = ENVS.getOrDefault("CONSOLE_OLM_CATALOG_SOURCE_NAME", "streamshub-console-catalog"); public static final String CONSOLE_OLM_PACKAGE_NAME = ENVS.getOrDefault("CONSOLE_OLM_PACKAGE_NAME", "streamshub-console-operator"); diff --git a/systemtests/src/main/java/com/github/streamshub/systemtests/upgrade/VersionModificationDataLoader.java b/systemtests/src/main/java/com/github/streamshub/systemtests/upgrade/VersionModificationDataLoader.java index ae080fa10..f55cd03f7 100644 --- a/systemtests/src/main/java/com/github/streamshub/systemtests/upgrade/VersionModificationDataLoader.java +++ b/systemtests/src/main/java/com/github/streamshub/systemtests/upgrade/VersionModificationDataLoader.java @@ -1,19 +1,17 @@ package com.github.streamshub.systemtests.upgrade; -import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; +import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import com.github.streamshub.systemtests.Environment; import com.github.streamshub.systemtests.exceptions.SetupException; import com.github.streamshub.systemtests.utils.FileUtils; @@ -24,8 +22,6 @@ public enum InstallType { } private static final Logger LOGGER = LogManager.getLogger(VersionModificationDataLoader.class); - private static final String UPGRADE_FILE_PATH = System.getProperty("user.dir") + "/src/test/resources/upgrade/"; - private static final String YAML_UPGRADE_FILE = UPGRADE_FILE_PATH + "YamlUpgrade.yaml"; // Output produced by a normal build in .github/workflows/release.yml, which joins the same two files into release operator YAML bundle. private static final String OPERATOR_KUBERNETES_DIR = System.getProperty("user.dir") + "/../operator/target/kubernetes/"; @@ -34,9 +30,6 @@ public enum InstallType { private static final Pattern VERSION_LABEL_PATTERN = Pattern.compile("app\\.kubernetes\\.io/version:\\s*\"?([\\w.-]+)\"?"); - // Literal upgrade value for 'newOperatorVersion'/'newOperatorCrdsUrl' in YamlUpgrade.yaml - uses the local build - private static final String HEAD_VERSION = "HEAD"; - private YamlVersionModificationData yamlUpgradeData; public VersionModificationDataLoader(InstallType upgradeType) { @@ -47,58 +40,35 @@ public VersionModificationDataLoader(InstallType upgradeType) { } private void loadYamlUpgradeData() { - LOGGER.info("Loading Yaml upgrade data from file {}", YAML_UPGRADE_FILE); - try { - ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); - this.yamlUpgradeData = mapper.readValue(new File(YAML_UPGRADE_FILE), YamlVersionModificationData.class); - resolveNewOperatorData(yamlUpgradeData); - LOGGER.info("Loaded Yaml upgrade data: operator version {} -> {}", - yamlUpgradeData.getOldOperatorVersion(), yamlUpgradeData.getNewOperatorVersion()); - } catch (IOException e) { - LOGGER.error("Failed to parse Yaml upgrade data from file {}: {}", YAML_UPGRADE_FILE, e.getMessage()); - throw new RuntimeException(e); - } + String oldOperatorVersion = requireNonBlank(Environment.OLD_CONSOLE_OPERATOR_VERSION, "OLD_CONSOLE_OPERATOR_VERSION"); + String oldOperatorCrdsUrl = requireNonBlank(Environment.OLD_CONSOLE_OPERATOR_CRDS_URL, "OLD_CONSOLE_OPERATOR_CRDS_URL"); + String newOperatorVersion = requireNonBlank(Environment.getConsoleOperatorVersion(), + "CONSOLE_OPERATOR_VERSION (or the 'operator.version' system property)"); + String newOperatorCrdsUrl = resolveNewOperatorCrdsUrl(Environment.NEW_CONSOLE_OPERATOR_CRDS_URL, + () -> mergeLocalOperatorBundle(newOperatorVersion)); + + this.yamlUpgradeData = new YamlVersionModificationData(oldOperatorVersion, newOperatorVersion, oldOperatorCrdsUrl, newOperatorCrdsUrl); + LOGGER.info("Loaded Yaml upgrade data: operator version {} -> {}", oldOperatorVersion, newOperatorVersion); } - /** - * Resolves {@code newOperatorVersion}/{@code newOperatorCrdsUrl} on the given data object. - * - *

If both are set to the literal value {@value #HEAD_VERSION} in the loaded YAML file, - * they are auto-derived from {@link Environment#getConsoleOperatorVersion()} and the local operator - * build output. If both are set to anything else (non-blank, non-head), they are left untouched. - * Any other combination (blank, missing, or a head explicit mismatch) is treated as a broken config. - */ - private void resolveNewOperatorData(YamlVersionModificationData data) { - String newOperatorVersion = data.getNewOperatorVersion(); - String newOperatorCrdsUrl = data.getNewOperatorCrdsUrl(); - - boolean versionExplicit = newOperatorVersion != null && !newOperatorVersion.isBlank() && !HEAD_VERSION.equals(newOperatorVersion); - boolean urlExplicit = newOperatorCrdsUrl != null && !newOperatorCrdsUrl.isBlank() && !HEAD_VERSION.equals(newOperatorCrdsUrl); - - if (versionExplicit && urlExplicit) { - LOGGER.info("Using explicit new operator version '{}' and bundle '{}' from {}", - newOperatorVersion, newOperatorCrdsUrl, YAML_UPGRADE_FILE); - return; - } - - boolean versionSentinel = HEAD_VERSION.equals(newOperatorVersion); - boolean urlSentinel = HEAD_VERSION.equals(newOperatorCrdsUrl); - - if (!(versionSentinel && urlSentinel)) { - throw new SetupException("YamlUpgrade.yaml's 'newOperatorVersion' and 'newOperatorCrdsUrl' must either both be set to the " + - "literal value '" + HEAD_VERSION + "' (to auto-derive them from the local build) or both be set to explicit. " + - "Found newOperatorVersion='" + newOperatorVersion + "', newOperatorCrdsUrl='" + newOperatorCrdsUrl + "'."); + static String requireNonBlank(String value, String sourceName) { + if (value == null || value.isBlank()) { + throw new SetupException(sourceName + " is not set"); } + return value; + } - LOGGER.info("New operator version/bundle set to '{}' in {}, auto-deriving from the local build", HEAD_VERSION, YAML_UPGRADE_FILE); - - String derivedVersion = Environment.getConsoleOperatorVersion(); - if (derivedVersion.isBlank()) { - throw new SetupException("Cannot auto-derive the new Console Operator version: set the CONSOLE_OPERATOR_VERSION environment " + - "variable (or the 'operator.version' system property), or specify 'newOperatorVersion'/'newOperatorCrdsUrl' explicitly in " + - YAML_UPGRADE_FILE); + static String resolveNewOperatorCrdsUrl(String overrideUrl, Supplier localMergeSupplier) { + if (overrideUrl != null && !overrideUrl.isBlank()) { + LOGGER.info("Using NEW_CONSOLE_OPERATOR_CRDS_URL override: {}", overrideUrl); + return overrideUrl; } + String mergedPath = localMergeSupplier.get(); + LOGGER.info("NEW_CONSOLE_OPERATOR_CRDS_URL not set, using locally merged operator manifest: {}", mergedPath); + return mergedPath; + } + private static String mergeLocalOperatorBundle(String expectedVersion) { if (Files.notExists(OPERATOR_CRD_FILE) || Files.notExists(OPERATOR_RESOURCES_FILE)) { throw new SetupException("Local Console Operator build output not found at '" + OPERATOR_CRD_FILE + "' and '" + OPERATOR_RESOURCES_FILE + "'. Build the operator module first before running tests."); @@ -113,15 +83,13 @@ private void resolveNewOperatorData(YamlVersionModificationData data) { throw new SetupException("Failed to read/merge local Console Operator build output", e); } - if (!derivedVersion.equals(actualVersion)) { + if (!expectedVersion.equals(actualVersion)) { throw new SetupException("Local Console Operator build output at '" + OPERATOR_RESOURCES_FILE + - "' has version '" + actualVersion + "' but the expected new operator version is '" + derivedVersion + + "' has version '" + actualVersion + "' but the expected new operator version is '" + expectedVersion + "' (from CONSOLE_OPERATOR_VERSION/operator.version). Rebuild the operator module for the expected version."); } - data.setNewOperatorVersion(derivedVersion); - data.setNewOperatorCrdsUrl(mergedBundle.toAbsolutePath().toString()); - LOGGER.info("Auto-derived new operator version '{}' from local build bundle '{}'", derivedVersion, mergedBundle); + return mergedBundle.toAbsolutePath().toString(); } /** diff --git a/systemtests/src/main/java/com/github/streamshub/systemtests/upgrade/YamlVersionModificationData.java b/systemtests/src/main/java/com/github/streamshub/systemtests/upgrade/YamlVersionModificationData.java index fc898dfd5..a7bc590e4 100644 --- a/systemtests/src/main/java/com/github/streamshub/systemtests/upgrade/YamlVersionModificationData.java +++ b/systemtests/src/main/java/com/github/streamshub/systemtests/upgrade/YamlVersionModificationData.java @@ -1,10 +1,18 @@ package com.github.streamshub.systemtests.upgrade; public class YamlVersionModificationData { - private String oldOperatorVersion; - private String newOperatorVersion; - private String oldOperatorCrdsUrl; - private String newOperatorCrdsUrl; + private final String oldOperatorVersion; + private final String newOperatorVersion; + private final String oldOperatorCrdsUrl; + private final String newOperatorCrdsUrl; + + public YamlVersionModificationData(String oldOperatorVersion, String newOperatorVersion, + String oldOperatorCrdsUrl, String newOperatorCrdsUrl) { + this.oldOperatorVersion = oldOperatorVersion; + this.newOperatorVersion = newOperatorVersion; + this.oldOperatorCrdsUrl = oldOperatorCrdsUrl; + this.newOperatorCrdsUrl = newOperatorCrdsUrl; + } public String getOldOperatorVersion() { return oldOperatorVersion; @@ -14,10 +22,6 @@ public String getNewOperatorVersion() { return newOperatorVersion; } - public void setNewOperatorVersion(String newOperatorVersion) { - this.newOperatorVersion = newOperatorVersion; - } - public String getOldOperatorCrdsUrl() { return oldOperatorCrdsUrl; } @@ -25,8 +29,4 @@ public String getOldOperatorCrdsUrl() { public String getNewOperatorCrdsUrl() { return newOperatorCrdsUrl; } - - public void setNewOperatorCrdsUrl(String newOperatorCrdsUrl) { - this.newOperatorCrdsUrl = newOperatorCrdsUrl; - } } diff --git a/systemtests/src/test/java/com/github/streamshub/systemtests/upgrade/AbstractUpgradeST.java b/systemtests/src/test/java/com/github/streamshub/systemtests/upgrade/AbstractUpgradeST.java index 0da0ffb65..8030bddf4 100644 --- a/systemtests/src/test/java/com/github/streamshub/systemtests/upgrade/AbstractUpgradeST.java +++ b/systemtests/src/test/java/com/github/streamshub/systemtests/upgrade/AbstractUpgradeST.java @@ -1,17 +1,13 @@ package com.github.streamshub.systemtests.upgrade; import com.github.streamshub.systemtests.ResetTracingExtension; -import com.github.streamshub.systemtests.TestCaseConfig; import com.github.streamshub.systemtests.TestExecutionWatcher; import com.github.streamshub.systemtests.constants.Constants; -import com.github.streamshub.systemtests.constants.TimeConstants; import com.github.streamshub.systemtests.interfaces.BucketMethodsOrderRandomizer; import com.github.streamshub.systemtests.interfaces.ExtensionContextParameterResolver; import com.github.streamshub.systemtests.logs.LogWrapper; import com.github.streamshub.systemtests.setup.strimzi.StrimziOperatorSetup; import com.github.streamshub.systemtests.utils.SetupUtils; -import com.github.streamshub.systemtests.utils.playwright.PwPageUrls; -import com.github.streamshub.systemtests.utils.playwright.PwUtils; import com.github.streamshub.systemtests.utils.resourceutils.ClusterUtils; import com.github.streamshub.systemtests.utils.resourceutils.NamespaceUtils; import io.skodjob.kubetest4j.annotations.ResourceManager; @@ -48,19 +44,6 @@ class AbstractUpgradeST { protected static final int UNAVAILABLE_TOPICS_COUNT = 0; protected static final int TOTAL_TOPICS_COUNT = TOTAL_REPLICATED_TOPICS_COUNT + UNDER_REPLICATED_TOPICS_COUNT + UNAVAILABLE_TOPICS_COUNT; - // Old (pre-redesign) Console UI, valid for every operator version that predates the UI overhaul - // that landed after 0.12.3 (e.g. 0.11.0, 0.12.3) - shared by OlmUpgradeST and YamlUpgradeST for - // whichever side(s) of their respective upgrades still target that old UI. - protected static final String COPS_TOPICS_CARD_TOTAL_TOPICS = "body > div:nth-of-type(2) > div.pf-v6-c-page > div.pf-v6-c-page__main-container:nth-of-type(2) > main.pf-v6-c-page__main > div.pf-v6-c-drawer > div.pf-v6-c-drawer__main > div.pf-v6-c-drawer__content:nth-of-type(1) > div.pf-v6-c-drawer__body > section.pf-v6-c-page__main-section > div.pf-v6-c-page__main-body > div.pf-v6-l-grid > div.pf-v6-l-grid__item:nth-of-type(2) > div.pf-v6-l-flex > div:nth-of-type(2) > div.pf-v6-c-card > div.pf-v6-c-card__body:nth-of-type(2) > div.pf-v6-l-flex > div.pf-v6-l-flex:nth-of-type(1) > div > div.pf-v6-l-flex > div:nth-of-type(1) > div.pf-v6-c-content"; - protected static final String COPS_TOPICS_CARD_TOTAL_PARTITIONS = "body > div:nth-of-type(2) > div.pf-v6-c-page > div.pf-v6-c-page__main-container:nth-of-type(2) > main.pf-v6-c-page__main > div.pf-v6-c-drawer > div.pf-v6-c-drawer__main > div.pf-v6-c-drawer__content:nth-of-type(1) > div.pf-v6-c-drawer__body > section.pf-v6-c-page__main-section > div.pf-v6-c-page__main-body > div.pf-v6-l-grid > div.pf-v6-l-grid__item:nth-of-type(2) > div.pf-v6-l-flex > div:nth-of-type(2) > div.pf-v6-c-card > div.pf-v6-c-card__body:nth-of-type(2) > div.pf-v6-l-flex > div.pf-v6-l-flex:nth-of-type(1) > div > div.pf-v6-l-flex > div:nth-of-type(2) > div.pf-v6-c-content"; - protected static final String COPS_TOPICS_CARD_FULLY_REPLICATED = "body > div:nth-of-type(2) > div.pf-v6-c-page > div.pf-v6-c-page__main-container:nth-of-type(2) > main.pf-v6-c-page__main > div.pf-v6-c-drawer > div.pf-v6-c-drawer__main > div.pf-v6-c-drawer__content:nth-of-type(1) > div.pf-v6-c-drawer__body > section.pf-v6-c-page__main-section > div.pf-v6-c-page__main-body > div.pf-v6-l-grid > div.pf-v6-l-grid__item:nth-of-type(2) > div.pf-v6-l-flex > div:nth-of-type(2) > div.pf-v6-c-card > div.pf-v6-c-card__body:nth-of-type(2) > div.pf-v6-l-flex > div.pf-v6-l-flex:nth-of-type(2) > div:nth-of-type(1)"; - protected static final String COPS_TOPICS_CARD_UNDER_REPLICATED = "body > div:nth-of-type(2) > div.pf-v6-c-page > div.pf-v6-c-page__main-container:nth-of-type(2) > main.pf-v6-c-page__main > div.pf-v6-c-drawer > div.pf-v6-c-drawer__main > div.pf-v6-c-drawer__content:nth-of-type(1) > div.pf-v6-c-drawer__body > section.pf-v6-c-page__main-section > div.pf-v6-c-page__main-body > div.pf-v6-l-grid > div.pf-v6-l-grid__item:nth-of-type(2) > div.pf-v6-l-flex > div:nth-of-type(2) > div.pf-v6-c-card > div.pf-v6-c-card__body:nth-of-type(2) > div.pf-v6-l-flex > div.pf-v6-l-flex:nth-of-type(2) > div:nth-of-type(2)"; - protected static final String COPS_TOPICS_CARD_UNAVAILABLE = "body > div:nth-of-type(2) > div.pf-v6-c-page > div.pf-v6-c-page__main-container:nth-of-type(2) > main.pf-v6-c-page__main > div.pf-v6-c-drawer > div.pf-v6-c-drawer__main > div.pf-v6-c-drawer__content:nth-of-type(1) > div.pf-v6-c-drawer__body > section.pf-v6-c-page__main-section > div.pf-v6-c-page__main-body > div.pf-v6-l-grid > div.pf-v6-l-grid__item:nth-of-type(2) > div.pf-v6-l-flex > div:nth-of-type(2) > div.pf-v6-c-card > div.pf-v6-c-card__body:nth-of-type(2) > div.pf-v6-l-flex > div.pf-v6-l-flex:nth-of-type(2) > div:nth-of-type(3)"; - protected static final String TPS_HEADER_TOTAL_TOPICS_BADGE = "body > div:nth-of-type(2) > div.pf-v6-c-page > div.pf-v6-c-page__main-container:nth-of-type(2) > main.pf-v6-c-page__main > div.pf-v6-c-drawer > div.pf-v6-c-drawer__main > div.pf-v6-c-drawer__content:nth-of-type(1) > div.pf-v6-c-drawer__body > div.pf-v6-c-page__main-group > section.pf-v6-c-page__main-section:nth-of-type(2) > div.pf-v6-c-page__main-body > div.pf-v6-l-flex > div.pf-v6-l-flex:nth-of-type(1) > div:nth-of-type(1) > h1.pf-v6-c-title > div.pf-v6-l-split > div.pf-v6-l-split__item:nth-of-type(2) > span.pf-v6-c-label > span.pf-v6-c-label__content > span"; - protected static final String TPS_HEADER_BADGE_STATUS_SUCCESS = "body > div:nth-of-type(2) > div.pf-v6-c-page > div.pf-v6-c-page__main-container:nth-of-type(2) > main.pf-v6-c-page__main > div.pf-v6-c-drawer > div.pf-v6-c-drawer__main > div.pf-v6-c-drawer__content:nth-of-type(1) > div.pf-v6-c-drawer__body > div.pf-v6-c-page__main-group > section.pf-v6-c-page__main-section:nth-of-type(2) > div.pf-v6-c-page__main-body > div.pf-v6-l-flex > div.pf-v6-l-flex:nth-of-type(1) > div:nth-of-type(1) > h1.pf-v6-c-title > div.pf-v6-l-split > div.pf-v6-l-split__item:nth-of-type(3) > div > span.pf-v6-c-label > span.pf-v6-c-label__content > span.pf-v6-c-label__text:nth-of-type(2)"; - protected static final String TPS_HEADER_BADGE_STATUS_WARNING = "body > div:nth-of-type(2) > div.pf-v6-c-page > div.pf-v6-c-page__main-container:nth-of-type(2) > main.pf-v6-c-page__main > div.pf-v6-c-drawer > div.pf-v6-c-drawer__main > div.pf-v6-c-drawer__content:nth-of-type(1) > div.pf-v6-c-drawer__body > div.pf-v6-c-page__main-group > section.pf-v6-c-page__main-section:nth-of-type(2) > div.pf-v6-c-page__main-body > div.pf-v6-l-flex > div.pf-v6-l-flex:nth-of-type(1) > div:nth-of-type(1) > h1.pf-v6-c-title > div.pf-v6-l-split > div.pf-v6-l-split__item:nth-of-type(4) > div > span.pf-v6-c-label > span.pf-v6-c-label__content > span.pf-v6-c-label__text:nth-of-type(2)"; - protected static final String TPS_HEADER_BADGE_STATUS_ERROR = "body > div:nth-of-type(2) > div.pf-v6-c-page > div.pf-v6-c-page__main-container:nth-of-type(2) > main.pf-v6-c-page__main > div.pf-v6-c-drawer > div.pf-v6-c-drawer__main > div.pf-v6-c-drawer__content:nth-of-type(1) > div.pf-v6-c-drawer__body > div.pf-v6-c-page__main-group > section.pf-v6-c-page__main-section:nth-of-type(2) > div.pf-v6-c-page__main-body > div.pf-v6-l-flex > div.pf-v6-l-flex:nth-of-type(1) > div:nth-of-type(1) > h1.pf-v6-c-title > div.pf-v6-l-split > div.pf-v6-l-split__item:nth-of-type(5) > div > span.pf-v6-c-label > span.pf-v6-c-label__content > span.pf-v6-c-label__text:nth-of-type(2)"; - @BeforeAll void setupTestSuite(ExtensionContext extensionContext) { if (!initialized) { @@ -70,8 +53,7 @@ void setupTestSuite(ExtensionContext extensionContext) { KubeResourceManager.get().setTestContext(extensionContext); NamespaceUtils.prepareNamespace(Constants.CO_NAMESPACE); - // V1 not compatible with 0.12 console - strimziOperatorSetup.install("0.51.0"); + strimziOperatorSetup.install(); } @BeforeEach @@ -91,37 +73,4 @@ void teardownTestSuite(ExtensionContext extensionContext) { KubeResourceManager.get().setTestContext(extensionContext); SetupUtils.cleanupIfNeeded(); } - - /** - * Checks Overview/Topics page topic counts using the pre-redesign Console UI's DOM. Bypasses - * {@link PwUtils#login(TestCaseConfig)} and {@link com.github.streamshub.systemtests.utils.testchecks.TopicChecks}, - * which target the current, redesigned UI and don't match an old version's markup. - * - *

Shared by {@link OlmUpgradeST} and {@link YamlUpgradeST} for whichever side(s) of their - * respective upgrades still target the old UI. - * - * @param tcc the test case configuration - * @param totalTopicsCount expected total topic count - * @param totalReplicatedTopicsCount expected fully-replicated topic count - * @param underReplicatedTopicsCount expected under-replicated topic count - * @param unavailableTopicsCount expected unavailable topic count - */ - protected void checkOldUiTopicState(TestCaseConfig tcc, int totalTopicsCount, int totalReplicatedTopicsCount, int underReplicatedTopicsCount, int unavailableTopicsCount) { - LOGGER.info("Checking overview page topic status: {} total topics, {} partitions, {} fully replicated, {} under-replicated, {} unavailable", - totalTopicsCount, totalTopicsCount, totalReplicatedTopicsCount, underReplicatedTopicsCount, unavailableTopicsCount); - PwUtils.navigate(tcc, PwPageUrls.getOverviewPage(tcc, tcc.kafkaName())); - PwUtils.waitForContainsText(tcc, COPS_TOPICS_CARD_TOTAL_TOPICS, totalTopicsCount + " topics", true, true, TimeConstants.ACTION_WAIT_MEDIUM, Constants.SELECTOR_RETRIES); - PwUtils.waitForContainsText(tcc, COPS_TOPICS_CARD_TOTAL_PARTITIONS, totalTopicsCount + " partitions", false, true, TimeConstants.ACTION_WAIT_MEDIUM, Constants.SELECTOR_RETRIES); - PwUtils.waitForContainsText(tcc, COPS_TOPICS_CARD_FULLY_REPLICATED, totalReplicatedTopicsCount + " Fully replicated", false, true, TimeConstants.ACTION_WAIT_MEDIUM, Constants.SELECTOR_RETRIES); - PwUtils.waitForContainsText(tcc, COPS_TOPICS_CARD_UNDER_REPLICATED, underReplicatedTopicsCount + " Under replicated", false, true, TimeConstants.ACTION_WAIT_MEDIUM, Constants.SELECTOR_RETRIES); - PwUtils.waitForContainsText(tcc, COPS_TOPICS_CARD_UNAVAILABLE, unavailableTopicsCount + " Unavailable", false, true, TimeConstants.ACTION_WAIT_MEDIUM, Constants.SELECTOR_RETRIES); - - LOGGER.info("Checking topics page topic status: {} total topics, {} fully replicated, {} under-replicated, {} unavailable", - totalTopicsCount, totalReplicatedTopicsCount, underReplicatedTopicsCount, unavailableTopicsCount); - PwUtils.navigate(tcc, PwPageUrls.getTopicsPage(tcc, tcc.kafkaName())); - PwUtils.waitForContainsText(tcc, TPS_HEADER_TOTAL_TOPICS_BADGE, totalTopicsCount + " total", false, true, TimeConstants.ACTION_WAIT_MEDIUM, Constants.SELECTOR_RETRIES); - PwUtils.waitForContainsText(tcc, TPS_HEADER_BADGE_STATUS_SUCCESS, Integer.toString(totalReplicatedTopicsCount), false, true, TimeConstants.ACTION_WAIT_SHORT, Constants.SELECTOR_RETRIES); - PwUtils.waitForContainsText(tcc, TPS_HEADER_BADGE_STATUS_WARNING, Integer.toString(underReplicatedTopicsCount), false, true, TimeConstants.ACTION_WAIT_SHORT, Constants.SELECTOR_RETRIES); - PwUtils.waitForContainsText(tcc, TPS_HEADER_BADGE_STATUS_ERROR, Integer.toString(unavailableTopicsCount), false, true, TimeConstants.ACTION_WAIT_SHORT, Constants.SELECTOR_RETRIES); - } } diff --git a/systemtests/src/test/java/com/github/streamshub/systemtests/upgrade/YamlUpgradeST.java b/systemtests/src/test/java/com/github/streamshub/systemtests/upgrade/YamlUpgradeST.java index 93697a844..8c515e91e 100644 --- a/systemtests/src/test/java/com/github/streamshub/systemtests/upgrade/YamlUpgradeST.java +++ b/systemtests/src/test/java/com/github/streamshub/systemtests/upgrade/YamlUpgradeST.java @@ -14,8 +14,8 @@ import com.github.streamshub.systemtests.utils.resourceutils.NamespaceUtils; import com.github.streamshub.systemtests.utils.resourceutils.ResourceUtils; import com.github.streamshub.systemtests.utils.resourceutils.console.ConsoleUtils; -import com.github.streamshub.systemtests.utils.resourceutils.kafka.KafkaNamingUtils; import com.github.streamshub.systemtests.utils.resourceutils.kafka.KafkaTopicUtils; +import com.github.streamshub.systemtests.utils.testchecks.TopicChecks; import io.fabric8.kubernetes.api.model.apps.Deployment; import org.apache.logging.log4j.Logger; import org.junit.jupiter.api.AfterAll; @@ -38,9 +38,8 @@ public class YamlUpgradeST extends AbstractUpgradeST { /** * Verifies that upgrading the Console Operator installed from plain YAML manifests * (as opposed to OLM) correctly transitions from the old to the new operator version, - * defined in {@code src/test/resources/upgrade/YamlUpgrade.yaml} (currently version - * {@code 0.11.0} to {@code 0.12.3}), while preserving the existing Console instance - * and keeping the UI fully functional throughout. + * while preserving the existing Console instance and keeping the UI fully functional + * throughout. * *

This test performs the following steps:

*