jcoglan opened a new pull request, #3256: URL: https://github.com/apache/logging-log4j2/pull/3256
Hi :wave: this is James from Neighbourhoodie, working on the STF agreed milestone to migrate the test suite to JUnit 5. This PR demonstrates an attempt to get a set of tests that use `@Parameterized` from JUnit 4 and try to get them running on JUnit 5. We have run into an odd problem where logger config files seem to be ignored and we're not sure how to resolve it. The class `DefaultRouteScriptAppenderTest` is parameterised like so: ```java @RunWith(Parameterized.class) public class DefaultRouteScriptAppenderTest { @Parameterized.Parameters(name = "{0} {1}") public static Object[][] getParameters() { return new Object[][] { {"log4j-routing-default-route-script-groovy.xml", false}, {"log4j-routing-default-route-script-javascript.xml", false}, {"log4j-routing-script-staticvars-javascript.xml", true}, {"log4j-routing-script-staticvars-groovy.xml", true}, }; } // ... } ``` We need to replicate the effect of this parameterisation under JUnit 5. Our understanding is that, whereas in JUnit 4 it is the _constructor_ that is parameterised, in JUnit 5 the `@ParameterizedTest` annotation applies to individual test methods. The class also uses `LoggerContextRule`, and makes use of the API of that class to inspect the loggers/appenders that are configured. Our understanding is that this has been replaced with the class-level `@LoggerContextSource` annotation, which causes a `LoggerContext` to be passed into the constructor. This PR shows an idea we had for refactoring this test class to JUnit 5. Rather than label each of its individual tests as parameterised, and then have to invoke code to set up a `LoggerContext` and the necessary before/after hooks in each one, we observe that parameterisation can be achieved by subclassing. If the `DefaultRouteScriptAppenderTest` constructor accepts the parameters that define each "version" of the tests, then we can write subclasses of `DefaultRouteScriptAppenderTest` that each invoke their parent's constructor with different inputs. Since the parameterisation is expressed in the form of classes, we can then also use `@LoggerContextSource` on each of those classes to turn the config filename into a `LoggerContext` implicitly and not have to write/call any additional setup code ourselves. In the first commit we remove the `@Parameterized.Parameters` block and add several subclasses, each of which sets up the parent class with one of the parameter sets, e.g. ```java public class DefaultRouteScriptGroovyAppenderTest extends DefaultRouteScriptAppenderTest { public DefaultRouteScriptGroovyAppenderTest() { super("log4j-routing-default-route-script-groovy.xml", false); } } ``` This works fine and the tests continue to pass. In the next commit, we attempt to migrate `DefaultRouteScriptAppenderTest` to JUnit 5, and as part of that we remove `LoggerContextRule` from that class and add `LoggerContextSource` to the subclasses: ```java @LoggerContextSource("log4j-routing-default-route-script-groovy.xml") public class DefaultRouteScriptGroovyAppenderTest extends DefaultRouteScriptAppenderTest { public DefaultRouteScriptGroovyAppenderTest(LoggerContext context) { super(context, false); } } ``` We have tried to migrate the use of `LoggerContextRule` methods like `getListAppender()` to their equivalents on `LoggerContext`. However, these tests no longer pass; e.g. this is the result of running `mvn test -Dtest=ScriptStaticVarsJavaScriptAppenderTest`: ``` ``` [ERROR] Tests run: 8, Failures: 1, Errors: 6, Skipped: 0, Time elapsed: 0.377 s <<< FAILURE! -- in org.apache.logging.log4j.core.appender.routing.ScriptStaticVarsJavaScriptAppenderTest [ERROR] org.apache.logging.log4j.core.appender.routing.ScriptStaticVarsJavaScriptAppenderTest.testListAppenderPresence -- Time elapsed: 0.012 s <<< ERROR! java.lang.NullPointerException: Cannot invoke "org.apache.logging.log4j.core.appender.routing.RoutingAppender.getAppenders()" because the return value of "org.apache.logging.log4j.core.appender.routing.DefaultRouteScriptAppenderTest.getRoutingAppender()" is null at org.apache.logging.log4j.core.appender.routing.DefaultRouteScriptAppenderTest.testListAppenderPresence(DefaultRouteScriptAppenderTest.java:103) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) [ERROR] org.apache.logging.log4j.core.appender.routing.ScriptStaticVarsJavaScriptAppenderTest.testNoPurgePolicy -- Time elapsed: 0.002 s <<< ERROR! java.lang.NullPointerException: Cannot invoke "org.apache.logging.log4j.core.appender.routing.RoutingAppender.getPurgePolicy()" because the return value of "org.apache.logging.log4j.core.appender.routing.DefaultRouteScriptAppenderTest.getRoutingAppender()" is null at org.apache.logging.log4j.core.appender.routing.DefaultRouteScriptAppenderTest.testNoPurgePolicy(DefaultRouteScriptAppenderTest.java:109) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) [ERROR] org.apache.logging.log4j.core.appender.routing.ScriptStaticVarsJavaScriptAppenderTest.testRoutingPresence1 -- Time elapsed: 0.007 s <<< ERROR! java.lang.NullPointerException: Cannot invoke "org.apache.logging.log4j.core.appender.routing.RoutingAppender.isStarted()" because "routingAppender" is null at org.apache.logging.log4j.core.appender.routing.DefaultRouteScriptAppenderTest.getListAppender(DefaultRouteScriptAppenderTest.java:69) at org.apache.logging.log4j.core.appender.routing.DefaultRouteScriptAppenderTest.logAndCheck(DefaultRouteScriptAppenderTest.java:85) at org.apache.logging.log4j.core.appender.routing.DefaultRouteScriptAppenderTest.testRoutingPresence1(DefaultRouteScriptAppenderTest.java:133) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) [ERROR] org.apache.logging.log4j.core.appender.routing.ScriptStaticVarsJavaScriptAppenderTest.testRoutingPresence2 -- Time elapsed: 0.001 s <<< ERROR! java.lang.NullPointerException: Cannot invoke "org.apache.logging.log4j.core.appender.routing.RoutingAppender.isStarted()" because "routingAppender" is null at org.apache.logging.log4j.core.appender.routing.DefaultRouteScriptAppenderTest.getListAppender(DefaultRouteScriptAppenderTest.java:69) at org.apache.logging.log4j.core.appender.routing.DefaultRouteScriptAppenderTest.logAndCheck(DefaultRouteScriptAppenderTest.java:85) at org.apache.logging.log4j.core.appender.routing.DefaultRouteScriptAppenderTest.testRoutingPresence2(DefaultRouteScriptAppenderTest.java:139) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) [ERROR] org.apache.logging.log4j.core.appender.routing.ScriptStaticVarsJavaScriptAppenderTest.testNotListAppender -- Time elapsed: 0.001 s <<< FAILURE! org.opentest4j.AssertionFailedError: expected: not <null> at org.apache.logging.log4j.core.appender.routing.DefaultRouteScriptAppenderTest.testNotListAppender(DefaultRouteScriptAppenderTest.java:96) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) [ERROR] org.apache.logging.log4j.core.appender.routing.ScriptStaticVarsJavaScriptAppenderTest.testNoRewritePolicy -- Time elapsed: 0 s <<< ERROR! java.lang.NullPointerException: Cannot invoke "org.apache.logging.log4j.core.appender.routing.RoutingAppender.getRewritePolicy()" because the return value of "org.apache.logging.log4j.core.appender.routing.DefaultRouteScriptAppenderTest.getRoutingAppender()" is null at org.apache.logging.log4j.core.appender.routing.DefaultRouteScriptAppenderTest.testNoRewritePolicy(DefaultRouteScriptAppenderTest.java:115) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) [ERROR] org.apache.logging.log4j.core.appender.routing.ScriptStaticVarsJavaScriptAppenderTest.testRoutingAppenderDefaultRouteKey -- Time elapsed: 0.001 s <<< ERROR! java.lang.NullPointerException: Cannot invoke "org.apache.logging.log4j.core.appender.routing.RoutingAppender.getDefaultRouteScript()" because "routingAppender" is null at org.apache.logging.log4j.core.appender.routing.DefaultRouteScriptAppenderTest.testRoutingAppenderDefaultRouteKey(DefaultRouteScriptAppenderTest.java:121) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) ``` It seems as though the config filename passed to `@LoggerContextSource` is being ignored -- changing the referenced files' content has no effect on the test outcome, and using a filename for a file that does not exist does not cause a different kind of failure. It just looks like the file is ignored entirely, and we're not sure why. Is there a quirk of `@LoggerContextSource` that means it doesn't work with subclassing, or something else we're not aware of? Should we be going about this in a different way, and if so how would you recommend turning a config filename into a working `LoggerContext`? -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: notifications-unsubscr...@logging.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org