Skip to content

Commit

Permalink
Polish logging message and test log output of throwIfFatal
Browse files Browse the repository at this point in the history
  • Loading branch information
simonbasle committed Aug 1, 2022
1 parent 988b16e commit b663215
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 47 deletions.
6 changes: 3 additions & 3 deletions reactor-core/src/main/java/reactor/core/Exceptions.java
Expand Up @@ -492,11 +492,11 @@ public static void throwIfFatal(@Nullable Throwable t) {
return;
}
if (isFatalButNotJvmFatal(t)) {
LOGGER.warn("throwIfFatal detected a fatal exception, throwing", t);
LOGGER.warn("throwIfFatal detected a fatal exception, which is thrown and logged below:", t);
throw (RuntimeException) t;
}
if (isJvmFatal(t)) {
LOGGER.warn("throwIfFatal detected a jvm fatal exception, throwing", t);
LOGGER.warn("throwIfFatal detected a jvm fatal exception, which is thrown and logged below:", t);
throw (Error) t;
}
}
Expand All @@ -514,7 +514,7 @@ public static void throwIfJvmFatal(@Nullable Throwable t) {
return;
}
if (isJvmFatal(t)) {
LOGGER.warn("throwIfJvmFatal detected a fatal exception, throwing", t);
LOGGER.warn("throwIfJvmFatal detected a jvm fatal exception, which is thrown and logged below:", t);
assert t instanceof Error;
throw (Error) t;
}
Expand Down
134 changes: 90 additions & 44 deletions reactor-core/src/test/java/reactor/core/ExceptionsTest.java
Expand Up @@ -24,11 +24,14 @@
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

import org.assertj.core.api.SoftAssertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;

import reactor.TestLoggerExtension;
import reactor.core.publisher.Mono;
import reactor.test.util.LoggerUtils;
import reactor.test.util.RaceTestUtils;
import reactor.test.util.TestLogger;
import reactor.util.annotation.Nullable;

