• 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.internal.util;
17 
18 import static com.google.common.truth.Truth.assertThat;
19 
20 import android.content.Context;
21 import android.net.Uri;
22 import androidx.test.core.app.ApplicationProvider;
23 import com.google.mobiledatadownload.internal.MetadataProto;
24 import com.google.mobiledatadownload.internal.MetadataProto.DataFileGroupBookkeeping;
25 import com.google.mobiledatadownload.internal.MetadataProto.DataFileGroupInternal;
26 import com.google.android.libraries.mobiledatadownload.file.SynchronousFileStorage;
27 import com.google.android.libraries.mobiledatadownload.file.backends.AndroidFileBackend;
28 import com.google.android.libraries.mobiledatadownload.file.backends.JavaFileBackend;
29 import com.google.android.libraries.mobiledatadownload.file.openers.ReadByteArrayOpener;
30 import com.google.android.libraries.mobiledatadownload.internal.MddTestUtil;
31 import com.google.common.collect.ImmutableList;
32 import com.google.common.truth.Correspondence;
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.DataFileGroup.AllowedReaders;
37 import com.google.mobiledatadownload.DownloadConfigProto.DeltaFile;
38 import com.google.mobiledatadownload.DownloadConfigProto.DownloadConditions;
39 import com.google.mobiledatadownload.DownloadConfigProto.DownloadConditions.DeviceNetworkPolicy;
40 import com.google.mobiledatadownload.DownloadConfigProto.DownloadConditions.DeviceStoragePolicy;
41 import com.google.mobiledatadownload.DownloadConfigProto.ExtraHttpHeader;
42 import com.google.mobiledatadownload.TransformProto.CompressTransform;
43 import com.google.mobiledatadownload.TransformProto.Transform;
44 import com.google.mobiledatadownload.TransformProto.Transforms;
45 import com.google.mobiledatadownload.TransformProto.ZipTransform;
46 import com.google.protobuf.ExtensionRegistryLite;
47 import com.google.protobuf.contrib.android.ProtoParsers;
48 import com.google.testing.util.TestUtil;
49 import java.io.File;
50 import org.junit.Before;
51 import org.junit.Rule;
52 import org.junit.Test;
53 import org.junit.runner.RunWith;
54 import org.mockito.junit.MockitoJUnit;
55 import org.mockito.junit.MockitoRule;
56 import org.robolectric.RobolectricTestRunner;
57 
58 /** Unit tests for {@link ProtoConversionUtil}. */
59 @RunWith(RobolectricTestRunner.class)
60 public final class ProtoConversionUtilTest {
61 
62   @Rule public final MockitoRule mocks = MockitoJUnit.rule();
63 
64   private SynchronousFileStorage fileStorage;
65   private Context context;
66 
67   // The raw test data folder in google3.
68   private static final String TEST_DATA_DIR =
69       TestUtil.getRunfilesDir()
70           + "/third_party/java_src/android_libs/mobiledatadownload/javatests/com/google/android/libraries/mobiledatadownload/internal/util/testdata/";
71   private static final File RAW_GROUP_WITH_EXTENSION =
72       new File(TEST_DATA_DIR, "raw_group_with_extension");
73 
74   @Before
setUp()75   public void setUp() throws Exception {
76     context = ApplicationProvider.getApplicationContext();
77     fileStorage =
78         new SynchronousFileStorage(
79             ImmutableList.of(AndroidFileBackend.builder(context).build(), new JavaFileBackend()));
80   }
81 
82   @Test
convert_fromDataFileGroup_toDataFileGroupInternal_noThrow()83   public void convert_fromDataFileGroup_toDataFileGroupInternal_noThrow() throws Exception {
84     DataFileGroup group =
85         DataFileGroup.newBuilder()
86             .setGroupName("test-group")
87             .setOwnerPackage("com.google.android.libraries.mobiledatadownload")
88             .setFileGroupVersionNumber(12)
89             .setAllowedReadersEnum(AllowedReaders.ALL_GOOGLE_APPS)
90             .setDownloadConditions(
91                 DownloadConditions.newBuilder()
92                     .setDeviceNetworkPolicy(DeviceNetworkPolicy.DOWNLOAD_ON_ANY_NETWORK)
93                     .setDeviceStoragePolicy(DeviceStoragePolicy.BLOCK_DOWNLOAD_LOWER_THRESHOLD)
94                     .build())
95             .setExpirationDate(1234567890)
96             .setStaleLifetimeSecs(123456)
97             .setTrafficTag(3)
98             .setPreserveFilenamesAndIsolateFiles(true)
99             .addAllFile(
100                 ImmutableList.of(
101                     DataFile.newBuilder()
102                         .setFileId("one")
103                         .setByteSize(200)
104                         .setUrlToDownload("https://www.google.com/")
105                         .setChecksum("checksum1")
106                         .build(),
107                     DataFile.newBuilder()
108                         .setFileId("two")
109                         .setByteSize(500)
110                         .setUrlToDownload("https://www.instagram.com/")
111                         .setChecksum("checksum2")
112                         .build()))
113             .addAllGroupExtraHttpHeaders(
114                 ImmutableList.of(
115                     ExtraHttpHeader.newBuilder().setKey("k1").setValue("v1").build(),
116                     ExtraHttpHeader.newBuilder().setKey("k2").setValue("v2").build()))
117             .build();
118     DataFileGroupInternal unused = ProtoConversionUtil.convert(group);
119   }
120 
121   @Test
convert_fromDataFileGroup_toDataFileGroupInternal_parseFromTextProto()122   public void convert_fromDataFileGroup_toDataFileGroupInternal_parseFromTextProto()
123       throws Exception {
124     DataFileGroup dataFileGroup = getDataFileGroupFromTextProto(R.raw.group_data_pb);
125     DataFileGroupInternal dataFileGroupInternal =
126         getDataFileGroupInternalFromTextProto(R.raw.group_internal_data_pb);
127     assertThat(ProtoConversionUtil.convert(dataFileGroup)).isEqualTo(dataFileGroupInternal);
128   }
129 
130   @Test
convert_fromDataFileGroup_toDataFileGroupInternal_parseFromTextProto_optionalUnset()131   public void convert_fromDataFileGroup_toDataFileGroupInternal_parseFromTextProto_optionalUnset()
132       throws Exception {
133     DataFileGroup dataFileGroup = getDataFileGroupFromTextProto(R.raw.group_optional_unset_data_pb);
134     DataFileGroupInternal dataFileGroupInternal =
135         getDataFileGroupInternalFromTextProto(R.raw.group_internal_optional_unset_data_pb);
136     assertThat(ProtoConversionUtil.convert(dataFileGroup)).isEqualTo(dataFileGroupInternal);
137   }
138 
139   /**
140    * The main purpose of this test is to make sure that after migration, we are still able to
141    * interpret and parse the group metadata correctly. The raw metadata was generated by the proto
142    * {@link DataFileGroup} with extensions before the migration. Since we reuse the same tag number,
143    * the extension should now be parsed into {@link DataFileGroupBookkeeping}.
144    */
145   @Test
convert_parseRawProtoWithExtensions()146   public void convert_parseRawProtoWithExtensions() throws Exception {
147     DataFileGroupInternal expected =
148         ProtoConversionUtil.convert(
149                 MddTestUtil.createDataFileGroup(/* fileGroupName= */ "test-group", 2))
150             .toBuilder()
151             .setBookkeeping(
152                 DataFileGroupBookkeeping.newBuilder()
153                     .setGroupNewFilesReceivedTimestamp(1000)
154                     .build())
155             .build();
156 
157     // Read the raw group with extension from file.
158     Uri uri = Uri.fromFile(RAW_GROUP_WITH_EXTENSION);
159     byte[] bytes = fileStorage.open(uri, ReadByteArrayOpener.create());
160 
161     // Make sure that the proto with extension is correcly parsed.
162     DataFileGroupInternal parsedFromRawProto =
163         DataFileGroupInternal.parseFrom(bytes, ExtensionRegistryLite.getEmptyRegistry());
164     assertThat(parsedFromRawProto).isEqualTo(expected);
165   }
166 
167   @Test
convert_onDownloadConditions()168   public void convert_onDownloadConditions() throws Exception {
169     DownloadConditions downloadConditions =
170         DownloadConditions.newBuilder()
171             .setDeviceNetworkPolicy(DeviceNetworkPolicy.DOWNLOAD_ON_ANY_NETWORK)
172             .setDeviceStoragePolicy(DeviceStoragePolicy.BLOCK_DOWNLOAD_LOWER_THRESHOLD)
173             .build();
174     MetadataProto.DownloadConditions convertedDownloadConditions =
175         ProtoConversionUtil.convert(downloadConditions);
176     assertThat(convertedDownloadConditions.hasDeviceStoragePolicy()).isTrue();
177     assertThat(convertedDownloadConditions.hasDeviceNetworkPolicy()).isTrue();
178     assertThat(convertedDownloadConditions.hasDownloadFirstOnWifiPeriodSecs()).isFalse();
179     assertThat(convertedDownloadConditions.getDeviceNetworkPolicy())
180         .isEqualTo(MetadataProto.DownloadConditions.DeviceNetworkPolicy.DOWNLOAD_ON_ANY_NETWORK);
181     assertThat(convertedDownloadConditions.getDeviceStoragePolicy())
182         .isEqualTo(
183             MetadataProto.DownloadConditions.DeviceStoragePolicy.BLOCK_DOWNLOAD_LOWER_THRESHOLD);
184   }
185 
186   @Test
convertDataFile_convertsFields()187   public void convertDataFile_convertsFields() {
188     Transforms downloadTransforms =
189         Transforms.newBuilder()
190             .addTransform(
191                 Transform.newBuilder().setCompress(CompressTransform.getDefaultInstance()).build())
192             .build();
193     Transforms readTransforms =
194         Transforms.newBuilder()
195             .addTransform(Transform.newBuilder().setZip(ZipTransform.getDefaultInstance()).build())
196             .build();
197 
198     DataFile dataFileExternal =
199         DataFile.newBuilder()
200             .setFileId("test-file")
201             .setUrlToDownload("https://url.to.download")
202             .setByteSize(10)
203             .setChecksumType(DataFile.ChecksumType.NONE)
204             .setChecksum("testchecksum")
205             .setDownloadTransforms(downloadTransforms)
206             .setDownloadedFileChecksum("testdownloadedchecksum")
207             .setDownloadedFileByteSize(100)
208             .setReadTransforms(readTransforms)
209             .setAndroidSharingType(DataFile.AndroidSharingType.ANDROID_BLOB_WHEN_AVAILABLE)
210             .setAndroidSharingChecksumType(DataFile.AndroidSharingChecksumType.SHA2_256)
211             .setAndroidSharingChecksum("testandroidsharingchecksum")
212             .setRelativeFilePath("relative/file/path")
213             .addDeltaFile(DeltaFile.newBuilder().setUrlToDownload("url1").build())
214             .addDeltaFile(DeltaFile.newBuilder().setUrlToDownload("url2").build())
215             .build();
216 
217     MetadataProto.DataFile dataFileInternal = ProtoConversionUtil.convertDataFile(dataFileExternal);
218 
219     assertThat(dataFileInternal.getFileId()).isEqualTo("test-file");
220     assertThat(dataFileInternal.getUrlToDownload()).isEqualTo("https://url.to.download");
221     assertThat(dataFileInternal.getByteSize()).isEqualTo(10);
222     assertThat(dataFileInternal.getChecksumType())
223         .isEqualTo(MetadataProto.DataFile.ChecksumType.NONE);
224     assertThat(dataFileInternal.getChecksum()).isEqualTo("testchecksum");
225     assertThat(dataFileInternal.getDownloadTransforms()).isEqualTo(downloadTransforms);
226     assertThat(dataFileInternal.getDownloadedFileChecksum()).isEqualTo("testdownloadedchecksum");
227     assertThat(dataFileInternal.getDownloadedFileByteSize()).isEqualTo(100);
228     assertThat(dataFileInternal.getReadTransforms()).isEqualTo(readTransforms);
229     assertThat(dataFileInternal.getAndroidSharingType())
230         .isEqualTo(MetadataProto.DataFile.AndroidSharingType.ANDROID_BLOB_WHEN_AVAILABLE);
231     assertThat(dataFileInternal.getAndroidSharingChecksumType())
232         .isEqualTo(MetadataProto.DataFile.AndroidSharingChecksumType.SHA2_256);
233     assertThat(dataFileInternal.getAndroidSharingChecksum())
234         .isEqualTo("testandroidsharingchecksum");
235     assertThat(dataFileInternal.getRelativeFilePath()).isEqualTo("relative/file/path");
236 
237     assertThat(dataFileInternal.getDeltaFileCount()).isEqualTo(2);
238     assertThat(dataFileInternal.getDeltaFileList())
239         .comparingElementsUsing(
240             Correspondence.transforming(MetadataProto.DeltaFile::getUrlToDownload, "using url"))
241         .containsExactly("url1", "url2");
242   }
243 
244   @Test
convertDeltaFile_convertsFields()245   public void convertDeltaFile_convertsFields() {
246     DeltaFile deltaFileExternal =
247         DeltaFile.newBuilder()
248             .setUrlToDownload("https://url.to.download")
249             .setByteSize(10)
250             .setChecksum("testchecksum")
251             .setDiffDecoder(DeltaFile.DiffDecoder.VC_DIFF)
252             .setBaseFile(BaseFile.newBuilder().setChecksum("testbasechecksum").build())
253             .build();
254 
255     MetadataProto.DeltaFile deltaFileInternal =
256         ProtoConversionUtil.convertDeltaFile(deltaFileExternal);
257 
258     assertThat(deltaFileInternal.getUrlToDownload()).isEqualTo("https://url.to.download");
259     assertThat(deltaFileInternal.getByteSize()).isEqualTo(10);
260     assertThat(deltaFileInternal.getChecksum()).isEqualTo("testchecksum");
261     assertThat(deltaFileInternal.getDiffDecoder())
262         .isEqualTo(MetadataProto.DeltaFile.DiffDecoder.VC_DIFF);
263     assertThat(deltaFileInternal.getBaseFile().getChecksum()).isEqualTo("testbasechecksum");
264   }
265 
getDataFileGroupFromTextProto(int rawResId)266   private static DataFileGroup getDataFileGroupFromTextProto(int rawResId) {
267     return ProtoParsers.parseFromRawRes(
268         ApplicationProvider.getApplicationContext(), DataFileGroup.parser(), rawResId);
269   }
270 
getDataFileGroupInternalFromTextProto(int rawResId)271   private static DataFileGroupInternal getDataFileGroupInternalFromTextProto(int rawResId) {
272     return ProtoParsers.parseFromRawRes(
273         ApplicationProvider.getApplicationContext(), DataFileGroupInternal.parser(), rawResId);
274   }
275 }
276