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