• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
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 
17 package com.android.textclassifier.downloader;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 import static java.util.concurrent.TimeUnit.SECONDS;
21 import static org.testng.Assert.expectThrows;
22 
23 import android.content.Context;
24 import androidx.test.core.app.ApplicationProvider;
25 import com.android.textclassifier.downloader.TestModelDownloaderService.DownloadResult;
26 import com.google.common.util.concurrent.ListenableFuture;
27 import com.google.common.util.concurrent.MoreExecutors;
28 import java.io.File;
29 import java.nio.file.Files;
30 import java.util.concurrent.CancellationException;
31 import org.junit.After;
32 import org.junit.Before;
33 import org.junit.Test;
34 import org.junit.runner.RunWith;
35 import org.junit.runners.JUnit4;
36 
37 @RunWith(JUnit4.class)
38 public final class ModelDownloaderImplTest {
39   private static final String MANIFEST_URL = "https://manifest.url";
40   private static final String MODEL_URL = "https://model.url";
41   private static final byte[] MODEL_CONTENT_BYTES = "content".getBytes();
42   private static final long MODEL_SIZE_IN_BYTES = 7L;
43   private static final String MODEL_FINGERPRINT =
44       "5406ebea1618e9b73a7290c5d716f0b47b4f1fbc5d8c"
45           + "5e78c9010a3e01c18d8594aa942e3536f7e01574245d34647523";
46   private static final ModelManifest.Model MODEL_PROTO =
47       ModelManifest.Model.newBuilder()
48           .setUrl(MODEL_URL)
49           .setSizeInBytes(MODEL_SIZE_IN_BYTES)
50           .setFingerprint(MODEL_FINGERPRINT)
51           .build();
52   private static final ModelManifest MODEL_MANIFEST_PROTO =
53       ModelManifest.newBuilder().addModels(MODEL_PROTO).build();
54 
55   private ModelDownloaderImpl modelDownloaderImpl;
56   private File modelDownloaderDir;
57 
58   @Before
setUp()59   public void setUp() {
60     Context context = ApplicationProvider.getApplicationContext();
61     this.modelDownloaderImpl =
62         new ModelDownloaderImpl(
63             context, MoreExecutors.newDirectExecutorService(), TestModelDownloaderService.class);
64     this.modelDownloaderDir = new File(context.getFilesDir(), "downloader");
65     this.modelDownloaderDir.mkdirs();
66 
67     TestModelDownloaderService.reset();
68   }
69 
70   @After
tearDown()71   public void tearDown() {
72     DownloaderTestUtils.deleteRecursively(modelDownloaderDir);
73   }
74 
75   @Test
downloadManifest_failToBind()76   public void downloadManifest_failToBind() throws Exception {
77     assertThat(TestModelDownloaderService.hasEverBeenBound()).isFalse();
78     assertThat(TestModelDownloaderService.isBound()).isFalse();
79 
80     TestModelDownloaderService.setBindSucceed(false);
81     ListenableFuture<ModelManifest> manifestFuture =
82         modelDownloaderImpl.downloadManifest(MANIFEST_URL);
83 
84     Throwable t = expectThrows(Throwable.class, manifestFuture::get);
85     assertThat(t).hasCauseThat().isInstanceOf(ModelDownloadException.class);
86     ModelDownloadException e = (ModelDownloadException) t.getCause();
87     assertThat(e.getErrorCode())
88         .isEqualTo(ModelDownloadException.FAILED_TO_DOWNLOAD_SERVICE_CONN_BROKEN);
89     assertThat(e.getDownloaderLibErrorCode())
90         .isEqualTo(ModelDownloadException.DEFAULT_DOWNLOADER_LIB_ERROR_CODE);
91     assertThat(TestModelDownloaderService.isBound()).isFalse();
92     assertThat(TestModelDownloaderService.hasEverBeenBound()).isFalse();
93   }
94 
95   @Test
downloadManifest_succeed()96   public void downloadManifest_succeed() throws Exception {
97     assertThat(TestModelDownloaderService.hasEverBeenBound()).isFalse();
98     assertThat(TestModelDownloaderService.isBound()).isFalse();
99 
100     TestModelDownloaderService.setBindSucceed(true);
101     TestModelDownloaderService.setDownloadResult(
102         MANIFEST_URL, DownloadResult.SUCCEEDED, MODEL_MANIFEST_PROTO.toByteArray());
103     ListenableFuture<ModelManifest> manifestFuture =
104         modelDownloaderImpl.downloadManifest(MANIFEST_URL);
105 
106     assertThat(manifestFuture.get()).isEqualTo(MODEL_MANIFEST_PROTO); // ProtoTruth is not available
107     assertThat(TestModelDownloaderService.getOnUnbindInvokedLatch().await(1L, SECONDS)).isTrue();
108     assertThat(TestModelDownloaderService.isBound()).isFalse();
109     assertThat(TestModelDownloaderService.hasEverBeenBound()).isTrue();
110   }
111 
112   @Test
downloadManifest_failToDownload()113   public void downloadManifest_failToDownload() throws Exception {
114     assertThat(TestModelDownloaderService.hasEverBeenBound()).isFalse();
115     assertThat(TestModelDownloaderService.isBound()).isFalse();
116 
117     TestModelDownloaderService.setBindSucceed(true);
118     TestModelDownloaderService.setDownloadResult(MANIFEST_URL, DownloadResult.FAILED, null);
119     ListenableFuture<ModelManifest> manifestFuture =
120         modelDownloaderImpl.downloadManifest(MANIFEST_URL);
121 
122     Throwable t = expectThrows(Throwable.class, manifestFuture::get);
123     assertThat(t).hasCauseThat().isInstanceOf(ModelDownloadException.class);
124     ModelDownloadException e = (ModelDownloadException) t.getCause();
125     assertThat(e.getErrorCode()).isEqualTo(ModelDownloadException.FAILED_TO_DOWNLOAD_OTHER);
126     assertThat(e.getDownloaderLibErrorCode())
127         .isEqualTo(TestModelDownloaderService.DOWNLOADER_LIB_ERROR_CODE);
128     assertThat(e).hasMessageThat().contains(TestModelDownloaderService.ERROR_MSG);
129     assertThat(TestModelDownloaderService.getOnUnbindInvokedLatch().await(1L, SECONDS)).isTrue();
130     assertThat(TestModelDownloaderService.isBound()).isFalse();
131     assertThat(TestModelDownloaderService.hasEverBeenBound()).isTrue();
132   }
133 
134   @Test
downloadManifest_failToParse()135   public void downloadManifest_failToParse() throws Exception {
136     assertThat(TestModelDownloaderService.hasEverBeenBound()).isFalse();
137     assertThat(TestModelDownloaderService.isBound()).isFalse();
138 
139     TestModelDownloaderService.setBindSucceed(true);
140     TestModelDownloaderService.setDownloadResult(
141         MANIFEST_URL, DownloadResult.SUCCEEDED, "randomString".getBytes());
142     ListenableFuture<ModelManifest> manifestFuture =
143         modelDownloaderImpl.downloadManifest(MANIFEST_URL);
144 
145     Throwable t = expectThrows(Throwable.class, manifestFuture::get);
146     assertThat(t).hasCauseThat().isInstanceOf(ModelDownloadException.class);
147     ModelDownloadException e = (ModelDownloadException) t.getCause();
148     assertThat(e.getErrorCode()).isEqualTo(ModelDownloadException.FAILED_TO_PARSE_MANIFEST);
149     assertThat(e.getDownloaderLibErrorCode())
150         .isEqualTo(ModelDownloadException.DEFAULT_DOWNLOADER_LIB_ERROR_CODE);
151     assertThat(TestModelDownloaderService.getOnUnbindInvokedLatch().await(1L, SECONDS)).isTrue();
152     assertThat(TestModelDownloaderService.isBound()).isFalse();
153     assertThat(TestModelDownloaderService.hasEverBeenBound()).isTrue();
154   }
155 
156   @Test
downloadManifest_cancelAndUnbind()157   public void downloadManifest_cancelAndUnbind() throws Exception {
158     assertThat(TestModelDownloaderService.hasEverBeenBound()).isFalse();
159     assertThat(TestModelDownloaderService.isBound()).isFalse();
160 
161     TestModelDownloaderService.setBindSucceed(true);
162     TestModelDownloaderService.setDownloadResult(MANIFEST_URL, DownloadResult.DO_NOTHING, null);
163     ListenableFuture<ModelManifest> manifestFuture =
164         modelDownloaderImpl.downloadManifest(MANIFEST_URL);
165 
166     assertThat(TestModelDownloaderService.getOnBindInvokedLatch().await(1L, SECONDS)).isTrue();
167     assertThat(TestModelDownloaderService.isBound()).isTrue();
168     manifestFuture.cancel(true);
169 
170     expectThrows(CancellationException.class, manifestFuture::get);
171     assertThat(TestModelDownloaderService.getOnUnbindInvokedLatch().await(1L, SECONDS)).isTrue();
172     assertThat(TestModelDownloaderService.isBound()).isFalse();
173     assertThat(TestModelDownloaderService.hasEverBeenBound()).isTrue();
174   }
175 
176   @Test
downloadModel_failToBind()177   public void downloadModel_failToBind() throws Exception {
178     assertThat(TestModelDownloaderService.hasEverBeenBound()).isFalse();
179     assertThat(TestModelDownloaderService.isBound()).isFalse();
180 
181     TestModelDownloaderService.setBindSucceed(false);
182     ListenableFuture<File> modelFuture =
183         modelDownloaderImpl.downloadModel(modelDownloaderDir, MODEL_PROTO);
184 
185     Throwable t = expectThrows(Throwable.class, modelFuture::get);
186     assertThat(t).hasCauseThat().isInstanceOf(ModelDownloadException.class);
187     ModelDownloadException e = (ModelDownloadException) t.getCause();
188     assertThat(e.getErrorCode())
189         .isEqualTo(ModelDownloadException.FAILED_TO_DOWNLOAD_SERVICE_CONN_BROKEN);
190     assertThat(e.getDownloaderLibErrorCode())
191         .isEqualTo(ModelDownloadException.DEFAULT_DOWNLOADER_LIB_ERROR_CODE);
192     assertThat(TestModelDownloaderService.isBound()).isFalse();
193     assertThat(TestModelDownloaderService.hasEverBeenBound()).isFalse();
194   }
195 
196   @Test
downloadModel_succeed()197   public void downloadModel_succeed() throws Exception {
198     assertThat(TestModelDownloaderService.hasEverBeenBound()).isFalse();
199     assertThat(TestModelDownloaderService.isBound()).isFalse();
200 
201     TestModelDownloaderService.setBindSucceed(true);
202     TestModelDownloaderService.setDownloadResult(
203         MODEL_URL, DownloadResult.SUCCEEDED, MODEL_CONTENT_BYTES);
204     ListenableFuture<File> modelFuture =
205         modelDownloaderImpl.downloadModel(modelDownloaderDir, MODEL_PROTO);
206 
207     File modelFile = modelFuture.get();
208     assertThat(modelFile.getParentFile()).isEqualTo(modelDownloaderDir);
209     assertThat(Files.readAllBytes(modelFile.toPath())).isEqualTo(MODEL_CONTENT_BYTES);
210     assertThat(TestModelDownloaderService.getOnUnbindInvokedLatch().await(1L, SECONDS)).isTrue();
211     assertThat(TestModelDownloaderService.isBound()).isFalse();
212     assertThat(TestModelDownloaderService.hasEverBeenBound()).isTrue();
213   }
214 
215   @Test
downloadModel_failToDownload()216   public void downloadModel_failToDownload() throws Exception {
217     assertThat(TestModelDownloaderService.hasEverBeenBound()).isFalse();
218     assertThat(TestModelDownloaderService.isBound()).isFalse();
219 
220     TestModelDownloaderService.setBindSucceed(true);
221     TestModelDownloaderService.setDownloadResult(MODEL_URL, DownloadResult.FAILED, null);
222     ListenableFuture<File> modelFuture =
223         modelDownloaderImpl.downloadModel(modelDownloaderDir, MODEL_PROTO);
224 
225     Throwable t = expectThrows(Throwable.class, modelFuture::get);
226     assertThat(t).hasCauseThat().isInstanceOf(ModelDownloadException.class);
227     ModelDownloadException e = (ModelDownloadException) t.getCause();
228     assertThat(e.getErrorCode()).isEqualTo(ModelDownloadException.FAILED_TO_DOWNLOAD_OTHER);
229     assertThat(e.getDownloaderLibErrorCode())
230         .isEqualTo(TestModelDownloaderService.DOWNLOADER_LIB_ERROR_CODE);
231     assertThat(e).hasMessageThat().contains(TestModelDownloaderService.ERROR_MSG);
232     assertThat(TestModelDownloaderService.getOnUnbindInvokedLatch().await(1L, SECONDS)).isTrue();
233     assertThat(TestModelDownloaderService.isBound()).isFalse();
234     assertThat(TestModelDownloaderService.hasEverBeenBound()).isTrue();
235   }
236 
237   @Test
downloadModel_failToValidate()238   public void downloadModel_failToValidate() throws Exception {
239     assertThat(TestModelDownloaderService.hasEverBeenBound()).isFalse();
240     assertThat(TestModelDownloaderService.isBound()).isFalse();
241 
242     TestModelDownloaderService.setBindSucceed(true);
243     TestModelDownloaderService.setDownloadResult(
244         MODEL_URL, DownloadResult.SUCCEEDED, "randomString".getBytes());
245     ListenableFuture<File> modelFuture =
246         modelDownloaderImpl.downloadModel(modelDownloaderDir, MODEL_PROTO);
247 
248     Throwable t = expectThrows(Throwable.class, modelFuture::get);
249     assertThat(t).hasCauseThat().isInstanceOf(ModelDownloadException.class);
250     ModelDownloadException e = (ModelDownloadException) t.getCause();
251     assertThat(e.getErrorCode()).isEqualTo(ModelDownloadException.FAILED_TO_VALIDATE_MODEL);
252     assertThat(e.getDownloaderLibErrorCode())
253         .isEqualTo(ModelDownloadException.DEFAULT_DOWNLOADER_LIB_ERROR_CODE);
254     assertThat(TestModelDownloaderService.getOnUnbindInvokedLatch().await(1L, SECONDS)).isTrue();
255     assertThat(TestModelDownloaderService.isBound()).isFalse();
256     assertThat(TestModelDownloaderService.hasEverBeenBound()).isTrue();
257   }
258 
259   @Test
downloadModel_cancelAndUnbind()260   public void downloadModel_cancelAndUnbind() throws Exception {
261     assertThat(TestModelDownloaderService.hasEverBeenBound()).isFalse();
262     assertThat(TestModelDownloaderService.isBound()).isFalse();
263 
264     TestModelDownloaderService.setBindSucceed(true);
265     TestModelDownloaderService.setDownloadResult(MODEL_URL, DownloadResult.DO_NOTHING, null);
266     ListenableFuture<File> modelFuture =
267         modelDownloaderImpl.downloadModel(modelDownloaderDir, MODEL_PROTO);
268 
269     assertThat(TestModelDownloaderService.getOnBindInvokedLatch().await(1L, SECONDS)).isTrue();
270     assertThat(TestModelDownloaderService.isBound()).isTrue();
271     modelFuture.cancel(true);
272 
273     expectThrows(CancellationException.class, modelFuture::get);
274     assertThat(TestModelDownloaderService.getOnUnbindInvokedLatch().await(1L, SECONDS)).isTrue();
275     assertThat(TestModelDownloaderService.isBound()).isFalse();
276     assertThat(TestModelDownloaderService.hasEverBeenBound()).isTrue();
277   }
278 }
279