Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make sure (basic) logging is set up before each test class #22920

Merged
merged 1 commit into from
Jan 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
junit.jupiter.testclass.order.default=io.quarkus.test.junit.util.QuarkusTestProfileAwareClassOrderer
junit.jupiter.extensions.autodetection.enabled=true
junit.jupiter.testclass.order.default=io.quarkus.test.junit.util.QuarkusTestProfileAwareClassOrderer
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package io.quarkus.test.junit;

import org.eclipse.microprofile.config.ConfigProvider;
import org.eclipse.microprofile.config.spi.ConfigProviderResolver;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;

import io.quarkus.bootstrap.logging.InitialConfigurator;

/**
* A (global) JUnit callback that enables/sets up basic logging if logging has not already been set up.
* <p/>
* This is useful for getting log output from non-Quarkus tests (if executed separately or before the first Quarkus test),
* but also for getting instant log output from {@code QuarkusTestResourceLifecycleManagers} etc.
* <p/>
* This callback can be disabled via {@link #CFGKEY_ENABLED} in {@code junit-platform.properties} or via system property.
*/
public class BasicLoggingEnabler implements BeforeAllCallback {

private static final String CFGKEY_ENABLED = "junit.quarkus.enable-basic-logging";
private static Boolean enabled;

// to speed things up a little, eager async loading of the config that will be looked up in LoggingSetupRecorder
// downside: doesn't obey CFGKEY_ENABLED, but that should be bearable
static {
// e.g. continuous testing has everything set up already (DELAYED_HANDLER is active)
if (!InitialConfigurator.DELAYED_HANDLER.isActivated()) {
new Thread(() -> ConfigProvider.getConfig()).start();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not pretty, but saves up to ~50ms total runtime in my not-so-small project.

}
}

@Override
public void beforeAll(ExtensionContext context) throws Exception {
if (enabled == null) {
enabled = context.getConfigurationParameter(CFGKEY_ENABLED).map(Boolean::valueOf).orElse(Boolean.TRUE);
}
if (!enabled || InitialConfigurator.DELAYED_HANDLER.isActivated()) {
return;
}
try {
IntegrationTestUtil.activateLogging();
} finally {
// release the config that was retrieved by above call so that tests that try to register their own config
// don't fail with:
// "IllegalStateException: SRCFG00017: Configuration already registered for the given class loader"
// also, a possible recreation of basically the same config for a later test class will consume far less time
var configProviderResolver = ConfigProviderResolver.instance();
var config = configProviderResolver.getConfig();
if (config != null) { // probably never null, but be safe
configProviderResolver.releaseConfig(config);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,22 @@ public class QuarkusTestProfileAwareClassOrderer implements ClassOrderer {
protected static final String DEFAULT_ORDER_PREFIX_QUARKUS_TEST_WITH_RESTRICTED_RES = "45_";
protected static final String DEFAULT_ORDER_PREFIX_NON_QUARKUS_TEST = "60_";

static final String CFGKEY_ORDER_PREFIX_QUARKUS_TEST = "quarkus.test.orderer.prefix.quarkus-test";
static final String CFGKEY_ORDER_PREFIX_QUARKUS_TEST_WITH_PROFILE = "quarkus.test.orderer.prefix.quarkus-test-with-profile";
static final String CFGKEY_ORDER_PREFIX_QUARKUS_TEST = "junit.quarkus.orderer.prefix.quarkus-test";
@Deprecated
static final String _CFGKEY_ORDER_PREFIX_QUARKUS_TEST = "quarkus.test.orderer.prefix.quarkus-test";

static final String CFGKEY_ORDER_PREFIX_QUARKUS_TEST_WITH_PROFILE = "junit.quarkus.orderer.prefix.quarkus-test-with-profile";
@Deprecated
static final String _CFGKEY_ORDER_PREFIX_QUARKUS_TEST_WITH_PROFILE = "quarkus.test.orderer.prefix.quarkus-test-with-profile";

static final String CFGKEY_ORDER_PREFIX_QUARKUS_TEST_WITH_RESTRICTED_RES = "quarkus.test.orderer.prefix.quarkus-test-with-restricted-resource";
@Deprecated
static final String _CFGKEY_ORDER_PREFIX_QUARKUS_TEST_WITH_RESTRICTED_RES = "junit.quarkus.orderer.prefix.quarkus-test-with-restricted-resource";

static final String CFGKEY_ORDER_PREFIX_NON_QUARKUS_TEST = "quarkus.test.orderer.prefix.non-quarkus-test";
@Deprecated
static final String _CFGKEY_ORDER_PREFIX_NON_QUARKUS_TEST = "junit.quarkus.orderer.prefix.non-quarkus-test";

static final String CFGKEY_SECONDARY_ORDERER = "quarkus.test.orderer.secondary-orderer";

@Override
Expand All @@ -67,18 +79,26 @@ public void orderClasses(ClassOrdererContext context) {
if (context.getClassDescriptors().size() <= 1 || context.getClassDescriptors().get(0).isAnnotated(Nested.class)) {
return;
}
var prefixQuarkusTest = context
.getConfigurationParameter(CFGKEY_ORDER_PREFIX_QUARKUS_TEST)
.orElse(DEFAULT_ORDER_PREFIX_QUARKUS_TEST);
var prefixQuarkusTestWithProfile = context
.getConfigurationParameter(CFGKEY_ORDER_PREFIX_QUARKUS_TEST_WITH_PROFILE)
.orElse(DEFAULT_ORDER_PREFIX_QUARKUS_TEST_WITH_PROFILE);
var prefixQuarkusTestWithRestrictedResource = context
.getConfigurationParameter(CFGKEY_ORDER_PREFIX_QUARKUS_TEST_WITH_RESTRICTED_RES)
.orElse(DEFAULT_ORDER_PREFIX_QUARKUS_TEST_WITH_RESTRICTED_RES);
var prefixNonQuarkusTest = context
.getConfigurationParameter(CFGKEY_ORDER_PREFIX_NON_QUARKUS_TEST)
.orElse(DEFAULT_ORDER_PREFIX_NON_QUARKUS_TEST);
var prefixQuarkusTest = getConfigParam(
CFGKEY_ORDER_PREFIX_QUARKUS_TEST,
_CFGKEY_ORDER_PREFIX_QUARKUS_TEST,
DEFAULT_ORDER_PREFIX_QUARKUS_TEST,
context);
var prefixQuarkusTestWithProfile = getConfigParam(
CFGKEY_ORDER_PREFIX_QUARKUS_TEST_WITH_PROFILE,
_CFGKEY_ORDER_PREFIX_QUARKUS_TEST_WITH_PROFILE,
DEFAULT_ORDER_PREFIX_QUARKUS_TEST_WITH_PROFILE,
context);
var prefixQuarkusTestWithRestrictedResource = getConfigParam(
CFGKEY_ORDER_PREFIX_QUARKUS_TEST_WITH_RESTRICTED_RES,
_CFGKEY_ORDER_PREFIX_QUARKUS_TEST_WITH_RESTRICTED_RES,
DEFAULT_ORDER_PREFIX_QUARKUS_TEST_WITH_RESTRICTED_RES,
context);
var prefixNonQuarkusTest = getConfigParam(
CFGKEY_ORDER_PREFIX_NON_QUARKUS_TEST,
_CFGKEY_ORDER_PREFIX_NON_QUARKUS_TEST,
DEFAULT_ORDER_PREFIX_NON_QUARKUS_TEST,
context);

// first pass: run secondary orderer first (!), which is easier than running it per "grouping"
buildSecondaryOrderer(context).orderClasses(context);
Expand Down Expand Up @@ -111,6 +131,19 @@ public void orderClasses(ClassOrdererContext context) {
}));
}

private String getConfigParam(String key, String deprecatedKey, String fallbackValue, ClassOrdererContext context) {
return context.getConfigurationParameter(key)
.orElseGet(() -> {
Optional<String> value = context.getConfigurationParameter(deprecatedKey);
if (value.isPresent()) {
System.out.printf("Config key %s is deprecated, please use %s instead.%n", deprecatedKey, key);
return value.orElseThrow();
} else {
return fallbackValue;
}
});
}

private ClassOrderer buildSecondaryOrderer(ClassOrdererContext context) {
return context.getConfigurationParameter(CFGKEY_SECONDARY_ORDERER)
.map(fqcn -> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
io.quarkus.test.junit.BasicLoggingEnabler
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static io.quarkus.test.junit.util.QuarkusTestProfileAwareClassOrderer.CFGKEY_ORDER_PREFIX_NON_QUARKUS_TEST;
import static io.quarkus.test.junit.util.QuarkusTestProfileAwareClassOrderer.CFGKEY_SECONDARY_ORDERER;
import static io.quarkus.test.junit.util.QuarkusTestProfileAwareClassOrderer._CFGKEY_ORDER_PREFIX_NON_QUARKUS_TEST;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
Expand Down Expand Up @@ -104,6 +105,23 @@ void configuredPrefix() {
assertThat(input).containsExactly(nonQuarkusTestDesc, quarkusTestDesc);
}

@Test
@Deprecated
void configuredPrefix_deprecated() {
ClassDescriptor quarkusTestDesc = quarkusDescriptorMock(Test01.class, null);
ClassDescriptor nonQuarkusTestDesc = descriptorMock(Test03.class);
List<ClassDescriptor> input = Arrays.asList(quarkusTestDesc, nonQuarkusTestDesc);
doReturn(input).when(contextMock).getClassDescriptors();

when(contextMock.getConfigurationParameter(anyString())).thenReturn(Optional.empty()); // for strict stubbing
// prioritize unit tests
when(contextMock.getConfigurationParameter(_CFGKEY_ORDER_PREFIX_NON_QUARKUS_TEST)).thenReturn(Optional.of("01_"));

underTest.orderClasses(contextMock);

assertThat(input).containsExactly(nonQuarkusTestDesc, quarkusTestDesc);
}

@Test
void secondaryOrderer() {
ClassDescriptor quarkusTest1Desc = quarkusDescriptorMock(Test01.class, null);
Expand Down