• 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 org.mockito.ArgumentMatchers.any;
21 import static org.mockito.Mockito.when;
22 import static org.testng.Assert.expectThrows;
23 
24 import androidx.test.core.app.ApplicationProvider;
25 import com.google.android.downloader.DownloadConstraints;
26 import com.google.android.downloader.DownloadRequest;
27 import com.google.android.downloader.DownloadResult;
28 import com.google.android.downloader.Downloader;
29 import com.google.android.downloader.ErrorDetails;
30 import com.google.android.downloader.RequestException;
31 import com.google.android.downloader.SimpleFileDownloadDestination;
32 import com.google.common.util.concurrent.FluentFuture;
33 import com.google.common.util.concurrent.Futures;
34 import com.google.common.util.concurrent.ListenableFuture;
35 import com.google.common.util.concurrent.MoreExecutors;
36 import com.google.common.util.concurrent.SettableFuture;
37 import java.io.File;
38 import java.net.URI;
39 import org.junit.Before;
40 import org.junit.Rule;
41 import org.junit.Test;
42 import org.junit.runner.RunWith;
43 import org.junit.runners.JUnit4;
44 import org.mockito.Mock;
45 import org.mockito.junit.MockitoJUnit;
46 import org.mockito.junit.MockitoRule;
47 
48 @RunWith(JUnit4.class)
49 public final class ModelDownloaderServiceImplTest {
50 
51   @Rule public final MockitoRule mocks = MockitoJUnit.rule();
52 
53   private static final long BYTES_WRITTEN = 1L;
54   private static final String DOWNLOAD_URI =
55       "https://www.gstatic.com/android/text_classifier/r/v999/en.fb";
56   private static final int DOWNLOADER_LIB_ERROR_CODE = 500;
57   private static final String ERROR_MESSAGE = "err_msg";
58   private static final Exception DOWNLOADER_LIB_EXCEPTION =
59       new RequestException(
60           ErrorDetails.builder()
61               .setErrorMessage(ERROR_MESSAGE)
62               .setHttpStatusCode(DOWNLOADER_LIB_ERROR_CODE)
63               .build());
64 
65   @Mock private Downloader downloader;
66   private File targetModelFile;
67   private File targetMetadataFile;
68   private ModelDownloaderServiceImpl modelDownloaderServiceImpl;
69   private TestSuccessCallbackImpl successCallback;
70   private TestFailureCallbackImpl failureCallback;
71 
72   @Before
setUp()73   public void setUp() {
74 
75     this.targetModelFile =
76         new File(ApplicationProvider.getApplicationContext().getCacheDir(), "model.fb");
77     this.targetMetadataFile = ModelDownloaderServiceImpl.getMetadataFile(targetModelFile);
78     this.modelDownloaderServiceImpl =
79         new ModelDownloaderServiceImpl(MoreExecutors.newDirectExecutorService(), downloader);
80     this.successCallback = new TestSuccessCallbackImpl();
81     this.failureCallback = new TestFailureCallbackImpl();
82 
83     targetModelFile.deleteOnExit();
84     targetMetadataFile.deleteOnExit();
85     when(downloader.newRequestBuilder(any(), any()))
86         .thenReturn(
87             DownloadRequest.newBuilder()
88                 .setUri(URI.create(DOWNLOAD_URI))
89                 .setDownloadConstraints(DownloadConstraints.NONE)
90                 .setDestination(
91                     new SimpleFileDownloadDestination(targetModelFile, targetMetadataFile)));
92   }
93 
94   @Test
download_succeeded()95   public void download_succeeded() throws Exception {
96     targetModelFile.createNewFile();
97     targetMetadataFile.createNewFile();
98     when(downloader.execute(any()))
99         .thenReturn(
100             FluentFuture.from(Futures.immediateFuture(DownloadResult.create(BYTES_WRITTEN))));
101     modelDownloaderServiceImpl.download(
102         DOWNLOAD_URI, targetModelFile.getAbsolutePath(), successCallback);
103 
104     assertThat(successCallback.getBytesWrittenFuture().get()).isEqualTo(BYTES_WRITTEN);
105     assertThat(targetModelFile.exists()).isTrue();
106     assertThat(targetMetadataFile.exists()).isFalse();
107   }
108 
109   @Test
download_failed()110   public void download_failed() throws Exception {
111     targetModelFile.createNewFile();
112     targetMetadataFile.createNewFile();
113     when(downloader.execute(any()))
114         .thenReturn(FluentFuture.from(Futures.immediateFailedFuture(DOWNLOADER_LIB_EXCEPTION)));
115     modelDownloaderServiceImpl.download(
116         DOWNLOAD_URI, targetModelFile.getAbsolutePath(), successCallback);
117 
118     Throwable t =
119         expectThrows(Throwable.class, () -> successCallback.getBytesWrittenFuture().get());
120     assertThat(t).hasCauseThat().isInstanceOf(ModelDownloadException.class);
121     ModelDownloadException e = (ModelDownloadException) t.getCause();
122     assertThat(e.getErrorCode()).isEqualTo(ModelDownloadException.FAILED_TO_DOWNLOAD_OTHER);
123     assertThat(e.getDownloaderLibErrorCode()).isEqualTo(DOWNLOADER_LIB_ERROR_CODE);
124     assertThat(e).hasMessageThat().contains(ERROR_MESSAGE);
125     assertThat(targetModelFile.exists()).isFalse();
126     assertThat(targetMetadataFile.exists()).isFalse();
127   }
128 
129   @Test
download_succeeded_callbackFailed()130   public void download_succeeded_callbackFailed() throws Exception {
131     targetModelFile.createNewFile();
132     targetMetadataFile.createNewFile();
133     when(downloader.execute(any()))
134         .thenReturn(
135             FluentFuture.from(Futures.immediateFuture(DownloadResult.create(BYTES_WRITTEN))));
136     modelDownloaderServiceImpl.download(
137         DOWNLOAD_URI, targetModelFile.getAbsolutePath(), failureCallback);
138 
139     assertThat(failureCallback.onSuccessCalled).isTrue();
140     assertThat(targetModelFile.exists()).isTrue();
141     assertThat(targetMetadataFile.exists()).isFalse();
142   }
143 
144   @Test
download_failed_callbackFailed()145   public void download_failed_callbackFailed() throws Exception {
146     targetModelFile.createNewFile();
147     targetMetadataFile.createNewFile();
148     when(downloader.execute(any()))
149         .thenReturn(FluentFuture.from(Futures.immediateFailedFuture(DOWNLOADER_LIB_EXCEPTION)));
150     modelDownloaderServiceImpl.download(
151         DOWNLOAD_URI, targetModelFile.getAbsolutePath(), failureCallback);
152 
153     assertThat(failureCallback.onFailureCalled).isTrue();
154     assertThat(targetModelFile.exists()).isFalse();
155     assertThat(targetMetadataFile.exists()).isFalse();
156   }
157 
158   // NOTICE: Had some problem mocking this AIDL interface, so created fake impls
159   private static final class TestSuccessCallbackImpl extends IModelDownloaderCallback.Stub {
160     private final SettableFuture<Long> bytesWrittenFuture = SettableFuture.<Long>create();
161 
getBytesWrittenFuture()162     public ListenableFuture<Long> getBytesWrittenFuture() {
163       return bytesWrittenFuture;
164     }
165 
166     @Override
onSuccess(long bytesWritten)167     public void onSuccess(long bytesWritten) {
168       bytesWrittenFuture.set(bytesWritten);
169     }
170 
171     @Override
onFailure(int downloaderLibErrorCode, String errorMsg)172     public void onFailure(int downloaderLibErrorCode, String errorMsg) {
173       bytesWrittenFuture.setException(
174           new ModelDownloadException(
175               ModelDownloadException.FAILED_TO_DOWNLOAD_OTHER, downloaderLibErrorCode, errorMsg));
176     }
177   }
178 
179   private static final class TestFailureCallbackImpl extends IModelDownloaderCallback.Stub {
180     public boolean onSuccessCalled = false;
181     public boolean onFailureCalled = false;
182 
183     @Override
onSuccess(long bytesWritten)184     public void onSuccess(long bytesWritten) {
185       onSuccessCalled = true;
186       throw new RuntimeException();
187     }
188 
189     @Override
onFailure(int downloaderLibErrorCode, String errorMsg)190     public void onFailure(int downloaderLibErrorCode, String errorMsg) {
191       onFailureCalled = true;
192       throw new RuntimeException();
193     }
194   }
195 }
196