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 android.healthconnect; 18 19 import static android.health.connect.datatypes.units.Length.fromMeters; 20 21 import static com.google.common.truth.Truth.assertThat; 22 23 import android.health.connect.datatypes.DataOrigin; 24 import android.health.connect.datatypes.Device; 25 import android.health.connect.datatypes.HeightRecord; 26 import android.health.connect.datatypes.Metadata; 27 import android.health.connect.datatypes.Record; 28 import android.health.connect.internal.ParcelUtils; 29 import android.health.connect.migration.MigrationEntity; 30 import android.health.connect.migration.MigrationEntityParcel; 31 import android.health.connect.migration.RecordMigrationPayload; 32 import android.os.Parcel; 33 34 import androidx.test.runner.AndroidJUnit4; 35 36 import org.junit.Test; 37 import org.junit.runner.RunWith; 38 39 import java.time.Instant; 40 import java.time.temporal.ChronoUnit; 41 import java.util.ArrayList; 42 import java.util.List; 43 import java.util.UUID; 44 45 @RunWith(AndroidJUnit4.class) 46 public class MigrationEntityParcelTest { 47 private static final String APP_PACKAGE_NAME = "android.healthconnect.cts.app"; 48 private static final String ENTITY_ID = "height"; 49 private static final Instant END_TIME = Instant.now().truncatedTo(ChronoUnit.MILLIS); 50 private static final HeightRecord HEIGHT_RECORD = 51 new HeightRecord.Builder( 52 getMetadata(ENTITY_ID, APP_PACKAGE_NAME), END_TIME, fromMeters(3D)) 53 .build(); 54 private static final MigrationEntity HEIGHT_MIGRATION_ENTITY = 55 getRecordEntity(HEIGHT_RECORD, ENTITY_ID); 56 57 @Test testMigrationEntityListParsing_usingParcel()58 public void testMigrationEntityListParsing_usingParcel() { 59 List<MigrationEntity> migrationEntityList = new ArrayList<>(); 60 migrationEntityList.add(HEIGHT_MIGRATION_ENTITY); 61 int migrationEntityListSize = migrationEntityList.size(); 62 MigrationEntityParcel heightMigrationEntityParcel = 63 new MigrationEntityParcel(migrationEntityList); 64 Parcel migrationEntityParcel = writeToParcel(heightMigrationEntityParcel); 65 migrationEntityParcel.setDataPosition(0); 66 67 MigrationEntityParcel deserializedMigrationEntityParcel = 68 MigrationEntityParcel.CREATOR.createFromParcel(migrationEntityParcel); 69 List<MigrationEntity> deserializedMigrationEntityList = 70 deserializedMigrationEntityParcel.getMigrationEntities(); 71 72 assertDeserializedListSize(migrationEntityListSize, deserializedMigrationEntityList); 73 assertDeserializedHeightRecord( 74 migrationEntityListSize, migrationEntityList, deserializedMigrationEntityList); 75 } 76 77 @Test testMigrationEntityListParsing_usingSharedMemory()78 public void testMigrationEntityListParsing_usingSharedMemory() { 79 int numRequiredEntities = getRequiredNumberOfEntities(); 80 List<MigrationEntity> migrationEntityList = new ArrayList<>(); 81 for (int i = 0; i < 2 * numRequiredEntities; i++) { 82 migrationEntityList.add(HEIGHT_MIGRATION_ENTITY); 83 } 84 int migrationEntityListSize = migrationEntityList.size(); 85 MigrationEntityParcel heightMigrationEntityParcel = 86 new MigrationEntityParcel(migrationEntityList); 87 Parcel migrationEntityParcel = writeToParcel(heightMigrationEntityParcel); 88 migrationEntityParcel.setDataPosition(0); 89 90 MigrationEntityParcel deserializedMigrationEntityParcel = 91 MigrationEntityParcel.CREATOR.createFromParcel(migrationEntityParcel); 92 List<MigrationEntity> deserializedMigrationEntityList = 93 deserializedMigrationEntityParcel.getMigrationEntities(); 94 95 assertDeserializedListSize(migrationEntityListSize, deserializedMigrationEntityList); 96 assertDeserializedHeightRecord( 97 migrationEntityListSize, migrationEntityList, deserializedMigrationEntityList); 98 } 99 100 @Test testParcelType_usingSharedMemory()101 public void testParcelType_usingSharedMemory() { 102 int numRequiredEntities = getRequiredNumberOfEntities(); 103 List<MigrationEntity> migrationEntityList = new ArrayList<>(); 104 for (int i = 0; i < 2 * numRequiredEntities; i++) { 105 migrationEntityList.add(HEIGHT_MIGRATION_ENTITY); 106 } 107 MigrationEntityParcel heightMigrationEntityParcel = 108 new MigrationEntityParcel(migrationEntityList); 109 Parcel migrationEntityParcel = writeToParcel(heightMigrationEntityParcel); 110 int parcelType = getParcelType(migrationEntityParcel); 111 112 assertThat(parcelType).isEqualTo(ParcelUtils.USING_SHARED_MEMORY); 113 } 114 115 @Test testParcelType_usingParcel()116 public void testParcelType_usingParcel() { 117 List<MigrationEntity> migrationEntityList = new ArrayList<>(); 118 migrationEntityList.add(HEIGHT_MIGRATION_ENTITY); 119 MigrationEntityParcel heightMigrationEntityParcel = 120 new MigrationEntityParcel(migrationEntityList); 121 Parcel migrationEntityParcel = writeToParcel(heightMigrationEntityParcel); 122 int parcelType = getParcelType(migrationEntityParcel); 123 124 assertThat(parcelType).isEqualTo(ParcelUtils.USING_PARCEL); 125 } 126 getMetadata(String clientRecordId, String packageName)127 private static Metadata getMetadata(String clientRecordId, String packageName) { 128 return new Metadata.Builder() 129 .setClientRecordId(clientRecordId) 130 .setId(UUID.randomUUID().toString()) 131 .setDataOrigin(new DataOrigin.Builder().setPackageName(packageName).build()) 132 .setDevice(new Device.Builder().setManufacturer("Device").setModel("Model").build()) 133 .build(); 134 } 135 getRecordEntity(Record record, String entityId)136 private static MigrationEntity getRecordEntity(Record record, String entityId) { 137 return new MigrationEntity( 138 entityId, 139 new RecordMigrationPayload.Builder( 140 record.getMetadata().getDataOrigin().getPackageName(), 141 "Example App", 142 record) 143 .build()); 144 } 145 146 /** Calculates the number of entities we need to cross the IPC_PARCEL_LIMIT threshold */ getRequiredNumberOfEntities()147 private static int getRequiredNumberOfEntities() { 148 Parcel migrationEntityRecordParcel = Parcel.obtain(); 149 HEIGHT_MIGRATION_ENTITY.getPayload().writeToParcel(migrationEntityRecordParcel, 0); 150 int migrationEntityDataParcelSize = migrationEntityRecordParcel.dataSize(); 151 return ParcelUtils.IPC_PARCEL_LIMIT / migrationEntityDataParcelSize; 152 } 153 writeToParcel(MigrationEntityParcel heightMigrationEntityParcel)154 private static Parcel writeToParcel(MigrationEntityParcel heightMigrationEntityParcel) { 155 Parcel migrationEntityParcel = Parcel.obtain(); 156 heightMigrationEntityParcel.writeToParcel(migrationEntityParcel, 0); 157 return migrationEntityParcel; 158 } 159 getParcelType(Parcel migrationEntityParcel)160 private static int getParcelType(Parcel migrationEntityParcel) { 161 migrationEntityParcel.setDataPosition(0); 162 int parcelType = migrationEntityParcel.readInt(); 163 migrationEntityParcel.recycle(); 164 return parcelType; 165 } 166 assertDeserializedListSize( int migrationEntityListSize, List<MigrationEntity> deserializedMigrationEntityList)167 private static void assertDeserializedListSize( 168 int migrationEntityListSize, List<MigrationEntity> deserializedMigrationEntityList) { 169 int deserializedMigrationEntityListSize = deserializedMigrationEntityList.size(); 170 assertThat(migrationEntityListSize).isEqualTo(deserializedMigrationEntityListSize); 171 } 172 assertDeserializedHeightRecord( int migrationEntityListSize, List<MigrationEntity> migrationEntityList, List<MigrationEntity> deserializedMigrationEntityList)173 private static void assertDeserializedHeightRecord( 174 int migrationEntityListSize, 175 List<MigrationEntity> migrationEntityList, 176 List<MigrationEntity> deserializedMigrationEntityList) { 177 for (int i = 0; i < migrationEntityListSize; i++) { 178 RecordMigrationPayload recordMigrationPayload = 179 (RecordMigrationPayload) migrationEntityList.get(i).getPayload(); 180 HeightRecord heightRecord = (HeightRecord) recordMigrationPayload.getRecord(); 181 182 RecordMigrationPayload deserializedRecordMigrationPayload = 183 (RecordMigrationPayload) deserializedMigrationEntityList.get(i).getPayload(); 184 HeightRecord deserializedHeightRecord = 185 (HeightRecord) deserializedRecordMigrationPayload.getRecord(); 186 187 assertThat(heightRecord).isEqualTo(deserializedHeightRecord); 188 } 189 } 190 } 191