From a3e39916dd1a15e2f89b9a58304c033897082018 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Fri, 12 Jan 2024 12:30:36 +0100 Subject: [PATCH 1/7] Initial draft for improving `log4j-osgi-test` --- log4j-osgi-test/pom.xml | 17 +- .../osgi/tests/AbstractLoadBundleTest.java | 232 ++++++++---------- .../log4j/osgi/tests/AbstractOsgiTest.java | 55 ----- .../log4j/osgi/tests/CoreOsgiTest.java | 2 - .../log4j/osgi/tests/CustomConfiguration.java | 15 +- .../tests/CustomConfigurationFactory.java | 2 +- .../EquinoxLoadApiBundleTest.java | 11 +- .../{felix => }/FelixLoadApiBundleTest.java | 12 +- .../OsgiTestRule.java => OsgiRule.java} | 8 +- .../src/test/resources/log4j2.custom | 18 +- 10 files changed, 147 insertions(+), 225 deletions(-) delete mode 100644 log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractOsgiTest.java rename log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/{equinox => }/EquinoxLoadApiBundleTest.java (77%) rename log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/{felix => }/FelixLoadApiBundleTest.java (74%) rename log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/{junit/OsgiTestRule.java => OsgiRule.java} (90%) diff --git a/log4j-osgi-test/pom.xml b/log4j-osgi-test/pom.xml index 953e3ed7e41..de53e536097 100644 --- a/log4j-osgi-test/pom.xml +++ b/log4j-osgi-test/pom.xml @@ -28,12 +28,13 @@ Apache Log4j OSGi tests The Apache Log4j OSGi tests - OSGi Documentation - /osgi org.apache.logging.log4j.osgi true true true + true + + true 1.3.7 @@ -41,6 +42,7 @@ javax.inject javax.inject 1 + provided org.apache.logging.log4j @@ -218,6 +220,17 @@ + + + org.apache.rat + apache-rat-plugin + + + felix-cache/**/* + + + + diff --git a/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java b/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java index 5cf6433d38d..1beb8b18607 100644 --- a/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java +++ b/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java @@ -16,23 +16,47 @@ */ package org.apache.logging.log4j.osgi.tests; -import java.io.PrintStream; -import java.lang.reflect.Field; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import java.lang.reflect.Method; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.apache.logging.log4j.util.ServiceLoaderUtil; import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.jupiter.api.function.ThrowingConsumer; import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; +import org.osgi.framework.launch.FrameworkFactory; /** * Tests a basic Log4J 'setup' in an OSGi container. */ -public abstract class AbstractLoadBundleTest extends AbstractOsgiTest { +abstract class AbstractLoadBundleTest { + + private BundleContext bundleContext; + + @Rule + public final OsgiRule osgi; + + AbstractLoadBundleTest(final FrameworkFactory frameworkFactory) { + this.osgi = new OsgiRule(frameworkFactory); + } + + @Before + public void before() { + bundleContext = osgi.getFramework().getBundleContext(); + } private Bundle installBundle(final String symbolicName) throws BundleException { // The links are generated by 'exam-maven-plugin' final String url = String.format("link:classpath:%s.link", symbolicName); - return getBundleContext().installBundle(url); + return bundleContext.installBundle(url); } private Bundle getApiBundle() throws BundleException { @@ -51,67 +75,8 @@ private Bundle get12ApiBundle() throws BundleException { return installBundle("org.apache.logging.log4j.1.2.api"); } - private void log(final Bundle dummy) throws ReflectiveOperationException { - // use reflection to log in the context of the dummy bundle - - final Class logManagerClass = dummy.loadClass("org.apache.logging.log4j.LogManager"); - final Method getLoggerMethod = logManagerClass.getMethod("getLogger", Class.class); - - final Class loggerClass = dummy.loadClass("org.apache.logging.log4j.configuration.CustomConfiguration"); - - final Object logger = getLoggerMethod.invoke(null, loggerClass); - final Method errorMethod = logger.getClass().getMethod("error", Object.class); - - errorMethod.invoke(logger, "Test OK"); - } - - private PrintStream setupStream(final Bundle api, final PrintStream newStream) throws ReflectiveOperationException { - // use reflection to access the classes internals and in the context of the api bundle - - final Class statusLoggerClass = api.loadClass("org.apache.logging.log4j.status.StatusLogger"); - - final Field statusLoggerField = statusLoggerClass.getDeclaredField("STATUS_LOGGER"); - statusLoggerField.setAccessible(true); - final Object statusLoggerFieldValue = statusLoggerField.get(null); - - final Field loggerField = statusLoggerClass.getDeclaredField("logger"); - loggerField.setAccessible(true); - final Object loggerFieldValue = loggerField.get(statusLoggerFieldValue); - - final Class simpleLoggerClass = api.loadClass("org.apache.logging.log4j.simple.SimpleLogger"); - - final Field streamField = simpleLoggerClass.getDeclaredField("stream"); - streamField.setAccessible(true); - - final PrintStream oldStream = (PrintStream) streamField.get(loggerFieldValue); - - streamField.set(loggerFieldValue, newStream); - - return oldStream; - } - - private void start(final Bundle api, final Bundle plugins, final Bundle core, final Bundle dummy) - throws BundleException { - api.start(); - plugins.start(); - core.start(); - dummy.start(); - } - - private void stop(final Bundle api, final Bundle plugins, final Bundle core, final Bundle dummy) - throws BundleException { - dummy.stop(); - core.stop(); - plugins.stop(); - api.stop(); - } - - private void uninstall(final Bundle api, final Bundle plugins, final Bundle core, final Bundle dummy) - throws BundleException { - dummy.uninstall(); - core.uninstall(); - plugins.uninstall(); - api.uninstall(); + private Bundle getApiTestsBundle() throws BundleException { + return installBundle("org.apache.logging.log4j.api.test"); } /** @@ -128,45 +93,15 @@ public void testApiCoreStartStopStartStop() throws BundleException { Assert.assertEquals("plugins is not in INSTALLED state", Bundle.INSTALLED, plugins.getState()); Assert.assertEquals("core is not in INSTALLED state", Bundle.INSTALLED, core.getState()); - api.start(); - plugins.start(); - core.start(); - - Assert.assertEquals("api is not in ACTIVE state", Bundle.ACTIVE, api.getState()); - Assert.assertEquals("plugins is not in ACTIVE state", Bundle.ACTIVE, plugins.getState()); - Assert.assertEquals("core is not in ACTIVE state", Bundle.ACTIVE, core.getState()); - - core.stop(); - plugins.stop(); - api.stop(); - - Assert.assertEquals("api is not in RESOLVED state", Bundle.RESOLVED, api.getState()); - Assert.assertEquals("plugins is not in RESOLVED state", Bundle.RESOLVED, plugins.getState()); - Assert.assertEquals("core is not in RESOLVED state", Bundle.RESOLVED, core.getState()); - - api.start(); - plugins.start(); - core.start(); - - Assert.assertEquals("api is not in ACTIVE state", Bundle.ACTIVE, api.getState()); - Assert.assertEquals("plugins is not in ACTIVE state", Bundle.ACTIVE, plugins.getState()); - Assert.assertEquals("core is not in ACTIVE state", Bundle.ACTIVE, core.getState()); + // 1st start-stop + doOnBundlesAndVerifyState(Bundle::start, Bundle.ACTIVE, api, plugins, core); + doOnBundlesAndVerifyState(Bundle::stop, Bundle.RESOLVED, core, plugins, api); - core.stop(); - plugins.stop(); - api.stop(); + // 2nd start-stop + doOnBundlesAndVerifyState(Bundle::start, Bundle.ACTIVE, api, plugins, core); + doOnBundlesAndVerifyState(Bundle::stop, Bundle.RESOLVED, core, plugins, api); - Assert.assertEquals("api is not in RESOLVED state", Bundle.RESOLVED, api.getState()); - Assert.assertEquals("plugins is not in RESOLVED state", Bundle.RESOLVED, plugins.getState()); - Assert.assertEquals("core is not in RESOLVED state", Bundle.RESOLVED, core.getState()); - - core.uninstall(); - plugins.uninstall(); - api.uninstall(); - - Assert.assertEquals("api is not in UNINSTALLED state", Bundle.UNINSTALLED, api.getState()); - Assert.assertEquals("plugins is not in UNINSTALLED state", Bundle.UNINSTALLED, plugins.getState()); - Assert.assertEquals("core is not in UNINSTALLED state", Bundle.UNINSTALLED, core.getState()); + doOnBundlesAndVerifyState(Bundle::uninstall, Bundle.UNINSTALLED, core, plugins, api); } /** @@ -179,40 +114,28 @@ public void testClassNotFoundErrorLogger() throws BundleException { final Bundle plugins = getPluginsBundle(); final Bundle core = getCoreBundle(); - api.start(); - plugins.start(); + doOnBundlesAndVerifyState(Bundle::start, Bundle.ACTIVE, api, plugins); // fails if LOG4J2-1637 is not fixed try { core.start(); - } catch (final BundleException ex) { - boolean shouldRethrow = true; - final Throwable t = ex.getCause(); - if (t != null) { - final Throwable t2 = t.getCause(); - if (t2 != null) { - final String cause = t2.toString(); - final boolean result = - cause.equals("java.lang.ClassNotFoundException: org.apache.logging.log4j.Logger") // Equinox - || cause.equals( - "java.lang.ClassNotFoundException: org.apache.logging.log4j.Logger not found by org.apache.logging.log4j.core [2]"); // Felix - Assert.assertFalse( - "org.apache.logging.log4j package is not properly imported in org.apache.logging.log4j.core bundle, check that the package is exported from api and is not split between api and core", - result); - shouldRethrow = !result; + } catch (final BundleException error0) { + boolean log4jClassNotFound = false; + final Throwable error1 = error0.getCause(); + if (error1 != null) { + final Throwable error2 = error1.getCause(); + if (error2 != null) { + log4jClassNotFound = error2.toString() + .startsWith("java.lang.ClassNotFoundException: org.apache.logging.log4j.Logger"); } } - if (shouldRethrow) { - throw ex; // rethrow if the cause of the exception is something else + if (!log4jClassNotFound) { + throw error0; } } + assertEquals(String.format("`%s` bundle state mismatch", core), Bundle.ACTIVE, core.getState()); - core.stop(); - plugins.stop(); - api.stop(); - - core.uninstall(); - plugins.uninstall(); - api.uninstall(); + doOnBundlesAndVerifyState(Bundle::stop, Bundle.RESOLVED, core, plugins, api); + doOnBundlesAndVerifyState(Bundle::uninstall, Bundle.UNINSTALLED, core, plugins, api); } /** @@ -227,9 +150,7 @@ public void testLog4J12Fragement() throws BundleException, ReflectiveOperationEx final Bundle core = getCoreBundle(); final Bundle compat = get12ApiBundle(); - api.start(); - plugins.start(); - core.start(); + doOnBundlesAndVerifyState(Bundle::start, Bundle.ACTIVE, api, plugins, core); final Class coreClassFromCore = core.loadClass("org.apache.logging.log4j.core.Core"); final Class levelClassFrom12API = core.loadClass("org.apache.log4j.Level"); @@ -244,9 +165,52 @@ public void testLog4J12Fragement() throws BundleException, ReflectiveOperationEx levelClassFrom12API.getClassLoader(), levelClassFromAPI.getClassLoader()); - core.stop(); - api.stop(); + doOnBundlesAndVerifyState(Bundle::stop, Bundle.RESOLVED, core, plugins, api); + doOnBundlesAndVerifyState(Bundle::uninstall, Bundle.UNINSTALLED, compat, core, plugins, api); + } - uninstall(api, plugins, core, compat); + /** + * Tests whether the {@link ServiceLoaderUtil} finds services in other bundles. + */ + @Test + public void testServiceLoader() throws BundleException, ReflectiveOperationException { + final Bundle api = getApiBundle(); + final Bundle core = getCoreBundle(); + final Bundle apiTests = getApiTestsBundle(); + + final Class osgiServiceLocator = api.loadClass("org.apache.logging.log4j.util.OsgiServiceLocator"); + assertTrue("OsgiServiceLocator is active", (boolean) + osgiServiceLocator.getMethod("isAvailable").invoke(null)); + + doOnBundlesAndVerifyState(Bundle::start, Bundle.ACTIVE, api, core, apiTests); + + final Class osgiServiceLocatorTest = + apiTests.loadClass("org.apache.logging.log4j.test.util.OsgiServiceLocatorTest"); + + final Method loadProviders = osgiServiceLocatorTest.getDeclaredMethod("loadProviders"); + final Object obj = loadProviders.invoke(null); + assertTrue(obj instanceof Stream); + @SuppressWarnings("unchecked") + final List services = ((Stream) obj).collect(Collectors.toList()); + assertEquals(1, services.size()); + assertEquals( + "org.apache.logging.log4j.core.impl.Log4jProvider", + services.get(0).getClass().getName()); + + doOnBundlesAndVerifyState(Bundle::stop, Bundle.RESOLVED, apiTests, core, api); + doOnBundlesAndVerifyState(Bundle::uninstall, Bundle.UNINSTALLED, apiTests, core, api); + } + + private static void doOnBundlesAndVerifyState( + final ThrowingConsumer operation, final int expectedState, final Bundle... bundles) { + for (final Bundle bundle : bundles) { + try { + operation.accept(bundle); + } catch (final Throwable error) { + final String message = String.format("operation failure for bundle `%s`", bundle); + throw new RuntimeException(message, error); + } + assertEquals(String.format("`%s` bundle state mismatch", bundle), expectedState, bundle.getState()); + } } } diff --git a/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractOsgiTest.java b/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractOsgiTest.java deleted file mode 100644 index 6bbf2d624bb..00000000000 --- a/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractOsgiTest.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to you 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 org.apache.logging.log4j.osgi.tests; - -import org.apache.logging.log4j.osgi.tests.junit.OsgiTestRule; -import org.junit.Before; -import org.junit.Rule; -import org.osgi.framework.BundleContext; -import org.osgi.framework.launch.FrameworkFactory; - -/** - * Subclasses can tests a basic setup in an OSGi container. - */ -public abstract class AbstractOsgiTest { - - private BundleContext bundleContext; - - @Rule - public OsgiTestRule osgi = new OsgiTestRule(getFactory()); - - /** - * Constructs a test for a given bundle. - */ - public AbstractOsgiTest() { - super(); - } - - /** - * Called before each @Test. - */ - @Before - public void before() { - bundleContext = osgi.getFramework().getBundleContext(); - } - - public BundleContext getBundleContext() { - return bundleContext; - } - - protected abstract FrameworkFactory getFactory(); -} diff --git a/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/CoreOsgiTest.java b/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/CoreOsgiTest.java index 08049c0dc90..222f73ddf8b 100644 --- a/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/CoreOsgiTest.java +++ b/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/CoreOsgiTest.java @@ -29,7 +29,6 @@ import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.impl.Log4jContextFactory; import org.apache.logging.log4j.spi.LoggerContextFactory; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.ops4j.pax.exam.Option; @@ -39,7 +38,6 @@ @RunWith(PaxExam.class) @ExamReactorStrategy(PerClass.class) -@Ignore public class CoreOsgiTest { @org.ops4j.pax.exam.Configuration diff --git a/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/CustomConfiguration.java b/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/CustomConfiguration.java index 5316e4d9742..ae4bfef4505 100644 --- a/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/CustomConfiguration.java +++ b/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/CustomConfiguration.java @@ -34,16 +34,11 @@ * This Configuration is the same as the DefaultConfiguration but shows how a * custom configuration can be built programmatically */ -public class CustomConfiguration extends AbstractConfiguration { - - /** - * The name of the default configuration. - */ - public static final String CONFIG_NAME = "Custom"; +final class CustomConfiguration extends AbstractConfiguration { private final ListAppender appender = new ListAppender(); - public CustomConfiguration(final LoggerContext loggerContext) { + CustomConfiguration(final LoggerContext loggerContext) { this(loggerContext, ConfigurationSource.NULL_SOURCE); } @@ -52,7 +47,7 @@ public CustomConfiguration(final LoggerContext loggerContext) { */ public CustomConfiguration(final LoggerContext loggerContext, final ConfigurationSource source) { super(loggerContext, source); - setName(CONFIG_NAME); + setName("Custom"); appender.start(); addAppender(appender); final LoggerConfig root = getRootLogger(); @@ -71,9 +66,9 @@ public void clearEvents() { appender.getEvents().clear(); } - private static class ListAppender extends AbstractLifeCycle implements Appender { + private static final class ListAppender extends AbstractLifeCycle implements Appender { - private final List events = Collections.synchronizedList(new ArrayList<>()); + private final List events = Collections.synchronizedList(new ArrayList<>()); @Override public void append(final LogEvent event) { diff --git a/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/CustomConfigurationFactory.java b/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/CustomConfigurationFactory.java index f14e9fb77c2..e58d2c81ed5 100644 --- a/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/CustomConfigurationFactory.java +++ b/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/CustomConfigurationFactory.java @@ -31,7 +31,7 @@ @Namespace(ConfigurationFactory.NAMESPACE) @Plugin("CustomConfigurationFactory") @Order(50) -public class CustomConfigurationFactory extends ConfigurationFactory { +public final class CustomConfigurationFactory extends ConfigurationFactory { /** * Valid file extensions for XML files. diff --git a/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/equinox/EquinoxLoadApiBundleTest.java b/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/EquinoxLoadApiBundleTest.java similarity index 77% rename from log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/equinox/EquinoxLoadApiBundleTest.java rename to log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/EquinoxLoadApiBundleTest.java index 6cc5389b018..c4060353a84 100644 --- a/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/equinox/EquinoxLoadApiBundleTest.java +++ b/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/EquinoxLoadApiBundleTest.java @@ -14,21 +14,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.logging.log4j.osgi.tests.equinox; +package org.apache.logging.log4j.osgi.tests; -import org.apache.logging.log4j.osgi.tests.AbstractLoadBundleTest; import org.eclipse.osgi.launch.EquinoxFactory; -import org.junit.Ignore; -import org.osgi.framework.launch.FrameworkFactory; /** * Tests loading the Core bundle into an Eclipse Equinox OSGi container. */ -@Ignore public class EquinoxLoadApiBundleTest extends AbstractLoadBundleTest { - @Override - protected FrameworkFactory getFactory() { - return new EquinoxFactory(); + public EquinoxLoadApiBundleTest() { + super(new EquinoxFactory()); } } diff --git a/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/felix/FelixLoadApiBundleTest.java b/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/FelixLoadApiBundleTest.java similarity index 74% rename from log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/felix/FelixLoadApiBundleTest.java rename to log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/FelixLoadApiBundleTest.java index f301caac96b..e82cebb094b 100644 --- a/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/felix/FelixLoadApiBundleTest.java +++ b/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/FelixLoadApiBundleTest.java @@ -14,20 +14,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.logging.log4j.osgi.tests.felix; +package org.apache.logging.log4j.osgi.tests; -import org.apache.logging.log4j.osgi.tests.AbstractLoadBundleTest; -import org.junit.Ignore; -import org.osgi.framework.launch.FrameworkFactory; +import org.apache.felix.framework.FrameworkFactory; /** * Tests loading the Core bundle into an Apache Felix OSGi container. */ -@Ignore public class FelixLoadApiBundleTest extends AbstractLoadBundleTest { - @Override - protected FrameworkFactory getFactory() { - return new org.apache.felix.framework.FrameworkFactory(); + public FelixLoadApiBundleTest() { + super(new FrameworkFactory()); } } diff --git a/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/junit/OsgiTestRule.java b/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/OsgiRule.java similarity index 90% rename from log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/junit/OsgiTestRule.java rename to log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/OsgiRule.java index 81a4ac4c82e..491d9f50b7a 100644 --- a/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/junit/OsgiTestRule.java +++ b/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/OsgiRule.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.logging.log4j.osgi.tests.junit; +package org.apache.logging.log4j.osgi.tests; import java.io.InputStream; import java.util.HashMap; @@ -29,12 +29,12 @@ /** * JUnit rule to initialize and shutdown an OSGi framework. */ -public class OsgiTestRule extends ExternalResource { +final class OsgiRule extends ExternalResource { private final FrameworkFactory factory; private Framework framework; - public OsgiTestRule(final FrameworkFactory factory) { + OsgiRule(final FrameworkFactory factory) { this.factory = factory; } @@ -53,7 +53,7 @@ protected void after() { @Override protected void before() throws Throwable { - try (final InputStream is = OsgiTestRule.class.getResourceAsStream("/osgi.properties")) { + try (final InputStream is = OsgiRule.class.getResourceAsStream("/osgi.properties")) { final Properties props = new Properties(); props.load(is); final Map configMap = props.entrySet().stream() diff --git a/log4j-osgi-test/src/test/resources/log4j2.custom b/log4j-osgi-test/src/test/resources/log4j2.custom index 36435a1e286..5238d0fde84 100644 --- a/log4j-osgi-test/src/test/resources/log4j2.custom +++ b/log4j-osgi-test/src/test/resources/log4j2.custom @@ -1 +1,17 @@ -# This file enables the CustomConfigurationFactory \ No newline at end of file +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to you 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. +# +This file enables the CustomConfigurationFactory \ No newline at end of file From 5444da1ddbb52920b5f56c7970c4743eab401723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Fri, 12 Jan 2024 14:40:53 +0100 Subject: [PATCH 2/7] Fix Error Prone related module descriptor issue in `log4j-plugins` --- log4j-plugins/pom.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/log4j-plugins/pom.xml b/log4j-plugins/pom.xml index ac1f8d3012b..b9a225e796b 100644 --- a/log4j-plugins/pom.xml +++ b/log4j-plugins/pom.xml @@ -29,7 +29,10 @@ Apache Log4j Plugins Log4j Plugin Support - ${basedir}/.. + + + com.google.errorprone.annotations.concurrent;resolution:=optional + From 83768e8f8b54e4afe42435cd7a6dc988b7a18be2 Mon Sep 17 00:00:00 2001 From: "Piotr P. Karwasz" Date: Fri, 12 Jan 2024 22:45:02 +0100 Subject: [PATCH 3/7] Fix custom OSGi plugins registration --- .../logging/log4j/osgi/tests/CoreOsgiTest.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/CoreOsgiTest.java b/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/CoreOsgiTest.java index 222f73ddf8b..2d5ee6c23b0 100644 --- a/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/CoreOsgiTest.java +++ b/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/CoreOsgiTest.java @@ -32,9 +32,12 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.ops4j.pax.exam.Option; +import org.ops4j.pax.exam.ProbeBuilder; +import org.ops4j.pax.exam.TestProbeBuilder; import org.ops4j.pax.exam.junit.PaxExam; import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy; import org.ops4j.pax.exam.spi.reactors.PerClass; +import org.osgi.framework.Constants; @RunWith(PaxExam.class) @ExamReactorStrategy(PerClass.class) @@ -60,6 +63,19 @@ public Option[] config() { junitBundles()); } + @ProbeBuilder + public TestProbeBuilder probeConfiguration(final TestProbeBuilder builder) { + // Register `Log4jPlugins` manually with the Service Loader Mediator + builder.setHeader( + Constants.PROVIDE_CAPABILITY, + "osgi.serviceloader;osgi.serviceloader=\"org.apache.logging.log4j.plugins.model.PluginService\";" + + "register:=\"org.apache.logging.log4j.osgi.tests.plugins.Log4jPlugins\""); + builder.setHeader( + Constants.REQUIRE_CAPABILITY, + "osgi.extender;filter:=\"(&(osgi.extender=osgi.serviceloader.registrar)(version>=1.0)(!(version>=2.0)))\""); + return builder; + } + @Test public void testSimpleLogInAnOsgiContext() { final CustomConfiguration custom = getConfiguration(); From 42aee1631707bd1feede03df2a50f5da1a2042f3 Mon Sep 17 00:00:00 2001 From: "Piotr P. Karwasz" Date: Fri, 12 Jan 2024 22:52:25 +0100 Subject: [PATCH 4/7] Add SPI Fly to `AbstractLoadBundleTest` --- .../osgi/tests/AbstractLoadBundleTest.java | 55 ++++++------------- 1 file changed, 17 insertions(+), 38 deletions(-) diff --git a/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java b/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java index 1beb8b18607..4e7c3daf3cf 100644 --- a/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java +++ b/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java @@ -17,13 +17,7 @@ package org.apache.logging.log4j.osgi.tests; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import java.lang.reflect.Method; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.apache.logging.log4j.util.ServiceLoaderUtil; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; @@ -59,6 +53,17 @@ private Bundle installBundle(final String symbolicName) throws BundleException { return bundleContext.installBundle(url); } + private Bundle startApacheSpiFly() throws BundleException { + installBundle("org.objectweb.asm"); + installBundle("org.objectweb.asm.commons"); + installBundle("org.objectweb.asm.tree"); + installBundle("org.objectweb.asm.tree.analysis"); + installBundle("org.objectweb.asm.util"); + final Bundle spiFly = installBundle("org.apache.aries.spifly.dynamic.bundle"); + spiFly.start(); + return spiFly; + } + private Bundle getApiBundle() throws BundleException { return installBundle("org.apache.logging.log4j.api"); } @@ -85,6 +90,7 @@ private Bundle getApiTestsBundle() throws BundleException { @Test public void testApiCoreStartStopStartStop() throws BundleException { + final Bundle spiFly = startApacheSpiFly(); final Bundle api = getApiBundle(); final Bundle plugins = getPluginsBundle(); final Bundle core = getCoreBundle(); @@ -102,6 +108,7 @@ public void testApiCoreStartStopStartStop() throws BundleException { doOnBundlesAndVerifyState(Bundle::stop, Bundle.RESOLVED, core, plugins, api); doOnBundlesAndVerifyState(Bundle::uninstall, Bundle.UNINSTALLED, core, plugins, api); + spiFly.uninstall(); } /** @@ -110,6 +117,7 @@ public void testApiCoreStartStopStartStop() throws BundleException { @Test public void testClassNotFoundErrorLogger() throws BundleException { + final Bundle spiFly = startApacheSpiFly(); final Bundle api = getApiBundle(); final Bundle plugins = getPluginsBundle(); final Bundle core = getCoreBundle(); @@ -136,6 +144,7 @@ public void testClassNotFoundErrorLogger() throws BundleException { doOnBundlesAndVerifyState(Bundle::stop, Bundle.RESOLVED, core, plugins, api); doOnBundlesAndVerifyState(Bundle::uninstall, Bundle.UNINSTALLED, core, plugins, api); + spiFly.uninstall(); } /** @@ -145,6 +154,7 @@ public void testClassNotFoundErrorLogger() throws BundleException { @Test public void testLog4J12Fragement() throws BundleException, ReflectiveOperationException { + final Bundle spiFly = startApacheSpiFly(); final Bundle api = getApiBundle(); final Bundle plugins = getPluginsBundle(); final Bundle core = getCoreBundle(); @@ -167,38 +177,7 @@ public void testLog4J12Fragement() throws BundleException, ReflectiveOperationEx doOnBundlesAndVerifyState(Bundle::stop, Bundle.RESOLVED, core, plugins, api); doOnBundlesAndVerifyState(Bundle::uninstall, Bundle.UNINSTALLED, compat, core, plugins, api); - } - - /** - * Tests whether the {@link ServiceLoaderUtil} finds services in other bundles. - */ - @Test - public void testServiceLoader() throws BundleException, ReflectiveOperationException { - final Bundle api = getApiBundle(); - final Bundle core = getCoreBundle(); - final Bundle apiTests = getApiTestsBundle(); - - final Class osgiServiceLocator = api.loadClass("org.apache.logging.log4j.util.OsgiServiceLocator"); - assertTrue("OsgiServiceLocator is active", (boolean) - osgiServiceLocator.getMethod("isAvailable").invoke(null)); - - doOnBundlesAndVerifyState(Bundle::start, Bundle.ACTIVE, api, core, apiTests); - - final Class osgiServiceLocatorTest = - apiTests.loadClass("org.apache.logging.log4j.test.util.OsgiServiceLocatorTest"); - - final Method loadProviders = osgiServiceLocatorTest.getDeclaredMethod("loadProviders"); - final Object obj = loadProviders.invoke(null); - assertTrue(obj instanceof Stream); - @SuppressWarnings("unchecked") - final List services = ((Stream) obj).collect(Collectors.toList()); - assertEquals(1, services.size()); - assertEquals( - "org.apache.logging.log4j.core.impl.Log4jProvider", - services.get(0).getClass().getName()); - - doOnBundlesAndVerifyState(Bundle::stop, Bundle.RESOLVED, apiTests, core, api); - doOnBundlesAndVerifyState(Bundle::uninstall, Bundle.UNINSTALLED, apiTests, core, api); + spiFly.uninstall(); } private static void doOnBundlesAndVerifyState( From ae7f38a3105506a4f65df9ca19d4a442da2e88f6 Mon Sep 17 00:00:00 2001 From: "Piotr P. Karwasz" Date: Mon, 27 Nov 2023 17:13:28 +0100 Subject: [PATCH 5/7] Fix Apache Rat errors --- log4j-osgi-test/pom.xml | 2 ++ pom.xml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/log4j-osgi-test/pom.xml b/log4j-osgi-test/pom.xml index de53e536097..76fa44a8ad6 100644 --- a/log4j-osgi-test/pom.xml +++ b/log4j-osgi-test/pom.xml @@ -213,6 +213,8 @@ false org.ops4j.pax.url + + ${project.build.directory} diff --git a/pom.xml b/pom.xml index 8d6bc34c2f6..309c1d5e0cb 100644 --- a/pom.xml +++ b/pom.xml @@ -621,7 +621,6 @@ **/.toDelete velocity.log - felix-cache/** **/README.md SECURITY.md **/*.yml @@ -903,6 +902,7 @@ + From d8bab7cd5352f7fff7260425601fed6d5573b425 Mon Sep 17 00:00:00 2001 From: "Piotr P. Karwasz" Date: Sat, 13 Jan 2024 09:24:49 +0100 Subject: [PATCH 6/7] Move OSGi caches to `target` directory --- log4j-osgi-test/pom.xml | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/log4j-osgi-test/pom.xml b/log4j-osgi-test/pom.xml index 76fa44a8ad6..ad9fc96e194 100644 --- a/log4j-osgi-test/pom.xml +++ b/log4j-osgi-test/pom.xml @@ -213,8 +213,6 @@ false org.ops4j.pax.url - - ${project.build.directory} @@ -222,17 +220,6 @@ - - - org.apache.rat - apache-rat-plugin - - - felix-cache/**/* - - - - From efc7b15f114fc135ac5d37be4f237b44197fe95a Mon Sep 17 00:00:00 2001 From: "Piotr P. Karwasz" Date: Sat, 13 Jan 2024 09:55:05 +0100 Subject: [PATCH 7/7] Fix Windows failure --- .../osgi/tests/AbstractLoadBundleTest.java | 38 +++++++++++-------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java b/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java index 4e7c3daf3cf..7b4b5f449c4 100644 --- a/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java +++ b/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java @@ -18,6 +18,7 @@ import static org.junit.Assert.assertEquals; +import java.util.List; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; @@ -53,15 +54,22 @@ private Bundle installBundle(final String symbolicName) throws BundleException { return bundleContext.installBundle(url); } - private Bundle startApacheSpiFly() throws BundleException { - installBundle("org.objectweb.asm"); - installBundle("org.objectweb.asm.commons"); - installBundle("org.objectweb.asm.tree"); - installBundle("org.objectweb.asm.tree.analysis"); - installBundle("org.objectweb.asm.util"); - final Bundle spiFly = installBundle("org.apache.aries.spifly.dynamic.bundle"); - spiFly.start(); - return spiFly; + private List startApacheSpiFly() throws BundleException { + final List bundles = List.of( + installBundle("org.apache.aries.spifly.dynamic.bundle"), + installBundle("org.objectweb.asm"), + installBundle("org.objectweb.asm.commons"), + installBundle("org.objectweb.asm.tree"), + installBundle("org.objectweb.asm.tree.analysis"), + installBundle("org.objectweb.asm.util")); + bundles.get(0).start(); + return bundles; + } + + private void uninstall(final List bundles) throws BundleException { + for (Bundle bundle : bundles) { + bundle.uninstall(); + } } private Bundle getApiBundle() throws BundleException { @@ -90,7 +98,7 @@ private Bundle getApiTestsBundle() throws BundleException { @Test public void testApiCoreStartStopStartStop() throws BundleException { - final Bundle spiFly = startApacheSpiFly(); + final List spiFly = startApacheSpiFly(); final Bundle api = getApiBundle(); final Bundle plugins = getPluginsBundle(); final Bundle core = getCoreBundle(); @@ -108,7 +116,7 @@ public void testApiCoreStartStopStartStop() throws BundleException { doOnBundlesAndVerifyState(Bundle::stop, Bundle.RESOLVED, core, plugins, api); doOnBundlesAndVerifyState(Bundle::uninstall, Bundle.UNINSTALLED, core, plugins, api); - spiFly.uninstall(); + uninstall(spiFly); } /** @@ -117,7 +125,7 @@ public void testApiCoreStartStopStartStop() throws BundleException { @Test public void testClassNotFoundErrorLogger() throws BundleException { - final Bundle spiFly = startApacheSpiFly(); + final List spiFly = startApacheSpiFly(); final Bundle api = getApiBundle(); final Bundle plugins = getPluginsBundle(); final Bundle core = getCoreBundle(); @@ -144,7 +152,7 @@ public void testClassNotFoundErrorLogger() throws BundleException { doOnBundlesAndVerifyState(Bundle::stop, Bundle.RESOLVED, core, plugins, api); doOnBundlesAndVerifyState(Bundle::uninstall, Bundle.UNINSTALLED, core, plugins, api); - spiFly.uninstall(); + uninstall(spiFly); } /** @@ -154,7 +162,7 @@ public void testClassNotFoundErrorLogger() throws BundleException { @Test public void testLog4J12Fragement() throws BundleException, ReflectiveOperationException { - final Bundle spiFly = startApacheSpiFly(); + final List spiFly = startApacheSpiFly(); final Bundle api = getApiBundle(); final Bundle plugins = getPluginsBundle(); final Bundle core = getCoreBundle(); @@ -177,7 +185,7 @@ public void testLog4J12Fragement() throws BundleException, ReflectiveOperationEx doOnBundlesAndVerifyState(Bundle::stop, Bundle.RESOLVED, core, plugins, api); doOnBundlesAndVerifyState(Bundle::uninstall, Bundle.UNINSTALLED, compat, core, plugins, api); - spiFly.uninstall(); + uninstall(spiFly); } private static void doOnBundlesAndVerifyState(