mirror of
https://github.com/google/pebble.git
synced 2025-07-03 05:46:21 +00:00
Import of the watch repository from Pebble
This commit is contained in:
commit
3b92768480
10334 changed files with 2564465 additions and 0 deletions
291
tests/fw/test_alarm_smart.c
Normal file
291
tests/fw/test_alarm_smart.c
Normal file
|
@ -0,0 +1,291 @@
|
|||
/*
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "test_alarm_common.h"
|
||||
|
||||
// Fakes
|
||||
#include "fake_rtc.h"
|
||||
#include "fake_new_timer.h"
|
||||
|
||||
#include "stubs_blob_db_sync.h"
|
||||
#include "stubs_blob_db_sync_util.h"
|
||||
|
||||
static int s_rand = 0;
|
||||
|
||||
int rand(void) {
|
||||
// There are no odds
|
||||
return s_rand;
|
||||
}
|
||||
|
||||
static ActivitySleepState s_sleep_state = ActivitySleepStateAwake;
|
||||
static uint16_t s_sleep_state_seconds = 0;
|
||||
static uint16_t s_last_vmc = 0;
|
||||
|
||||
bool activity_tracking_on(void) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool activity_get_metric(ActivityMetric metric, uint32_t history_len, int32_t *history) {
|
||||
cl_assert_equal_i(history_len, 1);
|
||||
if (metric == ActivityMetricSleepState) {
|
||||
*history = s_sleep_state;
|
||||
return true;
|
||||
} else if (metric == ActivityMetricSleepStateSeconds) {
|
||||
*history = s_sleep_state_seconds;
|
||||
return true;
|
||||
} else if (metric == ActivityMetricLastVMC) {
|
||||
*history = s_last_vmc;
|
||||
return true;
|
||||
}
|
||||
|
||||
cl_assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//! Helper Functions
|
||||
|
||||
static void prv_set_time(time_t day, int hour, int minute) {
|
||||
s_current_day = day;
|
||||
s_current_hour = hour;
|
||||
s_current_minute = minute;
|
||||
rtc_set_time(day + prv_hours_and_minutes_to_seconds(hour, minute));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//! Setup
|
||||
|
||||
void test_alarm_smart__initialize(void) {
|
||||
s_num_timeline_adds = 0;
|
||||
s_num_timeline_removes = 0;
|
||||
s_num_alarm_events_put = 0;
|
||||
s_num_alarms_fired = 0;
|
||||
s_last_vmc = 0;
|
||||
s_rand = 0;
|
||||
|
||||
// Setup time
|
||||
TimezoneInfo tz_info = {
|
||||
.tm_zone = "UTC",
|
||||
};
|
||||
time_util_update_timezone(&tz_info);
|
||||
rtc_set_timezone(&tz_info);
|
||||
|
||||
// Default to Thursday
|
||||
prv_set_time(s_thursday, 0, 0);
|
||||
|
||||
timeline_item_destroy(s_last_timeline_item_added);
|
||||
s_last_timeline_item_added = NULL;
|
||||
s_last_timeline_item_removed_uuid = (Uuid) {};
|
||||
|
||||
fake_spi_flash_init(0, 0x1000000);
|
||||
pfs_init(false);
|
||||
pfs_format(false);
|
||||
|
||||
cron_service_init();
|
||||
|
||||
alarm_init();
|
||||
alarm_service_enable_alarms(true);
|
||||
}
|
||||
|
||||
void test_alarm_smart__cleanup(void) {
|
||||
cron_service_deinit();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//! Smart alarms
|
||||
|
||||
#define SMART_ALARM_UPDATE_MIN (SMART_ALARM_SNOOZE_DELAY_S / SECONDS_PER_MINUTE)
|
||||
|
||||
void test_alarm_smart__trigger_30_min_early_awake(void) {
|
||||
AlarmId id;
|
||||
id = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 30, .kind = ALARM_KIND_EVERYDAY, .is_smart = true });
|
||||
prv_assert_alarm_config(id, 10, 30, false, ALARM_KIND_EVERYDAY, s_every_day_schedule);
|
||||
cl_assert_equal_i(s_num_timeline_adds, 3);
|
||||
cl_assert_equal_i(s_num_timeline_removes, 0);
|
||||
|
||||
// Set sleep status
|
||||
s_sleep_state = ActivitySleepStateAwake;
|
||||
s_sleep_state_seconds = 0;
|
||||
s_last_vmc = 0;
|
||||
|
||||
time_t next_alarm_time;
|
||||
alarm_get_next_enabled_alarm(&next_alarm_time);
|
||||
cl_assert_equal_i(next_alarm_time,
|
||||
s_current_day + 10 * SECONDS_PER_HOUR + 30 * SECONDS_PER_MINUTE);
|
||||
|
||||
// Don't trigger too early
|
||||
prv_set_time(s_current_day, 9, 49);
|
||||
cron_service_wakeup();
|
||||
cl_assert_equal_i(s_num_alarms_fired, 0);
|
||||
cl_assert_equal_i(s_num_alarm_events_put, 0);
|
||||
|
||||
// Trigger at the right time
|
||||
prv_set_time(s_current_day, 10, 0);
|
||||
cron_service_wakeup();
|
||||
cl_assert_equal_i(s_num_alarms_fired, 1);
|
||||
cl_assert_equal_i(s_num_alarm_events_put, 1);
|
||||
cl_assert_equal_i(s_num_timeline_adds, 6);
|
||||
cl_assert_equal_i(s_num_timeline_removes, 3);
|
||||
cl_assert_equal_i(s_last_timeline_item_added->header.timestamp, rtc_get_time());
|
||||
}
|
||||
|
||||
void test_alarm_smart__trigger_30_min_early_vmc(void) {
|
||||
AlarmId id;
|
||||
id = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 30, .kind = ALARM_KIND_EVERYDAY, .is_smart = true });
|
||||
prv_assert_alarm_config(id, 10, 30, false, ALARM_KIND_EVERYDAY, s_every_day_schedule);
|
||||
cl_assert_equal_i(s_num_timeline_adds, 3);
|
||||
cl_assert_equal_i(s_num_timeline_removes, 0);
|
||||
|
||||
s_sleep_state = ActivitySleepStateLightSleep;
|
||||
s_last_vmc = 1;
|
||||
prv_set_time(s_current_day, 10, 0);
|
||||
cron_service_wakeup();
|
||||
cl_assert_equal_i(s_num_alarms_fired, 1);
|
||||
cl_assert_equal_i(s_num_alarm_events_put, 1);
|
||||
cl_assert_equal_i(s_last_timeline_item_added->header.timestamp, rtc_get_time());
|
||||
}
|
||||
|
||||
void test_alarm_smart__dont_trigger_30_min_early_deep_sleep(void) {
|
||||
AlarmId id;
|
||||
id = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 30, .kind = ALARM_KIND_EVERYDAY, .is_smart = true });
|
||||
prv_assert_alarm_config(id, 10, 30, false, ALARM_KIND_EVERYDAY, s_every_day_schedule);
|
||||
cl_assert_equal_i(s_num_timeline_adds, 3);
|
||||
cl_assert_equal_i(s_num_timeline_removes, 0);
|
||||
|
||||
s_sleep_state = ActivitySleepStateRestfulSleep;
|
||||
s_sleep_state_seconds = 0;
|
||||
s_last_vmc = 0;
|
||||
prv_set_time(s_current_day, 10, 0);
|
||||
cron_service_wakeup();
|
||||
cl_assert_equal_i(s_num_alarms_fired, 1);
|
||||
cl_assert_equal_i(s_num_alarm_events_put, 0);
|
||||
}
|
||||
|
||||
void test_alarm_smart__trigger_15_min_early_light_sleep(void) {
|
||||
AlarmId id;
|
||||
id = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 30, .kind = ALARM_KIND_EVERYDAY, .is_smart = true });
|
||||
prv_assert_alarm_config(id, 10, 30, false, ALARM_KIND_EVERYDAY, s_every_day_schedule);
|
||||
cl_assert_equal_i(s_num_timeline_adds, 3);
|
||||
cl_assert_equal_i(s_num_timeline_removes, 0);
|
||||
|
||||
// Begin light sleep
|
||||
s_sleep_state = ActivitySleepStateLightSleep;
|
||||
s_sleep_state_seconds = SMART_ALARM_MAX_LIGHT_SLEEP_S - 15 * SECONDS_PER_MINUTE;
|
||||
|
||||
// Smart alarms are first triggered by cron at T-30min
|
||||
prv_set_time(s_current_day, 10, 0);
|
||||
cron_service_wakeup();
|
||||
cl_assert_equal_i(s_num_alarms_fired, 1);
|
||||
cl_assert_equal_i(s_num_alarm_events_put, 0);
|
||||
|
||||
// Afterwards, the alarm snooze timer triggers every 5min
|
||||
const int num_checks = 3;
|
||||
for (int i = 0; i < num_checks; i++) {
|
||||
// Step forward time and increase light sleep duration
|
||||
s_sleep_state_seconds += 5 * SECONDS_PER_MINUTE;
|
||||
s_last_vmc = i == 2 ? 1 : 0;
|
||||
prv_set_time(s_current_day, 10, (i + 1) * 5);
|
||||
PBL_LOG(LOG_LEVEL_DEBUG, "Iteration #%d, sleep %d seconds", i, s_sleep_state_seconds);
|
||||
stub_new_timer_invoke(1);
|
||||
if (i < num_checks - 1) {
|
||||
// Smart alarm non-trigger checks
|
||||
cl_assert_equal_i(s_num_alarms_fired, 1);
|
||||
cl_assert_equal_i(s_num_alarm_events_put, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Smart alarm trigger checks
|
||||
cl_assert_equal_i(s_num_alarms_fired, 1);
|
||||
cl_assert_equal_i(s_num_alarm_events_put, 1);
|
||||
cl_assert_equal_i(s_num_timeline_adds, 6);
|
||||
cl_assert_equal_i(s_num_timeline_removes, 3);
|
||||
cl_assert_equal_i(s_last_timeline_item_added->header.timestamp, rtc_get_time());
|
||||
}
|
||||
|
||||
void test_alarm_smart__trigger_at_timeout(void) {
|
||||
AlarmId id;
|
||||
id = alarm_create(&(AlarmInfo) { .hour = 10, .minute = 30, .kind = ALARM_KIND_EVERYDAY, .is_smart = true });
|
||||
prv_assert_alarm_config(id, 10, 30, false, ALARM_KIND_EVERYDAY, s_every_day_schedule);
|
||||
cl_assert_equal_i(s_num_timeline_adds, 3);
|
||||
cl_assert_equal_i(s_num_timeline_removes, 0);
|
||||
|
||||
// Stay in deep sleep
|
||||
s_sleep_state = ActivitySleepStateRestfulSleep;
|
||||
s_sleep_state_seconds = 0;
|
||||
|
||||
// Make sure random snooze does not cause the smart alarm to go beyond the alarm time
|
||||
s_rand = 4;
|
||||
|
||||
// Smart alarms are first triggered by cron at T-30min
|
||||
prv_set_time(s_current_day, 10, 0);
|
||||
cron_service_wakeup();
|
||||
cl_assert_equal_i(s_num_alarms_fired, 1);
|
||||
cl_assert_equal_i(s_num_alarm_events_put, 0);
|
||||
|
||||
// Afterwards, the alarm snooze timer triggers every 5min
|
||||
const int num_checks = 6;
|
||||
for (int i = 0; i < num_checks; i++) {
|
||||
// Step forward time and increase light sleep duration
|
||||
s_sleep_state_seconds = (i + 1) * 5 * SECONDS_PER_MINUTE;
|
||||
s_last_vmc = (i == 5);
|
||||
prv_set_time(s_current_day, 10, i * 5);
|
||||
PBL_LOG(LOG_LEVEL_DEBUG, "Iteration #%d, sleep %d seconds", i, s_sleep_state_seconds);
|
||||
stub_new_timer_invoke(1);
|
||||
if (i < num_checks - 1) {
|
||||
// Smart alarm non-trigger checks
|
||||
cl_assert_equal_i(s_num_alarms_fired, 1);
|
||||
cl_assert_equal_i(s_num_alarm_events_put, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Smart alarm trigger checks
|
||||
cl_assert_equal_i(s_num_alarms_fired, 1);
|
||||
cl_assert_equal_i(s_num_alarm_events_put, 1);
|
||||
cl_assert_equal_i(s_num_timeline_adds, 6);
|
||||
cl_assert_equal_i(s_num_timeline_removes, 3);
|
||||
cl_assert_equal_i(s_last_timeline_item_added->header.timestamp, rtc_get_time());
|
||||
}
|
||||
|
||||
void test_alarm_smart__across_midnight_boundary(void) {
|
||||
prv_set_time(s_sunday, 22, 0);
|
||||
|
||||
AlarmId id;
|
||||
bool monday_only[7] = {false, true, false, false, false, false, false};
|
||||
id = alarm_create(&(AlarmInfo) { .hour = 0, .minute = 15, .kind = ALARM_KIND_CUSTOM, .is_smart = true,
|
||||
.scheduled_days = &monday_only });
|
||||
prv_assert_alarm_config(id, 0, 15, false, ALARM_KIND_CUSTOM, monday_only);
|
||||
cl_assert_equal_i(s_num_timeline_adds, 1);
|
||||
cl_assert_equal_i(s_num_timeline_removes, 0);
|
||||
|
||||
// Set sleep status
|
||||
s_sleep_state = ActivitySleepStateAwake;
|
||||
s_sleep_state_seconds = 0;
|
||||
|
||||
// Don't trigger too early
|
||||
prv_set_time(s_sunday, 23, 44);
|
||||
cron_service_wakeup();
|
||||
cl_assert_equal_i(s_num_alarms_fired, 0);
|
||||
cl_assert_equal_i(s_num_alarm_events_put, 0);
|
||||
|
||||
// Trigger at the right time
|
||||
prv_set_time(s_sunday, 23, 45);
|
||||
cron_service_wakeup();
|
||||
cl_assert_equal_i(s_num_alarms_fired, 1);
|
||||
cl_assert_equal_i(s_num_alarm_events_put, 1);
|
||||
cl_assert_equal_i(s_num_timeline_adds, 2);
|
||||
cl_assert_equal_i(s_num_timeline_removes, 1);
|
||||
cl_assert_equal_i(s_last_timeline_item_added->header.timestamp, rtc_get_time());
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue