Skip to content

Commit

Permalink
Add .debugBytecode() and .traceCategories() to QuarkusUnitTest
Browse files Browse the repository at this point in the history
To easy debugging of such tests.
  • Loading branch information
yrodiere committed Sep 6, 2024
1 parent ac4d54d commit 8c8eac3
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@

import static org.assertj.core.api.Assertions.assertThat;

import java.util.Map;
import java.util.UUID;

import jakarta.inject.Inject;
import jakarta.persistence.Entity;
import jakarta.persistence.EntityManager;
Expand All @@ -30,36 +27,19 @@
*/
public class PublicFieldAccessInheritanceTest {

// FIXME Temporary debug options for https://github.com/quarkusio/quarkus/issues/42479
// Needs to be set very early (e.g. as system properties) in order to affect the build;
// see https://quarkusio.zulipchat.com/#narrow/stream/187038-dev/topic/Build.20logs
private static final Map<String, String> DEBUG_PROPERTIES = Map.of(
"quarkus.hibernate-orm.log.sql", "true",
"quarkus.hibernate-orm.log.bind-parameters", "true",
"quarkus.log.category.\"org.hibernate\".min-level", "TRACE",
"quarkus.log.category.\"org.hibernate\".level", "TRACE",
"quarkus.log.category.\"io.quarkus.hibernate\".min-level", "TRACE",
"quarkus.log.category.\"io.quarkus.hibernate\".level", "TRACE",
"quarkus.log.category.\"io.quarkus.panache\".min-level", "TRACE",
"quarkus.log.category.\"io.quarkus.panache\".level", "TRACE",
"quarkus.debug.transformed-classes-dir", "target/debug/${testRunId}/transformed-classes",
"quarkus.debug.generated-classes-dir", "target/debug/${testRunId}/generated-classes");

@RegisterExtension
static QuarkusUnitTest runner = new QuarkusUnitTest()
.setBeforeAllCustomizer(() -> {
// Used to differentiate reruns of flaky tests in Maven
var testRunId = PublicFieldAccessInheritanceTest.class + "/" + UUID.randomUUID();
System.out.println("Test run ID: " + testRunId);
DEBUG_PROPERTIES.forEach((key, value) -> System.setProperty(key, value.replace("${testRunId}", testRunId)));
})
.setAfterAllCustomizer(() -> DEBUG_PROPERTIES.keySet().forEach(System::clearProperty))
.withApplicationRoot((jar) -> jar
.addClass(MyMappedSuperclass.class)
.addClass(MyAbstractEntity.class)
.addClass(MyConcreteEntity.class)
.addClass(FieldAccessEnhancedDelegate.class))
.withConfigurationResource("application.properties");
.withConfigurationResource("application.properties")
// FIXME Temporary debug options for https://github.com/quarkusio/quarkus/issues/42479
.overrideConfigKey("quarkus.hibernate-orm.log.sql", "true")
.overrideConfigKey("quarkus.hibernate-orm.log.bind-parameters", "true")
.debugBytecode(true)
.traceCategories("org.hibernate", "io.quarkus.hibernate", "io.quarkus.panache");

@Inject
EntityManager em;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.util.ServiceLoader;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
Expand Down Expand Up @@ -137,6 +138,10 @@ public class QuarkusUnitTest

private List<Consumer<QuarkusBootstrap.Builder>> bootstrapCustomizers = new ArrayList<>();

private boolean debugBytecode = false;
private List<String> traceCategories = new ArrayList<>();
private Map<String, String> systemPropertiesToRestore = new HashMap<>();

public QuarkusUnitTest setExpectedException(Class<? extends Throwable> expectedException) {
return setExpectedException(expectedException, false);
}
Expand Down Expand Up @@ -514,6 +519,26 @@ public void beforeAll(ExtensionContext extensionContext) throws Exception {
if (beforeAllCustomizer != null) {
beforeAllCustomizer.run();
}
if (debugBytecode) {
// Use a unique ID to avoid overriding dumps between test classes (and re-execution of flaky tests).
var testRunId = extensionContext.getRequiredTestClass().getName() + "/" + UUID.randomUUID();
System.out.println("[QuarkusUnitTest] Debug dumps enabled. Test run ID: " + testRunId);
// This needs to be set as system properties; see BootstrapDebug.java.
// Note these paths are considered standard and may be taken advantage of in Quarkus CI (to collect dumps).
overrideSystemProperty("quarkus.debug.transformed-classes-dir",
"target/debug/" + testRunId + "/transformed-classes");
overrideSystemProperty("quarkus.debug.generated-classes-dir", "target/debug/" + testRunId + "/generated-classes");
overrideSystemProperty("quarkus.debug.generated-sources-dir", "target/debug/" + testRunId + "/generated-sources");
}
if (traceCategories != null) {
System.out.println("[QuarkusUnitTest] Trace logs enabled for the following categories: " + traceCategories);
// This needs to be set very early (e.g. as system properties) in order to affect the build too;
// see https://quarkusio.zulipchat.com/#narrow/stream/187038-dev/topic/Build.20logs
for (String traceCategory : traceCategories) {
overrideSystemProperty("quarkus.log.category.\"" + traceCategory + "\".min-level", "TRACE");
overrideSystemProperty("quarkus.log.category.\"" + traceCategory + "\".level", "TRACE");
}
}
originalClassLoader = Thread.currentThread().getContextClassLoader();
originalHandlers = rootLogger.getHandlers();
rootLogger.addHandler(inMemoryLogHandler);
Expand Down Expand Up @@ -718,6 +743,13 @@ private Throwable unwrapException(Throwable cause) {
return cause;
}

private void overrideSystemProperty(String key, String value) {
// IMPORTANT: Not logging the value in case it's a secret.
System.out.println("[QuarkusUnitTest] Overriding system property '" + key + "'");
systemPropertiesToRestore.putIfAbsent(key, System.getProperty(key));
System.setProperty(key, value);
}

@Override
public void afterAll(ExtensionContext extensionContext) throws Exception {
actualTestClass = null;
Expand Down Expand Up @@ -764,6 +796,13 @@ public void afterAll(ExtensionContext extensionContext) throws Exception {
if (afterAllCustomizer != null) {
afterAllCustomizer.run();
}
systemPropertiesToRestore.forEach((key, previousValue) -> {
if (previousValue == null) {
System.clearProperty(key);
} else {
System.setProperty(key, previousValue);
}
});
ClearCache.clearCaches();
TestConfigUtil.cleanUp();
}
Expand Down Expand Up @@ -850,6 +889,36 @@ public QuarkusUnitTest overrideRuntimeConfigKey(final String propertyKey, final
return this;
}

/**
* Controls bytecode-related debug dumping.
* <p>
* When enabled, each Quarkus startup will have configuration properties
* such as {@code quarkus.debug.generated-classes-dir} set
* so that generated code gets dumped in {@code target/debug},
* within a unique subdirectory for each test execution.
* <p>
* Look at the logs of a particular test to identify the corresponding dump directory.
*
* @param debugBytecode {@code true} if debug should be enabled
* @return {@code this}, for method chaining.
*/
public QuarkusUnitTest debugBytecode(boolean debugBytecode) {
this.debugBytecode = debugBytecode;
return this;
}

/**
* Enables trace logs for the given categories,
* during both build and runtime.
*
* @param categories The categories for which to enable trace logging.
* @return {@code this}, for method chaining.
*/
public QuarkusUnitTest traceCategories(String... categories) {
Collections.addAll(this.traceCategories, categories);
return this;
}

@Override
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
throws ParameterResolutionException {
Expand Down

0 comments on commit 8c8eac3

Please sign in to comment.