Add nullability annotations to tests in module/spring-boot-health

See gh-47263
This commit is contained in:
Moritz Halbritter 2025-09-26 12:40:36 +02:00
parent 0634c11eee
commit 80c384e92c
18 changed files with 93 additions and 28 deletions

View File

@ -37,5 +37,11 @@ dependencies {
testImplementation("io.projectreactor:reactor-test")
testImplementation("tools.jackson.core:jackson-databind")
testCompileOnly("com.google.code.findbugs:jsr305")
testRuntimeOnly("ch.qos.logback:logback-classic")
}
tasks.named("compileTestJava") {
options.nullability.checking = "tests"
}

View File

@ -21,6 +21,7 @@ import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Stream;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@ -41,7 +42,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
*/
abstract class AbstractCompositeHealthContributorConfigurationTests<C, I extends C> {
private final Class<?> indicatorType;
private final @Nullable Class<?> indicatorType;
AbstractCompositeHealthContributorConfigurationTests() {
ResolvableType type = ResolvableType.forClass(AbstractCompositeHealthContributorConfigurationTests.class,

View File

@ -39,11 +39,16 @@ class CompositeReactiveHealthContributorTests {
.fromMap(reactiveContributors);
CompositeHealthContributor adapted = contributor.asHealthContributor();
HealthIndicator byName = (HealthIndicator) adapted.getContributor("test");
assertThat(byName.health(true).getDetails()).containsEntry("spring", "boot");
assertThat(byName).isNotNull();
Health health = byName.health(true);
assertThat(health).isNotNull();
assertThat(health.getDetails()).containsEntry("spring", "boot");
HealthContributors.Entry entry = adapted.iterator().next();
assertThat(entry.name()).isEqualTo("test");
HealthIndicator byEntry = (HealthIndicator) entry.contributor();
assertThat(byEntry.health(true).getDetails()).containsEntry("spring", "boot");
health = byEntry.health(true);
assertThat(health).isNotNull();
assertThat(health.getDetails()).containsEntry("spring", "boot");
}
@Test

View File

@ -42,6 +42,7 @@ class HealthContributorsAdapterTests {
assertThat(adapted.name()).isEqualTo("test");
assertThat(adapted.contributor()).isInstanceOf(ReactiveHealthIndicator.class);
Health health = ((ReactiveHealthIndicator) adapted.contributor()).health(true).block();
assertThat(health).isNotNull();
assertThat(health.getStatus()).isEqualTo(Status.UP);
assertThat(health.getDetails()).containsEntry("spring", "boot");
}
@ -61,7 +62,9 @@ class HealthContributorsAdapterTests {
assertThat(adapted.contributor()).isInstanceOf(CompositeReactiveHealthContributor.class);
ReactiveHealthContributor nested = ((CompositeReactiveHealthContributor) adapted.contributor())
.getContributor("test1");
assertThat(nested).isNotNull();
Health health = ((ReactiveHealthIndicator) nested).health(true).block();
assertThat(health).isNotNull();
assertThat(health.getStatus()).isEqualTo(Status.UP);
assertThat(health.getDetails()).containsEntry("spring", "boot");
}
@ -73,7 +76,9 @@ class HealthContributorsAdapterTests {
.fromMap(Collections.singletonMap("test", indicator));
HealthContributorsAdapter adapter = createAdapter(delegate);
ReactiveHealthContributor adapted = adapter.getContributor("test");
assertThat(adapted).isNotNull();
Health health = ((ReactiveHealthIndicator) adapted).health(true).block();
assertThat(health).isNotNull();
assertThat(health.getStatus()).isEqualTo(Status.UP);
assertThat(health.getDetails()).containsEntry("spring", "boot");
}

View File

@ -18,6 +18,7 @@ package org.springframework.boot.health.contributor;
import java.util.stream.Stream;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Test;
import org.springframework.boot.health.contributor.HealthContributors.Entry;
@ -45,7 +46,7 @@ class HealthContributorsTests {
}
@Override
public HealthContributor getContributor(String name) {
public @Nullable HealthContributor getContributor(String name) {
return null;
}
@ -60,6 +61,7 @@ class HealthContributorsTests {
}
@Test
@SuppressWarnings("NullAway") // Test null check
void createEntryWhenContributorIsNullThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> new Entry("test", null))
.withMessage("'contributor' must not be null");

View File

@ -32,6 +32,7 @@ class HealthIndicatorTests {
@Test
void getHealthWhenIncludeDetailsIsTrueReturnsHealthWithDetails() {
Health health = this.indicator.health(true);
assertThat(health).isNotNull();
assertThat(health.getStatus()).isEqualTo(Status.UP);
assertThat(health.getDetails()).containsEntry("spring", "boot");
}
@ -39,6 +40,7 @@ class HealthIndicatorTests {
@Test
void getHealthWhenIncludeDetailsIsFalseReturnsHealthWithoutDetails() {
Health health = this.indicator.health(false);
assertThat(health).isNotNull();
assertThat(health.getStatus()).isEqualTo(Status.UP);
assertThat(health.getDetails()).isEmpty();
}

View File

@ -38,6 +38,7 @@ import static org.assertj.core.api.Assertions.entry;
class HealthTests {
@Test
@SuppressWarnings("NullAway") // Test null check
void statusMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new Health.Builder(null, null))
.withMessageContaining("'status' must not be null");

View File

@ -20,8 +20,12 @@ import java.util.Map;
import java.util.function.Function;
import java.util.stream.Stream;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.health.contributor.HealthContributors.Entry;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link MapCompositeHealthContributor}.
*
@ -31,8 +35,9 @@ class MapCompositeHealthContributorTests
extends MapCompositeTests<CompositeHealthContributor, HealthContributor, Entry> {
@Override
@SuppressWarnings("NullAway") // Test null check
protected CompositeHealthContributor create(Map<String, String> map,
Function<String, HealthContributor> valueAdapter) {
@Nullable Function<String, HealthContributor> valueAdapter) {
return new MapCompositeHealthContributor<>(map, valueAdapter);
}
@ -42,7 +47,7 @@ class MapCompositeHealthContributorTests
}
@Override
protected HealthContributor getContributor(CompositeHealthContributor composite, String name) {
protected @Nullable HealthContributor getContributor(CompositeHealthContributor composite, String name) {
return composite.getContributor(name);
}
@ -52,8 +57,10 @@ class MapCompositeHealthContributorTests
}
@Override
protected String getData(HealthContributor contributor) {
return (String) ((HealthIndicator) contributor).health().getDetails().get("data");
protected @Nullable String getData(HealthContributor contributor) {
Health health = ((HealthIndicator) contributor).health();
assertThat(health).isNotNull();
return (String) health.getDetails().get("data");
}
@Override

View File

@ -20,10 +20,13 @@ import java.util.Map;
import java.util.function.Function;
import java.util.stream.Stream;
import org.jspecify.annotations.Nullable;
import reactor.core.publisher.Mono;
import org.springframework.boot.health.contributor.ReactiveHealthContributors.Entry;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link MapCompositeReactiveHealthContributor}.
*
@ -33,8 +36,9 @@ class MapCompositeReactiveHealthContributorTests
extends MapCompositeTests<CompositeReactiveHealthContributor, ReactiveHealthContributor, Entry> {
@Override
@SuppressWarnings("NullAway") // Test null check
protected CompositeReactiveHealthContributor create(Map<String, String> map,
Function<String, ReactiveHealthContributor> valueAdapter) {
@Nullable Function<String, ReactiveHealthContributor> valueAdapter) {
return new MapCompositeReactiveHealthContributor<>(map, valueAdapter);
}
@ -44,7 +48,8 @@ class MapCompositeReactiveHealthContributorTests
}
@Override
protected ReactiveHealthContributor getContributor(CompositeReactiveHealthContributor composite, String name) {
protected @Nullable ReactiveHealthContributor getContributor(CompositeReactiveHealthContributor composite,
String name) {
return composite.getContributor(name);
}
@ -54,8 +59,10 @@ class MapCompositeReactiveHealthContributorTests
}
@Override
protected String getData(ReactiveHealthContributor contributor) {
return (String) ((ReactiveHealthIndicator) contributor).health().block().getDetails().get("data");
protected @Nullable String getData(ReactiveHealthContributor contributor) {
Health health = ((ReactiveHealthIndicator) contributor).health().block();
assertThat(health).isNotNull();
return (String) health.getDetails().get("data");
}
@Override

View File

@ -24,6 +24,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Stream;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@ -41,12 +42,14 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
abstract class MapCompositeTests<T, C, E> {
@Test
@SuppressWarnings("NullAway") // Test null check
void createWhenMapIsNullThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> createWithData(null, Function.identity()))
.withMessage("'map' must not be null");
}
@Test
@SuppressWarnings("NullAway") // Test null check
void createWhenValueAdapterIsNullThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> createWithData(Collections.emptyMap(), null))
.withMessage("'valueAdapter' must not be null");
@ -133,19 +136,21 @@ abstract class MapCompositeTests<T, C, E> {
return create(map, (dataAdapter != null) ? (key) -> createContributor(dataAdapter.apply(key)) : null);
}
private String getContributorData(T composite, String name) {
return getData(getContributor(composite, name));
private @Nullable String getContributorData(T composite, String name) {
C contributor = getContributor(composite, name);
assertThat(contributor).isNotNull();
return getData(contributor);
}
protected abstract T create(Map<String, String> map, Function<String, C> valueAdapter);
protected abstract T create(Map<String, String> map, @Nullable Function<String, C> valueAdapter);
protected abstract Stream<E> stream(T composite);
protected abstract C getContributor(T composite, String name);
protected abstract @Nullable C getContributor(T composite, String name);
protected abstract C createContributor(String data);
protected abstract String getData(C contributor);
protected abstract @Nullable String getData(C contributor);
protected abstract String getName(E entry);

View File

@ -35,7 +35,9 @@ class ReactiveHealthContributorTests {
HealthIndicator indicator = () -> Health.outOfService().build();
ReactiveHealthContributor adapted = ReactiveHealthContributor.adapt(indicator);
assertThat(adapted).isInstanceOf(HealthIndicatorAdapter.class);
assertThat(((ReactiveHealthIndicator) adapted).health().block().getStatus()).isEqualTo(Status.OUT_OF_SERVICE);
Health health = ((ReactiveHealthIndicator) adapted).health().block();
assertThat(health).isNotNull();
assertThat(health.getStatus()).isEqualTo(Status.OUT_OF_SERVICE);
}
@Test
@ -46,7 +48,10 @@ class ReactiveHealthContributorTests {
ReactiveHealthContributor adapted = ReactiveHealthContributor.adapt(contributor);
assertThat(adapted).isInstanceOf(CompositeHealthContributorAdapter.class);
ReactiveHealthContributor contained = ((CompositeReactiveHealthContributor) adapted).getContributor("a");
assertThat(((ReactiveHealthIndicator) contained).health().block().getStatus()).isEqualTo(Status.OUT_OF_SERVICE);
assertThat(contained).isNotNull();
Health health = ((ReactiveHealthIndicator) contained).health().block();
assertThat(health).isNotNull();
assertThat(health.getStatus()).isEqualTo(Status.OUT_OF_SERVICE);
}
}

View File

@ -18,6 +18,7 @@ package org.springframework.boot.health.contributor;
import java.util.stream.Stream;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Test;
import org.mockito.Answers;
@ -47,7 +48,7 @@ class ReactiveHealthContributorsTests {
}
@Override
public ReactiveHealthContributor getContributor(String name) {
public @Nullable ReactiveHealthContributor getContributor(String name) {
return null;
}
@ -86,6 +87,7 @@ class ReactiveHealthContributorsTests {
}
@Test
@SuppressWarnings("NullAway") // Test null check
void createEntryWhenContributorIsNullThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> new Entry("test", null))
.withMessage("'contributor' must not be null");

View File

@ -33,8 +33,10 @@ class ReactiveHealthIndicatorAdapterTests {
ReactiveHealthIndicator reactiveHealthIndicator = () -> Mono
.just(Health.up().withDetail("test", "test").build());
ReactiveHealthIndicatorAdapter adapter = new ReactiveHealthIndicatorAdapter(reactiveHealthIndicator);
assertThat(adapter.health().getStatus()).isEqualTo(Status.UP);
assertThat(adapter.health().getDetails()).containsEntry("test", "test");
Health health = adapter.health();
assertThat(health).isNotNull();
assertThat(health.getStatus()).isEqualTo(Status.UP);
assertThat(health.getDetails()).containsEntry("test", "test");
}
@Test
@ -42,8 +44,10 @@ class ReactiveHealthIndicatorAdapterTests {
ReactiveHealthIndicator reactiveHealthIndicator = () -> Mono
.just(Health.up().withDetail("test", "test").build());
ReactiveHealthIndicatorAdapter adapter = new ReactiveHealthIndicatorAdapter(reactiveHealthIndicator);
assertThat(adapter.health(false).getStatus()).isEqualTo(Status.UP);
assertThat(adapter.health(false).getDetails()).isEmpty();
Health health = adapter.health(false);
assertThat(health).isNotNull();
assertThat(health.getStatus()).isEqualTo(Status.UP);
assertThat(health.getDetails()).isEmpty();
}
}

View File

@ -33,12 +33,15 @@ class ReactiveHealthIndicatorTests {
@Test
void asHealthContributor() {
HealthIndicator adapted = this.indicator.asHealthContributor();
assertThat(adapted.health(true).getDetails()).containsEntry("spring", "boot");
Health health = adapted.health(true);
assertThat(health).isNotNull();
assertThat(health.getDetails()).containsEntry("spring", "boot");
}
@Test
void getHealthWhenIncludeDetailsIsTrueReturnsHealthWithDetails() {
Health health = this.indicator.health(true).block();
assertThat(health).isNotNull();
assertThat(health.getStatus()).isEqualTo(Status.UP);
assertThat(health.getDetails()).containsEntry("spring", "boot");
}
@ -46,6 +49,7 @@ class ReactiveHealthIndicatorTests {
@Test
void getHealthWhenIncludeDetailsIsFalseReturnsHealthWithoutDetails() {
Health health = this.indicator.health(false).block();
assertThat(health).isNotNull();
assertThat(health.getStatus()).isEqualTo(Status.UP);
assertThat(health.getDetails()).isEmpty();
}

View File

@ -30,12 +30,14 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
class StatusTests {
@Test
@SuppressWarnings("NullAway") // Test null check
void createWhenCodeIsNullThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> new Status(null, ""))
.withMessage("'code' must not be null");
}
@Test
@SuppressWarnings("NullAway") // Test null check
void createWhenDescriptionIsNullThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> new Status("code", null))
.withMessage("'description' must not be null");

View File

@ -22,6 +22,7 @@ import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -50,6 +51,7 @@ abstract class AbstractHealthContributorRegistryTests<C, E> {
}
@Test
@SuppressWarnings("NullAway") // Test null check
void registerContributorWhenNameIsNullThrowsException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> this.registry.registerContributor(null, mockHealthIndicator()))
@ -57,6 +59,7 @@ abstract class AbstractHealthContributorRegistryTests<C, E> {
}
@Test
@SuppressWarnings("NullAway") // Test null check
void registerContributorWhenContributorIsNullThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> this.registry.registerContributor("one", null))
.withMessage("'contributor' must not be null");
@ -147,7 +150,7 @@ abstract class AbstractHealthContributorRegistryTests<C, E> {
protected abstract AbstractRegistry<C, E> createRegistry(
Collection<? extends HealthContributorNameValidator> nameValidators,
Consumer<BiConsumer<String, C>> initialRegistrations);
@Nullable Consumer<BiConsumer<String, C>> initialRegistrations);
protected abstract C mockHealthIndicator();

