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

See gh-47263
This commit is contained in:
Moritz Halbritter
2025-10-06 12:03:54 +02:00
parent 58e2f9c872
commit e878db0abf
38 changed files with 213 additions and 64 deletions
@@ -25,6 +25,7 @@ import java.util.function.Supplier;
import javax.sql.DataSource;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
@@ -35,6 +36,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.mockito.BDDMockito.willReturn;
@@ -99,18 +101,21 @@ abstract class AbstractDevToolsDataSourceAutoConfigurationTests {
});
thread.start();
thread.join();
return atomicReference.get();
ConfigurableApplicationContext context = atomicReference.get();
assertThat(context).isNotNull();
return context;
}
protected final ConfigurableApplicationContext createContext(Class<?>... classes) {
return createContext(null, classes);
}
protected final ConfigurableApplicationContext createContext(String driverClassName, Class<?>... classes) {
protected final ConfigurableApplicationContext createContext(@Nullable String driverClassName,
Class<?>... classes) {
return createContext(driverClassName, null, classes);
}
protected final ConfigurableApplicationContext createContext(String driverClassName, String url,
protected final ConfigurableApplicationContext createContext(@Nullable String driverClassName, @Nullable String url,
Class<?>... classes) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(classes);
@@ -24,6 +24,7 @@ import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
import io.r2dbc.spi.ConnectionFactory;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@@ -125,14 +126,16 @@ class DevToolsR2dbcAutoConfigurationTests {
});
thread.start();
thread.join();
return atomicReference.get();
ConfigurableApplicationContext context = atomicReference.get();
assertThat(context).isNotNull();
return context;
}
protected final ConfigurableApplicationContext createContext(Class<?>... classes) {
return createContext(null, classes);
}
protected final ConfigurableApplicationContext createContext(String url, Class<?>... classes) {
protected final ConfigurableApplicationContext createContext(@Nullable String url, Class<?>... classes) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
if (!ObjectUtils.isEmpty(classes)) {
context.register(classes);
@@ -26,6 +26,7 @@ import java.util.function.Supplier;
import org.apache.catalina.Container;
import org.apache.catalina.core.StandardWrapper;
import org.apache.jasper.EmbeddedServletOptions;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -74,7 +75,7 @@ import static org.mockito.Mockito.reset;
@ExtendWith(MockRestarter.class)
class LocalDevToolsAutoConfigurationTests {
private ConfigurableApplicationContext context;
private @Nullable ConfigurableApplicationContext context;
@AfterEach
void cleanup() {
@@ -152,8 +153,10 @@ class LocalDevToolsAutoConfigurationTests {
Map<String, Object> properties = new HashMap<>();
properties.put("spring.devtools.livereload.enabled", false);
this.context = getContext(() -> initializeAndRun(Config.class, properties));
assertThatExceptionOfType(NoSuchBeanDefinitionException.class)
.isThrownBy(() -> this.context.getBean(OptionalLiveReloadServer.class));
assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> {
assertThat(this.context).isNotNull();
this.context.getBean(OptionalLiveReloadServer.class);
});
}
@Test
@@ -184,8 +187,10 @@ class LocalDevToolsAutoConfigurationTests {
Map<String, Object> properties = new HashMap<>();
properties.put("spring.devtools.restart.enabled", false);
this.context = getContext(() -> initializeAndRun(Config.class, properties));
assertThatExceptionOfType(NoSuchBeanDefinitionException.class)
.isThrownBy(() -> this.context.getBean(ClassPathFileSystemWatcher.class));
assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> {
assertThat(this.context).isNotNull();
this.context.getBean(ClassPathFileSystemWatcher.class);
});
}
@Test
@@ -195,7 +200,9 @@ class LocalDevToolsAutoConfigurationTests {
this.context = getContext(() -> initializeAndRun(Config.class, properties));
ClassPathFileSystemWatcher classPathWatcher = this.context.getBean(ClassPathFileSystemWatcher.class);
Object watcher = ReflectionTestUtils.getField(classPathWatcher, "fileSystemWatcher");
assertThat(watcher).isNotNull();
Object filter = ReflectionTestUtils.getField(watcher, "triggerFilter");
assertThat(filter).isNotNull();
assertThat(filter).isInstanceOf(TriggerFileFilter.class);
}
@@ -206,6 +213,7 @@ class LocalDevToolsAutoConfigurationTests {
this.context = getContext(() -> initializeAndRun(Config.class, properties));
ClassPathFileSystemWatcher classPathWatcher = this.context.getBean(ClassPathFileSystemWatcher.class);
Object watcher = ReflectionTestUtils.getField(classPathWatcher, "fileSystemWatcher");
assertThat(watcher).isNotNull();
@SuppressWarnings("unchecked")
Map<File, Object> directories = (Map<File, Object>) ReflectionTestUtils.getField(watcher, "directories");
assertThat(directories).hasSize(2)
@@ -218,10 +226,12 @@ class LocalDevToolsAutoConfigurationTests {
this.context = getContext(() -> initializeAndRun(Config.class));
TomcatWebServer tomcatContainer = (TomcatWebServer) ((ServletWebServerApplicationContext) this.context)
.getWebServer();
assertThat(tomcatContainer).isNotNull();
Container context = tomcatContainer.getTomcat().getHost().findChildren()[0];
StandardWrapper jspServletWrapper = (StandardWrapper) context.findChild("jsp");
EmbeddedServletOptions options = (EmbeddedServletOptions) ReflectionTestUtils
.getField(jspServletWrapper.getServlet(), "options");
assertThat(options).isNotNull();
assertThat(options.getDevelopment()).isTrue();
}
@@ -234,7 +244,9 @@ class LocalDevToolsAutoConfigurationTests {
});
thread.start();
thread.join();
return atomicReference.get();
ConfigurableApplicationContext context = atomicReference.get();
assertThat(context).isNotNull();
return context;
}
private ConfigurableApplicationContext initializeAndRun(Class<?> config, String... args) {
@@ -20,6 +20,7 @@ import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
import jakarta.servlet.Filter;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -65,7 +66,7 @@ class RemoteDevToolsAutoConfigurationTests {
private static final String DEFAULT_SECRET_HEADER_NAME = RemoteDevToolsProperties.DEFAULT_SECRET_HEADER_NAME;
private AnnotationConfigServletWebApplicationContext context;
private @Nullable AnnotationConfigServletWebApplicationContext context;
private MockHttpServletRequest request;
@@ -90,8 +91,10 @@ class RemoteDevToolsAutoConfigurationTests {
@Test
void disabledIfRemoteSecretIsMissing() throws Exception {
this.context = getContext(() -> loadContext("a:b"));
assertThatExceptionOfType(NoSuchBeanDefinitionException.class)
.isThrownBy(() -> this.context.getBean(DispatcherFilter.class));
assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> {
assertThat(this.context).isNotNull();
this.context.getBean(DispatcherFilter.class);
});
}
@Test
@@ -182,8 +185,10 @@ class RemoteDevToolsAutoConfigurationTests {
void disableRestart() throws Exception {
this.context = getContext(() -> loadContext("spring.devtools.remote.secret:supersecret",
"spring.devtools.remote.restart.enabled:false"));
assertThatExceptionOfType(NoSuchBeanDefinitionException.class)
.isThrownBy(() -> this.context.getBean("remoteRestartHandlerMapper"));
assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> {
assertThat(this.context).isNotNull();
this.context.getBean("remoteRestartHandlerMapper");
});
}
@Test
@@ -218,10 +223,13 @@ class RemoteDevToolsAutoConfigurationTests {
});
thread.start();
thread.join();
return atomicReference.get();
AnnotationConfigServletWebApplicationContext context = atomicReference.get();
assertThat(context).isNotNull();
return context;
}
private void assertRestartInvoked(boolean value) {
assertThat(this.context).isNotNull();
assertThat(this.context.getBean(MockHttpRestartServer.class).invoked).isEqualTo(value);
}
@@ -32,9 +32,11 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
class TriggerFileFilterTests {
@TempDir
@SuppressWarnings("NullAway.Init")
File tempDir;
@Test
@SuppressWarnings("NullAway") // Test null check
void nameMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new TriggerFileFilter(null))
.withMessageContaining("'name' must not be null");
@@ -36,6 +36,7 @@ class ClassPathChangedEventTests {
private final Object source = new Object();
@Test
@SuppressWarnings("NullAway") // Test null check
void changeSetMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new ClassPathChangedEvent(this.source, null, false))
.withMessageContaining("'changeSet' must not be null");
@@ -47,15 +47,19 @@ import static org.mockito.Mockito.never;
class ClassPathFileChangeListenerTests {
@Mock
@SuppressWarnings("NullAway.Init")
private ApplicationEventPublisher eventPublisher;
@Mock
@SuppressWarnings("NullAway.Init")
private ClassPathRestartStrategy restartStrategy;
@Mock
@SuppressWarnings("NullAway.Init")
private FileSystemWatcher fileSystemWatcher;
@Test
@SuppressWarnings("NullAway") // Test null check
void eventPublisherMustNotBeNull() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new ClassPathFileChangeListener(null, this.restartStrategy, this.fileSystemWatcher))
@@ -63,6 +67,7 @@ class ClassPathFileChangeListenerTests {
}
@Test
@SuppressWarnings("NullAway") // Test null check
void restartStrategyMustNotBeNull() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new ClassPathFileChangeListener(this.eventPublisher, null, this.fileSystemWatcher))
@@ -51,6 +51,7 @@ import static org.mockito.Mockito.mock;
class ClassPathFileSystemWatcherTests {
@Test
@SuppressWarnings("NullAway") // Test null check
void urlsMustNotBeNull() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new ClassPathFileSystemWatcher(mock(FileSystemWatcherFactory.class),
@@ -100,6 +101,7 @@ class ClassPathFileSystemWatcherTests {
ClassPathFileSystemWatcher watcher(ClassPathRestartStrategy restartStrategy) {
FileSystemWatcher watcher = new FileSystemWatcher(false, Duration.ofMillis(100), Duration.ofMillis(10));
URL[] urls = this.environment.getProperty("urls", URL[].class);
assertThat(urls).isNotNull();
return new ClassPathFileSystemWatcher(new MockFileSystemWatcherFactory(watcher), restartStrategy, urls);
}
@@ -18,6 +18,7 @@ package org.springframework.boot.devtools.classpath;
import java.io.File;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Test;
import org.springframework.boot.devtools.filewatch.ChangedFile;
@@ -82,7 +83,7 @@ class PatternClassPathRestartStrategyTests {
assertRestartRequired(strategy, "com/example/Example.class", true);
}
private ClassPathRestartStrategy createStrategy(String pattern) {
private ClassPathRestartStrategy createStrategy(@Nullable String pattern) {
return new PatternClassPathRestartStrategy(pattern);
}
@@ -22,6 +22,7 @@ import java.util.Locale;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -48,7 +49,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
*/
class DevToolPropertiesIntegrationTests {
private ConfigurableApplicationContext context;
private @Nullable ConfigurableApplicationContext context;
@BeforeEach
void setup() {
@@ -86,8 +87,10 @@ class DevToolPropertiesIntegrationTests {
SpringApplication application = new SpringApplication(BeanConditionConfiguration.class);
application.setWebApplicationType(WebApplicationType.NONE);
this.context = getContext(application::run);
assertThatExceptionOfType(NoSuchBeanDefinitionException.class)
.isThrownBy(() -> this.context.getBean(MyBean.class));
assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> {
assertThat(this.context).isNotNull();
this.context.getBean(MyBean.class);
});
}
@Test
@@ -124,7 +127,9 @@ class DevToolPropertiesIntegrationTests {
});
thread.start();
thread.join();
return atomicReference.get();
ConfigurableApplicationContext context = atomicReference.get();
assertThat(context).isNotNull();
return context;
}
@Configuration(proxyBeanMethods = false)
@@ -25,10 +25,12 @@ import java.util.Collections;
import java.util.Map;
import java.util.Properties;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.springframework.boot.SpringApplication;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.mock.env.MockEnvironment;
@@ -201,8 +203,8 @@ class DevToolsHomePropertiesPostProcessorTests {
return getPostProcessedEnvironment(env, null);
}
private ConfigurableEnvironment getPostProcessedEnvironment(Map<String, String> env, Properties systemProperties)
throws Exception {
private ConfigurableEnvironment getPostProcessedEnvironment(@Nullable Map<String, String> env,
@Nullable Properties systemProperties) throws Exception {
if (systemProperties == null) {
systemProperties = new Properties();
systemProperties.setProperty("user.home", this.home.getAbsolutePath());
@@ -210,7 +212,7 @@ class DevToolsHomePropertiesPostProcessorTests {
ConfigurableEnvironment environment = new MockEnvironment();
DevToolsHomePropertiesPostProcessor postProcessor = new DevToolsHomePropertiesPostProcessor(
(env != null) ? env : Collections.emptyMap(), systemProperties);
runPostProcessor(() -> postProcessor.postProcessEnvironment(environment, null));
runPostProcessor(() -> postProcessor.postProcessEnvironment(environment, new SpringApplication()));
return environment;
}
@@ -34,9 +34,11 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
class ChangedFileTests {
@TempDir
@SuppressWarnings("NullAway.Init")
File tempDir;
@Test
@SuppressWarnings("NullAway") // Test null check
void sourceDirectoryMustNotBeNull() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new ChangedFile(null, new File(this.tempDir, "file"), Type.ADD))
@@ -44,6 +46,7 @@ class ChangedFileTests {
}
@Test
@SuppressWarnings("NullAway") // Test null check
void fileMustNotBeNull() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new ChangedFile(new File(this.tempDir, "directory"), null, Type.ADD))
@@ -51,6 +54,7 @@ class ChangedFileTests {
}
@Test
@SuppressWarnings("NullAway") // Test null check
void typeMustNotBeNull() {
assertThatIllegalArgumentException()
.isThrownBy(
@@ -38,6 +38,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
class DirectorySnapshotTests {
@TempDir
@SuppressWarnings("NullAway.Init")
File tempDir;
private File directory;
@@ -51,6 +52,7 @@ class DirectorySnapshotTests {
}
@Test
@SuppressWarnings("NullAway") // Test null check
void directoryMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new DirectorySnapshot(null))
.withMessageContaining("'directory' must not be null");
@@ -101,6 +103,7 @@ class DirectorySnapshotTests {
}
@Test
@SuppressWarnings("NullAway") // Test null check
void getChangedFilesSnapshotMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> this.initialSnapshot.getChangedFiles(null, null))
.withMessageContaining("'snapshot' must not be null");
@@ -142,7 +145,7 @@ class DirectorySnapshotTests {
return changedFile;
}
}
return null;
throw new AssertionError("File '%s' not found".formatted(file));
}
private File createTestDirectoryStructure() throws IOException {
@@ -42,9 +42,11 @@ class FileSnapshotTests {
private static final long MODIFIED = new Date().getTime() - TimeUnit.DAYS.toMillis(10);
@TempDir
@SuppressWarnings("NullAway.Init")
File tempDir;
@Test
@SuppressWarnings("NullAway") // Test null check
void fileMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new FileSnapshot(null))
.withMessageContaining("'file' must not be null");
@@ -28,6 +28,7 @@ import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
@@ -53,11 +54,12 @@ class FileSystemWatcherTests {
private final List<Set<ChangedFiles>> changes = Collections.synchronizedList(new ArrayList<>());
@TempDir
@SuppressWarnings("NullAway.Init")
File tempDir;
@BeforeEach
void setup() {
setupWatcher(20, 10);
this.watcher = setupWatcher(20, 10);
}
@Test
@@ -82,6 +84,7 @@ class FileSystemWatcherTests {
}
@Test
@SuppressWarnings("NullAway") // Test null check
void listenerMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> this.watcher.addListener(null))
.withMessageContaining("'fileChangeListener' must not be null");
@@ -95,6 +98,7 @@ class FileSystemWatcherTests {
}
@Test
@SuppressWarnings("NullAway") // Test null check
void sourceDirectoryMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> this.watcher.addSourceDirectory(null))
.withMessageContaining("'directory' must not be null");
@@ -149,7 +153,7 @@ class FileSystemWatcherTests {
@Test
void waitsForPollingInterval() throws Exception {
setupWatcher(10, 1);
this.watcher = setupWatcher(10, 1);
File directory = startWithNewDirectory();
touch(new File(directory, "test1.txt"));
while (this.changes.size() != 1) {
@@ -162,7 +166,7 @@ class FileSystemWatcherTests {
@Test
void waitsForQuietPeriod() throws Exception {
setupWatcher(300, 200);
this.watcher = setupWatcher(300, 200);
File directory = startWithNewDirectory();
for (int i = 0; i < 100; i++) {
touch(new File(directory, i + "test.txt"));
@@ -270,7 +274,7 @@ class FileSystemWatcherTests {
@Test
void withSnapshotRepository() throws Exception {
SnapshotStateRepository repository = new TestSnapshotStateRepository();
setupWatcher(20, 10, repository);
this.watcher = setupWatcher(20, 10, repository);
File directory = new File(this.tempDir, UUID.randomUUID().toString());
directory.mkdir();
File file = touch(new File(directory, "file.txt"));
@@ -280,7 +284,7 @@ class FileSystemWatcherTests {
this.watcher.stopAfter(1);
this.changes.clear();
File recreate = touch(new File(directory, "file.txt"));
setupWatcher(20, 10, repository);
this.watcher = setupWatcher(20, 10, repository);
this.watcher.addSourceDirectory(directory);
this.watcher.start();
this.watcher.stopAfter(1);
@@ -290,14 +294,16 @@ class FileSystemWatcherTests {
assertThat(actual).isEqualTo(expected);
}
private void setupWatcher(long pollingInterval, long quietPeriod) {
setupWatcher(pollingInterval, quietPeriod, null);
private FileSystemWatcher setupWatcher(long pollingInterval, long quietPeriod) {
return setupWatcher(pollingInterval, quietPeriod, null);
}
private void setupWatcher(long pollingInterval, long quietPeriod, SnapshotStateRepository snapshotStateRepository) {
this.watcher = new FileSystemWatcher(false, Duration.ofMillis(pollingInterval), Duration.ofMillis(quietPeriod),
snapshotStateRepository);
this.watcher.addListener(FileSystemWatcherTests.this.changes::add);
private FileSystemWatcher setupWatcher(long pollingInterval, long quietPeriod,
@Nullable SnapshotStateRepository snapshotStateRepository) {
FileSystemWatcher watcher = new FileSystemWatcher(false, Duration.ofMillis(pollingInterval),
Duration.ofMillis(quietPeriod), snapshotStateRepository);
watcher.addListener(FileSystemWatcherTests.this.changes::add);
return watcher;
}
private File startWithNewDirectory() {
@@ -328,7 +334,7 @@ class FileSystemWatcherTests {
private static final class TestSnapshotStateRepository implements SnapshotStateRepository {
private Object state;
private @Nullable Object state;
@Override
public void save(Object state) {
@@ -336,7 +342,7 @@ class FileSystemWatcherTests {
}
@Override
public Object restore() {
public @Nullable Object restore() {
return this.state;
}
@@ -34,12 +34,14 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
class FrameTests {
@Test
@SuppressWarnings("NullAway") // Test null check
void payloadMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new Frame((String) null))
.withMessageContaining("'payload' must not be null");
}
@Test
@SuppressWarnings("NullAway") // Test null check
void typeMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new Frame((Frame.Type) null))
.withMessageContaining("'type' must not be null");
@@ -47,11 +47,13 @@ import jakarta.websocket.HandshakeResponse;
import jakarta.websocket.WebSocketContainer;
import org.apache.tomcat.websocket.WsWebSocketContainer;
import org.awaitility.Awaitility;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.http.HttpHeaders;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.socket.CloseStatus;
@@ -223,7 +225,7 @@ class LiveReloadServerTests {
class LiveReloadWebSocketHandler extends TextWebSocketHandler {
private volatile WebSocketSession session;
private volatile @Nullable WebSocketSession session;
private final CountDownLatch helloLatch = new CountDownLatch(2);
@@ -231,7 +233,7 @@ class LiveReloadServerTests {
private final AtomicInteger pongCount = new AtomicInteger();
private volatile CloseStatus closeStatus;
private volatile @Nullable CloseStatus closeStatus;
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
@@ -264,11 +266,15 @@ class LiveReloadServerTests {
}
void sendMessage(WebSocketMessage<?> message) throws IOException {
this.session.sendMessage(message);
WebSocketSession session = this.session;
assertThat(session).isNotNull();
session.sendMessage(message);
}
void close() throws IOException {
this.session.close();
WebSocketSession session = this.session;
assertThat(session).isNotNull();
session.close();
}
List<String> getMessages() {
@@ -279,7 +285,7 @@ class LiveReloadServerTests {
return this.pongCount.get();
}
CloseStatus getCloseStatus() {
@Nullable CloseStatus getCloseStatus() {
return this.closeStatus;
}
@@ -314,7 +320,9 @@ class LiveReloadServerTests {
this.webSocketContainer.connectToServer(endpoint, endpointConfig, uri);
return session;
};
return getTaskExecutor().submitCompletable(connectTask);
AsyncTaskExecutor taskExecutor = getTaskExecutor();
assertThat(taskExecutor).isNotNull();
return taskExecutor.submitCompletable(connectTask);
}
private InetAddress getLocalHost() {
@@ -26,6 +26,7 @@ import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
@@ -65,6 +66,7 @@ class ClassPathChangeUploaderTests {
}
@Test
@SuppressWarnings("NullAway") // Test null check
void urlMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new ClassPathChangeUploader(null, this.requestFactory))
.withMessageContaining("'url' must not be empty");
@@ -77,6 +79,7 @@ class ClassPathChangeUploaderTests {
}
@Test
@SuppressWarnings("NullAway") // Test null check
void requestFactoryMustNotBeNull() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new ClassPathChangeUploader("http://localhost:8080", null))
@@ -124,7 +127,7 @@ class ClassPathChangeUploaderTests {
assertThat(classFiles.hasNext()).isFalse();
}
private void assertClassFile(ClassLoaderFile file, String content, Kind kind) {
private void assertClassFile(ClassLoaderFile file, @Nullable String content, Kind kind) {
assertThat(file.getContents()).isEqualTo((content != null) ? content.getBytes() : null);
assertThat(file.getKind()).isEqualTo(kind);
}
@@ -49,21 +49,27 @@ class DelayedLiveReloadTriggerTests {
private static final String URL = "http://localhost:8080";
@Mock
@SuppressWarnings("NullAway.Init")
private OptionalLiveReloadServer liveReloadServer;
@Mock
@SuppressWarnings("NullAway.Init")
private ClientHttpRequestFactory requestFactory;
@Mock
@SuppressWarnings("NullAway.Init")
private ClientHttpRequest errorRequest;
@Mock
@SuppressWarnings("NullAway.Init")
private ClientHttpRequest okRequest;
@Mock
@SuppressWarnings("NullAway.Init")
private ClientHttpResponse errorResponse;
@Mock
@SuppressWarnings("NullAway.Init")
private ClientHttpResponse okResponse;
private DelayedLiveReloadTrigger trigger;
@@ -74,6 +80,7 @@ class DelayedLiveReloadTriggerTests {
}
@Test
@SuppressWarnings("NullAway") // Test null check
void liveReloadServerMustNotBeNull() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new DelayedLiveReloadTrigger(null, this.requestFactory, URL))
@@ -81,6 +88,7 @@ class DelayedLiveReloadTriggerTests {
}
@Test
@SuppressWarnings("NullAway") // Test null check
void requestFactoryMustNotBeNull() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new DelayedLiveReloadTrigger(this.liveReloadServer, null, URL))
@@ -88,6 +96,7 @@ class DelayedLiveReloadTriggerTests {
}
@Test
@SuppressWarnings("NullAway") // Test null check
void urlMustNotBeNull() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new DelayedLiveReloadTrigger(this.liveReloadServer, this.requestFactory, null))
@@ -54,9 +54,11 @@ class HttpHeaderInterceptorTests {
private byte[] body;
@Mock
@SuppressWarnings("NullAway.Init")
private ClientHttpRequestExecution execution;
@Mock
@SuppressWarnings("NullAway.Init")
private ClientHttpResponse response;
private MockHttpServletRequest httpRequest;
@@ -72,6 +74,7 @@ class HttpHeaderInterceptorTests {
}
@Test
@SuppressWarnings("NullAway") // Test null check
void constructorNullHeaderName() {
assertThatIllegalArgumentException().isThrownBy(() -> new HttpHeaderInterceptor(null, this.value))
.withMessageContaining("'name' must not be empty");
@@ -84,6 +87,7 @@ class HttpHeaderInterceptorTests {
}
@Test
@SuppressWarnings("NullAway") // Test null check
void constructorNullHeaderValue() {
assertThatIllegalArgumentException().isThrownBy(() -> new HttpHeaderInterceptor(this.name, null))
.withMessageContaining("'value' must not be empty");
@@ -22,6 +22,7 @@ import java.util.HashSet;
import java.util.Set;
import org.awaitility.Awaitility;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -41,6 +42,7 @@ import org.springframework.boot.test.system.CapturedOutput;
import org.springframework.boot.test.system.OutputCaptureExtension;
import org.springframework.boot.test.util.TestPropertyValues;
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.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
@@ -63,9 +65,9 @@ import static org.mockito.Mockito.mock;
@ExtendWith({ OutputCaptureExtension.class, MockRestarter.class })
class RemoteClientConfigurationTests {
private AnnotationConfigServletWebServerApplicationContext context;
private @Nullable AnnotationConfigServletWebServerApplicationContext context;
private AnnotationConfigApplicationContext clientContext;
private @Nullable AnnotationConfigApplicationContext clientContext;
@AfterEach
void cleanup() {
@@ -106,6 +108,7 @@ class RemoteClientConfigurationTests {
configure();
Set<ChangedFiles> changeSet = new HashSet<>();
ClassPathChangedEvent event = new ClassPathChangedEvent(this, changeSet, false);
assertThat(this.clientContext).isNotNull();
this.clientContext.publishEvent(event);
LiveReloadServer server = this.clientContext.getBean(LiveReloadServer.class);
Awaitility.await().atMost(Duration.ofMinutes(1)).untilAsserted(() -> then(server).should().triggerReload());
@@ -115,20 +118,26 @@ class RemoteClientConfigurationTests {
void liveReloadDisabled() {
configure("spring.devtools.livereload.enabled:false");
assertThatExceptionOfType(NoSuchBeanDefinitionException.class)
.isThrownBy(() -> this.context.getBean(OptionalLiveReloadServer.class));
.isThrownBy(() -> getContext().getBean(OptionalLiveReloadServer.class));
}
@Test
void remoteRestartDisabled() {
configure("spring.devtools.remote.restart.enabled:false");
assertThatExceptionOfType(NoSuchBeanDefinitionException.class)
.isThrownBy(() -> this.context.getBean(ClassPathFileSystemWatcher.class));
.isThrownBy(() -> getContext().getBean(ClassPathFileSystemWatcher.class));
}
private void configure(String... pairs) {
configure("http://localhost", true, pairs);
}
private AnnotationConfigServletWebServerApplicationContext getContext() {
AnnotationConfigServletWebServerApplicationContext context = this.context;
assertThat(context).isNotNull();
return context;
}
private void configure(String remoteUrl, boolean setSecret, String... pairs) {
this.context = new AnnotationConfigServletWebServerApplicationContext();
this.context.register(Config.class);
@@ -143,7 +152,9 @@ class RemoteClientConfigurationTests {
if (setSecret) {
TestPropertyValues.of("spring.devtools.remote.secret:secret").applyTo(this.clientContext);
}
String remoteUrlProperty = "remoteUrl:" + remoteUrl + ":" + this.context.getWebServer().getPort();
WebServer webServer = this.context.getWebServer();
assertThat(webServer).isNotNull();
String remoteUrlProperty = "remoteUrl:" + remoteUrl + ":" + webServer.getPort();
TestPropertyValues.of(remoteUrlProperty).applyTo(this.clientContext);
this.clientContext.refresh();
}
@@ -51,9 +51,11 @@ import static org.mockito.Mockito.mock;
class DispatcherFilterTests {
@Mock
@SuppressWarnings("NullAway.Init")
private Dispatcher dispatcher;
@Mock
@SuppressWarnings("NullAway.Init")
private FilterChain chain;
private DispatcherFilter filter;
@@ -64,6 +66,7 @@ class DispatcherFilterTests {
}
@Test
@SuppressWarnings("NullAway") // Test null check
void dispatcherMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new DispatcherFilter(null))
.withMessageContaining("'dispatcher' must not be null");
@@ -52,6 +52,7 @@ import static org.mockito.Mockito.withSettings;
class DispatcherTests {
@Mock
@SuppressWarnings("NullAway.Init")
private AccessManager accessManager;
private final MockHttpServletResponse response = new MockHttpServletResponse();
@@ -61,12 +62,14 @@ class DispatcherTests {
private final ServerHttpResponse serverResponse = new ServletServerHttpResponse(this.response);
@Test
@SuppressWarnings("NullAway") // Test null check
void accessManagerMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new Dispatcher(null, Collections.emptyList()))
.withMessageContaining("'accessManager' must not be null");
}
@Test
@SuppressWarnings("NullAway") // Test null check
void mappersMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new Dispatcher(this.accessManager, null))
.withMessageContaining("'mappers' must not be null");
@@ -52,6 +52,7 @@ class HttpHeaderAccessManagerTests {
}
@Test
@SuppressWarnings("NullAway") // Test null check
void headerNameMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new HttpHeaderAccessManager(null, SECRET))
.withMessageContaining("'headerName' must not be empty");
@@ -64,6 +65,7 @@ class HttpHeaderAccessManagerTests {
}
@Test
@SuppressWarnings("NullAway") // Test null check
void expectedSecretMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new HttpHeaderAccessManager(HEADER, null))
.withMessageContaining("'expectedSecret' must not be empty");
@@ -54,6 +54,7 @@ class HttpStatusHandlerTests {
}
@Test
@SuppressWarnings("NullAway") // Test null check
void statusMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new HttpStatusHandler(null))
.withMessageContaining("'status' must not be null");
@@ -38,6 +38,7 @@ class UrlHandlerMapperTests {
private final Handler handler = mock(Handler.class);
@Test
@SuppressWarnings("NullAway") // Test null check
void requestUriMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new UrlHandlerMapper(null, this.handler))
.withMessageContaining("'url' must not be empty");
@@ -43,6 +43,7 @@ import static org.assertj.core.api.Assertions.assertThat;
class ChangeableUrlsTests {
@TempDir
@SuppressWarnings("NullAway.Init")
File tempDir;
@Test
@@ -18,6 +18,7 @@ package org.springframework.boot.devtools.restart;
import java.lang.reflect.Method;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -45,6 +46,7 @@ class MainMethodTests {
}
@Test
@SuppressWarnings("NullAway") // Test null check
void threadMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new MainMethod(null))
.withMessageContaining("'thread' must not be null");
@@ -90,9 +92,9 @@ class MainMethodTests {
private final Runnable runnable;
private Exception exception;
private @Nullable Exception exception;
private MainMethod mainMethod;
private @Nullable MainMethod mainMethod;
TestThread(Runnable runnable) {
this.runnable = runnable;
@@ -104,7 +106,9 @@ class MainMethodTests {
if (this.exception != null) {
ReflectionUtils.rethrowRuntimeException(this.exception);
}
return this.mainMethod;
MainMethod mainMethod = this.mainMethod;
assertThat(mainMethod).isNotNull();
return mainMethod;
}
@Override
@@ -18,6 +18,7 @@ package org.springframework.boot.devtools.restart;
import java.util.concurrent.atomic.AtomicInteger;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Test;
import org.springframework.boot.SpringApplication;
@@ -37,9 +38,9 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
class RestartScopeInitializerTests {
private static AtomicInteger createCount;
private static @Nullable AtomicInteger createCount;
private static AtomicInteger refreshCount;
private static @Nullable AtomicInteger refreshCount;
@Test
void restartScope() {
@@ -73,11 +74,13 @@ class RestartScopeInitializerTests {
static class ScopeTestBean implements ApplicationListener<ContextRefreshedEvent> {
ScopeTestBean() {
assertThat(createCount).isNotNull();
createCount.incrementAndGet();
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
assertThat(refreshCount).isNotNull();
refreshCount.incrementAndGet();
}
@@ -26,6 +26,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.awaitility.Awaitility;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -111,6 +112,7 @@ class RestarterTests {
}
@Test
@SuppressWarnings("NullAway") // Test null check
void addUrlsMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> Restarter.getInstance().addUrls(null))
.withMessageContaining("'urls' must not be null");
@@ -124,10 +126,12 @@ class RestarterTests {
restarter.addUrls(urls);
restarter.restart();
ClassLoader classLoader = ((TestableRestarter) restarter).getRelaunchClassLoader();
assertThat(classLoader).isNotNull();
assertThat(((URLClassLoader) classLoader).getURLs()[0]).isEqualTo(url);
}
@Test
@SuppressWarnings("NullAway") // Test null check
void addClassLoaderFilesMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> Restarter.getInstance().addClassLoaderFiles(null))
.withMessageContaining("'classLoaderFiles' must not be null");
@@ -141,6 +145,7 @@ class RestarterTests {
restarter.addClassLoaderFiles(classLoaderFiles);
restarter.restart();
ClassLoader classLoader = ((TestableRestarter) restarter).getRelaunchClassLoader();
assertThat(classLoader).isNotNull();
assertThat(classLoader.getResourceAsStream("f")).hasContent("abc");
}
@@ -239,7 +244,7 @@ class RestarterTests {
static class TestableRestarter extends Restarter {
private ClassLoader relaunchClassLoader;
private @Nullable ClassLoader relaunchClassLoader;
TestableRestarter() {
this(Thread.currentThread(), new String[] {}, false, new MockRestartInitializer());
@@ -262,7 +267,7 @@ class RestarterTests {
}
@Override
protected Throwable relaunch(ClassLoader classLoader) {
protected @Nullable Throwable relaunch(ClassLoader classLoader) {
this.relaunchClassLoader = classLoader;
return null;
}
@@ -271,7 +276,7 @@ class RestarterTests {
protected void stop() {
}
ClassLoader getRelaunchClassLoader() {
@Nullable ClassLoader getRelaunchClassLoader() {
return this.relaunchClassLoader;
}
@@ -18,6 +18,7 @@ package org.springframework.boot.devtools.restart;
import java.util.concurrent.CountDownLatch;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -55,7 +56,9 @@ class SilentExitExceptionHandlerTests {
};
SilentExitExceptionHandler.setup(testThread);
testThread.startAndJoin();
assertThat(testThread.getThrown().getMessage()).isEqualTo("Expected");
Throwable thrown = testThread.getThrown();
assertThat(thrown).isNotNull();
assertThat(thrown.getMessage()).isEqualTo("Expected");
}
@Test
@@ -78,13 +81,13 @@ class SilentExitExceptionHandlerTests {
static class TestThread extends Thread {
private Throwable thrown;
private @Nullable Throwable thrown;
TestThread() {
setUncaughtExceptionHandler((thread, exception) -> TestThread.this.thrown = exception);
}
Throwable getThrown() {
@Nullable Throwable getThrown() {
return this.thrown;
}
@@ -33,24 +33,28 @@ class ClassLoaderFileTests {
public static final byte[] BYTES = "ABC".getBytes();
@Test
@SuppressWarnings("NullAway") // Test null check
void kindMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new ClassLoaderFile(null, null))
.withMessageContaining("'kind' must not be null");
}
@Test
@SuppressWarnings("NullAway") // Test null check
void addedContentsMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new ClassLoaderFile(Kind.ADDED, null))
.withMessageContaining("'contents' must not be null");
}
@Test
@SuppressWarnings("NullAway") // Test null check
void modifiedContentsMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new ClassLoaderFile(Kind.MODIFIED, null))
.withMessageContaining("'contents' must not be null");
}
@Test
@SuppressWarnings("NullAway") // Test null check
void deletedContentsMustBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new ClassLoaderFile(Kind.DELETED, new byte[10]))
.withMessageContaining("'contents' must be null");
@@ -41,12 +41,14 @@ class ClassLoaderFilesTests {
private final ClassLoaderFiles files = new ClassLoaderFiles();
@Test
@SuppressWarnings("NullAway") // Test null check
void addFileNameMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> this.files.addFile(null, mock(ClassLoaderFile.class)))
.withMessageContaining("'name' must not be null");
}
@Test
@SuppressWarnings("NullAway") // Test null check
void addFileFileMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> this.files.addFile("test", null))
.withMessageContaining("'file' must not be null");
@@ -151,6 +153,7 @@ class ClassLoaderFilesTests {
}
@Test
@SuppressWarnings("NullAway") // Test null check
void classLoaderFilesMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new ClassLoaderFiles(null))
.withMessageContaining("'classLoaderFiles' must not be null");
@@ -102,12 +102,14 @@ class RestartClassLoaderTests {
}
@Test
@SuppressWarnings("NullAway") // Test null check
void parentMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new RestartClassLoader(null, new URL[] {}))
.withMessageContaining("'parent' must not be null");
}
@Test
@SuppressWarnings("NullAway") // Test null check
void updatedFilesMustNotBeNull() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new RestartClassLoader(this.parentClassLoader, new URL[] {}, null))
@@ -164,6 +166,7 @@ class RestartClassLoaderTests {
byte[] bytes = "abc".getBytes();
this.updatedFiles.addFile(name, new ClassLoaderFile(Kind.MODIFIED, bytes));
URL resource = this.reloadClassLoader.getResource(name);
assertThat(resource).isNotNull();
assertThat(FileCopyUtils.copyToByteArray(resource.openStream())).isEqualTo(bytes);
}
@@ -33,6 +33,7 @@ import static org.mockito.Mockito.mock;
class HttpRestartServerHandlerTests {
@Test
@SuppressWarnings("NullAway") // Test null check
void serverMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new HttpRestartServerHandler(null))
.withMessageContaining("'server' must not be null");
@@ -48,6 +48,7 @@ import static org.mockito.BDDMockito.then;
class HttpRestartServerTests {
@Mock
@SuppressWarnings("NullAway.Init")
private RestartServer delegate;
private HttpRestartServer server;
@@ -58,12 +59,14 @@ class HttpRestartServerTests {
}
@Test
@SuppressWarnings("NullAway") // Test null check
void sourceDirectoryUrlFilterMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new HttpRestartServer((SourceDirectoryUrlFilter) null))
.withMessageContaining("'sourceDirectoryUrlFilter' must not be null");
}
@Test
@SuppressWarnings("NullAway") // Test null check
void restartServerMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new HttpRestartServer((RestartServer) null))
.withMessageContaining("'restartServer' must not be null");
@@ -24,6 +24,7 @@ import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
@@ -43,6 +44,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
class RestartServerTests {
@Test
@SuppressWarnings("NullAway") // Test null check
void sourceDirectoryUrlFilterMustNotBeNull() {
assertThatIllegalArgumentException().isThrownBy(() -> new RestartServer((SourceDirectoryUrlFilter) null))
.withMessageContaining("'sourceDirectoryUrlFilter' must not be null");
@@ -110,9 +112,9 @@ class RestartServerTests {
super(sourceDirectoryUrlFilter, classLoader);
}
private Set<URL> restartUrls;
private @Nullable Set<URL> restartUrls;
private ClassLoaderFiles restartFiles;
private @Nullable ClassLoaderFiles restartFiles;
@Override
protected void restart(Set<URL> urls, ClassLoaderFiles files) {