| /* |
| * Copyright 2022 Google LLC |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.google.android.libraries.mobiledatadownload.internal.util; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| |
| import android.content.Context; |
| import android.net.Uri; |
| import androidx.test.core.app.ApplicationProvider; |
| import com.google.android.libraries.mobiledatadownload.file.SynchronousFileStorage; |
| import com.google.android.libraries.mobiledatadownload.file.backends.AndroidFileBackend; |
| import com.google.android.libraries.mobiledatadownload.file.backends.JavaFileBackend; |
| import com.google.android.libraries.mobiledatadownload.file.openers.ReadByteArrayOpener; |
| import com.google.android.libraries.mobiledatadownload.internal.MddTestUtil; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.truth.Correspondence; |
| import com.google.mobiledatadownload.DownloadConfigProto.BaseFile; |
| import com.google.mobiledatadownload.DownloadConfigProto.DataFile; |
| import com.google.mobiledatadownload.DownloadConfigProto.DataFileGroup; |
| import com.google.mobiledatadownload.DownloadConfigProto.DataFileGroup.AllowedReaders; |
| import com.google.mobiledatadownload.DownloadConfigProto.DeltaFile; |
| import com.google.mobiledatadownload.DownloadConfigProto.DownloadConditions; |
| import com.google.mobiledatadownload.DownloadConfigProto.DownloadConditions.DeviceNetworkPolicy; |
| import com.google.mobiledatadownload.DownloadConfigProto.DownloadConditions.DeviceStoragePolicy; |
| import com.google.mobiledatadownload.DownloadConfigProto.ExtraHttpHeader; |
| import com.google.mobiledatadownload.TransformProto.CompressTransform; |
| import com.google.mobiledatadownload.TransformProto.Transform; |
| import com.google.mobiledatadownload.TransformProto.Transforms; |
| import com.google.mobiledatadownload.TransformProto.ZipTransform; |
| import com.google.mobiledatadownload.internal.MetadataProto; |
| import com.google.mobiledatadownload.internal.MetadataProto.DataFileGroupBookkeeping; |
| import com.google.mobiledatadownload.internal.MetadataProto.DataFileGroupInternal; |
| import com.google.protobuf.ExtensionRegistryLite; |
| import com.google.protobuf.contrib.android.ProtoParsers; |
| import com.google.testing.util.TestUtil; |
| import java.io.File; |
| import org.junit.Before; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.mockito.junit.MockitoJUnit; |
| import org.mockito.junit.MockitoRule; |
| import org.robolectric.RobolectricTestRunner; |
| |
| /** Unit tests for {@link ProtoConversionUtil}. */ |
| @RunWith(RobolectricTestRunner.class) |
| public final class ProtoConversionUtilTest { |
| |
| @Rule public final MockitoRule mocks = MockitoJUnit.rule(); |
| |
| private SynchronousFileStorage fileStorage; |
| private Context context; |
| |
| // The raw test data folder in google3. |
| private static final String TEST_DATA_DIR = |
| TestUtil.getRunfilesDir() |
| + "/google3/third_party/java_src/android_libs/mobiledatadownload/javatests/com/google/android/libraries/mobiledatadownload/internal/util/testdata/"; |
| private static final File RAW_GROUP_WITH_EXTENSION = |
| new File(TEST_DATA_DIR, "raw_group_with_extension"); |
| |
| @Before |
| public void setUp() throws Exception { |
| context = ApplicationProvider.getApplicationContext(); |
| fileStorage = |
| new SynchronousFileStorage( |
| ImmutableList.of(AndroidFileBackend.builder(context).build(), new JavaFileBackend())); |
| } |
| |
| @Test |
| public void convert_fromDataFileGroup_toDataFileGroupInternal_noThrow() throws Exception { |
| DataFileGroup group = |
| DataFileGroup.newBuilder() |
| .setGroupName("test-group") |
| .setOwnerPackage("com.google.android.libraries.mobiledatadownload") |
| .setFileGroupVersionNumber(12) |
| .setAllowedReadersEnum(AllowedReaders.ALL_GOOGLE_APPS) |
| .setDownloadConditions( |
| DownloadConditions.newBuilder() |
| .setDeviceNetworkPolicy(DeviceNetworkPolicy.DOWNLOAD_ON_ANY_NETWORK) |
| .setDeviceStoragePolicy(DeviceStoragePolicy.BLOCK_DOWNLOAD_LOWER_THRESHOLD) |
| .build()) |
| .setExpirationDate(1234567890) |
| .setStaleLifetimeSecs(123456) |
| .setTrafficTag(3) |
| .setPreserveFilenamesAndIsolateFiles(true) |
| .addAllFile( |
| ImmutableList.of( |
| DataFile.newBuilder() |
| .setFileId("one") |
| .setByteSize(200) |
| .setUrlToDownload("https://www.google.com/") |
| .setChecksum("checksum1") |
| .build(), |
| DataFile.newBuilder() |
| .setFileId("two") |
| .setByteSize(500) |
| .setUrlToDownload("https://www.instagram.com/") |
| .setChecksum("checksum2") |
| .build())) |
| .addAllGroupExtraHttpHeaders( |
| ImmutableList.of( |
| ExtraHttpHeader.newBuilder().setKey("k1").setValue("v1").build(), |
| ExtraHttpHeader.newBuilder().setKey("k2").setValue("v2").build())) |
| .build(); |
| DataFileGroupInternal unused = ProtoConversionUtil.convert(group); |
| } |
| |
| @Test |
| public void convert_fromDataFileGroup_toDataFileGroupInternal_parseFromTextProto() |
| throws Exception { |
| DataFileGroup dataFileGroup = getDataFileGroupFromTextProto(R.raw.group_data_pb); |
| DataFileGroupInternal dataFileGroupInternal = |
| getDataFileGroupInternalFromTextProto(R.raw.group_internal_data_pb); |
| assertThat(ProtoConversionUtil.convert(dataFileGroup)).isEqualTo(dataFileGroupInternal); |
| } |
| |
| @Test |
| public void convert_fromDataFileGroup_toDataFileGroupInternal_parseFromTextProto_optionalUnset() |
| throws Exception { |
| DataFileGroup dataFileGroup = getDataFileGroupFromTextProto(R.raw.group_optional_unset_data_pb); |
| DataFileGroupInternal dataFileGroupInternal = |
| getDataFileGroupInternalFromTextProto(R.raw.group_internal_optional_unset_data_pb); |
| assertThat(ProtoConversionUtil.convert(dataFileGroup)).isEqualTo(dataFileGroupInternal); |
| } |
| |
| /** |
| * The main purpose of this test is to make sure that after migration, we are still able to |
| * interpret and parse the group metadata correctly. The raw metadata was generated by the proto |
| * {@link DataFileGroup} with extensions before the migration. Since we reuse the same tag number, |
| * the extension should now be parsed into {@link DataFileGroupBookkeeping}. |
| */ |
| @Test |
| public void convert_parseRawProtoWithExtensions() throws Exception { |
| DataFileGroupInternal expected = |
| ProtoConversionUtil.convert( |
| MddTestUtil.createDataFileGroup(/*fileGroupName=*/ "test-group", 2)) |
| .toBuilder() |
| .setBookkeeping( |
| DataFileGroupBookkeeping.newBuilder() |
| .setGroupNewFilesReceivedTimestamp(1000) |
| .build()) |
| .build(); |
| |
| // Read the raw group with extension from file. |
| Uri uri = Uri.fromFile(RAW_GROUP_WITH_EXTENSION); |
| byte[] bytes = fileStorage.open(uri, ReadByteArrayOpener.create()); |
| |
| // Make sure that the proto with extension is correcly parsed. |
| DataFileGroupInternal parsedFromRawProto = |
| DataFileGroupInternal.parseFrom(bytes, ExtensionRegistryLite.getEmptyRegistry()); |
| assertThat(parsedFromRawProto).isEqualTo(expected); |
| } |
| |
| @Test |
| public void convert_onDownloadConditions() throws Exception { |
| DownloadConditions downloadConditions = |
| DownloadConditions.newBuilder() |
| .setDeviceNetworkPolicy(DeviceNetworkPolicy.DOWNLOAD_ON_ANY_NETWORK) |
| .setDeviceStoragePolicy(DeviceStoragePolicy.BLOCK_DOWNLOAD_LOWER_THRESHOLD) |
| .build(); |
| MetadataProto.DownloadConditions convertedDownloadConditions = |
| ProtoConversionUtil.convert(downloadConditions); |
| assertThat(convertedDownloadConditions.hasDeviceStoragePolicy()).isTrue(); |
| assertThat(convertedDownloadConditions.hasDeviceNetworkPolicy()).isTrue(); |
| assertThat(convertedDownloadConditions.hasDownloadFirstOnWifiPeriodSecs()).isFalse(); |
| assertThat(convertedDownloadConditions.getDeviceNetworkPolicy()) |
| .isEqualTo(MetadataProto.DownloadConditions.DeviceNetworkPolicy.DOWNLOAD_ON_ANY_NETWORK); |
| assertThat(convertedDownloadConditions.getDeviceStoragePolicy()) |
| .isEqualTo( |
| MetadataProto.DownloadConditions.DeviceStoragePolicy.BLOCK_DOWNLOAD_LOWER_THRESHOLD); |
| } |
| |
| @Test |
| public void convertDataFile_convertsFields() { |
| Transforms downloadTransforms = |
| Transforms.newBuilder() |
| .addTransform( |
| Transform.newBuilder().setCompress(CompressTransform.getDefaultInstance()).build()) |
| .build(); |
| Transforms readTransforms = |
| Transforms.newBuilder() |
| .addTransform(Transform.newBuilder().setZip(ZipTransform.getDefaultInstance()).build()) |
| .build(); |
| |
| DataFile dataFileExternal = |
| DataFile.newBuilder() |
| .setFileId("test-file") |
| .setUrlToDownload("https://url.to.download") |
| .setByteSize(10) |
| .setChecksumType(DataFile.ChecksumType.NONE) |
| .setChecksum("testchecksum") |
| .setDownloadTransforms(downloadTransforms) |
| .setDownloadedFileChecksum("testdownloadedchecksum") |
| .setDownloadedFileByteSize(100) |
| .setReadTransforms(readTransforms) |
| .setAndroidSharingType(DataFile.AndroidSharingType.ANDROID_BLOB_WHEN_AVAILABLE) |
| .setAndroidSharingChecksumType(DataFile.AndroidSharingChecksumType.SHA2_256) |
| .setAndroidSharingChecksum("testandroidsharingchecksum") |
| .setRelativeFilePath("relative/file/path") |
| .addDeltaFile(DeltaFile.newBuilder().setUrlToDownload("url1").build()) |
| .addDeltaFile(DeltaFile.newBuilder().setUrlToDownload("url2").build()) |
| .build(); |
| |
| MetadataProto.DataFile dataFileInternal = ProtoConversionUtil.convertDataFile(dataFileExternal); |
| |
| assertThat(dataFileInternal.getFileId()).isEqualTo("test-file"); |
| assertThat(dataFileInternal.getUrlToDownload()).isEqualTo("https://url.to.download"); |
| assertThat(dataFileInternal.getByteSize()).isEqualTo(10); |
| assertThat(dataFileInternal.getChecksumType()) |
| .isEqualTo(MetadataProto.DataFile.ChecksumType.NONE); |
| assertThat(dataFileInternal.getChecksum()).isEqualTo("testchecksum"); |
| assertThat(dataFileInternal.getDownloadTransforms()).isEqualTo(downloadTransforms); |
| assertThat(dataFileInternal.getDownloadedFileChecksum()).isEqualTo("testdownloadedchecksum"); |
| assertThat(dataFileInternal.getDownloadedFileByteSize()).isEqualTo(100); |
| assertThat(dataFileInternal.getReadTransforms()).isEqualTo(readTransforms); |
| assertThat(dataFileInternal.getAndroidSharingType()) |
| .isEqualTo(MetadataProto.DataFile.AndroidSharingType.ANDROID_BLOB_WHEN_AVAILABLE); |
| assertThat(dataFileInternal.getAndroidSharingChecksumType()) |
| .isEqualTo(MetadataProto.DataFile.AndroidSharingChecksumType.SHA2_256); |
| assertThat(dataFileInternal.getAndroidSharingChecksum()) |
| .isEqualTo("testandroidsharingchecksum"); |
| assertThat(dataFileInternal.getRelativeFilePath()).isEqualTo("relative/file/path"); |
| |
| assertThat(dataFileInternal.getDeltaFileCount()).isEqualTo(2); |
| assertThat(dataFileInternal.getDeltaFileList()) |
| .comparingElementsUsing( |
| Correspondence.transforming(MetadataProto.DeltaFile::getUrlToDownload, "using url")) |
| .containsExactly("url1", "url2"); |
| } |
| |
| @Test |
| public void convertDeltaFile_convertsFields() { |
| DeltaFile deltaFileExternal = |
| DeltaFile.newBuilder() |
| .setUrlToDownload("https://url.to.download") |
| .setByteSize(10) |
| .setChecksum("testchecksum") |
| .setDiffDecoder(DeltaFile.DiffDecoder.VC_DIFF) |
| .setBaseFile(BaseFile.newBuilder().setChecksum("testbasechecksum").build()) |
| .build(); |
| |
| MetadataProto.DeltaFile deltaFileInternal = |
| ProtoConversionUtil.convertDeltaFile(deltaFileExternal); |
| |
| assertThat(deltaFileInternal.getUrlToDownload()).isEqualTo("https://url.to.download"); |
| assertThat(deltaFileInternal.getByteSize()).isEqualTo(10); |
| assertThat(deltaFileInternal.getChecksum()).isEqualTo("testchecksum"); |
| assertThat(deltaFileInternal.getDiffDecoder()) |
| .isEqualTo(MetadataProto.DeltaFile.DiffDecoder.VC_DIFF); |
| assertThat(deltaFileInternal.getBaseFile().getChecksum()).isEqualTo("testbasechecksum"); |
| } |
| |
| private static DataFileGroup getDataFileGroupFromTextProto(int rawResId) { |
| return ProtoParsers.parseFromRawRes( |
| ApplicationProvider.getApplicationContext(), DataFileGroup.parser(), rawResId); |
| } |
| |
| private static DataFileGroupInternal getDataFileGroupInternalFromTextProto(int rawResId) { |
| return ProtoParsers.parseFromRawRes( |
| ApplicationProvider.getApplicationContext(), DataFileGroupInternal.parser(), rawResId); |
| } |
| } |