import static org.assertj.core.api.Assertions.*;
Expand All @@ -45,6 +48,32 @@ public class ExceptionsTest {
static final AtomicReferenceFieldUpdater<ExceptionsTest, Throwable> ADD_THROWABLE =
AtomicReferenceFieldUpdater.newUpdater(ExceptionsTest.class, Throwable.class, "addThrowable");

static VirtualMachineError JVM_FATAL_VIRTUAL_MACHINE_ERROR = new VirtualMachineError("expected to be logged") {
@Override
public String toString() {
return "custom VirtualMachineError: expected to be logged";
}
};

static final ThreadDeath JVM_FATAL_THREAD_DEATH = new ThreadDeath() {
@Override
public String getMessage() {
return "expected to be logged";
}

@Override
public String toString() {
return "custom ThreadDeath: expected to be logged";
}
};

static final LinkageError JVM_FATAL_LINKAGE_ERROR = new LinkageError("expected to be logged") {
@Override
public String toString() {
return "custom LinkageError: expected to be logged";
}
};

@Test
public void bubble() throws Exception {
Throwable t = new Exception("test");
Expand Down Expand Up @@ -182,121 +211,138 @@ void errorCallbackNotImplementedIsFatalButNotJvmFatal() {

@Test
void virtualMachineErrorIsFatalAndJvmFatal() {
Throwable exception = new VirtualMachineError() { };
assertThat(Exceptions.isFatal(exception))
assertThat(Exceptions.isFatal(JVM_FATAL_VIRTUAL_MACHINE_ERROR))
.as("isFatal(VirtualMachineError)")
.isTrue();
assertThat(Exceptions.isJvmFatal(exception))
assertThat(Exceptions.isJvmFatal(JVM_FATAL_VIRTUAL_MACHINE_ERROR))
.as("isJvmFatal(VirtualMachineError)")
.isTrue();
}

@Test
void linkageErrorIsFatalAndJvmFatal() {
Throwable exception = new LinkageError();
assertThat(Exceptions.isFatal(exception))
assertThat(Exceptions.isFatal(JVM_FATAL_LINKAGE_ERROR))
.as("isFatal(LinkageError)")
.isTrue();
assertThat(Exceptions.isJvmFatal(exception))
assertThat(Exceptions.isJvmFatal(JVM_FATAL_LINKAGE_ERROR))
.as("isJvmFatal(LinkageError)")
.isTrue();
}

@Test
void threadDeathIsFatalAndJvmFatal() {
Throwable exception = new ThreadDeath();
assertThat(Exceptions.isFatal(exception))
assertThat(Exceptions.isFatal(JVM_FATAL_THREAD_DEATH))
.as("isFatal(ThreadDeath)")
.isTrue();
assertThat(Exceptions.isJvmFatal(exception))
assertThat(Exceptions.isJvmFatal(JVM_FATAL_THREAD_DEATH))
.as("isJvmFatal(ThreadDeath)")
.isTrue();
}

@AfterEach
void disableCapture() {
LoggerUtils.disableCapture();
}

@Test
public void throwIfFatalThrowsBubbling() {
void throwIfFatalThrowsAndLogsBubbling() {
TestLogger testLogger = new TestLogger(false);
LoggerUtils.enableCaptureWith(testLogger);

BubblingException expected = new BubblingException("expected to be logged");

assertThatExceptionOfType(BubblingException.class)
.isThrownBy(() -> Exceptions.throwIfFatal(expected))
.isSameAs(expected);

assertThat(testLogger.getErrContent())
.startsWith("[ WARN] throwIfFatal detected a fatal exception, which is thrown and logged below: - reactor.core.Exceptions$BubblingException: expected to be logged");
}

@Test
public void throwIfFatalThrowsErrorCallbackNotImplemented() {
void throwIfFatalThrowsAndLogsErrorCallbackNotImplemented() {
TestLogger testLogger = new TestLogger(false);
LoggerUtils.enableCaptureWith(testLogger);

ErrorCallbackNotImplemented expected = new ErrorCallbackNotImplemented(new IllegalStateException("expected to be logged"));

assertThatExceptionOfType(ErrorCallbackNotImplemented.class)
.isThrownBy(() -> Exceptions.throwIfFatal(expected))
.isSameAs(expected)
.withCause(expected.getCause());

assertThat(testLogger.getErrContent())
.startsWith("[ WARN] throwIfFatal detected a fatal exception, which is thrown and logged below: - reactor.core.Exceptions$ErrorCallbackNotImplemented: java.lang.IllegalStateException: expected to be logged");
}

@Test
void throwIfFatalWithJvmFatalErrors() {
VirtualMachineError fatal1 = new VirtualMachineError("expected to be logged") {};
ThreadDeath fatal2 = new ThreadDeath() {
@Override
public String getMessage() {
return "expected to be logged";
}
};
LinkageError fatal3 = new LinkageError("expected to be logged");
void throwIfFatalWithJvmFatalErrorsDoesThrowAndLog() {
TestLogger testLogger = new TestLogger(false);
LoggerUtils.enableCaptureWith(testLogger);

SoftAssertions.assertSoftly(softly -> {
softly.assertThatExceptionOfType(VirtualMachineError.class)
.as("VirtualMachineError")
.isThrownBy(() -> Exceptions.throwIfFatal(fatal1))
.isSameAs(fatal1);
.isThrownBy(() -> Exceptions.throwIfFatal(JVM_FATAL_VIRTUAL_MACHINE_ERROR))
.isSameAs(JVM_FATAL_VIRTUAL_MACHINE_ERROR);

softly.assertThatExceptionOfType(ThreadDeath.class)
.as("ThreadDeath")
.isThrownBy(() -> Exceptions.throwIfFatal(fatal2))
.isSameAs(fatal2);
.isThrownBy(() -> Exceptions.throwIfFatal(JVM_FATAL_THREAD_DEATH))
.isSameAs(JVM_FATAL_THREAD_DEATH);

softly.assertThatExceptionOfType(LinkageError.class)
.as("LinkageError")
.isThrownBy(() -> Exceptions.throwIfFatal(fatal3))
.isSameAs(fatal3);
.isThrownBy(() -> Exceptions.throwIfFatal(JVM_FATAL_LINKAGE_ERROR))
.isSameAs(JVM_FATAL_LINKAGE_ERROR);

softly.assertThat(testLogger.getErrContent())
.startsWith("[ WARN] throwIfFatal detected a jvm fatal exception, which is thrown and logged below: - custom VirtualMachineError: expected to be logged")
.contains("[ WARN] throwIfFatal detected a jvm fatal exception, which is thrown and logged below: - custom ThreadDeath: expected to be logged")
.contains("[ WARN] throwIfFatal detected a jvm fatal exception, which is thrown and logged below: - custom LinkageError: expected to be logged");
});
}

@Test
void throwIfJvmFatal() {
VirtualMachineError fatal1 = new VirtualMachineError("expected to be logged") {};
ThreadDeath fatal2 = new ThreadDeath() {
@Override
public String getMessage() {
return "expected to be logged";
}
};
LinkageError fatal3 = new LinkageError("expected to be logged");
void throwIfJvmFatalDoesThrowAndLog() {
TestLogger testLogger = new TestLogger(false);
LoggerUtils.enableCaptureWith(testLogger);

assertThatExceptionOfType(VirtualMachineError.class)
.as("VirtualMachineError")
.isThrownBy(() -> Exceptions.throwIfJvmFatal(fatal1))
.isSameAs(fatal1);
.isThrownBy(() -> Exceptions.throwIfJvmFatal(JVM_FATAL_VIRTUAL_MACHINE_ERROR))
.isSameAs(JVM_FATAL_VIRTUAL_MACHINE_ERROR);

assertThatExceptionOfType(ThreadDeath.class)
.as("ThreadDeath")
.isThrownBy(() -> Exceptions.throwIfJvmFatal(fatal2))
.isSameAs(fatal2);
.isThrownBy(() -> Exceptions.throwIfJvmFatal(JVM_FATAL_THREAD_DEATH))
.isSameAs(JVM_FATAL_THREAD_DEATH);

assertThatExceptionOfType(LinkageError.class)
.as("LinkageError")
.isThrownBy(() -> Exceptions.throwIfJvmFatal(fatal3))
.isSameAs(fatal3);
}
.isThrownBy(() -> Exceptions.throwIfJvmFatal(JVM_FATAL_LINKAGE_ERROR))
.isSameAs(JVM_FATAL_LINKAGE_ERROR);

assertThat(testLogger.getErrContent())
.startsWith("[ WARN] throwIfJvmFatal detected a jvm fatal exception, which is thrown and logged below: - custom VirtualMachineError: expected to be logged")
.contains("[ WARN] throwIfJvmFatal detected a jvm fatal exception, which is thrown and logged below: - custom ThreadDeath: expected to be logged")
.contains("[ WARN] throwIfJvmFatal detected a jvm fatal exception, which is thrown and logged below: - custom LinkageError: expected to be logged");
};

@Test
void throwIfJvmFatalDoesntThrowOnSimplyFatalExceptions() {
void throwIfJvmFatalDoesntThrowNorLogsOnSimplyFatalExceptions() {
TestLogger testLogger = new TestLogger(false);
LoggerUtils.enableCaptureWith(testLogger);

SoftAssertions.assertSoftly(softly -> {
softly.assertThatCode(() -> Exceptions.throwIfJvmFatal(new BubblingException("not thrown")))
.doesNotThrowAnyException();

softly.assertThatCode(() -> Exceptions.throwIfJvmFatal(new ErrorCallbackNotImplemented(new RuntimeException("not thrown"))))
.doesNotThrowAnyException();
});

assertThat(testLogger.getErrContent()).isEmpty();
}

@Test
Expand Down

0 comments on commit b663215

Please sign in to comment.