• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.healthconnect.cts;
18 
19 import static android.health.connect.datatypes.PowerRecord.POWER_AVG;
20 import static android.health.connect.datatypes.PowerRecord.POWER_MAX;
21 import static android.health.connect.datatypes.PowerRecord.POWER_MIN;
22 
23 import static com.google.common.truth.Truth.assertThat;
24 
25 import android.content.Context;
26 import android.health.connect.AggregateRecordsRequest;
27 import android.health.connect.AggregateRecordsResponse;
28 import android.health.connect.DeleteUsingFiltersRequest;
29 import android.health.connect.HealthConnectException;
30 import android.health.connect.ReadRecordsRequestUsingFilters;
31 import android.health.connect.ReadRecordsRequestUsingIds;
32 import android.health.connect.RecordIdFilter;
33 import android.health.connect.TimeInstantRangeFilter;
34 import android.health.connect.changelog.ChangeLogTokenRequest;
35 import android.health.connect.changelog.ChangeLogTokenResponse;
36 import android.health.connect.changelog.ChangeLogsRequest;
37 import android.health.connect.changelog.ChangeLogsResponse;
38 import android.health.connect.datatypes.DataOrigin;
39 import android.health.connect.datatypes.Device;
40 import android.health.connect.datatypes.Metadata;
41 import android.health.connect.datatypes.PowerRecord;
42 import android.health.connect.datatypes.Record;
43 import android.health.connect.datatypes.units.Power;
44 import android.platform.test.annotations.AppModeFull;
45 
46 import androidx.test.core.app.ApplicationProvider;
47 import androidx.test.runner.AndroidJUnit4;
48 
49 import org.junit.After;
50 import org.junit.Assert;
51 import org.junit.Before;
52 import org.junit.Test;
53 import org.junit.runner.RunWith;
54 
55 import java.time.Instant;
56 import java.time.ZoneOffset;
57 import java.time.temporal.ChronoUnit;
58 import java.util.ArrayList;
59 import java.util.Arrays;
60 import java.util.Collections;
61 import java.util.List;
62 import java.util.Set;
63 import java.util.UUID;
64 
65 @AppModeFull(reason = "HealthConnectManager is not accessible to instant apps")
66 @RunWith(AndroidJUnit4.class)
67 public class PowerRecordTest {
68     private static final String TAG = "PowerRecordTest";
69 
70     @Before
setUp()71     public void setUp() {
72         // TODO(b/283737434): Update the HC code to use user aware context on permission change.
73         // Temporary fix to set firstGrantTime for the correct user in HSUM.
74         TestUtils.deleteAllStagedRemoteData();
75     }
76 
77     @After
tearDown()78     public void tearDown() throws InterruptedException {
79         TestUtils.verifyDeleteRecords(
80                 PowerRecord.class,
81                 new TimeInstantRangeFilter.Builder()
82                         .setStartTime(Instant.EPOCH)
83                         .setEndTime(Instant.now())
84                         .build());
85         TestUtils.deleteAllStagedRemoteData();
86     }
87 
88     @Test
testInsertPowerRecord()89     public void testInsertPowerRecord() throws InterruptedException {
90         TestUtils.insertRecords(Arrays.asList(getBasePowerRecord(), getCompletePowerRecord()));
91     }
92 
93     @Test
testReadPowerRecord_usingIds()94     public void testReadPowerRecord_usingIds() throws InterruptedException {
95         testReadPowerRecordIds();
96     }
97 
98     @Test
testReadPowerRecord_invalidIds()99     public void testReadPowerRecord_invalidIds() throws InterruptedException {
100         ReadRecordsRequestUsingIds<PowerRecord> request =
101                 new ReadRecordsRequestUsingIds.Builder<>(PowerRecord.class)
102                         .addId(UUID.randomUUID().toString())
103                         .build();
104         List<PowerRecord> result = TestUtils.readRecords(request);
105         assertThat(result.size()).isEqualTo(0);
106     }
107 
108     @Test
testReadPowerRecord_usingClientRecordIds()109     public void testReadPowerRecord_usingClientRecordIds() throws InterruptedException {
110         List<Record> recordList = Arrays.asList(getCompletePowerRecord(), getCompletePowerRecord());
111         List<Record> insertedRecords = TestUtils.insertRecords(recordList);
112         readPowerRecordUsingClientId(insertedRecords);
113     }
114 
115     @Test
testReadPowerRecord_invalidClientRecordIds()116     public void testReadPowerRecord_invalidClientRecordIds() throws InterruptedException {
117         ReadRecordsRequestUsingIds<PowerRecord> request =
118                 new ReadRecordsRequestUsingIds.Builder<>(PowerRecord.class)
119                         .addClientRecordId("abc")
120                         .build();
121         List<PowerRecord> result = TestUtils.readRecords(request);
122         assertThat(result.size()).isEqualTo(0);
123     }
124 
125     @Test
testReadPowerRecordUsingFilters_default()126     public void testReadPowerRecordUsingFilters_default() throws InterruptedException {
127         List<PowerRecord> oldPowerRecords =
128                 TestUtils.readRecords(
129                         new ReadRecordsRequestUsingFilters.Builder<>(PowerRecord.class).build());
130         PowerRecord testRecord = getCompletePowerRecord();
131         TestUtils.insertRecords(Collections.singletonList(testRecord));
132         List<PowerRecord> newPowerRecords =
133                 TestUtils.readRecords(
134                         new ReadRecordsRequestUsingFilters.Builder<>(PowerRecord.class).build());
135         assertThat(newPowerRecords.size()).isEqualTo(oldPowerRecords.size() + 1);
136         assertThat(newPowerRecords.get(newPowerRecords.size() - 1).equals(testRecord)).isTrue();
137     }
138 
139     @Test
testReadPowerRecordUsingFilters_timeFilter()140     public void testReadPowerRecordUsingFilters_timeFilter() throws InterruptedException {
141         TimeInstantRangeFilter filter =
142                 new TimeInstantRangeFilter.Builder()
143                         .setStartTime(Instant.now())
144                         .setEndTime(Instant.now().plusMillis(3000))
145                         .build();
146         PowerRecord testRecord = getCompletePowerRecord();
147         TestUtils.insertRecords(Collections.singletonList(testRecord));
148         List<PowerRecord> newPowerRecords =
149                 TestUtils.readRecords(
150                         new ReadRecordsRequestUsingFilters.Builder<>(PowerRecord.class)
151                                 .setTimeRangeFilter(filter)
152                                 .build());
153         assertThat(newPowerRecords.get(newPowerRecords.size() - 1).equals(testRecord)).isTrue();
154     }
155 
156     @Test
testReadPowerRecordUsingFilters_dataFilter_correct()157     public void testReadPowerRecordUsingFilters_dataFilter_correct() throws InterruptedException {
158         Context context = ApplicationProvider.getApplicationContext();
159         List<PowerRecord> oldPowerRecords =
160                 TestUtils.readRecords(
161                         new ReadRecordsRequestUsingFilters.Builder<>(PowerRecord.class)
162                                 .addDataOrigins(
163                                         new DataOrigin.Builder()
164                                                 .setPackageName(context.getPackageName())
165                                                 .build())
166                                 .build());
167         PowerRecord testRecord = getCompletePowerRecord();
168         TestUtils.insertRecords(Collections.singletonList(testRecord));
169         List<PowerRecord> newPowerRecords =
170                 TestUtils.readRecords(
171                         new ReadRecordsRequestUsingFilters.Builder<>(PowerRecord.class)
172                                 .addDataOrigins(
173                                         new DataOrigin.Builder()
174                                                 .setPackageName(context.getPackageName())
175                                                 .build())
176                                 .build());
177         assertThat(newPowerRecords.size() - oldPowerRecords.size()).isEqualTo(1);
178         assertThat(newPowerRecords.get(newPowerRecords.size() - 1).equals(testRecord)).isTrue();
179         PowerRecord newRecord = newPowerRecords.get(newPowerRecords.size() - 1);
180         assertThat(newRecord.equals(testRecord)).isTrue();
181         for (int idx = 0; idx < newRecord.getSamples().size(); idx++) {
182             assertThat(newRecord.getSamples().get(idx).getTime().toEpochMilli())
183                     .isEqualTo(testRecord.getSamples().get(idx).getTime().toEpochMilli());
184             assertThat(newRecord.getSamples().get(idx).getPower())
185                     .isEqualTo(testRecord.getSamples().get(idx).getPower());
186         }
187     }
188 
189     @Test
testReadPowerRecordUsingFilters_dataFilter_incorrect()190     public void testReadPowerRecordUsingFilters_dataFilter_incorrect() throws InterruptedException {
191         TestUtils.insertRecords(Collections.singletonList(getCompletePowerRecord()));
192         List<PowerRecord> newPowerRecords =
193                 TestUtils.readRecords(
194                         new ReadRecordsRequestUsingFilters.Builder<>(PowerRecord.class)
195                                 .addDataOrigins(
196                                         new DataOrigin.Builder().setPackageName("abc").build())
197                                 .build());
198         assertThat(newPowerRecords.size()).isEqualTo(0);
199     }
200 
201     @Test
testDeletePowerRecord_no_filters()202     public void testDeletePowerRecord_no_filters() throws InterruptedException {
203         String id = TestUtils.insertRecordAndGetId(getCompletePowerRecord());
204         TestUtils.verifyDeleteRecords(new DeleteUsingFiltersRequest.Builder().build());
205         TestUtils.assertRecordNotFound(id, PowerRecord.class);
206     }
207 
208     @Test
testDeletePowerRecord_time_filters()209     public void testDeletePowerRecord_time_filters() throws InterruptedException {
210         TimeInstantRangeFilter timeRangeFilter =
211                 new TimeInstantRangeFilter.Builder()
212                         .setStartTime(Instant.now())
213                         .setEndTime(Instant.now().plusMillis(1000))
214                         .build();
215         String id = TestUtils.insertRecordAndGetId(getCompletePowerRecord());
216         TestUtils.verifyDeleteRecords(
217                 new DeleteUsingFiltersRequest.Builder()
218                         .addRecordType(PowerRecord.class)
219                         .setTimeRangeFilter(timeRangeFilter)
220                         .build());
221         TestUtils.assertRecordNotFound(id, PowerRecord.class);
222     }
223 
224     @Test
testDeletePowerRecord_recordId_filters()225     public void testDeletePowerRecord_recordId_filters() throws InterruptedException {
226         List<Record> records = List.of(getBasePowerRecord(), getCompletePowerRecord());
227         TestUtils.insertRecords(records);
228 
229         for (Record record : records) {
230             TestUtils.verifyDeleteRecords(
231                     new DeleteUsingFiltersRequest.Builder()
232                             .addRecordType(record.getClass())
233                             .build());
234             TestUtils.assertRecordNotFound(record.getMetadata().getId(), record.getClass());
235         }
236     }
237 
238     @Test
testDeletePowerRecord_dataOrigin_filters()239     public void testDeletePowerRecord_dataOrigin_filters() throws InterruptedException {
240         Context context = ApplicationProvider.getApplicationContext();
241         String id = TestUtils.insertRecordAndGetId(getCompletePowerRecord());
242         TestUtils.verifyDeleteRecords(
243                 new DeleteUsingFiltersRequest.Builder()
244                         .addDataOrigin(
245                                 new DataOrigin.Builder()
246                                         .setPackageName(context.getPackageName())
247                                         .build())
248                         .build());
249         TestUtils.assertRecordNotFound(id, PowerRecord.class);
250     }
251 
252     @Test
testDeletePowerRecord_dataOrigin_filter_incorrect()253     public void testDeletePowerRecord_dataOrigin_filter_incorrect() throws InterruptedException {
254         String id = TestUtils.insertRecordAndGetId(getCompletePowerRecord());
255         TestUtils.verifyDeleteRecords(
256                 new DeleteUsingFiltersRequest.Builder()
257                         .addDataOrigin(new DataOrigin.Builder().setPackageName("abc").build())
258                         .build());
259         TestUtils.assertRecordFound(id, PowerRecord.class);
260     }
261 
262     @Test
testDeletePowerRecord_usingIds()263     public void testDeletePowerRecord_usingIds() throws InterruptedException {
264         List<Record> records = List.of(getBasePowerRecord(), getCompletePowerRecord());
265         List<Record> insertedRecord = TestUtils.insertRecords(records);
266         List<RecordIdFilter> recordIds = new ArrayList<>(records.size());
267         for (Record record : insertedRecord) {
268             recordIds.add(RecordIdFilter.fromId(record.getClass(), record.getMetadata().getId()));
269         }
270 
271         TestUtils.verifyDeleteRecords(recordIds);
272         for (Record record : records) {
273             TestUtils.assertRecordNotFound(record.getMetadata().getId(), record.getClass());
274         }
275     }
276 
277     @Test
testDeletePowerRecord_time_range()278     public void testDeletePowerRecord_time_range() throws InterruptedException {
279         TimeInstantRangeFilter timeRangeFilter =
280                 new TimeInstantRangeFilter.Builder()
281                         .setStartTime(Instant.now())
282                         .setEndTime(Instant.now().plusMillis(1000))
283                         .build();
284         String id = TestUtils.insertRecordAndGetId(getCompletePowerRecord());
285         TestUtils.verifyDeleteRecords(PowerRecord.class, timeRangeFilter);
286         TestUtils.assertRecordNotFound(id, PowerRecord.class);
287     }
288 
289     @Test
testAggregation_power()290     public void testAggregation_power() throws Exception {
291         Context context = ApplicationProvider.getApplicationContext();
292         List<Record> records =
293                 Arrays.asList(getPowerRecord(5.0), getPowerRecord(10.0), getPowerRecord(15.0));
294         AggregateRecordsResponse<Power> response =
295                 TestUtils.getAggregateResponse(
296                         new AggregateRecordsRequest.Builder<Power>(
297                                         new TimeInstantRangeFilter.Builder()
298                                                 .setStartTime(Instant.ofEpochMilli(0))
299                                                 .setEndTime(Instant.now().plus(1, ChronoUnit.DAYS))
300                                                 .build())
301                                 .addAggregationType(POWER_MAX)
302                                 .addAggregationType(POWER_MIN)
303                                 .addAggregationType(POWER_AVG)
304                                 .addDataOriginsFilter(
305                                         new DataOrigin.Builder()
306                                                 .setPackageName(context.getPackageName())
307                                                 .build())
308                                 .build(),
309                         records);
310         Power maxPower = response.get(POWER_MAX);
311         Power minPower = response.get(POWER_MIN);
312         Power avgPower = response.get(POWER_AVG);
313         assertThat(maxPower).isNotNull();
314         assertThat(maxPower.getInWatts()).isEqualTo(15.0);
315         assertThat(minPower).isNotNull();
316         assertThat(minPower.getInWatts()).isEqualTo(5.0);
317         assertThat(avgPower).isNotNull();
318         assertThat(avgPower.getInWatts()).isEqualTo(10.0);
319         Set<DataOrigin> newDataOrigin = response.getDataOrigins(POWER_AVG);
320         for (DataOrigin itr : newDataOrigin) {
321             assertThat(itr.getPackageName()).isEqualTo("android.healthconnect.cts");
322         }
323     }
324 
325     @Test
testZoneOffsets()326     public void testZoneOffsets() {
327         final ZoneOffset defaultZoneOffset =
328                 ZoneOffset.systemDefault().getRules().getOffset(Instant.now());
329         final ZoneOffset startZoneOffset = ZoneOffset.UTC;
330         final ZoneOffset endZoneOffset = ZoneOffset.MAX;
331         PowerRecord.Builder builder =
332                 new PowerRecord.Builder(
333                         new Metadata.Builder().build(),
334                         Instant.now(),
335                         Instant.now().plusMillis(1000),
336                         Collections.emptyList());
337 
338         assertThat(builder.setStartZoneOffset(startZoneOffset).build().getStartZoneOffset())
339                 .isEqualTo(startZoneOffset);
340         assertThat(builder.setEndZoneOffset(endZoneOffset).build().getEndZoneOffset())
341                 .isEqualTo(endZoneOffset);
342         assertThat(builder.clearStartZoneOffset().build().getStartZoneOffset())
343                 .isEqualTo(defaultZoneOffset);
344         assertThat(builder.clearEndZoneOffset().build().getEndZoneOffset())
345                 .isEqualTo(defaultZoneOffset);
346     }
347 
348     @Test
testUpdateRecords_validInput_dataBaseUpdatedSuccessfully()349     public void testUpdateRecords_validInput_dataBaseUpdatedSuccessfully()
350             throws InterruptedException {
351 
352         List<Record> insertedRecords =
353                 TestUtils.insertRecords(
354                         Arrays.asList(getCompletePowerRecord(), getCompletePowerRecord()));
355 
356         // read inserted records and verify that the data is same as inserted.
357         readPowerRecordUsingIds(insertedRecords);
358 
359         // Generate a new set of records that will be used to perform the update operation.
360         List<Record> updateRecords =
361                 Arrays.asList(getCompletePowerRecord(), getCompletePowerRecord());
362 
363         // Modify the uid of the updateRecords to the uuid that was present in the insert records.
364         for (int itr = 0; itr < updateRecords.size(); itr++) {
365             updateRecords.set(
366                     itr,
367                     getPowerRecord_update(
368                             updateRecords.get(itr),
369                             insertedRecords.get(itr).getMetadata().getId(),
370                             insertedRecords.get(itr).getMetadata().getClientRecordId()));
371         }
372 
373         TestUtils.updateRecords(updateRecords);
374 
375         // assert the inserted data has been modified by reading the data.
376         readPowerRecordUsingIds(updateRecords);
377     }
378 
379     @Test
testUpdateRecords_invalidInputRecords_noChangeInDataBase()380     public void testUpdateRecords_invalidInputRecords_noChangeInDataBase()
381             throws InterruptedException {
382         List<Record> insertedRecords =
383                 TestUtils.insertRecords(
384                         Arrays.asList(getCompletePowerRecord(), getCompletePowerRecord()));
385 
386         // read inserted records and verify that the data is same as inserted.
387         readPowerRecordUsingIds(insertedRecords);
388 
389         // Generate a second set of records that will be used to perform the update operation.
390         List<Record> updateRecords =
391                 Arrays.asList(getCompletePowerRecord(), getCompletePowerRecord());
392 
393         // Modify the Uid of the updateRecords to the UUID that was present in the insert records,
394         // leaving out alternate records so that they have a new UUID which is not present in the
395         // dataBase.
396         for (int itr = 0; itr < updateRecords.size(); itr++) {
397             updateRecords.set(
398                     itr,
399                     getPowerRecord_update(
400                             updateRecords.get(itr),
401                             itr % 2 == 0
402                                     ? insertedRecords.get(itr).getMetadata().getId()
403                                     : UUID.randomUUID().toString(),
404                             itr % 2 == 0
405                                     ? insertedRecords.get(itr).getMetadata().getId()
406                                     : UUID.randomUUID().toString()));
407         }
408 
409         try {
410             TestUtils.updateRecords(updateRecords);
411             Assert.fail("Expected to fail due to invalid records ids.");
412         } catch (HealthConnectException exception) {
413             assertThat(exception.getErrorCode())
414                     .isEqualTo(HealthConnectException.ERROR_INVALID_ARGUMENT);
415         }
416 
417         // assert the inserted data has not been modified by reading the data.
418         readPowerRecordUsingIds(insertedRecords);
419     }
420 
421     @Test
testUpdateRecords_recordWithInvalidPackageName_noChangeInDataBase()422     public void testUpdateRecords_recordWithInvalidPackageName_noChangeInDataBase()
423             throws InterruptedException {
424         List<Record> insertedRecords =
425                 TestUtils.insertRecords(
426                         Arrays.asList(getCompletePowerRecord(), getCompletePowerRecord()));
427 
428         // read inserted records and verify that the data is same as inserted.
429         readPowerRecordUsingIds(insertedRecords);
430 
431         // Generate a second set of records that will be used to perform the update operation.
432         List<Record> updateRecords =
433                 Arrays.asList(getCompletePowerRecord(), getCompletePowerRecord());
434 
435         // Modify the Uuid of the updateRecords to the uuid that was present in the insert records.
436         for (int itr = 0; itr < updateRecords.size(); itr++) {
437             updateRecords.set(
438                     itr,
439                     getPowerRecord_update(
440                             updateRecords.get(itr),
441                             insertedRecords.get(itr).getMetadata().getId(),
442                             insertedRecords.get(itr).getMetadata().getClientRecordId()));
443             //             adding an entry with invalid packageName.
444             updateRecords.set(itr, getCompletePowerRecord());
445         }
446 
447         try {
448             TestUtils.updateRecords(updateRecords);
449             Assert.fail("Expected to fail due to invalid package.");
450         } catch (Exception exception) {
451             // verify that the testcase failed due to invalid argument exception.
452             assertThat(exception).isNotNull();
453         }
454 
455         // assert the inserted data has not been modified by reading the data.
456         readPowerRecordUsingIds(insertedRecords);
457     }
458 
459     @Test
testInsertAndDeleteRecord_changelogs()460     public void testInsertAndDeleteRecord_changelogs() throws InterruptedException {
461         Context context = ApplicationProvider.getApplicationContext();
462         ChangeLogTokenResponse tokenResponse =
463                 TestUtils.getChangeLogToken(
464                         new ChangeLogTokenRequest.Builder()
465                                 .addDataOriginFilter(
466                                         new DataOrigin.Builder()
467                                                 .setPackageName(context.getPackageName())
468                                                 .build())
469                                 .addRecordType(PowerRecord.class)
470                                 .build());
471         ChangeLogsRequest changeLogsRequest =
472                 new ChangeLogsRequest.Builder(tokenResponse.getToken()).build();
473         ChangeLogsResponse response = TestUtils.getChangeLogs(changeLogsRequest);
474         assertThat(response.getUpsertedRecords().size()).isEqualTo(0);
475         assertThat(response.getDeletedLogs().size()).isEqualTo(0);
476 
477         List<Record> testRecord = Collections.singletonList(getCompletePowerRecord());
478         TestUtils.insertRecords(testRecord);
479         response = TestUtils.getChangeLogs(changeLogsRequest);
480         assertThat(response.getUpsertedRecords().size()).isEqualTo(1);
481         assertThat(
482                         response.getUpsertedRecords().stream()
483                                 .map(Record::getMetadata)
484                                 .map(Metadata::getId)
485                                 .toList())
486                 .containsExactlyElementsIn(
487                         testRecord.stream().map(Record::getMetadata).map(Metadata::getId).toList());
488         assertThat(response.getDeletedLogs().size()).isEqualTo(0);
489 
490         TestUtils.verifyDeleteRecords(
491                 new DeleteUsingFiltersRequest.Builder().addRecordType(PowerRecord.class).build());
492         response = TestUtils.getChangeLogs(changeLogsRequest);
493         assertThat(response.getDeletedLogs()).isEmpty();
494     }
495 
testReadPowerRecordIds()496     private void testReadPowerRecordIds() throws InterruptedException {
497         List<Record> recordList = Arrays.asList(getCompletePowerRecord(), getCompletePowerRecord());
498         readPowerRecordUsingIds(recordList);
499     }
500 
readPowerRecordUsingClientId(List<Record> insertedRecord)501     private void readPowerRecordUsingClientId(List<Record> insertedRecord)
502             throws InterruptedException {
503         ReadRecordsRequestUsingIds.Builder<PowerRecord> request =
504                 new ReadRecordsRequestUsingIds.Builder<>(PowerRecord.class);
505         for (Record record : insertedRecord) {
506             request.addClientRecordId(record.getMetadata().getClientRecordId());
507         }
508         List<PowerRecord> result = TestUtils.readRecords(request.build());
509         assertThat(result.size()).isEqualTo(insertedRecord.size());
510         assertThat(result).containsExactlyElementsIn(insertedRecord);
511     }
512 
readPowerRecordUsingIds(List<Record> recordList)513     private void readPowerRecordUsingIds(List<Record> recordList) throws InterruptedException {
514         List<Record> insertedRecords = TestUtils.insertRecords(recordList);
515         ReadRecordsRequestUsingIds.Builder<PowerRecord> request =
516                 new ReadRecordsRequestUsingIds.Builder<>(PowerRecord.class);
517         for (Record record : insertedRecords) {
518             request.addId(record.getMetadata().getId());
519         }
520         ReadRecordsRequestUsingIds requestUsingIds = request.build();
521         assertThat(requestUsingIds.getRecordType()).isEqualTo(PowerRecord.class);
522         assertThat(requestUsingIds.getRecordIdFilters()).isNotNull();
523         List<PowerRecord> result = TestUtils.readRecords(requestUsingIds);
524         assertThat(result).hasSize(insertedRecords.size());
525         assertThat(result.containsAll(insertedRecords)).isTrue();
526     }
527 
528     @Test(expected = IllegalArgumentException.class)
testCreatePowerRecord_invalidValue()529     public void testCreatePowerRecord_invalidValue() {
530         new PowerRecord.PowerRecordSample(Power.fromWatts(100001.0), Instant.now().plusMillis(100));
531     }
532 
getPowerRecord_update(Record record, String id, String clientRecordId)533     PowerRecord getPowerRecord_update(Record record, String id, String clientRecordId) {
534         Metadata metadata = record.getMetadata();
535         Metadata metadataWithId =
536                 new Metadata.Builder()
537                         .setId(id)
538                         .setClientRecordId(clientRecordId)
539                         .setClientRecordVersion(metadata.getClientRecordVersion())
540                         .setDataOrigin(metadata.getDataOrigin())
541                         .setDevice(metadata.getDevice())
542                         .setLastModifiedTime(metadata.getLastModifiedTime())
543                         .build();
544 
545         PowerRecord.PowerRecordSample powerRecordSample =
546                 new PowerRecord.PowerRecordSample(
547                         Power.fromWatts(8.0), Instant.now().plusMillis(100));
548 
549         return new PowerRecord.Builder(
550                         metadataWithId,
551                         Instant.now(),
552                         Instant.now().plusMillis(2000),
553                         List.of(powerRecordSample, powerRecordSample))
554                 .setStartZoneOffset(ZoneOffset.systemDefault().getRules().getOffset(Instant.now()))
555                 .setEndZoneOffset(ZoneOffset.systemDefault().getRules().getOffset(Instant.now()))
556                 .build();
557     }
558 
getBasePowerRecord()559     private static PowerRecord getBasePowerRecord() {
560         PowerRecord.PowerRecordSample powerRecord =
561                 new PowerRecord.PowerRecordSample(
562                         Power.fromWatts(10.0), Instant.now().plusMillis(100));
563         ArrayList<PowerRecord.PowerRecordSample> powerRecords = new ArrayList<>();
564         powerRecords.add(powerRecord);
565         powerRecords.add(powerRecord);
566 
567         return new PowerRecord.Builder(
568                         new Metadata.Builder().build(),
569                         Instant.now(),
570                         Instant.now().plusMillis(1000),
571                         powerRecords)
572                 .build();
573     }
574 
getPowerRecord(double power)575     static PowerRecord getPowerRecord(double power) {
576         PowerRecord.PowerRecordSample powerRecord =
577                 new PowerRecord.PowerRecordSample(
578                         Power.fromWatts(power), Instant.now().plusMillis(100));
579         ArrayList<PowerRecord.PowerRecordSample> powerRecords = new ArrayList<>();
580         powerRecords.add(powerRecord);
581         powerRecords.add(powerRecord);
582 
583         return new PowerRecord.Builder(
584                         new Metadata.Builder().setClientRecordId("PR" + Math.random()).build(),
585                         Instant.now(),
586                         Instant.now().plusMillis(1000),
587                         powerRecords)
588                 .build();
589     }
590 
getCompletePowerRecord()591     private static PowerRecord getCompletePowerRecord() {
592 
593         Device device =
594                 new Device.Builder()
595                         .setManufacturer("google")
596                         .setModel("Pixel4a")
597                         .setType(2)
598                         .build();
599         DataOrigin dataOrigin =
600                 new DataOrigin.Builder().setPackageName("android.healthconnect.cts").build();
601         Metadata.Builder testMetadataBuilder = new Metadata.Builder();
602         testMetadataBuilder.setDevice(device).setDataOrigin(dataOrigin);
603         testMetadataBuilder.setClientRecordId("PR" + Math.random());
604         testMetadataBuilder.setRecordingMethod(Metadata.RECORDING_METHOD_ACTIVELY_RECORDED);
605 
606         PowerRecord.PowerRecordSample powerRecord =
607                 new PowerRecord.PowerRecordSample(
608                         Power.fromWatts(10.0), Instant.now().plusMillis(100));
609 
610         ArrayList<PowerRecord.PowerRecordSample> powerRecords = new ArrayList<>();
611         powerRecords.add(powerRecord);
612         powerRecords.add(powerRecord);
613 
614         return new PowerRecord.Builder(
615                         testMetadataBuilder.build(),
616                         Instant.now(),
617                         Instant.now().plusMillis(1000),
618                         powerRecords)
619                 .build();
620     }
621 }
622