Consistently return non-zero exit codes for jarmode failures

Update jar mode launchers to catch all exceptions and return a non-zero
exit code. This refinement also allows us to consolidate the existing
error reporting logic to a central locations. Modes that wish to report
a simple error rather than a full stacktrace can throw the newly
introduced `JarModeErrorException`.

Fixes gh-43435
This commit is contained in:
Phillip Webb
2024-12-06 17:15:10 -08:00
parent 589697a011
commit f21402d4c3
18 changed files with 230 additions and 80 deletions

View File

@@ -32,7 +32,10 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.boot.loader.jarmode.JarModeErrorException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
/**
@@ -172,8 +175,8 @@ class ExtractCommandTests extends AbstractJarModeTests {
try (FileWriter writer = new FileWriter(file)) {
writer.write("text");
}
TestPrintStream out = run(file);
assertThat(out).contains("is not compatible; ensure jar file is valid and launch script is not enabled");
assertThatExceptionOfType(JarModeErrorException.class).isThrownBy(() -> run(file))
.withMessageContaining("is not compatible; ensure jar file is valid and launch script is not enabled");
}
@Test
@@ -181,8 +184,9 @@ class ExtractCommandTests extends AbstractJarModeTests {
File destination = file("out");
Files.createDirectories(destination.toPath());
Files.createFile(new File(destination, "file.txt").toPath());
TestPrintStream out = run(ExtractCommandTests.this.archive, "--destination", destination.getAbsolutePath());
assertThat(out).contains("already exists and is not empty");
assertThatExceptionOfType(JarModeErrorException.class)
.isThrownBy(() -> run(ExtractCommandTests.this.archive, "--destination", destination.getAbsolutePath()))
.withMessageContaining("already exists and is not empty");
}
@Test
@@ -266,10 +270,10 @@ class ExtractCommandTests extends AbstractJarModeTests {
}
@Test
void printErrorIfLayersAreNotEnabled() throws IOException {
void failsIfLayersAreNotEnabled() throws IOException {
File archive = createArchive();
TestPrintStream out = run(archive, "--layers");
assertThat(out).hasSameContentAsResource("ExtractCommand-printErrorIfLayersAreNotEnabled.txt");
assertThatExceptionOfType(JarModeErrorException.class).isThrownBy(() -> run(archive, "--layers"))
.withMessage("Layers are not enabled");
}
}
@@ -318,10 +322,11 @@ class ExtractCommandTests extends AbstractJarModeTests {
}
@Test
void printErrorIfLayersAreNotEnabled() throws IOException {
void failsIfLayersAreNotEnabled() throws IOException {
File archive = createArchive();
TestPrintStream out = run(archive, "--launcher", "--layers");
assertThat(out).hasSameContentAsResource("ExtractCommand-printErrorIfLayersAreNotEnabled.txt");
assertThatExceptionOfType(JarModeErrorException.class)
.isThrownBy(() -> run(archive, "--launcher", "--layers"))
.withMessage("Layers are not enabled");
}
@Test

View File

@@ -42,10 +42,12 @@ import org.junit.jupiter.api.io.TempDir;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.boot.loader.jarmode.JarModeErrorException;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.FileCopyUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.mockito.BDDMockito.given;
@@ -146,8 +148,9 @@ class ExtractLayersCommandTests {
}
given(this.context.getArchiveFile()).willReturn(file);
try (TestPrintStream out = new TestPrintStream(this)) {
this.command.run(out, Collections.emptyMap(), Collections.emptyList());
assertThat(out).contains("is not compatible");
assertThatExceptionOfType(JarModeErrorException.class)
.isThrownBy(() -> this.command.run(out, Collections.emptyMap(), Collections.emptyList()))
.withMessageContaining("is not compatible");
}
}

View File

@@ -22,7 +22,10 @@ import java.util.jar.Manifest;
import org.junit.jupiter.api.Test;
import org.springframework.boot.loader.jarmode.JarModeErrorException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Tests for {@link ListLayersCommand}.
@@ -39,9 +42,9 @@ class ListLayersCommandTests extends AbstractJarModeTests {
}
@Test
void shouldPrintErrorWhenLayersAreNotEnabled() throws IOException {
TestPrintStream out = run(createArchive());
assertThat(out).hasSameContentAsResource("list-layers-output-layers-disabled.txt");
void shouldFailWhenLayersAreNotEnabled() {
assertThatExceptionOfType(JarModeErrorException.class).isThrownBy(() -> run(createArchive()))
.withMessage("Layers are not enabled");
}
private TestPrintStream run(File archive) {