Skip to content

Commit

Permalink
Enhance LogbackTestHelpers
Browse files Browse the repository at this point in the history
* Make resetLogback() try logback-test.xml, then logback.xml as fallback
* Add varargs argument to resetLogback so that it accepts a primary
  location, and optionally fallback locations
  • Loading branch information
sleberknight committed Feb 9, 2024
1 parent 702a6d0 commit 7259c43
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 11 deletions.
58 changes: 52 additions & 6 deletions src/main/java/org/kiwiproject/test/logback/LogbackTestHelpers.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
package org.kiwiproject.test.logback;

import static com.google.common.base.Preconditions.checkArgument;
import static org.apache.commons.lang3.StringUtils.isNoneBlank;
import static org.kiwiproject.base.KiwiPreconditions.checkArgumentNotBlank;
import static org.kiwiproject.base.KiwiPreconditions.checkArgumentNotNull;

import ch.qos.logback.classic.ClassicConstants;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;
import com.google.common.io.Resources;
import lombok.experimental.UtilityClass;
import org.apache.commons.collections4.ListUtils;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.slf4j.LoggerFactory;

import java.net.URL;
import java.util.List;
import java.util.Objects;

/**
* Static test utilities that provide Logback-related functionality.
*/
Expand All @@ -16,32 +27,67 @@ public class LogbackTestHelpers {

/**
* Reset the Logback logging system using the default test configuration file ({@code logback-test.xml}).
* If that doesn't exist, try to fall back to the default configuration file ({@code logback.xml}).
* <p>
* If you need a custom location (or locations), use {@link #resetLogback(String, String...)}.
*
* @see ClassicConstants#TEST_AUTOCONFIG_FILE
* @throws UncheckedJoranException if an error occurs resetting Logback
* @see ClassicConstants#TEST_AUTOCONFIG_FILE
* @see ClassicConstants#AUTOCONFIG_FILE
*/
public static void resetLogback() {
resetLogback(ClassicConstants.TEST_AUTOCONFIG_FILE);
resetLogback(ClassicConstants.TEST_AUTOCONFIG_FILE, ClassicConstants.AUTOCONFIG_FILE);
}

/**
* Reset the Logback logging system using the given configuration file.
* Reset the Logback logging system using the given configuration file or fallback configuration files.
* <p>
* The fallback configurations are tried in the order they are provided.
*
* @param logbackConfigFilePath the location of the custom Logback configuration file
* @param logbackConfigFile the location of the custom Logback configuration file
* @param fallbackConfigFiles additional locations to check for Logback configuration files
* @throws UncheckedJoranException if an error occurs resetting Logback
* @throws IllegalArgumentException if none of the Logback configuration files exist
*/
public static void resetLogback(String logbackConfigFilePath) {
public static void resetLogback(String logbackConfigFile, String... fallbackConfigFiles) {
checkArgumentNotBlank(logbackConfigFile, "logbackConfigFile must not be blank");
checkArgumentNotNull(fallbackConfigFiles, "fallback locations vararg parameter must not be null");
checkArgument(isNoneBlank(fallbackConfigFiles), "fallbackConfigFiles must not contain blank locations");

try {
var loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
loggerContext.stop();

var joranConfigurator = new JoranConfigurator();
joranConfigurator.setContext(loggerContext);
var logbackConfigUrl = Resources.getResource(logbackConfigFilePath);
var logbackConfigUrl = getFirstLogbackConfigOrThrow(logbackConfigFile, fallbackConfigFiles);
joranConfigurator.doConfigure(logbackConfigUrl);
loggerContext.start();
} catch (JoranException e) {
throw new UncheckedJoranException(e);
}
}

private static URL getFirstLogbackConfigOrThrow(String logbackConfigFilePath, String... fallbackConfigFilePaths) {
var allConfigs = ListUtils.union(
List.of(logbackConfigFilePath),
List.of(fallbackConfigFilePaths)
);

return allConfigs.stream()
.map(LogbackTestHelpers::getResourceOrNull)
.filter(Objects::nonNull)
.findFirst()
.orElseThrow(() ->
new IllegalArgumentException("Did not find any of the Logback configurations: " + allConfigs));
}

@Nullable
private static URL getResourceOrNull(String resourceName) {
try {
return Resources.getResource(resourceName);
} catch (IllegalArgumentException e) {
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@

import ch.qos.logback.core.joran.spi.JoranException;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.kiwiproject.test.junit.jupiter.ResetLogbackLoggingExtension;
import org.kiwiproject.test.junit.jupiter.params.provider.MinimalBlankStringSource;

/**
* Unit test for {@link LogbackTestHelpers}. This mainly tests invalid arguments
Expand All @@ -18,16 +21,52 @@
@ExtendWith(ResetLogbackLoggingExtension.class)
class LogbackTestHelpersTest {

@Test
void shouldThrowIllegalArgument_WhenInvalidLogbackConfigPath() {
assertThatIllegalArgumentException()
.isThrownBy(() -> LogbackTestHelpers.resetLogback("dne.xml"));
@Nested
class ThrowsIllegalArgumentException {

@Test
void whenInvalidLogbackConfigPath() {
assertThatIllegalArgumentException()
.isThrownBy(() -> LogbackTestHelpers.resetLogback("dne.xml"))
.withMessage("Did not find any of the Logback configurations: [dne.xml]");
}

@Test
void whenInvalidLogbackConfigPaths() {
assertThatIllegalArgumentException().isThrownBy(() ->
LogbackTestHelpers.resetLogback("dne1.xml", "dne2.xml", "dne3.xml"))
.withMessage("Did not find any of the Logback configurations: [dne1.xml, dne2.xml, dne3.xml]");
}

@ParameterizedTest
@MinimalBlankStringSource
void whenGivenBlankConfigLocation(String location) {
assertThatIllegalArgumentException()
.isThrownBy(() -> LogbackTestHelpers.resetLogback(location))
.withMessage("logbackConfigFile must not be blank");
}

@Test
void whenExplicitNullFallbackLocationsIsGiven() {
assertThatIllegalArgumentException()
.isThrownBy(() -> LogbackTestHelpers.resetLogback("acme-logback.xml", (String[]) null))
.withMessage("fallback locations vararg parameter must not be null");
}

@ParameterizedTest
@MinimalBlankStringSource
void whenFallbackLocationIsBlank(String fallbackLocation) {
assertThatIllegalArgumentException()
.isThrownBy(() -> LogbackTestHelpers.resetLogback("acme-test-logback.xml", fallbackLocation))
.withMessage("fallbackConfigFiles must not contain blank locations");
}
}

@Test
void shouldThrowUncheckedJoranException_WhenInvalidLogbackConfig() {
assertThatExceptionOfType(UncheckedJoranException.class)
.isThrownBy(() -> LogbackTestHelpers.resetLogback("LogbackTestHelpersTest/invalid-logback-test.xml"))
.isThrownBy(() ->
LogbackTestHelpers.resetLogback("LogbackTestHelpersTest/invalid-logback-test.xml"))
.withCauseExactlyInstanceOf(JoranException.class);
}
}

0 comments on commit 7259c43

Please sign in to comment.