pebble/tests/fw/services/blob_db/weather_data_shared.c
2025-01-27 11:38:16 -08:00

303 lines
10 KiB
C

/*
* 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 "weather_data_shared.h"
#include "clar_asserts.h"
#include "drivers/rtc.h"
#include "kernel/pbl_malloc.h"
#include "services/normal/blob_db/watch_app_prefs_db.h"
#include "services/normal/blob_db/weather_db.h"
#include "services/normal/weather/weather_service_private.h"
#define WEATHER_PREFS_DATA_SIZE (sizeof(SerializedWeatherAppPrefs) + \
(sizeof(Uuid) * WEATHER_DATA_SHARED_WEATHER_DB_NUM_DB_ENTRIES))
static uint8_t s_weather_app_prefs[WEATHER_PREFS_DATA_SIZE];
static const WeatherDBKey s_keys[] = {
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
},
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2
},
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3
},
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4
},
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5
},
};
static WeatherDBEntry *s_entries[WEATHER_DATA_SHARED_WEATHER_DB_NUM_DB_ENTRIES];
static size_t s_entry_sizes[WEATHER_DATA_SHARED_WEATHER_DB_NUM_DB_ENTRIES];
static char *s_entry_names[] = {
TEST_WEATHER_DB_LOCATION_PALO_ALTO,
TEST_WEATHER_DB_LOCATION_KITCHENER,
TEST_WEATHER_DB_LOCATION_WATERLOO,
TEST_WEATHER_DB_LOCATION_RWC,
TEST_WEATHER_DB_LOCATION_SF,
};
static char *s_entry_phrases[] = {
TEST_WEATHER_DB_SHORT_PHRASE_SUNNY,
TEST_WEATHER_DB_SHORT_PHRASE_PARTLY_CLOUDY,
TEST_WEATHER_DB_SHORT_PHRASE_HEAVY_SNOW,
TEST_WEATHER_DB_SHORT_PHRASE_HEAVY_RAIN,
TEST_WEATHER_DB_SHORT_PHRASE_PARTLY_CLOUDY,
};
static const WeatherDBEntry s_entry_bases[] = {
{
.version = WEATHER_DB_CURRENT_VERSION,
.is_current_location = true,
.current_temp = 68,
.current_weather_type = WeatherType_Sun,
.today_high_temp = 68,
.today_low_temp = 52,
.tomorrow_weather_type = WeatherType_CloudyDay,
.tomorrow_high_temp = 70,
.tomorrow_low_temp = 60,
},
{
.version = WEATHER_DB_CURRENT_VERSION,
.is_current_location = false,
.current_temp = -10,
.current_weather_type = WeatherType_PartlyCloudy,
.today_high_temp = 0,
.today_low_temp = -11,
.tomorrow_weather_type = WeatherType_CloudyDay,
.tomorrow_high_temp = 2,
.tomorrow_low_temp = -3,
},
{
.version = WEATHER_DB_CURRENT_VERSION,
.is_current_location = false,
.current_temp = -99,
.current_weather_type = WeatherType_HeavySnow,
.today_high_temp = -98,
.today_low_temp = -99,
.tomorrow_weather_type = WeatherType_Sun,
.tomorrow_high_temp = 2,
.tomorrow_low_temp = 1,
},
{
.version = WEATHER_DB_CURRENT_VERSION,
.is_current_location = true,
.current_temp = 60,
.current_weather_type = WeatherType_HeavyRain,
.today_high_temp = 70,
.today_low_temp = 50,
.tomorrow_weather_type = WeatherType_PartlyCloudy,
.tomorrow_high_temp = 70,
.tomorrow_low_temp = 60,
},
{
.version = WEATHER_DB_CURRENT_VERSION,
.is_current_location = true,
.current_temp = 60,
.current_weather_type = WeatherType_PartlyCloudy,
.today_high_temp = 70,
.today_low_temp = 50,
.tomorrow_weather_type = WeatherType_PartlyCloudy,
.tomorrow_high_temp = 70,
.tomorrow_low_temp = 60,
}
};
// Fake out watch_app_prefs calls
void watch_app_prefs_destroy_weather(SerializedWeatherAppPrefs *prefs) {}
SerializedWeatherAppPrefs *watch_app_prefs_get_weather(void) {
SerializedWeatherAppPrefs *prefs = (SerializedWeatherAppPrefs *) s_weather_app_prefs;
prefs->num_locations = WEATHER_DATA_SHARED_WEATHER_DB_NUM_DB_ENTRIES;
for (int idx = 0; idx < WEATHER_DATA_SHARED_WEATHER_DB_NUM_DB_ENTRIES; idx++) {
prefs->locations[idx] = s_keys[idx];
}
return prefs;
}
static WeatherDBEntry *prv_create_entry(const WeatherDBEntry *base_entry, char *location,
char *phrase, size_t *size_out) {
PascalString16List pstring16_list;
PascalString16 *location_name;
PascalString16 *short_phrase;
size_t data_size;
location_name = pstring_create_pstring16_from_string(location);
short_phrase = pstring_create_pstring16_from_string(phrase);
data_size = strlen(location) +
strlen(phrase) +
sizeof(uint16_t) * 2; // One for each string
const size_t entry_size = sizeof(WeatherDBEntry) + data_size;
WeatherDBEntry *entry = task_zalloc_check(entry_size);
*entry = *base_entry;
entry->pstring16s.data_size = data_size;
entry->last_update_time_utc = rtc_get_time();
pstring_project_list_on_serialized_array(&pstring16_list, &entry->pstring16s);
pstring_add_pstring16_to_list(&pstring16_list, location_name);
pstring_add_pstring16_to_list(&pstring16_list, short_phrase);
pstring_destroy_pstring16(location_name);
pstring_destroy_pstring16(short_phrase);
*size_out = entry_size;
return entry;
}
static void prv_initialize_entries(void) {
for (int idx = 0; idx < WEATHER_DATA_SHARED_WEATHER_DB_NUM_DB_ENTRIES; idx++) {
WeatherDBEntry *entry = prv_create_entry(&s_entry_bases[idx],
s_entry_names[idx],
s_entry_phrases[idx],
&s_entry_sizes[idx]);
// Make the last entry contain a timestamp that is too old to be included in weather_service
// forecast list
if (idx == WEATHER_DATA_SHARED_NUM_VALID_TIMESTAMP_ENTRIES) {
entry->last_update_time_utc = (time_start_of_today() - SECONDS_PER_DAY - 1);
}
cl_assert_equal_i(S_SUCCESS, weather_db_insert((uint8_t*)&s_keys[idx],
sizeof(WeatherDBKey),
(uint8_t*)entry,
s_entry_sizes[idx]));
s_entries[idx] = entry;
}
}
void weather_shared_data_init(void) {
rtc_set_time(1461765790); // 2016-04-27T14:03:10+00:00
prv_initialize_entries();
}
void weather_shared_data_cleanup(void) {
for (int i = 0; i < WEATHER_DATA_SHARED_WEATHER_DB_NUM_DB_ENTRIES; i++) {
if (s_entries[i]) {
task_free(s_entries[i]);
s_entries[i] = NULL;
}
}
// Flush DB
cl_assert_equal_i(S_SUCCESS, weather_db_flush());
}
const WeatherDBKey *weather_shared_data_get_key(int index) {
return &s_keys[index];
}
WeatherDBEntry *weather_shared_data_get_entry(int index) {
return s_entries[index];
}
size_t weather_shared_data_get_entry_size(int index) {
return s_entry_sizes[index];
}
char *weather_shared_data_get_entry_name(int index) {
return s_entry_names[index];
}
char *weather_shared_data_get_entry_phrase(int index) {
return s_entry_phrases[index];
}
int weather_shared_data_get_index_of_key(const WeatherDBKey *key) {
for (int idx = 0; idx < WEATHER_DATA_SHARED_WEATHER_DB_NUM_DB_ENTRIES; idx++) {
if (uuid_equal(key, &s_keys[idx])) {
return idx;
}
}
return -1;
}
void weather_shared_data_assert_entries_equal(const WeatherDBKey *key, WeatherDBEntry *to_check,
WeatherDBEntry *original) {
cl_assert_equal_i(to_check->version, original->version);
cl_assert_equal_b(to_check->is_current_location, original->is_current_location);
cl_assert_equal_i(to_check->current_temp, original->current_temp);
cl_assert_equal_i(to_check->current_weather_type, original->current_weather_type);
cl_assert_equal_i(to_check->today_high_temp, original->today_high_temp);
cl_assert_equal_i(to_check->today_low_temp, original->today_low_temp);
cl_assert_equal_i(to_check->tomorrow_weather_type, original->tomorrow_weather_type);
cl_assert_equal_i(to_check->tomorrow_high_temp, original->tomorrow_high_temp);
cl_assert_equal_i(to_check->tomorrow_low_temp, original->tomorrow_low_temp);
cl_assert_equal_i(to_check->last_update_time_utc, original->last_update_time_utc);
PascalString16List pstring16_list;
pstring_project_list_on_serialized_array(&pstring16_list, &to_check->pstring16s);
cl_assert_equal_i(pstring16_list.count, 2);
PascalString16 *pstring;
pstring = pstring_get_pstring16_from_list(&pstring16_list, 0);
int index = weather_shared_data_get_index_of_key(key);
if (index == -1) {
cl_fail("key not found!");
}
cl_assert_equal_i(pstring->str_length, strlen(s_entry_names[index]));
char loc[WEATHER_SERVICE_MAX_WEATHER_LOCATION_BUFFER_SIZE];
pstring_pstring16_to_string(pstring, loc);
cl_assert_equal_s(loc, s_entry_names[index]);
pstring = pstring_get_pstring16_from_list(&pstring16_list, 1);
cl_assert_equal_i(pstring->str_length, strlen(s_entry_phrases[index]));
char phrase[WEATHER_SERVICE_MAX_SHORT_PHRASE_BUFFER_SIZE];
pstring_pstring16_to_string(pstring, phrase);
cl_assert_equal_s(phrase, s_entry_phrases[index]);
}
bool weather_shared_data_get_key_exists(WeatherDBKey *key) {
return weather_shared_data_get_index_of_key(key) != -1;
}
status_t weather_db_insert_stale(const uint8_t *key, int key_len, const uint8_t *val, int val_len);
size_t weather_shared_data_insert_stale_entry(WeatherDBKey *key) {
const WeatherDBEntry stale_entry = {
.version = WEATHER_DB_CURRENT_VERSION - 1,
.is_current_location = true,
.current_temp = 68,
.current_weather_type = WeatherType_Sun,
.today_high_temp = 68,
.today_low_temp = 52,
.tomorrow_weather_type = WeatherType_CloudyDay,
.tomorrow_high_temp = 70,
.tomorrow_low_temp = 60,
};
WeatherDBEntry *entry = prv_create_entry(&stale_entry,
s_entry_names[0],
s_entry_phrases[0],
&s_entry_sizes[0]);
cl_assert_equal_i(S_SUCCESS, weather_db_insert_stale((uint8_t*)key,
sizeof(WeatherDBKey),
(uint8_t*)entry,
s_entry_sizes[0]));
return s_entry_sizes[0];
}