Allow step action to be optional

Update `SpringApplicationRunListeners` so that the step action
is optional and does not need to call `end()`.

This commit also introduces a test for the failure case showing
that there is a missed call to end with the initial solution.

See gh-22845
This commit is contained in:
Marten Deinum
2020-08-10 11:44:58 +02:00
committed by Phillip Webb
parent ac357283a6
commit 0e5be0ab62
2 changed files with 27 additions and 1 deletions

View File

@@ -103,7 +103,8 @@ class SpringApplicationRunListeners {
}
private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction) {
doWithListeners(stepName, listenerAction, StartupStep::end);
doWithListeners(stepName, listenerAction, (step) -> {
});
}
private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
@@ -111,6 +112,7 @@ class SpringApplicationRunListeners {
StartupStep step = this.applicationStartup.start(stepName);
this.listeners.forEach(listenerAction);
stepAction.accept(step);
step.end();
}
}

View File

@@ -141,6 +141,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
* @author Madhura Bhave
* @author Brian Clozel
* @author Artsiom Yudovin
* @author Marten Deinum
*/
@ExtendWith(OutputCaptureExtension.class)
class SpringApplicationTests {
@@ -1179,6 +1180,29 @@ class SpringApplicationTests {
assertThat(startCount).isEqualTo(endCount);
}
@Test
void customApplicationStartupPublishStartupStepsWithFailure() {
ApplicationStartup applicationStartup = mock(ApplicationStartup.class);
StartupStep startupStep = mock(StartupStep.class);
given(applicationStartup.start(anyString())).willReturn(startupStep);
given(startupStep.tag(anyString(), anyString())).willReturn(startupStep);
given(startupStep.tag(anyString(), ArgumentMatchers.<Supplier<String>>any())).willReturn(startupStep);
SpringApplication application = new SpringApplication(BrokenPostConstructConfig.class);
application.setWebApplicationType(WebApplicationType.NONE);
application.setApplicationStartup(applicationStartup);
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(application::run);
verify(applicationStartup).start("spring.boot.application.starting");
verify(applicationStartup).start("spring.boot.application.environment-prepared");
verify(applicationStartup).start("spring.boot.application.failed");
long startCount = mockingDetails(applicationStartup).getInvocations().stream()
.filter((invocation) -> invocation.getMethod().toString().contains("start(")).count();
long endCount = mockingDetails(startupStep).getInvocations().stream()
.filter((invocation) -> invocation.getMethod().toString().contains("end(")).count();
assertThat(startCount).isEqualTo(endCount);
}
private <S extends AvailabilityState> ArgumentMatcher<ApplicationEvent> isAvailabilityChangeEventWithState(
S state) {
return (argument) -> (argument instanceof AvailabilityChangeEvent<?>)