Merge branch '2.7.x' into 3.0.x

Closes gh-34495
This commit is contained in:
Scott Frederick
2023-03-06 15:30:55 -06:00
11 changed files with 329 additions and 49 deletions

View File

@@ -18,7 +18,10 @@ package org.springframework.boot.buildpack.platform.build;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
@@ -33,7 +36,6 @@ import org.mockito.invocation.InvocationOnMock;
import org.springframework.boot.buildpack.platform.docker.type.Image;
import org.springframework.boot.buildpack.platform.docker.type.ImageReference;
import org.springframework.boot.buildpack.platform.io.IOBiConsumer;
import org.springframework.boot.buildpack.platform.io.TarArchive;
import org.springframework.boot.buildpack.platform.json.AbstractJsonTests;
import static org.assertj.core.api.Assertions.assertThat;
@@ -173,20 +175,20 @@ class ImageBuildpackTests extends AbstractJsonTests {
private Object withMockLayers(InvocationOnMock invocation) {
try {
IOBiConsumer<String, TarArchive> consumer = invocation.getArgument(1);
TarArchive archive = (out) -> {
try (TarArchiveOutputStream tarOut = new TarArchiveOutputStream(out)) {
tarOut.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);
writeTarEntry(tarOut, "/cnb/");
writeTarEntry(tarOut, "/cnb/buildpacks/");
writeTarEntry(tarOut, "/cnb/buildpacks/example_buildpack/");
writeTarEntry(tarOut, "/cnb/buildpacks/example_buildpack/0.0.1/");
writeTarEntry(tarOut, "/cnb/buildpacks/example_buildpack/0.0.1/buildpack.toml");
writeTarEntry(tarOut, "/cnb/buildpacks/example_buildpack/0.0.1/" + this.longFilePath);
tarOut.finish();
}
};
consumer.accept("test", archive);
IOBiConsumer<String, Path> consumer = invocation.getArgument(1);
File tarFile = File.createTempFile("create-builder-test-", null);
FileOutputStream out = new FileOutputStream(tarFile);
try (TarArchiveOutputStream tarOut = new TarArchiveOutputStream(out)) {
tarOut.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);
writeTarEntry(tarOut, "/cnb/");
writeTarEntry(tarOut, "/cnb/buildpacks/");
writeTarEntry(tarOut, "/cnb/buildpacks/example_buildpack/");
writeTarEntry(tarOut, "/cnb/buildpacks/example_buildpack/0.0.1/");
writeTarEntry(tarOut, "/cnb/buildpacks/example_buildpack/0.0.1/buildpack.toml");
writeTarEntry(tarOut, "/cnb/buildpacks/example_buildpack/0.0.1/" + this.longFilePath);
tarOut.finish();
}
consumer.accept("test", tarFile.toPath());
}
catch (IOException ex) {
fail("Error writing mock layers", ex);

View File

@@ -21,6 +21,9 @@ import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
@@ -310,14 +313,14 @@ class DockerApiTests {
@Test
void exportLayersWhenReferenceIsNullThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> this.api.exportLayers(null, (name, archive) -> {
assertThatIllegalArgumentException().isThrownBy(() -> this.api.exportLayerFiles(null, (name, archive) -> {
})).withMessage("Reference must not be null");
}
@Test
void exportLayersWhenExportsIsNullThrowsException() {
ImageReference reference = ImageReference.of("gcr.io/paketo-buildpacks/builder:base");
assertThatIllegalArgumentException().isThrownBy(() -> this.api.exportLayers(reference, null))
assertThatIllegalArgumentException().isThrownBy(() -> this.api.exportLayerFiles(reference, null))
.withMessage("Exports must not be null");
}
@@ -340,11 +343,62 @@ class DockerApiTests {
}
});
assertThat(contents).hasSize(3)
.containsKeys("1bf6c63a1e9ed1dd7cb961273bf60b8e0f440361faf273baf866f408e4910601/layer.tar",
"8fdfb915302159a842cbfae6faec5311b00c071ebf14e12da7116ae7532e9319/layer.tar",
"93cd584bb189bfca4f51744bd19d836fd36da70710395af5a1523ee88f208c6a/layer.tar");
assertThat(contents.get("1bf6c63a1e9ed1dd7cb961273bf60b8e0f440361faf273baf866f408e4910601/layer.tar"))
.containsExactly("etc/", "etc/apt/", "etc/apt/sources.list");
.containsKeys("70bb7a3115f3d5c01099852112c7e05bf593789e510468edb06b6a9a11fa3b73/layer.tar",
"74a9a50ece13c025cf10e9110d9ddc86c995079c34e2a22a28d1a3d523222c6e/layer.tar",
"a69532b5b92bb891fbd9fa1a6b3af9087ea7050255f59ba61a796f8555ecd783/layer.tar");
assertThat(contents.get("70bb7a3115f3d5c01099852112c7e05bf593789e510468edb06b6a9a11fa3b73/layer.tar"))
.containsExactly("/cnb/order.toml");
assertThat(contents.get("74a9a50ece13c025cf10e9110d9ddc86c995079c34e2a22a28d1a3d523222c6e/layer.tar"))
.containsExactly("/cnb/stack.toml");
}
@Test
void exportLayersWithSymlinksExportsLayerTars() throws Exception {
ImageReference reference = ImageReference.of("gcr.io/paketo-buildpacks/builder:base");
URI exportUri = new URI(IMAGES_URL + "/gcr.io/paketo-buildpacks/builder:base/get");
given(DockerApiTests.this.http.get(exportUri)).willReturn(responseOf("export-symlinks.tar"));
MultiValueMap<String, String> contents = new LinkedMultiValueMap<>();
this.api.exportLayers(reference, (name, archive) -> {
ByteArrayOutputStream out = new ByteArrayOutputStream();
archive.writeTo(out);
try (TarArchiveInputStream in = new TarArchiveInputStream(
new ByteArrayInputStream(out.toByteArray()))) {
TarArchiveEntry entry = in.getNextTarEntry();
while (entry != null) {
contents.add(name, entry.getName());
entry = in.getNextTarEntry();
}
}
});
assertThat(contents).hasSize(3)
.containsKeys("6aa3691a73805f608e5fce69fb6bc89aec8362f58a6b4be2682515e9cfa3cc1a.tar",
"762e198f655bc2580ef3e56b538810fd2b9981bd707f8a44c70344b58f9aee68.tar",
"d3cc975ad97fdfbb73d9daf157e7f658d6117249fd9c237e3856ad173c87e1d2.tar");
assertThat(contents.get("d3cc975ad97fdfbb73d9daf157e7f658d6117249fd9c237e3856ad173c87e1d2.tar"))
.containsExactly("/cnb/order.toml");
assertThat(contents.get("762e198f655bc2580ef3e56b538810fd2b9981bd707f8a44c70344b58f9aee68.tar"))
.containsExactly("/cnb/stack.toml");
}
@Test
void exportLayerFilesDeletesTempFiles() throws Exception {
ImageReference reference = ImageReference.of("gcr.io/paketo-buildpacks/builder:base");
URI exportUri = new URI(IMAGES_URL + "/gcr.io/paketo-buildpacks/builder:base/get");
given(DockerApiTests.this.http.get(exportUri)).willReturn(responseOf("export.tar"));
List<Path> layerFilePaths = new ArrayList<>();
this.api.exportLayerFiles(reference, (name, path) -> layerFilePaths.add(path));
layerFilePaths.forEach((path) -> assertThat(path.toFile()).doesNotExist());
}
@Test
void exportLayersWithNoManifestThrowsException() throws Exception {
ImageReference reference = ImageReference.of("gcr.io/paketo-buildpacks/builder:base");
URI exportUri = new URI(IMAGES_URL + "/gcr.io/paketo-buildpacks/builder:base/get");
given(DockerApiTests.this.http.get(exportUri)).willReturn(responseOf("export-no-manifest.tar"));
assertThatIllegalArgumentException()
.isThrownBy(() -> this.api.exportLayerFiles(reference, (name, archive) -> {
}))
.withMessageContaining("Manifest not found in image " + reference);
}
@Test

