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; 17 18 import static com.google.common.truth.Truth.assertThat; 19 import static org.mockito.ArgumentMatchers.any; 20 import static org.mockito.Mockito.doThrow; 21 import static org.mockito.Mockito.never; 22 import static org.mockito.Mockito.times; 23 import static org.mockito.Mockito.verify; 24 import static org.mockito.Mockito.verifyNoMoreInteractions; 25 import static org.mockito.Mockito.when; 26 27 import android.content.Context; 28 import android.net.Uri; 29 import androidx.test.core.app.ApplicationProvider; 30 import com.google.mobiledatadownload.internal.MetadataProto.DataFile; 31 import com.google.mobiledatadownload.internal.MetadataProto.DataFileGroupBookkeeping; 32 import com.google.mobiledatadownload.internal.MetadataProto.DataFileGroupInternal; 33 import com.google.mobiledatadownload.internal.MetadataProto.DataFileGroupInternal.AllowedReaders; 34 import com.google.mobiledatadownload.internal.MetadataProto.FileStatus; 35 import com.google.mobiledatadownload.internal.MetadataProto.GroupKey; 36 import com.google.mobiledatadownload.internal.MetadataProto.NewFileKey; 37 import com.google.mobiledatadownload.internal.MetadataProto.SharedFile; 38 import com.google.android.libraries.mobiledatadownload.SilentFeedback; 39 import com.google.android.libraries.mobiledatadownload.delta.DeltaDecoder; 40 import com.google.android.libraries.mobiledatadownload.file.SynchronousFileStorage; 41 import com.google.android.libraries.mobiledatadownload.file.spi.Backend; 42 import com.google.android.libraries.mobiledatadownload.internal.Migrations.FileKeyVersion; 43 import com.google.android.libraries.mobiledatadownload.internal.collect.GroupKeyAndGroup; 44 import com.google.android.libraries.mobiledatadownload.internal.downloader.MddFileDownloader; 45 import com.google.android.libraries.mobiledatadownload.internal.logging.EventLogger; 46 import com.google.android.libraries.mobiledatadownload.internal.util.DirectoryUtil; 47 import com.google.android.libraries.mobiledatadownload.monitor.DownloadProgressMonitor; 48 import com.google.android.libraries.mobiledatadownload.testing.FakeTimeSource; 49 import com.google.android.libraries.mobiledatadownload.testing.TestFlags; 50 import com.google.common.base.Optional; 51 import com.google.common.collect.ImmutableList; 52 import com.google.common.util.concurrent.Futures; 53 import com.google.common.util.concurrent.MoreExecutors; 54 import com.google.mobiledatadownload.LogEnumsProto.MddClientEvent; 55 import java.io.IOException; 56 import java.util.ArrayList; 57 import java.util.Arrays; 58 import java.util.Calendar; 59 import java.util.Collections; 60 import java.util.List; 61 import java.util.concurrent.atomic.AtomicReference; 62 import org.junit.Before; 63 import org.junit.Rule; 64 import org.junit.Test; 65 import org.junit.runner.RunWith; 66 import org.mockito.Mock; 67 import org.mockito.invocation.InvocationOnMock; 68 import org.mockito.junit.MockitoJUnit; 69 import org.mockito.junit.MockitoRule; 70 import org.robolectric.RobolectricTestRunner; 71 72 @RunWith(RobolectricTestRunner.class) 73 public final class ExpirationHandlerTest { 74 75 @Mock SharedFileManager mockSharedFileManager; 76 @Mock SharedFilesMetadata mockSharedFilesMetadata; 77 @Mock FileGroupsMetadata mockFileGroupsMetadata; 78 @Mock EventLogger mockEventLogger; 79 @Mock SilentFeedback mockSilentFeedback; 80 81 @Mock Backend mockBackend; 82 @Mock Backend mockBlobStoreBackend; 83 @Mock MddFileDownloader mockDownloader; 84 @Mock DownloadProgressMonitor mockDownloadMonitor; 85 86 // Allows mockFileGroupsMetadata to correctly respond to writeStaleGroups and getAllStaleGroups. 87 AtomicReference<ImmutableList<DataFileGroupInternal>> fileGroupsMetadataStaleGroups = 88 new AtomicReference<>(ImmutableList.of()); 89 90 private SynchronousFileStorage fileStorage; 91 private Context context; 92 private ExpirationHandler expirationHandler; 93 private ExpirationHandler expirationHandlerNoMocks; 94 private FakeTimeSource testClock; 95 private Uri baseDownloadDirectoryUri; 96 private Uri baseDownloadSymlinkDirectoryUri; 97 private FileGroupsMetadata fileGroupsMetadata; 98 private SharedFilesMetadata sharedFilesMetadata; 99 private SharedFileManager sharedFileManager; 100 101 private static final String TEST_GROUP_1 = "test-group-1"; 102 private static final GroupKey TEST_KEY_1 = GroupKey.getDefaultInstance(); 103 104 private static final String TEST_GROUP_2 = "test-group-2"; 105 private static final GroupKey TEST_KEY_2 = GroupKey.getDefaultInstance(); 106 107 private final Uri testUri1 = 108 Uri.parse( 109 "android://com.google.android.libraries.mobiledatadownload.internal/files/datadownload/shared/public/file_1"); 110 111 private final Uri testUri2 = 112 Uri.parse( 113 "android://com.google.android.libraries.mobiledatadownload.internal/files/datadownload/shared/public/file_2"); 114 115 private final Uri tempTestUri2 = 116 Uri.parse( 117 "android://com.google.android.libraries.mobiledatadownload.internal/files/datadownload/shared/public/file_2_temp"); 118 119 private final Uri testUri3 = 120 Uri.parse( 121 "android://com.google.android.libraries.mobiledatadownload.internal/files/datadownload/shared/public/file_3"); 122 123 private final Uri testUri4 = 124 Uri.parse( 125 "android://com.google.android.libraries.mobiledatadownload.internal/files/datadownload/shared/public/file_4"); 126 127 // MDD file URI could be a folder which is unzipped from zip folder download transform 128 private final Uri testDirUri1 = 129 Uri.parse( 130 "android://com.google.android.libraries.mobiledatadownload.internal/files/datadownload/shared/public/dir_1"); 131 132 private final Uri testDirFileUri1 = 133 Uri.parse( 134 "android://com.google.android.libraries.mobiledatadownload.internal/files/datadownload/shared/public/dir_1/file_1"); 135 136 private final Uri testDirFileUri2 = 137 Uri.parse( 138 "android://com.google.android.libraries.mobiledatadownload.internal/files/datadownload/shared/public/dir_1/file_2"); 139 140 private final Uri dirForAll = 141 Uri.parse( 142 "android://com.google.android.libraries.mobiledatadownload.internal/files/datadownload/shared/public_3p"); 143 private final Uri dirFor1p = 144 Uri.parse( 145 "android://com.google.android.libraries.mobiledatadownload.internal/files/datadownload/shared/public"); 146 private final Uri dirFor0p = 147 Uri.parse( 148 "android://com.google.android.libraries.mobiledatadownload.internal/files/datadownload/shared/private"); 149 150 private final Uri symlinkDirForGroup1 = 151 Uri.parse( 152 "android://com.google.android.libraries.mobiledatadownload.internal/files/datadownload/shared/links/public/test-group-1"); 153 private final Uri symlinkForUri1 = 154 Uri.parse( 155 "android://com.google.android.libraries.mobiledatadownload.internal/files/datadownload/shared/links/public/test-group-1/test-group-1_0"); 156 157 private final Uri symlinkDirForGroup2 = 158 Uri.parse( 159 "android://com.google.android.libraries.mobiledatadownload.internal/files/datadownload/shared/links/public/test-group-2"); 160 private final Uri symlinkForUri2 = 161 Uri.parse( 162 "android://com.google.android.libraries.mobiledatadownload.internal/files/datadownload/shared/links/public/test-group-2/test-group-2_0"); 163 164 private final TestFlags flags = new TestFlags(); 165 166 @Rule public final MockitoRule mocks = MockitoJUnit.rule(); 167 168 @Before setUp()169 public void setUp() throws Exception { 170 171 context = ApplicationProvider.getApplicationContext(); 172 173 testClock = new FakeTimeSource(); 174 175 baseDownloadDirectoryUri = DirectoryUtil.getBaseDownloadDirectory(context, Optional.absent()); 176 baseDownloadSymlinkDirectoryUri = 177 DirectoryUtil.getBaseDownloadSymlinkDirectory(context, Optional.absent()); 178 when(mockBackend.name()).thenReturn("android"); 179 when(mockBlobStoreBackend.name()).thenReturn("blobstore"); 180 setUpDirectoryMock(baseDownloadDirectoryUri, Arrays.asList(dirForAll, dirFor1p, dirFor0p)); 181 setUpDirectoryMock(dirForAll, ImmutableList.of()); 182 setUpDirectoryMock(dirFor0p, ImmutableList.of()); 183 setUpDirectoryMock(dirFor1p, ImmutableList.of()); 184 setUpDirectoryMock(testDirUri1, ImmutableList.of()); 185 fileStorage = new SynchronousFileStorage(Arrays.asList(mockBackend, mockBlobStoreBackend)); 186 187 expirationHandler = 188 new ExpirationHandler( 189 context, 190 mockFileGroupsMetadata, 191 mockSharedFileManager, 192 mockSharedFilesMetadata, 193 mockEventLogger, 194 testClock, 195 fileStorage, 196 Optional.absent(), 197 mockSilentFeedback, 198 MoreExecutors.directExecutor(), 199 flags); 200 201 // By default, mocks will return empty lists 202 when(mockFileGroupsMetadata.getAllFreshGroups()) 203 .thenReturn(Futures.immediateFuture(ImmutableList.of())); 204 when(mockFileGroupsMetadata.removeAllGroupsWithKeys(any())) 205 .thenReturn(Futures.immediateFuture(true)); 206 when(mockFileGroupsMetadata.removeAllStaleGroups()).thenReturn(Futures.immediateVoidFuture()); 207 when(mockSharedFileManager.removeFileEntry(any())).thenReturn(Futures.immediateFuture(true)); 208 when(mockSharedFilesMetadata.read(any())) 209 .thenReturn(Futures.immediateFuture(SharedFile.getDefaultInstance())); 210 211 // Calls to mockFileGroupsMetadata.writeStaleGroups() are reflected by getAllStaleGroups(). 212 when(mockFileGroupsMetadata.getAllStaleGroups()) 213 .thenAnswer(invocation -> Futures.immediateFuture(fileGroupsMetadataStaleGroups.get())); 214 when(mockFileGroupsMetadata.writeStaleGroups(any())) 215 .thenAnswer( 216 (InvocationOnMock invocation) -> { 217 List<DataFileGroupInternal> request = invocation.getArgument(0); 218 fileGroupsMetadataStaleGroups.set(ImmutableList.copyOf(request)); 219 return Futures.immediateFuture(true); 220 }); 221 } 222 setupForAndroidShared()223 private void setupForAndroidShared() { 224 // Construct an expiration handler without mocking the main classes 225 fileGroupsMetadata = 226 new SharedPreferencesFileGroupsMetadata( 227 context, 228 testClock, 229 mockSilentFeedback, 230 Optional.absent(), 231 MoreExecutors.directExecutor()); 232 Optional<DeltaDecoder> deltaDecoder = Optional.absent(); 233 sharedFilesMetadata = 234 new SharedPreferencesSharedFilesMetadata( 235 context, mockSilentFeedback, Optional.absent(), flags); 236 sharedFileManager = 237 new SharedFileManager( 238 context, 239 mockSilentFeedback, 240 sharedFilesMetadata, 241 fileStorage, 242 mockDownloader, 243 deltaDecoder, 244 Optional.of(mockDownloadMonitor), 245 mockEventLogger, 246 flags, 247 fileGroupsMetadata, 248 Optional.absent(), 249 MoreExecutors.directExecutor()); 250 251 expirationHandlerNoMocks = 252 new ExpirationHandler( 253 context, 254 fileGroupsMetadata, 255 sharedFileManager, 256 sharedFilesMetadata, 257 mockEventLogger, 258 testClock, 259 fileStorage, 260 Optional.absent(), 261 mockSilentFeedback, 262 MoreExecutors.directExecutor(), 263 flags); 264 } 265 266 @Test updateExpiration_noGroups()267 public void updateExpiration_noGroups() throws Exception { 268 when(mockFileGroupsMetadata.getAllFreshGroups()) 269 .thenReturn(Futures.immediateFuture(ImmutableList.of())); 270 when(mockSharedFilesMetadata.getAllFileKeys()) 271 .thenReturn(Futures.immediateFuture(ImmutableList.of())); 272 273 expirationHandler.updateExpiration().get(); 274 275 verify(mockFileGroupsMetadata, times(3)).getAllFreshGroups(); 276 verify(mockFileGroupsMetadata, times(2)).getAllStaleGroups(); 277 verify(mockFileGroupsMetadata).removeAllGroupsWithKeys(ImmutableList.of()); 278 verify(mockFileGroupsMetadata).removeAllStaleGroups(); 279 verify(mockFileGroupsMetadata).writeStaleGroups(ImmutableList.of()); 280 verifyNoMoreInteractions(mockFileGroupsMetadata); 281 verify(mockSharedFilesMetadata).getAllFileKeys(); 282 verify(mockBackend).exists(baseDownloadDirectoryUri); 283 verify(mockBackend).children(baseDownloadDirectoryUri); 284 verify(mockBackend, never()).deleteFile(any()); 285 verifyNoMoreInteractions(mockSharedFileManager); 286 verifyNoMoreInteractions(mockEventLogger); 287 } 288 289 @Test updateExpiration_noExpiredGroups_noExpirationDates()290 public void updateExpiration_noExpiredGroups_noExpirationDates() throws Exception { 291 DataFileGroupInternal dataFileGroup = MddTestUtil.createDataFileGroupInternal(TEST_GROUP_1, 2); 292 NewFileKey[] fileKeys = MddTestUtil.createFileKeysForDataFileGroupInternal(dataFileGroup); 293 294 List<GroupKeyAndGroup> groups = 295 Arrays.asList(GroupKeyAndGroup.create(TEST_KEY_1, dataFileGroup)); 296 when(mockFileGroupsMetadata.getAllFreshGroups()).thenReturn(Futures.immediateFuture(groups)); 297 when(mockSharedFileManager.getFileStatus(fileKeys[0])) 298 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 299 when(mockSharedFileManager.getOnDeviceUri(fileKeys[0])) 300 .thenReturn(Futures.immediateFuture(testUri1)); 301 when(mockSharedFileManager.getFileStatus(fileKeys[1])) 302 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 303 when(mockSharedFileManager.getOnDeviceUri(fileKeys[1])) 304 .thenReturn(Futures.immediateFuture(testUri2)); 305 306 when(mockSharedFilesMetadata.getAllFileKeys()) 307 .thenReturn(Futures.immediateFuture(Arrays.asList(fileKeys))); 308 when(mockBackend.children(dirFor0p)).thenReturn(Arrays.asList(testUri1, testUri2)); 309 310 expirationHandler.updateExpiration().get(); 311 312 verify(mockFileGroupsMetadata, times(3)).getAllFreshGroups(); 313 verify(mockFileGroupsMetadata, times(2)).getAllStaleGroups(); 314 verify(mockFileGroupsMetadata).removeAllGroupsWithKeys(ImmutableList.of()); 315 verify(mockFileGroupsMetadata).removeAllStaleGroups(); 316 verify(mockFileGroupsMetadata).writeStaleGroups(ImmutableList.of()); 317 verifyNoMoreInteractions(mockFileGroupsMetadata); 318 verify(mockSharedFilesMetadata).getAllFileKeys(); 319 verify(mockSharedFileManager).getOnDeviceUri(fileKeys[0]); 320 verify(mockSharedFileManager).getOnDeviceUri(fileKeys[1]); 321 verify(mockBackend).exists(baseDownloadDirectoryUri); 322 verify(mockBackend).children(baseDownloadDirectoryUri); 323 verify(mockBackend).isDirectory(dirForAll); 324 verify(mockBackend).isDirectory(dirFor1p); 325 verify(mockBackend, never()).deleteFile(any()); 326 verifyNoMoreInteractions(mockSharedFileManager); 327 verifyNoMoreInteractions(mockEventLogger); 328 } 329 330 @Test updateExpiration_noExpiredGroups_expirationDates()331 public void updateExpiration_noExpiredGroups_expirationDates() throws Exception { 332 Calendar now = new Calendar.Builder().setDate(2018, Calendar.MARCH, 20).build(); 333 testClock.set(now.getTimeInMillis()); 334 335 DataFileGroupInternal dataFileGroup = MddTestUtil.createDataFileGroupInternal(TEST_GROUP_1, 2); 336 Calendar later = new Calendar.Builder().setDate(2018, Calendar.APRIL, 20).build(); 337 long laterTimeSecs = later.getTimeInMillis() / 1000; 338 dataFileGroup = dataFileGroup.toBuilder().setExpirationDateSecs(laterTimeSecs).build(); 339 340 NewFileKey[] fileKeys = MddTestUtil.createFileKeysForDataFileGroupInternal(dataFileGroup); 341 342 List<GroupKeyAndGroup> groups = 343 Arrays.asList(GroupKeyAndGroup.create(TEST_KEY_1, dataFileGroup)); 344 when(mockFileGroupsMetadata.getAllFreshGroups()).thenReturn(Futures.immediateFuture(groups)); 345 when(mockSharedFileManager.getFileStatus(fileKeys[0])) 346 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 347 when(mockSharedFileManager.getOnDeviceUri(fileKeys[0])) 348 .thenReturn(Futures.immediateFuture(testUri1)); 349 when(mockSharedFileManager.getFileStatus(fileKeys[1])) 350 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 351 when(mockSharedFileManager.getOnDeviceUri(fileKeys[1])) 352 .thenReturn(Futures.immediateFuture(testUri2)); 353 354 when(mockSharedFilesMetadata.getAllFileKeys()) 355 .thenReturn(Futures.immediateFuture(Arrays.asList(fileKeys))); 356 when(mockBackend.children(dirFor0p)).thenReturn(Arrays.asList(testUri1, testUri2)); 357 358 expirationHandler.updateExpiration().get(); 359 360 verify(mockFileGroupsMetadata, times(3)).getAllFreshGroups(); 361 verify(mockFileGroupsMetadata, times(2)).getAllStaleGroups(); 362 verify(mockFileGroupsMetadata).removeAllGroupsWithKeys(ImmutableList.of()); 363 verify(mockFileGroupsMetadata).removeAllStaleGroups(); 364 verify(mockFileGroupsMetadata).writeStaleGroups(ImmutableList.of()); 365 verifyNoMoreInteractions(mockFileGroupsMetadata); 366 verify(mockSharedFilesMetadata).getAllFileKeys(); 367 verify(mockSharedFileManager).getOnDeviceUri(fileKeys[0]); 368 verify(mockSharedFileManager).getOnDeviceUri(fileKeys[1]); 369 verify(mockBackend).exists(baseDownloadDirectoryUri); 370 verify(mockBackend).children(baseDownloadDirectoryUri); 371 verify(mockBackend).isDirectory(dirForAll); 372 verify(mockBackend).isDirectory(dirFor1p); 373 verify(mockBackend, never()).deleteFile(any()); 374 verifyNoMoreInteractions(mockSharedFileManager); 375 verifyNoMoreInteractions(mockEventLogger); 376 } 377 378 @Test updateExpiration_expiredGroups()379 public void updateExpiration_expiredGroups() throws Exception { 380 // Current time 381 Calendar now = new Calendar.Builder().setDate(2020, Calendar.MARCH, 20).build(); 382 testClock.set(now.getTimeInMillis()); 383 384 DataFileGroupInternal dataFileGroup = MddTestUtil.createDataFileGroupInternal(TEST_GROUP_1, 5); 385 // Time when the group expires 386 Calendar earlier = new Calendar.Builder().setDate(2018, Calendar.MARCH, 20).build(); 387 long earlierTimeSecs = earlier.getTimeInMillis() / 1000; 388 dataFileGroup = dataFileGroup.toBuilder().setExpirationDateSecs(earlierTimeSecs).build(); 389 390 NewFileKey[] fileKeys = MddTestUtil.createFileKeysForDataFileGroupInternal(dataFileGroup); 391 392 List<GroupKeyAndGroup> groups = 393 Arrays.asList(GroupKeyAndGroup.create(TEST_KEY_1, dataFileGroup)); 394 when(mockFileGroupsMetadata.getAllFreshGroups()) 395 .thenReturn(Futures.immediateFuture(groups)) 396 .thenReturn(Futures.immediateFuture(new ArrayList<>())); 397 when(mockSharedFileManager.getFileStatus(fileKeys[0])) 398 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 399 when(mockSharedFileManager.getOnDeviceUri(fileKeys[0])) 400 .thenReturn(Futures.immediateFuture(testUri1)); 401 when(mockSharedFileManager.getFileStatus(fileKeys[1])) 402 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_FAILED)); 403 when(mockSharedFileManager.getOnDeviceUri(fileKeys[1])) 404 .thenReturn(Futures.immediateFuture(testUri2)); 405 when(mockSharedFileManager.getFileStatus(fileKeys[2])) 406 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_IN_PROGRESS)); 407 when(mockSharedFileManager.getOnDeviceUri(fileKeys[2])) 408 .thenReturn(Futures.immediateFuture(testUri3)); 409 when(mockSharedFileManager.getFileStatus(fileKeys[3])) 410 .thenReturn(Futures.immediateFuture(FileStatus.SUBSCRIBED)); 411 when(mockSharedFileManager.getOnDeviceUri(fileKeys[3])) 412 .thenReturn(Futures.immediateFuture(testUri4)); 413 when(mockSharedFileManager.getFileStatus(fileKeys[4])) 414 .thenReturn(Futures.immediateFuture(FileStatus.NONE)); 415 416 when(mockSharedFilesMetadata.getAllFileKeys()) 417 .thenReturn(Futures.immediateFuture(Arrays.asList(fileKeys))); 418 when(mockBackend.children(dirFor0p)) 419 .thenReturn(Arrays.asList(testUri1, testUri2, testUri3, testUri4)); 420 expirationHandler.updateExpiration().get(); 421 422 verify(mockFileGroupsMetadata, times(3)).getAllFreshGroups(); 423 verify(mockFileGroupsMetadata, times(2)).getAllStaleGroups(); 424 verify(mockFileGroupsMetadata).removeAllGroupsWithKeys(Arrays.asList(TEST_KEY_1)); 425 verify(mockFileGroupsMetadata).removeAllStaleGroups(); 426 verify(mockFileGroupsMetadata).writeStaleGroups(ImmutableList.of()); 427 verifyNoMoreInteractions(mockFileGroupsMetadata); 428 verify(mockSharedFilesMetadata).getAllFileKeys(); 429 verify(mockSharedFileManager).removeFileEntry(fileKeys[0]); 430 verify(mockSharedFileManager).removeFileEntry(fileKeys[1]); 431 verify(mockSharedFileManager).removeFileEntry(fileKeys[2]); 432 verify(mockSharedFileManager).removeFileEntry(fileKeys[3]); 433 verify(mockSharedFileManager).removeFileEntry(fileKeys[4]); 434 verify(mockBackend).exists(baseDownloadDirectoryUri); 435 verify(mockBackend).children(baseDownloadDirectoryUri); 436 verify(mockBackend).isDirectory(testUri1); 437 verify(mockBackend).isDirectory(testUri2); 438 verify(mockBackend).isDirectory(testUri3); 439 verify(mockBackend).isDirectory(testUri4); 440 verify(mockBackend).deleteFile(testUri1); 441 verify(mockBackend).deleteFile(testUri2); 442 verify(mockBackend).deleteFile(testUri3); 443 verify(mockBackend).deleteFile(testUri4); 444 verifyNoMoreInteractions(mockSharedFileManager); 445 446 verify(mockEventLogger) 447 .logEventSampled( 448 MddClientEvent.Code.EVENT_CODE_UNSPECIFIED, 449 dataFileGroup.getGroupName(), 450 dataFileGroup.getFileGroupVersionNumber(), 451 dataFileGroup.getBuildId(), 452 dataFileGroup.getVariantId()); 453 verify(mockEventLogger).logMddDataDownloadFileExpirationEvent(0, 4); 454 verify(mockEventLogger).logMddDataDownloadFileExpirationEvent(0, 5); 455 verifyNoMoreInteractions(mockEventLogger); 456 } 457 458 @Test updateExpiration_noExpiredGroups_pendingGroup()459 public void updateExpiration_noExpiredGroups_pendingGroup() throws Exception { 460 Calendar now = new Calendar.Builder().setDate(2018, Calendar.MARCH, 20).build(); 461 testClock.set(now.getTimeInMillis()); 462 463 DataFileGroupInternal dataFileGroup = MddTestUtil.createDataFileGroupInternal(TEST_GROUP_1, 2); 464 Calendar later = new Calendar.Builder().setDate(2018, Calendar.APRIL, 20).build(); 465 long laterTimeSecs = later.getTimeInMillis() / 1000; 466 dataFileGroup = dataFileGroup.toBuilder().setExpirationDateSecs(laterTimeSecs).build(); 467 468 NewFileKey[] fileKeys = MddTestUtil.createFileKeysForDataFileGroupInternal(dataFileGroup); 469 470 List<GroupKeyAndGroup> groups = 471 Arrays.asList(GroupKeyAndGroup.create(TEST_KEY_1, dataFileGroup)); 472 when(mockFileGroupsMetadata.getAllFreshGroups()).thenReturn(Futures.immediateFuture(groups)); 473 when(mockSharedFileManager.getFileStatus(fileKeys[0])) 474 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 475 when(mockSharedFileManager.getOnDeviceUri(fileKeys[0])) 476 .thenReturn(Futures.immediateFuture(testUri1)); 477 // The second file has not been downloaded. 478 when(mockSharedFileManager.getFileStatus(fileKeys[1])) 479 .thenReturn(Futures.immediateFuture(FileStatus.NONE)); 480 when(mockSharedFileManager.getOnDeviceUri(fileKeys[1])) 481 .thenReturn(Futures.immediateFuture(testUri2)); 482 when(mockSharedFilesMetadata.getAllFileKeys()) 483 .thenReturn(Futures.immediateFuture(Arrays.asList(fileKeys))); 484 when(mockBackend.children(dirFor0p)).thenReturn(Arrays.asList(testUri1, testUri2)); 485 486 expirationHandler.updateExpiration().get(); 487 488 verify(mockFileGroupsMetadata, times(3)).getAllFreshGroups(); 489 verify(mockFileGroupsMetadata, times(2)).getAllStaleGroups(); 490 verify(mockFileGroupsMetadata).removeAllGroupsWithKeys(ImmutableList.of()); 491 verify(mockFileGroupsMetadata).removeAllStaleGroups(); 492 verify(mockFileGroupsMetadata).writeStaleGroups(ImmutableList.of()); 493 verifyNoMoreInteractions(mockFileGroupsMetadata); 494 verify(mockSharedFilesMetadata).getAllFileKeys(); 495 verify(mockSharedFileManager).getOnDeviceUri(fileKeys[0]); 496 verify(mockSharedFileManager).getOnDeviceUri(fileKeys[1]); 497 verify(mockBackend).exists(baseDownloadDirectoryUri); 498 verify(mockBackend).children(baseDownloadDirectoryUri); 499 verify(mockBackend).isDirectory(dirForAll); 500 verify(mockBackend).isDirectory(dirFor1p); 501 verify(mockBackend, never()).deleteFile(any()); 502 verifyNoMoreInteractions(mockSharedFileManager); 503 verifyNoMoreInteractions(mockEventLogger); 504 } 505 506 @Test updateExpiration_notDeleteInternalFiles()507 public void updateExpiration_notDeleteInternalFiles() throws Exception { 508 Migrations.setCurrentVersion(context, FileKeyVersion.USE_CHECKSUM_ONLY); 509 Calendar now = new Calendar.Builder().setDate(2018, Calendar.MARCH, 20).build(); 510 testClock.set(now.getTimeInMillis()); 511 512 DataFileGroupInternal dataFileGroup = MddTestUtil.createDataFileGroupInternal(TEST_GROUP_1, 2); 513 Calendar later = new Calendar.Builder().setDate(2018, Calendar.APRIL, 20).build(); 514 long laterTimeSecs = later.getTimeInMillis() / 1000; 515 dataFileGroup = dataFileGroup.toBuilder().setExpirationDateSecs(laterTimeSecs).build(); 516 517 NewFileKey[] fileKeys = createFileKeysUseChecksumOnly(dataFileGroup); 518 519 List<GroupKeyAndGroup> groups = 520 Arrays.asList(GroupKeyAndGroup.create(TEST_KEY_1, dataFileGroup)); 521 when(mockFileGroupsMetadata.getAllFreshGroups()).thenReturn(Futures.immediateFuture(groups)); 522 when(mockSharedFileManager.getFileStatus(fileKeys[0])) 523 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 524 when(mockSharedFileManager.getOnDeviceUri(fileKeys[0])) 525 .thenReturn(Futures.immediateFuture(testUri1)); 526 // The second file has not been downloaded. 527 when(mockSharedFileManager.getFileStatus(fileKeys[1])) 528 .thenReturn(Futures.immediateFuture(FileStatus.NONE)); 529 when(mockSharedFileManager.getOnDeviceUri(fileKeys[1])) 530 .thenReturn(Futures.immediateFuture(testUri2)); 531 when(mockSharedFilesMetadata.getAllFileKeys()) 532 .thenReturn(Futures.immediateFuture(Arrays.asList(fileKeys))); 533 when(mockBackend.children(dirFor0p)) 534 .thenReturn(Arrays.asList(testUri1, testUri2, tempTestUri2)); 535 536 expirationHandler.updateExpiration().get(); 537 538 verify(mockFileGroupsMetadata, times(3)).getAllFreshGroups(); 539 verify(mockFileGroupsMetadata, times(2)).getAllStaleGroups(); 540 verify(mockFileGroupsMetadata).removeAllGroupsWithKeys(ImmutableList.of()); 541 verify(mockFileGroupsMetadata).removeAllStaleGroups(); 542 verify(mockFileGroupsMetadata).writeStaleGroups(ImmutableList.of()); 543 verifyNoMoreInteractions(mockFileGroupsMetadata); 544 verify(mockSharedFilesMetadata).getAllFileKeys(); 545 verify(mockSharedFileManager).getOnDeviceUri(fileKeys[0]); 546 verify(mockSharedFileManager).getOnDeviceUri(fileKeys[1]); 547 verify(mockBackend).exists(baseDownloadDirectoryUri); 548 verify(mockBackend).children(baseDownloadDirectoryUri); 549 verify(mockBackend).isDirectory(dirForAll); 550 verify(mockBackend).isDirectory(dirFor1p); 551 verify(mockBackend).isDirectory(dirFor0p); 552 verify(mockBackend, never()).deleteFile(any()); 553 verifyNoMoreInteractions(mockSharedFileManager); 554 verifyNoMoreInteractions(mockEventLogger); 555 } 556 557 @Test updateExpiration_deleteInternalFilesWithExipiredAccountedFile()558 public void updateExpiration_deleteInternalFilesWithExipiredAccountedFile() throws Exception { 559 Migrations.setCurrentVersion(context, FileKeyVersion.USE_CHECKSUM_ONLY); 560 Calendar now = new Calendar.Builder().setDate(2018, Calendar.MARCH, 20).build(); 561 testClock.set(now.getTimeInMillis()); 562 563 DataFileGroupInternal dataFileGroup = 564 MddTestUtil.createDataFileGroupInternal(TEST_GROUP_1, 1).toBuilder() 565 .setBuildId(10) 566 .setVariantId("testVariant") 567 .build(); 568 long nowTimeSecs = now.getTimeInMillis() / 1000; 569 dataFileGroup = dataFileGroup.toBuilder().setExpirationDateSecs(nowTimeSecs).build(); 570 571 NewFileKey[] fileKeys = createFileKeysUseChecksumOnly(dataFileGroup); 572 573 List<GroupKeyAndGroup> groups = 574 Arrays.asList(GroupKeyAndGroup.create(TEST_KEY_1, dataFileGroup)); 575 when(mockFileGroupsMetadata.getAllFreshGroups()) 576 .thenReturn(Futures.immediateFuture(groups)) 577 .thenReturn(Futures.immediateFuture(new ArrayList<>())); 578 when(mockSharedFileManager.getFileStatus(fileKeys[0])) 579 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 580 when(mockSharedFileManager.getOnDeviceUri(fileKeys[0])) 581 .thenReturn(Futures.immediateFuture(testUri2)); 582 583 when(mockSharedFilesMetadata.getAllFileKeys()) 584 .thenReturn(Futures.immediateFuture(Arrays.asList(fileKeys))); 585 when(mockBackend.children(dirFor0p)).thenReturn(Arrays.asList(testUri2, tempTestUri2)); 586 expirationHandler.updateExpiration().get(); 587 588 verify(mockFileGroupsMetadata, times(3)).getAllFreshGroups(); 589 verify(mockFileGroupsMetadata, times(2)).getAllStaleGroups(); 590 verify(mockFileGroupsMetadata).removeAllGroupsWithKeys(Arrays.asList(TEST_KEY_1)); 591 verify(mockFileGroupsMetadata).removeAllStaleGroups(); 592 verify(mockFileGroupsMetadata).writeStaleGroups(ImmutableList.of()); 593 verifyNoMoreInteractions(mockFileGroupsMetadata); 594 verify(mockSharedFilesMetadata).getAllFileKeys(); 595 verify(mockSharedFileManager).removeFileEntry(fileKeys[0]); 596 597 verify(mockBackend).exists(baseDownloadDirectoryUri); 598 verify(mockBackend).children(baseDownloadDirectoryUri); 599 verify(mockBackend).isDirectory(testUri2); 600 verify(mockBackend).isDirectory(tempTestUri2); 601 verify(mockBackend).deleteFile(testUri2); 602 verify(mockBackend).deleteFile(tempTestUri2); 603 verifyNoMoreInteractions(mockSharedFileManager); 604 605 verify(mockEventLogger) 606 .logEventSampled( 607 MddClientEvent.Code.EVENT_CODE_UNSPECIFIED, 608 dataFileGroup.getGroupName(), 609 dataFileGroup.getFileGroupVersionNumber(), 610 dataFileGroup.getBuildId(), 611 dataFileGroup.getVariantId()); 612 verify(mockEventLogger).logMddDataDownloadFileExpirationEvent(0, 2); 613 verify(mockEventLogger).logMddDataDownloadFileExpirationEvent(0, 1); 614 verifyNoMoreInteractions(mockEventLogger); 615 } 616 617 @Test updateExpiration_sharedFiles_noExpiration()618 public void updateExpiration_sharedFiles_noExpiration() throws Exception { 619 Calendar now = new Calendar.Builder().setDate(2018, Calendar.MARCH, 20).build(); 620 testClock.set(now.getTimeInMillis()); 621 622 DataFile dataFile = MddTestUtil.createDataFile("file", 0); 623 NewFileKey fileKey = 624 SharedFilesMetadata.createKeyFromDataFile( 625 dataFile, AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES); 626 627 // The first group expires 30 days from now. 628 Calendar later = new Calendar.Builder().setDate(2018, Calendar.APRIL, 20).build(); 629 long laterTimeSecs = later.getTimeInMillis() / 1000; 630 DataFileGroupInternal firstGroup = 631 DataFileGroupInternal.newBuilder() 632 .setGroupName(TEST_GROUP_1) 633 .addFile(dataFile) 634 .setAllowedReadersEnum(AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES) 635 .setExpirationDateSecs(laterTimeSecs) 636 .build(); 637 638 // The second group never expires 639 DataFileGroupInternal secondGroup = 640 DataFileGroupInternal.newBuilder() 641 .setGroupName(TEST_GROUP_2) 642 .addFile(dataFile) 643 .setAllowedReadersEnum(AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES) 644 .build(); 645 646 List<GroupKeyAndGroup> groups = 647 Arrays.asList( 648 GroupKeyAndGroup.create(TEST_KEY_1, firstGroup), 649 GroupKeyAndGroup.create(TEST_KEY_2, secondGroup)); 650 when(mockFileGroupsMetadata.getAllFreshGroups()).thenReturn(Futures.immediateFuture(groups)); 651 when(mockSharedFileManager.getFileStatus(fileKey)) 652 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 653 when(mockSharedFileManager.getOnDeviceUri(fileKey)) 654 .thenReturn(Futures.immediateFuture(testUri1)); 655 when(mockSharedFilesMetadata.getAllFileKeys()) 656 .thenReturn(Futures.immediateFuture(Collections.singletonList(fileKey))); 657 when(mockBackend.children(dirFor0p)).thenReturn(Arrays.asList(testUri1)); 658 659 expirationHandler.updateExpiration().get(); 660 661 verify(mockFileGroupsMetadata, times(3)).getAllFreshGroups(); 662 verify(mockFileGroupsMetadata, times(2)).getAllStaleGroups(); 663 verify(mockFileGroupsMetadata).removeAllGroupsWithKeys(ImmutableList.of()); 664 verify(mockFileGroupsMetadata).removeAllStaleGroups(); 665 verify(mockFileGroupsMetadata).writeStaleGroups(ImmutableList.of()); 666 verifyNoMoreInteractions(mockFileGroupsMetadata); 667 verify(mockSharedFilesMetadata).getAllFileKeys(); 668 verify(mockSharedFileManager).getOnDeviceUri(fileKey); 669 verify(mockBackend).exists(baseDownloadDirectoryUri); 670 verify(mockBackend).children(baseDownloadDirectoryUri); 671 verify(mockBackend).isDirectory(dirForAll); 672 verify(mockBackend, never()).deleteFile(any()); 673 verifyNoMoreInteractions(mockSharedFileManager); 674 verifyNoMoreInteractions(mockEventLogger); 675 } 676 677 @Test updateExpiration_sharedFiles_expiration()678 public void updateExpiration_sharedFiles_expiration() throws Exception { 679 Calendar now = new Calendar.Builder().setDate(2018, Calendar.MARCH, 20).build(); 680 testClock.set(now.getTimeInMillis()); 681 682 DataFile dataFile = MddTestUtil.createDataFile("file", 0); 683 NewFileKey fileKey = 684 SharedFilesMetadata.createKeyFromDataFile( 685 dataFile, AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES); 686 687 // The first group expires 30 days from now. 688 Calendar later = new Calendar.Builder().setDate(2018, Calendar.APRIL, 20).build(); 689 long laterTimeSecs = later.getTimeInMillis() / 1000; 690 DataFileGroupInternal firstGroup = 691 DataFileGroupInternal.newBuilder() 692 .setGroupName(TEST_GROUP_1) 693 .addFile(dataFile) 694 .setAllowedReadersEnum(AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES) 695 .setExpirationDateSecs(laterTimeSecs) 696 .build(); 697 698 // The second group expires 15 days 699 Calendar sooner = new Calendar.Builder().setDate(2018, Calendar.APRIL, 5).build(); 700 DataFileGroupInternal secondGroup = 701 DataFileGroupInternal.newBuilder() 702 .setGroupName(TEST_GROUP_2) 703 .addFile(dataFile) 704 .setAllowedReadersEnum(AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES) 705 .setExpirationDateSecs(sooner.getTimeInMillis() / 1000) 706 .build(); 707 708 List<GroupKeyAndGroup> groups = 709 Arrays.asList( 710 GroupKeyAndGroup.create(TEST_KEY_1, firstGroup), 711 GroupKeyAndGroup.create(TEST_KEY_2, secondGroup)); 712 when(mockFileGroupsMetadata.getAllFreshGroups()).thenReturn(Futures.immediateFuture(groups)); 713 when(mockSharedFileManager.getFileStatus(fileKey)) 714 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 715 when(mockSharedFileManager.getOnDeviceUri(fileKey)) 716 .thenReturn(Futures.immediateFuture(testUri1)); 717 when(mockSharedFilesMetadata.getAllFileKeys()) 718 .thenReturn(Futures.immediateFuture(Collections.singletonList(fileKey))); 719 when(mockBackend.children(dirFor0p)).thenReturn(Arrays.asList(testUri1)); 720 721 expirationHandler.updateExpiration().get(); 722 723 verify(mockFileGroupsMetadata, times(3)).getAllFreshGroups(); 724 verify(mockFileGroupsMetadata, times(2)).getAllStaleGroups(); 725 verify(mockFileGroupsMetadata).removeAllGroupsWithKeys(ImmutableList.of()); 726 verify(mockFileGroupsMetadata).removeAllStaleGroups(); 727 verify(mockFileGroupsMetadata).writeStaleGroups(ImmutableList.of()); 728 verifyNoMoreInteractions(mockFileGroupsMetadata); 729 verify(mockSharedFilesMetadata).getAllFileKeys(); 730 verify(mockSharedFileManager).getOnDeviceUri(fileKey); 731 verify(mockBackend).exists(baseDownloadDirectoryUri); 732 verify(mockBackend).children(baseDownloadDirectoryUri); 733 verify(mockBackend).isDirectory(dirForAll); 734 verify(mockBackend, never()).deleteFile(any()); 735 verifyNoMoreInteractions(mockSharedFileManager); 736 verifyNoMoreInteractions(mockEventLogger); 737 } 738 739 @Test updateExpiration_noExpiredStaleGroups()740 public void updateExpiration_noExpiredStaleGroups() throws Exception { 741 Calendar now = new Calendar.Builder().setDate(2018, Calendar.MARCH, 20).build(); 742 testClock.set(now.getTimeInMillis()); 743 744 Calendar later = new Calendar.Builder().setDate(2018, Calendar.MARCH, 22).build(); 745 Long laterTimeSecs = later.getTimeInMillis() / 1000; 746 ; 747 DataFileGroupInternal dataFileGroup = 748 MddTestUtil.createDataFileGroupInternal(TEST_GROUP_1, 2).toBuilder() 749 .setStaleLifetimeSecs(laterTimeSecs - (now.getTimeInMillis() / 1000)) 750 .setBookkeeping( 751 DataFileGroupBookkeeping.newBuilder().setStaleExpirationDate(laterTimeSecs).build()) 752 .build(); 753 NewFileKey[] fileKeys = MddTestUtil.createFileKeysForDataFileGroupInternal(dataFileGroup); 754 755 fileGroupsMetadataStaleGroups.set(ImmutableList.of(dataFileGroup)); 756 when(mockSharedFileManager.getFileStatus(fileKeys[0])) 757 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 758 when(mockSharedFileManager.getOnDeviceUri(fileKeys[0])) 759 .thenReturn(Futures.immediateFuture(testUri1)); 760 when(mockSharedFileManager.getFileStatus(fileKeys[1])) 761 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 762 when(mockSharedFileManager.getOnDeviceUri(fileKeys[1])) 763 .thenReturn(Futures.immediateFuture(testUri2)); 764 765 when(mockSharedFilesMetadata.getAllFileKeys()) 766 .thenReturn(Futures.immediateFuture(Arrays.asList(fileKeys))); 767 when(mockBackend.children(dirFor0p)).thenReturn(Arrays.asList(testUri1, testUri2)); 768 expirationHandler.updateExpiration().get(); 769 770 verify(mockFileGroupsMetadata, times(3)).getAllFreshGroups(); 771 verify(mockFileGroupsMetadata, times(2)).getAllStaleGroups(); 772 verify(mockFileGroupsMetadata).removeAllGroupsWithKeys(ImmutableList.of()); 773 verify(mockFileGroupsMetadata).removeAllStaleGroups(); 774 verify(mockFileGroupsMetadata).writeStaleGroups(ImmutableList.of(dataFileGroup)); 775 verifyNoMoreInteractions(mockFileGroupsMetadata); 776 verify(mockSharedFilesMetadata).getAllFileKeys(); 777 verify(mockSharedFileManager).getOnDeviceUri(fileKeys[0]); 778 verify(mockSharedFileManager).getOnDeviceUri(fileKeys[1]); 779 verify(mockBackend).exists(baseDownloadDirectoryUri); 780 verify(mockBackend).children(baseDownloadDirectoryUri); 781 verify(mockBackend).isDirectory(dirForAll); 782 verify(mockBackend).isDirectory(dirFor1p); 783 verify(mockBackend, never()).deleteFile(any()); 784 verifyNoMoreInteractions(mockSharedFileManager); 785 verifyNoMoreInteractions(mockEventLogger); 786 } 787 788 @Test updateExpiration_noExpiredStaleGroups_notDeleteDir()789 public void updateExpiration_noExpiredStaleGroups_notDeleteDir() throws Exception { 790 Calendar now = new Calendar.Builder().setDate(2018, Calendar.MARCH, 20).build(); 791 testClock.set(now.getTimeInMillis()); 792 793 Calendar later = new Calendar.Builder().setDate(2018, Calendar.MARCH, 22).build(); 794 long laterTimeSecs = later.getTimeInMillis() / 1000; 795 DataFileGroupInternal dataFileGroup = 796 MddTestUtil.createDataFileGroupInternal(TEST_GROUP_1, 2).toBuilder() 797 .setStaleLifetimeSecs(laterTimeSecs - (now.getTimeInMillis() / 1000)) 798 .setBookkeeping( 799 DataFileGroupBookkeeping.newBuilder().setStaleExpirationDate(laterTimeSecs).build()) 800 .build(); 801 NewFileKey[] fileKeys = MddTestUtil.createFileKeysForDataFileGroupInternal(dataFileGroup); 802 803 fileGroupsMetadataStaleGroups.set(ImmutableList.of(dataFileGroup)); 804 when(mockSharedFileManager.getFileStatus(fileKeys[0])) 805 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 806 when(mockSharedFileManager.getOnDeviceUri(fileKeys[0])) 807 .thenReturn(Futures.immediateFuture(testDirUri1)); 808 when(mockBackend.children(testDirUri1)) 809 .thenReturn(Arrays.asList(testDirFileUri1, testDirFileUri2)); 810 when(mockSharedFileManager.getFileStatus(fileKeys[1])) 811 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 812 when(mockSharedFileManager.getOnDeviceUri(fileKeys[1])) 813 .thenReturn(Futures.immediateFuture(testUri2)); 814 815 when(mockSharedFilesMetadata.getAllFileKeys()) 816 .thenReturn(Futures.immediateFuture(Arrays.asList(fileKeys))); 817 when(mockBackend.children(dirFor0p)).thenReturn(Arrays.asList(testDirUri1, testUri2)); 818 expirationHandler.updateExpiration().get(); 819 820 verify(mockFileGroupsMetadata, times(3)).getAllFreshGroups(); 821 verify(mockFileGroupsMetadata, times(2)).getAllStaleGroups(); 822 verify(mockFileGroupsMetadata).removeAllGroupsWithKeys(ImmutableList.of()); 823 verify(mockFileGroupsMetadata).removeAllStaleGroups(); 824 verify(mockFileGroupsMetadata).writeStaleGroups(ImmutableList.of(dataFileGroup)); 825 verifyNoMoreInteractions(mockFileGroupsMetadata); 826 verify(mockSharedFilesMetadata).getAllFileKeys(); 827 verify(mockSharedFileManager).getOnDeviceUri(fileKeys[0]); 828 verify(mockSharedFileManager).getOnDeviceUri(fileKeys[1]); 829 verify(mockBackend).exists(baseDownloadDirectoryUri); 830 verify(mockBackend).children(baseDownloadDirectoryUri); 831 verify(mockBackend).isDirectory(dirForAll); 832 verify(mockBackend).isDirectory(dirFor1p); 833 verify(mockBackend, never()).deleteFile(any()); 834 verifyNoMoreInteractions(mockSharedFileManager); 835 verifyNoMoreInteractions(mockEventLogger); 836 } 837 838 @Test updateExpiration_expiredStaleGroups_shorterStaleExpirationDate()839 public void updateExpiration_expiredStaleGroups_shorterStaleExpirationDate() throws Exception { 840 Calendar now = new Calendar.Builder().setDate(2018, Calendar.MARCH, 20).build(); 841 Calendar later = new Calendar.Builder().setDate(2018, Calendar.MARCH, 22).build(); 842 testClock.set(now.getTimeInMillis()); 843 844 Long nowTimeSecs = now.getTimeInMillis() / 1000; 845 DataFileGroupInternal dataFileGroup = 846 MddTestUtil.createDataFileGroupInternal(TEST_GROUP_1, 2).toBuilder() 847 .setStaleLifetimeSecs(0) 848 .setBookkeeping( 849 DataFileGroupBookkeeping.newBuilder().setStaleExpirationDate(nowTimeSecs).build()) 850 .setExpirationDateSecs(later.getTimeInMillis() / 1000) 851 .setBuildId(10) 852 .setVariantId("testVariant") 853 .build(); 854 NewFileKey[] fileKeys = MddTestUtil.createFileKeysForDataFileGroupInternal(dataFileGroup); 855 856 fileGroupsMetadataStaleGroups.set(ImmutableList.of(dataFileGroup)); 857 when(mockSharedFileManager.getFileStatus(fileKeys[0])) 858 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 859 when(mockSharedFileManager.getOnDeviceUri(fileKeys[0])) 860 .thenReturn(Futures.immediateFuture(testUri1)); 861 when(mockSharedFileManager.getFileStatus(fileKeys[1])) 862 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 863 when(mockSharedFileManager.getOnDeviceUri(fileKeys[1])) 864 .thenReturn(Futures.immediateFuture(testUri2)); 865 when(mockSharedFilesMetadata.getAllFileKeys()) 866 .thenReturn(Futures.immediateFuture(Arrays.asList(fileKeys))); 867 when(mockBackend.children(dirFor0p)).thenReturn(Arrays.asList(testUri1, testUri2)); 868 869 expirationHandler.updateExpiration().get(); 870 871 verify(mockFileGroupsMetadata, times(3)).getAllFreshGroups(); 872 verify(mockFileGroupsMetadata, times(2)).getAllStaleGroups(); 873 verify(mockFileGroupsMetadata).removeAllGroupsWithKeys(ImmutableList.of()); 874 verify(mockFileGroupsMetadata).removeAllStaleGroups(); 875 verify(mockFileGroupsMetadata).writeStaleGroups(ImmutableList.of()); 876 verifyNoMoreInteractions(mockFileGroupsMetadata); 877 verify(mockSharedFilesMetadata).getAllFileKeys(); 878 verify(mockSharedFileManager).removeFileEntry(fileKeys[0]); 879 verify(mockSharedFileManager).removeFileEntry(fileKeys[1]); 880 verifyNoMoreInteractions(mockSharedFileManager); 881 verify(mockBackend).exists(baseDownloadDirectoryUri); 882 verify(mockBackend).children(baseDownloadDirectoryUri); 883 verify(mockBackend).isDirectory(testUri1); 884 verify(mockBackend).isDirectory(testUri2); 885 verify(mockBackend).deleteFile(testUri1); 886 verify(mockBackend).deleteFile(testUri2); 887 verify(mockEventLogger) 888 .logEventSampled( 889 MddClientEvent.Code.EVENT_CODE_UNSPECIFIED, 890 dataFileGroup.getGroupName(), 891 dataFileGroup.getFileGroupVersionNumber(), 892 dataFileGroup.getBuildId(), 893 dataFileGroup.getVariantId()); 894 verify(mockEventLogger).logMddDataDownloadFileExpirationEvent(0, 2); 895 verify(mockEventLogger).logMddDataDownloadFileExpirationEvent(0, 2); 896 verifyNoMoreInteractions(mockEventLogger); 897 } 898 899 @Test updateExpiration_expiredStaleGroups_shorterExpirationDate()900 public void updateExpiration_expiredStaleGroups_shorterExpirationDate() throws Exception { 901 Calendar now = new Calendar.Builder().setDate(2018, Calendar.MARCH, 20).build(); 902 Calendar later = new Calendar.Builder().setDate(2018, Calendar.MARCH, 22).build(); 903 testClock.set(now.getTimeInMillis()); 904 905 Long nowTimeSecs = now.getTimeInMillis() / 1000; 906 DataFileGroupInternal dataFileGroup = 907 MddTestUtil.createDataFileGroupInternal(TEST_GROUP_1, 2).toBuilder() 908 .setBookkeeping( 909 DataFileGroupBookkeeping.newBuilder() 910 .setStaleExpirationDate(later.getTimeInMillis() / 1000) 911 .build()) 912 .setExpirationDateSecs(nowTimeSecs) 913 .setBuildId(10) 914 .setVariantId("testVariant") 915 .build(); 916 NewFileKey[] fileKeys = MddTestUtil.createFileKeysForDataFileGroupInternal(dataFileGroup); 917 918 fileGroupsMetadataStaleGroups.set(ImmutableList.of(dataFileGroup)); 919 920 when(mockSharedFileManager.getFileStatus(fileKeys[0])) 921 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 922 when(mockSharedFileManager.getOnDeviceUri(fileKeys[0])) 923 .thenReturn(Futures.immediateFuture(testUri1)); 924 when(mockSharedFileManager.getFileStatus(fileKeys[1])) 925 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 926 when(mockSharedFileManager.getOnDeviceUri(fileKeys[1])) 927 .thenReturn(Futures.immediateFuture(testUri2)); 928 when(mockSharedFilesMetadata.getAllFileKeys()) 929 .thenReturn(Futures.immediateFuture(Arrays.asList(fileKeys))); 930 when(mockBackend.children(dirFor0p)).thenReturn(Arrays.asList(testUri1, testUri2)); 931 932 expirationHandler.updateExpiration().get(); 933 934 verify(mockFileGroupsMetadata, times(3)).getAllFreshGroups(); 935 verify(mockFileGroupsMetadata, times(2)).getAllStaleGroups(); 936 verify(mockFileGroupsMetadata).removeAllGroupsWithKeys(ImmutableList.of()); 937 verify(mockFileGroupsMetadata).removeAllStaleGroups(); 938 verify(mockFileGroupsMetadata).writeStaleGroups(ImmutableList.of()); 939 verifyNoMoreInteractions(mockFileGroupsMetadata); 940 verify(mockSharedFilesMetadata).getAllFileKeys(); 941 verify(mockSharedFileManager).removeFileEntry(fileKeys[0]); 942 verify(mockSharedFileManager).removeFileEntry(fileKeys[1]); 943 verifyNoMoreInteractions(mockSharedFileManager); 944 verify(mockBackend).exists(baseDownloadDirectoryUri); 945 verify(mockBackend).children(baseDownloadDirectoryUri); 946 verify(mockBackend).isDirectory(testUri1); 947 verify(mockBackend).isDirectory(testUri2); 948 verify(mockBackend).deleteFile(testUri1); 949 verify(mockBackend).deleteFile(testUri2); 950 verify(mockEventLogger) 951 .logEventSampled( 952 MddClientEvent.Code.EVENT_CODE_UNSPECIFIED, 953 dataFileGroup.getGroupName(), 954 dataFileGroup.getFileGroupVersionNumber(), 955 dataFileGroup.getBuildId(), 956 dataFileGroup.getVariantId()); 957 verify(mockEventLogger).logMddDataDownloadFileExpirationEvent(0, 2); 958 verify(mockEventLogger).logMddDataDownloadFileExpirationEvent(0, 2); 959 verifyNoMoreInteractions(mockEventLogger); 960 } 961 962 @Test updateExpiration_expiredStaleGroups_deleteExpiredDir()963 public void updateExpiration_expiredStaleGroups_deleteExpiredDir() throws Exception { 964 Calendar now = new Calendar.Builder().setDate(2018, Calendar.MARCH, 20).build(); 965 Calendar later = new Calendar.Builder().setDate(2018, Calendar.MARCH, 22).build(); 966 testClock.set(now.getTimeInMillis()); 967 long nowTimeSecs = now.getTimeInMillis() / 1000; 968 DataFileGroupInternal dataFileGroup = 969 MddTestUtil.createDataFileGroupInternal(TEST_GROUP_1, 2).toBuilder() 970 .setBookkeeping( 971 DataFileGroupBookkeeping.newBuilder() 972 .setStaleExpirationDate(later.getTimeInMillis() / 1000) 973 .build()) 974 .setExpirationDateSecs(nowTimeSecs) 975 .build(); 976 NewFileKey[] fileKeys = MddTestUtil.createFileKeysForDataFileGroupInternal(dataFileGroup); 977 978 fileGroupsMetadataStaleGroups.set(ImmutableList.of(dataFileGroup)); 979 980 when(mockSharedFileManager.getFileStatus(fileKeys[0])) 981 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 982 when(mockSharedFileManager.getOnDeviceUri(fileKeys[0])) 983 .thenReturn(Futures.immediateFuture(testDirUri1)); 984 when(mockSharedFileManager.getFileStatus(fileKeys[1])) 985 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 986 when(mockSharedFileManager.getOnDeviceUri(fileKeys[1])) 987 .thenReturn(Futures.immediateFuture(testUri2)); 988 when(mockSharedFilesMetadata.getAllFileKeys()) 989 .thenReturn(Futures.immediateFuture(Arrays.asList(fileKeys))); 990 when(mockBackend.children(dirFor1p)).thenReturn(Arrays.asList(testDirUri1, testUri2)); 991 when(mockBackend.children(testDirUri1)) 992 .thenReturn(Arrays.asList(testDirFileUri1, testDirFileUri2)); 993 994 expirationHandler.updateExpiration().get(); 995 996 verify(mockFileGroupsMetadata, times(3)).getAllFreshGroups(); 997 verify(mockFileGroupsMetadata, times(2)).getAllStaleGroups(); 998 verify(mockFileGroupsMetadata).removeAllGroupsWithKeys(ImmutableList.of()); 999 verify(mockFileGroupsMetadata).removeAllStaleGroups(); 1000 verify(mockFileGroupsMetadata).writeStaleGroups(ImmutableList.of()); 1001 verifyNoMoreInteractions(mockFileGroupsMetadata); 1002 verify(mockSharedFilesMetadata).getAllFileKeys(); 1003 verify(mockSharedFileManager).removeFileEntry(fileKeys[0]); 1004 verify(mockSharedFileManager).removeFileEntry(fileKeys[1]); 1005 verifyNoMoreInteractions(mockSharedFileManager); 1006 verify(mockBackend).exists(baseDownloadDirectoryUri); 1007 verify(mockBackend).children(baseDownloadDirectoryUri); 1008 verify(mockBackend).isDirectory(testDirUri1); 1009 verify(mockBackend).isDirectory(testDirFileUri1); 1010 verify(mockBackend).isDirectory(testDirFileUri2); 1011 verify(mockBackend).isDirectory(testUri2); 1012 verify(mockBackend).deleteFile(testDirFileUri1); 1013 verify(mockBackend).deleteFile(testDirFileUri2); 1014 verify(mockBackend).deleteFile(testUri2); 1015 verify(mockEventLogger) 1016 .logEventSampled( 1017 MddClientEvent.Code.EVENT_CODE_UNSPECIFIED, 1018 dataFileGroup.getGroupName(), 1019 dataFileGroup.getFileGroupVersionNumber(), 1020 dataFileGroup.getBuildId(), 1021 dataFileGroup.getVariantId()); 1022 verify(mockEventLogger).logMddDataDownloadFileExpirationEvent(0, 3); 1023 verify(mockEventLogger).logMddDataDownloadFileExpirationEvent(0, 2); 1024 verifyNoMoreInteractions(mockEventLogger); 1025 } 1026 1027 @Test updateExpiration_sharedFiles_staleGroupSoonerExpiration_activeGroupLaterExpiration()1028 public void updateExpiration_sharedFiles_staleGroupSoonerExpiration_activeGroupLaterExpiration() 1029 throws Exception { 1030 Calendar now = new Calendar.Builder().setDate(2018, Calendar.MARCH, 20).build(); 1031 testClock.set(now.getTimeInMillis()); 1032 1033 DataFile dataFile = MddTestUtil.createDataFile("file", 0); 1034 NewFileKey fileKey = 1035 SharedFilesMetadata.createKeyFromDataFile( 1036 dataFile, AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES); 1037 1038 // The active group expires 30 days from now. 1039 Calendar later = new Calendar.Builder().setDate(2018, Calendar.APRIL, 20).build(); 1040 long laterTimeSecs = later.getTimeInMillis() / 1000; 1041 DataFileGroupInternal activeGroup = 1042 DataFileGroupInternal.newBuilder() 1043 .setGroupName(TEST_GROUP_1) 1044 .addFile(dataFile) 1045 .setAllowedReadersEnum(AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES) 1046 .setExpirationDateSecs(laterTimeSecs) 1047 .build(); 1048 1049 // The stale group expires 2 days from now. 1050 Calendar sooner = new Calendar.Builder().setDate(2018, Calendar.MARCH, 22).build(); 1051 DataFileGroupInternal staleGroup = 1052 DataFileGroupInternal.newBuilder() 1053 .setGroupName(TEST_GROUP_2) 1054 .addFile(dataFile) 1055 .setAllowedReadersEnum(AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES) 1056 .setBookkeeping( 1057 DataFileGroupBookkeeping.newBuilder() 1058 .setStaleExpirationDate(sooner.getTimeInMillis() / 1000) 1059 .build()) 1060 .setStaleLifetimeSecs((sooner.getTimeInMillis() - now.getTimeInMillis()) / 1000) 1061 .build(); 1062 1063 List<GroupKeyAndGroup> groups = Arrays.asList(GroupKeyAndGroup.create(TEST_KEY_1, activeGroup)); 1064 when(mockFileGroupsMetadata.getAllFreshGroups()).thenReturn(Futures.immediateFuture(groups)); 1065 1066 fileGroupsMetadataStaleGroups.set(ImmutableList.of(staleGroup)); 1067 1068 when(mockSharedFileManager.getFileStatus(fileKey)) 1069 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 1070 when(mockSharedFileManager.getOnDeviceUri(fileKey)) 1071 .thenReturn(Futures.immediateFuture(testUri1)); 1072 when(mockSharedFilesMetadata.getAllFileKeys()) 1073 .thenReturn(Futures.immediateFuture(Collections.singletonList(fileKey))); 1074 setUpDirectoryMock(dirFor1p, Arrays.asList(testUri1)); 1075 setUpFileMock(testUri1, 100); 1076 1077 expirationHandler.updateExpiration().get(); 1078 1079 verify(mockFileGroupsMetadata, times(3)).getAllFreshGroups(); 1080 verify(mockFileGroupsMetadata, times(2)).getAllStaleGroups(); 1081 verify(mockFileGroupsMetadata).removeAllGroupsWithKeys(ImmutableList.of()); 1082 verify(mockFileGroupsMetadata).removeAllStaleGroups(); 1083 verify(mockFileGroupsMetadata).writeStaleGroups(ImmutableList.of(staleGroup)); 1084 verifyNoMoreInteractions(mockFileGroupsMetadata); 1085 verify(mockSharedFilesMetadata).getAllFileKeys(); 1086 verify(mockSharedFileManager).getOnDeviceUri(fileKey); 1087 verifyNoMoreInteractions(mockSharedFileManager); 1088 verifyNoMoreInteractions(mockEventLogger); 1089 verify(mockBackend).exists(baseDownloadDirectoryUri); 1090 verify(mockBackend).children(baseDownloadDirectoryUri); 1091 verify(mockBackend).isDirectory(dirForAll); 1092 verify(mockBackend, never()).deleteFile(any()); 1093 } 1094 1095 @Test updateExpiration_sharedFiles_staleGroupLaterExpiration_activeGroupSoonerExpiration()1096 public void updateExpiration_sharedFiles_staleGroupLaterExpiration_activeGroupSoonerExpiration() 1097 throws Exception { 1098 Calendar now = new Calendar.Builder().setDate(2018, Calendar.MARCH, 20).build(); 1099 testClock.set(now.getTimeInMillis()); 1100 1101 DataFile dataFile = MddTestUtil.createDataFile("file", 0); 1102 NewFileKey fileKey = 1103 SharedFilesMetadata.createKeyFromDataFile( 1104 dataFile, AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES); 1105 1106 // The active group expires 1 day from now. 1107 Calendar sooner = new Calendar.Builder().setDate(2018, Calendar.MARCH, 21).build(); 1108 DataFileGroupInternal activeGroup = 1109 DataFileGroupInternal.newBuilder() 1110 .setGroupName(TEST_GROUP_1) 1111 .addFile(dataFile) 1112 .setAllowedReadersEnum(AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES) 1113 .setExpirationDateSecs(sooner.getTimeInMillis() / 1000) 1114 .build(); 1115 1116 // The stale group expires 2 days from now. 1117 Calendar later = new Calendar.Builder().setDate(2018, Calendar.MARCH, 22).build(); 1118 long laterTimeSecs = later.getTimeInMillis() / 1000; 1119 DataFileGroupInternal staleGroup = 1120 DataFileGroupInternal.newBuilder() 1121 .setGroupName(TEST_GROUP_2) 1122 .addFile(dataFile) 1123 .setAllowedReadersEnum(AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES) 1124 .setBookkeeping( 1125 DataFileGroupBookkeeping.newBuilder().setStaleExpirationDate(laterTimeSecs).build()) 1126 .setStaleLifetimeSecs(laterTimeSecs - now.getTimeInMillis() / 1000) 1127 .build(); 1128 1129 List<GroupKeyAndGroup> groups = Arrays.asList(GroupKeyAndGroup.create(TEST_KEY_1, activeGroup)); 1130 when(mockFileGroupsMetadata.getAllFreshGroups()).thenReturn(Futures.immediateFuture(groups)); 1131 1132 fileGroupsMetadataStaleGroups.set(ImmutableList.of(staleGroup)); 1133 1134 when(mockSharedFileManager.getFileStatus(fileKey)) 1135 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 1136 when(mockSharedFileManager.getOnDeviceUri(fileKey)) 1137 .thenReturn(Futures.immediateFuture(testUri1)); 1138 when(mockSharedFilesMetadata.getAllFileKeys()) 1139 .thenReturn(Futures.immediateFuture(Collections.singletonList(fileKey))); 1140 when(mockBackend.children(dirFor0p)).thenReturn(Arrays.asList(testUri1)); 1141 1142 expirationHandler.updateExpiration().get(); 1143 1144 verify(mockFileGroupsMetadata, times(3)).getAllFreshGroups(); 1145 verify(mockFileGroupsMetadata, times(2)).getAllStaleGroups(); 1146 verify(mockFileGroupsMetadata).removeAllGroupsWithKeys(ImmutableList.of()); 1147 verify(mockFileGroupsMetadata).removeAllStaleGroups(); 1148 verify(mockFileGroupsMetadata).writeStaleGroups(ImmutableList.of(staleGroup)); 1149 verifyNoMoreInteractions(mockFileGroupsMetadata); 1150 verify(mockSharedFilesMetadata).getAllFileKeys(); 1151 verify(mockSharedFileManager).getOnDeviceUri(fileKey); 1152 verifyNoMoreInteractions(mockSharedFileManager); 1153 verifyNoMoreInteractions(mockEventLogger); 1154 verify(mockBackend).exists(baseDownloadDirectoryUri); 1155 verify(mockBackend).children(baseDownloadDirectoryUri); 1156 verify(mockBackend).isDirectory(dirForAll); 1157 verify(mockBackend, never()).deleteFile(any()); 1158 } 1159 1160 @Test updateExpiration_sharedFiles_staleGroup_activeGroupNoExpiration()1161 public void updateExpiration_sharedFiles_staleGroup_activeGroupNoExpiration() throws Exception { 1162 Calendar now = new Calendar.Builder().setDate(2018, Calendar.MARCH, 20).build(); 1163 testClock.set(now.getTimeInMillis()); 1164 1165 DataFile dataFile = MddTestUtil.createDataFile("file", 0); 1166 NewFileKey fileKey = 1167 SharedFilesMetadata.createKeyFromDataFile( 1168 dataFile, AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES); 1169 1170 // The active group never expires. 1171 DataFileGroupInternal activeGroup = 1172 DataFileGroupInternal.newBuilder() 1173 .setGroupName(TEST_GROUP_1) 1174 .addFile(dataFile) 1175 .setAllowedReadersEnum(AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES) 1176 .build(); 1177 1178 // The stale group expires 2 days from now. 1179 Calendar sooner = new Calendar.Builder().setDate(2018, Calendar.MARCH, 22).build(); 1180 DataFileGroupInternal staleGroup = 1181 DataFileGroupInternal.newBuilder() 1182 .setGroupName(TEST_GROUP_2) 1183 .addFile(dataFile) 1184 .setAllowedReadersEnum(AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES) 1185 .setBookkeeping( 1186 DataFileGroupBookkeeping.newBuilder() 1187 .setStaleExpirationDate(sooner.getTimeInMillis() / 1000) 1188 .build()) 1189 .setStaleLifetimeSecs((sooner.getTimeInMillis() - now.getTimeInMillis()) / 1000) 1190 .build(); 1191 1192 List<GroupKeyAndGroup> groups = Arrays.asList(GroupKeyAndGroup.create(TEST_KEY_1, activeGroup)); 1193 when(mockFileGroupsMetadata.getAllFreshGroups()).thenReturn(Futures.immediateFuture(groups)); 1194 1195 fileGroupsMetadataStaleGroups.set(ImmutableList.of(staleGroup)); 1196 1197 when(mockSharedFileManager.getFileStatus(fileKey)) 1198 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 1199 when(mockSharedFileManager.getOnDeviceUri(fileKey)) 1200 .thenReturn(Futures.immediateFuture(testUri1)); 1201 when(mockSharedFilesMetadata.getAllFileKeys()) 1202 .thenReturn(Futures.immediateFuture(Collections.singletonList(fileKey))); 1203 when(mockBackend.children(dirFor0p)).thenReturn(Arrays.asList(testUri1)); 1204 1205 expirationHandler.updateExpiration().get(); 1206 1207 verify(mockFileGroupsMetadata, times(3)).getAllFreshGroups(); 1208 verify(mockFileGroupsMetadata, times(2)).getAllStaleGroups(); 1209 verify(mockFileGroupsMetadata).removeAllGroupsWithKeys(ImmutableList.of()); 1210 verify(mockFileGroupsMetadata).removeAllStaleGroups(); 1211 verify(mockFileGroupsMetadata).writeStaleGroups(ImmutableList.of(staleGroup)); 1212 verifyNoMoreInteractions(mockFileGroupsMetadata); 1213 verify(mockSharedFilesMetadata).getAllFileKeys(); 1214 verify(mockSharedFileManager).getOnDeviceUri(fileKey); 1215 verifyNoMoreInteractions(mockSharedFileManager); 1216 verifyNoMoreInteractions(mockEventLogger); 1217 verify(mockBackend).exists(baseDownloadDirectoryUri); 1218 verify(mockBackend).children(baseDownloadDirectoryUri); 1219 verify(mockBackend).isDirectory(dirForAll); 1220 verify(mockBackend, never()).deleteFile(any()); 1221 } 1222 1223 @Test updateExpiration_sharedFiles_staleGroupNonExpired_activeGroupExpired()1224 public void updateExpiration_sharedFiles_staleGroupNonExpired_activeGroupExpired() 1225 throws Exception { 1226 Calendar now = new Calendar.Builder().setDate(2018, Calendar.MARCH, 20).build(); 1227 testClock.set(now.getTimeInMillis()); 1228 1229 DataFile dataFile = MddTestUtil.createDataFile("file", 0); 1230 NewFileKey fileKey = 1231 SharedFilesMetadata.createKeyFromDataFile( 1232 dataFile, AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES); 1233 1234 // The active group is expired. 1235 Calendar sooner = new Calendar.Builder().setDate(2018, Calendar.MARCH, 19).build(); 1236 DataFileGroupInternal activeGroup = 1237 DataFileGroupInternal.newBuilder() 1238 .setGroupName(TEST_GROUP_1) 1239 .addFile(dataFile) 1240 .setAllowedReadersEnum(AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES) 1241 .setExpirationDateSecs(sooner.getTimeInMillis() / 1000) 1242 .build(); 1243 1244 // The stale group expires 2 days from now. 1245 Calendar later = new Calendar.Builder().setDate(2018, Calendar.MARCH, 22).build(); 1246 long laterTimeSecs = later.getTimeInMillis() / 1000; 1247 DataFileGroupInternal staleGroup = 1248 DataFileGroupInternal.newBuilder() 1249 .setGroupName(TEST_GROUP_2) 1250 .addFile(dataFile) 1251 .setAllowedReadersEnum(AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES) 1252 .setBookkeeping( 1253 DataFileGroupBookkeeping.newBuilder().setStaleExpirationDate(laterTimeSecs).build()) 1254 .setStaleLifetimeSecs(laterTimeSecs - now.getTimeInMillis() / 1000) 1255 .build(); 1256 1257 List<GroupKeyAndGroup> groups = Arrays.asList(GroupKeyAndGroup.create(TEST_KEY_1, activeGroup)); 1258 when(mockFileGroupsMetadata.getAllFreshGroups()).thenReturn(Futures.immediateFuture(groups)); 1259 1260 fileGroupsMetadataStaleGroups.set(ImmutableList.of(staleGroup)); 1261 1262 when(mockSharedFileManager.getFileStatus(fileKey)) 1263 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 1264 when(mockSharedFileManager.getOnDeviceUri(fileKey)) 1265 .thenReturn(Futures.immediateFuture(testUri1)); 1266 when(mockSharedFilesMetadata.getAllFileKeys()) 1267 .thenReturn(Futures.immediateFuture(Collections.singletonList(fileKey))); 1268 when(mockBackend.children(dirFor0p)).thenReturn(Arrays.asList(testUri1)); 1269 1270 expirationHandler.updateExpiration().get(); 1271 1272 verify(mockFileGroupsMetadata, times(3)).getAllFreshGroups(); 1273 verify(mockFileGroupsMetadata, times(2)).getAllStaleGroups(); 1274 verify(mockFileGroupsMetadata).removeAllGroupsWithKeys(Arrays.asList(TEST_KEY_1)); 1275 verify(mockFileGroupsMetadata).removeAllStaleGroups(); 1276 verify(mockFileGroupsMetadata).writeStaleGroups(ImmutableList.of(staleGroup)); 1277 verifyNoMoreInteractions(mockFileGroupsMetadata); 1278 verify(mockSharedFilesMetadata).getAllFileKeys(); 1279 verify(mockSharedFileManager).getOnDeviceUri(fileKey); 1280 verifyNoMoreInteractions(mockSharedFileManager); 1281 verify(mockEventLogger) 1282 .logEventSampled( 1283 MddClientEvent.Code.EVENT_CODE_UNSPECIFIED, 1284 activeGroup.getGroupName(), 1285 activeGroup.getFileGroupVersionNumber(), 1286 activeGroup.getBuildId(), 1287 activeGroup.getVariantId()); 1288 verifyNoMoreInteractions(mockEventLogger); 1289 verify(mockBackend).exists(baseDownloadDirectoryUri); 1290 verify(mockBackend).children(baseDownloadDirectoryUri); 1291 verify(mockBackend).isDirectory(dirForAll); 1292 verify(mockBackend, never()).deleteFile(any()); 1293 } 1294 1295 @Test updateExpiration_multipleExpiredGroups()1296 public void updateExpiration_multipleExpiredGroups() throws Exception { 1297 Calendar now = new Calendar.Builder().setDate(2018, Calendar.MARCH, 20).build(); 1298 testClock.set(now.getTimeInMillis()); 1299 1300 DataFile dataFile = MddTestUtil.createDataFile("file", 0); 1301 NewFileKey fileKey = 1302 SharedFilesMetadata.createKeyFromDataFile( 1303 dataFile, AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES); 1304 1305 // DAY 0 : The firstGroup is active and will expire in 30 days. 1306 Calendar earlier = new Calendar.Builder().setDate(2018, Calendar.MARCH, 19).build(); 1307 Long earlierSecs = earlier.getTimeInMillis() / 1000; 1308 DataFileGroupInternal firstGroup = 1309 DataFileGroupInternal.newBuilder() 1310 .setGroupName(TEST_GROUP_1) 1311 .addFile(dataFile) 1312 .setAllowedReadersEnum(AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES) 1313 .setExpirationDateSecs(earlierSecs) 1314 .build(); 1315 1316 Calendar earliest = new Calendar.Builder().setDate(2018, Calendar.MARCH, 18).build(); 1317 Long earliestSecs = earliest.getTimeInMillis() / 1000; 1318 DataFileGroupInternal secondGroup = 1319 DataFileGroupInternal.newBuilder() 1320 .setGroupName(TEST_GROUP_2) 1321 .addFile(dataFile) 1322 .setAllowedReadersEnum(AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES) 1323 .setExpirationDateSecs(earliestSecs) 1324 .build(); 1325 1326 List<GroupKeyAndGroup> groups = Arrays.asList(GroupKeyAndGroup.create(TEST_KEY_1, firstGroup)); 1327 when(mockFileGroupsMetadata.getAllFreshGroups()) 1328 .thenReturn(Futures.immediateFuture(groups)) 1329 .thenReturn(Futures.immediateFuture(ImmutableList.of())); 1330 1331 fileGroupsMetadataStaleGroups.set(ImmutableList.of(secondGroup)); 1332 1333 when(mockSharedFileManager.getFileStatus(fileKey)) 1334 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 1335 when(mockSharedFileManager.getOnDeviceUri(fileKey)) 1336 .thenReturn(Futures.immediateFuture(testUri1)); 1337 when(mockSharedFilesMetadata.getAllFileKeys()) 1338 .thenReturn(Futures.immediateFuture(Collections.singletonList(fileKey))); 1339 when(mockBackend.children(dirFor0p)) 1340 .thenReturn(Arrays.asList(testUri1, testUri3 /*an old file left on device somehow*/)); 1341 1342 expirationHandler.updateExpiration().get(); 1343 1344 verify(mockFileGroupsMetadata, times(3)).getAllFreshGroups(); 1345 verify(mockFileGroupsMetadata, times(2)).getAllStaleGroups(); 1346 verify(mockFileGroupsMetadata).removeAllGroupsWithKeys(Arrays.asList(TEST_KEY_1)); 1347 verify(mockFileGroupsMetadata).removeAllStaleGroups(); 1348 verify(mockFileGroupsMetadata).writeStaleGroups(ImmutableList.of()); 1349 verifyNoMoreInteractions(mockFileGroupsMetadata); 1350 verify(mockSharedFilesMetadata).getAllFileKeys(); 1351 // unsubscribe should only be called once even though two groups referencing fileKey have both 1352 // expired. 1353 verify(mockSharedFileManager).removeFileEntry(fileKey); 1354 verifyNoMoreInteractions(mockSharedFileManager); 1355 verify(mockBackend).exists(baseDownloadDirectoryUri); 1356 verify(mockBackend).children(baseDownloadDirectoryUri); 1357 verify(mockBackend).isDirectory(testUri1); 1358 verify(mockBackend).deleteFile(testUri1); 1359 verify(mockBackend).isDirectory(testUri3); 1360 verify(mockBackend).deleteFile(testUri3); 1361 } 1362 1363 @Test updateExpiration_multipleTimes_withGroupTransitions()1364 public void updateExpiration_multipleTimes_withGroupTransitions() throws Exception { 1365 Calendar now = new Calendar.Builder().setDate(2018, Calendar.MARCH, 20).build(); 1366 testClock.set(now.getTimeInMillis()); 1367 1368 DataFile dataFile = MddTestUtil.createDataFile("file", 0); 1369 NewFileKey fileKey = 1370 SharedFilesMetadata.createKeyFromDataFile( 1371 dataFile, AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES); 1372 1373 // DAY 0 : The firstGroup is active and will expire in 30 days. 1374 Calendar firstExpiration = new Calendar.Builder().setDate(2018, Calendar.APRIL, 20).build(); 1375 Long firstExpirationSecs = firstExpiration.getTimeInMillis() / 1000; 1376 DataFileGroupInternal.Builder firstGroup = 1377 DataFileGroupInternal.newBuilder() 1378 .setGroupName(TEST_GROUP_1) 1379 .addFile(dataFile) 1380 .setAllowedReadersEnum(AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES) 1381 .setExpirationDateSecs(firstExpirationSecs); 1382 1383 List<GroupKeyAndGroup> groups = 1384 Arrays.asList(GroupKeyAndGroup.create(TEST_KEY_1, firstGroup.build())); 1385 when(mockFileGroupsMetadata.getAllFreshGroups()).thenReturn(Futures.immediateFuture(groups)); 1386 1387 when(mockSharedFileManager.getFileStatus(fileKey)) 1388 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 1389 when(mockSharedFileManager.getOnDeviceUri(fileKey)) 1390 .thenReturn(Futures.immediateFuture(testUri1)); 1391 when(mockSharedFilesMetadata.getAllFileKeys()) 1392 .thenReturn(Futures.immediateFuture(Collections.singletonList(fileKey))); 1393 when(mockBackend.children(dirFor0p)).thenReturn(Arrays.asList(testUri1)); 1394 1395 expirationHandler.updateExpiration().get(); 1396 1397 verify(mockFileGroupsMetadata, times(3)).getAllFreshGroups(); 1398 verify(mockFileGroupsMetadata, times(2)).getAllStaleGroups(); 1399 verify(mockFileGroupsMetadata).removeAllGroupsWithKeys(ImmutableList.of()); 1400 verify(mockFileGroupsMetadata).removeAllStaleGroups(); 1401 verify(mockFileGroupsMetadata).writeStaleGroups(ImmutableList.of()); 1402 verifyNoMoreInteractions(mockFileGroupsMetadata); 1403 verify(mockSharedFilesMetadata).getAllFileKeys(); 1404 verify(mockSharedFileManager).getOnDeviceUri(fileKey); 1405 verify(mockBackend).exists(baseDownloadDirectoryUri); 1406 verify(mockBackend).children(baseDownloadDirectoryUri); 1407 verify(mockBackend).isDirectory(dirForAll); 1408 verify(mockBackend, never()).deleteFile(any()); 1409 verifyNoMoreInteractions(mockSharedFileManager); 1410 1411 // DAY 1 : firstGroup becomes stale and should expire in 2 days. 1412 now = new Calendar.Builder().setDate(2018, Calendar.MARCH, 21).build(); 1413 testClock.set(now.getTimeInMillis()); 1414 1415 Calendar firstStaleExpiration = 1416 new Calendar.Builder().setDate(2018, Calendar.MARCH, 23).build(); 1417 long firstStaleExpirationSecs = firstStaleExpiration.getTimeInMillis() / 1000; 1418 firstGroup 1419 .setBookkeeping( 1420 DataFileGroupBookkeeping.newBuilder() 1421 .setStaleExpirationDate(firstStaleExpirationSecs) 1422 .build()) 1423 .setStaleLifetimeSecs(firstStaleExpirationSecs - (now.getTimeInMillis() / 1000)); 1424 1425 when(mockFileGroupsMetadata.getAllFreshGroups()) 1426 .thenReturn(Futures.immediateFuture(ImmutableList.of())); 1427 1428 fileGroupsMetadataStaleGroups.set(ImmutableList.of(firstGroup.build())); 1429 1430 expirationHandler.updateExpiration().get(); 1431 1432 verify(mockFileGroupsMetadata, times(6)).getAllFreshGroups(); 1433 verify(mockFileGroupsMetadata, times(4)).getAllStaleGroups(); 1434 verify(mockFileGroupsMetadata, times(2)).removeAllGroupsWithKeys(ImmutableList.of()); 1435 verify(mockFileGroupsMetadata, times(2)).removeAllStaleGroups(); 1436 verify(mockFileGroupsMetadata).writeStaleGroups(ImmutableList.of(firstGroup.build())); 1437 verifyNoMoreInteractions(mockFileGroupsMetadata); 1438 verify(mockSharedFileManager, times(2)).getOnDeviceUri(fileKey); 1439 verify(mockSharedFilesMetadata, times(2)).getAllFileKeys(); 1440 verifyNoMoreInteractions(mockSharedFileManager); 1441 verify(mockBackend, times(2)).exists(baseDownloadDirectoryUri); 1442 verify(mockBackend, times(2)).children(baseDownloadDirectoryUri); 1443 verify(mockBackend, times(2)).isDirectory(dirFor1p); 1444 verify(mockBackend, never()).deleteFile(any()); 1445 1446 // DAY 2 : secondGroup arrives and requests the shared file. 1447 now = new Calendar.Builder().setDate(2018, Calendar.MARCH, 22).build(); 1448 testClock.set(now.getTimeInMillis()); 1449 1450 Calendar secondExpiration = new Calendar.Builder().setDate(2018, Calendar.APRIL, 22).build(); 1451 long secondExpirationSecs = secondExpiration.getTimeInMillis() / 1000; 1452 DataFileGroupInternal secondGroup = 1453 DataFileGroupInternal.newBuilder() 1454 .setGroupName(TEST_GROUP_2) 1455 .addFile(dataFile) 1456 .setAllowedReadersEnum(AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES) 1457 .setExpirationDateSecs(secondExpirationSecs) 1458 .build(); 1459 1460 groups = Arrays.asList(GroupKeyAndGroup.create(TEST_KEY_2, secondGroup)); 1461 when(mockFileGroupsMetadata.getAllFreshGroups()).thenReturn(Futures.immediateFuture(groups)); 1462 1463 expirationHandler.updateExpiration().get(); 1464 1465 verify(mockFileGroupsMetadata, times(9)).getAllFreshGroups(); 1466 verify(mockFileGroupsMetadata, times(6)).getAllStaleGroups(); 1467 verify(mockFileGroupsMetadata, times(3)).removeAllGroupsWithKeys(ImmutableList.of()); 1468 verify(mockFileGroupsMetadata, times(3)).removeAllStaleGroups(); 1469 verify(mockFileGroupsMetadata, times(2)).writeStaleGroups(ImmutableList.of(firstGroup.build())); 1470 verifyNoMoreInteractions(mockFileGroupsMetadata); 1471 verify(mockSharedFileManager, times(3)).getOnDeviceUri(fileKey); 1472 verify(mockSharedFilesMetadata, times(3)).getAllFileKeys(); 1473 verifyNoMoreInteractions(mockSharedFileManager); 1474 verify(mockBackend, times(3)).exists(baseDownloadDirectoryUri); 1475 verify(mockBackend, times(3)).children(baseDownloadDirectoryUri); 1476 verify(mockBackend, times(3)).isDirectory(dirFor0p); 1477 verify(mockBackend, never()).deleteFile(any()); 1478 1479 // DAY 3 : the firstGroup expires 1480 now = new Calendar.Builder().setDate(2018, Calendar.MARCH, 22).build(); 1481 testClock.set(now.getTimeInMillis()); 1482 1483 expirationHandler.updateExpiration().get(); 1484 1485 verify(mockFileGroupsMetadata, times(12)).getAllFreshGroups(); 1486 verify(mockFileGroupsMetadata, times(8)).getAllStaleGroups(); 1487 verify(mockFileGroupsMetadata, times(4)).removeAllGroupsWithKeys(ImmutableList.of()); 1488 verify(mockFileGroupsMetadata, times(4)).removeAllStaleGroups(); 1489 verify(mockFileGroupsMetadata, times(3)).writeStaleGroups(ImmutableList.of(firstGroup.build())); 1490 verifyNoMoreInteractions(mockFileGroupsMetadata); 1491 verify(mockSharedFileManager, times(4)).getOnDeviceUri(fileKey); 1492 verify(mockSharedFilesMetadata, times(4)).getAllFileKeys(); 1493 verifyNoMoreInteractions(mockSharedFileManager); 1494 verifyNoMoreInteractions(mockEventLogger); 1495 verify(mockBackend, times(4)).exists(baseDownloadDirectoryUri); 1496 verify(mockBackend, times(4)).children(baseDownloadDirectoryUri); 1497 verify(mockBackend, times(4)).isDirectory(dirForAll); 1498 verify(mockBackend, never()).deleteFile(any()); 1499 } 1500 1501 @Test updateExpiration_expiredGroups_withAndroidSharedFile()1502 public void updateExpiration_expiredGroups_withAndroidSharedFile() throws Exception { 1503 setupForAndroidShared(); 1504 // Current time 1505 Calendar now = new Calendar.Builder().setDate(2020, Calendar.MARCH, 20).build(); 1506 testClock.set(now.getTimeInMillis()); 1507 1508 DataFileGroupInternal dataFileGroup = MddTestUtil.createDataFileGroupInternal(TEST_GROUP_1, 1); 1509 // Time when the group expires 1510 Calendar earlier = new Calendar.Builder().setDate(2018, Calendar.MARCH, 20).build(); 1511 long nowTimeSecs = earlier.getTimeInMillis() / 1000; 1512 dataFileGroup = dataFileGroup.toBuilder().setExpirationDateSecs(nowTimeSecs).build(); 1513 NewFileKey[] fileKeys = MddTestUtil.createFileKeysForDataFileGroupInternal(dataFileGroup); 1514 String androidSharingChecksum = "sha256_" + dataFileGroup.getFile(0).getChecksum(); 1515 Uri blobUri = DirectoryUtil.getBlobUri(context, androidSharingChecksum); 1516 1517 assertThat(sharedFileManager.reserveFileEntry(fileKeys[0]).get()).isTrue(); 1518 assertThat( 1519 sharedFileManager 1520 .setAndroidSharedDownloadedFileEntry( 1521 fileKeys[0], androidSharingChecksum, nowTimeSecs) 1522 .get()) 1523 .isTrue(); 1524 assertThat(fileGroupsMetadata.write(TEST_KEY_1, dataFileGroup).get()).isTrue(); 1525 1526 expirationHandlerNoMocks.updateExpiration().get(); 1527 1528 verify(mockBlobStoreBackend).deleteFile(blobUri); 1529 assertThat(sharedFilesMetadata.read(fileKeys[0]).get()).isNull(); 1530 assertThat(fileGroupsMetadata.read(TEST_KEY_1).get()).isNull(); 1531 verify(mockEventLogger) 1532 .logEventSampled( 1533 MddClientEvent.Code.EVENT_CODE_UNSPECIFIED, 1534 dataFileGroup.getGroupName(), 1535 dataFileGroup.getFileGroupVersionNumber(), 1536 dataFileGroup.getBuildId(), 1537 dataFileGroup.getVariantId()); 1538 verify(mockEventLogger).logEventSampled(MddClientEvent.Code.EVENT_CODE_UNSPECIFIED); 1539 verify(mockEventLogger).logMddDataDownloadFileExpirationEvent(0, 1); 1540 verify(mockEventLogger).logMddDataDownloadFileExpirationEvent(0, 1); 1541 verifyNoMoreInteractions(mockEventLogger); 1542 } 1543 1544 @Test updateExpiration_expiredGroups_withAndroidSharedFile_releaseLeaseFails()1545 public void updateExpiration_expiredGroups_withAndroidSharedFile_releaseLeaseFails() 1546 throws Exception { 1547 setupForAndroidShared(); 1548 // Current time 1549 Calendar now = new Calendar.Builder().setDate(2020, Calendar.MARCH, 20).build(); 1550 testClock.set(now.getTimeInMillis()); 1551 1552 DataFileGroupInternal dataFileGroup = MddTestUtil.createDataFileGroupInternal(TEST_GROUP_1, 1); 1553 // Time when the group expires 1554 Calendar earlier = new Calendar.Builder().setDate(2018, Calendar.MARCH, 20).build(); 1555 long nowTimeSecs = earlier.getTimeInMillis() / 1000; 1556 dataFileGroup = dataFileGroup.toBuilder().setExpirationDateSecs(nowTimeSecs).build(); 1557 NewFileKey[] fileKeys = MddTestUtil.createFileKeysForDataFileGroupInternal(dataFileGroup); 1558 String androidSharingChecksum = "sha256_" + dataFileGroup.getFile(0).getChecksum(); 1559 Uri blobUri = DirectoryUtil.getBlobUri(context, androidSharingChecksum); 1560 1561 doThrow(new IOException()).when(mockBlobStoreBackend).deleteFile(blobUri); 1562 1563 assertThat(sharedFileManager.reserveFileEntry(fileKeys[0]).get()).isTrue(); 1564 assertThat( 1565 sharedFileManager 1566 .setAndroidSharedDownloadedFileEntry( 1567 fileKeys[0], androidSharingChecksum, nowTimeSecs) 1568 .get()) 1569 .isTrue(); 1570 assertThat(fileGroupsMetadata.write(TEST_KEY_1, dataFileGroup).get()).isTrue(); 1571 1572 expirationHandlerNoMocks.updateExpiration().get(); 1573 1574 verify(mockBlobStoreBackend).deleteFile(blobUri); 1575 assertThat(sharedFilesMetadata.read(fileKeys[0]).get()).isNull(); 1576 assertThat(fileGroupsMetadata.read(TEST_KEY_1).get()).isNull(); 1577 verify(mockEventLogger) 1578 .logEventSampled( 1579 MddClientEvent.Code.EVENT_CODE_UNSPECIFIED, 1580 dataFileGroup.getGroupName(), 1581 dataFileGroup.getFileGroupVersionNumber(), 1582 dataFileGroup.getBuildId(), 1583 dataFileGroup.getVariantId()); 1584 verify(mockEventLogger).logEventSampled(MddClientEvent.Code.EVENT_CODE_UNSPECIFIED); 1585 verify(mockEventLogger).logMddDataDownloadFileExpirationEvent(0, 1); 1586 verifyNoMoreInteractions(mockEventLogger); 1587 } 1588 1589 @Test updateExpiration_expiredGroups_withAndroidSharedAndNotAndroidSharedFiles()1590 public void updateExpiration_expiredGroups_withAndroidSharedAndNotAndroidSharedFiles() 1591 throws Exception { 1592 setupForAndroidShared(); 1593 Calendar now = new Calendar.Builder().setDate(2018, Calendar.MARCH, 20).build(); 1594 testClock.set(now.getTimeInMillis()); 1595 1596 DataFileGroupInternal dataFileGroup = MddTestUtil.createDataFileGroupInternal(TEST_GROUP_1, 2); 1597 long nowTimeSecs = now.getTimeInMillis() / 1000; 1598 dataFileGroup = dataFileGroup.toBuilder().setExpirationDateSecs(nowTimeSecs).build(); 1599 NewFileKey[] fileKeys = MddTestUtil.createFileKeysForDataFileGroupInternal(dataFileGroup); 1600 String androidSharingChecksum = "sha256_" + dataFileGroup.getFile(0).getChecksum(); 1601 Uri blobUri = DirectoryUtil.getBlobUri(context, androidSharingChecksum); 1602 1603 assertThat(sharedFileManager.reserveFileEntry(fileKeys[0]).get()).isTrue(); 1604 assertThat(sharedFileManager.reserveFileEntry(fileKeys[1]).get()).isTrue(); 1605 assertThat( 1606 sharedFileManager 1607 .setAndroidSharedDownloadedFileEntry( 1608 fileKeys[0], androidSharingChecksum, nowTimeSecs) 1609 .get()) 1610 .isTrue(); 1611 assertThat(fileGroupsMetadata.write(TEST_KEY_1, dataFileGroup).get()).isTrue(); 1612 1613 when(mockBackend.children(dirFor0p)).thenReturn(Arrays.asList(testUri2)); 1614 1615 expirationHandlerNoMocks.updateExpiration().get(); 1616 1617 verify(mockBackend).deleteFile(testUri2); 1618 verify(mockBlobStoreBackend).deleteFile(blobUri); 1619 assertThat(sharedFilesMetadata.read(fileKeys[0]).get()).isNull(); 1620 assertThat(sharedFilesMetadata.read(fileKeys[1]).get()).isNull(); 1621 assertThat(fileGroupsMetadata.read(TEST_KEY_1).get()).isNull(); 1622 1623 verify(mockEventLogger) 1624 .logEventSampled( 1625 MddClientEvent.Code.EVENT_CODE_UNSPECIFIED, 1626 dataFileGroup.getGroupName(), 1627 dataFileGroup.getFileGroupVersionNumber(), 1628 dataFileGroup.getBuildId(), 1629 dataFileGroup.getVariantId()); 1630 verify(mockEventLogger).logEventSampled(MddClientEvent.Code.EVENT_CODE_UNSPECIFIED); 1631 verify(mockEventLogger).logMddDataDownloadFileExpirationEvent(0, 1); 1632 verify(mockEventLogger).logMddDataDownloadFileExpirationEvent(0, 1); 1633 verify(mockEventLogger).logMddDataDownloadFileExpirationEvent(0, 2); 1634 verifyNoMoreInteractions(mockEventLogger); 1635 } 1636 1637 @Test updateExpiration_noExpiredAndroidSharedGroup_withUnaccountedFile()1638 public void updateExpiration_noExpiredAndroidSharedGroup_withUnaccountedFile() throws Exception { 1639 setupForAndroidShared(); 1640 Calendar now = new Calendar.Builder().setDate(2018, Calendar.MARCH, 20).build(); 1641 testClock.set(now.getTimeInMillis()); 1642 1643 DataFileGroupInternal dataFileGroup = 1644 MddTestUtil.createSharedDataFileGroupInternal(TEST_GROUP_1, 1); 1645 // No changes to dataFileGroup 1646 NewFileKey[] fileKeys = MddTestUtil.createFileKeysForDataFileGroupInternal(dataFileGroup); 1647 String androidSharingChecksum = dataFileGroup.getFile(0).getAndroidSharingChecksum(); 1648 Uri blobUri = DirectoryUtil.getBlobUri(context, androidSharingChecksum); 1649 1650 assertThat(sharedFileManager.reserveFileEntry(fileKeys[0]).get()).isTrue(); 1651 assertThat( 1652 sharedFileManager 1653 .setAndroidSharedDownloadedFileEntry(fileKeys[0], androidSharingChecksum, 0) 1654 .get()) 1655 .isTrue(); 1656 assertThat(fileGroupsMetadata.write(TEST_KEY_1, dataFileGroup).get()).isTrue(); 1657 1658 // Unaccounted file 1659 when(mockBackend.children(dirFor0p)).thenReturn(Arrays.asList(tempTestUri2)); 1660 1661 expirationHandlerNoMocks.updateExpiration().get(); 1662 1663 assertThat(fileGroupsMetadata.read(TEST_KEY_1).get()).isNotNull(); 1664 verify(mockBlobStoreBackend, never()).deleteFile(blobUri); 1665 verify(mockBackend).deleteFile(tempTestUri2); 1666 verify(mockEventLogger).logMddDataDownloadFileExpirationEvent(0, 1); 1667 verifyNoMoreInteractions(mockEventLogger); 1668 } 1669 1670 @Test updateExpiration_expiredGroups_withIsolatedStructure()1671 public void updateExpiration_expiredGroups_withIsolatedStructure() throws Exception { 1672 setupIsolatedSymlinkStructure(); 1673 1674 // Current time 1675 Calendar now = new Calendar.Builder().setDate(2020, Calendar.MARCH, 20).build(); 1676 testClock.set(now.getTimeInMillis()); 1677 1678 DataFileGroupInternal dataFileGroup = MddTestUtil.createDataFileGroupInternal(TEST_GROUP_1, 1); 1679 // Time when the group expires 1680 Calendar earlier = new Calendar.Builder().setDate(2018, Calendar.MARCH, 20).build(); 1681 long earlierTimeSecs = earlier.getTimeInMillis() / 1000; 1682 dataFileGroup = 1683 dataFileGroup.toBuilder() 1684 .setExpirationDateSecs(earlierTimeSecs) 1685 .setPreserveFilenamesAndIsolateFiles(true) 1686 .build(); 1687 1688 NewFileKey[] fileKeys = MddTestUtil.createFileKeysForDataFileGroupInternal(dataFileGroup); 1689 1690 List<GroupKeyAndGroup> groups = 1691 Arrays.asList(GroupKeyAndGroup.create(TEST_KEY_1, dataFileGroup)); 1692 when(mockFileGroupsMetadata.getAllFreshGroups()) 1693 .thenReturn(Futures.immediateFuture(groups)) 1694 .thenReturn(Futures.immediateFuture(new ArrayList<>())); 1695 when(mockSharedFileManager.getFileStatus(fileKeys[0])) 1696 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 1697 when(mockSharedFileManager.getOnDeviceUri(fileKeys[0])) 1698 .thenReturn(Futures.immediateFuture(testUri1)); 1699 1700 when(mockSharedFilesMetadata.getAllFileKeys()) 1701 .thenReturn(Futures.immediateFuture(Arrays.asList(fileKeys))); 1702 when(mockBackend.children(dirFor0p)).thenReturn(Arrays.asList(testUri1)); 1703 expirationHandler.updateExpiration().get(); 1704 1705 verify(mockFileGroupsMetadata, times(3)).getAllFreshGroups(); 1706 verify(mockFileGroupsMetadata, times(2)).getAllStaleGroups(); 1707 verify(mockFileGroupsMetadata).removeAllGroupsWithKeys(Arrays.asList(TEST_KEY_1)); 1708 verify(mockFileGroupsMetadata).removeAllStaleGroups(); 1709 verify(mockFileGroupsMetadata).writeStaleGroups(ImmutableList.of()); 1710 verifyNoMoreInteractions(mockFileGroupsMetadata); 1711 verify(mockSharedFilesMetadata).getAllFileKeys(); 1712 verify(mockSharedFileManager).removeFileEntry(fileKeys[0]); 1713 verify(mockBackend).exists(baseDownloadDirectoryUri); 1714 verify(mockBackend).children(baseDownloadDirectoryUri); 1715 verify(mockBackend).isDirectory(testUri1); 1716 verify(mockBackend).deleteFile(testUri1); 1717 verify(mockBackend, times(2)).exists(symlinkDirForGroup1); 1718 verify(mockBackend, times(2)).isDirectory(symlinkDirForGroup1); 1719 verify(mockBackend).deleteDirectory(symlinkDirForGroup1); 1720 verifyNoMoreInteractions(mockSharedFileManager); 1721 } 1722 1723 @Test updateExpiration_noExpiredGroups_doesNotRemoveIsolatedStructure()1724 public void updateExpiration_noExpiredGroups_doesNotRemoveIsolatedStructure() throws Exception { 1725 // Create group that has isolated structure 1726 DataFileGroupInternal dataFileGroup = 1727 MddTestUtil.createDataFileGroupInternal(TEST_GROUP_1, 1).toBuilder() 1728 .setPreserveFilenamesAndIsolateFiles(true) 1729 .build(); 1730 1731 NewFileKey[] fileKeys = MddTestUtil.createFileKeysForDataFileGroupInternal(dataFileGroup); 1732 1733 // Setup mocks to return our fresh group 1734 List<GroupKeyAndGroup> groups = 1735 Arrays.asList(GroupKeyAndGroup.create(TEST_KEY_1, dataFileGroup)); 1736 when(mockFileGroupsMetadata.getAllFreshGroups()).thenReturn(Futures.immediateFuture(groups)); 1737 when(mockSharedFileManager.getFileStatus(fileKeys[0])) 1738 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 1739 when(mockSharedFileManager.getOnDeviceUri(fileKeys[0])) 1740 .thenReturn(Futures.immediateFuture(testUri1)); 1741 when(mockSharedFilesMetadata.getAllFileKeys()) 1742 .thenReturn(Futures.immediateFuture(Arrays.asList(fileKeys))); 1743 1744 expirationHandler.updateExpiration().get(); 1745 1746 // Verify file is not deleted 1747 verify(mockBackend, never()).deleteFile(testUri1); 1748 1749 // Verify symlinks are not considered for deletion: 1750 verify(mockBackend, never()).exists(symlinkDirForGroup1); 1751 verify(mockBackend, never()).isDirectory(symlinkDirForGroup1); 1752 verify(mockBackend, never()).deleteDirectory(symlinkDirForGroup1); 1753 verify(mockBackend, never()).exists(symlinkForUri1); 1754 verify(mockBackend, never()).isDirectory(symlinkForUri1); 1755 verify(mockBackend, never()).deleteFile(symlinkForUri1); 1756 } 1757 1758 @Test updateExpiration_expiredStaleGroup_withIsolatedStructure_deletesFiles()1759 public void updateExpiration_expiredStaleGroup_withIsolatedStructure_deletesFiles() 1760 throws Exception { 1761 setupIsolatedSymlinkStructure(); 1762 1763 Calendar now = new Calendar.Builder().setDate(2018, Calendar.MARCH, 20).build(); 1764 Calendar later = new Calendar.Builder().setDate(2018, Calendar.MARCH, 22).build(); 1765 testClock.set(now.getTimeInMillis()); 1766 long nowTimeSecs = now.getTimeInMillis() / 1000; 1767 DataFileGroupInternal dataFileGroup = 1768 MddTestUtil.createDataFileGroupInternal(TEST_GROUP_1, 1).toBuilder() 1769 .setBookkeeping( 1770 DataFileGroupBookkeeping.newBuilder() 1771 .setStaleExpirationDate(later.getTimeInMillis() / 1000) 1772 .build()) 1773 .setExpirationDateSecs(nowTimeSecs) 1774 .setPreserveFilenamesAndIsolateFiles(true) 1775 .build(); 1776 NewFileKey[] fileKeys = MddTestUtil.createFileKeysForDataFileGroupInternal(dataFileGroup); 1777 1778 fileGroupsMetadataStaleGroups.set(ImmutableList.of(dataFileGroup)); 1779 1780 when(mockSharedFileManager.getFileStatus(fileKeys[0])) 1781 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 1782 when(mockSharedFileManager.getOnDeviceUri(fileKeys[0])) 1783 .thenReturn(Futures.immediateFuture(testDirUri1)); 1784 when(mockSharedFilesMetadata.getAllFileKeys()) 1785 .thenReturn(Futures.immediateFuture(Arrays.asList(fileKeys))); 1786 when(mockBackend.children(dirFor1p)).thenReturn(Arrays.asList(testDirUri1, testUri2)); 1787 when(mockBackend.children(testDirUri1)) 1788 .thenReturn(Arrays.asList(testDirFileUri1, testDirFileUri2)); 1789 1790 expirationHandler.updateExpiration().get(); 1791 1792 verify(mockFileGroupsMetadata, times(3)).getAllFreshGroups(); 1793 verify(mockFileGroupsMetadata, times(2)).getAllStaleGroups(); 1794 verify(mockFileGroupsMetadata).removeAllGroupsWithKeys(ImmutableList.of()); 1795 verify(mockFileGroupsMetadata).removeAllStaleGroups(); 1796 verify(mockFileGroupsMetadata).writeStaleGroups(ImmutableList.of()); 1797 verifyNoMoreInteractions(mockFileGroupsMetadata); 1798 verify(mockSharedFilesMetadata).getAllFileKeys(); 1799 verify(mockSharedFileManager).removeFileEntry(fileKeys[0]); 1800 verifyNoMoreInteractions(mockSharedFileManager); 1801 verify(mockBackend).exists(baseDownloadDirectoryUri); 1802 verify(mockBackend).children(baseDownloadDirectoryUri); 1803 verify(mockBackend).isDirectory(testDirUri1); 1804 verify(mockBackend).isDirectory(testDirFileUri1); 1805 verify(mockBackend).isDirectory(testDirFileUri2); 1806 verify(mockBackend, times(2)).exists(symlinkDirForGroup1); 1807 verify(mockBackend, times(2)).isDirectory(symlinkDirForGroup1); 1808 verify(mockBackend).deleteDirectory(symlinkDirForGroup1); 1809 verifyNoMoreInteractions(mockSharedFileManager); 1810 } 1811 1812 @Test updateExpiration_noExpiredGroups_removesUnaccountedIsolatedFileUri()1813 public void updateExpiration_noExpiredGroups_removesUnaccountedIsolatedFileUri() 1814 throws Exception { 1815 setupIsolatedSymlinkStructure(); 1816 1817 DataFileGroupInternal isolatedGroup1 = 1818 MddTestUtil.createDataFileGroupInternal(TEST_GROUP_1, 1).toBuilder() 1819 .setPreserveFilenamesAndIsolateFiles(true) 1820 .build(); 1821 NewFileKey[] fileKeys = MddTestUtil.createFileKeysForDataFileGroupInternal(isolatedGroup1); 1822 1823 List<GroupKeyAndGroup> groups = 1824 Arrays.asList(GroupKeyAndGroup.create(TEST_KEY_1, isolatedGroup1)); 1825 when(mockFileGroupsMetadata.getAllFreshGroups()).thenReturn(Futures.immediateFuture(groups)); 1826 when(mockSharedFileManager.getFileStatus(fileKeys[0])) 1827 .thenReturn(Futures.immediateFuture(FileStatus.DOWNLOAD_COMPLETE)); 1828 when(mockSharedFileManager.getOnDeviceUri(fileKeys[0])) 1829 .thenReturn(Futures.immediateFuture(testUri1)); 1830 1831 when(mockSharedFilesMetadata.getAllFileKeys()) 1832 .thenReturn(Futures.immediateFuture(Arrays.asList(fileKeys))); 1833 1834 expirationHandler.updateExpiration().get(); 1835 1836 // Verify only the unaccounted isolated file uri is deleted. 1837 verify(mockBackend).deleteFile(symlinkForUri2); 1838 verify(mockBackend, never()).deleteFile(symlinkForUri1); 1839 } 1840 1841 // TODO(b/115659980): consider moving this to a public utility class in the File Library setUpFileMock(Uri uri, long size)1842 private void setUpFileMock(Uri uri, long size) throws Exception { 1843 when(mockBackend.exists(uri)).thenReturn(true); 1844 when(mockBackend.isDirectory(uri)).thenReturn(false); 1845 when(mockBackend.fileSize(uri)).thenReturn(size); 1846 } 1847 1848 // TODO(b/115659980): consider moving this to a public utility class in the File Library setUpDirectoryMock(Uri uri, List<Uri> children)1849 private void setUpDirectoryMock(Uri uri, List<Uri> children) throws Exception { 1850 when(mockBackend.exists(uri)).thenReturn(true); 1851 when(mockBackend.isDirectory(uri)).thenReturn(true); 1852 when(mockBackend.children(uri)).thenReturn(children); 1853 } 1854 createFileKeysUseChecksumOnly(DataFileGroupInternal group)1855 private NewFileKey[] createFileKeysUseChecksumOnly(DataFileGroupInternal group) { 1856 NewFileKey[] newFileKeys = new NewFileKey[group.getFileCount()]; 1857 for (int i = 0; i < group.getFileCount(); ++i) { 1858 newFileKeys[i] = 1859 SharedFilesMetadata.createKeyFromDataFileForCurrentVersion( 1860 context, group.getFile(i), group.getAllowedReadersEnum(), mockSilentFeedback); 1861 } 1862 return newFileKeys; 1863 } 1864 setupIsolatedSymlinkStructure()1865 private void setupIsolatedSymlinkStructure() throws Exception { 1866 setUpDirectoryMock( 1867 baseDownloadDirectoryUri, 1868 Arrays.asList(dirForAll, dirFor1p, dirFor0p, baseDownloadSymlinkDirectoryUri)); 1869 setUpDirectoryMock( 1870 baseDownloadSymlinkDirectoryUri, 1871 ImmutableList.of(symlinkDirForGroup1, symlinkDirForGroup2)); 1872 setUpDirectoryMock(symlinkDirForGroup1, ImmutableList.of(symlinkForUri1)); 1873 setUpDirectoryMock(symlinkDirForGroup2, ImmutableList.of(symlinkForUri2)); 1874 } 1875 } 1876