• 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.populator;
17 
18 import static com.google.android.libraries.mobiledatadownload.populator.ManifestConfigHelper.URL_TEMPLATE_CHECKSUM_PLACEHOLDER;
19 import static com.google.common.truth.Truth.assertThat;
20 import static org.junit.Assert.assertThrows;
21 import static org.mockito.ArgumentMatchers.any;
22 import static org.mockito.Mockito.times;
23 import static org.mockito.Mockito.verify;
24 import static org.mockito.Mockito.when;
25 
26 import com.google.android.libraries.mobiledatadownload.AddFileGroupRequest;
27 import com.google.android.libraries.mobiledatadownload.MobileDataDownload;
28 import com.google.common.base.Optional;
29 import com.google.common.collect.ImmutableList;
30 import com.google.common.collect.Iterables;
31 import com.google.common.util.concurrent.Futures;
32 import com.google.common.util.concurrent.ListenableFuture;
33 import com.google.mobiledatadownload.DownloadConfigProto.BaseFile;
34 import com.google.mobiledatadownload.DownloadConfigProto.DataFile;
35 import com.google.mobiledatadownload.DownloadConfigProto.DataFileGroup;
36 import com.google.mobiledatadownload.DownloadConfigProto.DeltaFile;
37 import com.google.mobiledatadownload.DownloadConfigProto.DeltaFile.DiffDecoder;
38 import com.google.mobiledatadownload.DownloadConfigProto.ManifestConfig;
39 import com.google.mobiledatadownload.DownloadConfigProto.ManifestConfig.UrlTemplate;
40 import java.util.ArrayList;
41 import java.util.List;
42 import java.util.concurrent.ExecutionException;
43 import org.junit.Before;
44 import org.junit.Rule;
45 import org.junit.Test;
46 import org.junit.runner.RunWith;
47 import org.mockito.ArgumentCaptor;
48 import org.mockito.Captor;
49 import org.mockito.Mock;
50 import org.mockito.junit.MockitoJUnit;
51 import org.mockito.junit.MockitoRule;
52 import org.robolectric.RobolectricTestRunner;
53 
54 /** Tests for {@link ManifestConfigFlagPopulator}. */
55 @RunWith(RobolectricTestRunner.class)
56 public class ManifestConfigFlagPopulatorTest {
57   @Rule public final MockitoRule mocks = MockitoJUnit.rule();
58 
59   @Mock MobileDataDownload mockMobileDataDownload;
60   @Captor private ArgumentCaptor<AddFileGroupRequest> addFileGroupRequestCaptor;
61 
62   private static final DeltaFile DELTA_FILE =
63       DeltaFile.newBuilder()
64           .setDiffDecoder(DiffDecoder.VC_DIFF)
65           .setUrlToDownload("https://standard.file.url")
66           .setChecksum("standardDeltaFileChecksum")
67           .setBaseFile(BaseFile.newBuilder().setChecksum("standardBaseFileChecksum").build())
68           .build();
69 
70   private static final DataFile DATA_FILE =
71       DataFile.newBuilder()
72           .setFileId("standard-file")
73           .setUrlToDownload("https://standard.file.url")
74           .setChecksum("standardFileChecksum")
75           .addDeltaFile(DELTA_FILE)
76           .build();
77 
78   private static final DataFileGroup DATA_FILE_GROUP =
79       DataFileGroup.newBuilder().setGroupName("groupName").setOwnerPackage("ownerPackage").build();
80 
81   @Before
setUp()82   public void setUp() {
83     when(mockMobileDataDownload.addFileGroup(any(AddFileGroupRequest.class)))
84         .thenReturn(Futures.immediateFuture(true));
85   }
86 
87   @Test
refreshFromManifestConfig_absentOverrider()88   public void refreshFromManifestConfig_absentOverrider()
89       throws ExecutionException, InterruptedException {
90     ManifestConfig manifestConfig = createManifestConfig();
91 
92     ManifestConfigHelper.refreshFromManifestConfig(
93             mockMobileDataDownload,
94             manifestConfig,
95             /* overriderOptional= */ Optional.absent(),
96             /* accounts= */ ImmutableList.of(),
97             /* addGroupsWithVariantId= */ false)
98         .get();
99     verify(mockMobileDataDownload, times(2)).addFileGroup(addFileGroupRequestCaptor.capture());
100 
101     assertThat(addFileGroupRequestCaptor.getAllValues().get(0).dataFileGroup().getGroupName())
102         .isEqualTo("groupNameLocaleEnUS");
103     assertThat(addFileGroupRequestCaptor.getAllValues().get(1).dataFileGroup().getGroupName())
104         .isEqualTo("groupNameLocaleEnUK");
105   }
106 
107   @Test
refreshFromManifestConfig_withUrlTemplate_absentOverrider()108   public void refreshFromManifestConfig_withUrlTemplate_absentOverrider()
109       throws ExecutionException, InterruptedException {
110     ManifestConfig manifestConfigWithUrlTemplate = createManifestConfigWithUrlTemplate();
111     // File url_to_download populated using url templates.
112     DataFileGroup dataFileGroup1 =
113         DATA_FILE_GROUP.toBuilder()
114             .addFile(
115                 DATA_FILE.toBuilder()
116                     .setUrlToDownload("https://standard.file.url/standardFileChecksum")
117                     .setDeltaFile(
118                         0,
119                         DELTA_FILE.toBuilder()
120                             .setUrlToDownload(
121                                 "https://standard.file.url/standardDeltaFileChecksum")))
122             .build();
123     DataFileGroup dataFileGroup2 = DATA_FILE_GROUP.toBuilder().addFile(DATA_FILE).build();
124 
125     ManifestConfigHelper.refreshFromManifestConfig(
126             mockMobileDataDownload,
127             manifestConfigWithUrlTemplate,
128             /* overriderOptional= */ Optional.absent(),
129             /* accounts= */ ImmutableList.of(),
130             /* addGroupsWithVariantId= */ false)
131         .get();
132     verify(mockMobileDataDownload, times(2)).addFileGroup(addFileGroupRequestCaptor.capture());
133 
134     List<AddFileGroupRequest> addFileGroupRequests = addFileGroupRequestCaptor.getAllValues();
135     assertThat(Iterables.transform(addFileGroupRequests, AddFileGroupRequest::dataFileGroup))
136         .containsExactly(dataFileGroup1, dataFileGroup2)
137         .inOrder();
138   }
139 
140   @Test
refreshFromManifestConfig_noUrlTemplate_urlToDownloadEmpty_absentOverrider()141   public void refreshFromManifestConfig_noUrlTemplate_urlToDownloadEmpty_absentOverrider()
142       throws ExecutionException, InterruptedException {
143     // Files with no url_to_download will fail since url template is not available.
144     ManifestConfig manifestConfigWithoutUrlTemplate =
145         createManifestConfigWithUrlTemplate().toBuilder().clearUrlTemplate().build();
146 
147     IllegalArgumentException illegalArgumentException =
148         assertThrows(
149             IllegalArgumentException.class,
150             () ->
151                 ManifestConfigHelper.refreshFromManifestConfig(
152                         mockMobileDataDownload,
153                         manifestConfigWithoutUrlTemplate,
154                         /* overriderOptional= */ Optional.absent(),
155                         /* accounts= */ ImmutableList.of(),
156                         /* addGroupsWithVariantId= */ false)
157                     .get());
158 
159     assertThat(illegalArgumentException)
160         .hasMessageThat()
161         .isEqualTo("DataFile standard-file url_to_download is missing.");
162   }
163 
164   @Test
refreshFromManifestConfig_identityOverrider()165   public void refreshFromManifestConfig_identityOverrider()
166       throws ExecutionException, InterruptedException {
167     ManifestConfig manifestConfig = createManifestConfig();
168 
169     // Use a ManifestConfigOverrider that does not filter/change anything.
170     ManifestConfigOverrider overrider =
171         new ManifestConfigOverrider() {
172           @Override
173           public ListenableFuture<List<DataFileGroup>> override(ManifestConfig config) {
174             List<DataFileGroup> overriderResults = new ArrayList<>();
175             for (ManifestConfig.Entry entry : config.getEntryList()) {
176               overriderResults.add(entry.getDataFileGroup());
177             }
178 
179             return Futures.immediateFuture(overriderResults);
180           }
181         };
182 
183     ManifestConfigHelper.refreshFromManifestConfig(
184             mockMobileDataDownload,
185             manifestConfig,
186             Optional.of(overrider),
187             /* accounts= */ ImmutableList.of(),
188             /* addGroupsWithVariantId= */ false)
189         .get();
190     verify(mockMobileDataDownload, times(2)).addFileGroup(addFileGroupRequestCaptor.capture());
191 
192     assertThat(addFileGroupRequestCaptor.getAllValues().get(0).dataFileGroup().getGroupName())
193         .isEqualTo("groupNameLocaleEnUS");
194     assertThat(addFileGroupRequestCaptor.getAllValues().get(1).dataFileGroup().getGroupName())
195         .isEqualTo("groupNameLocaleEnUK");
196   }
197 
198   @Test
refreshFromManifestConfig_en_USLocaleOverrider()199   public void refreshFromManifestConfig_en_USLocaleOverrider()
200       throws ExecutionException, InterruptedException {
201     ManifestConfig manifestConfig = createManifestConfig();
202 
203     // Use a ManifestConfigOverrider that only keeps entry with locale en_US.
204     ManifestConfigOverrider overrider =
205         new ManifestConfigOverrider() {
206           @Override
207           public ListenableFuture<List<DataFileGroup>> override(ManifestConfig config) {
208             List<DataFileGroup> overriderResults = new ArrayList<>();
209             for (ManifestConfig.Entry entry : config.getEntryList()) {
210               if ("en_US".equals(entry.getModifier().getLocaleList().get(0))) {
211                 overriderResults.add(entry.getDataFileGroup());
212               }
213             }
214 
215             return Futures.immediateFuture(overriderResults);
216           }
217         };
218 
219     ManifestConfigHelper.refreshFromManifestConfig(
220             mockMobileDataDownload,
221             manifestConfig,
222             Optional.of(overrider),
223             /* accounts= */ ImmutableList.of(),
224             /* addGroupsWithVariantId= */ false)
225         .get();
226     verify(mockMobileDataDownload, times(1)).addFileGroup(addFileGroupRequestCaptor.capture());
227 
228     assertThat(addFileGroupRequestCaptor.getAllValues().get(0).dataFileGroup().getGroupName())
229         .isEqualTo("groupNameLocaleEnUS");
230   }
231 
232   @Test
refreshFileGroups_usesSupplier()233   public void refreshFileGroups_usesSupplier() throws ExecutionException, InterruptedException {
234     ManifestConfig manifestConfig = createManifestConfig();
235 
236     ManifestConfigFlagPopulator populator =
237         ManifestConfigFlagPopulator.builder()
238             .setManifestConfigSupplier(() -> manifestConfig)
239             .build();
240 
241     populator.refreshFileGroups(mockMobileDataDownload).get();
242     verify(mockMobileDataDownload, times(2)).addFileGroup(addFileGroupRequestCaptor.capture());
243 
244     assertThat(addFileGroupRequestCaptor.getAllValues().get(0).dataFileGroup().getGroupName())
245         .isEqualTo("groupNameLocaleEnUS");
246     assertThat(addFileGroupRequestCaptor.getAllValues().get(1).dataFileGroup().getGroupName())
247         .isEqualTo("groupNameLocaleEnUK");
248   }
249 
250   @Test
manifestConfigFlagPopulatorBuilder_rejectsNotBothPackageAndFlag()251   public void manifestConfigFlagPopulatorBuilder_rejectsNotBothPackageAndFlag() {
252     assertThrows(
253         IllegalArgumentException.class, () -> ManifestConfigFlagPopulator.builder().build());
254   }
255 
createManifestConfig()256   private static ManifestConfig createManifestConfig() {
257     // Create a ManifestConfig with 2 entries for locale en_US and en_UK.
258     ManifestConfig.Entry entryUs =
259         ManifestConfig.Entry.newBuilder()
260             .setModifier(ManifestConfig.Entry.Modifier.newBuilder().addLocale("en_US").build())
261             .setDataFileGroup(
262                 DataFileGroup.newBuilder()
263                     .setGroupName("groupNameLocaleEnUS")
264                     .setOwnerPackage("ownerPackage"))
265             .build();
266 
267     ManifestConfig.Entry entryUk =
268         ManifestConfig.Entry.newBuilder()
269             .setModifier(ManifestConfig.Entry.Modifier.newBuilder().addLocale("en_UK").build())
270             .setDataFileGroup(
271                 DataFileGroup.newBuilder()
272                     .setGroupName("groupNameLocaleEnUK")
273                     .setOwnerPackage("ownerPackage"))
274             .build();
275 
276     return ManifestConfig.newBuilder().addEntry(entryUs).addEntry(entryUk).build();
277   }
278 
createManifestConfigWithUrlTemplate()279   private static ManifestConfig createManifestConfigWithUrlTemplate() {
280     DataFileGroup dataFileGroupWithoutUrlDownload =
281         DATA_FILE_GROUP.toBuilder()
282             .addFile(
283                 DATA_FILE.toBuilder()
284                     .clearUrlToDownload()
285                     .setDeltaFile(0, DELTA_FILE.toBuilder().clearUrlToDownload()))
286             .build();
287     DataFileGroup dataFileGroup2 = DATA_FILE_GROUP.toBuilder().addFile(DATA_FILE).build();
288 
289     return ManifestConfig.newBuilder()
290         .setUrlTemplate(
291             UrlTemplate.newBuilder()
292                 .setFileUrlTemplate(
293                     "https://standard.file.url/" + URL_TEMPLATE_CHECKSUM_PLACEHOLDER)
294                 .build())
295         .addEntry(
296             ManifestConfig.Entry.newBuilder().setDataFileGroup(dataFileGroupWithoutUrlDownload))
297         .addEntry(ManifestConfig.Entry.newBuilder().setDataFileGroup(dataFileGroup2))
298         .build();
299   }
300 }
301