|
@@ -240,6 +240,106 @@ void main() { |
|
@@ -240,6 +240,106 @@ void main() { |
|
240
|
expect(daily.single.uploaded, isFalse);
|
240
|
expect(daily.single.uploaded, isFalse);
|
|
241
|
});
|
241
|
});
|
|
242
|
|
242
|
|
|
|
|
243
|
+ test('daily stress marks uploaded after upload and resets today on calculate',
|
|
|
|
244
|
+ () async {
|
|
|
|
245
|
+ final now = DateTime.now();
|
|
|
|
246
|
+ final todayDate = now.year * 10000 + now.month * 100 + now.day;
|
|
|
|
247
|
+ final nowSeconds = now.millisecondsSinceEpoch ~/ 1000;
|
|
|
|
248
|
+ final store = _MemoryHealthRawStressLocalStore();
|
|
|
|
249
|
+ store.insertDailyStress(
|
|
|
|
250
|
+ HealthRawDailyStressPoint(
|
|
|
|
251
|
+ userId: 42,
|
|
|
|
252
|
+ date: todayDate,
|
|
|
|
253
|
+ stressValue: 40,
|
|
|
|
254
|
+ stressScore: 40,
|
|
|
|
255
|
+ state: HealthRawStressState.normal,
|
|
|
|
256
|
+ dataTime: nowSeconds,
|
|
|
|
257
|
+ ),
|
|
|
|
258
|
+ );
|
|
|
|
259
|
+
|
|
|
|
260
|
+ await store.markDailyStressUploadedUntil(userId: 42, date: todayDate);
|
|
|
|
261
|
+ var daily = await store.queryDailyStressPoints(
|
|
|
|
262
|
+ userId: 42,
|
|
|
|
263
|
+ startDate: todayDate,
|
|
|
|
264
|
+ endDate: todayDate,
|
|
|
|
265
|
+ );
|
|
|
|
266
|
+ expect(daily.single.uploaded, isTrue);
|
|
|
|
267
|
+
|
|
|
|
268
|
+ await store.upsertDailyStressPoints(
|
|
|
|
269
|
+ userId: 42,
|
|
|
|
270
|
+ points: [
|
|
|
|
271
|
+ HealthRawDailyStressPoint(
|
|
|
|
272
|
+ userId: 42,
|
|
|
|
273
|
+ date: todayDate,
|
|
|
|
274
|
+ stressValue: 40,
|
|
|
|
275
|
+ stressScore: 40,
|
|
|
|
276
|
+ state: HealthRawStressState.normal,
|
|
|
|
277
|
+ dataTime: nowSeconds + 1,
|
|
|
|
278
|
+ ),
|
|
|
|
279
|
+ ],
|
|
|
|
280
|
+ );
|
|
|
|
281
|
+ daily = await store.queryDailyStressPoints(
|
|
|
|
282
|
+ userId: 42,
|
|
|
|
283
|
+ startDate: todayDate,
|
|
|
|
284
|
+ endDate: todayDate,
|
|
|
|
285
|
+ );
|
|
|
|
286
|
+ expect(daily.single.uploaded, isFalse);
|
|
|
|
287
|
+ });
|
|
|
|
288
|
+
|
|
|
|
289
|
+ test('daily stress recalculates today before native upload', () async {
|
|
|
|
290
|
+ final operationLog = <String>[];
|
|
|
|
291
|
+ final now = DateTime.now();
|
|
|
|
292
|
+ final todayStart = DateTime(now.year, now.month, now.day);
|
|
|
|
293
|
+ final todayDate =
|
|
|
|
294
|
+ todayStart.year * 10000 + todayStart.month * 100 + todayStart.day;
|
|
|
|
295
|
+ final startSeconds = todayStart.millisecondsSinceEpoch ~/ 1000;
|
|
|
|
296
|
+ final api = _FakeHealthKitRawDataHostApi(operationLog: operationLog)
|
|
|
|
297
|
+ ..dailyStressUploadUntil = todayDate;
|
|
|
|
298
|
+ final store = _MemoryHealthRawStressLocalStore(operationLog: operationLog);
|
|
|
|
299
|
+ await store.upsertResult(
|
|
|
|
300
|
+ HealthRawStressCalculationResult(
|
|
|
|
301
|
+ userId: 42,
|
|
|
|
302
|
+ hrvStressPoints: const <HealthRawHrvStressPoint>[],
|
|
|
|
303
|
+ realtimeStressPoints: [
|
|
|
|
304
|
+ _realtimeStressPoint(startSeconds + 60),
|
|
|
|
305
|
+ _realtimeStressPoint(startSeconds + 120),
|
|
|
|
306
|
+ _realtimeStressPoint(startSeconds + 180),
|
|
|
|
307
|
+ ],
|
|
|
|
308
|
+ dailyStressPoints: const <HealthRawDailyStressPoint>[],
|
|
|
|
309
|
+ ),
|
|
|
|
310
|
+ );
|
|
|
|
311
|
+ store.insertDailyStress(
|
|
|
|
312
|
+ HealthRawDailyStressPoint(
|
|
|
|
313
|
+ userId: 42,
|
|
|
|
314
|
+ date: todayDate,
|
|
|
|
315
|
+ stressValue: 30,
|
|
|
|
316
|
+ stressScore: 30,
|
|
|
|
317
|
+ state: HealthRawStressState.normal,
|
|
|
|
318
|
+ dataTime: startSeconds,
|
|
|
|
319
|
+ uploaded: true,
|
|
|
|
320
|
+ ),
|
|
|
|
321
|
+ );
|
|
|
|
322
|
+ final service = HealthRawDataCoreService(
|
|
|
|
323
|
+ healthApi: _FakeHealthKitHostApi(),
|
|
|
|
324
|
+ rawDataApi: api,
|
|
|
|
325
|
+ localStore: store,
|
|
|
|
326
|
+ userIdProvider: () => 42,
|
|
|
|
327
|
+ );
|
|
|
|
328
|
+
|
|
|
|
329
|
+ await service.startCoreCaculate(
|
|
|
|
330
|
+ endTime: startSeconds + 240,
|
|
|
|
331
|
+ readChunkDays: 1,
|
|
|
|
332
|
+ );
|
|
|
|
333
|
+
|
|
|
|
334
|
+ expect(
|
|
|
|
335
|
+ operationLog.indexOf('upsertDailyStressPoints'),
|
|
|
|
336
|
+ lessThan(operationLog.indexOf('performAvgRealtimeStressDataUpload')),
|
|
|
|
337
|
+ );
|
|
|
|
338
|
+ expect(api.dailyStressUploadCallCount, 1);
|
|
|
|
339
|
+ final rows = await store.debugQueryAllRows(42);
|
|
|
|
340
|
+ expect(rows.dailyStressRows.single['uploaded'], 1);
|
|
|
|
341
|
+ });
|
|
|
|
342
|
+
|
|
243
|
test('same calculated rows keep uploaded state', () async {
|
343
|
test('same calculated rows keep uploaded state', () async {
|
|
244
|
final store = _MemoryHealthRawStressLocalStore();
|
344
|
final store = _MemoryHealthRawStressLocalStore();
|
|
245
|
const uploadedDaily = HealthRawDailyStressPoint(
|
345
|
const uploadedDaily = HealthRawDailyStressPoint(
|
|
@@ -414,6 +514,77 @@ void main() { |
|
@@ -414,6 +514,77 @@ void main() { |
|
414
|
expect(rows.sleepRows.single['uploaded'], 1);
|
514
|
expect(rows.sleepRows.single['uploaded'], 1);
|
|
415
|
});
|
515
|
});
|
|
416
|
|
516
|
|
|
|
|
517
|
+ test(
|
|
|
|
518
|
+ 'startCoreCaculate uploads pending rows even when no new data calculates',
|
|
|
|
519
|
+ () async {
|
|
|
|
520
|
+ const base = 1800000000;
|
|
|
|
521
|
+ final oldDate = DateTime.fromMillisecondsSinceEpoch(base * 1000);
|
|
|
|
522
|
+ final oldDateKey = oldDate.year * 10000 + oldDate.month * 100 + oldDate.day;
|
|
|
|
523
|
+ final api = _FakeHealthKitRawDataHostApi()
|
|
|
|
524
|
+ ..hrvUploadUntil = base + 10
|
|
|
|
525
|
+ ..hrUploadUntil = base + 20
|
|
|
|
526
|
+ ..dailyStressUploadUntil = oldDateKey
|
|
|
|
527
|
+ ..sleepUploadUntil = base + 30;
|
|
|
|
528
|
+ final store = _MemoryHealthRawStressLocalStore();
|
|
|
|
529
|
+ await store.upsertResult(
|
|
|
|
530
|
+ HealthRawStressCalculationResult(
|
|
|
|
531
|
+ userId: 42,
|
|
|
|
532
|
+ hrvStressPoints: [_hrvStressPoint(base + 10)],
|
|
|
|
533
|
+ realtimeStressPoints: [_realtimeStressPoint(base + 20)],
|
|
|
|
534
|
+ dailyStressPoints: const <HealthRawDailyStressPoint>[],
|
|
|
|
535
|
+ ),
|
|
|
|
536
|
+ );
|
|
|
|
537
|
+ store.insertDailyStress(
|
|
|
|
538
|
+ HealthRawDailyStressPoint(
|
|
|
|
539
|
+ userId: 42,
|
|
|
|
540
|
+ date: oldDateKey,
|
|
|
|
541
|
+ stressValue: 40,
|
|
|
|
542
|
+ stressScore: 40,
|
|
|
|
543
|
+ state: HealthRawStressState.normal,
|
|
|
|
544
|
+ dataTime: base + 20,
|
|
|
|
545
|
+ ),
|
|
|
|
546
|
+ );
|
|
|
|
547
|
+ await store.upsertSleepResults(
|
|
|
|
548
|
+ userId: 42,
|
|
|
|
549
|
+ results: const [
|
|
|
|
550
|
+ HealthRawSleepResult(
|
|
|
|
551
|
+ userId: 42,
|
|
|
|
552
|
+ date: base + 30,
|
|
|
|
553
|
+ startDate: base,
|
|
|
|
554
|
+ sleepScore: 80,
|
|
|
|
555
|
+ sleepState: 2,
|
|
|
|
556
|
+ inBedMinutes: 500,
|
|
|
|
557
|
+ awakMinutes: 20,
|
|
|
|
558
|
+ sleepMinutes: 480,
|
|
|
|
559
|
+ ),
|
|
|
|
560
|
+ ],
|
|
|
|
561
|
+ );
|
|
|
|
562
|
+ final service = HealthRawDataCoreService(
|
|
|
|
563
|
+ healthApi: _FakeHealthKitHostApi(),
|
|
|
|
564
|
+ rawDataApi: api,
|
|
|
|
565
|
+ localStore: store,
|
|
|
|
566
|
+ userIdProvider: () => 42,
|
|
|
|
567
|
+ );
|
|
|
|
568
|
+
|
|
|
|
569
|
+ final result = await service.startCoreCaculate(
|
|
|
|
570
|
+ endTime: base + 40,
|
|
|
|
571
|
+ readChunkDays: 1,
|
|
|
|
572
|
+ );
|
|
|
|
573
|
+ final rows = await store.debugQueryAllRows(42);
|
|
|
|
574
|
+
|
|
|
|
575
|
+ expect(result.hrvStressPoints, isEmpty);
|
|
|
|
576
|
+ expect(result.realtimeStressPoints, isEmpty);
|
|
|
|
577
|
+ expect(result.sleepResults, isEmpty);
|
|
|
|
578
|
+ expect(api.hrvUploadCallCount, 1);
|
|
|
|
579
|
+ expect(api.hrUploadCallCount, 1);
|
|
|
|
580
|
+ expect(api.dailyStressUploadCallCount, 1);
|
|
|
|
581
|
+ expect(api.sleepUploadCallCount, 1);
|
|
|
|
582
|
+ expect(rows.hrvRows.single['uploaded'], 1);
|
|
|
|
583
|
+ expect(rows.realtimeRows.single['uploaded'], 1);
|
|
|
|
584
|
+ expect(rows.dailyStressRows.single['uploaded'], 1);
|
|
|
|
585
|
+ expect(rows.sleepRows.single['uploaded'], 1);
|
|
|
|
586
|
+ });
|
|
|
|
587
|
+
|
|
417
|
test('local data source returns earliest local hr start time', () async {
|
588
|
test('local data source returns earliest local hr start time', () async {
|
|
418
|
const base = 1800000000;
|
589
|
const base = 1800000000;
|
|
419
|
final api = _FakeHealthKitRawDataHostApi();
|
590
|
final api = _FakeHealthKitRawDataHostApi();
|
|
@@ -472,14 +643,40 @@ HealthRawRealtimeStressPoint _realtimeStressPoint(int time) { |
|
@@ -472,14 +643,40 @@ HealthRawRealtimeStressPoint _realtimeStressPoint(int time) { |
|
472
|
);
|
643
|
);
|
|
473
|
}
|
644
|
}
|
|
474
|
|
645
|
|
|
|
|
646
|
+HealthRawHrvStressPoint _hrvStressPoint(int time) {
|
|
|
|
647
|
+ return HealthRawHrvStressPoint(
|
|
|
|
648
|
+ userId: 42,
|
|
|
|
649
|
+ rawEndTime: time,
|
|
|
|
650
|
+ rawHrv: 30,
|
|
|
|
651
|
+ result: 30,
|
|
|
|
652
|
+ sourceStartTime: time,
|
|
|
|
653
|
+ sourceEndTime: time,
|
|
|
|
654
|
+ state: HealthRawStressState.normal,
|
|
|
|
655
|
+ baselineHrv: 30,
|
|
|
|
656
|
+ baselineAwakeHrv: 30,
|
|
|
|
657
|
+ baselineSleepHrv: null,
|
|
|
|
658
|
+ baselineRestingHr: 60,
|
|
|
|
659
|
+ );
|
|
|
|
660
|
+}
|
|
|
|
661
|
+
|
|
475
|
class _FakeHealthKitRawDataHostApi extends HealthKitRawDataHostApi {
|
662
|
class _FakeHealthKitRawDataHostApi extends HealthKitRawDataHostApi {
|
|
|
|
663
|
+ _FakeHealthKitRawDataHostApi({List<String>? operationLog})
|
|
|
|
664
|
+ : operationLog = operationLog ?? <String>[];
|
|
|
|
665
|
+
|
|
476
|
final Map<int, List<HealthKitRawDataPoint>> _pointsByType = {};
|
666
|
final Map<int, List<HealthKitRawDataPoint>> _pointsByType = {};
|
|
477
|
final List<HealthKitRawWorkoutDataPoint> _workoutPoints = [];
|
667
|
final List<HealthKitRawWorkoutDataPoint> _workoutPoints = [];
|
|
478
|
final List<HealthKitRawDataPoint> _sleepPoints = [];
|
668
|
final List<HealthKitRawDataPoint> _sleepPoints = [];
|
|
479
|
final List<_ReadCall> calls = [];
|
669
|
final List<_ReadCall> calls = [];
|
|
|
|
670
|
+ final List<String> operationLog;
|
|
480
|
var sleepCallCount = 0;
|
671
|
var sleepCallCount = 0;
|
|
481
|
var workoutCallCount = 0;
|
672
|
var workoutCallCount = 0;
|
|
|
|
673
|
+ var hrUploadCallCount = 0;
|
|
|
|
674
|
+ var hrvUploadCallCount = 0;
|
|
|
|
675
|
+ var dailyStressUploadCallCount = 0;
|
|
482
|
var sleepUploadCallCount = 0;
|
676
|
var sleepUploadCallCount = 0;
|
|
|
|
677
|
+ var hrUploadUntil = 0;
|
|
|
|
678
|
+ var hrvUploadUntil = 0;
|
|
|
|
679
|
+ var dailyStressUploadUntil = 0;
|
|
483
|
var sleepUploadUntil = 0;
|
680
|
var sleepUploadUntil = 0;
|
|
484
|
var hasData = true;
|
681
|
var hasData = true;
|
|
485
|
|
682
|
|
|
@@ -519,16 +716,25 @@ class _FakeHealthKitRawDataHostApi extends HealthKitRawDataHostApi { |
|
@@ -519,16 +716,25 @@ class _FakeHealthKitRawDataHostApi extends HealthKitRawDataHostApi { |
|
519
|
}
|
716
|
}
|
|
520
|
|
717
|
|
|
521
|
@override
|
718
|
@override
|
|
522
|
- Future<int> performHRDataUpload({required String sqliteFilePath}) async => 0;
|
719
|
+ Future<int> performHRDataUpload({required String sqliteFilePath}) async {
|
|
|
|
720
|
+ hrUploadCallCount += 1;
|
|
|
|
721
|
+ return hrUploadUntil;
|
|
|
|
722
|
+ }
|
|
523
|
|
723
|
|
|
524
|
@override
|
724
|
@override
|
|
525
|
- Future<int> performHRVDataUpload({required String sqliteFilePath}) async => 0;
|
725
|
+ Future<int> performHRVDataUpload({required String sqliteFilePath}) async {
|
|
|
|
726
|
+ hrvUploadCallCount += 1;
|
|
|
|
727
|
+ return hrvUploadUntil;
|
|
|
|
728
|
+ }
|
|
526
|
|
729
|
|
|
527
|
@override
|
730
|
@override
|
|
528
|
Future<int> performAvgRealtimeStressDataUpload({
|
731
|
Future<int> performAvgRealtimeStressDataUpload({
|
|
529
|
required String sqliteFilePath,
|
732
|
required String sqliteFilePath,
|
|
530
|
- }) async =>
|
|
|
|
531
|
- 0;
|
733
|
+ }) async {
|
|
|
|
734
|
+ operationLog.add('performAvgRealtimeStressDataUpload');
|
|
|
|
735
|
+ dailyStressUploadCallCount += 1;
|
|
|
|
736
|
+ return dailyStressUploadUntil;
|
|
|
|
737
|
+ }
|
|
532
|
|
738
|
|
|
533
|
@override
|
739
|
@override
|
|
534
|
Future<int> performSleepAnalysisDataUpload({
|
740
|
Future<int> performSleepAnalysisDataUpload({
|
|
@@ -588,11 +794,14 @@ class _ReadCall { |
|
@@ -588,11 +794,14 @@ class _ReadCall { |
|
588
|
}
|
794
|
}
|
|
589
|
|
795
|
|
|
590
|
class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore {
|
796
|
class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore {
|
|
|
|
797
|
+ _MemoryHealthRawStressLocalStore({List<String>? operationLog})
|
|
|
|
798
|
+ : operationLog = operationLog ?? <String>[];
|
|
|
|
799
|
+
|
|
591
|
final Map<int, List<HealthRawHrvStressPoint>> _hrv = {};
|
800
|
final Map<int, List<HealthRawHrvStressPoint>> _hrv = {};
|
|
592
|
final Map<int, List<HealthRawRealtimeStressPoint>> _realtime = {};
|
801
|
final Map<int, List<HealthRawRealtimeStressPoint>> _realtime = {};
|
|
593
|
final Map<int, List<HealthRawDailyStressPoint>> _daily = {};
|
802
|
final Map<int, List<HealthRawDailyStressPoint>> _daily = {};
|
|
594
|
final Map<int, List<HealthRawSleepResult>> _sleep = {};
|
803
|
final Map<int, List<HealthRawSleepResult>> _sleep = {};
|
|
595
|
- final List<String> operationLog = [];
|
804
|
+ final List<String> operationLog;
|
|
596
|
|
805
|
|
|
597
|
void insertDailyStress(HealthRawDailyStressPoint point) {
|
806
|
void insertDailyStress(HealthRawDailyStressPoint point) {
|
|
598
|
final byDate = <int, HealthRawDailyStressPoint>{
|
807
|
final byDate = <int, HealthRawDailyStressPoint>{
|
|
@@ -683,6 +892,7 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore { |
|
@@ -683,6 +892,7 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore { |
|
683
|
existing.stressValue == point.stressValue &&
|
892
|
existing.stressValue == point.stressValue &&
|
|
684
|
existing.stressScore == point.stressScore &&
|
893
|
existing.stressScore == point.stressScore &&
|
|
685
|
existing.state == point.state;
|
894
|
existing.state == point.state;
|
|
|
|
895
|
+ final isToday = point.date == _todayDateKey();
|
|
686
|
byDate[point.date] = HealthRawDailyStressPoint(
|
896
|
byDate[point.date] = HealthRawDailyStressPoint(
|
|
687
|
userId: point.userId,
|
897
|
userId: point.userId,
|
|
688
|
date: point.date,
|
898
|
date: point.date,
|
|
@@ -690,7 +900,7 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore { |
|
@@ -690,7 +900,7 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore { |
|
690
|
stressScore: point.stressScore,
|
900
|
stressScore: point.stressScore,
|
|
691
|
state: point.state,
|
901
|
state: point.state,
|
|
692
|
dataTime: point.dataTime,
|
902
|
dataTime: point.dataTime,
|
|
693
|
- uploaded: same ? existing.uploaded : false,
|
903
|
+ uploaded: isToday ? false : (same ? existing.uploaded : false),
|
|
694
|
);
|
904
|
);
|
|
695
|
}
|
905
|
}
|
|
696
|
_daily[userId] = byDate.values.toList()
|
906
|
_daily[userId] = byDate.values.toList()
|
|
@@ -737,6 +947,14 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore { |
|
@@ -737,6 +947,14 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore { |
|
737
|
}
|
947
|
}
|
|
738
|
|
948
|
|
|
739
|
@override
|
949
|
@override
|
|
|
|
950
|
+ Future<void> clearTables(int userId) async {
|
|
|
|
951
|
+ _hrv.remove(userId);
|
|
|
|
952
|
+ _realtime.remove(userId);
|
|
|
|
953
|
+ _daily.remove(userId);
|
|
|
|
954
|
+ _sleep.remove(userId);
|
|
|
|
955
|
+ }
|
|
|
|
956
|
+
|
|
|
|
957
|
+ @override
|
|
740
|
Future<List<HealthRawHrvStressPoint>> queryHrvStressPoints({
|
958
|
Future<List<HealthRawHrvStressPoint>> queryHrvStressPoints({
|
|
741
|
required int userId,
|
959
|
required int userId,
|
|
742
|
required int startTime,
|
960
|
required int startTime,
|
|
@@ -1068,4 +1286,9 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore { |
|
@@ -1068,4 +1286,9 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore { |
|
1068
|
'uploaded': result.uploaded ? 1 : 0,
|
1286
|
'uploaded': result.uploaded ? 1 : 0,
|
|
1069
|
};
|
1287
|
};
|
|
1070
|
}
|
1288
|
}
|
|
|
|
1289
|
+
|
|
|
|
1290
|
+ int _todayDateKey() {
|
|
|
|
1291
|
+ final now = DateTime.now();
|
|
|
|
1292
|
+ return now.year * 10000 + now.month * 100 + now.day;
|
|
|
|
1293
|
+ }
|
|
1071
|
} |
1294
|
} |