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; 17 18 import static com.google.android.libraries.mobiledatadownload.TestFileGroupPopulator.FILE_CHECKSUM; 19 import static com.google.android.libraries.mobiledatadownload.TestFileGroupPopulator.FILE_ID; 20 import static com.google.android.libraries.mobiledatadownload.TestFileGroupPopulator.FILE_SIZE; 21 import static com.google.android.libraries.mobiledatadownload.TestFileGroupPopulator.FILE_URL; 22 import static com.google.android.libraries.mobiledatadownload.testing.MddTestDependencies.ExecutorType; 23 import static com.google.common.truth.Truth.assertThat; 24 import static java.util.concurrent.TimeUnit.SECONDS; 25 26 import android.accounts.Account; 27 import android.content.Context; 28 import androidx.test.core.app.ApplicationProvider; 29 import com.google.android.libraries.mobiledatadownload.account.AccountUtil; 30 import com.google.android.libraries.mobiledatadownload.file.SynchronousFileStorage; 31 import com.google.android.libraries.mobiledatadownload.file.backends.AndroidFileBackend; 32 import com.google.android.libraries.mobiledatadownload.file.backends.JavaFileBackend; 33 import com.google.android.libraries.mobiledatadownload.monitor.NetworkUsageMonitor; 34 import com.google.android.libraries.mobiledatadownload.testing.FakeTimeSource; 35 import com.google.android.libraries.mobiledatadownload.testing.MddTestDependencies; 36 import com.google.android.libraries.mobiledatadownload.testing.TestFileDownloader; 37 import com.google.android.libraries.mobiledatadownload.testing.TestFlags; 38 import com.google.common.base.Optional; 39 import com.google.common.collect.ImmutableList; 40 import com.google.common.util.concurrent.ListeningExecutorService; 41 import com.google.common.util.concurrent.ListeningScheduledExecutorService; 42 import com.google.common.util.concurrent.MoreExecutors; 43 import com.google.mobiledatadownload.ClientConfigProto.ClientFileGroup; 44 import com.google.mobiledatadownload.DownloadConfigProto.DataFile; 45 import com.google.mobiledatadownload.DownloadConfigProto.DataFileGroup; 46 import com.google.mobiledatadownload.DownloadConfigProto.DownloadConditions; 47 import com.google.mobiledatadownload.DownloadConfigProto.DownloadConditions.DeviceNetworkPolicy; 48 import com.google.testing.junit.testparameterinjector.TestParameter; 49 import com.google.testing.junit.testparameterinjector.TestParameterInjector; 50 import java.util.concurrent.Executors; 51 import org.junit.Before; 52 import org.junit.Rule; 53 import org.junit.Test; 54 import org.junit.runner.RunWith; 55 import org.mockito.Mock; 56 import org.mockito.junit.MockitoJUnit; 57 import org.mockito.junit.MockitoRule; 58 59 /** 60 * Integration Tests that relate to interactions with MDD's Isolated Structures feature 61 * 62 * <p>Tests should be included here if they test MDD's behavior regarding reading/writing isolated 63 * structure groups. 64 */ 65 @RunWith(TestParameterInjector.class) 66 public class MobileDataDownloadIsolatedStructuresIntegrationTest { 67 68 private static final String TAG = "MDDIsolatedStructuresIntegrationTest"; 69 private static final int MAX_MDD_API_WAIT_TIME_SECS = 5; 70 71 private static final String GROUP_NAME_1 = "test-group-1"; 72 private static final String GROUP_NAME_2 = "test-group-2"; 73 74 private static final String VARIANT_1 = "test-variant-1"; 75 private static final String VARIANT_2 = "test-variant-2"; 76 77 private static final Account ACCOUNT_1 = AccountUtil.create("account-name-1", "account-type"); 78 private static final Account ACCOUNT_2 = AccountUtil.create("account-name-2", "account-type"); 79 80 private static final String TEST_DATA_RELATIVE_PATH = 81 "third_party/java_src/android_libs/mobiledatadownload/javatests/com/google/android/libraries/mobiledatadownload/testdata/"; 82 83 private static final ListeningScheduledExecutorService DOWNLOAD_EXECUTOR = 84 MoreExecutors.listeningDecorator(Executors.newScheduledThreadPool(2)); 85 86 private static final Context context = ApplicationProvider.getApplicationContext(); 87 88 private final NetworkUsageMonitor networkUsageMonitor = 89 new NetworkUsageMonitor(context, new FakeTimeSource()); 90 91 private final SynchronousFileStorage fileStorage = 92 new SynchronousFileStorage( 93 ImmutableList.of(AndroidFileBackend.builder(context).build(), new JavaFileBackend()), 94 ImmutableList.of(), 95 ImmutableList.of(networkUsageMonitor)); 96 97 private final TestFlags flags = new TestFlags(); 98 99 private ListeningExecutorService controlExecutor; 100 101 @Mock private Logger mockLogger; 102 @Mock private TaskScheduler mockTaskScheduler; 103 104 @Rule(order = 1) 105 public final MockitoRule mocks = MockitoJUnit.rule(); 106 107 @TestParameter ExecutorType controlExecutorType; 108 109 @Before setUp()110 public void setUp() throws Exception { 111 112 controlExecutor = controlExecutorType.executor(); 113 } 114 115 @Test addFileGroup_whenImmediatelyComplete_createsCorrectIsolatedRoot( @estParameter boolean sameGroupName, @TestParameter boolean sameAccount, @TestParameter boolean sameVariantId)116 public void addFileGroup_whenImmediatelyComplete_createsCorrectIsolatedRoot( 117 @TestParameter boolean sameGroupName, 118 @TestParameter boolean sameAccount, 119 @TestParameter boolean sameVariantId) 120 throws Exception { 121 Optional<String> instanceId = Optional.of(MddTestDependencies.randomInstanceId()); 122 123 String groupName1 = GROUP_NAME_1; 124 String variantId1 = VARIANT_1; 125 Account account1 = ACCOUNT_1; 126 127 // Define group2 properties based on test parameters 128 String groupName2 = sameGroupName ? GROUP_NAME_1 : GROUP_NAME_2; 129 String variantId2 = sameVariantId ? VARIANT_1 : VARIANT_2; 130 Account account2 = sameAccount ? ACCOUNT_1 : ACCOUNT_2; 131 132 DataFileGroup symlinkGroup1 = buildSymlinkGroup(groupName1, variantId1); 133 DataFileGroup symlinkGroup2 = buildSymlinkGroup(groupName2, variantId2); 134 135 MobileDataDownload mobileDataDownload = 136 builderForTest() 137 .setInstanceIdOptional(instanceId) 138 .setFileDownloaderSupplier( 139 () -> 140 new TestFileDownloader( 141 TEST_DATA_RELATIVE_PATH, 142 fileStorage, 143 MoreExecutors.listeningDecorator(DOWNLOAD_EXECUTOR))) 144 .build(); 145 146 // Add group1 and download it 147 mobileDataDownload 148 .addFileGroup( 149 AddFileGroupRequest.newBuilder() 150 .setDataFileGroup(symlinkGroup1) 151 .setVariantIdOptional(Optional.of(variantId1)) 152 .setAccountOptional(Optional.of(account1)) 153 .build()) 154 .get(MAX_MDD_API_WAIT_TIME_SECS, SECONDS); 155 ClientFileGroup downloadedSymlinkGroup1 = 156 mobileDataDownload 157 .downloadFileGroup( 158 DownloadFileGroupRequest.newBuilder() 159 .setGroupName(groupName1) 160 .setVariantIdOptional(Optional.of(variantId1)) 161 .setAccountOptional(Optional.of(account1)) 162 .build()) 163 .get(MAX_MDD_API_WAIT_TIME_SECS, SECONDS); 164 165 // Add group2 and get it since it should be immediately downloaded. 166 mobileDataDownload 167 .addFileGroup( 168 AddFileGroupRequest.newBuilder() 169 .setDataFileGroup(symlinkGroup2) 170 .setVariantIdOptional(Optional.of(variantId2)) 171 .setAccountOptional(Optional.of(account2)) 172 .build()) 173 .get(MAX_MDD_API_WAIT_TIME_SECS, SECONDS); 174 ClientFileGroup downloadedSymlinkGroup2 = 175 mobileDataDownload 176 .getFileGroup( 177 GetFileGroupRequest.newBuilder() 178 .setGroupName(groupName2) 179 .setVariantIdOptional(Optional.of(variantId2)) 180 .setAccountOptional(Optional.of(account2)) 181 .build()) 182 .get(MAX_MDD_API_WAIT_TIME_SECS, SECONDS); 183 184 String isolatedFileUriGroup1 = downloadedSymlinkGroup1.getFile(0).getFileUri(); 185 String isolatedFileUriGroup2 = downloadedSymlinkGroup2.getFile(0).getFileUri(); 186 assertThat(isolatedFileUriGroup1).contains(groupName1 + "_"); 187 assertThat(isolatedFileUriGroup2).contains(groupName2 + "_"); 188 189 // assert that uris are the same if all test parameters are true and different if otherwise. 190 assertThat(isolatedFileUriGroup1.equalsIgnoreCase(isolatedFileUriGroup2)) 191 .isEqualTo(sameGroupName && sameVariantId && sameAccount); 192 } 193 buildSymlinkGroup(String groupName, String variantId)194 private static DataFileGroup buildSymlinkGroup(String groupName, String variantId) { 195 return DataFileGroup.newBuilder() 196 .setOwnerPackage(context.getPackageName()) 197 .setGroupName(groupName) 198 .setDownloadConditions( 199 DownloadConditions.newBuilder() 200 .setDeviceNetworkPolicy(DeviceNetworkPolicy.DOWNLOAD_ON_ANY_NETWORK) 201 .build()) 202 .addFile( 203 DataFile.newBuilder() 204 .setFileId(FILE_ID) 205 .setByteSize(FILE_SIZE) 206 .setChecksum(FILE_CHECKSUM) 207 .setUrlToDownload(FILE_URL) 208 .setRelativeFilePath("my-file.tmp") 209 .build()) 210 .setPreserveFilenamesAndIsolateFiles(true) 211 .setVariantId(variantId) 212 .setBuildId(9999) 213 .build(); 214 } 215 builderForTest()216 private MobileDataDownloadBuilder builderForTest() { 217 return MobileDataDownloadBuilder.newBuilder() 218 .setContext(context) 219 .setControlExecutor(controlExecutor) 220 .setTaskScheduler(Optional.of(mockTaskScheduler)) 221 .setLoggerOptional(Optional.of(mockLogger)) 222 .setDeltaDecoderOptional(Optional.absent()) 223 .setFileStorage(fileStorage) 224 .setNetworkUsageMonitor(networkUsageMonitor) 225 .setFlagsOptional(Optional.of(flags)); 226 } 227 } 228