1 /* 2 * Copyright (C) 2022 The Android Open Source Project 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 17 package android.app.backup; 18 19 import static android.app.backup.BackupAnnotations.OperationType.BACKUP; 20 import static android.app.backup.BackupAnnotations.OperationType.RESTORE; 21 22 import static com.google.common.truth.Truth.assertThat; 23 24 import static junit.framework.Assert.fail; 25 26 import android.app.backup.BackupRestoreEventLogger.DataTypeResult; 27 import android.os.Parcel; 28 import android.platform.test.annotations.Presubmit; 29 import android.platform.test.flag.junit.SetFlagsRule; 30 31 import androidx.test.runner.AndroidJUnit4; 32 33 import com.android.server.backup.Flags; 34 35 import org.junit.Before; 36 import org.junit.Rule; 37 import org.junit.Test; 38 import org.junit.runner.RunWith; 39 40 import java.nio.charset.StandardCharsets; 41 import java.security.MessageDigest; 42 import java.util.ArrayList; 43 import java.util.Arrays; 44 import java.util.List; 45 import java.util.Optional; 46 47 @Presubmit 48 @RunWith(AndroidJUnit4.class) 49 public class BackupRestoreEventLoggerTest { 50 private static final int DATA_TYPES_ALLOWED_AFTER_FLAG = 150; 51 52 private static final int DATA_TYPES_ALLOWED_BEFORE_FLAG = 15; 53 54 private static final String DATA_TYPE_1 = "data_type_1"; 55 private static final String DATA_TYPE_2 = "data_type_2"; 56 private static final String ERROR_1 = "error_1"; 57 private static final String ERROR_2 = "error_2"; 58 private static final String METADATA_1 = "metadata_1"; 59 private static final String METADATA_2 = "metadata_2"; 60 61 private BackupRestoreEventLogger mLogger; 62 private MessageDigest mHashDigest; 63 64 @Rule 65 public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); 66 67 @Before setUp()68 public void setUp() throws Exception { 69 mHashDigest = MessageDigest.getInstance("SHA-256"); 70 } 71 72 @Test testBackupLogger_rejectsRestoreLogs()73 public void testBackupLogger_rejectsRestoreLogs() { 74 mLogger = new BackupRestoreEventLogger(BACKUP); 75 76 mLogger.logItemsRestored(DATA_TYPE_1, /* count */ 5); 77 mLogger.logItemsRestoreFailed(DATA_TYPE_1, /* count */ 5, ERROR_1); 78 mLogger.logRestoreMetadata(DATA_TYPE_1, /* metadata */ "metadata"); 79 80 assertThat(getResultForDataTypeIfPresent(mLogger, DATA_TYPE_1)).isEqualTo(Optional.empty()); 81 } 82 83 @Test testRestoreLogger_rejectsBackupLogs()84 public void testRestoreLogger_rejectsBackupLogs() { 85 mLogger = new BackupRestoreEventLogger(RESTORE); 86 87 mLogger.logItemsBackedUp(DATA_TYPE_1, /* count */ 5); 88 mLogger.logItemsBackupFailed(DATA_TYPE_1, /* count */ 5, ERROR_1); 89 mLogger.logBackupMetadata(DATA_TYPE_1, /* metadata */ "metadata"); 90 91 assertThat(getResultForDataTypeIfPresent(mLogger, DATA_TYPE_1)).isEqualTo(Optional.empty()); 92 } 93 94 @Test testBackupLogger_datatypeLimitFlagOff_onlyAcceptsAllowedNumberOfDataTypes()95 public void testBackupLogger_datatypeLimitFlagOff_onlyAcceptsAllowedNumberOfDataTypes() { 96 mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_INCREASE_DATATYPES_FOR_AGENT_LOGGING); 97 mLogger = new BackupRestoreEventLogger(BACKUP); 98 99 for (int i = 0; i < DATA_TYPES_ALLOWED_BEFORE_FLAG; i++) { 100 String dataType = DATA_TYPE_1 + i; 101 mLogger.logItemsBackedUp(dataType, /* count */ 5); 102 mLogger.logItemsBackupFailed(dataType, /* count */ 5, /* error */ null); 103 mLogger.logBackupMetadata(dataType, METADATA_1); 104 105 assertThat(getResultForDataTypeIfPresent(mLogger, dataType)).isNotEqualTo( 106 Optional.empty()); 107 } 108 109 mLogger.logItemsBackedUp(DATA_TYPE_2, /* count */ 5); 110 mLogger.logItemsBackupFailed(DATA_TYPE_2, /* count */ 5, /* error */ null); 111 mLogger.logRestoreMetadata(DATA_TYPE_2, METADATA_1); 112 assertThat(getResultForDataTypeIfPresent(mLogger, DATA_TYPE_2)).isEqualTo(Optional.empty()); 113 } 114 115 @Test testRestoreLogger_datatypeLimitFlagOff_onlyAcceptsAllowedNumberOfDataTypes()116 public void testRestoreLogger_datatypeLimitFlagOff_onlyAcceptsAllowedNumberOfDataTypes() { 117 mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_INCREASE_DATATYPES_FOR_AGENT_LOGGING); 118 mLogger = new BackupRestoreEventLogger(RESTORE); 119 120 for (int i = 0; i < DATA_TYPES_ALLOWED_BEFORE_FLAG; i++) { 121 String dataType = DATA_TYPE_1 + i; 122 mLogger.logItemsRestored(dataType, /* count */ 5); 123 mLogger.logItemsRestoreFailed(dataType, /* count */ 5, /* error */ null); 124 mLogger.logRestoreMetadata(dataType, METADATA_1); 125 126 assertThat(getResultForDataTypeIfPresent(mLogger, dataType)).isNotEqualTo( 127 Optional.empty()); 128 } 129 130 mLogger.logItemsRestored(DATA_TYPE_2, /* count */ 5); 131 mLogger.logItemsRestoreFailed(DATA_TYPE_2, /* count */ 5, /* error */ null); 132 mLogger.logRestoreMetadata(DATA_TYPE_2, METADATA_1); 133 assertThat(getResultForDataTypeIfPresent(mLogger, DATA_TYPE_2)).isEqualTo(Optional.empty()); 134 } 135 136 @Test testBackupLogger_datatypeLimitFlagOn_onlyAcceptsAllowedNumberOfDataTypes()137 public void testBackupLogger_datatypeLimitFlagOn_onlyAcceptsAllowedNumberOfDataTypes() { 138 mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_INCREASE_DATATYPES_FOR_AGENT_LOGGING); 139 mLogger = new BackupRestoreEventLogger(BACKUP); 140 141 for (int i = 0; i < DATA_TYPES_ALLOWED_AFTER_FLAG; i++) { 142 String dataType = DATA_TYPE_1 + i; 143 mLogger.logItemsBackedUp(dataType, /* count */ 5); 144 mLogger.logItemsBackupFailed(dataType, /* count */ 5, /* error */ null); 145 mLogger.logBackupMetadata(dataType, METADATA_1); 146 147 assertThat(getResultForDataTypeIfPresent(mLogger, dataType)).isNotEqualTo( 148 Optional.empty()); 149 } 150 151 mLogger.logItemsBackedUp(DATA_TYPE_2, /* count */ 5); 152 mLogger.logItemsBackupFailed(DATA_TYPE_2, /* count */ 5, /* error */ null); 153 mLogger.logRestoreMetadata(DATA_TYPE_2, METADATA_1); 154 assertThat(getResultForDataTypeIfPresent(mLogger, DATA_TYPE_2)).isEqualTo(Optional.empty()); 155 } 156 157 @Test testRestoreLogger_datatypeLimitFlagOn_onlyAcceptsAllowedNumberOfDataTypes()158 public void testRestoreLogger_datatypeLimitFlagOn_onlyAcceptsAllowedNumberOfDataTypes() { 159 mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_INCREASE_DATATYPES_FOR_AGENT_LOGGING); 160 mLogger = new BackupRestoreEventLogger(RESTORE); 161 162 for (int i = 0; i < DATA_TYPES_ALLOWED_AFTER_FLAG; i++) { 163 String dataType = DATA_TYPE_1 + i; 164 mLogger.logItemsRestored(dataType, /* count */ 5); 165 mLogger.logItemsRestoreFailed(dataType, /* count */ 5, /* error */ null); 166 mLogger.logRestoreMetadata(dataType, METADATA_1); 167 168 assertThat(getResultForDataTypeIfPresent(mLogger, dataType)).isNotEqualTo( 169 Optional.empty()); 170 } 171 172 mLogger.logItemsRestored(DATA_TYPE_2, /* count */ 5); 173 mLogger.logItemsRestoreFailed(DATA_TYPE_2, /* count */ 5, /* error */ null); 174 mLogger.logRestoreMetadata(DATA_TYPE_2, METADATA_1); 175 assertThat(getResultForDataTypeIfPresent(mLogger, DATA_TYPE_2)).isEqualTo(Optional.empty()); 176 } 177 178 @Test testLogBackupMetadata_repeatedCalls_recordsLatestMetadataHash()179 public void testLogBackupMetadata_repeatedCalls_recordsLatestMetadataHash() { 180 mLogger = new BackupRestoreEventLogger(BACKUP); 181 182 mLogger.logBackupMetadata(DATA_TYPE_1, METADATA_1); 183 mLogger.logBackupMetadata(DATA_TYPE_1, METADATA_2); 184 185 byte[] recordedHash = getResultForDataType(mLogger, DATA_TYPE_1).getMetadataHash(); 186 byte[] expectedHash = getMetaDataHash(METADATA_2); 187 assertThat(Arrays.equals(recordedHash, expectedHash)).isTrue(); 188 } 189 190 @Test testLogRestoreMetadata_repeatedCalls_recordsLatestMetadataHash()191 public void testLogRestoreMetadata_repeatedCalls_recordsLatestMetadataHash() { 192 mLogger = new BackupRestoreEventLogger(RESTORE); 193 194 mLogger.logRestoreMetadata(DATA_TYPE_1, METADATA_1); 195 mLogger.logRestoreMetadata(DATA_TYPE_1, METADATA_2); 196 197 byte[] recordedHash = getResultForDataType(mLogger, DATA_TYPE_1).getMetadataHash(); 198 byte[] expectedHash = getMetaDataHash(METADATA_2); 199 assertThat(Arrays.equals(recordedHash, expectedHash)).isTrue(); 200 } 201 202 @Test testLogItemsBackedUp_repeatedCalls_recordsTotalItems()203 public void testLogItemsBackedUp_repeatedCalls_recordsTotalItems() { 204 mLogger = new BackupRestoreEventLogger(BACKUP); 205 206 int firstCount = 10; 207 int secondCount = 5; 208 mLogger.logItemsBackedUp(DATA_TYPE_1, firstCount); 209 mLogger.logItemsBackedUp(DATA_TYPE_1, secondCount); 210 211 int dataTypeCount = getResultForDataType(mLogger, DATA_TYPE_1).getSuccessCount(); 212 assertThat(dataTypeCount).isEqualTo(firstCount + secondCount); 213 } 214 215 @Test testLogItemsRestored_repeatedCalls_recordsTotalItems()216 public void testLogItemsRestored_repeatedCalls_recordsTotalItems() { 217 mLogger = new BackupRestoreEventLogger(RESTORE); 218 219 int firstCount = 10; 220 int secondCount = 5; 221 mLogger.logItemsRestored(DATA_TYPE_1, firstCount); 222 mLogger.logItemsRestored(DATA_TYPE_1, secondCount); 223 224 int dataTypeCount = getResultForDataType(mLogger, DATA_TYPE_1).getSuccessCount(); 225 assertThat(dataTypeCount).isEqualTo(firstCount + secondCount); 226 } 227 228 @Test testLogItemsBackedUp_multipleDataTypes_recordsEachDataType()229 public void testLogItemsBackedUp_multipleDataTypes_recordsEachDataType() { 230 mLogger = new BackupRestoreEventLogger(BACKUP); 231 232 int firstCount = 10; 233 int secondCount = 5; 234 mLogger.logItemsBackedUp(DATA_TYPE_1, firstCount); 235 mLogger.logItemsBackedUp(DATA_TYPE_2, secondCount); 236 237 int firstDataTypeCount = getResultForDataType(mLogger, DATA_TYPE_1).getSuccessCount(); 238 int secondDataTypeCount = getResultForDataType(mLogger, DATA_TYPE_2).getSuccessCount(); 239 assertThat(firstDataTypeCount).isEqualTo(firstCount); 240 assertThat(secondDataTypeCount).isEqualTo(secondCount); 241 } 242 243 @Test testLogItemsRestored_multipleDataTypes_recordsEachDataType()244 public void testLogItemsRestored_multipleDataTypes_recordsEachDataType() { 245 mLogger = new BackupRestoreEventLogger(RESTORE); 246 247 int firstCount = 10; 248 int secondCount = 5; 249 mLogger.logItemsRestored(DATA_TYPE_1, firstCount); 250 mLogger.logItemsRestored(DATA_TYPE_2, secondCount); 251 252 int firstDataTypeCount = getResultForDataType(mLogger, DATA_TYPE_1).getSuccessCount(); 253 int secondDataTypeCount = getResultForDataType(mLogger, DATA_TYPE_2).getSuccessCount(); 254 assertThat(firstDataTypeCount).isEqualTo(firstCount); 255 assertThat(secondDataTypeCount).isEqualTo(secondCount); 256 } 257 258 @Test testLogItemsBackupFailed_repeatedCalls_recordsTotalItems()259 public void testLogItemsBackupFailed_repeatedCalls_recordsTotalItems() { 260 mLogger = new BackupRestoreEventLogger(BACKUP); 261 262 int firstCount = 10; 263 int secondCount = 5; 264 mLogger.logItemsBackupFailed(DATA_TYPE_1, firstCount, /* error */ null); 265 mLogger.logItemsBackupFailed(DATA_TYPE_1, secondCount, "error"); 266 267 int dataTypeCount = getResultForDataType(mLogger, DATA_TYPE_1).getFailCount(); 268 assertThat(dataTypeCount).isEqualTo(firstCount + secondCount); 269 } 270 271 @Test testLogItemsRestoreFailed_repeatedCalls_recordsTotalItems()272 public void testLogItemsRestoreFailed_repeatedCalls_recordsTotalItems() { 273 mLogger = new BackupRestoreEventLogger(RESTORE); 274 275 int firstCount = 10; 276 int secondCount = 5; 277 mLogger.logItemsRestoreFailed(DATA_TYPE_1, firstCount, /* error */ null); 278 mLogger.logItemsRestoreFailed(DATA_TYPE_1, secondCount, "error"); 279 280 int dataTypeCount = getResultForDataType(mLogger, DATA_TYPE_1).getFailCount(); 281 assertThat(dataTypeCount).isEqualTo(firstCount + secondCount); 282 } 283 284 @Test testLogItemsBackupFailed_multipleErrors_recordsEachError()285 public void testLogItemsBackupFailed_multipleErrors_recordsEachError() { 286 mLogger = new BackupRestoreEventLogger(BACKUP); 287 288 int firstCount = 10; 289 int secondCount = 5; 290 mLogger.logItemsBackupFailed(DATA_TYPE_1, firstCount, ERROR_1); 291 mLogger.logItemsBackupFailed(DATA_TYPE_1, secondCount, ERROR_2); 292 293 int firstErrorTypeCount = 294 getResultForDataType(mLogger, DATA_TYPE_1).getErrors().get(ERROR_1); 295 int secondErrorTypeCount = 296 getResultForDataType(mLogger, DATA_TYPE_1).getErrors().get(ERROR_2); 297 assertThat(firstErrorTypeCount).isEqualTo(firstCount); 298 assertThat(secondErrorTypeCount).isEqualTo(secondCount); 299 } 300 301 @Test testLogItemsRestoreFailed_multipleErrors_recordsEachError()302 public void testLogItemsRestoreFailed_multipleErrors_recordsEachError() { 303 mLogger = new BackupRestoreEventLogger(RESTORE); 304 305 int firstCount = 10; 306 int secondCount = 5; 307 mLogger.logItemsRestoreFailed(DATA_TYPE_1, firstCount, ERROR_1); 308 mLogger.logItemsRestoreFailed(DATA_TYPE_1, secondCount, ERROR_2); 309 310 int firstErrorTypeCount = 311 getResultForDataType(mLogger, DATA_TYPE_1).getErrors().get(ERROR_1); 312 int secondErrorTypeCount = 313 getResultForDataType(mLogger, DATA_TYPE_1).getErrors().get(ERROR_2); 314 assertThat(firstErrorTypeCount).isEqualTo(firstCount); 315 assertThat(secondErrorTypeCount).isEqualTo(secondCount); 316 } 317 318 @Test testGetLoggingResults_resultsParceledAndUnparceled_recreatedCorrectly()319 public void testGetLoggingResults_resultsParceledAndUnparceled_recreatedCorrectly() { 320 mLogger = new BackupRestoreEventLogger(RESTORE); 321 int firstTypeSuccessCount = 1; 322 int firstTypeErrorOneCount = 2; 323 int firstTypeErrorTwoCount = 3; 324 mLogger.logItemsRestored(DATA_TYPE_1, firstTypeSuccessCount); 325 mLogger.logItemsRestoreFailed(DATA_TYPE_1, firstTypeErrorOneCount, ERROR_1); 326 mLogger.logItemsRestoreFailed(DATA_TYPE_1, firstTypeErrorTwoCount, ERROR_2); 327 mLogger.logRestoreMetadata(DATA_TYPE_1, METADATA_1); 328 int secondTypeSuccessCount = 4; 329 int secondTypeErrorOneCount = 5; 330 mLogger.logItemsRestored(DATA_TYPE_2, secondTypeSuccessCount); 331 mLogger.logItemsRestoreFailed(DATA_TYPE_2, secondTypeErrorOneCount, ERROR_1); 332 333 List<DataTypeResult> resultsList = mLogger.getLoggingResults(); 334 Parcel parcel = Parcel.obtain(); 335 336 parcel.writeParcelableList(resultsList, /* flags= */ 0); 337 338 parcel.setDataPosition(0); 339 List<DataTypeResult> recreatedList = new ArrayList<>(); 340 parcel.readParcelableList( 341 recreatedList, DataTypeResult.class.getClassLoader(), DataTypeResult.class); 342 343 assertThat(recreatedList.get(0).getDataType()).isEqualTo(DATA_TYPE_1); 344 assertThat(recreatedList.get(0).getSuccessCount()).isEqualTo(firstTypeSuccessCount); 345 assertThat(recreatedList.get(0).getFailCount()) 346 .isEqualTo(firstTypeErrorOneCount + firstTypeErrorTwoCount); 347 assertThat(recreatedList.get(0).getErrors().get(ERROR_1)).isEqualTo(firstTypeErrorOneCount); 348 assertThat(recreatedList.get(0).getErrors().get(ERROR_2)).isEqualTo(firstTypeErrorTwoCount); 349 assertThat(recreatedList.get(1).getDataType()).isEqualTo(DATA_TYPE_2); 350 assertThat(recreatedList.get(1).getSuccessCount()).isEqualTo(secondTypeSuccessCount); 351 assertThat(recreatedList.get(1).getFailCount()).isEqualTo(secondTypeErrorOneCount); 352 assertThat(recreatedList.get(1).getErrors().get(ERROR_1)) 353 .isEqualTo(secondTypeErrorOneCount); 354 } 355 356 @Test testClearData_clearsAllResults()357 public void testClearData_clearsAllResults() { 358 mLogger = new BackupRestoreEventLogger(BACKUP); 359 mLogger.logItemsBackedUp(DATA_TYPE_1, 5); 360 mLogger.logItemsBackedUp(DATA_TYPE_2, 4); 361 mLogger.logItemsBackupFailed(DATA_TYPE_2, 1, ERROR_1); 362 assertThat(mLogger.getLoggingResults()).isNotEmpty(); 363 364 mLogger.clearData(); 365 366 assertThat(mLogger.getLoggingResults()).isEmpty(); 367 } 368 getResultForDataType( BackupRestoreEventLogger logger, String dataType)369 private static DataTypeResult getResultForDataType( 370 BackupRestoreEventLogger logger, String dataType) { 371 Optional<DataTypeResult> result = getResultForDataTypeIfPresent(logger, dataType); 372 if (result.isEmpty()) { 373 fail("Failed to find result for data type: " + dataType); 374 } 375 return result.get(); 376 } 377 getResultForDataTypeIfPresent( BackupRestoreEventLogger logger, String dataType)378 private static Optional<DataTypeResult> getResultForDataTypeIfPresent( 379 BackupRestoreEventLogger logger, String dataType) { 380 List<DataTypeResult> resultList = logger.getLoggingResults(); 381 return resultList.stream() 382 .filter(dataTypeResult -> dataTypeResult.getDataType().equals(dataType)) 383 .findAny(); 384 } 385 getMetaDataHash(String metaData)386 private byte[] getMetaDataHash(String metaData) { 387 return mHashDigest.digest(metaData.getBytes(StandardCharsets.UTF_8)); 388 } 389 } 390