Repository: OpenLiberty/open-liberty
Pull request #31189: Add MP Config visibility tests
Author: login: Azquelt
Labels: name: noproductcode
Created: 2025-04-07T16:03:44Z | Merged: 2025-04-10T12:55:15Z

Tests which config sources can be seen from different parts of an .ear.

Only tests the microprofile-config.properties config source since it is impacted by the classloader used, which varies throughout the .ear.

There's no behaviour change here, this just asserts the current behaviour.

- [x] I have considered the risk of behavior change or other zero migration impact (https://github.com/OpenLiberty/open-liberty/wiki/Behavior-Changes).
- [x] If this PR fixes an Issue, the description includes "Fixes #FILLMEIN" or "Resolves #FILLMEIN" (verify `release bug` label if applicable: https://github.com/OpenLiberty/open-liberty/wiki/Open-Liberty-Conventions).
- [x] If this PR resolves an external Known Issue (including APARS), the description includes "Fixes #FILLMEIN" or "Resolves #FILLMEIN".



Diff:
diff --git a/dev/com.ibm.ws.microprofile.config.1.1_fat/bnd.bnd b/dev/com.ibm.ws.microprofile.config.1.1_fat/bnd.bnd
index b25221d9508..eb1adbbdd1a 100644
--- a/dev/com.ibm.ws.microprofile.config.1.1_fat/bnd.bnd
+++ b/dev/com.ibm.ws.microprofile.config.1.1_fat/bnd.bnd
@@ -1,5 +1,5 @@
 #*******************************************************************************
-# Copyright (c) 2017, 2021 IBM Corporation and others.
+# Copyright (c) 2017, 2025 IBM Corporation and others.
 # All rights reserved. This program and the accompanying materials
 # are made available under the terms of the Eclipse Public License 2.0
 # which accompanies this distribution, and is available at
@@ -47,6 +47,8 @@ tested.features: mpConfig-1.1,\
                  cdi-3.0,\
                  cdi-4.0,\
                  cdi-4.1,\
+                 ejbLite-3.2,\
+                 enterpriseBeansLite-4.0,\
                  localconnector-1.0,\
                  servlet-3.1,\
                  servlet-4.0,\
@@ -57,8 +59,9 @@ tested.features: mpConfig-1.1,\
 -buildpath: \
 	com.ibm.websphere.javaee.servlet.3.1;version=latest,\
 	com.ibm.websphere.org.eclipse.microprofile.config.1.1;version=latest,\
-        com.ibm.ws.microprofile.config.1.1;version=latest,\
-        com.ibm.ws.microprofile.config.1.1.cdi;version=latest,\
-        com.ibm.websphere.javaee.annotation.1.2;version=latest,\
+	com.ibm.ws.microprofile.config.1.1;version=latest,\
+	com.ibm.ws.microprofile.config.1.1.cdi;version=latest,\
+	com.ibm.websphere.javaee.annotation.1.2;version=latest,\
 	com.ibm.websphere.javaee.cdi.1.2;version=latest,\
+	com.ibm.websphere.javaee.ejb.3.2;version=latest,\
 	io.openliberty.microprofile.config.internal_repeat_tests;version=latest
diff --git a/dev/com.ibm.ws.microprofile.config.1.1_fat/fat/src/com/ibm/ws/microprofile/config/fat/suite/FATSuite.java b/dev/com.ibm.ws.microprofile.config.1.1_fat/fat/src/com/ibm/ws/microprofile/config/fat/suite/FATSuite.java
index d003df0855e..31a66c0aaab 100644
--- a/dev/com.ibm.ws.microprofile.config.1.1_fat/fat/src/com/ibm/ws/microprofile/config/fat/suite/FATSuite.java
+++ b/dev/com.ibm.ws.microprofile.config.1.1_fat/fat/src/com/ibm/ws/microprofile/config/fat/suite/FATSuite.java
@@ -1,10 +1,10 @@
 /*******************************************************************************
- * Copyright (c) 2016, 2020 IBM Corporation and others.
+ * Copyright (c) 2016, 2025 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-2.0/
- * 
+ *
  * SPDX-License-Identifier: EPL-2.0
  *
  * Contributors:
@@ -22,6 +22,7 @@
 import com.ibm.ws.microprofile.config.fat.tests.CDIBrokenInjectionTest;
 import com.ibm.ws.microprofile.config.fat.tests.ClassLoaderCacheTest;
 import com.ibm.ws.microprofile.config.fat.tests.ClassLoadersTest;
+import com.ibm.ws.microprofile.config.fat.tests.VisibilityTest;
 import com.ibm.ws.microprofile.config.fat.tests.DefaultSourcesTest;
 import com.ibm.ws.microprofile.config.fat.tests.DynamicSourcesTest;
 import com.ibm.ws.microprofile.config.fat.tests.LibertySpecificConfigTests;
@@ -47,6 +48,7 @@
                 SimultaneousRequestsTest.class, //FULL
                 SharedLibTest.class, //FULL
                 StressTest.class, //FULL
+                VisibilityTest.class, //FULL
 
                 // The following don't repeat against mpConfig > 1.4. See classes for why.
                 LibertySpecificConfigTests.class, //FULL
diff --git a/dev/com.ibm.ws.microprofile.config.1.1_fat/fat/src/com/ibm/ws/microprofile/config/fat/tests/VisibilityTest.java b/dev/com.ibm.ws.microprofile.config.1.1_fat/fat/src/com/ibm/ws/microprofile/config/fat/tests/VisibilityTest.java
new file mode 100644
index 00000000000..2e69f67d94a
--- /dev/null
+++ b/dev/com.ibm.ws.microprofile.config.1.1_fat/fat/src/com/ibm/ws/microprofile/config/fat/tests/VisibilityTest.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2025 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package com.ibm.ws.microprofile.config.fat.tests;
+
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EAR_LIB_CONFIG_PROPERTY;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EAR_LIB_VALUE;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EJB_JAR_CONFIG_PROPERTY;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EJB_JAR_VALUE;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.WAR_CONFIG_PROPERTY;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.WAR_VALUE;
+
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.EnterpriseArchive;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.runner.RunWith;
+
+import com.ibm.websphere.simplicity.PropertiesAsset;
+import com.ibm.websphere.simplicity.ShrinkHelper;
+import com.ibm.websphere.simplicity.ShrinkHelper.DeployOptions;
+import com.ibm.ws.microprofile.config.fat.suite.SharedShrinkWrapApps;
+import com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.EarLibBean;
+import com.ibm.ws.microprofile.config.fat.tests.visibility.ejbjar.VisibilityTestEjb;
+import com.ibm.ws.microprofile.config.fat.tests.visibility.war.VisibilityTestServlet;
+
+import componenttest.annotation.Server;
+import componenttest.annotation.TestServlet;
+import componenttest.custom.junit.runner.FATRunner;
+import componenttest.rules.repeater.RepeatTests;
+import componenttest.topology.impl.LibertyServer;
+import componenttest.topology.utils.FATServletClient;
+import io.openliberty.microprofile.config.fat.repeat.ConfigRepeatActions;
+
+/**
+ * Tests which config sources can be seen from different locations within an .ear
+ */
+@RunWith(FATRunner.class)
+public class VisibilityTest extends FATServletClient {
+
+    public static final String SERVER_NAME = "VisibilityServer";
+    public static final String APP_NAME = "VisibilityTest";
+
+    @Server(SERVER_NAME)
+    @TestServlet(servlet = VisibilityTestServlet.class, contextRoot = APP_NAME)
+    public static LibertyServer server;
+
+    @ClassRule
+    public static RepeatTests r = ConfigRepeatActions.repeatDefault(SERVER_NAME);
+
+    @BeforeClass
+    public static void setUp() throws Exception {
+        JavaArchive testAppUtils = SharedShrinkWrapApps.getTestAppUtilsJar();
+
+        PropertiesAsset warConfig = new PropertiesAsset()
+                                                         .addProperty(WAR_CONFIG_PROPERTY, WAR_VALUE);
+        WebArchive war = ShrinkWrap.create(WebArchive.class, APP_NAME + ".war")
+                                   .addPackage(VisibilityTestServlet.class.getPackage())
+                                   .addAsResource(warConfig, "/META-INF/microprofile-config.properties");
+
+        PropertiesAsset ejbJarConfig = new PropertiesAsset()
+                                                            .addProperty(EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        JavaArchive ejbJar = ShrinkWrap.create(JavaArchive.class, APP_NAME + "ejb.jar")
+                                       .addPackage(VisibilityTestEjb.class.getPackage())
+                                       .addAsResource(ejbJarConfig, "/META-INF/microprofile-config.properties");
+
+        PropertiesAsset earLibConfig = new PropertiesAsset()
+                                                            .addProperty(EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+        JavaArchive earLibJar = ShrinkWrap.create(JavaArchive.class, APP_NAME + "-earlib.jar")
+                                          .addPackage(EarLibBean.class.getPackage())
+                                          .addAsResource(earLibConfig, "/META-INF/microprofile-config.properties");
+
+        EnterpriseArchive ear = ShrinkWrap.create(EnterpriseArchive.class, APP_NAME + ".ear")
+                                          .addAsModule(war)
+                                          .addAsModule(ejbJar)
+                                          .addAsLibrary(earLibJar)
+                                          .addAsLibrary(testAppUtils);
+
+        ShrinkHelper.exportDropinAppToServer(server, ear, DeployOptions.SERVER_ONLY);
+
+        server.startServer();
+    }
+
+    @AfterClass
+    public static void tearDown() throws Exception {
+        server.stopServer();
+    }
+
+}
diff --git a/dev/com.ibm.ws.microprofile.config.1.1_fat/fat/src/com/ibm/ws/microprofile/config/fat/tests/visibility/earlib/EarLibBean.java b/dev/com.ibm.ws.microprofile.config.1.1_fat/fat/src/com/ibm/ws/microprofile/config/fat/tests/visibility/earlib/EarLibBean.java
new file mode 100644
index 00000000000..0ede2a33bb5
--- /dev/null
+++ b/dev/com.ibm.ws.microprofile.config.1.1_fat/fat/src/com/ibm/ws/microprofile/config/fat/tests/visibility/earlib/EarLibBean.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2025 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package com.ibm.ws.microprofile.config.fat.tests.visibility.earlib;
+
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EAR_LIB_CONFIG_PROPERTY;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EJB_JAR_CONFIG_PROPERTY;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.WAR_CONFIG_PROPERTY;
+
+import java.util.Optional;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+
+import org.eclipse.microprofile.config.Config;
+import org.eclipse.microprofile.config.ConfigProvider;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+
+@ApplicationScoped
+public class EarLibBean {
+
+    @Inject
+    private Config injectedConfig;
+
+    @Inject
+    @ConfigProperty(name = WAR_CONFIG_PROPERTY)
+    private Optional<String> warProperty;
+
+    @Inject
+    @ConfigProperty(name = EJB_JAR_CONFIG_PROPERTY)
+    private Optional<String> ejbJarProperty;
+
+    @Inject
+    @ConfigProperty(name = EAR_LIB_CONFIG_PROPERTY)
+    private Optional<String> earLibProperty;
+
+    public Config getConfig() {
+        return ConfigProvider.getConfig();
+    }
+
+    public Config getInjectedConfig() {
+        return injectedConfig;
+    }
+
+    public Optional<String> getWarProperty() {
+        return warProperty;
+    }
+
+    public Optional<String> getEjbJarProperty() {
+        return ejbJarProperty;
+    }
+
+    public Optional<String> getEarLibProperty() {
+        return earLibProperty;
+    }
+}
diff --git a/dev/com.ibm.ws.microprofile.config.1.1_fat/fat/src/com/ibm/ws/microprofile/config/fat/tests/visibility/earlib/EarLibDependentBean.java b/dev/com.ibm.ws.microprofile.config.1.1_fat/fat/src/com/ibm/ws/microprofile/config/fat/tests/visibility/earlib/EarLibDependentBean.java
new file mode 100644
index 00000000000..ee8abca646e
--- /dev/null
+++ b/dev/com.ibm.ws.microprofile.config.1.1_fat/fat/src/com/ibm/ws/microprofile/config/fat/tests/visibility/earlib/EarLibDependentBean.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2025 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package com.ibm.ws.microprofile.config.fat.tests.visibility.earlib;
+
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EAR_LIB_CONFIG_PROPERTY;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EJB_JAR_CONFIG_PROPERTY;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.WAR_CONFIG_PROPERTY;
+
+import java.util.Optional;
+
+import javax.enterprise.context.Dependent;
+import javax.inject.Inject;
+
+import org.eclipse.microprofile.config.Config;
+import org.eclipse.microprofile.config.ConfigProvider;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+
+@Dependent
+public class EarLibDependentBean {
+
+    @Inject
+    private Config injectedConfig;
+
+    @Inject
+    @ConfigProperty(name = WAR_CONFIG_PROPERTY)
+    private Optional<String> warProperty;
+
+    @Inject
+    @ConfigProperty(name = EJB_JAR_CONFIG_PROPERTY)
+    private Optional<String> ejbJarProperty;
+
+    @Inject
+    @ConfigProperty(name = EAR_LIB_CONFIG_PROPERTY)
+    private Optional<String> earLibProperty;
+
+    public Config getConfig() {
+        return ConfigProvider.getConfig();
+    }
+
+    public Config getInjectedConfig() {
+        return injectedConfig;
+    }
+
+    public Optional<String> getWarProperty() {
+        return warProperty;
+    }
+
+    public Optional<String> getEjbJarProperty() {
+        return ejbJarProperty;
+    }
+
+    public Optional<String> getEarLibProperty() {
+        return earLibProperty;
+    }
+}
diff --git a/dev/com.ibm.ws.microprofile.config.1.1_fat/fat/src/com/ibm/ws/microprofile/config/fat/tests/visibility/earlib/VisibilityTestConstants.java b/dev/com.ibm.ws.microprofile.config.1.1_fat/fat/src/com/ibm/ws/microprofile/config/fat/tests/visibility/earlib/VisibilityTestConstants.java
new file mode 100644
index 00000000000..e09144c90d5
--- /dev/null
+++ b/dev/com.ibm.ws.microprofile.config.1.1_fat/fat/src/com/ibm/ws/microprofile/config/fat/tests/visibility/earlib/VisibilityTestConstants.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2025 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package com.ibm.ws.microprofile.config.fat.tests.visibility.earlib;
+
+public class VisibilityTestConstants {
+
+    public static final String EAR_LIB_VALUE = "earLibValue";
+    public static final String EAR_LIB_CONFIG_PROPERTY = "earlib.meta-inf.config.properties";
+
+    public static final String EJB_JAR_VALUE = "ejbJarValue";
+    public static final String EJB_JAR_CONFIG_PROPERTY = "ejbjar.meta-inf.config.properties";
+
+    public static final String WAR_VALUE = "warValue";
+    public static final String WAR_CONFIG_PROPERTY = "war.meta-inf.config.properties";
+
+}
diff --git a/dev/com.ibm.ws.microprofile.config.1.1_fat/fat/src/com/ibm/ws/microprofile/config/fat/tests/visibility/ejbjar/VisibilityTestEjb.java b/dev/com.ibm.ws.microprofile.config.1.1_fat/fat/src/com/ibm/ws/microprofile/config/fat/tests/visibility/ejbjar/VisibilityTestEjb.java
new file mode 100644
index 00000000000..23105dc16b4
--- /dev/null
+++ b/dev/com.ibm.ws.microprofile.config.1.1_fat/fat/src/com/ibm/ws/microprofile/config/fat/tests/visibility/ejbjar/VisibilityTestEjb.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2025 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package com.ibm.ws.microprofile.config.fat.tests.visibility.ejbjar;
+
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EAR_LIB_CONFIG_PROPERTY;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EJB_JAR_CONFIG_PROPERTY;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.WAR_CONFIG_PROPERTY;
+
+import java.util.Optional;
+
+import javax.ejb.LocalBean;
+import javax.ejb.Stateless;
+import javax.inject.Inject;
+
+import org.eclipse.microprofile.config.Config;
+import org.eclipse.microprofile.config.ConfigProvider;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+
+import com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.EarLibBean;
+import com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.EarLibDependentBean;
+
+@Stateless
+@LocalBean
+public class VisibilityTestEjb {
+
+    @Inject
+    private Config injectedConfig;
+
+    @Inject
+    private EarLibBean earLibBean;
+
+    @Inject
+    private EarLibDependentBean earLibDependentBean;
+
+    @Inject
+    @ConfigProperty(name = WAR_CONFIG_PROPERTY)
+    private Optional<String> warProperty;
+
+    @Inject
+    @ConfigProperty(name = EJB_JAR_CONFIG_PROPERTY)
+    private Optional<String> ejbJarProperty;
+
+    @Inject
+    @ConfigProperty(name = EAR_LIB_CONFIG_PROPERTY)
+    private Optional<String> earLibProperty;
+
+    public Config getConfig() {
+        return ConfigProvider.getConfig();
+    }
+
+    public Config getInjectedConfig() {
+        return injectedConfig;
+    }
+
+    public EarLibBean getEarLibBean() {
+        return earLibBean;
+    }
+
+    public EarLibDependentBean getEarLibDependentBean() {
+        return earLibDependentBean;
+    }
+
+    public Optional<String> getWarProperty() {
+        return warProperty;
+    }
+
+    public Optional<String> getEjbJarProperty() {
+        return ejbJarProperty;
+    }
+
+    public Optional<String> getEarLibProperty() {
+        return earLibProperty;
+    }
+}
diff --git a/dev/com.ibm.ws.microprofile.config.1.1_fat/fat/src/com/ibm/ws/microprofile/config/fat/tests/visibility/war/VisibilityTestServlet.java b/dev/com.ibm.ws.microprofile.config.1.1_fat/fat/src/com/ibm/ws/microprofile/config/fat/tests/visibility/war/VisibilityTestServlet.java
new file mode 100644
index 00000000000..10be7f83cea
--- /dev/null
+++ b/dev/com.ibm.ws.microprofile.config.1.1_fat/fat/src/com/ibm/ws/microprofile/config/fat/tests/visibility/war/VisibilityTestServlet.java
@@ -0,0 +1,282 @@
+/*******************************************************************************
+ * Copyright (c) 2025 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package com.ibm.ws.microprofile.config.fat.tests.visibility.war;
+
+import static com.ibm.ws.microprofile.appConfig.test.utils.TestUtils.assertContains;
+import static com.ibm.ws.microprofile.appConfig.test.utils.TestUtils.assertNotContains;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EAR_LIB_CONFIG_PROPERTY;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EAR_LIB_VALUE;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EJB_JAR_CONFIG_PROPERTY;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EJB_JAR_VALUE;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.WAR_CONFIG_PROPERTY;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.WAR_VALUE;
+
+import java.util.Arrays;
+import java.util.Optional;
+
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+import javax.servlet.annotation.WebServlet;
+
+import org.eclipse.microprofile.config.Config;
+import org.eclipse.microprofile.config.ConfigProvider;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+import org.junit.Test;
+
+import com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.EarLibBean;
+import com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.EarLibDependentBean;
+import com.ibm.ws.microprofile.config.fat.tests.visibility.ejbjar.VisibilityTestEjb;
+
+import componenttest.app.FATServlet;
+
+/**
+ * Tests which config sources can be seen from different locations within an .ear
+ * <p>
+ * Each test uses one method of reading config properties from one location within the .ear
+ */
+@WebServlet("/testWar")
+public class VisibilityTestServlet extends FATServlet {
+
+    private static final long serialVersionUID = 1L;
+
+    @Inject
+    private VisibilityTestEjb testEjb;
+
+    @Inject
+    private EarLibBean earLibBean;
+
+    @Inject
+    private EarLibDependentBean earLibDependentBean;
+
+    @Inject
+    private Config injectedConfig;
+
+    @Inject
+    @ConfigProperty(name = WAR_CONFIG_PROPERTY)
+    private Optional<String> warProperty;
+
+    @Inject
+    @ConfigProperty(name = EJB_JAR_CONFIG_PROPERTY)
+    private Optional<String> ejbJarProperty;
+
+    @Inject
+    @ConfigProperty(name = EAR_LIB_CONFIG_PROPERTY)
+    private Optional<String> earLibProperty;
+
+    @PostConstruct
+    private void initializeInjectedConfig() {
+        // Initialize the injected Config object before running any tests
+        // This should ensure it's initialized in the context of the .war, even if one of the EJB tests is the first to run
+        // This is important because mpConfig-1.x uses an ApplicationScoped Config bean which will use whichever TCCL is active when it's initialized
+        // and we want that to be consistent regardless of the order tests are run
+
+        // Calling any method is sufficient to initialize the bean
+        injectedConfig.getConfigSources();
+    }
+
+    @Test
+    public void testGetConfigFromWar() {
+        // GetConfig from this .war
+        Config config = ConfigProvider.getConfig();
+
+        // Expect to see properties from all locations visible on classpath
+        assertContains(config, WAR_CONFIG_PROPERTY, WAR_VALUE);
+        assertContains(config, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(config, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+    }
+
+    @Test
+    public void testGetConfigFromEjbJar() {
+        // GetConfig from an ejb
+        Config config = testEjb.getConfig();
+
+        // Expect to see properties from all locations visible on classpath
+        assertContains(config, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(config, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+        assertNotContains(config, WAR_CONFIG_PROPERTY);
+    }
+
+    @Test
+    public void testGetConfigFromEarLib() {
+        // getConfig called from app scoped ear lib jar
+        Config config = earLibBean.getConfig();
+
+        // Expect to see everything visible to the .war, since the TCCL is the war classloader when getConfig was called
+        assertContains(config, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(config, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+        assertContains(config, WAR_CONFIG_PROPERTY, WAR_VALUE);
+
+        // Same bean obtained via EJB
+        config = testEjb.getEarLibBean().getConfig();
+
+        // Expect to see everything visible to the .war
+        // We get the bean via the EJB, but we call the bean ourselves, so it's the .war TCCL that's active
+        assertContains(config, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(config, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+        assertContains(config, WAR_CONFIG_PROPERTY, WAR_VALUE);
+
+        // Test with dependent-scoped ear lib jar
+        config = earLibDependentBean.getConfig();
+
+        // Expect same results as app-scoped bean
+        // The bean creation has no impact when calling getConfig
+        assertContains(config, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(config, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+        assertContains(config, WAR_CONFIG_PROPERTY, WAR_VALUE);
+
+        // Test with dependent-scoped ear lib jar obtained via EJB
+        config = testEjb.getEarLibDependentBean().getConfig();
+
+        // Expect to see everything visible to the .war
+        // We get the bean via the EJB, but we call the bean ourselves, so it's the .war TCCL that's active
+        assertContains(config, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(config, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+        assertContains(config, WAR_CONFIG_PROPERTY, WAR_VALUE);
+    }
+
+    @Test
+    public void testInjectedConfigFromWar() {
+        // Config injected into .war
+        Config config = injectedConfig;
+
+        // Expect to see properties from all locations visible on war classpath
+        assertContains(config, WAR_CONFIG_PROPERTY, WAR_VALUE);
+        assertContains(config, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(config, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+    }
+
+    @Test
+    public void testInjectedConfigFromEjbJar() {
+        // Config injected into EJB
+        Config config = testEjb.getInjectedConfig();
+
+        // Expect to see properties from all locations visible on EJB jar classpath
+        assertContains(config, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(config, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+
+        if (isMpConfig1x()) {
+            // In mpConfig 1.x, the injected Config bean is ApplicationScoped, and reports the same properties everywhere
+            // It gets initialized wherever it's first used (which is from the .war)
+            assertContains(config, WAR_CONFIG_PROPERTY, WAR_VALUE);
+        } else {
+            // In mpConfig 2.0 and later, the injected Config bean is Dependent-scoped and will take its values from the EJB module TCCL
+            assertNotContains(config, WAR_CONFIG_PROPERTY);
+        }
+    }
+
+    @Test
+    public void testInjectedConfigFromEarLib() {
+        // Config injected into app scoped ear lib jar
+        Config config = earLibBean.getInjectedConfig();
+
+        // Expect to see everything visible to the .war, since the war TCCL was active when the bean was created
+        assertContains(config, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(config, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+        assertContains(config, WAR_CONFIG_PROPERTY, WAR_VALUE);
+
+        // Same bean obtained via EJB
+        config = testEjb.getEarLibBean().getInjectedConfig();
+
+        // Expect to see everything visible to the .war
+        // The bean is app scoped, the injected config is not changed after the bean is created
+        // The bean was created with the war TCCL
+        assertContains(config, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(config, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+        assertContains(config, WAR_CONFIG_PROPERTY, WAR_VALUE);
+
+        // Test with dependent-scoped ear lib jar
+        config = earLibDependentBean.getInjectedConfig();
+
+        // Expect same results as app-scoped bean
+        // Expect to see everything visible to the .war, since the war TCCL was active when the bean was created
+        assertContains(config, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(config, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+        assertContains(config, WAR_CONFIG_PROPERTY, WAR_VALUE);
+
+        // Test with dependent-scoped ear lib jar obtained via EJB
+        config = testEjb.getEarLibDependentBean().getInjectedConfig();
+
+        // Expect to see only values visible to the EJB jar
+        // Dependent scope means the bean will be created when the EJB instance is created, with the EJB TCCL active
+        assertContains(config, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(config, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+
+        if (isMpConfig1x()) {
+            // In mpConfig 1.x, the injected Config bean is ApplicationScoped, and reports the same properties everywhere
+            // It gets initialized wherever it's first used (which is from the .war)
+            assertContains(config, WAR_CONFIG_PROPERTY, WAR_VALUE);
+        } else {
+            // In mpConfig 2.0 and later, the injected Config bean is Dependent-scoped and will take its values from the EJB module TCCL
+            assertNotContains(config, WAR_CONFIG_PROPERTY);
+        }
+    }
+
+    @Test
+    public void testInjectedPropertyFromWar() {
+        // Behaviour when injecting config properties is the same as when injecting the Config itself
+        // Expect to see properties from all locations visible on war classpath
+        assertContains(warProperty, WAR_CONFIG_PROPERTY, WAR_VALUE);
+        assertContains(ejbJarProperty, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(earLibProperty, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+    }
+
+    @Test
+    public void testInjectedPropertyFromEjbJar() {
+        // Behaviour when injecting config properties is the same as when injecting the Config itself
+        // Expect to see properties from all locations visible on EJB jar classpath
+        assertContains(testEjb.getEjbJarProperty(), EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(testEjb.getEarLibProperty(), EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+        assertNotContains(testEjb.getWarProperty(), WAR_CONFIG_PROPERTY);
+    }
+
+    @Test
+    public void testInjectedPropertyFromEarLib() {
+        // Behaviour when injecting config properties is the same as when injecting the Config itself
+
+        // Properties injected into app-scoped ear lib jar
+        // Expect to see everything visible to the .war, since the war TCCL was active when the bean was created
+        assertContains(earLibBean.getEjbJarProperty(), EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(earLibBean.getEarLibProperty(), EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+        assertContains(earLibBean.getWarProperty(), WAR_CONFIG_PROPERTY, WAR_VALUE);
+
+        // Properties injected into same bean, obtained via EJB
+        // Expect to see everything visible to the .war, since the bean was created and injected when the .war TCCL was active
+        assertContains(testEjb.getEarLibBean().getEjbJarProperty(), EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(testEjb.getEarLibBean().getEarLibProperty(), EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+        assertContains(testEjb.getEarLibBean().getWarProperty(), WAR_CONFIG_PROPERTY, WAR_VALUE);
+
+        // Test with a dependent-scoped ear lib jar
+        // Expect to see everything visible to the .war, since the war TTCL was active when the bean was created
+        assertContains(earLibDependentBean.getEjbJarProperty(), EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(earLibDependentBean.getEarLibProperty(), EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+        assertContains(earLibDependentBean.getWarProperty(), WAR_CONFIG_PROPERTY, WAR_VALUE);
+
+        // Expect to see only values visible to the EJB jar
+        // Dependent scope means the bean will be created when the EJB instance is created, with the EJB TCCL active
+        assertContains(testEjb.getEarLibDependentBean().getEjbJarProperty(), EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(testEjb.getEarLibDependentBean().getEarLibProperty(), EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+        assertNotContains(testEjb.getEarLibDependentBean().getWarProperty(), WAR_CONFIG_PROPERTY);
+    }
+
+    /**
+     * Check whether we're testing mpConfig-1.x
+     *
+     * @return {@code true} if running with MP Config 1.x, otherwise {@code false}
+     */
+    private boolean isMpConfig1x() {
+        // Check for the existence of Config.getValues methods, added in MP Config 2.0
+        // It's a bit of a hack but it's the easiest way to check the feature version from within an app
+        // and avoids lots of duplication in the tests
+        boolean hasGetValues = Arrays.stream(Config.class.getMethods())
+                                     .anyMatch(m -> m.getName().equals("getValues"));
+        return !hasGetValues;
+    }
+
+}
diff --git a/dev/com.ibm.ws.microprofile.config.1.1_fat/publish/servers/VisibilityServer/bootstrap.properties b/dev/com.ibm.ws.microprofile.config.1.1_fat/publish/servers/VisibilityServer/bootstrap.properties
new file mode 100644
index 00000000000..4f1ae5a2e10
--- /dev/null
+++ b/dev/com.ibm.ws.microprofile.config.1.1_fat/publish/servers/VisibilityServer/bootstrap.properties
@@ -0,0 +1 @@
+bootstrap.include=../testports.properties
diff --git a/dev/com.ibm.ws.microprofile.config.1.1_fat/publish/servers/VisibilityServer/server.xml b/dev/com.ibm.ws.microprofile.config.1.1_fat/publish/servers/VisibilityServer/server.xml
new file mode 100644
index 00000000000..26e08adaf3b
--- /dev/null
+++ b/dev/com.ibm.ws.microprofile.config.1.1_fat/publish/servers/VisibilityServer/server.xml
@@ -0,0 +1,13 @@
+<server description="Server for testing appConfig">
+
+	<include location="../fatTestPorts.xml" />
+
+	<featureManager>
+        <feature>osgiconsole-1.0</feature>
+        <feature>cdi-2.0</feature>
+        <feature>servlet-4.0</feature>
+        <feature>componentTest-1.0</feature>
+        <feature>mpConfig-1.4</feature>
+        <feature>ejbLite-3.2</feature>
+    </featureManager>
+</server>
\ No newline at end of file
diff --git a/dev/com.ibm.ws.microprofile.config.1.1_fat/test-applications/testAppUtils.jar/src/com/ibm/ws/microprofile/appConfig/test/utils/TestUtils.java b/dev/com.ibm.ws.microprofile.config.1.1_fat/test-applications/testAppUtils.jar/src/com/ibm/ws/microprofile/appConfig/test/utils/TestUtils.java
index 33d1bbb5cb8..0ae0c80fa94 100644
--- a/dev/com.ibm.ws.microprofile.config.1.1_fat/test-applications/testAppUtils.jar/src/com/ibm/ws/microprofile/appConfig/test/utils/TestUtils.java
+++ b/dev/com.ibm.ws.microprofile.config.1.1_fat/test-applications/testAppUtils.jar/src/com/ibm/ws/microprofile/appConfig/test/utils/TestUtils.java
@@ -1,10 +1,10 @@
 /*******************************************************************************
- * Copyright (c) 2016 IBM Corporation and others.
+ * Copyright (c) 2016, 2025 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-2.0/
- * 
+ *
  * SPDX-License-Identifier: EPL-2.0
  *
  * Contributors:
@@ -37,7 +37,11 @@ public static <T> void assertContains(Config config, String key, T expected) {
         }
         @SuppressWarnings("unchecked")
         Optional<T> opt = config.getOptionalValue(key, (Class<T>) expected.getClass());
-        T actual = opt.orElse(null);
+        assertContains(opt, key, expected);
+    }
+
+    public static <T> void assertContains(Optional<T> optional, String key, T expected) {
+        T actual = optional.orElse(null);
         if (actual == null) {
             throw new AssertionError("Value for key '" + key + "' was null");
         }
@@ -59,6 +63,13 @@ public static <T> void assertNotContains(Config config, String key, Class<T> cla
         }
     }
 
+    public static <T> void assertNotContains(Optional<T> optional, String key) {
+        if (optional.isPresent()) {
+            T value = optional.get();
+            throw new AssertionError("Key '" + key + "' was found. Value was '" + value + "'");
+        }
+    }
+
     public static void assertEquals(Object expected, Object actual) {
         if (expected != null && !expected.equals(actual)) {
             throw new AssertionError("Expected: " + expected + ". Actual: " + actual);


Reviews:
user: login: benjamin-confino
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-09T20:09:31Z
user: login: benjamin-confino
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-09T20:12:54Z
user: login: benjamin-confino
body: I like the extensive commenting, made it very clear what was going on. 
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-09T20:14:58Z
user: login: Azquelt
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-10T12:53:12Z
user: login: Azquelt
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-10T12:55:03Z

Review comments:
diff_hunk: @@ -0,0 +1,282 @@
+/*******************************************************************************
+ * Copyright (c) 2025 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package com.ibm.ws.microprofile.config.fat.tests.visibility.war;
+
+import static com.ibm.ws.microprofile.appConfig.test.utils.TestUtils.assertContains;
+import static com.ibm.ws.microprofile.appConfig.test.utils.TestUtils.assertNotContains;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EAR_LIB_CONFIG_PROPERTY;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EAR_LIB_VALUE;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EJB_JAR_CONFIG_PROPERTY;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EJB_JAR_VALUE;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.WAR_CONFIG_PROPERTY;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.WAR_VALUE;
+
+import java.util.Arrays;
+import java.util.Optional;
+
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+import javax.servlet.annotation.WebServlet;
+
+import org.eclipse.microprofile.config.Config;
+import org.eclipse.microprofile.config.ConfigProvider;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+import org.junit.Test;
+
+import com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.EarLibBean;
+import com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.EarLibDependentBean;
+import com.ibm.ws.microprofile.config.fat.tests.visibility.ejbjar.VisibilityTestEjb;
+
+import componenttest.app.FATServlet;
+
+/**
+ * Tests which config sources can be seen from different locations within an .ear
+ * <p>
+ * Each test uses one method of reading config properties from one location within the .ear
+ */
+@WebServlet("/testWar")
+public class VisibilityTestServlet extends FATServlet {
+
+    private static final long serialVersionUID = 1L;
+
+    @Inject
+    private VisibilityTestEjb testEjb;
+
+    @Inject
+    private EarLibBean earLibBean;
+
+    @Inject
+    private EarLibDependentBean earLibDependentBean;
+
+    @Inject
+    private Config injectedConfig;
+
+    @Inject
+    @ConfigProperty(name = WAR_CONFIG_PROPERTY)
+    private Optional<String> warProperty;
+
+    @Inject
+    @ConfigProperty(name = EJB_JAR_CONFIG_PROPERTY)
+    private Optional<String> ejbJarProperty;
+
+    @Inject
+    @ConfigProperty(name = EAR_LIB_CONFIG_PROPERTY)
+    private Optional<String> earLibProperty;
+
+    @PostConstruct
+    private void initializeInjectedConfig() {
+        // Initialize the injected Config object before running any tests
+        // This should ensure it's initialized in the context of the .war, even if one of the EJB tests is the first to run
+        // This is important because mpConfig-1.x uses an ApplicationScoped Config bean which will use whichever TCCL is active when it's initialized
path: dev/com.ibm.ws.microprofile.config.1.1_fat/fat/src/com/ibm/ws/microprofile/config/fat/tests/visibility/war/VisibilityTestServlet.java
user: login: benjamin-confino
body: Well that sounds nightmarish. Hopefully that's fixed on later mpConfigs?
created_at: 2025-04-09T20:09:31Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,282 @@
+/*******************************************************************************
+ * Copyright (c) 2025 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package com.ibm.ws.microprofile.config.fat.tests.visibility.war;
+
+import static com.ibm.ws.microprofile.appConfig.test.utils.TestUtils.assertContains;
+import static com.ibm.ws.microprofile.appConfig.test.utils.TestUtils.assertNotContains;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EAR_LIB_CONFIG_PROPERTY;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EAR_LIB_VALUE;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EJB_JAR_CONFIG_PROPERTY;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EJB_JAR_VALUE;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.WAR_CONFIG_PROPERTY;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.WAR_VALUE;
+
+import java.util.Arrays;
+import java.util.Optional;
+
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+import javax.servlet.annotation.WebServlet;
+
+import org.eclipse.microprofile.config.Config;
+import org.eclipse.microprofile.config.ConfigProvider;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+import org.junit.Test;
+
+import com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.EarLibBean;
+import com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.EarLibDependentBean;
+import com.ibm.ws.microprofile.config.fat.tests.visibility.ejbjar.VisibilityTestEjb;
+
+import componenttest.app.FATServlet;
+
+/**
+ * Tests which config sources can be seen from different locations within an .ear
+ * <p>
+ * Each test uses one method of reading config properties from one location within the .ear
+ */
+@WebServlet("/testWar")
+public class VisibilityTestServlet extends FATServlet {
+
+    private static final long serialVersionUID = 1L;
+
+    @Inject
+    private VisibilityTestEjb testEjb;
+
+    @Inject
+    private EarLibBean earLibBean;
+
+    @Inject
+    private EarLibDependentBean earLibDependentBean;
+
+    @Inject
+    private Config injectedConfig;
+
+    @Inject
+    @ConfigProperty(name = WAR_CONFIG_PROPERTY)
+    private Optional<String> warProperty;
+
+    @Inject
+    @ConfigProperty(name = EJB_JAR_CONFIG_PROPERTY)
+    private Optional<String> ejbJarProperty;
+
+    @Inject
+    @ConfigProperty(name = EAR_LIB_CONFIG_PROPERTY)
+    private Optional<String> earLibProperty;
+
+    @PostConstruct
+    private void initializeInjectedConfig() {
+        // Initialize the injected Config object before running any tests
+        // This should ensure it's initialized in the context of the .war, even if one of the EJB tests is the first to run
+        // This is important because mpConfig-1.x uses an ApplicationScoped Config bean which will use whichever TCCL is active when it's initialized
+        // and we want that to be consistent regardless of the order tests are run
+
+        // Calling any method is sufficient to initialize the bean
+        injectedConfig.getConfigSources();
+    }
+
+    @Test
+    public void testGetConfigFromWar() {
+        // GetConfig from this .war
+        Config config = ConfigProvider.getConfig();
+
+        // Expect to see properties from all locations visible on classpath
+        assertContains(config, WAR_CONFIG_PROPERTY, WAR_VALUE);
+        assertContains(config, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(config, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+    }
+
+    @Test
+    public void testGetConfigFromEjbJar() {
+        // GetConfig from an ejb
+        Config config = testEjb.getConfig();
+
+        // Expect to see properties from all locations visible on classpath
+        assertContains(config, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(config, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+        assertNotContains(config, WAR_CONFIG_PROPERTY);
+    }
+
+    @Test
+    public void testGetConfigFromEarLib() {
+        // getConfig called from app scoped ear lib jar
+        Config config = earLibBean.getConfig();
+
+        // Expect to see everything visible to the .war, since the TCCL is the war classloader when getConfig was called
+        assertContains(config, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(config, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+        assertContains(config, WAR_CONFIG_PROPERTY, WAR_VALUE);
+
+        // Same bean obtained via EJB
+        config = testEjb.getEarLibBean().getConfig();
+
+        // Expect to see everything visible to the .war
+        // We get the bean via the EJB, but we call the bean ourselves, so it's the .war TCCL that's active
+        assertContains(config, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(config, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+        assertContains(config, WAR_CONFIG_PROPERTY, WAR_VALUE);
+
+        // Test with dependent-scoped ear lib jar
+        config = earLibDependentBean.getConfig();
+
+        // Expect same results as app-scoped bean
+        // The bean creation has no impact when calling getConfig
+        assertContains(config, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(config, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+        assertContains(config, WAR_CONFIG_PROPERTY, WAR_VALUE);
+
+        // Test with dependent-scoped ear lib jar obtained via EJB
+        config = testEjb.getEarLibDependentBean().getConfig();
+
+        // Expect to see everything visible to the .war
+        // We get the bean via the EJB, but we call the bean ourselves, so it's the .war TCCL that's active
+        assertContains(config, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(config, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+        assertContains(config, WAR_CONFIG_PROPERTY, WAR_VALUE);
+    }
+
+    @Test
+    public void testInjectedConfigFromWar() {
+        // Config injected into .war
+        Config config = injectedConfig;
+
+        // Expect to see properties from all locations visible on war classpath
+        assertContains(config, WAR_CONFIG_PROPERTY, WAR_VALUE);
+        assertContains(config, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(config, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+    }
+
+    @Test
+    public void testInjectedConfigFromEjbJar() {
+        // Config injected into EJB
+        Config config = testEjb.getInjectedConfig();
+
+        // Expect to see properties from all locations visible on EJB jar classpath
+        assertContains(config, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(config, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+
+        if (isMpConfig1x()) {
+            // In mpConfig 1.x, the injected Config bean is ApplicationScoped, and reports the same properties everywhere
+            // It gets initialized wherever it's first used (which is from the .war)
+            assertContains(config, WAR_CONFIG_PROPERTY, WAR_VALUE);
+        } else {
+            // In mpConfig 2.0 and later, the injected Config bean is Dependent-scoped and will take its values from the EJB module TCCL
path: dev/com.ibm.ws.microprofile.config.1.1_fat/fat/src/com/ibm/ws/microprofile/config/fat/tests/visibility/war/VisibilityTestServlet.java
user: login: benjamin-confino
body: I admit the fact what properties the class can see is dependent on its CDI scope and not which archive it is in feels wrong. 

But of course that doesn't make the test wrong. 
created_at: 2025-04-09T20:12:54Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,282 @@
+/*******************************************************************************
+ * Copyright (c) 2025 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package com.ibm.ws.microprofile.config.fat.tests.visibility.war;
+
+import static com.ibm.ws.microprofile.appConfig.test.utils.TestUtils.assertContains;
+import static com.ibm.ws.microprofile.appConfig.test.utils.TestUtils.assertNotContains;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EAR_LIB_CONFIG_PROPERTY;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EAR_LIB_VALUE;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EJB_JAR_CONFIG_PROPERTY;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EJB_JAR_VALUE;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.WAR_CONFIG_PROPERTY;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.WAR_VALUE;
+
+import java.util.Arrays;
+import java.util.Optional;
+
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+import javax.servlet.annotation.WebServlet;
+
+import org.eclipse.microprofile.config.Config;
+import org.eclipse.microprofile.config.ConfigProvider;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+import org.junit.Test;
+
+import com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.EarLibBean;
+import com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.EarLibDependentBean;
+import com.ibm.ws.microprofile.config.fat.tests.visibility.ejbjar.VisibilityTestEjb;
+
+import componenttest.app.FATServlet;
+
+/**
+ * Tests which config sources can be seen from different locations within an .ear
+ * <p>
+ * Each test uses one method of reading config properties from one location within the .ear
+ */
+@WebServlet("/testWar")
+public class VisibilityTestServlet extends FATServlet {
+
+    private static final long serialVersionUID = 1L;
+
+    @Inject
+    private VisibilityTestEjb testEjb;
+
+    @Inject
+    private EarLibBean earLibBean;
+
+    @Inject
+    private EarLibDependentBean earLibDependentBean;
+
+    @Inject
+    private Config injectedConfig;
+
+    @Inject
+    @ConfigProperty(name = WAR_CONFIG_PROPERTY)
+    private Optional<String> warProperty;
+
+    @Inject
+    @ConfigProperty(name = EJB_JAR_CONFIG_PROPERTY)
+    private Optional<String> ejbJarProperty;
+
+    @Inject
+    @ConfigProperty(name = EAR_LIB_CONFIG_PROPERTY)
+    private Optional<String> earLibProperty;
+
+    @PostConstruct
+    private void initializeInjectedConfig() {
+        // Initialize the injected Config object before running any tests
+        // This should ensure it's initialized in the context of the .war, even if one of the EJB tests is the first to run
+        // This is important because mpConfig-1.x uses an ApplicationScoped Config bean which will use whichever TCCL is active when it's initialized
path: dev/com.ibm.ws.microprofile.config.1.1_fat/fat/src/com/ibm/ws/microprofile/config/fat/tests/visibility/war/VisibilityTestServlet.java
user: login: Azquelt
body: Yeah, the injected object is `@Dependent` scoped in mpConfig-2.0 and later.

It's still not entirely great since you can inject that `@Dependent` scoped bean into an `@ApplicationScoped` bean and it'll then still be initialized once with the active TCCL at the time.

I think it would be possible to change it to use the classloader of the class it's injected into (as you can get the target `InjectionPoint` for a `@Dependent` scoped bean), but then I think you're in violation of the spec since it specifies the TCCL.
created_at: 2025-04-10T12:53:12Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,282 @@
+/*******************************************************************************
+ * Copyright (c) 2025 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package com.ibm.ws.microprofile.config.fat.tests.visibility.war;
+
+import static com.ibm.ws.microprofile.appConfig.test.utils.TestUtils.assertContains;
+import static com.ibm.ws.microprofile.appConfig.test.utils.TestUtils.assertNotContains;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EAR_LIB_CONFIG_PROPERTY;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EAR_LIB_VALUE;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EJB_JAR_CONFIG_PROPERTY;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.EJB_JAR_VALUE;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.WAR_CONFIG_PROPERTY;
+import static com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.VisibilityTestConstants.WAR_VALUE;
+
+import java.util.Arrays;
+import java.util.Optional;
+
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+import javax.servlet.annotation.WebServlet;
+
+import org.eclipse.microprofile.config.Config;
+import org.eclipse.microprofile.config.ConfigProvider;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+import org.junit.Test;
+
+import com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.EarLibBean;
+import com.ibm.ws.microprofile.config.fat.tests.visibility.earlib.EarLibDependentBean;
+import com.ibm.ws.microprofile.config.fat.tests.visibility.ejbjar.VisibilityTestEjb;
+
+import componenttest.app.FATServlet;
+
+/**
+ * Tests which config sources can be seen from different locations within an .ear
+ * <p>
+ * Each test uses one method of reading config properties from one location within the .ear
+ */
+@WebServlet("/testWar")
+public class VisibilityTestServlet extends FATServlet {
+
+    private static final long serialVersionUID = 1L;
+
+    @Inject
+    private VisibilityTestEjb testEjb;
+
+    @Inject
+    private EarLibBean earLibBean;
+
+    @Inject
+    private EarLibDependentBean earLibDependentBean;
+
+    @Inject
+    private Config injectedConfig;
+
+    @Inject
+    @ConfigProperty(name = WAR_CONFIG_PROPERTY)
+    private Optional<String> warProperty;
+
+    @Inject
+    @ConfigProperty(name = EJB_JAR_CONFIG_PROPERTY)
+    private Optional<String> ejbJarProperty;
+
+    @Inject
+    @ConfigProperty(name = EAR_LIB_CONFIG_PROPERTY)
+    private Optional<String> earLibProperty;
+
+    @PostConstruct
+    private void initializeInjectedConfig() {
+        // Initialize the injected Config object before running any tests
+        // This should ensure it's initialized in the context of the .war, even if one of the EJB tests is the first to run
+        // This is important because mpConfig-1.x uses an ApplicationScoped Config bean which will use whichever TCCL is active when it's initialized
+        // and we want that to be consistent regardless of the order tests are run
+
+        // Calling any method is sufficient to initialize the bean
+        injectedConfig.getConfigSources();
+    }
+
+    @Test
+    public void testGetConfigFromWar() {
+        // GetConfig from this .war
+        Config config = ConfigProvider.getConfig();
+
+        // Expect to see properties from all locations visible on classpath
+        assertContains(config, WAR_CONFIG_PROPERTY, WAR_VALUE);
+        assertContains(config, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(config, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+    }
+
+    @Test
+    public void testGetConfigFromEjbJar() {
+        // GetConfig from an ejb
+        Config config = testEjb.getConfig();
+
+        // Expect to see properties from all locations visible on classpath
+        assertContains(config, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(config, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+        assertNotContains(config, WAR_CONFIG_PROPERTY);
+    }
+
+    @Test
+    public void testGetConfigFromEarLib() {
+        // getConfig called from app scoped ear lib jar
+        Config config = earLibBean.getConfig();
+
+        // Expect to see everything visible to the .war, since the TCCL is the war classloader when getConfig was called
+        assertContains(config, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(config, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+        assertContains(config, WAR_CONFIG_PROPERTY, WAR_VALUE);
+
+        // Same bean obtained via EJB
+        config = testEjb.getEarLibBean().getConfig();
+
+        // Expect to see everything visible to the .war
+        // We get the bean via the EJB, but we call the bean ourselves, so it's the .war TCCL that's active
+        assertContains(config, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(config, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+        assertContains(config, WAR_CONFIG_PROPERTY, WAR_VALUE);
+
+        // Test with dependent-scoped ear lib jar
+        config = earLibDependentBean.getConfig();
+
+        // Expect same results as app-scoped bean
+        // The bean creation has no impact when calling getConfig
+        assertContains(config, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(config, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+        assertContains(config, WAR_CONFIG_PROPERTY, WAR_VALUE);
+
+        // Test with dependent-scoped ear lib jar obtained via EJB
+        config = testEjb.getEarLibDependentBean().getConfig();
+
+        // Expect to see everything visible to the .war
+        // We get the bean via the EJB, but we call the bean ourselves, so it's the .war TCCL that's active
+        assertContains(config, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(config, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+        assertContains(config, WAR_CONFIG_PROPERTY, WAR_VALUE);
+    }
+
+    @Test
+    public void testInjectedConfigFromWar() {
+        // Config injected into .war
+        Config config = injectedConfig;
+
+        // Expect to see properties from all locations visible on war classpath
+        assertContains(config, WAR_CONFIG_PROPERTY, WAR_VALUE);
+        assertContains(config, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(config, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+    }
+
+    @Test
+    public void testInjectedConfigFromEjbJar() {
+        // Config injected into EJB
+        Config config = testEjb.getInjectedConfig();
+
+        // Expect to see properties from all locations visible on EJB jar classpath
+        assertContains(config, EJB_JAR_CONFIG_PROPERTY, EJB_JAR_VALUE);
+        assertContains(config, EAR_LIB_CONFIG_PROPERTY, EAR_LIB_VALUE);
+
+        if (isMpConfig1x()) {
+            // In mpConfig 1.x, the injected Config bean is ApplicationScoped, and reports the same properties everywhere
+            // It gets initialized wherever it's first used (which is from the .war)
+            assertContains(config, WAR_CONFIG_PROPERTY, WAR_VALUE);
+        } else {
+            // In mpConfig 2.0 and later, the injected Config bean is Dependent-scoped and will take its values from the EJB module TCCL
path: dev/com.ibm.ws.microprofile.config.1.1_fat/fat/src/com/ibm/ws/microprofile/config/fat/tests/visibility/war/VisibilityTestServlet.java
user: login: Azquelt
body: Yeah, I agree the current behaviour isn't great :wink:. This test is just to assert what the behaviour is so that if we change it we do so deliberately.
created_at: 2025-04-10T12:55:03Z
author_association: MEMBER

PR comments:
user: login: Azquelt
created_at: 2025-04-07T16:04:11Z
body: !build ([view Open Liberty Personal Build](https://libh-proxy1.fyre.ibm.com/cognitive/pipelineAnalysis.html?pipelineId=0b67f4d6-dcf2-4021-abdb-7a2bbe27ebab) - :x: completed with errors/failures.)

_Note: Target locations of links might be accessible only to IBM employees._
author_association: MEMBER
user: login: Azquelt
created_at: 2025-04-08T09:35:14Z
body: !build ([view Open Liberty Personal Build](https://libh-proxy1.fyre.ibm.com/cognitive/pipelineAnalysis.html?pipelineId=c7a916aa-1c1d-4ab3-867b-2583f7df182a) - :white_check_mark: completed successfully!)

_Note: Target locations of links might be accessible only to IBM employees._
author_association: MEMBER
user: login: LibbyBot
created_at: 2025-04-08T09:43:52Z
body: <h3>Code analysis and actions</h3>
DO NOT DELETE THIS COMMENT.

- 11 FAT files were changed, added, or removed.
 - Check that the build did not break the affected FAT suite(s).

- **Please describe in a separate comment how you tested your changes.**
author_association: MEMBER