Skip to content

Commit 2850ba0

Browse files
committed
Add nullability annotations to tests in buildpack/spring-boot-buildpack-platform
See gh-47263
1 parent c2286ab commit 2850ba0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+244
-51
lines changed

buildpack/spring-boot-buildpack-platform/build.gradle

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,11 @@ dependencies {
3737

3838
testImplementation(project(":test-support:spring-boot-test-support"))
3939
}
40+
41+
tasks.named("compileTestJava") {
42+
options.nullability.checking = "tests"
43+
}
44+
45+
tasks.named("compileDockerTestJava") {
46+
options.nullability.checking = "tests"
47+
}

buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuildOwnerTests.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.LinkedHashMap;
2020
import java.util.Map;
2121

22+
import org.jspecify.annotations.Nullable;
2223
import org.junit.jupiter.api.Test;
2324

2425
import static org.assertj.core.api.Assertions.assertThat;
@@ -35,7 +36,7 @@ class BuildOwnerTests {
3536

3637
@Test
3738
void fromEnvReturnsOwner() {
38-
Map<String, String> env = new LinkedHashMap<>();
39+
Map<String, @Nullable String> env = new LinkedHashMap<>();
3940
env.put("CNB_USER_ID", "123");
4041
env.put("CNB_GROUP_ID", "456");
4142
BuildOwner owner = BuildOwner.fromEnv(env);
@@ -45,30 +46,31 @@ void fromEnvReturnsOwner() {
4546
}
4647

4748
@Test
49+
@SuppressWarnings("NullAway") // Test null check
4850
void fromEnvWhenEnvIsNullThrowsException() {
4951
assertThatIllegalArgumentException().isThrownBy(() -> BuildOwner.fromEnv(null))
5052
.withMessage("'env' must not be null");
5153
}
5254

5355
@Test
5456
void fromEnvWhenUserPropertyIsMissingThrowsException() {
55-
Map<String, String> env = new LinkedHashMap<>();
57+
Map<String, @Nullable String> env = new LinkedHashMap<>();
5658
env.put("CNB_GROUP_ID", "456");
5759
assertThatIllegalStateException().isThrownBy(() -> BuildOwner.fromEnv(env))
5860
.withMessage("Missing 'CNB_USER_ID' value from the builder environment '" + env + "'");
5961
}
6062

6163
@Test
6264
void fromEnvWhenGroupPropertyIsMissingThrowsException() {
63-
Map<String, String> env = new LinkedHashMap<>();
65+
Map<String, @Nullable String> env = new LinkedHashMap<>();
6466
env.put("CNB_USER_ID", "123");
6567
assertThatIllegalStateException().isThrownBy(() -> BuildOwner.fromEnv(env))
6668
.withMessage("Missing 'CNB_GROUP_ID' value from the builder environment '" + env + "'");
6769
}
6870

6971
@Test
7072
void fromEnvWhenUserPropertyIsMalformedThrowsException() {
71-
Map<String, String> env = new LinkedHashMap<>();
73+
Map<String, @Nullable String> env = new LinkedHashMap<>();
7274
env.put("CNB_USER_ID", "nope");
7375
env.put("CNB_GROUP_ID", "456");
7476
assertThatIllegalStateException().isThrownBy(() -> BuildOwner.fromEnv(env))
@@ -77,7 +79,7 @@ void fromEnvWhenUserPropertyIsMalformedThrowsException() {
7779

7880
@Test
7981
void fromEnvWhenGroupPropertyIsMalformedThrowsException() {
80-
Map<String, String> env = new LinkedHashMap<>();
82+
Map<String, @Nullable String> env = new LinkedHashMap<>();
8183
env.put("CNB_USER_ID", "123");
8284
env.put("CNB_GROUP_ID", "nope");
8385
assertThatIllegalStateException().isThrownBy(() -> BuildOwner.fromEnv(env))

buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuildRequestTests.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ class BuildRequestTests {
6161
private static final ZoneId UTC = ZoneId.of("UTC");
6262

6363
@TempDir
64+
@SuppressWarnings("NullAway.Init")
6465
File tempDir;
6566

6667
@Test
@@ -86,6 +87,7 @@ void forJarFileWithNameReturnsRequest() throws IOException {
8687
}
8788

8889
@Test
90+
@SuppressWarnings("NullAway") // Test null check
8991
void forJarFileWhenJarFileIsNullThrowsException() {
9092
assertThatIllegalArgumentException().isThrownBy(() -> BuildRequest.forJarFile(null))
9193
.withMessage("'jarFile' must not be null");
@@ -214,13 +216,15 @@ void withEnvMapAddsEnvEntries() throws IOException {
214216
}
215217

216218
@Test
219+
@SuppressWarnings("NullAway") // Test null check
217220
void withEnvWhenKeyIsNullThrowsException() throws IOException {
218221
BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar"));
219222
assertThatIllegalArgumentException().isThrownBy(() -> request.withEnv(null, "test"))
220223
.withMessage("'name' must not be empty");
221224
}
222225

223226
@Test
227+
@SuppressWarnings("NullAway") // Test null check
224228
void withEnvWhenValueIsNullThrowsException() throws IOException {
225229
BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar"));
226230
assertThatIllegalArgumentException().isThrownBy(() -> request.withEnv("test", null))
@@ -238,6 +242,7 @@ void withBuildpacksAddsBuildpacks() throws IOException {
238242
}
239243

240244
@Test
245+
@SuppressWarnings("NullAway") // Test null check
241246
void withBuildpacksWhenBuildpacksIsNullThrowsException() throws IOException {
242247
BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar"));
243248
assertThatIllegalArgumentException().isThrownBy(() -> request.withBuildpacks((List<BuildpackReference>) null))
@@ -255,6 +260,7 @@ void withBindingsAddsBindings() throws IOException {
255260
}
256261

257262
@Test
263+
@SuppressWarnings("NullAway") // Test null check
258264
void withBindingsWhenBindingsIsNullThrowsException() throws IOException {
259265
BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar"));
260266
assertThatIllegalArgumentException().isThrownBy(() -> request.withBindings((List<Binding>) null))
@@ -280,6 +286,7 @@ void withTagsAddsTags() throws IOException {
280286
}
281287

282288
@Test
289+
@SuppressWarnings("NullAway") // Test null check
283290
void withTagsWhenTagsIsNullThrowsException() throws IOException {
284291
BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar"));
285292
assertThatIllegalArgumentException().isThrownBy(() -> request.withTags((List<ImageReference>) null))
@@ -319,6 +326,7 @@ void withBuildBindCacheAddsCache() throws IOException {
319326
}
320327

321328
@Test
329+
@SuppressWarnings("NullAway") // Test null check
322330
void withBuildVolumeCacheWhenCacheIsNullThrowsException() throws IOException {
323331
BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar"));
324332
assertThatIllegalArgumentException().isThrownBy(() -> request.withBuildCache(null))
@@ -342,6 +350,7 @@ void withLaunchBindCacheAddsCache() throws IOException {
342350
}
343351

344352
@Test
353+
@SuppressWarnings("NullAway") // Test null check
345354
void withLaunchVolumeCacheWhenCacheIsNullThrowsException() throws IOException {
346355
BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar"));
347356
assertThatIllegalArgumentException().isThrownBy(() -> request.withLaunchCache(null))

buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuilderBuildpackTests.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ void setUp() throws Exception {
5151
void resolveWhenFullyQualifiedBuildpackWithVersionResolves() throws Exception {
5252
BuildpackReference reference = BuildpackReference.of("urn:cnb:builder:paketo-buildpacks/[email protected]");
5353
Buildpack buildpack = BuilderBuildpack.resolve(this.resolverContext, reference);
54+
assertThat(buildpack).isNotNull();
5455
assertThat(buildpack.getCoordinates())
5556
.isEqualTo(BuildpackCoordinates.of("paketo-buildpacks/spring-boot", "3.5.0"));
5657
assertThatNoLayersAreAdded(buildpack);
@@ -60,6 +61,7 @@ void resolveWhenFullyQualifiedBuildpackWithVersionResolves() throws Exception {
6061
void resolveWhenFullyQualifiedBuildpackWithoutVersionResolves() throws Exception {
6162
BuildpackReference reference = BuildpackReference.of("urn:cnb:builder:paketo-buildpacks/spring-boot");
6263
Buildpack buildpack = BuilderBuildpack.resolve(this.resolverContext, reference);
64+
assertThat(buildpack).isNotNull();
6365
assertThat(buildpack.getCoordinates())
6466
.isEqualTo(BuildpackCoordinates.of("paketo-buildpacks/spring-boot", "3.5.0"));
6567
assertThatNoLayersAreAdded(buildpack);
@@ -69,6 +71,7 @@ void resolveWhenFullyQualifiedBuildpackWithoutVersionResolves() throws Exception
6971
void resolveWhenUnqualifiedBuildpackWithVersionResolves() throws Exception {
7072
BuildpackReference reference = BuildpackReference.of("paketo-buildpacks/[email protected]");
7173
Buildpack buildpack = BuilderBuildpack.resolve(this.resolverContext, reference);
74+
assertThat(buildpack).isNotNull();
7275
assertThat(buildpack.getCoordinates())
7376
.isEqualTo(BuildpackCoordinates.of("paketo-buildpacks/spring-boot", "3.5.0"));
7477
assertThatNoLayersAreAdded(buildpack);
@@ -78,6 +81,7 @@ void resolveWhenUnqualifiedBuildpackWithVersionResolves() throws Exception {
7881
void resolveWhenUnqualifiedBuildpackWithoutVersionResolves() throws Exception {
7982
BuildpackReference reference = BuildpackReference.of("paketo-buildpacks/spring-boot");
8083
Buildpack buildpack = BuilderBuildpack.resolve(this.resolverContext, reference);
84+
assertThat(buildpack).isNotNull();
8185
assertThat(buildpack.getCoordinates())
8286
.isEqualTo(BuildpackCoordinates.of("paketo-buildpacks/spring-boot", "3.5.0"));
8387
assertThatNoLayersAreAdded(buildpack);

buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuilderMetadataTests.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ void fromImageWithoutStackLoadsMetadata() throws IOException {
8888
}
8989

9090
@Test
91+
@SuppressWarnings("NullAway") // Test null check
9192
void fromImageWhenImageIsNullThrowsException() {
9293
assertThatIllegalArgumentException().isThrownBy(() -> BuilderMetadata.fromImage(null))
9394
.withMessage("'image' must not be null");
@@ -150,6 +151,7 @@ void attachToUpdatesMetadata() throws IOException {
150151
BuilderMetadata metadata = BuilderMetadata.fromImage(image);
151152
ImageConfig imageConfigCopy = imageConfig.copy(metadata::attachTo);
152153
String label = imageConfigCopy.getLabels().get("io.buildpacks.builder.metadata");
154+
assertThat(label).isNotNull();
153155
BuilderMetadata metadataCopy = BuilderMetadata.fromJson(label);
154156
assertThat(metadataCopy.getStack().getRunImage().getImage())
155157
.isEqualTo(metadata.getStack().getRunImage().getImage());

buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuilderTests.java

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
import java.io.IOException;
2121
import java.io.PrintStream;
2222
import java.net.URI;
23+
import java.util.Objects;
2324

25+
import org.jspecify.annotations.Nullable;
2426
import org.junit.jupiter.api.Test;
2527
import org.mockito.ArgumentCaptor;
2628
import org.mockito.stubbing.Answer;
@@ -77,6 +79,7 @@ class BuilderTests {
7779
private static final ImageReference BASE_CNB = ImageReference.of("docker.io/cloudfoundry/run:base-cnb");
7880

7981
@Test
82+
@SuppressWarnings("NullAway") // Test null check
8083
void createWhenLogIsNullThrowsException() {
8184
assertThatIllegalArgumentException().isThrownBy(() -> new Builder((BuildLog) null))
8285
.withMessage("'log' must not be null");
@@ -106,6 +109,7 @@ void createDockerApiWithLogDockerSystemOutDelegate() {
106109
}
107110

108111
@Test
112+
@SuppressWarnings("NullAway") // Test null check
109113
void buildWhenRequestIsNullThrowsException() {
110114
Builder builder = new Builder();
111115
assertThatIllegalArgumentException().isThrownBy(() -> builder.build(null))
@@ -131,7 +135,9 @@ void buildInvokesBuilder() throws Exception {
131135
then(docker.image()).should().pull(eq(DEFAULT_BUILDER), isNull(), any(), isNull());
132136
then(docker.image()).should().pull(eq(BASE_CNB), eq(ImagePlatform.from(builderImage)), any(), isNull());
133137
then(docker.image()).should().load(archive.capture(), any());
134-
then(docker.image()).should().remove(archive.getValue().getTag(), true);
138+
ImageReference tag = archive.getValue().getTag();
139+
assertThat(tag).isNotNull();
140+
then(docker.image()).should().remove(tag, true);
135141
then(docker.image()).shouldHaveNoMoreInteractions();
136142
}
137143

@@ -161,7 +167,9 @@ void buildInvokesBuilderAndPublishesImage() throws Exception {
161167
.pull(eq(BASE_CNB), eq(ImagePlatform.from(builderImage)), any(), regAuthEq(builderToken));
162168
then(docker.image()).should().push(eq(request.getName()), any(), regAuthEq(publishToken));
163169
then(docker.image()).should().load(archive.capture(), any());
164-
then(docker.image()).should().remove(archive.getValue().getTag(), true);
170+
ImageReference tag = archive.getValue().getTag();
171+
assertThat(tag).isNotNull();
172+
then(docker.image()).should().remove(tag, true);
165173
then(docker.image()).shouldHaveNoMoreInteractions();
166174
}
167175

@@ -184,7 +192,9 @@ void buildInvokesBuilderWithDefaultImageTags() throws Exception {
184192
assertThat(out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'");
185193
ArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);
186194
then(docker.image()).should().load(archive.capture(), any());
187-
then(docker.image()).should().remove(archive.getValue().getTag(), true);
195+
ImageReference tag = archive.getValue().getTag();
196+
assertThat(tag).isNotNull();
197+
then(docker.image()).should().remove(tag, true);
188198
}
189199

190200
@Test
@@ -207,7 +217,9 @@ void buildInvokesBuilderWithRunImageInDigestForm() throws Exception {
207217
assertThat(out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'");
208218
ArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);
209219
then(docker.image()).should().load(archive.capture(), any());
210-
then(docker.image()).should().remove(archive.getValue().getTag(), true);
220+
ImageReference tag = archive.getValue().getTag();
221+
assertThat(tag).isNotNull();
222+
then(docker.image()).should().remove(tag, true);
211223
}
212224

213225
@Test
@@ -227,7 +239,9 @@ void buildInvokesBuilderWithNoStack() throws Exception {
227239
assertThat(out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'");
228240
ArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);
229241
then(docker.image()).should().load(archive.capture(), any());
230-
then(docker.image()).should().remove(archive.getValue().getTag(), true);
242+
ImageReference tag = archive.getValue().getTag();
243+
assertThat(tag).isNotNull();
244+
then(docker.image()).should().remove(tag, true);
231245
}
232246

233247
@Test
@@ -249,7 +263,9 @@ void buildInvokesBuilderWithRunImageFromRequest() throws Exception {
249263
assertThat(out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'");
250264
ArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);
251265
then(docker.image()).should().load(archive.capture(), any());
252-
then(docker.image()).should().remove(archive.getValue().getTag(), true);
266+
ImageReference tag = archive.getValue().getTag();
267+
assertThat(tag).isNotNull();
268+
then(docker.image()).should().remove(tag, true);
253269
}
254270

255271
@Test
@@ -271,7 +287,9 @@ void buildInvokesBuilderWithNeverPullPolicy() throws Exception {
271287
assertThat(out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'");
272288
ArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);
273289
then(docker.image()).should().load(archive.capture(), any());
274-
then(docker.image()).should().remove(archive.getValue().getTag(), true);
290+
ImageReference tag = archive.getValue().getTag();
291+
assertThat(tag).isNotNull();
292+
then(docker.image()).should().remove(tag, true);
275293
then(docker.image()).should(never()).pull(any(), any(), any());
276294
then(docker.image()).should(times(2)).inspect(any());
277295
}
@@ -295,7 +313,9 @@ void buildInvokesBuilderWithAlwaysPullPolicy() throws Exception {
295313
assertThat(out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'");
296314
ArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);
297315
then(docker.image()).should().load(archive.capture(), any());
298-
then(docker.image()).should().remove(archive.getValue().getTag(), true);
316+
ImageReference tag = archive.getValue().getTag();
317+
assertThat(tag).isNotNull();
318+
then(docker.image()).should().remove(tag, true);
299319
then(docker.image()).should(times(2)).pull(any(), any(), any(), isNull());
300320
then(docker.image()).should(never()).inspect(any());
301321
}
@@ -325,7 +345,9 @@ void buildInvokesBuilderWithIfNotPresentPullPolicy() throws Exception {
325345
assertThat(out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'");
326346
ArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);
327347
then(docker.image()).should().load(archive.capture(), any());
328-
then(docker.image()).should().remove(archive.getValue().getTag(), true);
348+
ImageReference tag = archive.getValue().getTag();
349+
assertThat(tag).isNotNull();
350+
then(docker.image()).should().remove(tag, true);
329351
then(docker.image()).should(times(2)).inspect(any());
330352
then(docker.image()).should(times(2)).pull(any(), any(), any(), isNull());
331353
}
@@ -349,7 +371,9 @@ void buildInvokesBuilderWithTags() throws Exception {
349371
then(docker.image()).should().tag(eq(request.getName()), eq(ImageReference.of("my-application:1.2.3")));
350372
ArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);
351373
then(docker.image()).should().load(archive.capture(), any());
352-
then(docker.image()).should().remove(archive.getValue().getTag(), true);
374+
ImageReference tag = archive.getValue().getTag();
375+
assertThat(tag).isNotNull();
376+
then(docker.image()).should().remove(tag, true);
353377
}
354378

355379
@Test
@@ -385,7 +409,9 @@ void buildInvokesBuilderWithTagsAndPublishesImageAndTags() throws Exception {
385409
then(docker.image()).should().push(eq(builtImageReference), any(), regAuthEq(publishToken));
386410
ArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);
387411
then(docker.image()).should().load(archive.capture(), any());
388-
then(docker.image()).should().remove(archive.getValue().getTag(), true);
412+
ImageReference tag = archive.getValue().getTag();
413+
assertThat(tag).isNotNull();
414+
then(docker.image()).should().remove(tag, true);
389415
then(docker.image()).shouldHaveNoMoreInteractions();
390416
}
391417

@@ -408,7 +434,9 @@ void buildInvokesBuilderWithPlatform() throws Exception {
408434
then(docker.image()).should().pull(eq(DEFAULT_BUILDER), eq(platform), any(), isNull());
409435
then(docker.image()).should().pull(eq(BASE_CNB), eq(platform), any(), isNull());
410436
then(docker.image()).should().load(archive.capture(), any());
411-
then(docker.image()).should().remove(archive.getValue().getTag(), true);
437+
ImageReference tag = archive.getValue().getTag();
438+
assertThat(tag).isNotNull();
439+
then(docker.image()).should().remove(tag, true);
412440
then(docker.image()).shouldHaveNoMoreInteractions();
413441
}
414442

@@ -483,7 +511,7 @@ private DockerApi mockDockerApi() throws IOException {
483511
return mockDockerApi(null);
484512
}
485513

486-
private DockerApi mockDockerApi(ImagePlatform platform) throws IOException {
514+
private DockerApi mockDockerApi(@Nullable ImagePlatform platform) throws IOException {
487515
ContainerApi containerApi = mock(ContainerApi.class);
488516
ContainerReference reference = ContainerReference.of("container-ref");
489517
given(containerApi.create(any(), eq(platform), any())).willReturn(reference);
@@ -531,7 +559,7 @@ private Answer<Image> withPulledImage(Image image) {
531559
}
532560

533561
private static String regAuthEq(DockerRegistryAuthentication authentication) {
534-
return argThat(authentication.getAuthHeader()::equals);
562+
return argThat((arg) -> Objects.equals(authentication.getAuthHeader(), arg));
535563
}
536564

537565
static class TestPrintStream extends PrintStream {

0 commit comments

Comments
 (0)