From 9acda06b0852a507cf8305ca8ade95f66a0523fe Mon Sep 17 00:00:00 2001 From: Rohan Kumar Date: Mon, 27 Nov 2023 12:07:55 +0530 Subject: [PATCH] feat (jkube-kit/common) : Add IoUtil.downloadArchive method to download archives (#2454) + Refactor IoUtil.download method to be able to extract response body for further consumption + Add IoUtil.downloadArchive method to download and extract archive to specified folder Signed-off-by: Rohan Kumar --- .../eclipse/jkube/kit/common/util/IoUtil.java | 42 ++++++--- .../jkube/kit/common/util/IoUtilTest.java | 89 ++++++++++++++++++ .../foo-v0.0.1-linux.tgz | Bin 0 -> 150 bytes .../foo-v0.0.1-windows.zip | Bin 0 -> 164 bytes 4 files changed, 120 insertions(+), 11 deletions(-) create mode 100644 jkube-kit/common/src/test/resources/downloadable-artifacts/foo-v0.0.1-linux.tgz create mode 100644 jkube-kit/common/src/test/resources/downloadable-artifacts/foo-v0.0.1-windows.zip diff --git a/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/IoUtil.java b/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/IoUtil.java index 948aa9764a..8532802aa9 100644 --- a/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/IoUtil.java +++ b/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/IoUtil.java @@ -33,6 +33,7 @@ import org.eclipse.jkube.kit.common.KitLogger; import static org.apache.commons.io.IOUtils.EOF; +import static org.eclipse.jkube.kit.common.archive.ArchiveDecompressor.extractArchive; /** * @@ -54,14 +55,12 @@ private IoUtil() { } * @throws IOException IO Exception */ public static void download(KitLogger log, URL downloadUrl, File target) throws IOException { - log.progressStart(); - try (HttpClient client = HttpClientUtils.createHttpClient(Config.empty()).newBuilder().build()) { - final HttpResponse response = client.sendAsync( - client.newHttpRequestBuilder().timeout(30, TimeUnit.MINUTES).url(downloadUrl).build(), InputStream.class) - .get(); - final int length = Integer.parseInt(response.headers(StandardHttpHeaders.CONTENT_LENGTH) - .stream().findAny().orElse("-1")); + try (HttpClient httpClient = HttpClientUtils.getHttpClientFactory().newBuilder(Config.empty()).build()) { + HttpResponse response = download(httpClient, downloadUrl); try (OutputStream out = Files.newOutputStream(target.toPath()); InputStream is = response.body()) { + log.progressStart(); + final int length = Integer.parseInt(response.headers(StandardHttpHeaders.CONTENT_LENGTH) + .stream().findAny().orElse("-1")); final byte[] buffer = new byte[8192]; long readBytes = 0; int len; @@ -70,14 +69,35 @@ public static void download(KitLogger log, URL downloadUrl, File target) throws log.progressUpdate(target.getName(), "Downloading", getProgressBar(readBytes, length)); out.write(buffer, 0, len); } + } finally { + log.progressFinished(); + } + } + } + + public static void downloadArchive(URL downloadUrl, File target) throws IOException { + try (HttpClient httpClient = HttpClientUtils.getHttpClientFactory().newBuilder(Config.empty()).build()){ + HttpResponse response = download(httpClient, downloadUrl); + try (InputStream is = response.body()) { + extractArchive(is, target); + } + } + } + + private static HttpResponse download(HttpClient httpClient, URL downloadUrl) throws IOException { + try { + final HttpResponse response = httpClient.sendAsync( + httpClient.newHttpRequestBuilder().timeout(30, TimeUnit.MINUTES).url(downloadUrl).build(), InputStream.class) + .get(); + if (response.isSuccessful()) { + return response; } + throw new IllegalStateException("Got (" + response.code() + ") while downloading from URL " + downloadUrl); } catch(InterruptedException ex) { Thread.currentThread().interrupt(); throw new IOException("Download interrupted", ex); - } catch (IOException | ExecutionException e) { - throw new IOException("Failed to download URL " + downloadUrl + " to " + target + ": " + e, e); - } finally { - log.progressFinished(); + } catch (ExecutionException e) { + throw new IOException("Failed to download from URL " + downloadUrl, e); } } diff --git a/jkube-kit/common/src/test/java/org/eclipse/jkube/kit/common/util/IoUtilTest.java b/jkube-kit/common/src/test/java/org/eclipse/jkube/kit/common/util/IoUtilTest.java index a3ca3e0d0f..cc2621c379 100644 --- a/jkube-kit/common/src/test/java/org/eclipse/jkube/kit/common/util/IoUtilTest.java +++ b/jkube-kit/common/src/test/java/org/eclipse/jkube/kit/common/util/IoUtilTest.java @@ -13,15 +13,34 @@ */ package org.eclipse.jkube.kit.common.util; +import java.io.File; import java.io.IOException; import java.net.ServerSocket; +import java.net.URL; +import org.eclipse.jkube.kit.common.KitLogger; +import org.eclipse.jkube.kit.common.TestHttpStaticServer; +import org.eclipse.jkube.kit.common.assertj.FileAssertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalStateException; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; class IoUtilTest { + @TempDir + private File temporaryFolder; + + private KitLogger kitLogger; + + @BeforeEach + void setUp() { + kitLogger = spy(new KitLogger.SilentLogger()); + } @Test void findOpenPort() throws IOException { @@ -88,4 +107,74 @@ void testSanitizeFileName() { assertThat(IoUtil.sanitizeFileName("s2i-env-docker.io/fabric8/java:latest")).isEqualTo("s2i-env-docker-io-fabric8-java-latest"); } + @Test + void download_whenRemoteFragmentProvided_thenDownloadToSpecifiedDir() throws IOException { + File remoteDirectory = new File(getClass().getResource("/remote-resources").getFile()); + try (TestHttpStaticServer http = new TestHttpStaticServer(remoteDirectory)) { + // Given + URL downloadUrl = new URL(String.format("http://localhost:%d/deployment.yaml", http.getPort())); + + // When + IoUtil.download(kitLogger, downloadUrl, new File(temporaryFolder, "deployment.yaml")); + + // Then + verify(kitLogger).progressStart(); + verify(kitLogger).progressFinished(); + FileAssertions.assertThat(temporaryFolder) + .exists() + .fileTree() + .containsExactlyInAnyOrder("deployment.yaml"); + } + } + + @Test + void downloadArchive_whenUnixArtifactProvided_thenDownloadAndExtract() throws IOException { + File remoteDirectory = new File(getClass().getResource("/downloadable-artifacts").getFile()); + try (TestHttpStaticServer http = new TestHttpStaticServer(remoteDirectory)) { + // Given + URL downloadUrl = new URL(String.format("http://localhost:%d/foo-v0.0.1-linux.tgz", http.getPort())); + + // When + IoUtil.downloadArchive(downloadUrl, temporaryFolder); + + // Then + FileAssertions.assertThat(temporaryFolder) + .exists() + .fileTree() + .containsExactlyInAnyOrder("linux-amd64", "linux-amd64/foo"); + } + } + + @Test + void downloadArchive_whenZipArtifactProvided_thenDownloadAndExtract() throws IOException { + File remoteDirectory = new File(getClass().getResource("/downloadable-artifacts").getFile()); + try (TestHttpStaticServer http = new TestHttpStaticServer(remoteDirectory)) { + // Given + URL downloadUrl = new URL(String.format("http://localhost:%d/foo-v0.0.1-windows.zip", http.getPort())); + + // When + IoUtil.downloadArchive(downloadUrl, temporaryFolder); + + // Then + FileAssertions.assertThat(temporaryFolder) + .exists() + .fileTree() + .containsExactlyInAnyOrder("foo.exe"); + } + } + + @Test + void downloadArchive_whenArtifactNotAvailable_thenThrowException() throws IOException { + File remoteDirectory = new File(getClass().getResource("/downloadable-artifacts").getFile()); + try (TestHttpStaticServer http = new TestHttpStaticServer(remoteDirectory)) { + // Given + URL downloadUrl = new URL(String.format("http://localhost:%d/idontexist-v0.0.1-linux.tgz", http.getPort())); + + // When + Then + assertThatIllegalStateException() + .isThrownBy(() -> IoUtil.downloadArchive(downloadUrl, temporaryFolder)) + .withMessageContaining("Got (404) while downloading from URL "); + } + } + } diff --git a/jkube-kit/common/src/test/resources/downloadable-artifacts/foo-v0.0.1-linux.tgz b/jkube-kit/common/src/test/resources/downloadable-artifacts/foo-v0.0.1-linux.tgz new file mode 100644 index 0000000000000000000000000000000000000000..a591d0be5a88b1bbb01c367ff44654cfbe8c732d GIT binary patch literal 150 zcmb2|=3oE==C>CQaxp0iG$hI&74ML_bMd*LQb(Dv&cfsQwk$$Ar5`tZsh@6X@!)`c zeBReekJFky?#3O_u2;=eSG|5dd!pywmKFQnc9ttjtX|Cb>gsQ0(QMz7*LN-1wDbGh w+U3vI{kMFsSpVmq{fe$F|5jz!n?ISwUw=;?Vl{+3P`8(1?(KuQ3>pj!0Ni3ha{vGU literal 0 HcmV?d00001 diff --git a/jkube-kit/common/src/test/resources/downloadable-artifacts/foo-v0.0.1-windows.zip b/jkube-kit/common/src/test/resources/downloadable-artifacts/foo-v0.0.1-windows.zip new file mode 100644 index 0000000000000000000000000000000000000000..13c037c48b11b430ed0c03ee28f8a65055418268 GIT binary patch literal 164 zcmWIWW@h1H0D-$f)!|?UlwfC&VMxo**GsKP4GrOBU|y+^k_y7572FJrEH9WD7{Ek; nHzSiAGcF?};3mFp1ToK>=eSx$ih{FH?yb&3Y literal 0 HcmV?d00001