Skip to content

Commit c042dbf

Browse files
authored
Adds Downloader. (#3)
1 parent a3efc99 commit c042dbf

6 files changed

Lines changed: 223 additions & 0 deletions

File tree

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright 2018 Google LLC. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
17+
package com.google.cloud.tools.skaffold.downloader;
18+
19+
import com.google.cloud.tools.skaffold.filesystem.OperatingSystem;
20+
import com.google.common.io.CharStreams;
21+
import com.google.common.io.Resources;
22+
import java.io.IOException;
23+
import java.io.InputStreamReader;
24+
import java.net.URL;
25+
import java.nio.charset.StandardCharsets;
26+
import java.nio.file.Path;
27+
import java.util.ArrayList;
28+
import java.util.Arrays;
29+
import java.util.List;
30+
import org.hamcrest.CoreMatchers;
31+
import org.junit.Assert;
32+
import org.junit.Assume;
33+
import org.junit.Rule;
34+
import org.junit.Test;
35+
import org.junit.rules.TemporaryFolder;
36+
37+
/** Integration tests for {@link Downloader}. */
38+
public class DownloaderIntegationTest {
39+
40+
private static String downloadAndRun(URL url, Path destination, String... command)
41+
throws IOException, InterruptedException {
42+
// Downloads a script that says "hello".
43+
Downloader.download(url, destination, 1);
44+
Assert.assertTrue(destination.toFile().setExecutable(true));
45+
46+
// Runs the downloaded script.
47+
List<String> commandList = new ArrayList<>(Arrays.asList(command));
48+
commandList.add(destination.toString());
49+
Process process = new ProcessBuilder(commandList).start();
50+
String stdout =
51+
CharStreams.toString(
52+
new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8));
53+
String stderr =
54+
CharStreams.toString(
55+
new InputStreamReader(process.getErrorStream(), StandardCharsets.UTF_8));
56+
Assert.assertEquals("", stderr);
57+
Assert.assertEquals(0, process.waitFor());
58+
return stdout;
59+
}
60+
61+
@Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder();
62+
63+
@Test
64+
public void testDownload() throws IOException, InterruptedException {
65+
Assume.assumeTrue("non-Windows test", OperatingSystem.resolve() != OperatingSystem.WINDOWS);
66+
67+
Assert.assertEquals(
68+
"hello\n",
69+
downloadAndRun(
70+
Resources.getResource("helloScript.sh"),
71+
temporaryFolder.newFolder().toPath().resolve("hello.sh"),
72+
System.getenv("SHELL")));
73+
}
74+
75+
@Test
76+
public void testDownload_windows() throws IOException, InterruptedException {
77+
Assume.assumeTrue("Windows test", OperatingSystem.resolve() == OperatingSystem.WINDOWS);
78+
79+
Assert.assertThat(
80+
downloadAndRun(
81+
Resources.getResource("helloScript.bat"),
82+
temporaryFolder.newFolder().toPath().resolve("hello.bat"),
83+
"cmd",
84+
"/c"),
85+
CoreMatchers.containsString("hello world"));
86+
}
87+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright 2018 Google LLC. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
17+
package com.google.cloud.tools.skaffold.downloader;
18+
19+
import com.google.common.annotations.VisibleForTesting;
20+
import java.io.BufferedInputStream;
21+
import java.io.IOException;
22+
import java.io.InputStream;
23+
import java.net.URL;
24+
import java.net.URLConnection;
25+
import java.nio.channels.Channels;
26+
import java.nio.channels.FileChannel;
27+
import java.nio.channels.ReadableByteChannel;
28+
import java.nio.file.Path;
29+
import java.nio.file.StandardOpenOption;
30+
31+
/** Downloads files. */
32+
public class Downloader {
33+
34+
/**
35+
* Downloads to a destination file.
36+
*
37+
* @param url the {@link URL} to download
38+
* @param destination the destination file to download to
39+
* @return the size of the downloaded contents, or -1 if {@code Content-Length} is unknown and
40+
* thus nothing downloaded
41+
* @throws IOException if an I/O exception occurred during the download process
42+
*/
43+
public static long download(URL url, Path destination) throws IOException {
44+
return download(url, destination, Long.MAX_VALUE);
45+
}
46+
47+
@VisibleForTesting
48+
static long download(URL url, Path destination, long chunkSize) throws IOException {
49+
URLConnection connection = url.openConnection();
50+
try (FileChannel fileChannel =
51+
FileChannel.open(destination, StandardOpenOption.WRITE, StandardOpenOption.CREATE);
52+
InputStream connectionInputStream = new BufferedInputStream(connection.getInputStream());
53+
ReadableByteChannel urlChannel = Channels.newChannel(connectionInputStream)) {
54+
long totalSize = connection.getContentLengthLong();
55+
while (fileChannel.position() < totalSize) {
56+
fileChannel.position(
57+
fileChannel.position()
58+
+ fileChannel.transferFrom(urlChannel, fileChannel.position(), chunkSize));
59+
}
60+
return totalSize;
61+
}
62+
}
63+
64+
private Downloader() {}
65+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright 2018 Google LLC. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
17+
package com.google.cloud.tools.skaffold.downloader;
18+
19+
import java.io.ByteArrayInputStream;
20+
import java.io.IOException;
21+
import java.io.InputStream;
22+
import java.net.URL;
23+
import java.net.URLConnection;
24+
import java.nio.file.Files;
25+
import java.nio.file.Path;
26+
import org.junit.Assert;
27+
import org.junit.Rule;
28+
import org.junit.Test;
29+
import org.junit.rules.TemporaryFolder;
30+
import org.junit.runner.RunWith;
31+
import org.mockito.Mock;
32+
import org.mockito.Mockito;
33+
import org.mockito.junit.MockitoJUnitRunner;
34+
35+
/** Test for {@link Downloader}. */
36+
@RunWith(MockitoJUnitRunner.class)
37+
public class DownloaderTest {
38+
39+
@Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder();
40+
41+
@Mock private URL mockURL;
42+
@Mock private URLConnection mockURLConnection;
43+
44+
@Test
45+
public void testDownload_newFile() throws IOException {
46+
downloadToFile(temporaryFolder.newFolder().toPath().resolve("nonexistent"));
47+
}
48+
49+
@Test
50+
public void testDownload_overwrite() throws IOException {
51+
downloadToFile(temporaryFolder.newFile().toPath());
52+
}
53+
54+
private void downloadToFile(Path destination) throws IOException {
55+
byte[] expectedDownloadContents = new byte[] {0x11, 0x22, 0x33, 0x44, 0x55};
56+
long expectedSize = expectedDownloadContents.length;
57+
InputStream fakeInputStream = new ByteArrayInputStream(expectedDownloadContents);
58+
Mockito.when(mockURL.openConnection()).thenReturn(mockURLConnection);
59+
Mockito.when(mockURLConnection.getInputStream()).thenReturn(fakeInputStream);
60+
Mockito.when(mockURLConnection.getContentLengthLong()).thenReturn(expectedSize);
61+
62+
long size = Downloader.download(mockURL, destination, 1);
63+
Assert.assertEquals(expectedSize, size);
64+
Assert.assertArrayEquals(expectedDownloadContents, Files.readAllBytes(destination));
65+
}
66+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
echo "hello world"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#! /bin/sh
2+
3+
echo "hello"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
mock-maker-inline

0 commit comments

Comments
 (0)