1 /* 2 * Copyright (C) 2023 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 com.android.server.healthconnect.storage.datatypehelpers; 18 19 import static android.health.connect.Constants.DEFAULT_PAGE_SIZE; 20 import static android.health.connect.accesslog.AccessLog.OperationType.OPERATION_TYPE_DELETE; 21 import static android.health.connect.accesslog.AccessLog.OperationType.OPERATION_TYPE_READ; 22 import static android.health.connect.accesslog.AccessLog.OperationType.OPERATION_TYPE_UPSERT; 23 import static android.health.connect.datatypes.FhirResource.FHIR_RESOURCE_TYPE_IMMUNIZATION; 24 import static android.health.connect.datatypes.MedicalResource.MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES; 25 import static android.health.connect.datatypes.MedicalResource.MEDICAL_RESOURCE_TYPE_VACCINES; 26 import static android.healthconnect.cts.phr.utils.PhrDataFactory.DATA_SOURCE_ID; 27 import static android.healthconnect.cts.phr.utils.PhrDataFactory.DATA_SOURCE_PACKAGE_NAME; 28 import static android.healthconnect.cts.phr.utils.PhrDataFactory.DIFFERENT_DATA_SOURCE_ID; 29 import static android.healthconnect.cts.phr.utils.PhrDataFactory.DIFFERENT_DATA_SOURCE_PACKAGE_NAME; 30 import static android.healthconnect.cts.phr.utils.PhrDataFactory.FHIR_RESOURCE_ID_IMMUNIZATION; 31 import static android.healthconnect.cts.phr.utils.PhrDataFactory.FHIR_VERSION_R4; 32 import static android.healthconnect.cts.phr.utils.PhrDataFactory.FHIR_VERSION_R4B; 33 import static android.healthconnect.cts.phr.utils.PhrDataFactory.createAllergyMedicalResource; 34 import static android.healthconnect.cts.phr.utils.PhrDataFactory.createDifferentVaccineMedicalResource; 35 import static android.healthconnect.cts.phr.utils.PhrDataFactory.createUpdatedAllergyMedicalResource; 36 import static android.healthconnect.cts.phr.utils.PhrDataFactory.createUpdatedVaccineMedicalResource; 37 import static android.healthconnect.cts.phr.utils.PhrDataFactory.createVaccineMedicalResource; 38 import static android.healthconnect.cts.phr.utils.PhrDataFactory.createVaccineMedicalResources; 39 import static android.healthconnect.cts.phr.utils.PhrDataFactory.getFhirResource; 40 import static android.healthconnect.cts.phr.utils.PhrDataFactory.getMedicalResourceId; 41 42 import static com.android.server.healthconnect.storage.datatypehelpers.MedicalResourceHelper.DATA_SOURCE_ID_COLUMN_NAME; 43 import static com.android.server.healthconnect.storage.datatypehelpers.MedicalResourceHelper.FHIR_DATA_COLUMN_NAME; 44 import static com.android.server.healthconnect.storage.datatypehelpers.MedicalResourceHelper.FHIR_RESOURCE_ID_COLUMN_NAME; 45 import static com.android.server.healthconnect.storage.datatypehelpers.MedicalResourceHelper.FHIR_RESOURCE_TYPE_COLUMN_NAME; 46 import static com.android.server.healthconnect.storage.datatypehelpers.MedicalResourceHelper.MEDICAL_RESOURCE_TABLE_NAME; 47 import static com.android.server.healthconnect.storage.datatypehelpers.MedicalResourceHelper.getCreateTableRequest; 48 import static com.android.server.healthconnect.storage.datatypehelpers.MedicalResourceHelper.getPrimaryColumn; 49 import static com.android.server.healthconnect.storage.datatypehelpers.MedicalResourceHelper.getReadQueryForMedicalResourceTypeToDataSourceIdsMap; 50 import static com.android.server.healthconnect.storage.datatypehelpers.MedicalResourceIndicesHelper.getMedicalResourceTypeColumnName; 51 import static com.android.server.healthconnect.storage.datatypehelpers.MedicalResourceIndicesHelper.getParentColumnReference; 52 import static com.android.server.healthconnect.storage.datatypehelpers.MedicalResourceIndicesHelper.getTableName; 53 import static com.android.server.healthconnect.storage.datatypehelpers.RecordHelper.LAST_MODIFIED_TIME_COLUMN_NAME; 54 import static com.android.server.healthconnect.storage.utils.StorageUtils.INTEGER_NOT_NULL; 55 import static com.android.server.healthconnect.storage.utils.StorageUtils.PRIMARY_AUTOINCREMENT; 56 import static com.android.server.healthconnect.storage.utils.StorageUtils.TEXT_NOT_NULL; 57 import static com.android.server.healthconnect.storage.utils.StorageUtils.generateMedicalResourceUUID; 58 import static com.android.server.healthconnect.storage.utils.StorageUtils.getCursorInt; 59 import static com.android.server.healthconnect.storage.utils.StorageUtils.getHexString; 60 import static com.android.server.healthconnect.testing.storage.PhrTestUtils.ACCESS_LOG_EQUIVALENCE; 61 import static com.android.server.healthconnect.testing.storage.PhrTestUtils.makeUpsertRequest; 62 63 import static com.google.common.truth.Truth.assertThat; 64 65 import static org.junit.Assert.assertThrows; 66 import static org.mockito.Mockito.mock; 67 68 import android.content.ContentValues; 69 import android.content.Context; 70 import android.database.Cursor; 71 import android.health.connect.DeleteMedicalResourcesRequest; 72 import android.health.connect.MedicalResourceId; 73 import android.health.connect.ReadMedicalResourcesInitialRequest; 74 import android.health.connect.ReadMedicalResourcesPageRequest; 75 import android.health.connect.accesslog.AccessLog; 76 import android.health.connect.datatypes.FhirResource; 77 import android.health.connect.datatypes.MedicalDataSource; 78 import android.health.connect.datatypes.MedicalResource; 79 import android.healthconnect.cts.phr.utils.PhrDataFactory; 80 import android.os.UserHandle; 81 import android.platform.test.annotations.EnableFlags; 82 import android.platform.test.flag.junit.SetFlagsRule; 83 import android.util.Pair; 84 85 import androidx.test.core.app.ApplicationProvider; 86 import androidx.test.ext.junit.runners.AndroidJUnit4; 87 88 import com.android.healthfitness.flags.Flags; 89 import com.android.server.healthconnect.injector.HealthConnectInjector; 90 import com.android.server.healthconnect.injector.HealthConnectInjectorImpl; 91 import com.android.server.healthconnect.permission.FirstGrantTimeManager; 92 import com.android.server.healthconnect.permission.HealthPermissionIntentAppsTracker; 93 import com.android.server.healthconnect.phr.PhrPageTokenWrapper; 94 import com.android.server.healthconnect.phr.ReadMedicalResourcesInternalResponse; 95 import com.android.server.healthconnect.storage.TransactionManager; 96 import com.android.server.healthconnect.storage.request.CreateTableRequest; 97 import com.android.server.healthconnect.storage.request.ReadTableRequest; 98 import com.android.server.healthconnect.storage.request.UpsertMedicalResourceInternalRequest; 99 import com.android.server.healthconnect.storage.utils.StorageUtils; 100 import com.android.server.healthconnect.testing.fakes.FakeTimeSource; 101 import com.android.server.healthconnect.testing.storage.PhrTestUtils; 102 import com.android.server.healthconnect.testing.storage.TransactionTestUtils; 103 104 import org.json.JSONException; 105 import org.junit.Before; 106 import org.junit.Rule; 107 import org.junit.Test; 108 import org.junit.rules.TemporaryFolder; 109 import org.junit.runner.RunWith; 110 import org.mockito.Mock; 111 import org.mockito.junit.MockitoJUnit; 112 import org.mockito.junit.MockitoRule; 113 114 import java.time.Instant; 115 import java.util.ArrayList; 116 import java.util.Collection; 117 import java.util.Collections; 118 import java.util.Comparator; 119 import java.util.HashSet; 120 import java.util.List; 121 import java.util.Map; 122 import java.util.Set; 123 import java.util.UUID; 124 import java.util.stream.Collectors; 125 import java.util.stream.Stream; 126 127 @RunWith(AndroidJUnit4.class) 128 public class MedicalResourceHelperTest { 129 130 @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); 131 @Rule public final TemporaryFolder mEnvironmentDataDir = new TemporaryFolder(); 132 @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); 133 134 private static final long DATA_SOURCE_ROW_ID = 1234; 135 private static final String INVALID_PAGE_TOKEN = "aw=="; 136 private static final Instant INSTANT_NOW = Instant.now(); 137 138 @Mock private AppOpLogsHelper mAppOpLogsHelper; 139 140 private MedicalResourceHelper mMedicalResourceHelper; 141 private TransactionManager mTransactionManager; 142 private AccessLogsHelper mAccessLogsHelper; 143 private PhrTestUtils mUtil; 144 private FakeTimeSource mFakeTimeSource; 145 private UserHandle mUserHandle; 146 147 @Before setup()148 public void setup() { 149 Context context = ApplicationProvider.getApplicationContext(); 150 mFakeTimeSource = new FakeTimeSource(INSTANT_NOW); 151 HealthConnectInjector healthConnectInjector = 152 HealthConnectInjectorImpl.newBuilderForTest(context) 153 .setFirstGrantTimeManager(mock(FirstGrantTimeManager.class)) 154 .setHealthPermissionIntentAppsTracker( 155 mock(HealthPermissionIntentAppsTracker.class)) 156 .setAppOpLogsHelper(mAppOpLogsHelper) 157 .setTimeSource(mFakeTimeSource) 158 .setEnvironmentDataDirectory(mEnvironmentDataDir.getRoot()) 159 .build(); 160 mTransactionManager = healthConnectInjector.getTransactionManager(); 161 mAccessLogsHelper = healthConnectInjector.getAccessLogsHelper(); 162 mMedicalResourceHelper = healthConnectInjector.getMedicalResourceHelper(); 163 mUtil = new PhrTestUtils(healthConnectInjector); 164 mUserHandle = context.getUser(); 165 166 TransactionTestUtils transactionTestUtils = new TransactionTestUtils(healthConnectInjector); 167 transactionTestUtils.insertApp(DATA_SOURCE_PACKAGE_NAME); 168 transactionTestUtils.insertApp(DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 169 } 170 171 @Test getCreateTableRequest_correctResult()172 public void getCreateTableRequest_correctResult() { 173 List<Pair<String, String>> columnInfoMedicalResource = 174 List.of( 175 Pair.create(getPrimaryColumn(), PRIMARY_AUTOINCREMENT), 176 Pair.create(FHIR_RESOURCE_TYPE_COLUMN_NAME, INTEGER_NOT_NULL), 177 Pair.create(FHIR_RESOURCE_ID_COLUMN_NAME, TEXT_NOT_NULL), 178 Pair.create(FHIR_DATA_COLUMN_NAME, TEXT_NOT_NULL), 179 Pair.create(DATA_SOURCE_ID_COLUMN_NAME, INTEGER_NOT_NULL), 180 Pair.create(LAST_MODIFIED_TIME_COLUMN_NAME, INTEGER_NOT_NULL)); 181 List<Pair<String, String>> columnInfoMedicalResourceIndices = 182 List.of( 183 Pair.create(getParentColumnReference(), INTEGER_NOT_NULL), 184 Pair.create(getMedicalResourceTypeColumnName(), INTEGER_NOT_NULL)); 185 CreateTableRequest childTableRequest = 186 new CreateTableRequest(getTableName(), columnInfoMedicalResourceIndices) 187 .addForeignKey( 188 MEDICAL_RESOURCE_TABLE_NAME, 189 Collections.singletonList(getParentColumnReference()), 190 Collections.singletonList(getPrimaryColumn())); 191 CreateTableRequest expected = 192 new CreateTableRequest(MEDICAL_RESOURCE_TABLE_NAME, columnInfoMedicalResource) 193 .addForeignKey( 194 MedicalDataSourceHelper.getMainTableName(), 195 Collections.singletonList(DATA_SOURCE_ID_COLUMN_NAME), 196 Collections.singletonList( 197 MedicalDataSourceHelper.getPrimaryColumnName())) 198 .createIndexOn(LAST_MODIFIED_TIME_COLUMN_NAME) 199 .setChildTableRequests(List.of(childTableRequest)); 200 201 CreateTableRequest result = getCreateTableRequest(); 202 assertThat(result).isEqualTo(expected); 203 } 204 205 @Test getUpsertContentValues_correctResult()206 public void getUpsertContentValues_correctResult() { 207 FhirResource fhirResource = getFhirResource(); 208 UpsertMedicalResourceInternalRequest upsertMedicalResourceInternalRequest = 209 makeUpsertRequest( 210 fhirResource, 211 MEDICAL_RESOURCE_TYPE_VACCINES, 212 FHIR_VERSION_R4, 213 DATA_SOURCE_ID); 214 215 ContentValues contentValues = 216 MedicalResourceHelper.getContentValues( 217 DATA_SOURCE_ROW_ID, upsertMedicalResourceInternalRequest, INSTANT_NOW); 218 219 assertThat(contentValues.size()).isEqualTo(5); 220 assertThat(contentValues.get(FHIR_RESOURCE_TYPE_COLUMN_NAME)) 221 .isEqualTo(fhirResource.getType()); 222 assertThat(contentValues.get(DATA_SOURCE_ID_COLUMN_NAME)).isEqualTo(DATA_SOURCE_ROW_ID); 223 assertThat(contentValues.get(FHIR_DATA_COLUMN_NAME)).isEqualTo(fhirResource.getData()); 224 assertThat(contentValues.get(LAST_MODIFIED_TIME_COLUMN_NAME)) 225 .isEqualTo(INSTANT_NOW.toEpochMilli()); 226 } 227 228 @Test getReadTableRequest_distinctResourceTypesUsingAppIdAndDataSourceIds_correctQuery()229 public void getReadTableRequest_distinctResourceTypesUsingAppIdAndDataSourceIds_correctQuery() { 230 List<UUID> dataSourceIds = List.of(UUID.fromString("a6194e35-698c-4706-918f-00bf959f123b")); 231 long appId = 123L; 232 List<String> hexValues = StorageUtils.getListOfHexStrings(dataSourceIds); 233 234 ReadTableRequest request = 235 MedicalResourceHelper.getFilteredReadRequestForDistinctResourceTypes( 236 dataSourceIds, new HashSet<>(), appId); 237 238 assertThat(request.getReadCommand()) 239 .isEqualTo( 240 "SELECT DISTINCT medical_resource_type FROM ( SELECT * FROM" 241 + " medical_resource_table ) AS inner_query_result" 242 + " INNER JOIN ( SELECT" 243 + " * FROM medical_data_source_table WHERE app_info_id = '" 244 + appId 245 + "'" 246 + " AND data_source_uuid IN (" 247 + String.join(", ", hexValues) 248 + ")) medical_data_source_table ON" 249 + " inner_query_result.data_source_id =" 250 + " medical_data_source_table.medical_data_source_row_id" 251 + " INNER JOIN ( SELECT * FROM medical_resource_indices_table)" 252 + " medical_resource_indices_table ON" 253 + " inner_query_result.medical_resource_row_id =" 254 + " medical_resource_indices_table.medical_resource_id"); 255 } 256 257 @Test getReadTableRequest_distinctResourceTypesUsingAppIdAndResourceTypes_correctQuery()258 public void getReadTableRequest_distinctResourceTypesUsingAppIdAndResourceTypes_correctQuery() { 259 long appId = 123L; 260 261 ReadTableRequest request = 262 MedicalResourceHelper.getFilteredReadRequestForDistinctResourceTypes( 263 List.of(), Set.of(MEDICAL_RESOURCE_TYPE_VACCINES), appId); 264 265 assertThat(request.getReadCommand()) 266 .isEqualTo( 267 "SELECT DISTINCT medical_resource_type FROM ( SELECT * FROM" 268 + " medical_resource_table ) AS inner_query_result" 269 + " INNER JOIN ( SELECT" 270 + " * FROM medical_data_source_table WHERE app_info_id = '" 271 + appId 272 + "'" 273 + ") medical_data_source_table ON" 274 + " inner_query_result.data_source_id =" 275 + " medical_data_source_table.medical_data_source_row_id" 276 + " INNER JOIN ( SELECT * FROM medical_resource_indices_table" 277 + " WHERE medical_resource_type IN (1))" 278 + " medical_resource_indices_table ON" 279 + " inner_query_result.medical_resource_row_id =" 280 + " medical_resource_indices_table.medical_resource_id"); 281 } 282 283 @Test getReadTableRequest_distinctResourceTypesUsingAppIdResourceTypesAndDataSourceIds()284 public void getReadTableRequest_distinctResourceTypesUsingAppIdResourceTypesAndDataSourceIds() { 285 List<UUID> dataSourceIds = List.of(UUID.fromString("a6194e35-698c-4706-918f-00bf959f123b")); 286 long appId = 123L; 287 List<String> hexValues = StorageUtils.getListOfHexStrings(dataSourceIds); 288 289 ReadTableRequest request = 290 MedicalResourceHelper.getFilteredReadRequestForDistinctResourceTypes( 291 dataSourceIds, Set.of(MEDICAL_RESOURCE_TYPE_VACCINES), appId); 292 293 assertThat(request.getReadCommand()) 294 .isEqualTo( 295 "SELECT DISTINCT medical_resource_type FROM ( SELECT * FROM" 296 + " medical_resource_table ) AS inner_query_result" 297 + " INNER JOIN ( SELECT" 298 + " * FROM medical_data_source_table WHERE app_info_id = '" 299 + appId 300 + "'" 301 + " AND data_source_uuid IN (" 302 + String.join(", ", hexValues) 303 + ")) medical_data_source_table ON" 304 + " inner_query_result.data_source_id =" 305 + " medical_data_source_table.medical_data_source_row_id" 306 + " INNER JOIN ( SELECT * FROM medical_resource_indices_table" 307 + " WHERE medical_resource_type IN (1))" 308 + " medical_resource_indices_table ON" 309 + " inner_query_result.medical_resource_row_id =" 310 + " medical_resource_indices_table.medical_resource_id"); 311 } 312 313 @Test 314 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD, Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) insertAndUpdateResource_lastModifiedTimeIsUpdated()315 public void insertAndUpdateResource_lastModifiedTimeIsUpdated() throws JSONException { 316 MedicalDataSource dataSource = 317 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 318 MedicalResource resource = createVaccineMedicalResource(dataSource.getId()); 319 UpsertMedicalResourceInternalRequest insertRequest = makeUpsertRequest(resource); 320 MedicalResource updatedResource = createUpdatedVaccineMedicalResource(dataSource.getId()); 321 UpsertMedicalResourceInternalRequest updateRequest = makeUpsertRequest(updatedResource); 322 323 mMedicalResourceHelper.upsertMedicalResources( 324 DATA_SOURCE_PACKAGE_NAME, List.of(insertRequest)); 325 long lastModifiedTimeOriginal = 326 mUtil.readLastModifiedTimestamp(MEDICAL_RESOURCE_TABLE_NAME); 327 assertThat(lastModifiedTimeOriginal).isEqualTo(INSTANT_NOW.toEpochMilli()); 328 329 Instant upadatedInstant = Instant.now(); 330 mFakeTimeSource.setInstant(upadatedInstant); 331 332 mMedicalResourceHelper.upsertMedicalResources( 333 DATA_SOURCE_PACKAGE_NAME, List.of(updateRequest)); 334 long lastModifiedTimeUpdated = mUtil.readLastModifiedTimestamp(MEDICAL_RESOURCE_TABLE_NAME); 335 336 assertThat(lastModifiedTimeUpdated).isEqualTo(upadatedInstant.toEpochMilli()); 337 } 338 339 @Test 340 @EnableFlags({Flags.FLAG_PHR_READ_MEDICAL_RESOURCES_FIX_QUERY_LIMIT}) getReadTableRequest_usingRequest_correctQuery()341 public void getReadTableRequest_usingRequest_correctQuery() { 342 ReadMedicalResourcesInitialRequest request = 343 new ReadMedicalResourcesInitialRequest.Builder(MEDICAL_RESOURCE_TYPE_VACCINES) 344 .build(); 345 ReadTableRequest readRequest = 346 MedicalResourceHelper.getReadTableRequestUsingRequestFilters( 347 PhrPageTokenWrapper.from(request.toParcel()), request.getPageSize()); 348 349 // TODO(b/352546342): Explore improving the query building logic, so the query below 350 // is simpler to read, for context: http://shortn/_2YCniY49K6 351 assertThat(readRequest.getTableName()).isEqualTo(MEDICAL_RESOURCE_TABLE_NAME); 352 assertThat(readRequest.getReadCommand()) 353 .isEqualTo( 354 "SELECT medical_resource_row_id,fhir_resource_type,fhir_resource_id," 355 + "fhir_data,fhir_version,medical_resource_type," 356 + "data_source_uuid,inner_query_result.last_modified_time" 357 + " AS medical_resource_last_modified_time FROM ( SELECT * FROM" 358 + " medical_resource_table ) AS" 359 + " inner_query_result INNER JOIN ( SELECT * FROM" 360 + " medical_resource_indices_table WHERE medical_resource_type IN " 361 + "(" 362 + MEDICAL_RESOURCE_TYPE_VACCINES 363 + ")" 364 + ") medical_resource_indices_table ON" 365 + " inner_query_result.medical_resource_row_id =" 366 + " medical_resource_indices_table.medical_resource_id INNER JOIN" 367 + " medical_data_source_table ON inner_query_result.data_source_id" 368 + " = medical_data_source_table.medical_data_source_row_id" 369 + " ORDER BY medical_resource_row_id" 370 + " LIMIT " 371 + (DEFAULT_PAGE_SIZE + 1)); 372 } 373 374 @Test 375 @EnableFlags({ 376 Flags.FLAG_PERSONAL_HEALTH_RECORD, 377 Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, 378 Flags.FLAG_PHR_READ_MEDICAL_RESOURCES_FIX_QUERY_LIMIT 379 }) getReadTableRequest_usingRequestWithDataSourceIds_correctQuery()380 public void getReadTableRequest_usingRequestWithDataSourceIds_correctQuery() { 381 MedicalDataSource dataSource1 = 382 mUtil.insertR4MedicalDataSource("id1", DATA_SOURCE_PACKAGE_NAME); 383 MedicalDataSource dataSource2 = 384 mUtil.insertR4MedicalDataSource("id2", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 385 ReadMedicalResourcesInitialRequest request = 386 new ReadMedicalResourcesInitialRequest.Builder(MEDICAL_RESOURCE_TYPE_VACCINES) 387 .addDataSourceId(dataSource1.getId()) 388 .addDataSourceId(dataSource2.getId()) 389 .build(); 390 ReadTableRequest readRequest = 391 MedicalResourceHelper.getReadTableRequestUsingRequestFilters( 392 PhrPageTokenWrapper.from(request.toParcel()), request.getPageSize()); 393 List<String> dataSourceIdHexValues = 394 StorageUtils.toUuids(request.getDataSourceIds()).stream() 395 .map(StorageUtils::getHexString) 396 .toList(); 397 398 assertThat(readRequest.getTableName()).isEqualTo(MEDICAL_RESOURCE_TABLE_NAME); 399 assertThat(readRequest.getReadCommand()) 400 .isEqualTo( 401 "SELECT medical_resource_row_id,fhir_resource_type,fhir_resource_id," 402 + "fhir_data,fhir_version,medical_resource_type,data_source_uuid," 403 + "inner_query_result.last_modified_time" 404 + " AS medical_resource_last_modified_time FROM ( SELECT * FROM" 405 + " medical_resource_table ) AS" 406 + " inner_query_result INNER JOIN ( SELECT * FROM" 407 + " medical_resource_indices_table WHERE medical_resource_type IN " 408 + "(" 409 + MEDICAL_RESOURCE_TYPE_VACCINES 410 + ")) medical_resource_indices_table ON" 411 + " inner_query_result.medical_resource_row_id =" 412 + " medical_resource_indices_table.medical_resource_id INNER JOIN" 413 + " ( SELECT * FROM medical_data_source_table WHERE" 414 + " data_source_uuid IN (" 415 + String.join(", ", dataSourceIdHexValues) 416 + ")) medical_data_source_table ON" 417 + " inner_query_result.data_source_id =" 418 + " medical_data_source_table.medical_data_source_row_id" 419 + " ORDER BY medical_resource_row_id" 420 + " LIMIT " 421 + (DEFAULT_PAGE_SIZE + 1)); 422 } 423 424 @Test getReadQuery_forMedicalResourceTypeToDataSourceIdsMap_correctQuery()425 public void getReadQuery_forMedicalResourceTypeToDataSourceIdsMap_correctQuery() { 426 String readQuery = getReadQueryForMedicalResourceTypeToDataSourceIdsMap(); 427 428 assertThat(readQuery) 429 .isEqualTo( 430 "SELECT medical_resource_type, " 431 + "GROUP_CONCAT(data_source_id, ',') AS data_source_id " 432 + "FROM (" 433 + "SELECT DISTINCT medical_resource_type,data_source_id " 434 + "FROM ( SELECT * FROM medical_resource_table )" 435 + " AS inner_query_result " 436 + " INNER JOIN medical_resource_indices_table" 437 + " ON inner_query_result.medical_resource_row_id" 438 + " = medical_resource_indices_table.medical_resource_id)" 439 + " GROUP BY medical_resource_type"); 440 } 441 442 @Test 443 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD, Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) readMedicalResourcesByIds_dbEmpty_returnsEmpty()444 public void readMedicalResourcesByIds_dbEmpty_returnsEmpty() { 445 List<MedicalResourceId> medicalResourceIds = List.of(getMedicalResourceId()); 446 447 List<MedicalResource> resources = 448 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 449 medicalResourceIds); 450 451 assertThat(resources).isEmpty(); 452 } 453 454 @Test 455 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD, Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) readMedicalResourcesByRequest_dbEmpty_returnsEmpty()456 public void readMedicalResourcesByRequest_dbEmpty_returnsEmpty() { 457 ReadMedicalResourcesInitialRequest request = 458 new ReadMedicalResourcesInitialRequest.Builder(MEDICAL_RESOURCE_TYPE_VACCINES) 459 .build(); 460 461 ReadMedicalResourcesInternalResponse result = 462 mMedicalResourceHelper.readMedicalResourcesByRequestWithoutPermissionChecks( 463 PhrPageTokenWrapper.from(request.toParcel()), request.getPageSize()); 464 465 assertThat(result.getMedicalResources()).isEmpty(); 466 assertThat(result.getPageToken()).isEqualTo(null); 467 assertThat(result.getRemainingCount()).isEqualTo(0); 468 } 469 470 @Test 471 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD, Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) upsertAndReadMedicalResourcesByRequest_MedicalResourceTypeDoesNotExist_success()472 public void upsertAndReadMedicalResourcesByRequest_MedicalResourceTypeDoesNotExist_success() { 473 MedicalDataSource dataSource = 474 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 475 MedicalResource vaccine = createVaccineMedicalResource(dataSource.getId()); 476 477 List<MedicalResource> upsertedResources = 478 mMedicalResourceHelper.upsertMedicalResources( 479 DATA_SOURCE_PACKAGE_NAME, List.of(makeUpsertRequest(vaccine))); 480 ReadMedicalResourcesInitialRequest readAllAllergiesRequest = 481 new ReadMedicalResourcesInitialRequest.Builder( 482 MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES) 483 .build(); 484 ReadMedicalResourcesInternalResponse result = 485 mMedicalResourceHelper.readMedicalResourcesByRequestWithoutPermissionChecks( 486 PhrPageTokenWrapper.from(readAllAllergiesRequest.toParcel()), 487 readAllAllergiesRequest.getPageSize()); 488 489 assertThat(upsertedResources).containsExactly(vaccine); 490 assertThat(result.getMedicalResources()).isEmpty(); 491 assertThat(result.getPageToken()).isEqualTo(null); 492 assertThat(result.getRemainingCount()).isEqualTo(0); 493 } 494 495 @Test 496 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD, Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) upsertMedicalResourcesSameDataSource_readMedicalResourcesByRequest_success()497 public void upsertMedicalResourcesSameDataSource_readMedicalResourcesByRequest_success() { 498 // Upsert 3 resources in this test: vaccine, differentVaccine and allergy, all 499 // with the same data source. 500 MedicalDataSource dataSource = 501 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 502 MedicalResource vaccine = createVaccineMedicalResource(dataSource.getId()); 503 MedicalResource differentVaccine = 504 createDifferentVaccineMedicalResource(dataSource.getId()); 505 MedicalResource allergy = createAllergyMedicalResource(dataSource.getId()); 506 List<MedicalResource> upsertedResources = 507 mMedicalResourceHelper.upsertMedicalResources( 508 DATA_SOURCE_PACKAGE_NAME, 509 List.of( 510 makeUpsertRequest(vaccine), 511 makeUpsertRequest(differentVaccine), 512 makeUpsertRequest(allergy))); 513 514 ReadMedicalResourcesInitialRequest readAllAllergiesRequest = 515 new ReadMedicalResourcesInitialRequest.Builder( 516 MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES) 517 .build(); 518 ReadMedicalResourcesInitialRequest readAllVaccinesRequest = 519 new ReadMedicalResourcesInitialRequest.Builder(MEDICAL_RESOURCE_TYPE_VACCINES) 520 .build(); 521 ReadMedicalResourcesInitialRequest readVaccinesFromSameDataSourceRequest = 522 new ReadMedicalResourcesInitialRequest.Builder(MEDICAL_RESOURCE_TYPE_VACCINES) 523 .addDataSourceId(dataSource.getId()) 524 .build(); 525 ReadMedicalResourcesInitialRequest readVaccinesFromDifferentDataSourceRequest = 526 new ReadMedicalResourcesInitialRequest.Builder(MEDICAL_RESOURCE_TYPE_VACCINES) 527 .addDataSourceId(DIFFERENT_DATA_SOURCE_ID) 528 .build(); 529 ReadMedicalResourcesInternalResponse allAllergiesResult = 530 mMedicalResourceHelper.readMedicalResourcesByRequestWithoutPermissionChecks( 531 PhrPageTokenWrapper.from(readAllAllergiesRequest.toParcel()), 532 readAllAllergiesRequest.getPageSize()); 533 ReadMedicalResourcesInternalResponse allVaccinesResult = 534 mMedicalResourceHelper.readMedicalResourcesByRequestWithoutPermissionChecks( 535 PhrPageTokenWrapper.from(readAllVaccinesRequest.toParcel()), 536 readAllVaccinesRequest.getPageSize()); 537 ReadMedicalResourcesInternalResponse vaccinesFromSameDataSourceResult = 538 mMedicalResourceHelper.readMedicalResourcesByRequestWithoutPermissionChecks( 539 PhrPageTokenWrapper.from(readVaccinesFromSameDataSourceRequest.toParcel()), 540 readVaccinesFromSameDataSourceRequest.getPageSize()); 541 ReadMedicalResourcesInternalResponse vaccinesFromDifferentDataSourceResult = 542 mMedicalResourceHelper.readMedicalResourcesByRequestWithoutPermissionChecks( 543 PhrPageTokenWrapper.from( 544 readVaccinesFromDifferentDataSourceRequest.toParcel()), 545 readVaccinesFromDifferentDataSourceRequest.getPageSize()); 546 547 assertThat(upsertedResources).containsExactly(vaccine, differentVaccine, allergy); 548 assertThat(allAllergiesResult.getMedicalResources()).containsExactly(allergy); 549 assertThat(allAllergiesResult.getPageToken()).isEqualTo(null); 550 assertThat(allAllergiesResult.getRemainingCount()).isEqualTo(0); 551 assertThat(allVaccinesResult.getMedicalResources()) 552 .containsExactly(vaccine, differentVaccine); 553 assertThat(allVaccinesResult.getPageToken()).isEqualTo(null); 554 assertThat(allVaccinesResult.getRemainingCount()).isEqualTo(0); 555 assertThat(vaccinesFromSameDataSourceResult.getMedicalResources()) 556 .containsExactly(vaccine, differentVaccine); 557 assertThat(vaccinesFromSameDataSourceResult.getPageToken()).isEqualTo(null); 558 assertThat(vaccinesFromDifferentDataSourceResult.getMedicalResources()).isEmpty(); 559 assertThat(vaccinesFromDifferentDataSourceResult.getPageToken()).isEqualTo(null); 560 assertThat(vaccinesFromDifferentDataSourceResult.getRemainingCount()).isEqualTo(0); 561 } 562 563 @Test 564 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD, Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) upsertMedicalResourcesDifferentDataSources_readMedicalResourcesByRequest_success()565 public void upsertMedicalResourcesDifferentDataSources_readMedicalResourcesByRequest_success() { 566 // Upsert 3 resources in this test: vaccine, differentVaccine and allergy. Among 567 // which vaccine and allergy are from data source 1 and the differentVaccine is 568 // from data source 2. 569 MedicalDataSource dataSource1 = 570 mUtil.insertR4MedicalDataSource("id1", DATA_SOURCE_PACKAGE_NAME); 571 MedicalDataSource dataSource2 = 572 mUtil.insertR4MedicalDataSource("id2", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 573 MedicalResource vaccineDS1 = createVaccineMedicalResource(dataSource1.getId()); 574 MedicalResource differentVaccineDS2 = 575 createDifferentVaccineMedicalResource(dataSource2.getId()); 576 MedicalResource allergyDS1 = createAllergyMedicalResource(dataSource1.getId()); 577 List<MedicalResource> upsertedResources = 578 mMedicalResourceHelper.upsertMedicalResources( 579 DATA_SOURCE_PACKAGE_NAME, 580 List.of(makeUpsertRequest(vaccineDS1), makeUpsertRequest(allergyDS1))); 581 upsertedResources.addAll( 582 mMedicalResourceHelper.upsertMedicalResources( 583 DIFFERENT_DATA_SOURCE_PACKAGE_NAME, 584 List.of(makeUpsertRequest(differentVaccineDS2)))); 585 586 ReadMedicalResourcesInitialRequest readAllAllergiesRequest = 587 new ReadMedicalResourcesInitialRequest.Builder( 588 MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES) 589 .build(); 590 ReadMedicalResourcesInitialRequest readAllVaccinesRequest = 591 new ReadMedicalResourcesInitialRequest.Builder(MEDICAL_RESOURCE_TYPE_VACCINES) 592 .build(); 593 ReadMedicalResourcesInitialRequest readVaccinesFromDataSource1Request = 594 new ReadMedicalResourcesInitialRequest.Builder(MEDICAL_RESOURCE_TYPE_VACCINES) 595 .addDataSourceId(dataSource1.getId()) 596 .build(); 597 ReadMedicalResourcesInitialRequest readVaccinesFromDataSource2Request = 598 new ReadMedicalResourcesInitialRequest.Builder(MEDICAL_RESOURCE_TYPE_VACCINES) 599 .addDataSourceId(dataSource2.getId()) 600 .build(); 601 ReadMedicalResourcesInternalResponse allAllergiesResult = 602 mMedicalResourceHelper.readMedicalResourcesByRequestWithoutPermissionChecks( 603 PhrPageTokenWrapper.from(readAllAllergiesRequest.toParcel()), 604 readAllAllergiesRequest.getPageSize()); 605 ReadMedicalResourcesInternalResponse allVaccinesResult = 606 mMedicalResourceHelper.readMedicalResourcesByRequestWithoutPermissionChecks( 607 PhrPageTokenWrapper.from(readAllVaccinesRequest.toParcel()), 608 readAllVaccinesRequest.getPageSize()); 609 ReadMedicalResourcesInternalResponse vaccinesFromDataSource1Result = 610 mMedicalResourceHelper.readMedicalResourcesByRequestWithoutPermissionChecks( 611 PhrPageTokenWrapper.from(readVaccinesFromDataSource1Request.toParcel()), 612 readVaccinesFromDataSource1Request.getPageSize()); 613 ReadMedicalResourcesInternalResponse vaccinesFromDataSource2Result = 614 mMedicalResourceHelper.readMedicalResourcesByRequestWithoutPermissionChecks( 615 PhrPageTokenWrapper.from(readVaccinesFromDataSource2Request.toParcel()), 616 readVaccinesFromDataSource2Request.getPageSize()); 617 618 assertThat(upsertedResources).containsExactly(vaccineDS1, differentVaccineDS2, allergyDS1); 619 assertThat(allAllergiesResult.getMedicalResources()).containsExactly(allergyDS1); 620 assertThat(allAllergiesResult.getPageToken()).isEqualTo(null); 621 assertThat(allAllergiesResult.getRemainingCount()).isEqualTo(0); 622 assertThat(allVaccinesResult.getMedicalResources()) 623 .containsExactly(vaccineDS1, differentVaccineDS2); 624 assertThat(allVaccinesResult.getPageToken()).isEqualTo(null); 625 assertThat(allVaccinesResult.getRemainingCount()).isEqualTo(0); 626 assertThat(vaccinesFromDataSource1Result.getMedicalResources()).containsExactly(vaccineDS1); 627 assertThat(vaccinesFromDataSource1Result.getPageToken()).isEqualTo(null); 628 assertThat(vaccinesFromDataSource1Result.getRemainingCount()).isEqualTo(0); 629 assertThat(vaccinesFromDataSource2Result.getMedicalResources()) 630 .containsExactly(differentVaccineDS2); 631 assertThat(vaccinesFromDataSource2Result.getPageToken()).isEqualTo(null); 632 assertThat(vaccinesFromDataSource2Result.getRemainingCount()).isEqualTo(0); 633 } 634 635 @Test 636 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD, Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) insertMedicalResources_dataSourceNotInserted_exceptionThrown()637 public void insertMedicalResources_dataSourceNotInserted_exceptionThrown() { 638 FhirResource fhirResource = getFhirResource(); 639 String datasourceId = "acc6c726-b7ea-42f1-a063-e34f5b4e6247"; 640 UpsertMedicalResourceInternalRequest upsertMedicalResourceInternalRequest = 641 makeUpsertRequest( 642 fhirResource, 643 MEDICAL_RESOURCE_TYPE_VACCINES, 644 FHIR_VERSION_R4, 645 datasourceId); 646 647 Throwable thrown = 648 assertThrows( 649 IllegalArgumentException.class, 650 () -> 651 mMedicalResourceHelper.upsertMedicalResources( 652 DATA_SOURCE_PACKAGE_NAME, 653 List.of(upsertMedicalResourceInternalRequest))); 654 assertThat(thrown) 655 .hasMessageThat() 656 .contains( 657 "Invalid data source id: " 658 + upsertMedicalResourceInternalRequest.getDataSourceId()); 659 } 660 661 @Test 662 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD, Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) insertMedicalResources_dataSourceBelongsToDifferentApp_exceptionThrownNoWrite()663 public void insertMedicalResources_dataSourceBelongsToDifferentApp_exceptionThrownNoWrite() { 664 MedicalDataSource ownDataSource = 665 mUtil.insertR4MedicalDataSource("id1", DATA_SOURCE_PACKAGE_NAME); 666 MedicalDataSource differentDataSource = 667 mUtil.insertR4MedicalDataSource("id2", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 668 UpsertMedicalResourceInternalRequest upsertRequestOwnDataSource = 669 makeUpsertRequest( 670 getFhirResource(), 671 MEDICAL_RESOURCE_TYPE_VACCINES, 672 FHIR_VERSION_R4, 673 ownDataSource.getId()); 674 UpsertMedicalResourceInternalRequest upsertRequestDifferentDataSource = 675 makeUpsertRequest( 676 getFhirResource(), 677 MEDICAL_RESOURCE_TYPE_VACCINES, 678 FHIR_VERSION_R4, 679 differentDataSource.getId()); 680 681 Throwable thrown = 682 assertThrows( 683 IllegalArgumentException.class, 684 () -> 685 mMedicalResourceHelper.upsertMedicalResources( 686 DATA_SOURCE_PACKAGE_NAME, 687 List.of( 688 upsertRequestOwnDataSource, 689 upsertRequestDifferentDataSource))); 690 assertThat(thrown) 691 .hasMessageThat() 692 .contains("Invalid data source id: " + differentDataSource.getId()); 693 assertThat(getMedicalResourcesTableRowCount()).isEqualTo(0); 694 } 695 696 @Test 697 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD, Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) upsertMedicalResources_fhirVersionDoesNotMatchDataSource_exceptionThrown()698 public void upsertMedicalResources_fhirVersionDoesNotMatchDataSource_exceptionThrown() { 699 MedicalDataSource dataSource = 700 mUtil.insertR4MedicalDataSource("id1", DATA_SOURCE_PACKAGE_NAME); 701 FhirResource fhirResource = getFhirResource(); 702 UpsertMedicalResourceInternalRequest upsertMedicalResourceInternalRequest = 703 makeUpsertRequest( 704 fhirResource, 705 MEDICAL_RESOURCE_TYPE_VACCINES, 706 FHIR_VERSION_R4B, 707 dataSource.getId()); 708 709 Throwable thrown = 710 assertThrows( 711 IllegalArgumentException.class, 712 () -> 713 mMedicalResourceHelper.upsertMedicalResources( 714 DATA_SOURCE_PACKAGE_NAME, 715 List.of(upsertMedicalResourceInternalRequest))); 716 assertThat(thrown) 717 .hasMessageThat() 718 .contains( 719 String.format( 720 "Invalid fhir version: %s. It did not match the data source's fhir" 721 + " version", 722 FHIR_VERSION_R4B)); 723 } 724 725 @Test 726 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD, Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) readSubsetOfResourcesByIds_multipleResourcesUpserted_success()727 public void readSubsetOfResourcesByIds_multipleResourcesUpserted_success() { 728 MedicalDataSource dataSource = 729 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 730 MedicalResource resource1 = createVaccineMedicalResource(dataSource.getId()); 731 MedicalResource resource2 = createAllergyMedicalResource(dataSource.getId()); 732 List<MedicalResource> upsertedMedicalResources = 733 mMedicalResourceHelper.upsertMedicalResources( 734 DATA_SOURCE_PACKAGE_NAME, 735 List.of(makeUpsertRequest(resource1), makeUpsertRequest(resource2))); 736 List<MedicalResource> readResource1Result = 737 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 738 List.of(resource1.getId())); 739 List<Integer> indicesResult = readEntriesInMedicalResourceIndicesTable(); 740 741 assertThat(upsertedMedicalResources).containsExactly(resource1, resource2); 742 assertThat(indicesResult) 743 .containsExactly( 744 MEDICAL_RESOURCE_TYPE_VACCINES, 745 MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES); 746 assertThat(readResource1Result).containsExactly(resource1); 747 } 748 749 @Test 750 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD, Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) insertMedicalResources_returnsMedicalResources()751 public void insertMedicalResources_returnsMedicalResources() { 752 MedicalDataSource dataSource = 753 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 754 MedicalResource expectedResource = createVaccineMedicalResource(dataSource.getId()); 755 UpsertMedicalResourceInternalRequest upsertMedicalResourceInternalRequest = 756 makeUpsertRequest(expectedResource); 757 758 List<MedicalResource> result = 759 mMedicalResourceHelper.upsertMedicalResources( 760 DATA_SOURCE_PACKAGE_NAME, List.of(upsertMedicalResourceInternalRequest)); 761 762 assertThat(result).containsExactly(expectedResource); 763 } 764 765 @Test 766 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD, Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) insertSingleMedicalResource_readSingleResource()767 public void insertSingleMedicalResource_readSingleResource() { 768 MedicalDataSource dataSource = 769 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 770 MedicalResource expectedResource = createVaccineMedicalResource(dataSource.getId()); 771 UpsertMedicalResourceInternalRequest upsertMedicalResourceInternalRequest = 772 makeUpsertRequest(expectedResource); 773 List<MedicalResourceId> ids = List.of(expectedResource.getId()); 774 775 List<MedicalResource> upsertedMedicalResources = 776 mMedicalResourceHelper.upsertMedicalResources( 777 DATA_SOURCE_PACKAGE_NAME, List.of(upsertMedicalResourceInternalRequest)); 778 List<MedicalResource> result = 779 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks(ids); 780 List<Integer> indicesResult = readEntriesInMedicalResourceIndicesTable(); 781 782 assertThat(result).isEqualTo(upsertedMedicalResources); 783 assertThat(result).containsExactly(expectedResource); 784 assertThat(indicesResult).containsExactly(MEDICAL_RESOURCE_TYPE_VACCINES); 785 } 786 787 @Test 788 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) readById_noReadOrWritePermissions_throws()789 public void readById_noReadOrWritePermissions_throws() { 790 assertThrows( 791 IllegalStateException.class, 792 () -> 793 mMedicalResourceHelper.readMedicalResourcesByIdsWithPermissionChecks( 794 List.of(), 795 /* grantedReadMedicalResourceTypes= */ Set.of(), 796 DATA_SOURCE_PACKAGE_NAME, 797 /* hasWritePermission= */ false, 798 /* isCalledFromBgWithoutBgRead= */ false)); 799 } 800 801 @Test 802 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) readById_inBgWithoutBgPerm_hasWritePerm_noAccessLog()803 public void readById_inBgWithoutBgPerm_hasWritePerm_noAccessLog() { 804 List<MedicalResourceId> ids = List.of(getMedicalResourceId()); 805 mMedicalResourceHelper.readMedicalResourcesByIdsWithPermissionChecks( 806 ids, 807 Set.of(), 808 DATA_SOURCE_PACKAGE_NAME, 809 /* hasWritePermission= */ true, 810 /* isCalledFromBgWithoutBgRead= */ true); 811 812 assertThat(mAccessLogsHelper.queryAccessLogs(mUserHandle)).isEmpty(); 813 } 814 815 @Test 816 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) readById_inBgWithoutBgPerm_hasWritePerm_hasReadPermForResourceTypes_noAccessLog()817 public void readById_inBgWithoutBgPerm_hasWritePerm_hasReadPermForResourceTypes_noAccessLog() { 818 List<MedicalResourceId> ids = List.of(getMedicalResourceId()); 819 mMedicalResourceHelper.readMedicalResourcesByIdsWithPermissionChecks( 820 ids, 821 Set.of(MEDICAL_RESOURCE_TYPE_VACCINES), 822 DATA_SOURCE_PACKAGE_NAME, 823 /* hasWritePermission= */ true, 824 /* isCalledFromBgWithoutBgRead= */ true); 825 826 assertThat(mAccessLogsHelper.queryAccessLogs(mUserHandle)).isEmpty(); 827 } 828 829 @Test 830 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) readById_inBgWithoutBgPerm_noWritePerm_vaccineReadPermOnly_noAccessLog()831 public void readById_inBgWithoutBgPerm_noWritePerm_vaccineReadPermOnly_noAccessLog() { 832 List<MedicalResourceId> ids = List.of(getMedicalResourceId()); 833 mMedicalResourceHelper.readMedicalResourcesByIdsWithPermissionChecks( 834 ids, 835 Set.of(MEDICAL_RESOURCE_TYPE_VACCINES), 836 DATA_SOURCE_PACKAGE_NAME, 837 /* hasWritePermission= */ false, 838 /* isCalledFromBgWithoutBgRead= */ true); 839 840 assertThat(mAccessLogsHelper.queryAccessLogs(mUserHandle)).isEmpty(); 841 } 842 843 @Test 844 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) readById_expectAccessLogsOnlyContainsNonSelfRead()845 public void readById_expectAccessLogsOnlyContainsNonSelfRead() { 846 MedicalDataSource dataSource1 = 847 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 848 MedicalDataSource dataSource2 = 849 mUtil.insertR4MedicalDataSource("ds", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 850 MedicalResource vaccinePackage1 = createVaccineMedicalResource(dataSource1.getId()); 851 MedicalResource vaccinePackage2 = createVaccineMedicalResource(dataSource2.getId()); 852 MedicalResource allergyResourcePackage2 = createAllergyMedicalResource(dataSource2.getId()); 853 mMedicalResourceHelper.upsertMedicalResources( 854 DATA_SOURCE_PACKAGE_NAME, List.of(makeUpsertRequest(vaccinePackage1))); 855 mMedicalResourceHelper.upsertMedicalResources( 856 DIFFERENT_DATA_SOURCE_PACKAGE_NAME, 857 List.of( 858 makeUpsertRequest(vaccinePackage2), 859 makeUpsertRequest(allergyResourcePackage2))); 860 // Clear access logs table, so that only the access logs from read will be present 861 mAccessLogsHelper.clearData(mTransactionManager); 862 863 mMedicalResourceHelper.readMedicalResourcesByIdsWithPermissionChecks( 864 List.of( 865 vaccinePackage1.getId(), 866 vaccinePackage2.getId(), 867 allergyResourcePackage2.getId()), 868 Set.of(MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES), 869 DATA_SOURCE_PACKAGE_NAME, 870 /* hasWritePermission= */ true, 871 /* isCalledFromBgWithoutBgRead= */ false); 872 873 // Testing the case where calling app: 874 // is calling from foreground or background with permission. 875 // has MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES read permission. 876 // has write permission. 877 // The data that the calling app can read: vaccinePackage1 (through selfRead) 878 // allergyResourcePackage2 (through read permission) 879 // In this case, read access log is only created for non self read data: 880 // MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES. 881 AccessLog expected = 882 new AccessLog( 883 DATA_SOURCE_PACKAGE_NAME, 884 INSTANT_NOW.toEpochMilli(), 885 OPERATION_TYPE_READ, 886 /* medicalResourceTypes= */ Set.of( 887 MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES), 888 /* isMedicalDataSourceAccessed= */ false); 889 assertThat(mAccessLogsHelper.queryAccessLogs(mUserHandle)) 890 .comparingElementsUsing(ACCESS_LOG_EQUIVALENCE) 891 .containsExactly(expected); 892 } 893 894 @Test 895 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) readById_expectAccessLogsWhenAppHasNoWritePermHasReadPermButReadOnlySelfData()896 public void readById_expectAccessLogsWhenAppHasNoWritePermHasReadPermButReadOnlySelfData() { 897 MedicalDataSource dataSource1 = 898 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 899 MedicalDataSource dataSource2 = 900 mUtil.insertR4MedicalDataSource("ds", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 901 MedicalResource vaccinePackage1 = createVaccineMedicalResource(dataSource1.getId()); 902 MedicalResource allergyResourcePackage2 = createAllergyMedicalResource(dataSource2.getId()); 903 mMedicalResourceHelper.upsertMedicalResources( 904 DATA_SOURCE_PACKAGE_NAME, List.of(makeUpsertRequest(vaccinePackage1))); 905 mMedicalResourceHelper.upsertMedicalResources( 906 DIFFERENT_DATA_SOURCE_PACKAGE_NAME, 907 List.of(makeUpsertRequest(allergyResourcePackage2))); 908 // Clear access logs table, so that only the access logs from read will be present 909 mAccessLogsHelper.clearData(mTransactionManager); 910 911 mMedicalResourceHelper.readMedicalResourcesByIdsWithPermissionChecks( 912 List.of(vaccinePackage1.getId(), allergyResourcePackage2.getId()), 913 Set.of(MEDICAL_RESOURCE_TYPE_VACCINES), 914 DATA_SOURCE_PACKAGE_NAME, 915 /* hasWritePermission= */ false, 916 /* isCalledFromBgWithoutBgRead= */ false); 917 918 // Testing the case where calling app: 919 // is calling from foreground or background with permission. 920 // has MEDICAL_RESOURCE_TYPE_VACCINES read permission. 921 // no write permission. 922 // The data that the calling app can read: vaccinePackage1 (through read permission) 923 // In this case, read access log is created based on the intention of the app 924 // even though the actual data accessed is self data: MEDICAL_RESOURCE_TYPE_VACCINES. 925 AccessLog expected = 926 new AccessLog( 927 DATA_SOURCE_PACKAGE_NAME, 928 INSTANT_NOW.toEpochMilli(), 929 OPERATION_TYPE_READ, 930 /* medicalResourceTypes= */ Set.of(MEDICAL_RESOURCE_TYPE_VACCINES), 931 /* isMedicalDataSourceAccessed= */ false); 932 assertThat(mAccessLogsHelper.queryAccessLogs(mUserHandle)) 933 .comparingElementsUsing(ACCESS_LOG_EQUIVALENCE) 934 .containsExactly(expected); 935 } 936 937 @Test 938 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) readById_expectAccessLogsWhenAppHasNoWritePermHasReadPermReadNonSelfData()939 public void readById_expectAccessLogsWhenAppHasNoWritePermHasReadPermReadNonSelfData() { 940 String dataSource = 941 mUtil.insertR4MedicalDataSource("ds", DIFFERENT_DATA_SOURCE_PACKAGE_NAME).getId(); 942 MedicalResource vaccineDifferentPackage = createVaccineMedicalResource(dataSource); 943 mMedicalResourceHelper.upsertMedicalResources( 944 DIFFERENT_DATA_SOURCE_PACKAGE_NAME, 945 List.of(makeUpsertRequest(vaccineDifferentPackage))); 946 // Clear access logs table, so that only the access logs from read will be present 947 mAccessLogsHelper.clearData(mTransactionManager); 948 949 mMedicalResourceHelper.readMedicalResourcesByIdsWithPermissionChecks( 950 List.of(vaccineDifferentPackage.getId()), 951 Set.of(MEDICAL_RESOURCE_TYPE_VACCINES), 952 DATA_SOURCE_PACKAGE_NAME, 953 /* hasWritePermission= */ false, 954 /* isCalledFromBgWithoutBgRead= */ false); 955 956 // Testing the case where calling app: 957 // is calling from foreground or background with permission. 958 // has MEDICAL_RESOURCE_TYPE_VACCINES read permission. 959 // no write permission. 960 // The data that the calling app can read: vaccine (through read permission) 961 // In this case, read access log is created: MEDICAL_RESOURCE_TYPE_VACCINES. 962 AccessLog expected = 963 new AccessLog( 964 DATA_SOURCE_PACKAGE_NAME, 965 INSTANT_NOW.toEpochMilli(), 966 OPERATION_TYPE_READ, 967 /* medicalResourceTypes= */ Set.of(MEDICAL_RESOURCE_TYPE_VACCINES), 968 /* isMedicalDataSourceAccessed= */ false); 969 assertThat(mAccessLogsHelper.queryAccessLogs(mUserHandle)) 970 .comparingElementsUsing(ACCESS_LOG_EQUIVALENCE) 971 .containsExactly(expected); 972 } 973 974 @Test 975 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) readById_inForegroundOrBgWithPerm_hasReadVaccine_noResourceRead_noAccessLog()976 public void readById_inForegroundOrBgWithPerm_hasReadVaccine_noResourceRead_noAccessLog() { 977 List<MedicalResourceId> ids = List.of(getMedicalResourceId()); 978 mMedicalResourceHelper.readMedicalResourcesByIdsWithPermissionChecks( 979 ids, 980 Set.of(MEDICAL_RESOURCE_TYPE_VACCINES), 981 DATA_SOURCE_PACKAGE_NAME, 982 /* hasWritePermission= */ true, 983 /* isCalledFromBgWithoutBgRead= */ false); 984 985 assertThat(mAccessLogsHelper.queryAccessLogs(mUserHandle)).isEmpty(); 986 } 987 988 @Test 989 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) readById_inForegroundOrBgWithPerm_hasWritePerm_noReadPerm_noAccessLog()990 public void readById_inForegroundOrBgWithPerm_hasWritePerm_noReadPerm_noAccessLog() { 991 List<MedicalResourceId> ids = List.of(getMedicalResourceId()); 992 mMedicalResourceHelper.readMedicalResourcesByIdsWithPermissionChecks( 993 ids, 994 Set.of(), 995 DATA_SOURCE_PACKAGE_NAME, 996 /* hasWritePermission= */ true, 997 /* isCalledFromBgWithoutBgRead= */ false); 998 999 // No access log should be created since app is intending to access self data as it has 1000 // no read permissions. 1001 assertThat(mAccessLogsHelper.queryAccessLogs(mUserHandle)).isEmpty(); 1002 } 1003 1004 @Test 1005 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) readById_expectAccessLogsWhenAppHasWritePermHasReadPermReadSelfData()1006 public void readById_expectAccessLogsWhenAppHasWritePermHasReadPermReadSelfData() { 1007 MedicalDataSource dataSource = 1008 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 1009 MedicalResource vaccine = 1010 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource); 1011 // Clear access logs table, so that only the access logs from read will be present 1012 mAccessLogsHelper.clearData(mTransactionManager); 1013 1014 mMedicalResourceHelper.readMedicalResourcesByIdsWithPermissionChecks( 1015 List.of(vaccine.getId()), 1016 Set.of(MEDICAL_RESOURCE_TYPE_VACCINES), 1017 DATA_SOURCE_PACKAGE_NAME, 1018 /* hasWritePermission= */ true, 1019 /* isCalledFromBgWithoutBgRead= */ false); 1020 1021 // Testing the case where calling app: 1022 // is calling from foreground or background with permission. 1023 // has MEDICAL_RESOURCE_TYPE_VACCINES read permission. 1024 // has write permission. 1025 // The data that the calling app can read: vaccine (through read permission) 1026 // In this case, read access log is created based on the intention of the app 1027 // even though the actual data accessed is self data: MEDICAL_RESOURCE_TYPE_VACCINES. 1028 AccessLog expected = 1029 new AccessLog( 1030 DATA_SOURCE_PACKAGE_NAME, 1031 INSTANT_NOW.toEpochMilli(), 1032 OPERATION_TYPE_READ, 1033 /* medicalResourceTypes= */ Set.of(MEDICAL_RESOURCE_TYPE_VACCINES), 1034 /* isMedicalDataSourceAccessed= */ false); 1035 assertThat(mAccessLogsHelper.queryAccessLogs(mUserHandle)) 1036 .comparingElementsUsing(ACCESS_LOG_EQUIVALENCE) 1037 .containsExactly(expected); 1038 } 1039 1040 @Test 1041 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) readById_expectAccessLogsForEachResourceTypeReadBasedOnReadPerm()1042 public void readById_expectAccessLogsForEachResourceTypeReadBasedOnReadPerm() { 1043 MedicalDataSource dataSource = 1044 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 1045 MedicalResource vaccine = 1046 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource); 1047 // Clear access logs table, so that only the access logs from read will be present 1048 mAccessLogsHelper.clearData(mTransactionManager); 1049 1050 mMedicalResourceHelper.readMedicalResourcesByIdsWithPermissionChecks( 1051 List.of(vaccine.getId()), 1052 Set.of( 1053 MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES, 1054 MEDICAL_RESOURCE_TYPE_VACCINES), 1055 DATA_SOURCE_PACKAGE_NAME, 1056 /* hasWritePermission= */ true, 1057 /* isCalledFromBgWithoutBgRead= */ false); 1058 1059 // Testing the case where calling app: 1060 // is calling from foreground or background with permission. 1061 // has MEDICAL_RESOURCE_TYPE_VACCINES and MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES 1062 // read permission. 1063 // has write permission. 1064 // The data that the calling app reads: vaccine (through read permission) 1065 // In this case, read access log is created only for: MEDICAL_RESOURCE_TYPE_VACCINES. 1066 // Even though the app has read permission for MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES, 1067 // the app did 1068 // not read any data of that type, so no access logs added for that. 1069 AccessLog expected = 1070 new AccessLog( 1071 DATA_SOURCE_PACKAGE_NAME, 1072 INSTANT_NOW.toEpochMilli(), 1073 OPERATION_TYPE_READ, 1074 /* medicalResourceTypes= */ Set.of(MEDICAL_RESOURCE_TYPE_VACCINES), 1075 /* isMedicalDataSourceAccessed= */ false); 1076 assertThat(mAccessLogsHelper.queryAccessLogs(mUserHandle)) 1077 .comparingElementsUsing(ACCESS_LOG_EQUIVALENCE) 1078 .containsExactly(expected); 1079 } 1080 1081 @Test 1082 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) readById_inBgWithoutBgPerm_hasWritePerm_success()1083 public void readById_inBgWithoutBgPerm_hasWritePerm_success() { 1084 MedicalDataSource dataSource1 = 1085 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 1086 MedicalDataSource dataSource2 = 1087 mUtil.insertR4MedicalDataSource("ds", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 1088 MedicalResource vaccineDatasource1 = 1089 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 1090 MedicalResource allergyDatasource1 = 1091 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource1); 1092 MedicalResource vaccineDatasource2 = 1093 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource2); 1094 MedicalResource allergyDatasource2 = 1095 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource2); 1096 List<MedicalResourceId> ids = 1097 List.of( 1098 vaccineDatasource1.getId(), 1099 vaccineDatasource2.getId(), 1100 allergyDatasource1.getId(), 1101 allergyDatasource2.getId()); 1102 1103 List<MedicalResource> result = 1104 mMedicalResourceHelper.readMedicalResourcesByIdsWithPermissionChecks( 1105 ids, 1106 Set.of(), 1107 DATA_SOURCE_PACKAGE_NAME, 1108 /* hasWritePermission= */ true, 1109 /* isCalledFromBgWithoutBgRead= */ true); 1110 1111 assertThat(result).containsExactly(vaccineDatasource1, allergyDatasource1); 1112 } 1113 1114 @Test 1115 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) readById_inBgWithoutBgPerm_hasWritePerm_hasReadPermForResourceTypes_success()1116 public void readById_inBgWithoutBgPerm_hasWritePerm_hasReadPermForResourceTypes_success() { 1117 MedicalDataSource dataSource1 = 1118 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 1119 MedicalDataSource dataSource2 = 1120 mUtil.insertR4MedicalDataSource("ds", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 1121 MedicalResource vaccineDatasource1 = 1122 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 1123 MedicalResource allergyDatasource1 = 1124 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource1); 1125 MedicalResource vaccineDatasource2 = 1126 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource2); 1127 MedicalResource allergyDatasource2 = 1128 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource2); 1129 List<MedicalResourceId> ids = 1130 List.of( 1131 vaccineDatasource1.getId(), 1132 vaccineDatasource2.getId(), 1133 allergyDatasource1.getId(), 1134 allergyDatasource2.getId()); 1135 1136 List<MedicalResource> result = 1137 mMedicalResourceHelper.readMedicalResourcesByIdsWithPermissionChecks( 1138 ids, 1139 Set.of(MEDICAL_RESOURCE_TYPE_VACCINES), 1140 DATA_SOURCE_PACKAGE_NAME, 1141 /* hasWritePermission= */ true, 1142 /* isCalledFromBgWithoutBgRead= */ true); 1143 1144 assertThat(result).containsExactly(vaccineDatasource1, allergyDatasource1); 1145 } 1146 1147 @Test 1148 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) readById_inBgWithoutBgPerm_noWritePerm_vaccineReadPermOnly_success()1149 public void readById_inBgWithoutBgPerm_noWritePerm_vaccineReadPermOnly_success() { 1150 MedicalDataSource dataSource1 = 1151 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 1152 MedicalDataSource dataSource2 = 1153 mUtil.insertR4MedicalDataSource("ds", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 1154 MedicalResource vaccineDatasource1 = 1155 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 1156 MedicalResource allergyDatasource1 = 1157 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource1); 1158 MedicalResource vaccineDatasource2 = 1159 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource2); 1160 MedicalResource allergyDatasource2 = 1161 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource2); 1162 List<MedicalResourceId> ids = 1163 List.of( 1164 vaccineDatasource1.getId(), 1165 vaccineDatasource2.getId(), 1166 allergyDatasource1.getId(), 1167 allergyDatasource2.getId()); 1168 1169 List<MedicalResource> result = 1170 mMedicalResourceHelper.readMedicalResourcesByIdsWithPermissionChecks( 1171 ids, 1172 Set.of(MEDICAL_RESOURCE_TYPE_VACCINES), 1173 DATA_SOURCE_PACKAGE_NAME, 1174 /* hasWritePermission= */ false, 1175 /* isCalledFromBgWithoutBgRead= */ true); 1176 1177 assertThat(result).containsExactly(vaccineDatasource1); 1178 } 1179 1180 @Test 1181 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) readById_inBgWithoutBgPerm_noWritePerm_bothAllergyAndVaccineReadPerm_success()1182 public void readById_inBgWithoutBgPerm_noWritePerm_bothAllergyAndVaccineReadPerm_success() { 1183 MedicalDataSource dataSource1 = 1184 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 1185 MedicalDataSource dataSource2 = 1186 mUtil.insertR4MedicalDataSource("ds", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 1187 MedicalResource vaccineDatasource1 = 1188 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 1189 MedicalResource allergyDatasource1 = 1190 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource1); 1191 MedicalResource vaccineDatasource2 = 1192 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource2); 1193 MedicalResource allergyDatasource2 = 1194 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource2); 1195 List<MedicalResourceId> ids = 1196 List.of( 1197 vaccineDatasource1.getId(), 1198 vaccineDatasource2.getId(), 1199 allergyDatasource1.getId(), 1200 allergyDatasource2.getId()); 1201 1202 List<MedicalResource> result = 1203 mMedicalResourceHelper.readMedicalResourcesByIdsWithPermissionChecks( 1204 ids, 1205 Set.of( 1206 MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES, 1207 MEDICAL_RESOURCE_TYPE_VACCINES), 1208 DATA_SOURCE_PACKAGE_NAME, 1209 /* hasWritePermission= */ false, 1210 /* isCalledFromBgWithoutBgRead= */ true); 1211 1212 assertThat(result).containsExactly(vaccineDatasource1, allergyDatasource1); 1213 } 1214 1215 @Test 1216 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) readById_inForegroundOrinBgWithBgPerm_noWritePerm_success()1217 public void readById_inForegroundOrinBgWithBgPerm_noWritePerm_success() { 1218 MedicalDataSource dataSource1 = 1219 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 1220 MedicalDataSource dataSource2 = 1221 mUtil.insertR4MedicalDataSource("ds", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 1222 MedicalResource vaccineDatasource1 = 1223 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 1224 MedicalResource allergyDatasource1 = 1225 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource1); 1226 MedicalResource vaccineDatasource2 = 1227 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource2); 1228 MedicalResource allergyDatasource2 = 1229 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource2); 1230 List<MedicalResourceId> ids = 1231 List.of( 1232 vaccineDatasource1.getId(), 1233 vaccineDatasource2.getId(), 1234 allergyDatasource1.getId(), 1235 allergyDatasource2.getId()); 1236 1237 List<MedicalResource> result = 1238 mMedicalResourceHelper.readMedicalResourcesByIdsWithPermissionChecks( 1239 ids, 1240 Set.of(MEDICAL_RESOURCE_TYPE_VACCINES), 1241 DIFFERENT_DATA_SOURCE_PACKAGE_NAME, 1242 /* hasWritePermission= */ false, 1243 /* isCalledFromBgWithoutBgRead= */ false); 1244 1245 assertThat(result).containsExactly(vaccineDatasource1, vaccineDatasource2); 1246 } 1247 1248 @Test 1249 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) readById_inForeground_hasWritePerm_noReadResourceTypesPerm_canOnlyReadSelfData()1250 public void readById_inForeground_hasWritePerm_noReadResourceTypesPerm_canOnlyReadSelfData() { 1251 MedicalDataSource dataSource1 = 1252 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 1253 MedicalDataSource dataSource2 = 1254 mUtil.insertR4MedicalDataSource("ds", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 1255 MedicalResource vaccineDatasource1 = 1256 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 1257 MedicalResource allergyDatasource1 = 1258 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource1); 1259 MedicalResource vaccineDatasource2 = 1260 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource2); 1261 MedicalResource allergyDatasource2 = 1262 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource2); 1263 List<MedicalResourceId> ids = 1264 List.of( 1265 vaccineDatasource1.getId(), 1266 vaccineDatasource2.getId(), 1267 allergyDatasource1.getId(), 1268 allergyDatasource2.getId()); 1269 1270 List<MedicalResource> result = 1271 mMedicalResourceHelper.readMedicalResourcesByIdsWithPermissionChecks( 1272 ids, 1273 Set.of(), 1274 DATA_SOURCE_PACKAGE_NAME, 1275 /* hasWritePermission= */ true, 1276 /* isCalledFromBgWithoutBgRead= */ false); 1277 1278 assertThat(result).containsExactly(vaccineDatasource1, allergyDatasource1); 1279 } 1280 1281 @Test 1282 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) readById_inForeground_noWritePerm_readVaccinePerm_canOnlyReadVaccine()1283 public void readById_inForeground_noWritePerm_readVaccinePerm_canOnlyReadVaccine() { 1284 MedicalDataSource dataSource1 = 1285 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 1286 MedicalDataSource dataSource2 = 1287 mUtil.insertR4MedicalDataSource("ds", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 1288 MedicalResource vaccineDatasource1 = 1289 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 1290 MedicalResource allergyDatasource1 = 1291 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource1); 1292 MedicalResource vaccineDatasource2 = 1293 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource2); 1294 MedicalResource allergyDatasource2 = 1295 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource2); 1296 List<MedicalResourceId> ids = 1297 List.of( 1298 vaccineDatasource1.getId(), 1299 vaccineDatasource2.getId(), 1300 allergyDatasource1.getId(), 1301 allergyDatasource2.getId()); 1302 1303 List<MedicalResource> result = 1304 mMedicalResourceHelper.readMedicalResourcesByIdsWithPermissionChecks( 1305 ids, 1306 Set.of(MEDICAL_RESOURCE_TYPE_VACCINES), 1307 DATA_SOURCE_PACKAGE_NAME, 1308 /* hasWritePermission= */ false, 1309 /* isCalledFromBgWithoutBgRead= */ false); 1310 1311 assertThat(result).containsExactly(vaccineDatasource1, vaccineDatasource2); 1312 } 1313 1314 @Test 1315 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) readById_inForeground_noWritePerm_readAllergyPerm_canOnlyReadAllergy()1316 public void readById_inForeground_noWritePerm_readAllergyPerm_canOnlyReadAllergy() { 1317 MedicalDataSource dataSource1 = 1318 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 1319 MedicalDataSource dataSource2 = 1320 mUtil.insertR4MedicalDataSource("ds", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 1321 MedicalResource vaccineDatasource1 = 1322 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 1323 MedicalResource allergyDatasource1 = 1324 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource1); 1325 MedicalResource vaccineDatasource2 = 1326 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource2); 1327 MedicalResource allergyDatasource2 = 1328 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource2); 1329 List<MedicalResourceId> ids = 1330 List.of( 1331 vaccineDatasource1.getId(), 1332 vaccineDatasource2.getId(), 1333 allergyDatasource1.getId(), 1334 allergyDatasource2.getId()); 1335 1336 List<MedicalResource> result = 1337 mMedicalResourceHelper.readMedicalResourcesByIdsWithPermissionChecks( 1338 ids, 1339 Set.of(MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES), 1340 DATA_SOURCE_PACKAGE_NAME, 1341 /* hasWritePermission= */ false, 1342 /* isCalledFromBgWithoutBgRead= */ false); 1343 1344 assertThat(result).containsExactly(allergyDatasource1, allergyDatasource2); 1345 } 1346 1347 @Test 1348 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) readById_inForeground_noWritePerm_readVaccineAndAllergyPerm_canReadBoth()1349 public void readById_inForeground_noWritePerm_readVaccineAndAllergyPerm_canReadBoth() { 1350 MedicalDataSource dataSource1 = 1351 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 1352 MedicalDataSource dataSource2 = 1353 mUtil.insertR4MedicalDataSource("ds", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 1354 MedicalResource vaccineDatasource1 = 1355 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 1356 MedicalResource allergyDatasource1 = 1357 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource1); 1358 MedicalResource vaccineDatasource2 = 1359 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource2); 1360 MedicalResource allergyDatasource2 = 1361 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource2); 1362 List<MedicalResourceId> ids = 1363 List.of( 1364 vaccineDatasource1.getId(), 1365 vaccineDatasource2.getId(), 1366 allergyDatasource1.getId(), 1367 allergyDatasource2.getId()); 1368 1369 List<MedicalResource> result = 1370 mMedicalResourceHelper.readMedicalResourcesByIdsWithPermissionChecks( 1371 ids, 1372 Set.of( 1373 MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES, 1374 MEDICAL_RESOURCE_TYPE_VACCINES), 1375 DATA_SOURCE_PACKAGE_NAME, 1376 /* hasWritePermission= */ false, 1377 /* isCalledFromBgWithoutBgRead= */ false); 1378 1379 assertThat(result) 1380 .containsExactly( 1381 vaccineDatasource1, 1382 vaccineDatasource2, 1383 allergyDatasource1, 1384 allergyDatasource2); 1385 } 1386 1387 @Test 1388 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) readById_inForeground_hasWritePermAndReadVaccine_readsSelfDataAndVaccines()1389 public void readById_inForeground_hasWritePermAndReadVaccine_readsSelfDataAndVaccines() { 1390 MedicalDataSource dataSource1 = 1391 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 1392 MedicalDataSource dataSource2 = 1393 mUtil.insertR4MedicalDataSource("ds", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 1394 MedicalResource vaccineDatasource1 = 1395 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 1396 MedicalResource allergyDatasource1 = 1397 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource1); 1398 MedicalResource vaccineDatasource2 = 1399 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource2); 1400 MedicalResource allergyDatasource2 = 1401 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource2); 1402 List<MedicalResourceId> ids = 1403 List.of( 1404 vaccineDatasource1.getId(), 1405 vaccineDatasource2.getId(), 1406 allergyDatasource1.getId(), 1407 allergyDatasource2.getId()); 1408 1409 List<MedicalResource> result = 1410 mMedicalResourceHelper.readMedicalResourcesByIdsWithPermissionChecks( 1411 ids, 1412 Set.of(MEDICAL_RESOURCE_TYPE_VACCINES), 1413 DATA_SOURCE_PACKAGE_NAME, 1414 /* hasWritePermission= */ true, 1415 /* isCalledFromBgWithoutBgRead= */ false); 1416 1417 assertThat(result) 1418 .containsExactly(vaccineDatasource1, vaccineDatasource2, allergyDatasource1); 1419 } 1420 1421 @Test 1422 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) readByRequest_isNotEnforceSelfRead_createsAccessLog()1423 public void readByRequest_isNotEnforceSelfRead_createsAccessLog() { 1424 ReadMedicalResourcesInitialRequest readRequest = 1425 new ReadMedicalResourcesInitialRequest.Builder(MEDICAL_RESOURCE_TYPE_VACCINES) 1426 .build(); 1427 mMedicalResourceHelper.readMedicalResourcesByRequestWithPermissionChecks( 1428 PhrPageTokenWrapper.from(readRequest.toParcel()), 1429 readRequest.getPageSize(), 1430 DATA_SOURCE_PACKAGE_NAME, 1431 /* enforceSelfRead= */ false); 1432 1433 AccessLog expected = 1434 new AccessLog( 1435 DATA_SOURCE_PACKAGE_NAME, 1436 INSTANT_NOW.toEpochMilli(), 1437 OPERATION_TYPE_READ, 1438 /* medicalResourceTypes= */ Set.of(MEDICAL_RESOURCE_TYPE_VACCINES), 1439 /* isMedicalDataSourceAccessed= */ false); 1440 1441 assertThat(mAccessLogsHelper.queryAccessLogs(mUserHandle)) 1442 .comparingElementsUsing(ACCESS_LOG_EQUIVALENCE) 1443 .containsExactly(expected); 1444 } 1445 1446 @Test 1447 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) readByRequest_isEnforceSelfRead_doesNotCreateAccessLog()1448 public void readByRequest_isEnforceSelfRead_doesNotCreateAccessLog() { 1449 ReadMedicalResourcesInitialRequest readRequest = 1450 new ReadMedicalResourcesInitialRequest.Builder(MEDICAL_RESOURCE_TYPE_VACCINES) 1451 .build(); 1452 mMedicalResourceHelper.readMedicalResourcesByRequestWithPermissionChecks( 1453 PhrPageTokenWrapper.from(readRequest.toParcel()), 1454 readRequest.getPageSize(), 1455 DATA_SOURCE_PACKAGE_NAME, 1456 /* enforceSelfRead= */ true); 1457 1458 List<AccessLog> accessLogs = mAccessLogsHelper.queryAccessLogs(mUserHandle); 1459 1460 assertThat(accessLogs).isEmpty(); 1461 } 1462 1463 @Test 1464 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) readByRequest_isNotEnforceSelfRead_vaccineFilter_canReadAllVaccines()1465 public void readByRequest_isNotEnforceSelfRead_vaccineFilter_canReadAllVaccines() { 1466 MedicalDataSource dataSource1 = 1467 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 1468 MedicalDataSource dataSource2 = 1469 mUtil.insertR4MedicalDataSource("ds", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 1470 // In total inserts 8 resources, among which 6 are vaccines to be read in 3 pages. 1471 List<MedicalResource> vaccinesDataSource1 = 1472 mUtil.upsertResources( 1473 PhrDataFactory::createVaccineMedicalResources, 1474 /* numOfResources= */ 4, 1475 dataSource1); 1476 List<MedicalResource> vaccinesDataSource2 = 1477 mUtil.upsertResources( 1478 PhrDataFactory::createVaccineMedicalResources, 1479 /* numOfResources= */ 2, 1480 dataSource2); 1481 List<MedicalResource> allergyDatasource1 = 1482 mUtil.upsertResources( 1483 PhrDataFactory::createAllergyMedicalResources, 1484 /* numOfResources= */ 2, 1485 dataSource1); 1486 List<MedicalResource> resources = 1487 joinLists(vaccinesDataSource1, vaccinesDataSource2, allergyDatasource1); 1488 1489 ReadMedicalResourcesInitialRequest initialRequest = 1490 new ReadMedicalResourcesInitialRequest.Builder(MEDICAL_RESOURCE_TYPE_VACCINES) 1491 .setPageSize(2) 1492 .build(); 1493 PhrPageTokenWrapper initialPageTokenWrapper = 1494 PhrPageTokenWrapper.from(initialRequest.toParcel()); 1495 ReadMedicalResourcesInternalResponse initialResult = 1496 mMedicalResourceHelper.readMedicalResourcesByRequestWithPermissionChecks( 1497 initialPageTokenWrapper, 1498 initialRequest.getPageSize(), 1499 DATA_SOURCE_PACKAGE_NAME, 1500 /* enforceSelfRead= */ false); 1501 String pageToken1 = initialResult.getPageToken(); 1502 assertThat(initialResult.getMedicalResources()) 1503 .containsExactlyElementsIn(List.of(resources.get(0), resources.get(1))); 1504 assertThat(pageToken1).isNotEmpty(); 1505 assertThat(pageToken1) 1506 .isEqualTo( 1507 initialPageTokenWrapper.cloneWithNewLastRowId(/* lastRowId= */ 2).encode()); 1508 assertThat(initialResult.getRemainingCount()).isEqualTo(4); 1509 1510 ReadMedicalResourcesPageRequest pageRequest1 = 1511 new ReadMedicalResourcesPageRequest.Builder(pageToken1).setPageSize(2).build(); 1512 PhrPageTokenWrapper pageTokenWrapper1 = PhrPageTokenWrapper.from(pageRequest1.toParcel()); 1513 ReadMedicalResourcesInternalResponse pageResult = 1514 mMedicalResourceHelper.readMedicalResourcesByRequestWithPermissionChecks( 1515 pageTokenWrapper1, 1516 pageRequest1.getPageSize(), 1517 DATA_SOURCE_PACKAGE_NAME, 1518 /* enforceSelfRead= */ false); 1519 String pageToken2 = pageResult.getPageToken(); 1520 assertThat(pageResult.getMedicalResources()) 1521 .containsExactlyElementsIn(List.of(resources.get(2), resources.get(3))); 1522 assertThat(pageToken2).isNotEmpty(); 1523 assertThat(pageToken2) 1524 .isEqualTo(pageTokenWrapper1.cloneWithNewLastRowId(/* lastRowId= */ 4).encode()); 1525 assertThat(pageResult.getRemainingCount()).isEqualTo(2); 1526 1527 ReadMedicalResourcesPageRequest pageRequest2 = 1528 new ReadMedicalResourcesPageRequest.Builder(pageToken2).setPageSize(2).build(); 1529 PhrPageTokenWrapper pageTokenWrapper2 = PhrPageTokenWrapper.from(pageRequest2.toParcel()); 1530 ReadMedicalResourcesInternalResponse pageResult2 = 1531 mMedicalResourceHelper.readMedicalResourcesByRequestWithPermissionChecks( 1532 pageTokenWrapper2, 1533 pageRequest2.getPageSize(), 1534 DATA_SOURCE_PACKAGE_NAME, 1535 /* enforceSelfRead= */ false); 1536 String pageToken3 = pageResult2.getPageToken(); 1537 assertThat(pageResult2.getMedicalResources()) 1538 .containsExactlyElementsIn(List.of(resources.get(4), resources.get(5))); 1539 assertThat(pageToken3).isNull(); 1540 assertThat(pageResult2.getRemainingCount()).isEqualTo(0); 1541 } 1542 1543 @Test 1544 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) readByRequest_enforceSelfRead_vaccineFilter_canReadOnlySelfVaccines()1545 public void readByRequest_enforceSelfRead_vaccineFilter_canReadOnlySelfVaccines() { 1546 MedicalDataSource dataSource1 = 1547 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 1548 MedicalDataSource dataSource2 = 1549 mUtil.insertR4MedicalDataSource("ds", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 1550 // In total inserts 8 resources, among which 4 are vaccines from data source 1 to be 1551 // read in 2 pages. 1552 List<MedicalResource> vaccinesDataSource1 = 1553 mUtil.upsertResources( 1554 PhrDataFactory::createVaccineMedicalResources, 1555 /* numOfResources= */ 4, 1556 dataSource1); 1557 List<MedicalResource> vaccinesDataSource2 = 1558 mUtil.upsertResources( 1559 PhrDataFactory::createVaccineMedicalResources, 1560 /* numOfResources= */ 2, 1561 dataSource2); 1562 List<MedicalResource> allergyDatasource1 = 1563 mUtil.upsertResources( 1564 PhrDataFactory::createAllergyMedicalResources, 1565 /* numOfResources= */ 2, 1566 dataSource1); 1567 List<MedicalResource> resources = 1568 joinLists(vaccinesDataSource1, vaccinesDataSource2, allergyDatasource1); 1569 1570 ReadMedicalResourcesInitialRequest initialRequest = 1571 new ReadMedicalResourcesInitialRequest.Builder(MEDICAL_RESOURCE_TYPE_VACCINES) 1572 .setPageSize(2) 1573 .build(); 1574 PhrPageTokenWrapper initialPageTokenWrapper = 1575 PhrPageTokenWrapper.from(initialRequest.toParcel()); 1576 ReadMedicalResourcesInternalResponse initialResult = 1577 mMedicalResourceHelper.readMedicalResourcesByRequestWithPermissionChecks( 1578 initialPageTokenWrapper, 1579 initialRequest.getPageSize(), 1580 DATA_SOURCE_PACKAGE_NAME, 1581 /* enforceSelfRead= */ true); 1582 String pageToken1 = initialResult.getPageToken(); 1583 assertThat(initialResult.getMedicalResources()) 1584 .containsExactlyElementsIn(List.of(resources.get(0), resources.get(1))); 1585 assertThat(pageToken1).isNotEmpty(); 1586 assertThat(pageToken1) 1587 .isEqualTo( 1588 initialPageTokenWrapper.cloneWithNewLastRowId(/* lastRowId= */ 2).encode()); 1589 assertThat(initialResult.getRemainingCount()).isEqualTo(2); 1590 1591 ReadMedicalResourcesPageRequest pageRequest = 1592 new ReadMedicalResourcesPageRequest.Builder(pageToken1).setPageSize(2).build(); 1593 PhrPageTokenWrapper pageTokenWrapper = PhrPageTokenWrapper.from(pageRequest.toParcel()); 1594 ReadMedicalResourcesInternalResponse pageResult = 1595 mMedicalResourceHelper.readMedicalResourcesByRequestWithPermissionChecks( 1596 pageTokenWrapper, 1597 pageRequest.getPageSize(), 1598 DATA_SOURCE_PACKAGE_NAME, 1599 /* enforceSelfRead= */ true); 1600 String pageToken2 = pageResult.getPageToken(); 1601 assertThat(pageResult.getMedicalResources()) 1602 .containsExactlyElementsIn(List.of(resources.get(2), resources.get(3))); 1603 assertThat(pageToken2).isNull(); 1604 assertThat(pageResult.getRemainingCount()).isEqualTo(0); 1605 } 1606 1607 @Test 1608 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD, Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) insertMultipleMedicalResourcesWithSameDataSource_readMultipleResources()1609 public void insertMultipleMedicalResourcesWithSameDataSource_readMultipleResources() { 1610 // TODO(b/351992434): Create test utilities to make these large repeated code blocks 1611 // clearer. 1612 MedicalDataSource dataSource = 1613 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 1614 MedicalResource resource1 = createVaccineMedicalResource(dataSource.getId()); 1615 MedicalResource resource2 = createAllergyMedicalResource(dataSource.getId()); 1616 1617 List<MedicalResource> upsertedMedicalResources = 1618 mMedicalResourceHelper.upsertMedicalResources( 1619 DATA_SOURCE_PACKAGE_NAME, 1620 List.of(makeUpsertRequest(resource1), makeUpsertRequest(resource2))); 1621 List<MedicalResource> result = 1622 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 1623 List.of(resource1.getId(), resource2.getId())); 1624 List<Integer> indicesResult = readEntriesInMedicalResourceIndicesTable(); 1625 1626 assertThat(result).containsExactly(resource1, resource2); 1627 assertThat(upsertedMedicalResources).containsExactly(resource1, resource2); 1628 assertThat(indicesResult) 1629 .containsExactly( 1630 MEDICAL_RESOURCE_TYPE_VACCINES, 1631 MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES); 1632 } 1633 1634 @Test 1635 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD, Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) insertMedicalResourcesOfSameType_createsAccessLog_success()1636 public void insertMedicalResourcesOfSameType_createsAccessLog_success() { 1637 MedicalDataSource dataSource = 1638 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 1639 mUtil.upsertResources( 1640 PhrDataFactory::createVaccineMedicalResources, /* numOfResources= */ 6, dataSource); 1641 1642 AccessLog expected = 1643 new AccessLog( 1644 DATA_SOURCE_PACKAGE_NAME, 1645 INSTANT_NOW.toEpochMilli(), 1646 OPERATION_TYPE_UPSERT, 1647 /* medicalResourceTypes= */ Set.of(MEDICAL_RESOURCE_TYPE_VACCINES), 1648 /* isMedicalDataSourceAccessed= */ false); 1649 1650 assertThat(mAccessLogsHelper.queryAccessLogs(mUserHandle)) 1651 .comparingElementsUsing(ACCESS_LOG_EQUIVALENCE) 1652 .contains(expected); 1653 } 1654 1655 @Test 1656 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD, Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) insertMedicalResourcesOfDifferentTypes_createsAccessLog_success()1657 public void insertMedicalResourcesOfDifferentTypes_createsAccessLog_success() { 1658 String dataSource = mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME).getId(); 1659 MedicalResource vaccine = createVaccineMedicalResource(dataSource); 1660 MedicalResource allergy = createAllergyMedicalResource(dataSource); 1661 mMedicalResourceHelper.upsertMedicalResources( 1662 DATA_SOURCE_PACKAGE_NAME, 1663 createUpsertMedicalResourceRequests(List.of(vaccine, allergy), dataSource)); 1664 1665 AccessLog expected = 1666 new AccessLog( 1667 DATA_SOURCE_PACKAGE_NAME, 1668 INSTANT_NOW.toEpochMilli(), 1669 OPERATION_TYPE_UPSERT, 1670 /* medicalResourceTypes= */ Set.of( 1671 MEDICAL_RESOURCE_TYPE_VACCINES, 1672 MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES), 1673 /* isMedicalDataSourceAccessed= */ false); 1674 1675 assertThat(mAccessLogsHelper.queryAccessLogs(mUserHandle)) 1676 .comparingElementsUsing(ACCESS_LOG_EQUIVALENCE) 1677 .contains(expected); 1678 } 1679 1680 @Test 1681 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD, Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) insertAndUpdateMedicalResources_createsAccessLog_success()1682 public void insertAndUpdateMedicalResources_createsAccessLog_success() throws JSONException { 1683 String dataSource = mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME).getId(); 1684 MedicalResource vaccine = createVaccineMedicalResource(dataSource); 1685 MedicalResource allergy = createAllergyMedicalResource(dataSource); 1686 MedicalResource updatedVaccine = createUpdatedVaccineMedicalResource(dataSource); 1687 // initial insert 1688 mMedicalResourceHelper.upsertMedicalResources( 1689 DATA_SOURCE_PACKAGE_NAME, 1690 createUpsertMedicalResourceRequests(List.of(vaccine, allergy), dataSource)); 1691 // update the vaccine resource 1692 mMedicalResourceHelper.upsertMedicalResources( 1693 DATA_SOURCE_PACKAGE_NAME, 1694 createUpsertMedicalResourceRequests(List.of(updatedVaccine), dataSource)); 1695 1696 AccessLog insertAccessLog = 1697 new AccessLog( 1698 DATA_SOURCE_PACKAGE_NAME, 1699 INSTANT_NOW.toEpochMilli(), 1700 OPERATION_TYPE_UPSERT, 1701 /* medicalResourceTypes= */ Set.of( 1702 MEDICAL_RESOURCE_TYPE_VACCINES, 1703 MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES), 1704 /* isMedicalDataSourceAccessed= */ false); 1705 AccessLog updateAccessLog = 1706 new AccessLog( 1707 DATA_SOURCE_PACKAGE_NAME, 1708 INSTANT_NOW.toEpochMilli(), 1709 OPERATION_TYPE_UPSERT, 1710 /* medicalResourceTypes= */ Set.of(MEDICAL_RESOURCE_TYPE_VACCINES), 1711 /* isMedicalDataSourceAccessed= */ false); 1712 1713 assertThat(mAccessLogsHelper.queryAccessLogs(mUserHandle)) 1714 .comparingElementsUsing(ACCESS_LOG_EQUIVALENCE) 1715 .containsAtLeast(insertAccessLog, updateAccessLog); 1716 } 1717 1718 @Test 1719 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD, Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE}) insertMultipleMedicalResourcesWithDifferentDataSources_readMultipleResources()1720 public void insertMultipleMedicalResourcesWithDifferentDataSources_readMultipleResources() { 1721 MedicalDataSource dataSource1 = 1722 mUtil.insertR4MedicalDataSource("ds1", DATA_SOURCE_PACKAGE_NAME); 1723 MedicalDataSource dataSource2 = 1724 mUtil.insertR4MedicalDataSource("ds2", DATA_SOURCE_PACKAGE_NAME); 1725 MedicalResource resource1 = createVaccineMedicalResource(dataSource1.getId()); 1726 MedicalResource resource2 = createDifferentVaccineMedicalResource(dataSource2.getId()); 1727 1728 List<MedicalResource> upsertedMedicalResources = 1729 mMedicalResourceHelper.upsertMedicalResources( 1730 DATA_SOURCE_PACKAGE_NAME, 1731 List.of(makeUpsertRequest(resource1), makeUpsertRequest(resource2))); 1732 List<MedicalResource> result = 1733 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 1734 List.of(resource1.getId(), resource2.getId())); 1735 List<Integer> indicesResult = readEntriesInMedicalResourceIndicesTable(); 1736 1737 assertThat(result).containsExactly(resource1, resource2); 1738 assertThat(upsertedMedicalResources).containsExactly(resource1, resource2); 1739 assertThat(indicesResult) 1740 .containsExactly(MEDICAL_RESOURCE_TYPE_VACCINES, MEDICAL_RESOURCE_TYPE_VACCINES); 1741 } 1742 1743 @Test 1744 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) updateSingleMedicalResource_success()1745 public void updateSingleMedicalResource_success() throws JSONException { 1746 MedicalDataSource dataSource = 1747 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 1748 MedicalResource originalResource = createVaccineMedicalResource(dataSource.getId()); 1749 MedicalResource updatedResource = createUpdatedVaccineMedicalResource(dataSource.getId()); 1750 1751 mMedicalResourceHelper.upsertMedicalResources( 1752 DATA_SOURCE_PACKAGE_NAME, List.of(makeUpsertRequest(originalResource))); 1753 List<MedicalResource> updatedMedicalResource = 1754 mMedicalResourceHelper.upsertMedicalResources( 1755 DATA_SOURCE_PACKAGE_NAME, List.of(makeUpsertRequest(updatedResource))); 1756 List<MedicalResource> result = 1757 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 1758 List.of(originalResource.getId())); 1759 List<Integer> indicesResult = readEntriesInMedicalResourceIndicesTable(); 1760 1761 assertThat(result).containsExactly(updatedResource); 1762 assertThat(result).isEqualTo(updatedMedicalResource); 1763 assertThat(indicesResult).containsExactly(MEDICAL_RESOURCE_TYPE_VACCINES); 1764 } 1765 1766 @Test 1767 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) insertMultipleMedicalResources_updateSingleMedicalResource_success()1768 public void insertMultipleMedicalResources_updateSingleMedicalResource_success() 1769 throws JSONException { 1770 MedicalDataSource dataSource = 1771 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 1772 MedicalResource originalResource1 = createVaccineMedicalResource(dataSource.getId()); 1773 MedicalResource updatedResource1 = createUpdatedVaccineMedicalResource(dataSource.getId()); 1774 MedicalResource resource2 = createAllergyMedicalResource(dataSource.getId()); 1775 1776 List<MedicalResource> upsertedMedicalResources = 1777 mMedicalResourceHelper.upsertMedicalResources( 1778 DATA_SOURCE_PACKAGE_NAME, 1779 List.of( 1780 makeUpsertRequest(originalResource1), 1781 makeUpsertRequest(resource2))); 1782 List<MedicalResource> updatedMedicalResource = 1783 mMedicalResourceHelper.upsertMedicalResources( 1784 DATA_SOURCE_PACKAGE_NAME, List.of(makeUpsertRequest(updatedResource1))); 1785 List<MedicalResource> readResults = 1786 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 1787 List.of(updatedResource1.getId(), resource2.getId())); 1788 List<Integer> indicesResult = readEntriesInMedicalResourceIndicesTable(); 1789 1790 assertThat(readResults).containsExactly(updatedResource1, resource2); 1791 assertThat(upsertedMedicalResources).containsExactly(originalResource1, resource2); 1792 assertThat(updatedMedicalResource).containsExactly(updatedResource1); 1793 assertThat(indicesResult) 1794 .containsExactly( 1795 MEDICAL_RESOURCE_TYPE_VACCINES, 1796 MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES); 1797 } 1798 1799 @Test 1800 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) insertMultipleMedicalResources_updateMultipleMedicalResources_success()1801 public void insertMultipleMedicalResources_updateMultipleMedicalResources_success() 1802 throws JSONException { 1803 MedicalDataSource dataSource = 1804 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 1805 MedicalResource resource1 = createVaccineMedicalResource(dataSource.getId()); 1806 MedicalResource updatedResource1 = createUpdatedVaccineMedicalResource(dataSource.getId()); 1807 MedicalResource resource2 = createAllergyMedicalResource(dataSource.getId()); 1808 MedicalResource updatedResource2 = createUpdatedAllergyMedicalResource(dataSource.getId()); 1809 1810 List<MedicalResource> insertedMedicalResources = 1811 mMedicalResourceHelper.upsertMedicalResources( 1812 DATA_SOURCE_PACKAGE_NAME, 1813 List.of(makeUpsertRequest(resource1), makeUpsertRequest(resource2))); 1814 List<MedicalResource> updatedMedicalResource = 1815 mMedicalResourceHelper.upsertMedicalResources( 1816 DATA_SOURCE_PACKAGE_NAME, 1817 List.of( 1818 makeUpsertRequest(updatedResource1), 1819 makeUpsertRequest(updatedResource2))); 1820 List<MedicalResourceId> medicalIdFilters = List.of(resource1.getId(), resource2.getId()); 1821 List<MedicalResource> result = 1822 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 1823 medicalIdFilters); 1824 List<Integer> indicesResult = readEntriesInMedicalResourceIndicesTable(); 1825 1826 assertThat(insertedMedicalResources).containsExactly(resource1, resource2); 1827 assertThat(updatedMedicalResource) 1828 .containsExactly(updatedResource1, updatedResource2) 1829 .inOrder(); 1830 assertThat(result).containsExactly(updatedResource1, updatedResource2); 1831 assertThat(indicesResult) 1832 .containsExactly( 1833 MEDICAL_RESOURCE_TYPE_VACCINES, 1834 MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES); 1835 } 1836 1837 @Test 1838 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) insertMultipleMedicalResources_readByRequest_success()1839 public void insertMultipleMedicalResources_readByRequest_success() { 1840 MedicalDataSource dataSource = 1841 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 1842 List<MedicalResource> resources = 1843 createVaccineMedicalResources(/* numOfResources= */ 6, dataSource.getId()); 1844 List<UpsertMedicalResourceInternalRequest> upsertRequests = 1845 createUpsertMedicalResourceRequests(resources, dataSource.getId()); 1846 1847 List<MedicalResource> upsertedMedicalResources = 1848 mMedicalResourceHelper.upsertMedicalResources( 1849 DATA_SOURCE_PACKAGE_NAME, upsertRequests); 1850 assertThat(upsertedMedicalResources).containsExactlyElementsIn(resources); 1851 1852 ReadMedicalResourcesInitialRequest initialRequest = 1853 new ReadMedicalResourcesInitialRequest.Builder(MEDICAL_RESOURCE_TYPE_VACCINES) 1854 .setPageSize(2) 1855 .build(); 1856 PhrPageTokenWrapper pageTokenWrapper = PhrPageTokenWrapper.from(initialRequest.toParcel()); 1857 ReadMedicalResourcesInternalResponse initialResult = 1858 mMedicalResourceHelper.readMedicalResourcesByRequestWithoutPermissionChecks( 1859 pageTokenWrapper, initialRequest.getPageSize()); 1860 String pageToken1 = initialResult.getPageToken(); 1861 assertThat(initialResult.getMedicalResources()) 1862 .containsExactlyElementsIn(List.of(resources.get(0), resources.get(1))); 1863 assertThat(pageToken1).isNotEmpty(); 1864 assertThat(pageToken1) 1865 .isEqualTo(pageTokenWrapper.cloneWithNewLastRowId(/* lastRowId= */ 2).encode()); 1866 assertThat(initialResult.getRemainingCount()).isEqualTo(4); 1867 1868 ReadMedicalResourcesPageRequest pageRequest1 = 1869 new ReadMedicalResourcesPageRequest.Builder(pageToken1).setPageSize(2).build(); 1870 PhrPageTokenWrapper pageTokenWrapper1 = PhrPageTokenWrapper.from(pageRequest1.toParcel()); 1871 ReadMedicalResourcesInternalResponse pageResult1 = 1872 mMedicalResourceHelper.readMedicalResourcesByRequestWithoutPermissionChecks( 1873 pageTokenWrapper1, pageRequest1.getPageSize()); 1874 String pageToken2 = pageResult1.getPageToken(); 1875 assertThat(pageResult1.getMedicalResources()) 1876 .containsExactlyElementsIn(List.of(resources.get(2), resources.get(3))); 1877 assertThat(pageToken2).isNotEmpty(); 1878 assertThat(pageToken2) 1879 .isEqualTo(pageTokenWrapper1.cloneWithNewLastRowId(/* lastRowId= */ 4).encode()); 1880 assertThat(pageResult1.getRemainingCount()).isEqualTo(2); 1881 1882 ReadMedicalResourcesPageRequest pageRequest2 = 1883 new ReadMedicalResourcesPageRequest.Builder(pageToken2).setPageSize(2).build(); 1884 PhrPageTokenWrapper pageTokenWrapper2 = PhrPageTokenWrapper.from(pageRequest2.toParcel()); 1885 ReadMedicalResourcesInternalResponse result2 = 1886 mMedicalResourceHelper.readMedicalResourcesByRequestWithoutPermissionChecks( 1887 pageTokenWrapper2, pageRequest2.getPageSize()); 1888 String pageToken3 = result2.getPageToken(); 1889 assertThat(result2.getMedicalResources()) 1890 .containsExactlyElementsIn(List.of(resources.get(4), resources.get(5))); 1891 assertThat(pageToken3).isNull(); 1892 assertThat(result2.getRemainingCount()).isEqualTo(0); 1893 } 1894 1895 @Test 1896 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) insertMultipleMedicalResourcesReadByRequest_pageSizeLargerThanResources_success()1897 public void insertMultipleMedicalResourcesReadByRequest_pageSizeLargerThanResources_success() { 1898 MedicalDataSource dataSource = 1899 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 1900 List<MedicalResource> resources = 1901 createVaccineMedicalResources(/* numOfResources= */ 6, dataSource.getId()); 1902 List<UpsertMedicalResourceInternalRequest> requests = 1903 createUpsertMedicalResourceRequests(resources, dataSource.getId()); 1904 1905 List<MedicalResource> upsertedMedicalResources = 1906 mMedicalResourceHelper.upsertMedicalResources(DATA_SOURCE_PACKAGE_NAME, requests); 1907 ReadMedicalResourcesInitialRequest readRequest = 1908 new ReadMedicalResourcesInitialRequest.Builder(MEDICAL_RESOURCE_TYPE_VACCINES) 1909 .setPageSize(10) 1910 .build(); 1911 ReadMedicalResourcesInternalResponse result = 1912 mMedicalResourceHelper.readMedicalResourcesByRequestWithoutPermissionChecks( 1913 PhrPageTokenWrapper.from(readRequest.toParcel()), 1914 readRequest.getPageSize()); 1915 1916 assertThat(upsertedMedicalResources).containsExactlyElementsIn(resources); 1917 assertThat(result.getMedicalResources()).containsExactlyElementsIn(resources); 1918 assertThat(result.getPageToken()).isEqualTo(null); 1919 assertThat(result.getRemainingCount()).isEqualTo(0); 1920 } 1921 1922 @Test 1923 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) readMedicalResourcedByRequest_invalidPageToken_throws()1924 public void readMedicalResourcedByRequest_invalidPageToken_throws() { 1925 ReadMedicalResourcesPageRequest request = 1926 new ReadMedicalResourcesPageRequest.Builder(INVALID_PAGE_TOKEN).build(); 1927 assertThrows( 1928 IllegalArgumentException.class, 1929 () -> 1930 mMedicalResourceHelper.readMedicalResourcesByRequestWithoutPermissionChecks( 1931 PhrPageTokenWrapper.from(request.toParcel()), 1932 request.getPageSize())); 1933 } 1934 1935 @Test 1936 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteMedicalResourcesByIds_appIdDoesNotExist_throws()1937 public void deleteMedicalResourcesByIds_appIdDoesNotExist_throws() { 1938 assertThrows( 1939 IllegalArgumentException.class, 1940 () -> 1941 mMedicalResourceHelper.deleteMedicalResourcesByIdsWithPermissionChecks( 1942 List.of(getMedicalResourceId()), "fake.package.com")); 1943 } 1944 1945 @Test 1946 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteMedicalResourcesByIds_withPackageName_noDataDeleted_noDeleteAccessLogs()1947 public void deleteMedicalResourcesByIds_withPackageName_noDataDeleted_noDeleteAccessLogs() { 1948 mMedicalResourceHelper.deleteMedicalResourcesByIdsWithPermissionChecks( 1949 List.of(getMedicalResourceId()), DATA_SOURCE_PACKAGE_NAME); 1950 1951 assertThat(mAccessLogsHelper.queryAccessLogs(mUserHandle)).isEmpty(); 1952 } 1953 1954 @Test 1955 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteMedicalResourcesByIdsWithoutPermissionChecks_noDeleteAccessLogs()1956 public void deleteMedicalResourcesByIdsWithoutPermissionChecks_noDeleteAccessLogs() { 1957 MedicalDataSource dataSource1 = 1958 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 1959 MedicalResource resource1 = 1960 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 1961 // Clear access logs table, so that only the access logs from delete will be present 1962 mAccessLogsHelper.clearData(mTransactionManager); 1963 1964 mMedicalResourceHelper.deleteMedicalResourcesByIdsWithoutPermissionChecks( 1965 List.of(resource1.getId())); 1966 1967 assertThat(mAccessLogsHelper.queryAccessLogs(mUserHandle)).isEmpty(); 1968 } 1969 1970 @Test 1971 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteByIdsWithPermissionChecks_resourcesWithDifferentPackages_correctAccessLogs()1972 public void deleteByIdsWithPermissionChecks_resourcesWithDifferentPackages_correctAccessLogs() { 1973 MedicalDataSource dataSource1 = 1974 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 1975 MedicalDataSource dataSource2 = 1976 mUtil.insertR4MedicalDataSource("ds", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 1977 MedicalResource vaccinePackage1 = 1978 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 1979 MedicalResource unknownResourcePackage2 = 1980 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource2); 1981 // Clear access logs table, so that only the access logs from delete will be present 1982 mAccessLogsHelper.clearData(mTransactionManager); 1983 1984 mMedicalResourceHelper.deleteMedicalResourcesByIdsWithPermissionChecks( 1985 List.of(vaccinePackage1.getId(), unknownResourcePackage2.getId()), 1986 /* packageName= */ DATA_SOURCE_PACKAGE_NAME); 1987 1988 // In this test, we have inserted two different resource types from different packages. 1989 // When the calling app, calls the delete API, we expect access log to be created only 1990 // for the deleted resource type. In this case it would be: vaccinePackage1 1991 AccessLog deleteAccessLog = 1992 new AccessLog( 1993 DATA_SOURCE_PACKAGE_NAME, 1994 INSTANT_NOW.toEpochMilli(), 1995 OPERATION_TYPE_DELETE, 1996 /* medicalResourceTypes= */ Set.of(MEDICAL_RESOURCE_TYPE_VACCINES), 1997 /* isMedicalDataSourceAccessed= */ false); 1998 assertThat(mAccessLogsHelper.queryAccessLogs(mUserHandle)) 1999 .comparingElementsUsing(ACCESS_LOG_EQUIVALENCE) 2000 .containsExactly(deleteAccessLog); 2001 } 2002 2003 @Test 2004 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteByIds_withPackageName_resourcesWithSamePackages_correctAccessLogs()2005 public void deleteByIds_withPackageName_resourcesWithSamePackages_correctAccessLogs() { 2006 MedicalDataSource dataSource1 = 2007 mUtil.insertR4MedicalDataSource("ds1", DATA_SOURCE_PACKAGE_NAME); 2008 MedicalDataSource dataSource2 = 2009 mUtil.insertR4MedicalDataSource("ds2", DATA_SOURCE_PACKAGE_NAME); 2010 MedicalResource vaccinePackage1 = 2011 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 2012 MedicalResource unknownResourcePackage1 = 2013 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource2); 2014 // Clear access logs table, so that only the access logs from delete will be present 2015 mAccessLogsHelper.clearData(mTransactionManager); 2016 2017 mMedicalResourceHelper.deleteMedicalResourcesByIdsWithPermissionChecks( 2018 List.of(vaccinePackage1.getId(), unknownResourcePackage1.getId()), 2019 /* packageName= */ DATA_SOURCE_PACKAGE_NAME); 2020 2021 // In this test, we have inserted two different resource types from the same package. 2022 // When the calling app, calls the delete API, we expect access log to be created 2023 // for the deleted resource types. In this case it would be: vaccinePackage1, 2024 // allergyResourcePackage1 2025 AccessLog deleteAccessLog = 2026 new AccessLog( 2027 DATA_SOURCE_PACKAGE_NAME, 2028 INSTANT_NOW.toEpochMilli(), 2029 OPERATION_TYPE_DELETE, 2030 /* medicalResourceTypes= */ Set.of( 2031 MEDICAL_RESOURCE_TYPE_VACCINES, 2032 MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES), 2033 /* isMedicalDataSourceAccessed= */ false); 2034 assertThat(mAccessLogsHelper.queryAccessLogs(mUserHandle)) 2035 .comparingElementsUsing(ACCESS_LOG_EQUIVALENCE) 2036 .containsExactly(deleteAccessLog); 2037 } 2038 2039 @Test 2040 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteMedicalResourcesByIds_noId_fails()2041 public void deleteMedicalResourcesByIds_noId_fails() { 2042 assertThrows( 2043 IllegalArgumentException.class, 2044 () -> 2045 mMedicalResourceHelper.deleteMedicalResourcesByIdsWithoutPermissionChecks( 2046 List.of())); 2047 } 2048 2049 @Test 2050 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteMedicalResourcesByIds_oneIdNotPresent_succeeds()2051 public void deleteMedicalResourcesByIds_oneIdNotPresent_succeeds() { 2052 mMedicalResourceHelper.deleteMedicalResourcesByIdsWithoutPermissionChecks( 2053 List.of( 2054 new MedicalResourceId( 2055 DATA_SOURCE_ID, 2056 FHIR_RESOURCE_TYPE_IMMUNIZATION, 2057 FHIR_RESOURCE_ID_IMMUNIZATION))); 2058 } 2059 2060 @Test 2061 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteMedicalResourcesByIds_oneIdPresent_succeedsDeleting()2062 public void deleteMedicalResourcesByIds_oneIdPresent_succeedsDeleting() { 2063 MedicalDataSource dataSource = 2064 mUtil.insertR4MedicalDataSource("ds", DATA_SOURCE_PACKAGE_NAME); 2065 MedicalResource medicalResource1 = 2066 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource); 2067 2068 mMedicalResourceHelper.deleteMedicalResourcesByIdsWithoutPermissionChecks( 2069 List.of(medicalResource1.getId())); 2070 2071 List<MedicalResource> result = 2072 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 2073 List.of(medicalResource1.getId())); 2074 List<Integer> indicesResult = readEntriesInMedicalResourceIndicesTable(); 2075 2076 assertThat(result).isEmpty(); 2077 assertThat(indicesResult).isEmpty(); 2078 } 2079 2080 @Test 2081 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteMedicalResourcesByIds_oneOfTwoSpecified_onlySpecifiedDeleted()2082 public void deleteMedicalResourcesByIds_oneOfTwoSpecified_onlySpecifiedDeleted() { 2083 MedicalDataSource dataSource = 2084 mUtil.insertR4MedicalDataSource("ds1", DATA_SOURCE_PACKAGE_NAME); 2085 MedicalResource medicalResource1 = 2086 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource); 2087 MedicalResource medicalResource2 = 2088 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource); 2089 2090 mMedicalResourceHelper.deleteMedicalResourcesByIdsWithoutPermissionChecks( 2091 List.of(medicalResource1.getId())); 2092 List<Integer> indicesResult = readEntriesInMedicalResourceIndicesTable(); 2093 2094 List<MedicalResource> result = 2095 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 2096 List.of(medicalResource1.getId(), medicalResource2.getId())); 2097 assertThat(result).containsExactly(medicalResource2); 2098 assertThat(indicesResult).containsExactly(MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES); 2099 } 2100 2101 @Test 2102 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteMedicalResourcesByIds_oneOfTwoSpecifiedWrongPackage_nothingDeleted()2103 public void deleteMedicalResourcesByIds_oneOfTwoSpecifiedWrongPackage_nothingDeleted() { 2104 MedicalDataSource dataSource = 2105 mUtil.insertR4MedicalDataSource("ds1", DATA_SOURCE_PACKAGE_NAME); 2106 MedicalResource medicalResource1 = 2107 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource); 2108 MedicalResource medicalResource2 = 2109 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource); 2110 2111 mMedicalResourceHelper.deleteMedicalResourcesByIdsWithPermissionChecks( 2112 List.of(medicalResource1.getId()), DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 2113 2114 List<MedicalResource> result = 2115 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 2116 List.of(medicalResource1.getId(), medicalResource2.getId())); 2117 assertThat(result).containsExactly(medicalResource1, medicalResource2); 2118 } 2119 2120 @Test 2121 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteMedicalResourcesByIds_oneOfTwoSpecifiedRightPackage_oneOfTwo()2122 public void deleteMedicalResourcesByIds_oneOfTwoSpecifiedRightPackage_oneOfTwo() { 2123 MedicalDataSource dataSource = 2124 mUtil.insertR4MedicalDataSource("ds1", DATA_SOURCE_PACKAGE_NAME); 2125 MedicalResource medicalResource1 = 2126 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource); 2127 MedicalResource medicalResource2 = 2128 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource); 2129 2130 mMedicalResourceHelper.deleteMedicalResourcesByIdsWithPermissionChecks( 2131 List.of(medicalResource1.getId()), DATA_SOURCE_PACKAGE_NAME); 2132 2133 List<MedicalResource> result = 2134 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 2135 List.of(medicalResource1.getId(), medicalResource2.getId())); 2136 assertThat(result).containsExactly(medicalResource2); 2137 } 2138 2139 @Test 2140 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteMedicalResourcesByIds_multipleIdsFromDifferentPackages_succeeds()2141 public void deleteMedicalResourcesByIds_multipleIdsFromDifferentPackages_succeeds() { 2142 MedicalDataSource dataSource1 = 2143 mUtil.insertR4MedicalDataSource("ds1", DATA_SOURCE_PACKAGE_NAME); 2144 MedicalDataSource dataSource2 = 2145 mUtil.insertR4MedicalDataSource("ds2", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 2146 MedicalResource expectedResource1Source1 = 2147 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 2148 MedicalResource expectedResource1Source2 = 2149 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource2); 2150 MedicalResource expectedResource2Source1 = 2151 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource1); 2152 MedicalResource expectedResource2Source2 = 2153 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource2); 2154 2155 mMedicalResourceHelper.deleteMedicalResourcesByIdsWithoutPermissionChecks( 2156 List.of(expectedResource1Source1.getId(), expectedResource2Source2.getId())); 2157 2158 List<MedicalResource> result = 2159 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 2160 List.of( 2161 expectedResource1Source1.getId(), 2162 expectedResource1Source2.getId(), 2163 expectedResource2Source1.getId(), 2164 expectedResource2Source2.getId())); 2165 assertThat(result).containsExactly(expectedResource1Source2, expectedResource2Source1); 2166 } 2167 2168 @Test 2169 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteMedicalResourcesByRequestWithPermChecks_appHasNotInsertedData_throws()2170 public void deleteMedicalResourcesByRequestWithPermChecks_appHasNotInsertedData_throws() { 2171 DeleteMedicalResourcesRequest request = 2172 new DeleteMedicalResourcesRequest.Builder().addDataSourceId(DATA_SOURCE_ID).build(); 2173 2174 assertThrows( 2175 IllegalArgumentException.class, 2176 () -> 2177 mMedicalResourceHelper.deleteMedicalResourcesByRequestWithPermissionChecks( 2178 request, "fake.package.com")); 2179 } 2180 2181 @Test 2182 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteMedicalResourcesByRequestWithPermChecks_singleDataSource_succeeds()2183 public void deleteMedicalResourcesByRequestWithPermChecks_singleDataSource_succeeds() { 2184 // Create two datasources, with one resource each. 2185 MedicalDataSource dataSource1 = 2186 mUtil.insertR4MedicalDataSource("ds1", DATA_SOURCE_PACKAGE_NAME); 2187 MedicalDataSource dataSource2 = 2188 mUtil.insertR4MedicalDataSource("ds2", DATA_SOURCE_PACKAGE_NAME); 2189 MedicalResource dataSource1Resource1 = 2190 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 2191 MedicalResource dataSource2Resource1 = 2192 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource2); 2193 MedicalResource dataSource1Resource2 = 2194 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource1); 2195 2196 // Delete all of the data for just the first datasource 2197 mMedicalResourceHelper.deleteMedicalResourcesByRequestWithPermissionChecks( 2198 new DeleteMedicalResourcesRequest.Builder() 2199 .addDataSourceId(dataSource1.getId()) 2200 .build(), 2201 DATA_SOURCE_PACKAGE_NAME); 2202 2203 // Test that the data for data source 1 is gone, but 2 is still present 2204 assertThat( 2205 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 2206 List.of( 2207 dataSource1Resource1.getId(), 2208 dataSource1Resource2.getId()))) 2209 .hasSize(0); 2210 assertThat( 2211 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 2212 List.of(dataSource2Resource1.getId()))) 2213 .hasSize(1); 2214 } 2215 2216 @Test 2217 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteMedicalResourcesByRequestWithPermChecks_multipleDataSources_succeeds()2218 public void deleteMedicalResourcesByRequestWithPermChecks_multipleDataSources_succeeds() { 2219 // Create three datasources, with one resource each. 2220 MedicalDataSource dataSource1 = 2221 mUtil.insertR4MedicalDataSource("ds1", DATA_SOURCE_PACKAGE_NAME); 2222 MedicalDataSource dataSource2 = 2223 mUtil.insertR4MedicalDataSource("ds2", DATA_SOURCE_PACKAGE_NAME); 2224 MedicalDataSource dataSource3 = 2225 mUtil.insertR4MedicalDataSource("ds3", DATA_SOURCE_PACKAGE_NAME); 2226 MedicalResource vaccineDS1 = 2227 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 2228 MedicalResource vaccineDS2 = 2229 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource2); 2230 MedicalResource vaccineDS3 = 2231 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource3); 2232 2233 // Delete all of the data for the first and second datasource 2234 mMedicalResourceHelper.deleteMedicalResourcesByRequestWithPermissionChecks( 2235 new DeleteMedicalResourcesRequest.Builder() 2236 .addDataSourceId(dataSource1.getId()) 2237 .addDataSourceId(dataSource2.getId()) 2238 .build(), 2239 DATA_SOURCE_PACKAGE_NAME); 2240 2241 // Test that the data for data source 1 and 2 is gone, but 3 is still present 2242 assertThat( 2243 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 2244 List.of(vaccineDS1.getId(), vaccineDS2.getId()))) 2245 .hasSize(0); 2246 assertThat( 2247 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 2248 List.of(vaccineDS3.getId()))) 2249 .hasSize(1); 2250 } 2251 2252 @Test 2253 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteMedicalResourcesByRequestWithPermChecks_singleType_succeeds()2254 public void deleteMedicalResourcesByRequestWithPermChecks_singleType_succeeds() { 2255 // Create two data sources, with one vaccine each and one extra allergy. 2256 MedicalDataSource dataSource1 = 2257 mUtil.insertR4MedicalDataSource("ds1", DATA_SOURCE_PACKAGE_NAME); 2258 MedicalDataSource dataSource2 = 2259 mUtil.insertR4MedicalDataSource("ds2", DATA_SOURCE_PACKAGE_NAME); 2260 MedicalResource vaccine1 = 2261 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 2262 MedicalResource vaccine2 = 2263 mUtil.upsertResource( 2264 PhrDataFactory::createDifferentVaccineMedicalResource, dataSource2); 2265 MedicalResource allergy = 2266 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource1); 2267 2268 // Delete all vaccines. 2269 mMedicalResourceHelper.deleteMedicalResourcesByRequestWithPermissionChecks( 2270 new DeleteMedicalResourcesRequest.Builder() 2271 .addMedicalResourceType(MEDICAL_RESOURCE_TYPE_VACCINES) 2272 .build(), 2273 DATA_SOURCE_PACKAGE_NAME); 2274 2275 // Test that only the allergy remains 2276 assertThat( 2277 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 2278 List.of(vaccine1.getId(), vaccine2.getId()))) 2279 .hasSize(0); 2280 assertThat( 2281 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 2282 List.of(allergy.getId()))) 2283 .hasSize(1); 2284 } 2285 2286 @Test 2287 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteMedicalResourcesByRequestWithPermChecks_multipleTypes_succeeds()2288 public void deleteMedicalResourcesByRequestWithPermChecks_multipleTypes_succeeds() { 2289 // Create two data sources, with one allergy and one vaccine each. 2290 MedicalDataSource dataSource1 = 2291 mUtil.insertR4MedicalDataSource("ds1", DATA_SOURCE_PACKAGE_NAME); 2292 MedicalDataSource dataSource2 = 2293 mUtil.insertR4MedicalDataSource("ds2", DATA_SOURCE_PACKAGE_NAME); 2294 MedicalResource vaccineDS1 = 2295 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 2296 MedicalResource vaccineDS2 = 2297 mUtil.upsertResource( 2298 PhrDataFactory::createDifferentVaccineMedicalResource, dataSource2); 2299 MedicalResource allergyDS1 = 2300 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource1); 2301 MedicalResource allergyDS2 = 2302 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource2); 2303 2304 // Delete all vaccines and allergies. 2305 mMedicalResourceHelper.deleteMedicalResourcesByRequestWithPermissionChecks( 2306 new DeleteMedicalResourcesRequest.Builder() 2307 .addMedicalResourceType(MEDICAL_RESOURCE_TYPE_VACCINES) 2308 .addMedicalResourceType(MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES) 2309 .build(), 2310 DATA_SOURCE_PACKAGE_NAME); 2311 2312 // Test that nothing remains 2313 assertThat( 2314 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 2315 List.of( 2316 vaccineDS1.getId(), 2317 vaccineDS2.getId(), 2318 allergyDS1.getId(), 2319 allergyDS2.getId()))) 2320 .isEmpty(); 2321 } 2322 2323 @Test 2324 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteMedicalResourcesByRequestWithPermChecks_byTypeAndDataSource_succeeds()2325 public void deleteMedicalResourcesByRequestWithPermChecks_byTypeAndDataSource_succeeds() { 2326 // Create two data sources, with one allergy and one vaccine each. 2327 MedicalDataSource dataSource1 = 2328 mUtil.insertR4MedicalDataSource("ds1", DATA_SOURCE_PACKAGE_NAME); 2329 MedicalDataSource dataSource2 = 2330 mUtil.insertR4MedicalDataSource("ds2", DATA_SOURCE_PACKAGE_NAME); 2331 MedicalResource vaccineDS1 = 2332 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 2333 MedicalResource vaccineDS2 = 2334 mUtil.upsertResource( 2335 PhrDataFactory::createDifferentVaccineMedicalResource, dataSource2); 2336 MedicalResource allergyDS1 = 2337 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource1); 2338 MedicalResource allergyDS2 = 2339 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource2); 2340 2341 // Delete data by vaccine and data source 1. 2342 mMedicalResourceHelper.deleteMedicalResourcesByRequestWithPermissionChecks( 2343 new DeleteMedicalResourcesRequest.Builder() 2344 .addDataSourceId(dataSource1.getId()) 2345 .addMedicalResourceType(MEDICAL_RESOURCE_TYPE_VACCINES) 2346 .build(), 2347 DATA_SOURCE_PACKAGE_NAME); 2348 2349 // Test that only one vaccine was deleted. 2350 assertThat( 2351 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 2352 List.of( 2353 vaccineDS2.getId(), 2354 allergyDS1.getId(), 2355 allergyDS2.getId()))) 2356 .hasSize(3); 2357 assertThat( 2358 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 2359 List.of(vaccineDS1.getId()))) 2360 .hasSize(0); 2361 } 2362 2363 @Test 2364 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteMedicalResourcesByRequestWithPermChecks_byDataSourceNoData_succeeds()2365 public void deleteMedicalResourcesByRequestWithPermChecks_byDataSourceNoData_succeeds() { 2366 MedicalDataSource dataSource1 = 2367 mUtil.insertR4MedicalDataSource("ds1", DATA_SOURCE_PACKAGE_NAME); 2368 2369 mMedicalResourceHelper.deleteMedicalResourcesByRequestWithPermissionChecks( 2370 new DeleteMedicalResourcesRequest.Builder() 2371 .addDataSourceId(dataSource1.getId()) 2372 .addDataSourceId(DIFFERENT_DATA_SOURCE_ID) 2373 .build(), 2374 DATA_SOURCE_PACKAGE_NAME); 2375 } 2376 2377 @Test 2378 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteMedicalResourcesByRequestWithPermChecks_byTypeNoData_succeeds()2379 public void deleteMedicalResourcesByRequestWithPermChecks_byTypeNoData_succeeds() { 2380 MedicalDataSource dataSource1 = 2381 mUtil.insertR4MedicalDataSource("ds1", DATA_SOURCE_PACKAGE_NAME); 2382 2383 mMedicalResourceHelper.deleteMedicalResourcesByRequestWithPermissionChecks( 2384 new DeleteMedicalResourcesRequest.Builder() 2385 .addMedicalResourceType(MEDICAL_RESOURCE_TYPE_VACCINES) 2386 .build(), 2387 DATA_SOURCE_PACKAGE_NAME); 2388 } 2389 2390 @Test 2391 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) 2392 public void deleteMedicalResourcesByRequestWithPermChecks_byTypeDataBelongsToOtherApp_noDelete()2393 deleteMedicalResourcesByRequestWithPermChecks_byTypeDataBelongsToOtherApp_noDelete() { 2394 MedicalDataSource dataSource = 2395 mUtil.insertR4MedicalDataSource("ds1", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 2396 MedicalResource vaccine = 2397 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource); 2398 2399 mMedicalResourceHelper.deleteMedicalResourcesByRequestWithPermissionChecks( 2400 new DeleteMedicalResourcesRequest.Builder() 2401 .addMedicalResourceType(MEDICAL_RESOURCE_TYPE_VACCINES) 2402 .build(), 2403 DATA_SOURCE_PACKAGE_NAME); 2404 2405 // Test that nothing was deleted 2406 assertThat( 2407 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 2408 List.of(vaccine.getId()))) 2409 .hasSize(1); 2410 } 2411 2412 @Test 2413 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) 2414 public void deleteMedicalResourcesByRequestWithPermChecks_bySourceDataBelongsToOtherApp_noDelete()2415 deleteMedicalResourcesByRequestWithPermChecks_bySourceDataBelongsToOtherApp_noDelete() { 2416 MedicalDataSource dataSource = 2417 mUtil.insertR4MedicalDataSource("ds1", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 2418 MedicalResource vaccine = 2419 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource); 2420 2421 mMedicalResourceHelper.deleteMedicalResourcesByRequestWithPermissionChecks( 2422 new DeleteMedicalResourcesRequest.Builder() 2423 .addDataSourceId(dataSource.getId()) 2424 .build(), 2425 DATA_SOURCE_PACKAGE_NAME); 2426 2427 // Test that nothing was deleted 2428 assertThat( 2429 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 2430 List.of(vaccine.getId()))) 2431 .hasSize(1); 2432 } 2433 2434 @Test 2435 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) 2436 public void deleteMedicalResourcesByRequestWithPermChecks_bySourceAndTypeOtherPackage_noDelete()2437 deleteMedicalResourcesByRequestWithPermChecks_bySourceAndTypeOtherPackage_noDelete() { 2438 MedicalDataSource dataSource = 2439 mUtil.insertR4MedicalDataSource("ds1", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 2440 MedicalResource vaccine = 2441 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource); 2442 2443 mMedicalResourceHelper.deleteMedicalResourcesByRequestWithPermissionChecks( 2444 new DeleteMedicalResourcesRequest.Builder() 2445 .addDataSourceId(dataSource.getId()) 2446 .addMedicalResourceType(MEDICAL_RESOURCE_TYPE_VACCINES) 2447 .build(), 2448 DATA_SOURCE_PACKAGE_NAME); 2449 2450 // Test that nothing was deleted 2451 assertThat( 2452 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 2453 List.of(vaccine.getId()))) 2454 .hasSize(1); 2455 } 2456 2457 @Test 2458 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteByRequestWithPermChecks_bothSourcesFromCallingPackage_expectAccessLogs()2459 public void deleteByRequestWithPermChecks_bothSourcesFromCallingPackage_expectAccessLogs() { 2460 MedicalDataSource dataSource1 = 2461 mUtil.insertR4MedicalDataSource("ds1", DATA_SOURCE_PACKAGE_NAME); 2462 MedicalDataSource dataSource2 = 2463 mUtil.insertR4MedicalDataSource("ds2", DATA_SOURCE_PACKAGE_NAME); 2464 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 2465 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource2); 2466 // Clear access logs table, so that only the access logs from delete will be present 2467 mAccessLogsHelper.clearData(mTransactionManager); 2468 2469 // Both created dataSources are from the same calling app. 2470 // So when the calling app deletes medicalResources from both those dataSources, 2471 // resourceTypes for both should be included in the accessLogs. 2472 mMedicalResourceHelper.deleteMedicalResourcesByRequestWithPermissionChecks( 2473 new DeleteMedicalResourcesRequest.Builder() 2474 .addDataSourceId(dataSource1.getId()) 2475 .addDataSourceId(dataSource2.getId()) 2476 .build(), 2477 /* callingPackageName= */ DATA_SOURCE_PACKAGE_NAME); 2478 2479 AccessLog deleteAccessLog = 2480 new AccessLog( 2481 DATA_SOURCE_PACKAGE_NAME, 2482 INSTANT_NOW.toEpochMilli(), 2483 OPERATION_TYPE_DELETE, 2484 /* medicalResourceTypes= */ Set.of( 2485 MEDICAL_RESOURCE_TYPE_VACCINES, 2486 MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES), 2487 /* isMedicalDataSourceAccessed= */ false); 2488 assertThat(mAccessLogsHelper.queryAccessLogs(mUserHandle)) 2489 .comparingElementsUsing(ACCESS_LOG_EQUIVALENCE) 2490 .containsExactly(deleteAccessLog); 2491 } 2492 2493 @Test 2494 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteByRequestWithPermChecks_dataSourcesFromDifferentPackages_expectAccessLogs()2495 public void deleteByRequestWithPermChecks_dataSourcesFromDifferentPackages_expectAccessLogs() { 2496 MedicalDataSource dataSource1 = 2497 mUtil.insertR4MedicalDataSource("ds1", DATA_SOURCE_PACKAGE_NAME); 2498 MedicalDataSource dataSource2 = 2499 mUtil.insertR4MedicalDataSource("ds2", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 2500 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 2501 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource2); 2502 // Clear access logs table, so that only the access logs from delete will be present 2503 mAccessLogsHelper.clearData(mTransactionManager); 2504 2505 // The created dataSources are from different calling apps. 2506 // When the first calling app tries to delete resources given both dataSources, 2507 // only the resources belonging to the dataSource of the calling app will 2508 // be deleted. So accessLogs are added only for the deleted resourceTypes which would 2509 // be resourceTypes belonging to dataSource1. 2510 mMedicalResourceHelper.deleteMedicalResourcesByRequestWithPermissionChecks( 2511 new DeleteMedicalResourcesRequest.Builder() 2512 .addDataSourceId(dataSource1.getId()) 2513 .addDataSourceId(dataSource2.getId()) 2514 .build(), 2515 /* callingPackageName= */ DATA_SOURCE_PACKAGE_NAME); 2516 2517 AccessLog deleteAccessLog = 2518 new AccessLog( 2519 DATA_SOURCE_PACKAGE_NAME, 2520 INSTANT_NOW.toEpochMilli(), 2521 OPERATION_TYPE_DELETE, 2522 /* medicalResourceTypes= */ Set.of(MEDICAL_RESOURCE_TYPE_VACCINES), 2523 /* isMedicalDataSourceAccessed= */ false); 2524 assertThat(mAccessLogsHelper.queryAccessLogs(mUserHandle)) 2525 .comparingElementsUsing(ACCESS_LOG_EQUIVALENCE) 2526 .containsExactly(deleteAccessLog); 2527 } 2528 2529 @Test 2530 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) 2531 public void deleteByRequestWithPermChecks_resourceTypesFromDifferentPackages_expectAccessLogs()2532 deleteByRequestWithPermChecks_resourceTypesFromDifferentPackages_expectAccessLogs() { 2533 MedicalDataSource dataSource1 = 2534 mUtil.insertR4MedicalDataSource("ds1", DATA_SOURCE_PACKAGE_NAME); 2535 MedicalDataSource dataSource2 = 2536 mUtil.insertR4MedicalDataSource("ds2", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 2537 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 2538 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource2); 2539 // Clear access logs table, so that only the access logs from delete will be present 2540 mAccessLogsHelper.clearData(mTransactionManager); 2541 2542 // The created resources are in data sources from different calling apps. 2543 // When the first calling app tries to delete resources given both resource types, 2544 // only the resources belonging to the calling app will be deleted. So accessLogs are added 2545 // only for the deleted resourceType. 2546 mMedicalResourceHelper.deleteMedicalResourcesByRequestWithPermissionChecks( 2547 new DeleteMedicalResourcesRequest.Builder() 2548 .addMedicalResourceType(MEDICAL_RESOURCE_TYPE_VACCINES) 2549 .addMedicalResourceType(MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES) 2550 .build(), 2551 /* callingPackageName= */ DATA_SOURCE_PACKAGE_NAME); 2552 2553 AccessLog deleteAccessLog = 2554 new AccessLog( 2555 DATA_SOURCE_PACKAGE_NAME, 2556 INSTANT_NOW.toEpochMilli(), 2557 OPERATION_TYPE_DELETE, 2558 /* medicalResourceTypes= */ Set.of(MEDICAL_RESOURCE_TYPE_VACCINES), 2559 /* isMedicalDataSourceAccessed= */ false); 2560 assertThat(mAccessLogsHelper.queryAccessLogs(mUserHandle)) 2561 .comparingElementsUsing(ACCESS_LOG_EQUIVALENCE) 2562 .containsExactly(deleteAccessLog); 2563 } 2564 2565 @Test 2566 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteByRequestWithPermChecks_resourcesTypesFromSamePackage_logsForAccessedTypes()2567 public void deleteByRequestWithPermChecks_resourcesTypesFromSamePackage_logsForAccessedTypes() { 2568 MedicalDataSource dataSource1 = 2569 mUtil.insertR4MedicalDataSource("ds1", DATA_SOURCE_PACKAGE_NAME); 2570 MedicalDataSource dataSource2 = 2571 mUtil.insertR4MedicalDataSource("ds2", DATA_SOURCE_PACKAGE_NAME); 2572 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource1); 2573 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 2574 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource2); 2575 // Clear access logs table, so that only the access logs from delete will be present 2576 mAccessLogsHelper.clearData(mTransactionManager); 2577 2578 mMedicalResourceHelper.deleteMedicalResourcesByRequestWithPermissionChecks( 2579 new DeleteMedicalResourcesRequest.Builder() 2580 .addMedicalResourceType(MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES) 2581 .build(), 2582 /* callingPackageName= */ DATA_SOURCE_PACKAGE_NAME); 2583 2584 AccessLog deleteAccessLog = 2585 new AccessLog( 2586 DATA_SOURCE_PACKAGE_NAME, 2587 INSTANT_NOW.toEpochMilli(), 2588 OPERATION_TYPE_DELETE, 2589 /* medicalResourceTypes= */ Set.of( 2590 MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES), 2591 /* isMedicalDataSourceAccessed= */ false); 2592 assertThat(mAccessLogsHelper.queryAccessLogs(mUserHandle)) 2593 .comparingElementsUsing(ACCESS_LOG_EQUIVALENCE) 2594 .containsExactly(deleteAccessLog); 2595 } 2596 2597 @Test 2598 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteByRequestWithPermChecks_expectAccessLogsForAccessedTypesAndSources_noMatch()2599 public void deleteByRequestWithPermChecks_expectAccessLogsForAccessedTypesAndSources_noMatch() { 2600 MedicalDataSource dataSource1 = 2601 mUtil.insertR4MedicalDataSource("ds1", DATA_SOURCE_PACKAGE_NAME); 2602 MedicalDataSource dataSource2 = 2603 mUtil.insertR4MedicalDataSource("ds2", DATA_SOURCE_PACKAGE_NAME); 2604 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 2605 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource2); 2606 // Clear access logs table, so that only the access logs from delete will be present 2607 mAccessLogsHelper.clearData(mTransactionManager); 2608 2609 mMedicalResourceHelper.deleteMedicalResourcesByRequestWithPermissionChecks( 2610 new DeleteMedicalResourcesRequest.Builder() 2611 .addDataSourceId(dataSource2.getId()) 2612 .addMedicalResourceType(MEDICAL_RESOURCE_TYPE_VACCINES) 2613 .build(), 2614 /* callingPackageName= */ DATA_SOURCE_PACKAGE_NAME); 2615 2616 assertThat(mAccessLogsHelper.queryAccessLogs(mUserHandle)).isEmpty(); 2617 } 2618 2619 @Test 2620 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteByRequestWithPermChecks_expectAccessLogsForAccessedTypesAndSources_logs()2621 public void deleteByRequestWithPermChecks_expectAccessLogsForAccessedTypesAndSources_logs() { 2622 MedicalDataSource dataSource1 = 2623 mUtil.insertR4MedicalDataSource("ds1", DATA_SOURCE_PACKAGE_NAME); 2624 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 2625 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource1); 2626 // Clear access logs table, so that only the access logs from delete will be present 2627 mAccessLogsHelper.clearData(mTransactionManager); 2628 2629 mMedicalResourceHelper.deleteMedicalResourcesByRequestWithPermissionChecks( 2630 new DeleteMedicalResourcesRequest.Builder() 2631 .addDataSourceId(dataSource1.getId()) 2632 .addMedicalResourceType(MEDICAL_RESOURCE_TYPE_VACCINES) 2633 .build(), 2634 /* callingPackageName= */ DATA_SOURCE_PACKAGE_NAME); 2635 2636 AccessLog deleteAccessLog = 2637 new AccessLog( 2638 DATA_SOURCE_PACKAGE_NAME, 2639 INSTANT_NOW.toEpochMilli(), 2640 OPERATION_TYPE_DELETE, 2641 /* medicalResourceTypes= */ Set.of(MEDICAL_RESOURCE_TYPE_VACCINES), 2642 /* isMedicalDataSourceAccessed= */ false); 2643 assertThat(mAccessLogsHelper.queryAccessLogs(mUserHandle)) 2644 .comparingElementsUsing(ACCESS_LOG_EQUIVALENCE) 2645 .containsExactly(deleteAccessLog); 2646 } 2647 2648 @Test 2649 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteByRequestWithPermChecks_noMatchingDataSources_noAccessLogsCreated()2650 public void deleteByRequestWithPermChecks_noMatchingDataSources_noAccessLogsCreated() { 2651 MedicalDataSource dataSource1 = 2652 mUtil.insertR4MedicalDataSource("ds1", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 2653 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 2654 // Clear access logs table, so that only the access logs from delete will be present 2655 mAccessLogsHelper.clearData(mTransactionManager); 2656 2657 mMedicalResourceHelper.deleteMedicalResourcesByRequestWithPermissionChecks( 2658 new DeleteMedicalResourcesRequest.Builder() 2659 .addDataSourceId(dataSource1.getId()) 2660 .build(), 2661 /* callingPackageName= */ DATA_SOURCE_PACKAGE_NAME); 2662 2663 assertThat(mAccessLogsHelper.queryAccessLogs(mUserHandle)).isEmpty(); 2664 } 2665 2666 @Test 2667 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteByRequestWithoutPermChecks_withoutPackageRestriction_noAccessLogsCreated()2668 public void deleteByRequestWithoutPermChecks_withoutPackageRestriction_noAccessLogsCreated() { 2669 MedicalDataSource dataSource1 = 2670 mUtil.insertR4MedicalDataSource("ds1", DATA_SOURCE_PACKAGE_NAME); 2671 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 2672 // Clear access logs table, so that only the access logs from delete will be present 2673 mAccessLogsHelper.clearData(mTransactionManager); 2674 2675 mMedicalResourceHelper.deleteMedicalResourcesByRequestWithoutPermissionChecks( 2676 new DeleteMedicalResourcesRequest.Builder() 2677 .addDataSourceId(dataSource1.getId()) 2678 .build()); 2679 2680 assertThat(mAccessLogsHelper.queryAccessLogs(mUserHandle)).isEmpty(); 2681 } 2682 2683 @Test 2684 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteMedicalResourcesByRequestWithoutPermsCheck_singleResourceType_succeeds()2685 public void deleteMedicalResourcesByRequestWithoutPermsCheck_singleResourceType_succeeds() { 2686 // Create two datasources, with one resource each. 2687 MedicalDataSource dataSource1 = 2688 mUtil.insertR4MedicalDataSource("ds1", DATA_SOURCE_PACKAGE_NAME); 2689 MedicalDataSource dataSource2 = 2690 mUtil.insertR4MedicalDataSource("ds2", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 2691 MedicalResource vaccineDS1 = 2692 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 2693 MedicalResource vaccineDS2 = 2694 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource2); 2695 MedicalResource allergyResource = 2696 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource1); 2697 2698 // Delete all of the data for just the first datasource 2699 mMedicalResourceHelper.deleteMedicalResourcesByRequestWithoutPermissionChecks( 2700 new DeleteMedicalResourcesRequest.Builder() 2701 .addMedicalResourceType(MEDICAL_RESOURCE_TYPE_VACCINES) 2702 .build()); 2703 2704 // Test that the data for the vaccines are gone, but the allergy is still present 2705 assertThat( 2706 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 2707 List.of(vaccineDS1.getId(), vaccineDS2.getId()))) 2708 .hasSize(0); 2709 assertThat( 2710 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 2711 List.of(allergyResource.getId()))) 2712 .hasSize(1); 2713 } 2714 2715 @Test 2716 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteMedicalResourcesByRequestWithoutPermsCheck_multipleSources_succeeds()2717 public void deleteMedicalResourcesByRequestWithoutPermsCheck_multipleSources_succeeds() { 2718 MedicalDataSource dataSource1 = 2719 mUtil.insertR4MedicalDataSource("ds1", DATA_SOURCE_PACKAGE_NAME); 2720 MedicalDataSource dataSource2 = 2721 mUtil.insertR4MedicalDataSource("ds2", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 2722 MedicalDataSource dataSource3 = 2723 mUtil.insertR4MedicalDataSource("ds3", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 2724 MedicalResource vaccineDS1 = 2725 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 2726 MedicalResource vaccineDS2 = 2727 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource2); 2728 MedicalResource vaccineDS3 = 2729 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource3); 2730 MedicalResource allergyDS1 = 2731 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource1); 2732 2733 // Delete data for data sources 1 and 2. 2734 mMedicalResourceHelper.deleteMedicalResourcesByRequestWithoutPermissionChecks( 2735 new DeleteMedicalResourcesRequest.Builder() 2736 .addDataSourceId(dataSource1.getId()) 2737 .addDataSourceId(dataSource2.getId()) 2738 .build()); 2739 2740 // Test that only data for data source 3 remains. 2741 assertThat( 2742 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 2743 List.of( 2744 vaccineDS1.getId(), 2745 vaccineDS2.getId(), 2746 allergyDS1.getId()))) 2747 .hasSize(0); 2748 assertThat( 2749 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 2750 List.of(vaccineDS3.getId()))) 2751 .hasSize(1); 2752 } 2753 2754 @Test 2755 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) deleteByRequestWithoutPermChecks_oneResourceTypeAndDataSource_succeeds()2756 public void deleteByRequestWithoutPermChecks_oneResourceTypeAndDataSource_succeeds() { 2757 // Create two data sources, with one resource each. 2758 MedicalDataSource dataSource1 = 2759 mUtil.insertR4MedicalDataSource("ds1", DATA_SOURCE_PACKAGE_NAME); 2760 MedicalDataSource dataSource2 = 2761 mUtil.insertR4MedicalDataSource("ds2", DATA_SOURCE_PACKAGE_NAME); 2762 MedicalResource vaccineDS1 = 2763 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 2764 MedicalResource vaccineDS2 = 2765 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource2); 2766 MedicalResource allergyDS1 = 2767 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource1); 2768 2769 // Delete all of the data for just data source 1. 2770 mMedicalResourceHelper.deleteMedicalResourcesByRequestWithoutPermissionChecks( 2771 new DeleteMedicalResourcesRequest.Builder() 2772 .addDataSourceId(dataSource1.getId()) 2773 .addMedicalResourceType(MEDICAL_RESOURCE_TYPE_VACCINES) 2774 .build()); 2775 2776 // Test that the data for the vaccines are gone, but the allergy is still present. 2777 assertThat( 2778 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 2779 List.of(vaccineDS1.getId()))) 2780 .hasSize(0); 2781 assertThat( 2782 mMedicalResourceHelper.readMedicalResourcesByIdsWithoutPermissionChecks( 2783 List.of(allergyDS1.getId(), vaccineDS2.getId()))) 2784 .hasSize(2); 2785 } 2786 2787 @Test 2788 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) testGetMedicalResourceTypeToContributingDataSourcesMap_success()2789 public void testGetMedicalResourceTypeToContributingDataSourcesMap_success() { 2790 // Create some data sources with data: ds1 contains [vaccine, differentVaccine, 2791 // allergy], ds2 contains [vaccine], and ds3 contains [allergy]. 2792 MedicalDataSource dataSource1 = 2793 mUtil.insertR4MedicalDataSource("ds1", DATA_SOURCE_PACKAGE_NAME); 2794 MedicalDataSource dataSource2 = 2795 mUtil.insertR4MedicalDataSource("ds2", DATA_SOURCE_PACKAGE_NAME); 2796 MedicalDataSource dataSource3 = 2797 mUtil.insertR4MedicalDataSource("ds3", DIFFERENT_DATA_SOURCE_PACKAGE_NAME); 2798 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource1); 2799 mUtil.upsertResource(PhrDataFactory::createDifferentVaccineMedicalResource, dataSource1); 2800 mUtil.upsertResource(PhrDataFactory::createVaccineMedicalResource, dataSource2); 2801 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource1); 2802 mUtil.upsertResource(PhrDataFactory::createAllergyMedicalResource, dataSource3); 2803 Instant lastDataUpdateTime = 2804 Instant.ofEpochMilli(mFakeTimeSource.getInstantNow().toEpochMilli()); 2805 MedicalDataSource expectedDataSource1 = 2806 new MedicalDataSource.Builder(dataSource1) 2807 .setLastDataUpdateTime(lastDataUpdateTime) 2808 .build(); 2809 MedicalDataSource expectedDataSource2 = 2810 new MedicalDataSource.Builder(dataSource2) 2811 .setLastDataUpdateTime(lastDataUpdateTime) 2812 .build(); 2813 MedicalDataSource expectedDataSource3 = 2814 new MedicalDataSource.Builder(dataSource3) 2815 .setLastDataUpdateTime(lastDataUpdateTime) 2816 .build(); 2817 2818 Map<Integer, Set<MedicalDataSource>> response = 2819 mMedicalResourceHelper.getMedicalResourceTypeToContributingDataSourcesMap(); 2820 2821 assertThat(response).hasSize(2); 2822 assertThat(response.keySet()) 2823 .containsExactly( 2824 MEDICAL_RESOURCE_TYPE_VACCINES, 2825 MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES); 2826 assertThat(response.get(MEDICAL_RESOURCE_TYPE_VACCINES)) 2827 .containsExactly(expectedDataSource1, expectedDataSource2); 2828 assertThat(response.get(MEDICAL_RESOURCE_TYPE_ALLERGIES_INTOLERANCES)) 2829 .containsExactly(expectedDataSource1, expectedDataSource3); 2830 } 2831 2832 @Test 2833 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) testGetMedicalResourceTypeToContributingDataSourcesMap_noDataSources_success()2834 public void testGetMedicalResourceTypeToContributingDataSourcesMap_noDataSources_success() { 2835 Map<Integer, Set<MedicalDataSource>> response = 2836 mMedicalResourceHelper.getMedicalResourceTypeToContributingDataSourcesMap(); 2837 2838 assertThat(response).isEmpty(); 2839 } 2840 2841 @Test 2842 @EnableFlags({Flags.FLAG_PERSONAL_HEALTH_RECORD_DATABASE, Flags.FLAG_PERSONAL_HEALTH_RECORD}) 2843 public void testGetMedicalResourceTypeToContributingDataSourcesMap_noMedicalResources_success()2844 testGetMedicalResourceTypeToContributingDataSourcesMap_noMedicalResources_success() { 2845 mUtil.insertR4MedicalDataSource("ds1", DATA_SOURCE_PACKAGE_NAME); 2846 2847 Map<Integer, Set<MedicalDataSource>> response = 2848 mMedicalResourceHelper.getMedicalResourceTypeToContributingDataSourcesMap(); 2849 2850 assertThat(response).isEmpty(); 2851 } 2852 2853 /** 2854 * Returns a UUID for the given triple {@code resourceId}, {@code resourceType} and {@code 2855 * dataSourceId}. 2856 */ makeMedicalResourceHexString(MedicalResourceId medicalResourceId)2857 private static String makeMedicalResourceHexString(MedicalResourceId medicalResourceId) { 2858 return getHexString( 2859 generateMedicalResourceUUID( 2860 medicalResourceId.getFhirResourceId(), 2861 medicalResourceId.getFhirResourceType(), 2862 medicalResourceId.getDataSourceId())); 2863 } 2864 readEntriesInMedicalResourceIndicesTable()2865 private List<Integer> readEntriesInMedicalResourceIndicesTable() { 2866 List<Integer> medicalResourceTypes = new ArrayList<>(); 2867 ReadTableRequest readTableRequest = new ReadTableRequest(getTableName()); 2868 try (Cursor cursor = mTransactionManager.read(readTableRequest)) { 2869 if (cursor.moveToFirst()) { 2870 do { 2871 medicalResourceTypes.add( 2872 getCursorInt(cursor, getMedicalResourceTypeColumnName())); 2873 } while (cursor.moveToNext()); 2874 } 2875 return medicalResourceTypes; 2876 } 2877 } 2878 getMedicalResourcesTableRowCount()2879 private int getMedicalResourcesTableRowCount() { 2880 ReadTableRequest readTableRequest = 2881 new ReadTableRequest(MedicalResourceHelper.getMainTableName()); 2882 try (Cursor cursor = mTransactionManager.read(readTableRequest)) { 2883 return cursor.getCount(); 2884 } 2885 } 2886 2887 /** 2888 * Creates a list of {@link UpsertMedicalResourceInternalRequest}s for the given list of {@link 2889 * MedicalResource}s and {@code dataSourceId}. 2890 */ createUpsertMedicalResourceRequests( List<MedicalResource> medicalResources, String dataSourceId)2891 private static List<UpsertMedicalResourceInternalRequest> createUpsertMedicalResourceRequests( 2892 List<MedicalResource> medicalResources, String dataSourceId) { 2893 List<UpsertMedicalResourceInternalRequest> requests = new ArrayList<>(); 2894 for (MedicalResource medicalResource : medicalResources) { 2895 FhirResource fhirResource = medicalResource.getFhirResource(); 2896 UpsertMedicalResourceInternalRequest request = 2897 new UpsertMedicalResourceInternalRequest() 2898 .setMedicalResourceType(medicalResource.getType()) 2899 .setFhirResourceId(fhirResource.getId()) 2900 .setFhirResourceType(fhirResource.getType()) 2901 .setFhirVersion(medicalResource.getFhirVersion()) 2902 .setData(fhirResource.getData()) 2903 .setDataSourceId(dataSourceId); 2904 requests.add(request); 2905 } 2906 return requests; 2907 } 2908 2909 /** 2910 * Returns the list of {@link AccessLog}s sorted based on the {@link AccessLog#getAccessTime()} 2911 * in an ascending order. 2912 */ sortByAccessTime(List<AccessLog> accessLogs)2913 private static List<AccessLog> sortByAccessTime(List<AccessLog> accessLogs) { 2914 return accessLogs.stream() 2915 .sorted(Comparator.comparing(AccessLog::getAccessTime)) 2916 .collect(Collectors.toList()); 2917 } 2918 joinLists(List<T>.... lists)2919 private static <T> List<T> joinLists(List<T>... lists) { 2920 return Stream.of(lists).flatMap(Collection::stream).collect(Collectors.toList()); 2921 } 2922 } 2923