Skip to content

Commit 60c8dfb

Browse files
committed
add method to get downloaded files with meta-info from Grid
To track the downloading progress and wait for the full download completion, we need to know this info about downloaded files: 1. File modification time 2. File size
1 parent 209ad97 commit 60c8dfb

File tree

4 files changed

+107
-20
lines changed

4 files changed

+107
-20
lines changed

java/src/org/openqa/selenium/HasDownloads.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,13 @@ static boolean isDownloadsEnabled(Capabilities capabilities) {
5757
*/
5858
List<String> getDownloadableFiles();
5959

60+
/**
61+
* Gets all files downloaded by browser.
62+
*
63+
* @return a list of files with their name, size and time.
64+
*/
65+
List<DownloadedFile> getDownloadedFiles();
66+
6067
/**
6168
* Downloads a file to a given location.
6269
*
@@ -68,4 +75,34 @@ static boolean isDownloadsEnabled(Capabilities capabilities) {
6875

6976
/** Deletes the downloadable files. */
7077
void deleteDownloadableFiles();
78+
79+
class DownloadedFile {
80+
private final String name;
81+
private final long creationTime;
82+
private final long lastModifiedTime;
83+
private final long size;
84+
85+
public DownloadedFile(String name, long creationTime, long lastModifiedTime, long size) {
86+
this.name = name;
87+
this.creationTime = creationTime;
88+
this.lastModifiedTime = lastModifiedTime;
89+
this.size = size;
90+
}
91+
92+
public String getName() {
93+
return name;
94+
}
95+
96+
public long getCreationTime() {
97+
return creationTime;
98+
}
99+
100+
public long getLastModifiedTime() {
101+
return lastModifiedTime;
102+
}
103+
104+
public long getSize() {
105+
return size;
106+
}
107+
}
71108
}

java/src/org/openqa/selenium/grid/node/local/LocalNode.java

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
package org.openqa.selenium.grid.node.local;
1919