View File

@@ -0,0 +1,69 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.buildpack.platform.docker.type;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.boot.buildpack.platform.json.AbstractJsonTests;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ImageArchiveManifest}.
*
* @author Scott Frederick
* @author Andy Wilkinson
*/
class ImageArchiveManifestTests extends AbstractJsonTests {
@Test
void getLayersReturnsLayers() throws Exception {
ImageArchiveManifest manifest = getManifest();
List<String> expectedLayers = new ArrayList<>();
for (int blankLayersCount = 0; blankLayersCount < 46; blankLayersCount++) {
expectedLayers.add("blank_" + blankLayersCount);
}
expectedLayers.add("bb09e17fd1bd2ee47155f1349645fcd9fff31e1247c7ed99cad469f1c16a4216.tar");
assertThat(manifest.getEntries()).hasSize(1);
assertThat(manifest.getEntries().get(0).getLayers()).hasSize(47);
assertThat(manifest.getEntries().get(0).getLayers()).isEqualTo(expectedLayers);
}
@Test
void getLayersWithNoLayersReturnsEmptyList() throws Exception {
String content = "[{\"Layers\": []}]";
ImageArchiveManifest manifest = new ImageArchiveManifest(getObjectMapper().readTree(content));
assertThat(manifest.getEntries()).hasSize(1);
assertThat(manifest.getEntries().get(0).getLayers()).hasSize(0);
}
@Test
void getLayersWithEmptyManifestReturnsEmptyList() throws Exception {
String content = "[]";
ImageArchiveManifest manifest = new ImageArchiveManifest(getObjectMapper().readTree(content));
assertThat(manifest.getEntries()).isEmpty();
}
private ImageArchiveManifest getManifest() throws IOException {
return new ImageArchiveManifest(getObjectMapper().readTree(getContent("image-archive-manifest.json")));
}
}