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