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

See gh-47263
This commit is contained in:
Moritz Halbritter
2025-10-02 15:35:04 +02:00
parent b6950f8fb0
commit 419d78b359
15 changed files with 65 additions and 24 deletions
@@ -50,5 +50,11 @@ dependencies {
testImplementation("io.projectreactor:reactor-test")
testImplementation("org.springframework.security:spring-security-test")
testCompileOnly("com.google.code.findbugs:jsr305")
testRuntimeOnly("ch.qos.logback:logback-classic")
}
tasks.named("compileTestJava") {
options.nullability.checking = "tests"
}
@@ -21,6 +21,7 @@ import java.util.Collections;
import java.util.function.Consumer;
import java.util.function.Function;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Test;
import org.springframework.aot.hint.MemberCategory;
@@ -96,8 +97,8 @@ class CloudFoundryWebEndpointDiscovererTests {
load((id) -> null, EndpointId::toString, configuration, consumer);
}
private void load(Function<EndpointId, Long> timeToLive, PathMapper endpointPathMapper, Class<?> configuration,
Consumer<CloudFoundryWebEndpointDiscoverer> consumer) {
private void load(Function<EndpointId, @Nullable Long> timeToLive, PathMapper endpointPathMapper,
Class<?> configuration, Consumer<CloudFoundryWebEndpointDiscoverer> consumer) {
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(configuration)) {
ConversionServiceParameterValueMapper parameterMapper = new ConversionServiceParameterValueMapper(
DefaultConversionService.getSharedInstance());
@@ -147,7 +148,7 @@ class CloudFoundryWebEndpointDiscovererTests {
static class TestEndpoint {
@ReadOperation
Object getAll() {
@Nullable Object getAll() {
return null;
}
@@ -157,7 +158,7 @@ class CloudFoundryWebEndpointDiscovererTests {
static class TestEndpointWebExtension {
@ReadOperation
Object getAll() {
@Nullable Object getAll() {
return null;
}
@@ -167,7 +168,7 @@ class CloudFoundryWebEndpointDiscovererTests {
static class HealthEndpointWebExtension {
@ReadOperation
Object getAll() {
@Nullable Object getAll() {
return null;
}
@@ -28,6 +28,7 @@ import javax.net.ssl.SSLException;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import reactor.netty.http.HttpResources;
@@ -203,7 +204,7 @@ class CloudFoundryReactiveActuatorAutoConfigurationTests {
});
}
private static Boolean getMatches(List<? extends SecurityWebFilterChain> filters, String urlTemplate) {
private static @Nullable Boolean getMatches(List<? extends SecurityWebFilterChain> filters, String urlTemplate) {
return filters.get(0)
.matches(MockServerWebExchange.from(MockServerHttpRequest.get(urlTemplate).build()))
.block(Duration.ofSeconds(30));
@@ -290,6 +291,7 @@ class CloudFoundryReactiveActuatorAutoConfigurationTests {
CloudFoundryInfoEndpointWebExtension extension = context
.getBean(CloudFoundryInfoEndpointWebExtension.class);
Map<String, Object> git = (Map<String, Object>) extension.info().get("git");
assertThat(git).isNotNull();
Map<String, Object> commit = (Map<String, Object>) git.get("commit");
assertThat(commit).hasSize(4);
});
@@ -317,6 +319,7 @@ class CloudFoundryReactiveActuatorAutoConfigurationTests {
.retrieve()
.toBodilessEntity()
.block(Duration.ofSeconds(30));
assertThat(response).isNotNull();
assertThat(response.getStatusCode()).isEqualTo(HttpStatusCode.valueOf(204));
}));
}
@@ -17,6 +17,7 @@
package org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint.reactive;
import java.time.Duration;
import java.util.Map;
import org.junit.jupiter.api.Test;
@@ -25,6 +26,7 @@ import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAu
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
import org.springframework.boot.actuate.endpoint.ApiVersion;
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
import org.springframework.boot.actuate.health.CompositeHealthDescriptor;
import org.springframework.boot.actuate.health.HealthDescriptor;
import org.springframework.boot.actuate.health.IndicatedHealthDescriptor;
@@ -71,12 +73,14 @@ class CloudFoundryReactiveHealthEndpointWebExtensionTests {
this.contextRunner.run((context) -> {
CloudFoundryReactiveHealthEndpointWebExtension extension = context
.getBean(CloudFoundryReactiveHealthEndpointWebExtension.class);
HealthDescriptor descriptor = extension.health(ApiVersion.V3).block(Duration.ofSeconds(30)).getBody();
HealthDescriptor component = ((CompositeHealthDescriptor) descriptor).getComponents()
.entrySet()
.iterator()
.next()
.getValue();
WebEndpointResponse<? extends HealthDescriptor> response = extension.health(ApiVersion.V3)
.block(Duration.ofSeconds(30));
assertThat(response).isNotNull();
HealthDescriptor descriptor = response.getBody();
assertThat(descriptor).isNotNull();
Map<String, HealthDescriptor> components = ((CompositeHealthDescriptor) descriptor).getComponents();
assertThat(components).isNotNull();
HealthDescriptor component = components.entrySet().iterator().next().getValue();
assertThat(((IndicatedHealthDescriptor) component).getDetails()).containsEntry("spring", "boot");
});
}
@@ -48,6 +48,7 @@ import org.springframework.boot.reactor.netty.autoconfigure.NettyReactiveWebServ
import org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;
import org.springframework.boot.test.context.runner.ContextConsumer;
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
import org.springframework.boot.web.server.WebServer;
import org.springframework.boot.web.server.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;
import org.springframework.boot.webflux.autoconfigure.HttpHandlerAutoConfiguration;
import org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;
@@ -61,6 +62,7 @@ import org.springframework.http.MediaType;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.web.cors.CorsConfiguration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
@@ -213,9 +215,10 @@ class CloudFoundryWebFluxEndpointIntegrationTests {
private ContextConsumer<AssertableReactiveWebApplicationContext> withWebTestClient(
Consumer<WebTestClient> clientConsumer) {
return (context) -> {
int port = ((AnnotationConfigReactiveWebServerApplicationContext) context.getSourceApplicationContext())
.getWebServer()
.getPort();
WebServer webServer = ((AnnotationConfigReactiveWebServerApplicationContext) context
.getSourceApplicationContext()).getWebServer();
assertThat(webServer).isNotNull();
int port = webServer.getPort();
clientConsumer.accept(WebTestClient.bindToServer()
.baseUrl("http://localhost:" + port)
.responseTimeout(Duration.ofMinutes(5))
@@ -48,9 +48,11 @@ import static org.mockito.BDDMockito.given;
class SecurityInterceptorTests {
@Mock
@SuppressWarnings("NullAway.Init")
private TokenValidator tokenValidator;
@Mock
@SuppressWarnings("NullAway.Init")
private SecurityService securityService;
private SecurityInterceptor interceptor;
@@ -60,6 +60,7 @@ class TokenValidatorTests {
private static final byte[] DOT = ".".getBytes();
@Mock
@SuppressWarnings("NullAway.Init")
private SecurityService securityService;
private TokenValidator tokenValidator;
@@ -98,9 +98,11 @@ class CloudFoundryActuatorAutoConfigurationTests {
CloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping(context);
EndpointMapping endpointMapping = (EndpointMapping) ReflectionTestUtils.getField(handlerMapping,
"endpointMapping");
assertThat(endpointMapping).isNotNull();
assertThat(endpointMapping.getPath()).isEqualTo("/cloudfoundryapplication");
CorsConfiguration corsConfiguration = (CorsConfiguration) ReflectionTestUtils.getField(handlerMapping,
"corsConfiguration");
assertThat(corsConfiguration).isNotNull();
assertThat(corsConfiguration.getAllowedOrigins()).contains("*");
assertThat(corsConfiguration.getAllowedMethods())
.containsAll(Arrays.asList(HttpMethod.GET.name(), HttpMethod.POST.name()));
@@ -128,6 +130,7 @@ class CloudFoundryActuatorAutoConfigurationTests {
.run((context) -> {
CloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping(context);
Object interceptor = ReflectionTestUtils.getField(handlerMapping, "securityInterceptor");
assertThat(interceptor).isNotNull();
String applicationId = (String) ReflectionTestUtils.getField(interceptor, "applicationId");
assertThat(applicationId).isEqualTo("my-app-id");
});
@@ -141,8 +144,10 @@ class CloudFoundryActuatorAutoConfigurationTests {
.run((context) -> {
CloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping(context);
Object interceptor = ReflectionTestUtils.getField(handlerMapping, "securityInterceptor");
assertThat(interceptor).isNotNull();
Object interceptorSecurityService = ReflectionTestUtils.getField(interceptor,
"cloudFoundrySecurityService");
assertThat(interceptorSecurityService).isNotNull();
String cloudControllerUrl = (String) ReflectionTestUtils.getField(interceptorSecurityService,
"cloudControllerUrl");
assertThat(cloudControllerUrl).isEqualTo("https://my-cloud-controller.com");
@@ -158,10 +163,13 @@ class CloudFoundryActuatorAutoConfigurationTests {
.run((context) -> {
CloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping(context);
Object interceptor = ReflectionTestUtils.getField(handlerMapping, "securityInterceptor");
assertThat(interceptor).isNotNull();
Object interceptorSecurityService = ReflectionTestUtils.getField(interceptor,
"cloudFoundrySecurityService");
assertThat(interceptorSecurityService).isNotNull();
RestTemplate restTemplate = (RestTemplate) ReflectionTestUtils.getField(interceptorSecurityService,
"restTemplate");
assertThat(restTemplate).isNotNull();
assertThat(restTemplate.getRequestFactory()).isInstanceOf(SkipSslVerificationHttpRequestFactory.class);
});
}
@@ -172,6 +180,7 @@ class CloudFoundryActuatorAutoConfigurationTests {
.run((context) -> {
CloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping(context);
Object securityInterceptor = ReflectionTestUtils.getField(handlerMapping, "securityInterceptor");
assertThat(securityInterceptor).isNotNull();
Object interceptorSecurityService = ReflectionTestUtils.getField(securityInterceptor,
"cloudFoundrySecurityService");
assertThat(interceptorSecurityService).isNull();
@@ -214,8 +223,7 @@ class CloudFoundryActuatorAutoConfigurationTests {
private SecurityFilterChain getSecurityFilterChain(AssertableWebApplicationContext context) {
Filter springSecurityFilterChain = context.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN, Filter.class);
FilterChainProxy filterChainProxy = getFilterChainProxy(springSecurityFilterChain);
SecurityFilterChain securityFilterChain = filterChainProxy.getFilterChains().get(0);
return securityFilterChain;
return filterChainProxy.getFilterChains().get(0);
}
private FilterChainProxy getFilterChainProxy(Filter filter) {
@@ -224,6 +232,7 @@ class CloudFoundryActuatorAutoConfigurationTests {
}
if (filter instanceof CompositeFilter) {
List<?> filters = (List<?>) ReflectionTestUtils.getField(filter, "filters");
assertThat(filters).isNotNull();
return (FilterChainProxy) filters.stream()
.filter(FilterChainProxy.class::isInstance)
.findFirst()
@@ -16,6 +16,8 @@
package org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint.servlet;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
@@ -68,11 +70,10 @@ class CloudFoundryHealthEndpointWebExtensionTests {
CloudFoundryHealthEndpointWebExtension extension = context
.getBean(CloudFoundryHealthEndpointWebExtension.class);
HealthDescriptor descriptor = extension.health(ApiVersion.V3).getBody();
HealthDescriptor component = ((CompositeHealthDescriptor) descriptor).getComponents()
.entrySet()
.iterator()
.next()
.getValue();
assertThat(descriptor).isNotNull();
Map<String, HealthDescriptor> components = ((CompositeHealthDescriptor) descriptor).getComponents();
assertThat(components).isNotNull();
HealthDescriptor component = components.entrySet().iterator().next().getValue();
assertThat(((IndicatedHealthDescriptor) component).getDetails()).containsEntry("spring", "boot");
});
}
@@ -81,6 +81,7 @@ class CloudFoundryInfoEndpointWebExtensionTests {
CloudFoundryInfoEndpointWebExtension extension = context
.getBean(CloudFoundryInfoEndpointWebExtension.class);
Map<String, Object> git = (Map<String, Object>) extension.info().get("git");
assertThat(git).isNotNull();
Map<String, Object> commit = (Map<String, Object>) git.get("commit");
assertThat(commit).hasSize(4);
});
@@ -45,6 +45,7 @@ import org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint.Clou
import org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint.CloudFoundryAuthorizationException.Reason;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServer;
import org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
@@ -58,6 +59,7 @@ import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
@@ -213,7 +215,9 @@ class CloudFoundryMvcWebEndpointIntegrationTests {
}
private int getPort(AnnotationConfigServletWebServerApplicationContext context) {
return context.getWebServer().getPort();
WebServer webServer = context.getWebServer();
assertThat(webServer).isNotNull();
return webServer.getPort();
}
private String mockAccessToken() {
@@ -46,9 +46,11 @@ import static org.mockito.BDDMockito.then;
class SecurityInterceptorTests {
@Mock
@SuppressWarnings("NullAway.Init")
private TokenValidator tokenValidator;
@Mock
@SuppressWarnings("NullAway.Init")
private SecurityService securityService;
private SecurityInterceptor interceptor;
@@ -72,6 +72,7 @@ class SecurityServiceTests {
RestTemplateBuilder builder = new RestTemplateBuilder();
this.securityService = new SecurityService(builder, CLOUD_CONTROLLER, true);
RestTemplate restTemplate = (RestTemplate) ReflectionTestUtils.getField(this.securityService, "restTemplate");
assertThat(restTemplate).isNotNull();
assertThat(restTemplate.getRequestFactory()).isInstanceOf(SkipSslVerificationHttpRequestFactory.class);
}
@@ -80,6 +81,7 @@ class SecurityServiceTests {
RestTemplateBuilder builder = new RestTemplateBuilder();
this.securityService = new SecurityService(builder, CLOUD_CONTROLLER, false);
RestTemplate restTemplate = (RestTemplate) ReflectionTestUtils.getField(this.securityService, "restTemplate");
assertThat(restTemplate).isNotNull();
assertThat(restTemplate.getRequestFactory()).isNotInstanceOf(SkipSslVerificationHttpRequestFactory.class);
}
@@ -18,6 +18,7 @@ package org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint.ser
import javax.net.ssl.SSLHandshakeException;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
@@ -40,7 +41,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
*/
class SkipSslVerificationHttpRequestFactoryTests {
private WebServer webServer;
private @Nullable WebServer webServer;
@AfterEach
void shutdownContainer() {
@@ -59,6 +59,7 @@ class TokenValidatorTests {
private static final byte[] DOT = ".".getBytes();
@Mock
@SuppressWarnings("NullAway.Init")
private SecurityService securityService;
private TokenValidator tokenValidator;