This is an automated email from the ASF dual-hosted git repository. gnodet pushed a commit to branch fix-flaky-test-themetest-34-flaky-rate-on-devel in repository https://gitbox.apache.org/repos/asf/camel.git
commit c63a7fdfa80becf53461c0391a58925b327aeab4 Author: Guillaume Nodet <[email protected]> AuthorDate: Mon Jul 6 21:06:15 2026 +0000 CAMEL-23912: Fix flaky ThemeTest by using Theme's own classloader for CSS Load CSS resources via Theme.class.getClassLoader() and addStylesheet() instead of StyleEngine.loadStylesheet() which uses StyleEngine.class.getClassLoader(). Under parallel test execution (camel.surefire.parallel=true in the DSL parent), the two classloaders can diverge, causing intermittent "resource not found" failures that make the engine fall back to built-in defaults. The light theme test then fails because fallback values differ from CSS-resolved ones. Also make accent() and zebra() synchronized to match all other Theme accessors, and use ConcurrentHashMap for the style cache as a defensive measure. Co-Authored-By: Claude Opus 4.6 <[email protected]> --- .../camel/dsl/jbang/core/commands/tui/Theme.java | 40 +++++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/Theme.java b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/Theme.java index 1d549acaa65b..6b62c45fa96a 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/Theme.java +++ b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/Theme.java @@ -16,11 +16,14 @@ */ package org.apache.camel.dsl.jbang.core.commands.tui; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.util.Collections; -import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import dev.tamboui.css.Styleable; import dev.tamboui.css.engine.StyleEngine; @@ -70,7 +73,7 @@ final class Theme { private static final Style FALLBACK_MCP_DOWN = Style.EMPTY.fg(Color.LIGHT_RED); private static final Color FALLBACK_ZEBRA = Color.rgb(0x1C, 0x1C, 0x1C); - private static final Map<String, Style> CACHE = new HashMap<>(); + private static final Map<String, Style> CACHE = new ConcurrentHashMap<>(); private static boolean initialized; private static boolean fallbackLogged; @@ -81,7 +84,7 @@ final class Theme { private Theme() { } - static Color accent() { + static synchronized Color accent() { StyleEngine e = engine(); if (e == null) { return ACCENT; @@ -98,7 +101,7 @@ final class Theme { * Subtle alternating-row background for zebra striping. Theme-aware (dark gray on dark, light gray on light) so * stripes stay readable on both terminals. Applied at the row level so it never overrides the selection highlight. */ - static Color zebra() { + static synchronized Color zebra() { StyleEngine e = engine(); if (e == null) { return FALLBACK_ZEBRA; @@ -243,7 +246,12 @@ final class Theme { } try { StyleEngine e = StyleEngine.create(); - e.loadStylesheet(mode, "tui/themes/" + mode + ".tcss"); + // Read CSS content via Theme's own classloader instead of delegating + // to StyleEngine.loadStylesheet() which uses StyleEngine.class.getClassLoader(). + // Under parallel test execution the two classloaders can diverge, causing + // intermittent "resource not found" failures in CI. + String cssContent = loadCssResource("tui/themes/" + mode + ".tcss"); + e.addStylesheet(mode, cssContent); e.setActiveStylesheet(mode); engine = e; } catch (Exception ex) { @@ -253,6 +261,28 @@ final class Theme { return engine; } + /** + * Reads a CSS resource from the classpath using this class's own classloader, which is guaranteed to have access to + * project resources regardless of classloader hierarchy. + */ + private static String loadCssResource(String path) throws IOException { + InputStream is = Theme.class.getClassLoader().getResourceAsStream(path); + if (is == null) { + // Fallback to the thread context classloader in case the class's own classloader + // doesn't have visibility (e.g., in OSGi or custom classloader setups). + ClassLoader tccl = Thread.currentThread().getContextClassLoader(); + if (tccl != null) { + is = tccl.getResourceAsStream(path); + } + } + if (is == null) { + throw new IOException("Theme CSS resource not found on classpath: " + path); + } + try (InputStream in = is) { + return new String(in.readAllBytes(), StandardCharsets.UTF_8); + } + } + private static String loadPersistedMode() { String[] holder = { DARK }; try {
