This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 8d6769e36b7a CAMEL-23912: Fix flaky ThemeTest by using Theme's own
classloader for CSS
8d6769e36b7a is described below
commit 8d6769e36b7ad92e188b989409a6744cf5bdfd58
Author: Guillaume Nodet <[email protected]>
AuthorDate: Tue Jul 7 07:09:43 2026 +0200
CAMEL-23912: Fix flaky ThemeTest by using Theme's own classloader for CSS
ThemeTest had a 34% flaky rate under parallel test execution because
StyleEngine.loadStylesheet() used StyleEngine.class.getClassLoader() which
can diverge from the project's classloader. Load CSS via
Theme.class.getClassLoader() and addStylesheet() instead, synchronize the
accent() and zebra() accessors, and use ConcurrentHashMap for the style
cache.
Closes #24475
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 {