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.logging; 17 18 import static com.google.common.truth.Truth.assertThat; 19 import static junit.framework.TestCase.assertTrue; 20 import static org.junit.Assert.assertFalse; 21 import static org.mockito.ArgumentMatchers.any; 22 import static org.mockito.Mockito.times; 23 import static org.mockito.Mockito.verify; 24 import static org.mockito.Mockito.when; 25 26 import com.google.mobiledatadownload.internal.MetadataProto.DataFile; 27 import com.google.mobiledatadownload.internal.MetadataProto.DataFileGroupBookkeeping; 28 import com.google.mobiledatadownload.internal.MetadataProto.DataFileGroupInternal; 29 import com.google.mobiledatadownload.internal.MetadataProto.GroupKey; 30 import com.google.android.libraries.mobiledatadownload.internal.FileGroupManager; 31 import com.google.android.libraries.mobiledatadownload.internal.FileGroupManager.GroupDownloadStatus; 32 import com.google.android.libraries.mobiledatadownload.internal.FileGroupsMetadata; 33 import com.google.android.libraries.mobiledatadownload.internal.MddTestUtil; 34 import com.google.android.libraries.mobiledatadownload.internal.collect.GroupKeyAndGroup; 35 import com.google.android.libraries.mobiledatadownload.internal.util.FileGroupUtil; 36 import com.google.common.util.concurrent.AsyncCallable; 37 import com.google.common.util.concurrent.Futures; 38 import com.google.common.util.concurrent.MoreExecutors; 39 import com.google.mobiledatadownload.LogEnumsProto.MddFileGroupDownloadStatus; 40 import com.google.mobiledatadownload.LogProto.DataDownloadFileGroupStats; 41 import com.google.mobiledatadownload.LogProto.MddFileGroupStatus; 42 import java.util.ArrayList; 43 import java.util.List; 44 import org.junit.Before; 45 import org.junit.Rule; 46 import org.junit.Test; 47 import org.junit.runner.RunWith; 48 import org.mockito.ArgumentCaptor; 49 import org.mockito.Captor; 50 import org.mockito.Mock; 51 import org.mockito.junit.MockitoJUnit; 52 import org.mockito.junit.MockitoRule; 53 import org.robolectric.RobolectricTestRunner; 54 55 @RunWith(RobolectricTestRunner.class) 56 public class FileGroupStatsLoggerTest { 57 58 private static final String TEST_GROUP = "test-group"; 59 private static final String TEST_GROUP_2 = "test-group-2"; 60 61 private static final String TEST_PACKAGE = "test-package"; 62 63 // This one has account 64 private static final GroupKey TEST_KEY = 65 GroupKey.newBuilder() 66 .setGroupName(TEST_GROUP) 67 .setOwnerPackage(TEST_PACKAGE) 68 .setAccount("some_account") 69 .build(); 70 71 // This one does not have account 72 private static final GroupKey TEST_KEY_2 = 73 GroupKey.newBuilder().setGroupName(TEST_GROUP_2).setOwnerPackage(TEST_PACKAGE).build(); 74 75 @Mock FileGroupManager mockFileGroupManager; 76 @Mock FileGroupsMetadata mockFileGroupsMetadata; 77 @Mock EventLogger mockEventLogger; 78 79 private FileGroupStatsLogger fileGroupStatsLogger; 80 81 @Rule public final MockitoRule mocks = MockitoJUnit.rule(); 82 83 @Captor 84 ArgumentCaptor<AsyncCallable<List<EventLogger.FileGroupStatusWithDetails>>> 85 fileGroupStatusAndDetailsListCaptor; 86 87 @Before setUp()88 public void setUp() throws Exception { 89 90 fileGroupStatsLogger = 91 new FileGroupStatsLogger( 92 mockFileGroupManager, 93 mockFileGroupsMetadata, 94 mockEventLogger, 95 MoreExecutors.directExecutor()); 96 } 97 98 @Test fileGroupStatsLogging()99 public void fileGroupStatsLogging() throws Exception { 100 int daysSinceLastLog = 10; 101 102 List<GroupKeyAndGroup> groups = new ArrayList<>(); 103 104 // Add a downloaded group with version number 10. 105 DataFileGroupInternal fileGroupDownloaded = 106 MddTestUtil.createDataFileGroupInternal(TEST_GROUP, 2).toBuilder() 107 .setFileGroupVersionNumber(10) 108 .setBuildId(10) 109 .setVariantId("test-variant") 110 .build(); 111 fileGroupDownloaded = 112 FileGroupUtil.setGroupNewFilesReceivedTimestamp(fileGroupDownloaded, 5000); 113 fileGroupDownloaded = FileGroupUtil.setDownloadedTimestampInMillis(fileGroupDownloaded, 10000); 114 115 groups.add( 116 GroupKeyAndGroup.create( 117 TEST_KEY.toBuilder().setDownloaded(true).build(), fileGroupDownloaded)); 118 119 // Add a pending download group for the same group name with version number 11. 120 DataFileGroupInternal fileGroupPending = 121 MddTestUtil.createDataFileGroupInternal(TEST_GROUP, 3).toBuilder() 122 .setFileGroupVersionNumber(11) 123 .setStaleLifetimeSecs(0) 124 .setExpirationDateSecs(0) 125 .setBookkeeping(DataFileGroupBookkeeping.newBuilder().setStaleExpirationDate(0).build()) 126 .setBuildId(11) 127 .setVariantId("test-variant") 128 .build(); 129 fileGroupPending = FileGroupUtil.setGroupNewFilesReceivedTimestamp(fileGroupPending, 15000); 130 groups.add(GroupKeyAndGroup.create(TEST_KEY, fileGroupPending)); 131 when(mockFileGroupManager.getFileGroupDownloadStatus(fileGroupPending)) 132 .thenReturn(Futures.immediateFuture(GroupDownloadStatus.PENDING)); 133 134 // Add a failed group to metadata with version 5. 135 DataFileGroupInternal fileGroupFailed = 136 MddTestUtil.createDataFileGroupInternal(TEST_GROUP_2, 3).toBuilder() 137 .setFileGroupVersionNumber(5) 138 .setStaleLifetimeSecs(0) 139 .setExpirationDateSecs(0) 140 .setBookkeeping(DataFileGroupBookkeeping.newBuilder().setStaleExpirationDate(0).build()) 141 .build(); 142 fileGroupFailed = FileGroupUtil.setGroupNewFilesReceivedTimestamp(fileGroupFailed, 12000); 143 groups.add(GroupKeyAndGroup.create(TEST_KEY_2, fileGroupFailed)); 144 when(mockFileGroupManager.getFileGroupDownloadStatus(fileGroupFailed)) 145 .thenReturn(Futures.immediateFuture(GroupDownloadStatus.FAILED)); 146 147 when(mockFileGroupsMetadata.getAllFreshGroups()).thenReturn(Futures.immediateFuture(groups)); 148 149 when(mockEventLogger.logMddFileGroupStats(any())).thenReturn(Futures.immediateVoidFuture()); 150 fileGroupStatsLogger.log(daysSinceLastLog).get(); 151 152 verify(mockEventLogger, times(1)) 153 .logMddFileGroupStats(fileGroupStatusAndDetailsListCaptor.capture()); 154 155 List<EventLogger.FileGroupStatusWithDetails> allFileGroupStatusAndDetailsList = 156 fileGroupStatusAndDetailsListCaptor.getValue().call().get(); 157 MddFileGroupStatus status1 = allFileGroupStatusAndDetailsList.get(0).fileGroupStatus(); 158 MddFileGroupStatus status2 = allFileGroupStatusAndDetailsList.get(1).fileGroupStatus(); 159 MddFileGroupStatus status3 = allFileGroupStatusAndDetailsList.get(2).fileGroupStatus(); 160 161 DataDownloadFileGroupStats details1 = 162 allFileGroupStatusAndDetailsList.get(0).fileGroupDetails(); 163 DataDownloadFileGroupStats details2 = 164 allFileGroupStatusAndDetailsList.get(1).fileGroupDetails(); 165 DataDownloadFileGroupStats details3 = 166 allFileGroupStatusAndDetailsList.get(2).fileGroupDetails(); 167 168 // Check that the downloaded group status is logged. 169 assertThat(details1.getFileGroupName()).isEqualTo(TEST_GROUP); 170 assertThat(details1.getOwnerPackage()).isEqualTo(TEST_PACKAGE); 171 assertThat(details1.getFileGroupVersionNumber()).isEqualTo(10); 172 assertThat(details1.getBuildId()).isEqualTo(10); 173 assertThat(details1.getVariantId()).isEqualTo("test-variant"); 174 assertThat(details1.getFileCount()).isEqualTo(2); 175 assertThat(details1.getInlineFileCount()).isEqualTo(0); 176 assertTrue(details1.getHasAccount()); 177 assertThat(status1.getFileGroupDownloadStatus()) 178 .isEqualTo(MddFileGroupDownloadStatus.Code.COMPLETE); 179 assertThat(status1.getGroupAddedTimestampInSeconds()).isEqualTo(5); 180 assertThat(status1.getGroupDownloadedTimestampInSeconds()).isEqualTo(10); 181 assertThat(status1.getDaysSinceLastLog()).isEqualTo(daysSinceLastLog); 182 183 // Check that the pending group status is logged. 184 assertThat(details2.getFileGroupName()).isEqualTo(TEST_GROUP); 185 assertThat(details2.getFileGroupVersionNumber()).isEqualTo(11); 186 assertThat(details2.getBuildId()).isEqualTo(11); 187 assertThat(details2.getVariantId()).isEqualTo("test-variant"); 188 assertThat(details2.getOwnerPackage()).isEqualTo(TEST_PACKAGE); 189 assertThat(details2.getFileCount()).isEqualTo(3); 190 assertThat(details2.getInlineFileCount()).isEqualTo(0); 191 assertTrue(details2.getHasAccount()); 192 assertThat(status2.getFileGroupDownloadStatus()) 193 .isEqualTo(MddFileGroupDownloadStatus.Code.PENDING); 194 assertThat(status2.getGroupAddedTimestampInSeconds()).isEqualTo(15); 195 assertThat(status2.getGroupDownloadedTimestampInSeconds()).isEqualTo(-1); 196 assertThat(status2.getDaysSinceLastLog()).isEqualTo(daysSinceLastLog); 197 198 // Check that the failed group status is logged. 199 assertThat(details3.getFileGroupName()).isEqualTo(TEST_GROUP_2); 200 assertThat(details3.getFileGroupVersionNumber()).isEqualTo(5); 201 assertThat(details3.getOwnerPackage()).isEqualTo(TEST_PACKAGE); 202 assertThat(details3.getFileCount()).isEqualTo(3); 203 assertThat(details3.getInlineFileCount()).isEqualTo(0); 204 assertFalse(details3.getHasAccount()); 205 assertThat(status3.getFileGroupDownloadStatus()) 206 .isEqualTo(MddFileGroupDownloadStatus.Code.FAILED); 207 assertThat(status3.getGroupAddedTimestampInSeconds()).isEqualTo(12); 208 assertThat(status3.getGroupDownloadedTimestampInSeconds()).isEqualTo(-1); 209 assertThat(status3.getDaysSinceLastLog()).isEqualTo(daysSinceLastLog); 210 } 211 212 @Test fileGroupStatsLogging_withInlineFiles()213 public void fileGroupStatsLogging_withInlineFiles() throws Exception { 214 int daysSinceLastLog = 10; 215 216 List<GroupKeyAndGroup> groups = new ArrayList<>(); 217 218 DataFile inlineFile1 = 219 DataFile.newBuilder() 220 .setFileId("inline-file") 221 .setUrlToDownload("inlinefile:sha1:checksum") 222 .setChecksum("checksum") 223 .setByteSize(10) 224 .build(); 225 DataFile inlineFile2 = 226 DataFile.newBuilder() 227 .setFileId("inline-file-2") 228 .setUrlToDownload("inlinefile:sha1:checksum2") 229 .setChecksum("checksum2") 230 .setByteSize(11) 231 .build(); 232 233 // Add a downloaded group with version number 10 and inline file 234 DataFileGroupInternal fileGroupDownloaded = 235 MddTestUtil.createDataFileGroupInternal(TEST_GROUP, 2).toBuilder() 236 .setFileGroupVersionNumber(10) 237 .setBuildId(10) 238 .setVariantId("test-variant") 239 .addFile(inlineFile1) 240 .addFile(inlineFile2) 241 .build(); 242 fileGroupDownloaded = 243 FileGroupUtil.setGroupNewFilesReceivedTimestamp(fileGroupDownloaded, 5000); 244 fileGroupDownloaded = FileGroupUtil.setDownloadedTimestampInMillis(fileGroupDownloaded, 10000); 245 246 groups.add( 247 GroupKeyAndGroup.create( 248 TEST_KEY.toBuilder().setDownloaded(true).build(), fileGroupDownloaded)); 249 250 // Add a pending download group for the same group name with version number 11 and inline file. 251 DataFileGroupInternal fileGroupPending = 252 MddTestUtil.createDataFileGroupInternal(TEST_GROUP, 3).toBuilder() 253 .setFileGroupVersionNumber(11) 254 .setStaleLifetimeSecs(0) 255 .setExpirationDateSecs(0) 256 .setBookkeeping(DataFileGroupBookkeeping.newBuilder().setStaleExpirationDate(0).build()) 257 .setBuildId(11) 258 .setVariantId("test-variant") 259 .addFile(inlineFile1) 260 .build(); 261 fileGroupPending = FileGroupUtil.setGroupNewFilesReceivedTimestamp(fileGroupPending, 15000); 262 groups.add(GroupKeyAndGroup.create(TEST_KEY, fileGroupPending)); 263 when(mockFileGroupManager.getFileGroupDownloadStatus(fileGroupPending)) 264 .thenReturn(Futures.immediateFuture(GroupDownloadStatus.PENDING)); 265 266 // Add a failed group to metadata with version 5 with no inline files. 267 DataFileGroupInternal fileGroupFailed = 268 MddTestUtil.createDataFileGroupInternal(TEST_GROUP_2, 3).toBuilder() 269 .setFileGroupVersionNumber(5) 270 .setStaleLifetimeSecs(0) 271 .setExpirationDateSecs(0) 272 .setBookkeeping(DataFileGroupBookkeeping.newBuilder().setStaleExpirationDate(0).build()) 273 .build(); 274 fileGroupFailed = FileGroupUtil.setGroupNewFilesReceivedTimestamp(fileGroupFailed, 12000); 275 groups.add(GroupKeyAndGroup.create(TEST_KEY_2, fileGroupFailed)); 276 when(mockFileGroupManager.getFileGroupDownloadStatus(fileGroupFailed)) 277 .thenReturn(Futures.immediateFuture(GroupDownloadStatus.FAILED)); 278 279 when(mockFileGroupsMetadata.getAllFreshGroups()).thenReturn(Futures.immediateFuture(groups)); 280 when(mockEventLogger.logMddFileGroupStats(any())).thenReturn(Futures.immediateVoidFuture()); 281 282 fileGroupStatsLogger.log(daysSinceLastLog).get(); 283 284 verify(mockEventLogger, times(1)) 285 .logMddFileGroupStats(fileGroupStatusAndDetailsListCaptor.capture()); 286 287 List<EventLogger.FileGroupStatusWithDetails> allFileGroupStatusAndDetailsList = 288 fileGroupStatusAndDetailsListCaptor.getValue().call().get(); 289 MddFileGroupStatus status1 = allFileGroupStatusAndDetailsList.get(0).fileGroupStatus(); 290 MddFileGroupStatus status2 = allFileGroupStatusAndDetailsList.get(1).fileGroupStatus(); 291 MddFileGroupStatus status3 = allFileGroupStatusAndDetailsList.get(2).fileGroupStatus(); 292 293 DataDownloadFileGroupStats details1 = 294 allFileGroupStatusAndDetailsList.get(0).fileGroupDetails(); 295 DataDownloadFileGroupStats details2 = 296 allFileGroupStatusAndDetailsList.get(1).fileGroupDetails(); 297 DataDownloadFileGroupStats details3 = 298 allFileGroupStatusAndDetailsList.get(2).fileGroupDetails(); 299 300 // Check that the downloaded group status is logged. 301 assertThat(details1.getFileGroupName()).isEqualTo(TEST_GROUP); 302 assertThat(details1.getOwnerPackage()).isEqualTo(TEST_PACKAGE); 303 assertThat(details1.getFileGroupVersionNumber()).isEqualTo(10); 304 assertThat(details1.getBuildId()).isEqualTo(10); 305 assertThat(details1.getVariantId()).isEqualTo("test-variant"); 306 assertThat(details1.getFileCount()).isEqualTo(4); 307 assertThat(details1.getInlineFileCount()).isEqualTo(2); 308 assertTrue(details1.getHasAccount()); 309 assertThat(status1.getFileGroupDownloadStatus()) 310 .isEqualTo(MddFileGroupDownloadStatus.Code.COMPLETE); 311 assertThat(status1.getGroupAddedTimestampInSeconds()).isEqualTo(5); 312 assertThat(status1.getGroupDownloadedTimestampInSeconds()).isEqualTo(10); 313 assertThat(status1.getDaysSinceLastLog()).isEqualTo(daysSinceLastLog); 314 315 // Check that the pending group status is logged. 316 assertThat(details2.getFileGroupName()).isEqualTo(TEST_GROUP); 317 assertThat(details2.getFileGroupVersionNumber()).isEqualTo(11); 318 assertThat(details2.getBuildId()).isEqualTo(11); 319 assertThat(details2.getVariantId()).isEqualTo("test-variant"); 320 assertThat(details2.getOwnerPackage()).isEqualTo(TEST_PACKAGE); 321 assertThat(details2.getFileCount()).isEqualTo(4); 322 assertThat(details2.getInlineFileCount()).isEqualTo(1); 323 assertTrue(details2.getHasAccount()); 324 assertThat(status2.getFileGroupDownloadStatus()) 325 .isEqualTo(MddFileGroupDownloadStatus.Code.PENDING); 326 assertThat(status2.getGroupAddedTimestampInSeconds()).isEqualTo(15); 327 assertThat(status2.getGroupDownloadedTimestampInSeconds()).isEqualTo(-1); 328 assertThat(status2.getDaysSinceLastLog()).isEqualTo(daysSinceLastLog); 329 330 // Check that the failed group status is logged. 331 assertThat(details3.getFileGroupName()).isEqualTo(TEST_GROUP_2); 332 assertThat(details3.getFileGroupVersionNumber()).isEqualTo(5); 333 assertThat(details3.getOwnerPackage()).isEqualTo(TEST_PACKAGE); 334 assertThat(details3.getFileCount()).isEqualTo(3); 335 assertThat(details3.getInlineFileCount()).isEqualTo(0); 336 assertFalse(details3.getHasAccount()); 337 assertThat(status3.getFileGroupDownloadStatus()) 338 .isEqualTo(MddFileGroupDownloadStatus.Code.FAILED); 339 assertThat(status3.getGroupAddedTimestampInSeconds()).isEqualTo(12); 340 assertThat(status3.getGroupDownloadedTimestampInSeconds()).isEqualTo(-1); 341 assertThat(status3.getDaysSinceLastLog()).isEqualTo(daysSinceLastLog); 342 } 343 } 344