Skip to content

Commit

Permalink
replace plugin integration tests with unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mpeddada1 committed May 28, 2024
1 parent 8f81743 commit b399f5e
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 164 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,8 @@ private void buildAndCacheApplicationLayers(
BuildAndCacheApplicationLayerStep.makeList(buildContext, progressDispatcherFactory));
}

private void buildImages(ProgressEventDispatcher.Factory progressDispatcherFactory) {
@VisibleForTesting
void buildImages(ProgressEventDispatcher.Factory progressDispatcherFactory) {
results.baseImagesAndBuiltImages =
executorService.submit(
() -> {
Expand All @@ -431,7 +432,6 @@ private void buildImages(ProgressEventDispatcher.Factory progressDispatcherFacto
Image baseImage = entry.getKey();
List<Future<PreparedLayer>> baseLayers = entry.getValue();

// Image is immutable once built.
Future<Image> builtImage =
buildImage(baseImage, baseLayers, progressDispatcher.newChildProducer());
baseImagesAndBuiltImages.put(baseImage, builtImage);
Expand Down Expand Up @@ -657,7 +657,8 @@ private <E> List<Future<E>> scheduleCallables(ImmutableList<? extends Callable<E
return callables.stream().map(executorService::submit).collect(Collectors.toList());
}

private String computeArchitecture(String architecture) {
@VisibleForTesting
String computeArchitecture(String architecture) {
if (architecture.equals("x86_64")) {
return "amd64";
} else if (architecture.equals("aarch64")) {
Expand All @@ -666,11 +667,14 @@ private String computeArchitecture(String architecture) {
return architecture;
}

private Optional<Image> fetchBuiltImageForLocalBuild(String osType, String architecture)
@VisibleForTesting
Optional<Image> fetchBuiltImageForLocalBuild(String osType, String architecture)
throws InterruptedException, ExecutionException {
if (results.baseImagesAndBuiltImages.get().size() > 1) {
LOGGER.warning(
"Detected multi-platform configuration, only building the one that matches the local Docker Engine's os and architecture");
String.format(
"Detected multi-platform configuration, only building the one that matches the local Docker Engine's os and architecture (%s/%s)",
osType, architecture));
}
for (Map.Entry<Image, Future<Image>> imageEntry :
results.baseImagesAndBuiltImages.get().entrySet()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

package com.google.cloud.tools.jib.builder.steps;

import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;

import com.google.cloud.tools.jib.api.DescriptorDigest;
import com.google.cloud.tools.jib.builder.ProgressEventDispatcher;
import com.google.cloud.tools.jib.builder.steps.PullBaseImageStep.ImagesAndRegistryClient;
Expand All @@ -26,6 +29,7 @@
import com.google.cloud.tools.jib.image.json.ManifestTemplate;
import com.google.cloud.tools.jib.registry.ManifestAndDigest;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.util.concurrent.ForwardingExecutorService;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
Expand Down Expand Up @@ -90,14 +94,14 @@ protected ExecutorService delegate() {
public void setup() {
stepsRunner = new StepsRunner(new MockListeningExecutorService(), buildContext);

Mockito.when(progressDispatcherFactory.create(Mockito.anyString(), Mockito.anyLong()))
when(progressDispatcherFactory.create(Mockito.anyString(), Mockito.anyLong()))
.thenReturn(progressDispatcher);
}

@Test
public void testObtainBaseImageLayers_skipObtainingDuplicateLayers()
throws DigestException, InterruptedException, ExecutionException {
Mockito.when(executorService.submit(Mockito.any(PullBaseImageStep.class)))
when(executorService.submit(Mockito.any(PullBaseImageStep.class)))
.thenReturn(Futures.immediateFuture(new ImagesAndRegistryClient(null, null)));
// Pretend that a thread pulling base images returned some (meaningless) result.
stepsRunner.pullBaseImages(progressDispatcherFactory);
Expand All @@ -118,7 +122,7 @@ public void testObtainBaseImageLayers_skipObtainingDuplicateLayers()
PreparedLayer preparedLayer1 = Mockito.mock(PreparedLayer.class);
PreparedLayer preparedLayer2 = Mockito.mock(PreparedLayer.class);
PreparedLayer preparedLayer3 = Mockito.mock(PreparedLayer.class);
Mockito.when(executorService.submit(Mockito.any(ObtainBaseImageLayerStep.class)))
when(executorService.submit(Mockito.any(ObtainBaseImageLayerStep.class)))
.thenReturn(Futures.immediateFuture(preparedLayer1))
.thenReturn(Futures.immediateFuture(preparedLayer2))
.thenReturn(Futures.immediateFuture(preparedLayer3));
Expand All @@ -127,7 +131,7 @@ public void testObtainBaseImageLayers_skipObtainingDuplicateLayers()

// 1. Should schedule two threads to obtain new layers.
Image image = Mockito.mock(Image.class);
Mockito.when(image.getLayers()).thenReturn(ImmutableList.of(layer1, layer2));
when(image.getLayers()).thenReturn(ImmutableList.of(layer1, layer2));

stepsRunner.obtainBaseImageLayers(image, true, preparedLayersCache, progressDispatcherFactory);
Assert.assertEquals(2, preparedLayersCache.size()); // two new layers cached
Expand All @@ -141,7 +145,7 @@ public void testObtainBaseImageLayers_skipObtainingDuplicateLayers()
Assert.assertEquals(preparedLayer2, preparedLayersCache.get(digest2).get());

// 3. Another image with one duplicate layer.
Mockito.when(image.getLayers()).thenReturn(ImmutableList.of(layer3, layer2));
when(image.getLayers()).thenReturn(ImmutableList.of(layer3, layer2));
stepsRunner.obtainBaseImageLayers(image, true, preparedLayersCache, progressDispatcherFactory);
Assert.assertEquals(3, preparedLayersCache.size()); // one new layer cached
Assert.assertEquals(preparedLayer1, preparedLayersCache.get(digest1).get());
Expand All @@ -156,7 +160,7 @@ public void testObtainBaseImageLayers_skipObtainingDuplicateLayers()
@Test
public void testIsImagePushed_skipExistingEnabledAndManifestPresent() {
Optional<ManifestAndDigest<ManifestTemplate>> manifestResult = Mockito.mock(Optional.class);
Mockito.when(manifestResult.isPresent()).thenReturn(true);
when(manifestResult.isPresent()).thenReturn(true);
System.setProperty(JibSystemProperties.SKIP_EXISTING_IMAGES, "true");

Assert.assertFalse(stepsRunner.isImagePushed(manifestResult));
Expand All @@ -174,8 +178,121 @@ public void testIsImagePushed_skipExistingImageDisabledAndManifestPresent() {
public void testIsImagePushed_skipExistingImageEnabledAndManifestNotPresent() {
Optional<ManifestAndDigest<ManifestTemplate>> manifestResult = Mockito.mock(Optional.class);
System.setProperty(JibSystemProperties.SKIP_EXISTING_IMAGES, "true");
Mockito.when(manifestResult.isPresent()).thenReturn(false);
when(manifestResult.isPresent()).thenReturn(false);

Assert.assertTrue(stepsRunner.isImagePushed(manifestResult));
}

@Test
public void testFetchBuildImageForLocalBuild_matchingOsAndArch()
throws ExecutionException, InterruptedException {
Image mockImage1 = Mockito.mock(Image.class);
Image mockImage2 = Mockito.mock(Image.class);
Image baseImage1 = Mockito.mock(Image.class);
Image baseImage2 = Mockito.mock(Image.class);
when(mockImage1.getArchitecture()).thenReturn("arch1");
when(mockImage1.getOs()).thenReturn("os1");
when(mockImage1.getArchitecture()).thenReturn("arch2");
when(mockImage1.getOs()).thenReturn("os2");

when(executorService.submit(Mockito.any(Callable.class)))
.thenReturn(
Futures.immediateFuture(
ImmutableMap.of(
baseImage1,
Futures.immediateFuture(mockImage1),
baseImage2,
Futures.immediateFuture(mockImage2))));
stepsRunner.buildImages(progressDispatcherFactory);
Optional<Image> expectedImage = stepsRunner.fetchBuiltImageForLocalBuild("os2", "arch2");

assertThat(expectedImage.get().getOs()).isEqualTo("os2");
assertThat(expectedImage.get().getArchitecture()).isEqualTo("arch2");
}

@Test
public void testFetchBuildImageForLocalBuild_differentOsAndArch()
throws ExecutionException, InterruptedException {
Image builtImage1 = Mockito.mock(Image.class);
Image builtImage2 = Mockito.mock(Image.class);
Image baseImage1 = Mockito.mock(Image.class);
Image baseImage2 = Mockito.mock(Image.class);
when(builtImage1.getArchitecture()).thenReturn("os1");
when(builtImage1.getOs()).thenReturn("arch1");
when(builtImage2.getArchitecture()).thenReturn("os2");
when(builtImage2.getOs()).thenReturn("arch2");
when(executorService.submit(Mockito.any(Callable.class)))
.thenReturn(
Futures.immediateFuture(
ImmutableMap.of(
baseImage1,
Futures.immediateFuture(builtImage1),
baseImage2,
Futures.immediateFuture(builtImage2))));
stepsRunner.buildImages(progressDispatcherFactory);
Optional<Image> expectedImage = stepsRunner.fetchBuiltImageForLocalBuild("linux", "arm64");

assertThat(expectedImage.isPresent()).isFalse();
}

@Test
public void testFetchBuildImageForLocalBuild_matchingOSDifferentArch()
throws ExecutionException, InterruptedException {
Image builtImage1 = Mockito.mock(Image.class);
Image builtImage2 = Mockito.mock(Image.class);
Image baseImage1 = Mockito.mock(Image.class);
Image baseImage2 = Mockito.mock(Image.class);
when(builtImage1.getArchitecture()).thenReturn("arch1");
when(builtImage1.getOs()).thenReturn("os1");
when(builtImage2.getArchitecture()).thenReturn("arch2");
when(builtImage2.getOs()).thenReturn("os1");
when(executorService.submit(Mockito.any(Callable.class)))
.thenReturn(
Futures.immediateFuture(
ImmutableMap.of(
baseImage1,
Futures.immediateFuture(builtImage1),
baseImage2,
Futures.immediateFuture(builtImage2))));
stepsRunner.buildImages(progressDispatcherFactory);
Optional<Image> expectedImage = stepsRunner.fetchBuiltImageForLocalBuild("os1", "arch3");

assertThat(expectedImage.isPresent()).isFalse();
}

@Test
public void testFetchBuildImageForLocalBuild_differentOSMatchingArch()
throws ExecutionException, InterruptedException {
Image builtImage1 = Mockito.mock(Image.class);
Image builtImage2 = Mockito.mock(Image.class);
Image baseImage1 = Mockito.mock(Image.class);
Image baseImage2 = Mockito.mock(Image.class);
when(builtImage1.getArchitecture()).thenReturn("arch1");
when(builtImage1.getOs()).thenReturn("os1");
when(builtImage2.getArchitecture()).thenReturn("arch2");
when(builtImage2.getOs()).thenReturn("os2");
when(executorService.submit(Mockito.any(Callable.class)))
.thenReturn(
Futures.immediateFuture(
ImmutableMap.of(
baseImage1,
Futures.immediateFuture(builtImage1),
baseImage2,
Futures.immediateFuture(builtImage2))));
stepsRunner.buildImages(progressDispatcherFactory);

Optional<Image> expectedImage = stepsRunner.fetchBuiltImageForLocalBuild("os3", "arch1");

assertThat(expectedImage.isPresent()).isFalse();
}

@Test
public void testComputeArchitecture_aarch64() {
assertThat(stepsRunner.computeArchitecture("aarch64")).isEqualTo("arm64");
}

@Test
public void testComputeArchitecture_x86_64() {
assertThat(stepsRunner.computeArchitecture("x86_64")).isEqualTo("amd64");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -592,28 +592,4 @@ public void testCredHelperConfiguration()
simpleTestProject, targetImage, "build-cred-helper.gradle"))
.isEqualTo("Hello, world. \n1970-01-01T00:00:01Z\n");
}

@Test
public void testToDockerDaemon_multiPlatform()
throws DigestException, IOException, InterruptedException {
String targetImage = "multiplatform:gradle" + System.nanoTime();
assertThat(
JibRunHelper.buildToDockerDaemonAndRun(
simpleTestProject, targetImage, "build-multi-platform.gradle"))
.isEqualTo("Hello, world. \n1970-01-01T00:00:01Z\n");
}

@Test
public void testToDockerDaemon_multiPlatform_invalid() {
String targetImage = "multiplatform:gradle" + System.nanoTime();
UnexpectedBuildFailure exception =
assertThrows(
UnexpectedBuildFailure.class,
() ->
JibRunHelper.buildToDockerDaemonAndRun(
simpleTestProject, targetImage, "build-multi-platform-invalid.gradle"));
assertThat(exception)
.hasMessageThat()
.contains("The configured platforms don't match the Docker Engine's OS and architecture");
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package com.google.cloud.tools.jib.maven;

import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;

import com.google.cloud.tools.jib.Command;
import java.io.IOException;
Expand Down Expand Up @@ -276,29 +275,4 @@ public void testCredHelperConfigurationComplex()
"Hello, world. \n1970-01-01T00:00:01Z\n",
new Command("docker", "run", "--rm", targetImage).run());
}

@Test
public void testMultiPlatform()
throws DigestException, VerificationException, IOException, InterruptedException {
String targetImage = "multiplatformproject:maven" + System.nanoTime();
buildToDockerDaemon(simpleTestProject, targetImage, "pom-multiplatform-build.xml");
Assert.assertEquals(
"Hello, world. \n1970-01-01T00:00:01Z\n",
new Command("docker", "run", "--rm", targetImage).run());
}

@Test
public void testMultiPlatform_invalidPlatforms()
throws DigestException, VerificationException, IOException, InterruptedException {
String targetImage = "multiplatformproject:maven" + System.nanoTime();
VerificationException exception =
assertThrows(
VerificationException.class,
() ->
buildToDockerDaemon(
simpleTestProject, targetImage, "pom-multiplatform-invalid-platforms.xml"));
assertThat(exception)
.hasMessageThat()
.contains("The configured platforms don't match the Docker Engine's OS and architecture");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
<version>${jib-maven-plugin.version}</version>
<configuration>
<from>
<image>eclipse-temurin:11</image>
<image>busybox@sha256:4f47c01fa91355af2865ac10fef5bf6ec9c7f42ad2321377c21e844427972977</image>
<platforms>
<platform>
<architecture>arm64</architecture>
Expand Down
Loading

0 comments on commit b399f5e

Please sign in to comment.