2020
import static com.google.common.collect.ImmutableSet.toImmutableSet;
21+
import static java.nio.file.Files.readAttributes;
22+
import static org.openqa.selenium.HasDownloads.DownloadedFile;
2123
import static org.openqa.selenium.concurrent.ExecutorServices.shutdownGracefully;
2224
import static org.openqa.selenium.grid.data.Availability.DOWN;
2325
import static org.openqa.selenium.grid.data.Availability.DRAINING;
@@ -44,6 +46,7 @@
4446
import java.io.UncheckedIOException;
4547
import java.net.URI;
4648
import java.net.URISyntaxException;
49+
import java.nio.file.attribute.BasicFileAttributes;
4750
import java.time.Clock;
4851
import java.time.Duration;
4952
import java.time.Instant;
@@ -753,15 +756,32 @@ public HttpResponse downloadFile(HttpRequest req, SessionId id) {
753756

754757
/** User wants to list files that can be downloaded */
755758
private HttpResponse listDownloadedFiles(File downloadsDirectory) {
756-
List<String> collected =
757-
Arrays.stream(Optional.ofNullable(downloadsDirectory.listFiles()).orElse(new File[] {}))
758-
.map(File::getName)
759-
.collect(Collectors.toList());
760-
Map<String, Object> data = Map.of("names", collected);
759+
File[] files = Optional.ofNullable(downloadsDirectory.listFiles()).orElse(new File[] {});
760+
List<String> fileNames = Arrays.stream(files).map(File::getName).collect(Collectors.toList());
761+
List<DownloadedFile> fileInfos =
762+
Arrays.stream(files).map(this::getFileInfo).collect(Collectors.toList());
763+
764+
Map<String, Object> data =
765+
Map.of(
766+
"names", fileNames,
767+
"files", fileInfos);
761768
Map<String, Map<String, Object>> result = Map.of("value", data);
762769
return new HttpResponse().setContent(asJson(result));
763770
}
764771

772+
private DownloadedFile getFileInfo(File file) {
773+
try {
774+
BasicFileAttributes attributes = readAttributes(file.toPath(), BasicFileAttributes.class);
775+
return new DownloadedFile(
776+
file.getName(),
777+
attributes.creationTime().toMillis(),
778+
attributes.lastModifiedTime().toMillis(),
779+
attributes.size());
780+
} catch (IOException e) {
781+
throw new RuntimeException("Failed to get file attributes: " + file.getAbsolutePath(), e);
782+
}
783+
}
784+
765785
private HttpResponse getDownloadedFile(HttpRequest req, File downloadsDirectory)
766786
throws IOException {
767787
String raw = string(req);

java/src/org/openqa/selenium/remote/RemoteWebDriver.java

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static java.util.Collections.singleton;
2121
import static java.util.concurrent.TimeUnit.SECONDS;
2222
import static java.util.logging.Level.SEVERE;
23+
import static org.openqa.selenium.HasDownloads.DownloadedFile;
2324
import static org.openqa.selenium.remote.CapabilityType.PLATFORM_NAME;
2425

2526
import java.io.IOException;
@@ -672,9 +673,9 @@ public boolean isDownloadsEnabled() {
672673
}
673674

674675
/**
675-
* Retrieves the names of the downloadable files.
676+
* Retrieves the names of the files downloaded by browser.
676677
*
677-
* @return A list containing the names of the downloadable files.
678+
* @return A list containing the names of the downloaded files.
678679
* @throws WebDriverException if capability to enable downloads is not set
679680
*/
680681
@Override
@@ -683,8 +684,27 @@ public List<String> getDownloadableFiles() {
683684
requireDownloadsEnabled(capabilities);
684685

685686
Response response = execute(DriverCommand.GET_DOWNLOADABLE_FILES);
686-
Map<String, List<String>> value = (Map<String, List<String>>) response.getValue();
687-
return value.get("names");
687+
Map<String, Object> value = (Map<String, Object>) response.getValue();
688+
return (List<String>) value.get("names");
689+
}
690+
691+
@Override
692+
@SuppressWarnings("unchecked")
693+
public List<DownloadedFile> getDownloadedFiles() {
694+
requireDownloadsEnabled(capabilities);
695+
696+
Response response = execute(DriverCommand.GET_DOWNLOADABLE_FILES);
697+
Map<String, Object> value = (Map<String, Object>) response.getValue();
698+
List<Map<String, Object>> files = (List<Map<String, Object>>) value.get("files");
699+
return files.stream()
700+
.map(
701+
file ->
702+
new DownloadedFile(
703+
(String) file.get("name"),
704+
(Long) file.get("creationTime"),
705+
(Long) file.get("lastModifiedTime"),
706+
(Long) file.get("size")))
707+
.collect(Collectors.toUnmodifiableList());
688708
}
689709

690710
/**

java/test/org/openqa/selenium/grid/router/RemoteWebDriverDownloadTest.java

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818
package org.openqa.selenium.grid.router;
1919

2020
import static org.assertj.core.api.Assertions.assertThat;
21+
import static org.openqa.selenium.HasDownloads.DownloadedFile;
2122
import static org.openqa.selenium.remote.CapabilityType.ENABLE_DOWNLOADS;
2223
import static org.openqa.selenium.testing.drivers.Browser.IE;
2324
import static org.openqa.selenium.testing.drivers.Browser.SAFARI;
2425

26+
import java.io.File;
2527
import java.io.IOException;
2628
import java.io.StringReader;
2729
import java.net.URL;
@@ -34,6 +36,8 @@
3436
import java.util.Set;
3537
import java.util.concurrent.ExecutorService;
3638
import java.util.concurrent.Executors;
39+
import java.util.stream.Collectors;
40+
3741
import org.junit.jupiter.api.AfterEach;
3842
import org.junit.jupiter.api.Assertions;
3943
import org.junit.jupiter.api.BeforeEach;
@@ -114,20 +118,24 @@ void canListDownloadedFiles() {
114118
driver.findElement(By.id("file-1")).click();
115119
driver.findElement(By.id("file-2")).click();
116120

121+
HasDownloads hasDownloads = (HasDownloads) driver;
117122
new WebDriverWait(driver, Duration.ofSeconds(5))
118123
.until(
119124
d ->
120-
((HasDownloads) d)
121-
.getDownloadableFiles().stream()
122-
// ensure we hit no temporary file created by the browser while
123-
// downloading
124-
.filter((f) -> FILE_EXTENSIONS.stream().anyMatch(f::endsWith))
125-
.count()
125+
hasDownloads.getDownloadableFiles().stream()
126+
// ensure we hit no temporary file created by the browser while
127+
// downloading
128+
.filter((f) -> FILE_EXTENSIONS.stream().anyMatch(f::endsWith))
129+
.count()
126130
== 2);
127131

128-
List<String> downloadableFiles = ((HasDownloads) driver).getDownloadableFiles();
132+
List<String> downloadableFiles = hasDownloads.getDownloadableFiles();
129133
assertThat(downloadableFiles).contains("file_1.txt", "file_2.jpg");
130134

135+
List<DownloadedFile> downloadedFiles = hasDownloads.getDownloadedFiles();
136+
assertThat(downloadedFiles.stream().map(f -> f.getName()).collect(Collectors.toList()))
137+
.contains("file_1.txt", "file_2.jpg");
138+
131139
driver.quit();
132140
}
133141

@@ -150,13 +158,15 @@ void canDownloadFiles() throws IOException {
150158
// ensure we hit no temporary file created by the browser while downloading
151159
.anyMatch((f) -> FILE_EXTENSIONS.stream().anyMatch(f::endsWith)));
152160

153-
String fileName = ((HasDownloads) driver).getDownloadableFiles().get(0);
161+
DownloadedFile file = ((HasDownloads) driver).getDownloadedFiles().get(0);
154162

155163
Path targetLocation = Files.createTempDirectory("download");
156-
((HasDownloads) driver).downloadFile(fileName, targetLocation);
164+
((HasDownloads) driver).downloadFile(file.getName(), targetLocation);
157165

158-
String fileContent = String.join("", Files.readAllLines(targetLocation.resolve(fileName)));
159-
assertThat(fileContent).isEqualTo("Hello, World!");
166+
File localFile = targetLocation.resolve(file.getName()).toFile();
167+
assertThat(localFile).hasName(file.getName());
168+
assertThat(localFile).hasSize(file.getSize());
169+
assertThat(localFile).content().isEqualToIgnoringNewLines("Hello, World!");
160170

161171
driver.quit();
162172
}

0 commit comments

Comments
 (0)