View File

@ -20,6 +20,8 @@ import java.util.Collection;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.health.contributor.HealthContributor;
import org.springframework.boot.health.contributor.HealthContributors;
import org.springframework.boot.health.contributor.HealthContributors.Entry;
@ -38,7 +40,7 @@ class DefaultHealthContributorRegistryTests
@Override
protected AbstractRegistry<HealthContributor, Entry> createRegistry(
Collection<? extends HealthContributorNameValidator> nameValidators,
Consumer<BiConsumer<String, HealthContributor>> initialRegistrations) {
@Nullable Consumer<BiConsumer<String, HealthContributor>> initialRegistrations) {
return new DefaultHealthContributorRegistry(nameValidators, initialRegistrations);
}

View File

@ -20,6 +20,8 @@ import java.util.Collection;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.health.contributor.ReactiveHealthContributor;
import org.springframework.boot.health.contributor.ReactiveHealthContributors;
import org.springframework.boot.health.contributor.ReactiveHealthContributors.Entry;
@ -38,7 +40,7 @@ class DefaultReactiveHealthContributorRegistryTests
@Override
protected AbstractRegistry<ReactiveHealthContributor, Entry> createRegistry(
Collection<? extends HealthContributorNameValidator> nameValidators,
Consumer<BiConsumer<String, ReactiveHealthContributor>> initialRegistrations) {
@Nullable Consumer<BiConsumer<String, ReactiveHealthContributor>> initialRegistrations) {
return new DefaultReactiveHealthContributorRegistry(nameValidators, initialRegistrations);
}