• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 Google LLC
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of 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,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.google.android.libraries.mobiledatadownload.testing;
17 
18 import static com.google.common.util.concurrent.Futures.immediateFailedFuture;
19 import static com.google.common.util.concurrent.Futures.immediateVoidFuture;
20 
21 import android.net.Uri;
22 import com.google.android.libraries.mobiledatadownload.downloader.DownloadConstraints;
23 import com.google.android.libraries.mobiledatadownload.downloader.DownloadRequest;
24 import com.google.android.libraries.mobiledatadownload.downloader.FileDownloader;
25 import com.google.android.libraries.mobiledatadownload.file.SynchronousFileStorage;
26 import com.google.android.libraries.mobiledatadownload.file.backends.FileUri;
27 import com.google.common.util.concurrent.ExecutionSequencer;
28 import com.google.common.util.concurrent.ListenableFuture;
29 import com.google.common.util.concurrent.ListeningExecutorService;
30 import com.google.devtools.build.runtime.RunfilesPaths;
31 import java.io.IOException;
32 import java.nio.file.Path;
33 
34 /**
35  * A {@link FileDownloader} suitable for use in Robolectric tests that "downloads" by copying the
36  * file from the testdata folder.
37  *
38  * <p>The filename is the Last Path Segment of the urlToDownload. For example, the URL
39  * https://www.gstatic.com/icing/idd/sample_group/step1.txt will be mapped to the file
40  * testSrcDirectory/testDataRelativePath/step1.txt. See <internal> for additional information on
41  * providing data files for tests.
42  *
43  * <p>Note that TestFileDownloader ignores the DownloadConditions.
44  */
45 public final class RobolectricFileDownloader implements FileDownloader {
46 
47   private final String testDataRelativePath;
48   private final SynchronousFileStorage fileStorage;
49   private final ListeningExecutorService executor;
50   private final FileDownloader delegateDownloader;
51 
52   // Sequence downloads to prevent any potential overwrites
53   private final ExecutionSequencer executionSequencer = ExecutionSequencer.create();
54 
RobolectricFileDownloader( String testDataRelativePath, SynchronousFileStorage fileStorage, ListeningExecutorService executor)55   public RobolectricFileDownloader(
56       String testDataRelativePath,
57       SynchronousFileStorage fileStorage,
58       ListeningExecutorService executor) {
59     this.testDataRelativePath = testDataRelativePath;
60     this.fileStorage = fileStorage;
61     this.executor = executor;
62     this.delegateDownloader = new LocalFileDownloader(fileStorage, executor);
63   }
64 
65   @Override
startDownloading(DownloadRequest downloadRequest)66   public ListenableFuture<Void> startDownloading(DownloadRequest downloadRequest) {
67     return executionSequencer.submitAsync(
68         () -> startDownloadingInternal(downloadRequest), executor);
69   }
70 
startDownloadingInternal(DownloadRequest downloadRequest)71   private ListenableFuture<Void> startDownloadingInternal(DownloadRequest downloadRequest) {
72     Uri fileUri = downloadRequest.fileUri();
73     String urlToDownload = downloadRequest.urlToDownload();
74     DownloadConstraints downloadConstraints = downloadRequest.downloadConstraints();
75 
76     // If the file already exists, return immediately
77     try {
78       if (fileStorage.exists(fileUri)) {
79         return immediateVoidFuture();
80       }
81     } catch (IOException e) {
82       return immediateFailedFuture(e);
83     }
84 
85     // We need to translate the real urlToDownload to the one representing the local file in
86     // testdata folder.
87     Uri uriToDownload = Uri.parse(urlToDownload.trim());
88     if (uriToDownload == null) {
89       return immediateVoidFuture();
90     }
91 
92     Path testDataPath = RunfilesPaths.resolve(testDataRelativePath);
93     Path uriToDownloadPath = testDataPath.resolve(uriToDownload.getLastPathSegment());
94 
95     String testDataUrl = FileUri.builder().setPath(uriToDownloadPath.toString()).build().toString();
96 
97     return delegateDownloader.startDownloading(
98         DownloadRequest.newBuilder()
99             .setFileUri(fileUri)
100             .setUrlToDownload(testDataUrl)
101             .setDownloadConstraints(downloadConstraints)
102             .build());
103   }
104 }
105