From e1a9e88898c8508118c443eeeaf1292747e3c325 Mon Sep 17 00:00:00 2001 From: Marsette Vona Date: Wed, 12 Apr 2023 16:36:22 -0400 Subject: [PATCH] add unit tests for buildX platforms Signed-off-by: Marsette Vona --- .../maven/docker/service/BuildXService.java | 20 +-- .../docker/service/BuildXServiceTest.java | 132 ++++++++++++++++++ 2 files changed, 142 insertions(+), 10 deletions(-) create mode 100644 src/test/java/io/fabric8/maven/docker/service/BuildXServiceTest.java diff --git a/src/main/java/io/fabric8/maven/docker/service/BuildXService.java b/src/main/java/io/fabric8/maven/docker/service/BuildXService.java index 57693ea2d..254a53636 100644 --- a/src/main/java/io/fabric8/maven/docker/service/BuildXService.java +++ b/src/main/java/io/fabric8/maven/docker/service/BuildXService.java @@ -58,7 +58,7 @@ public void push(ProjectPaths projectPaths, ImageConfiguration imageConfig, Stri useBuilder(projectPaths, imageConfig, configuredRegistry, authConfig, archive, this::pushMultiPlatform); } - private void useBuilder(ProjectPaths projectPaths, ImageConfiguration imageConfig, String configuredRegistry, AuthConfig authConfig, C context, Builder builder) throws MojoExecutionException { + protected void useBuilder(ProjectPaths projectPaths, ImageConfiguration imageConfig, String configuredRegistry, AuthConfig authConfig, C context, Builder builder) throws MojoExecutionException { BuildDirs buildDirs = new BuildDirs(projectPaths, imageConfig.getName()); Path configPath = getDockerStateDir(imageConfig.getBuildConfiguration(), buildDirs); @@ -74,7 +74,7 @@ private void useBuilder(ProjectPaths projectPaths, ImageConfiguration imageC } } - private void createConfigJson(Path configJson, AuthConfig authConfig) throws MojoExecutionException { + protected void createConfigJson(Path configJson, AuthConfig authConfig) throws MojoExecutionException { try (BufferedWriter bufferedWriter = Files.newBufferedWriter(configJson, StandardCharsets.UTF_8, StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING) ) { @@ -84,7 +84,7 @@ private void createConfigJson(Path configJson, AuthConfig authConfig) throws Moj } } - private void removeConfigJson(Path configJson) { + protected void removeConfigJson(Path configJson) { try { Files.deleteIfExists(configJson); } catch (IOException e) { @@ -92,7 +92,7 @@ private void removeConfigJson(Path configJson) { } } - private void buildAndLoadSinglePlatform(List buildX, String builderName, BuildDirs buildDirs, ImageConfiguration imageConfig, String configuredRegistry, File buildArchive) throws MojoExecutionException { + protected void buildAndLoadSinglePlatform(List buildX, String builderName, BuildDirs buildDirs, ImageConfiguration imageConfig, String configuredRegistry, File buildArchive) throws MojoExecutionException { List platforms = imageConfig.getBuildConfiguration().getBuildX().getPlatforms(); // build and load the single-platform image by re-building, image should be cached and build should be quick String nativePlatform = dockerAccess.getNativePlatform(); @@ -105,12 +105,12 @@ private void buildAndLoadSinglePlatform(List buildX, String builderName, } } - private void pushMultiPlatform(List buildX, String builderName, BuildDirs buildDirs, ImageConfiguration imageConfig, String configuredRegistry, File buildArchive) throws MojoExecutionException { + protected void pushMultiPlatform(List buildX, String builderName, BuildDirs buildDirs, ImageConfiguration imageConfig, String configuredRegistry, File buildArchive) throws MojoExecutionException { // build and push all images. The native platform may be re-built, image should be cached and build should be quick buildX(buildX, builderName, buildDirs, imageConfig, configuredRegistry, imageConfig.getBuildConfiguration().getBuildX().getPlatforms(), buildArchive, "--push"); } - private void buildX(List buildX, String builderName, BuildDirs buildDirs, ImageConfiguration imageConfig, String configuredRegistry, List platforms, File buildArchive, String extraParam) + protected void buildX(List buildX, String builderName, BuildDirs buildDirs, ImageConfiguration imageConfig, String configuredRegistry, List platforms, File buildArchive, String extraParam) throws MojoExecutionException { BuildImageConfiguration buildConfiguration = imageConfig.getBuildConfiguration(); @@ -160,7 +160,7 @@ private void buildX(List buildX, String builderName, BuildDirs buildDirs } } - private Path getContextPath(File buildArchive) throws MojoExecutionException { + protected Path getContextPath(File buildArchive) throws MojoExecutionException { String archiveName = buildArchive.getName(); String fileName = archiveName.substring(0, archiveName.indexOf('.')); File destinationDirectory = new File(buildArchive.getParentFile(), fileName); @@ -174,14 +174,14 @@ private Path getContextPath(File buildArchive) throws MojoExecutionException { return destinationPath; } - private Path getDockerStateDir(BuildImageConfiguration buildConfiguration, BuildDirs buildDirs) { + protected Path getDockerStateDir(BuildImageConfiguration buildConfiguration, BuildDirs buildDirs) { String stateDir = buildConfiguration.getBuildX().getDockerStateDir(); Path dockerStatePath = buildDirs.getBuildPath(stateDir != null ? EnvUtil.resolveHomeReference(stateDir) : "docker"); createDirectory(dockerStatePath); return dockerStatePath; } - private void createDirectory(Path cachePath) { + protected void createDirectory(Path cachePath) { try { Files.createDirectories(cachePath); } catch (IOException e) { @@ -189,7 +189,7 @@ private void createDirectory(Path cachePath) { } } - private String createBuilder(Path configPath, List buildX, ImageConfiguration imageConfig, BuildDirs buildDirs) throws MojoExecutionException { + protected String createBuilder(Path configPath, List buildX, ImageConfiguration imageConfig, BuildDirs buildDirs) throws MojoExecutionException { BuildXConfiguration buildXConfiguration = imageConfig.getBuildConfiguration().getBuildX(); String builderName = buildXConfiguration.getBuilderName(); if (builderName == null) { diff --git a/src/test/java/io/fabric8/maven/docker/service/BuildXServiceTest.java b/src/test/java/io/fabric8/maven/docker/service/BuildXServiceTest.java new file mode 100644 index 000000000..273812124 --- /dev/null +++ b/src/test/java/io/fabric8/maven/docker/service/BuildXServiceTest.java @@ -0,0 +1,132 @@ +package io.fabric8.maven.docker.service; + +import java.util.Arrays; +import java.util.List; +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.Mockito; +import org.mockito.quality.Strictness; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; + +import io.fabric8.maven.docker.access.DockerAccess; +import io.fabric8.maven.docker.access.AuthConfig; +import io.fabric8.maven.docker.assembly.DockerAssemblyManager; +import io.fabric8.maven.docker.util.Logger; +import io.fabric8.maven.docker.util.ProjectPaths; +import io.fabric8.maven.docker.config.BuildXConfiguration; +import io.fabric8.maven.docker.config.BuildImageConfiguration; +import io.fabric8.maven.docker.config.ImageConfiguration; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.WARN) +class BuildXServiceTest { + + private static final String NATIVE = "linux/amd64"; + private static final String FOREIGN1 = "linux/arm64"; + private static final String FOREIGN2 = "darwin/amd64"; + + @Mock + private DockerAccess dockerAccess; + + @Mock + private DockerAssemblyManager dockerAssemblyManager; + + @Mock + private Logger logger; + + @Mock + private BuildXService.Exec exec; + + @InjectMocks + @Spy + private BuildXService buildx; + + private ImageConfiguration imageConfig; + + private final ProjectPaths projectPaths = new ProjectPaths(new File("project-base-dir"), "output-dir"); + private final String configuredRegistry = "configured-registry"; + private final File buildArchive = new File("build-archive"); + private final AuthConfig authConfig = null; + + @BeforeEach + void setup() throws Exception { + + Mockito.when(dockerAccess.getNativePlatform()).thenReturn(NATIVE); + + Mockito.doNothing().when(buildx).createConfigJson(Mockito.any(), Mockito.any()); + Mockito.doNothing().when(buildx).removeConfigJson(Mockito.any()); + + Mockito.doReturn(Paths.get("docker-state-dir")).when(buildx).getDockerStateDir(Mockito.any(), Mockito.any()); + Mockito.doReturn("maven").when(buildx).createBuilder(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any()); + } + + @Test + void testBuildNativePlatform() throws Exception { + givenAnImageConfiguration(NATIVE); + mockBuildX(); + buildx.build(projectPaths, imageConfig, configuredRegistry, authConfig, buildArchive); + verifyBuildXPlatforms(NATIVE); + } + + @Test + void testBuildForeignPlatform() throws Exception { + givenAnImageConfiguration(FOREIGN1); + mockBuildX(); + buildx.build(projectPaths, imageConfig, configuredRegistry, authConfig, buildArchive); + verifyBuildXPlatforms(FOREIGN1); + } + + @Test + void testBuildNativePlatformWithForeign() throws Exception { + givenAnImageConfiguration(NATIVE, FOREIGN1); + mockBuildX(); + buildx.build(projectPaths, imageConfig, configuredRegistry, authConfig, buildArchive); + verifyBuildXPlatforms(NATIVE); + } + + @Test + void testBuildForeignPlatforms() throws Exception { + givenAnImageConfiguration(FOREIGN1, FOREIGN2); + buildx.build(projectPaths, imageConfig, configuredRegistry, authConfig, buildArchive); + Mockito.verify(buildx, Mockito.times(0)).buildX(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), + Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any()); + } + + private void givenAnImageConfiguration(String... platforms) { + + final BuildXConfiguration buildxConfig = new BuildXConfiguration.Builder() + .platforms(Arrays.asList(platforms)) + .build(); + + final BuildImageConfiguration buildImageConfig = new BuildImageConfiguration.Builder() + .buildx(buildxConfig) + .build(); + + imageConfig = new ImageConfiguration.Builder() + .name("build-image") + .buildConfig(buildImageConfig) + .build(); + } + + private void mockBuildX() throws Exception { + Mockito.doNothing().when(buildx).buildX(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), + Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any()); + } + + private void verifyBuildXPlatforms(String... platforms) throws Exception { + final List expect = Arrays.asList(platforms); + Mockito.verify(buildx).buildX(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), + Mockito.argThat(l -> expect.equals(l)), Mockito.any(), Mockito.any()); + } +}