Nina
Nina

Reputation: 701

Set System Properties for JUnit Test before ServletContextListener uses file path from web.xml

I am modifying and old project that uses Spring 3.1.4.

I am trying to use a StartupListener to configure Logback:

public class LoggingStartupListener implements ServletContextListener {

    private static final Logger LOGGER = LoggerFactory.getLogger(LoggingStartupListener.class.getName());


@Override
public void contextInitialized(final ServletContextEvent sce) {
    final LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
    context.reset();
    final JoranConfigurator configurator = new JoranConfigurator();
    final ServletContext servletContext = sce.getServletContext();
    final StringBuilder filePath = new StringBuilder(100);
    filePath.append(servletContext.getRealPath("/"));
    filePath.append(servletContext.getInitParameter("logFileName"));
    InputStream configStream = null;
    try {
        configStream = FileUtils.openInputStream(new File(filePath.toString()));

...

It is reading a file path from the web.xml:

<context-param>
    <param-name>logFileName</param-name>
    <param-value>/WEB-INF/config/${spring.profiles.active}/logback.xml</param-value>
</context-param>

Now, when I run a JUnit test I always run into the exception:

java.io.FileNotFoundException: File '/var/folders/v7/1r3m8y8j487dqj7vmvb4n4kxcw70fj/T/tomcat-embedded-77438108580291256392.tmp/webapps/myproject/WEB-INF/config/${spring.profiles.active}/logback.xml' does not exist
at org.apache.commons.io.FileUtils.openInputStream(FileUtils.java:136)

Which means, that the property spring.profiles.active is never resolved.

I tried all kind of things:

1) I tried setting the property before the test:

@BeforeClass
public static void setSystemProperty() {
    System.out.println("---------------------BeforeClass--------------------");
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
    ctx.getEnvironment().setActiveProfiles("local");
    ctx.refresh();

    System.setProperty("spring.profiles.active", "local");
}

But it did not work, because this method is called way after the error is thrown. ("----------BeforeClass--------------" appears much after the error in the log.)

2) I tried using an annotation before the test class:

@ActiveProfiles(profiles = "local")

3) I tried setting the property with a spring-test.properties file:

spring.profile.active=local

and include it in the test-context:

<context:property-placeholder location="classpath:spring-test.properties"/>

-> no effect whatsoever

4) I even tried to set the property directly IN the ServletContextListener:

@Override
public void contextInitialized(final ServletContextEvent sce) {
    System.setProperty("spring.profiles.active", "local");
    ...

And this really surprised me, because this should have worked, shouldn't it?

Do I encounter these problems because I am using an old Spring version? I never had these problems in other projects with higher Spring versions. Or what am I missing?

Can I configure the listener to startup later? Or can I configure the unit tests to set the system property before the ServletContextListener is started?

Or will it be better to initialise logback in a different way to avoid these problems - but why don't they appear in other projects then?

I found this but I don't know whether that applies to my case: Spring-test and ServletContextListener in web.xml

It says there is no way to configure ServletContextListener using Spring MVC Test. It says I can try to overwrite the context-param with

wac.getServletContext().setInitParameter(name, value);

But I wouldn't know when/ where to do it because the web.xml is obviously read before the test classes are initialised.

Thanks a lot in advance for any hint

Upvotes: 1

Views: 2686

Answers (1)

Nina
Nina

Reputation: 701

I used logback spring extensions instead of our own implementation and with that the problem disappears!

I used this documentation: https://github.com/qos-ch/logback-extensions/wiki/Spring

One of the features is: - "Specify the logback.xml location using a Spring resource path and system property placeholders."

Exactly what I needed. I used logback-ext-spring with version 0.1.4.

Upvotes: 1

Related Questions