From 092b7b9aee17a8a0ee85e642972001c1fd38cca5 Mon Sep 17 00:00:00 2001 From: Sajeer Date: Mon, 24 Aug 2026 10:39:11 +0530 Subject: [PATCH 1/4] Fixed misleading expansion variable log message in ci.common --- .../plugins/config/ServerConfigDocument.java | 8 +- .../ExpansionVariableLogMessageTest.java | 153 ++++++++++++++++++ 2 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 src/test/java/io/openliberty/tools/common/config/ExpansionVariableLogMessageTest.java diff --git a/src/main/java/io/openliberty/tools/common/plugins/config/ServerConfigDocument.java b/src/main/java/io/openliberty/tools/common/plugins/config/ServerConfigDocument.java index 2ae4372f3..05ce7f487 100644 --- a/src/main/java/io/openliberty/tools/common/plugins/config/ServerConfigDocument.java +++ b/src/main/java/io/openliberty/tools/common/plugins/config/ServerConfigDocument.java @@ -357,7 +357,9 @@ private String resolveExpansionProperties(Properties props, String value, String Pattern pattern = OSUtil.isWindows() ? WINDOWS_EXPANSION_VAR_PATTERN : LINUX_EXPANSION_VAR_PATTERN; Matcher matcher = pattern.matcher(value); StringBuffer sb = new StringBuffer(); + boolean anyMatched = false; while (matcher.find()) { + anyMatched = true; String finalReplacement; String varName = matcher.group(1); // 2. Circular Reference Guard @@ -381,10 +383,14 @@ private String resolveExpansionProperties(Properties props, String value, String finalReplacement = matcher.group(0); // Keep original } matcher.appendReplacement(sb, Matcher.quoteReplacement(finalReplacement)); - log.info(String.format("Resolving Property %s for expression %s. Resolved expression value is %s", varName , value , sb)); + log.info(String.format("Resolved environment variable \"%s\" in path \"%s\" to \"%s\"", varName, value, finalReplacement)); } // 4. Finalize the string matcher.appendTail(sb); + // Log the complete resolved value once, only when at least one variable was expanded + if (anyMatched) { + log.info(String.format("Resolved path \"%s\" to \"%s\"", value, sb)); + } return sb.toString(); } diff --git a/src/test/java/io/openliberty/tools/common/config/ExpansionVariableLogMessageTest.java b/src/test/java/io/openliberty/tools/common/config/ExpansionVariableLogMessageTest.java new file mode 100644 index 000000000..fe176c9ff --- /dev/null +++ b/src/test/java/io/openliberty/tools/common/config/ExpansionVariableLogMessageTest.java @@ -0,0 +1,153 @@ +/** + * (C) Copyright IBM Corporation 2026. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openliberty.tools.common.config; + +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.Assume; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import io.openliberty.tools.common.TestLogger; +import io.openliberty.tools.common.plugins.config.ServerConfigDocument; +import io.openliberty.tools.common.plugins.util.OSUtil; +import io.openliberty.tools.common.plugins.util.ServerFeatureUtil; + +// Verifies the log message format produced by resolveExpansionProperties() after the fix for issue #2076 +public class ExpansionVariableLogMessageTest { + + @Rule + public TemporaryFolder tmp = new TemporaryFolder(); + + // Captures info() calls for assertion; all other methods delegate to TestLogger + private static class CapturingLogger extends TestLogger { + final List infoMessages = new ArrayList<>(); + + @Override + public void info(String msg) { infoMessages.add(msg); } + } + + // server.env is placed in serverDir because SERVER_CONFIG_DIR maps there, making it visible to processServerEnv() + private ServerConfigDocument buildDoc(CapturingLogger log, File serverDir, String serverEnvContent) throws Exception { + Files.write(new File(serverDir, "server.env").toPath(), serverEnvContent.getBytes()); + + Map dirMap = new HashMap<>(); + dirMap.put(ServerFeatureUtil.WLP_INSTALL_DIR, serverDir); + dirMap.put(ServerFeatureUtil.WLP_USER_DIR, serverDir); + dirMap.put(ServerFeatureUtil.SERVER_CONFIG_DIR, serverDir); + dirMap.put(ServerFeatureUtil.SERVER_OUTPUT_DIR, serverDir); + return new ServerConfigDocument(log, null, dirMap); + } + + @Test + public void testUnixStyleLogMessageFormat() throws Exception { + Assume.assumeFalse("Skipped on Windows: Unix ${VAR} pattern not active", OSUtil.isWindows()); + + CapturingLogger log = new CapturingLogger(); + File serverDir = tmp.newFolder("server-unix"); + + String envContent = "BASE=TEST\nDERIVED=${BASE}_SUFFIX\n"; + buildDoc(log, serverDir, envContent).processServerEnv(); + + String expectedMsg = "Resolved environment variable \"BASE\" in path \"${BASE}_SUFFIX\" to \"TEST\""; + String expectedSummary = "Resolved path \"${BASE}_SUFFIX\" to \"TEST_SUFFIX\""; + assertTrue("Expected log message not found.\nActual info messages: " + log.infoMessages, + log.infoMessages.stream().anyMatch(m -> m.equals(expectedMsg))); + assertTrue("Expected summary log message not found.\nActual: " + log.infoMessages, + log.infoMessages.stream().anyMatch(m -> m.equals(expectedSummary))); + } + + @Test + public void testUnixStyleMultipleVarsLogsBothVarNames() throws Exception { + Assume.assumeFalse("Skipped on Windows: Unix ${VAR} pattern not active", OSUtil.isWindows()); + + CapturingLogger log = new CapturingLogger(); + File serverDir = tmp.newFolder("server-unix-multi"); + + String envContent = "EXP_VAR=TEST\nEXP_VAR2=UNIX\nCOMBINED=${EXP_VAR}_${EXP_VAR2}\n"; + buildDoc(log, serverDir, envContent).processServerEnv(); + + String expectedMsg1 = "Resolved environment variable \"EXP_VAR\" in path \"${EXP_VAR}_${EXP_VAR2}\" to \"TEST\""; + String expectedMsg2 = "Resolved environment variable \"EXP_VAR2\" in path \"${EXP_VAR}_${EXP_VAR2}\" to \"UNIX\""; + String expectedSummary = "Resolved path \"${EXP_VAR}_${EXP_VAR2}\" to \"TEST_UNIX\""; + assertTrue("Expected first log message not found.\nActual: " + log.infoMessages, + log.infoMessages.stream().anyMatch(m -> m.equals(expectedMsg1))); + assertTrue("Expected second log message not found.\nActual: " + log.infoMessages, + log.infoMessages.stream().anyMatch(m -> m.equals(expectedMsg2))); + assertTrue("Expected summary log message not found.\nActual: " + log.infoMessages, + log.infoMessages.stream().anyMatch(m -> m.equals(expectedSummary))); + } + + @Test + public void testNoExpansionReferenceNoLogEmitted() throws Exception { + CapturingLogger log = new CapturingLogger(); + File serverDir = tmp.newFolder("server-no-expansion"); + + String envContent = "PLAIN_VAR=just_a_value\n"; + buildDoc(log, serverDir, envContent).processServerEnv(); + + assertTrue("No info log message should be emitted for plain values, but found: " + log.infoMessages, + log.infoMessages.isEmpty()); + } + + @Test + public void testWindowsStyleBackslashesPreservedInLog() throws Exception { + Assume.assumeTrue("Skipped on non-Windows: !VAR! pattern only active on Windows", OSUtil.isWindows()); + + CapturingLogger log = new CapturingLogger(); + File serverDir = tmp.newFolder("server-win"); + + // Reproduces the exact scenario from issue #2076 + String envContent = "IBM_JAVA_SEMERU_HOME=C:\\MyData\\java\\ibm-semeru-certified\nJAVA_HOME=!IBM_JAVA_SEMERU_HOME!\\jdk-21.0.10+7\n"; + buildDoc(log, serverDir, envContent).processServerEnv(); + + String expectedMsg = "Resolved environment variable \"IBM_JAVA_SEMERU_HOME\" in path \"!IBM_JAVA_SEMERU_HOME!\\jdk-21.0.10+7\" to \"C:\\MyData\\java\\ibm-semeru-certified\\jdk-21.0.10+7\""; + String expectedSummary = "Resolved path \"!IBM_JAVA_SEMERU_HOME!\\jdk-21.0.10+7\" to \"C:\\MyData\\java\\ibm-semeru-certified\\jdk-21.0.10+7\""; + assertTrue("Log message with backslashes not found — backslashes may have been dropped.\nActual: " + log.infoMessages, + log.infoMessages.stream().anyMatch(m -> m.equals(expectedMsg))); + assertTrue("Expected summary log message not found.\nActual: " + log.infoMessages, + log.infoMessages.stream().anyMatch(m -> m.equals(expectedSummary))); + } + + @Test + public void testWindowsStyleMultipleVarsOneLogPerExpression() throws Exception { + Assume.assumeTrue("Skipped on non-Windows: !VAR! pattern only active on Windows", OSUtil.isWindows()); + + CapturingLogger log = new CapturingLogger(); + File serverDir = tmp.newFolder("server-win-multi"); + + String envContent = "EXP_VAR=TEST\nEXP_VAR3=WINDOWS\nCOMBINED=!EXP_VAR!_!EXP_VAR3!\n"; + buildDoc(log, serverDir, envContent).processServerEnv(); + + String expectedMsg1 = "Resolved environment variable \"EXP_VAR\" in path \"!EXP_VAR!_!EXP_VAR3!\" to \"TEST\""; + String expectedMsg2 = "Resolved environment variable \"EXP_VAR3\" in path \"!EXP_VAR!_!EXP_VAR3!\" to \"WINDOWS\""; + String expectedSummary = "Resolved path \"!EXP_VAR!_!EXP_VAR3!\" to \"TEST_WINDOWS\""; + assertTrue("Expected first log message not found.\nActual: " + log.infoMessages, + log.infoMessages.stream().anyMatch(m -> m.equals(expectedMsg1))); + assertTrue("Expected second log message not found.\nActual: " + log.infoMessages, + log.infoMessages.stream().anyMatch(m -> m.equals(expectedMsg2))); + assertTrue("Expected summary log message not found.\nActual: " + log.infoMessages, + log.infoMessages.stream().anyMatch(m -> m.equals(expectedSummary))); + } +} From 13f592c04c9f20e13a193038b75938045cc0f2ce Mon Sep 17 00:00:00 2001 From: Sajeer Date: Mon, 24 Aug 2026 12:28:42 +0530 Subject: [PATCH 2/4] Fixes the windows ci failure issues --- .../tools/common/config/ExpansionVariableLogMessageTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/java/io/openliberty/tools/common/config/ExpansionVariableLogMessageTest.java b/src/test/java/io/openliberty/tools/common/config/ExpansionVariableLogMessageTest.java index fe176c9ff..680a91b91 100644 --- a/src/test/java/io/openliberty/tools/common/config/ExpansionVariableLogMessageTest.java +++ b/src/test/java/io/openliberty/tools/common/config/ExpansionVariableLogMessageTest.java @@ -49,7 +49,10 @@ private static class CapturingLogger extends TestLogger { } // server.env is placed in serverDir because SERVER_CONFIG_DIR maps there, making it visible to processServerEnv() + // A minimal server.xml is required so that ServerConfigDocument. does not NPE when it calls parseDocument(serverXMLFile). private ServerConfigDocument buildDoc(CapturingLogger log, File serverDir, String serverEnvContent) throws Exception { + Files.write(new File(serverDir, "server.xml").toPath(), + "".getBytes()); Files.write(new File(serverDir, "server.env").toPath(), serverEnvContent.getBytes()); Map dirMap = new HashMap<>(); From 2c6d7792e8cd6a4cc09b665eae63224b5be7df7e Mon Sep 17 00:00:00 2001 From: Sajeer Date: Mon, 24 Aug 2026 16:00:41 +0530 Subject: [PATCH 3/4] Fixed Windows CI failures in ExpansionVariableLogMessageTest --- .../tools/common/config/ExpansionVariableLogMessageTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/java/io/openliberty/tools/common/config/ExpansionVariableLogMessageTest.java b/src/test/java/io/openliberty/tools/common/config/ExpansionVariableLogMessageTest.java index 680a91b91..6324b7c5c 100644 --- a/src/test/java/io/openliberty/tools/common/config/ExpansionVariableLogMessageTest.java +++ b/src/test/java/io/openliberty/tools/common/config/ExpansionVariableLogMessageTest.java @@ -121,8 +121,9 @@ public void testWindowsStyleBackslashesPreservedInLog() throws Exception { CapturingLogger log = new CapturingLogger(); File serverDir = tmp.newFolder("server-win"); - // Reproduces the exact scenario from issue #2076 - String envContent = "IBM_JAVA_SEMERU_HOME=C:\\MyData\\java\\ibm-semeru-certified\nJAVA_HOME=!IBM_JAVA_SEMERU_HOME!\\jdk-21.0.10+7\n"; + // Reproduces the exact scenario from issue #2076. + // Backslashes must be doubled in the .properties file format so that Properties.load() preserves them as single backslashes. + String envContent = "IBM_JAVA_SEMERU_HOME=C:\\\\MyData\\\\java\\\\ibm-semeru-certified\nJAVA_HOME=!IBM_JAVA_SEMERU_HOME!\\\\jdk-21.0.10+7\n"; buildDoc(log, serverDir, envContent).processServerEnv(); String expectedMsg = "Resolved environment variable \"IBM_JAVA_SEMERU_HOME\" in path \"!IBM_JAVA_SEMERU_HOME!\\jdk-21.0.10+7\" to \"C:\\MyData\\java\\ibm-semeru-certified\\jdk-21.0.10+7\""; From 4280bafb93e1f6297ef88a050b0dd77ed50d1b3d Mon Sep 17 00:00:00 2001 From: Sajeer Date: Mon, 24 Aug 2026 16:07:04 +0530 Subject: [PATCH 4/4] Fixed Windows CI failures in ExpansionVariableLogMessageTest --- .../tools/common/config/ExpansionVariableLogMessageTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/java/io/openliberty/tools/common/config/ExpansionVariableLogMessageTest.java b/src/test/java/io/openliberty/tools/common/config/ExpansionVariableLogMessageTest.java index 6324b7c5c..6ceb013b7 100644 --- a/src/test/java/io/openliberty/tools/common/config/ExpansionVariableLogMessageTest.java +++ b/src/test/java/io/openliberty/tools/common/config/ExpansionVariableLogMessageTest.java @@ -126,7 +126,9 @@ public void testWindowsStyleBackslashesPreservedInLog() throws Exception { String envContent = "IBM_JAVA_SEMERU_HOME=C:\\\\MyData\\\\java\\\\ibm-semeru-certified\nJAVA_HOME=!IBM_JAVA_SEMERU_HOME!\\\\jdk-21.0.10+7\n"; buildDoc(log, serverDir, envContent).processServerEnv(); - String expectedMsg = "Resolved environment variable \"IBM_JAVA_SEMERU_HOME\" in path \"!IBM_JAVA_SEMERU_HOME!\\jdk-21.0.10+7\" to \"C:\\MyData\\java\\ibm-semeru-certified\\jdk-21.0.10+7\""; + // per-var log: shows only what IBM_JAVA_SEMERU_HOME itself resolved to, not the full concatenated value + String expectedMsg = "Resolved environment variable \"IBM_JAVA_SEMERU_HOME\" in path \"!IBM_JAVA_SEMERU_HOME!\\jdk-21.0.10+7\" to \"C:\\MyData\\java\\ibm-semeru-certified\""; + // summary log: shows the full expression after all substitutions String expectedSummary = "Resolved path \"!IBM_JAVA_SEMERU_HOME!\\jdk-21.0.10+7\" to \"C:\\MyData\\java\\ibm-semeru-certified\\jdk-21.0.10+7\""; assertTrue("Log message with backslashes not found — backslashes may have been dropped.\nActual: " + log.infoMessages, log.infoMessages.stream().anyMatch(m -> m.equals(expectedMsg)));