diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/CliDockerClient.java b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/CliDockerClient.java index 035c9316f3..37d0e3ef2d 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/CliDockerClient.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/CliDockerClient.java @@ -277,11 +277,18 @@ public DockerImageDetails inspect(ImageReference imageReference) throws IOException, InterruptedException { Process inspectProcess = docker("inspect", "-f", "{{json .}}", "--type", "image", imageReference.toString()); - if (inspectProcess.waitFor() != 0) { - throw new IOException( - "'docker inspect' command failed with error: " + getStderrOutput(inspectProcess)); + + try (InputStreamReader stdout = + new InputStreamReader(inspectProcess.getInputStream(), StandardCharsets.UTF_8)) { + String output = CharStreams.toString(stdout); + + if (inspectProcess.waitFor() != 0) { + throw new IOException( + "'docker inspect' command failed with error: " + getStderrOutput(inspectProcess)); + } + + return JsonTemplateMapper.readJson(output, DockerImageDetails.class); } - return JsonTemplateMapper.readJson(inspectProcess.getInputStream(), DockerImageDetails.class); } /** Runs a {@code docker} command. */ @@ -291,11 +298,17 @@ private Process docker(String... subCommand) throws IOException { private DockerInfoDetails fetchInfoDetails() throws IOException, InterruptedException { Process infoProcess = docker("info", "-f", "{{json .}}"); - InputStream inputStream = infoProcess.getInputStream(); - if (infoProcess.waitFor() != 0) { - throw new IOException( - "'docker info' command failed with error: " + getStderrOutput(infoProcess)); + + try (InputStreamReader stdout = + new InputStreamReader(infoProcess.getInputStream(), StandardCharsets.UTF_8)) { + String output = CharStreams.toString(stdout); + + if (infoProcess.waitFor() != 0) { + throw new IOException( + "'docker info' command failed with error: " + getStderrOutput(infoProcess)); + } + + return JsonTemplateMapper.readJson(output, DockerInfoDetails.class); } - return JsonTemplateMapper.readJson(inputStream, DockerInfoDetails.class); } } diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/CliDockerClientTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/CliDockerClientTest.java index a88539f8c0..2b451ebe05 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/CliDockerClientTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/CliDockerClientTest.java @@ -113,6 +113,8 @@ public void testInfo_fail() throws InterruptedException { assertThat(subcommand).containsExactly("info", "-f", "{{json .}}"); return mockProcessBuilder; }); + Mockito.when(mockProcess.getInputStream()) + .thenReturn(new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8))); Mockito.when(mockProcess.waitFor()).thenReturn(1); Mockito.when(mockProcess.getErrorStream()) .thenReturn(new ByteArrayInputStream("error".getBytes(StandardCharsets.UTF_8))); @@ -123,6 +125,29 @@ public void testInfo_fail() throws InterruptedException { .contains("'docker info' command failed with error: error"); } + @Test + public void testInfo_stdinFail() throws InterruptedException { + DockerClient testDockerClient = + new CliDockerClient( + subcommand -> { + assertThat(subcommand).containsExactly("info", "-f", "{{json .}}"); + return mockProcessBuilder; + }); + Mockito.when(mockProcess.getInputStream()) + .thenReturn( + new InputStream() { + + @Override + public int read() throws IOException { + throw new IOException(); + } + }); + + assertThrows(IOException.class, testDockerClient::info); + + Mockito.verify(mockProcess, Mockito.never()).waitFor(); + } + @Test public void testInfo_returnsUnknownKeys() throws InterruptedException, IOException { String dockerInfoJson = "{ \"unknownOS\": \"windows\"," + "\"unknownArchitecture\": \"arm64\"}"; @@ -311,6 +336,8 @@ public void testSize_fail() throws InterruptedException { Assert.assertEquals("inspect", subcommand.get(0)); return mockProcessBuilder; }); + Mockito.when(mockProcess.getInputStream()) + .thenReturn(new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8))); Mockito.when(mockProcess.waitFor()).thenReturn(1); Mockito.when(mockProcess.getErrorStream()) @@ -325,6 +352,30 @@ public void testSize_fail() throws InterruptedException { } } + @Test + public void testSize_stdinFail() throws InterruptedException { + DockerClient testDockerClient = + new CliDockerClient( + subcommand -> { + Assert.assertEquals("inspect", subcommand.get(0)); + return mockProcessBuilder; + }); + Mockito.when(mockProcess.getInputStream()) + .thenReturn( + new InputStream() { + + @Override + public int read() throws IOException { + throw new IOException(); + } + }); + + assertThrows( + IOException.class, () -> testDockerClient.inspect(ImageReference.of(null, "image", null))); + + Mockito.verify(mockProcess, Mockito.never()).waitFor(); + } + @Test public void testDockerImageDetails() throws DigestException, IOException { String json =