mirror of
https://github.com/google/pebble.git
synced 2025-07-09 08:26:20 +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
275
tests/fw/services/blob_db/test_app_db.c
Normal file
275
tests/fw/services/blob_db/test_app_db.c
Normal file
|
@ -0,0 +1,275 @@
|
|||
/*
|
||||
* 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 "clar.h"
|
||||
|
||||
#include "process_management/app_install_types.h"
|
||||
#include "process_management/pebble_process_info.h"
|
||||
#include "process_management/pebble_process_md.h"
|
||||
#include "services/normal/filesystem/pfs.h"
|
||||
#include "services/normal/blob_db/app_db.h"
|
||||
|
||||
// Fixture
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// Fakes
|
||||
////////////////////////////////////////////////////////////////
|
||||
#include "fake_spi_flash.h"
|
||||
|
||||
// Stubs
|
||||
////////////////////////////////////////////////////////////////
|
||||
#include "stubs_analytics.h"
|
||||
#include "stubs_app_cache.h"
|
||||
#include "stubs_events.h"
|
||||
#include "stubs_hexdump.h"
|
||||
#include "stubs_logging.h"
|
||||
#include "stubs_mutex.h"
|
||||
#include "stubs_passert.h"
|
||||
#include "stubs_pbl_malloc.h"
|
||||
#include "stubs_pebble_tasks.h"
|
||||
#include "stubs_prompt.h"
|
||||
#include "stubs_rand_ptr.h"
|
||||
#include "stubs_sleep.h"
|
||||
#include "stubs_task_watchdog.h"
|
||||
|
||||
void app_install_clear_app_db(void) {
|
||||
}
|
||||
|
||||
void put_bytes_cancel(void) {
|
||||
}
|
||||
|
||||
typedef void (*InstallCallbackDoneCallback)(void*);
|
||||
bool app_install_do_callbacks(InstallEventType event_type, AppInstallId install_id, Uuid *uuid,
|
||||
InstallCallbackDoneCallback done_callback, void* done_callback_data) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool app_fetch_in_progress(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void app_fetch_cancel_from_system_task(void) {
|
||||
}
|
||||
|
||||
extern AppInstallId app_db_check_next_unique_id(void);
|
||||
|
||||
static const AppDBEntry app1 = {
|
||||
.name = "Application 1",
|
||||
.uuid = {0x6b, 0xf6, 0x21, 0x5b, 0xc9, 0x7f, 0x40, 0x9e,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4},
|
||||
.app_version = {
|
||||
.major = 1,
|
||||
.minor = 1,
|
||||
},
|
||||
.sdk_version = {
|
||||
.major = 1,
|
||||
.minor = 1,
|
||||
},
|
||||
.info_flags = 0,
|
||||
.icon_resource_id = 0,
|
||||
};
|
||||
|
||||
static const AppDBEntry app2 = {
|
||||
.name = "Application 2",
|
||||
.uuid = {0x55, 0xcb, 0x7c, 0x75, 0x8a, 0x35, 0x44, 0x87,
|
||||
0x90, 0xa4, 0x91, 0x3f, 0x1f, 0xa6, 0x76, 0x01},
|
||||
.app_version = {
|
||||
.major = 1,
|
||||
.minor = 1,
|
||||
},
|
||||
.sdk_version = {
|
||||
.major = 1,
|
||||
.minor = 1,
|
||||
},
|
||||
.info_flags = 0,
|
||||
.icon_resource_id = 0,
|
||||
};
|
||||
|
||||
static const AppDBEntry app3 = {
|
||||
.name = "Application 3",
|
||||
.uuid = {0x7c, 0x65, 0x2e, 0xb9, 0x26, 0xd6, 0x44, 0x2c,
|
||||
0x98, 0x68, 0xa4, 0x36, 0x79, 0x7d, 0xe2, 0x05},
|
||||
.app_version = {
|
||||
.major = 1,
|
||||
.minor = 1,
|
||||
},
|
||||
.sdk_version = {
|
||||
.major = 1,
|
||||
.minor = 1,
|
||||
},
|
||||
.info_flags = 0,
|
||||
.icon_resource_id = 0,
|
||||
};
|
||||
|
||||
|
||||
// Setup
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void test_app_db__initialize(void) {
|
||||
fake_spi_flash_init(0, 0x1000000);
|
||||
pfs_init(false);
|
||||
app_db_init();
|
||||
|
||||
// add all three
|
||||
cl_assert_equal_i(S_SUCCESS, app_db_insert((uint8_t*)&app1.uuid,
|
||||
sizeof(Uuid), (uint8_t*)&app1, sizeof(AppDBEntry)));
|
||||
|
||||
cl_assert_equal_i(S_SUCCESS, app_db_insert((uint8_t*)&app2.uuid,
|
||||
sizeof(Uuid), (uint8_t*)&app2, sizeof(AppDBEntry)));
|
||||
|
||||
cl_assert_equal_i(S_SUCCESS, app_db_insert((uint8_t*)&app3.uuid,
|
||||
sizeof(Uuid), (uint8_t*)&app3, sizeof(AppDBEntry)));
|
||||
}
|
||||
|
||||
void test_app_db__cleanup(void) {
|
||||
//nada
|
||||
}
|
||||
|
||||
// Tests
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void test_app_db__basic_test(void) {
|
||||
// confirm all three are there
|
||||
cl_assert(app_db_get_len((uint8_t*)&app1.uuid, sizeof(Uuid)) > 0);
|
||||
cl_assert(app_db_get_len((uint8_t*)&app2.uuid, sizeof(Uuid)) > 0);
|
||||
cl_assert(app_db_get_len((uint8_t*)&app3.uuid, sizeof(Uuid)) > 0);
|
||||
|
||||
// remove #1 and confirm it's deleted
|
||||
cl_assert_equal_i(S_SUCCESS, app_db_delete((uint8_t*)&app1.uuid, sizeof(Uuid)));
|
||||
cl_assert_equal_i(0, app_db_get_len((uint8_t*)&app1.uuid, sizeof(Uuid)));
|
||||
|
||||
// add 1 back so it's clean
|
||||
cl_assert_equal_i(S_SUCCESS, app_db_insert((uint8_t*)&app1.uuid,
|
||||
sizeof(Uuid), (uint8_t*)&app1, sizeof(AppDBEntry)));
|
||||
|
||||
AppDBEntry temp;
|
||||
cl_assert_equal_i(S_SUCCESS, app_db_read((uint8_t*)&app1.uuid,
|
||||
sizeof(Uuid), (uint8_t*)&temp, sizeof(AppDBEntry)));
|
||||
|
||||
cl_assert_equal_i(5, app_db_check_next_unique_id());
|
||||
|
||||
// check app 1
|
||||
memset(&temp, 0, sizeof(AppDBEntry));
|
||||
cl_assert_equal_i(S_SUCCESS, app_db_get_app_entry_for_uuid(&app1.uuid, &temp));
|
||||
cl_assert_equal_b(true, uuid_equal(&app1.uuid, &temp.uuid));
|
||||
cl_assert_equal_i(0 , strncmp((char *)&app1.name, (char *)&temp.name, APP_NAME_SIZE_BYTES));
|
||||
|
||||
// check app 2
|
||||
memset(&temp, 0, sizeof(AppDBEntry));
|
||||
cl_assert_equal_i(S_SUCCESS, app_db_get_app_entry_for_uuid(&app1.uuid, &temp));
|
||||
cl_assert_equal_b(true, uuid_equal(&app1.uuid, &temp.uuid));
|
||||
cl_assert_equal_i(0, strncmp((char *)&app1.name, (char *)&temp.name, APP_NAME_SIZE_BYTES));
|
||||
|
||||
// check app 3
|
||||
memset(&temp, 0, sizeof(AppDBEntry));
|
||||
cl_assert_equal_i(S_SUCCESS, app_db_get_app_entry_for_uuid(&app3.uuid, &temp));
|
||||
cl_assert_equal_b(true, uuid_equal(&app3.uuid, &temp.uuid));
|
||||
cl_assert_equal_i(0, strncmp((char *)&app3.name, (char *)&temp.name, APP_NAME_SIZE_BYTES));
|
||||
}
|
||||
|
||||
void test_app_db__retrieve_app_db_entries_by_install_id(void) {
|
||||
AppDBEntry temp;
|
||||
|
||||
// check app_db_get_install_id_for_uuid for app 1
|
||||
memset(&temp, 0, sizeof(AppDBEntry));
|
||||
AppInstallId app_one_id = app_db_get_install_id_for_uuid(&app1.uuid);
|
||||
cl_assert(app_one_id > 0);
|
||||
cl_assert_equal_i(S_SUCCESS, app_db_get_app_entry_for_install_id(app_one_id, &temp));
|
||||
cl_assert_equal_b(true, uuid_equal(&app1.uuid, &temp.uuid));
|
||||
|
||||
// check app_db_get_install_id_for_uuid for app 2
|
||||
memset(&temp, 0, sizeof(AppDBEntry));
|
||||
AppInstallId app_two_id = app_db_get_install_id_for_uuid(&app2.uuid);
|
||||
cl_assert(app_one_id > 0);
|
||||
cl_assert_equal_i(S_SUCCESS, app_db_get_app_entry_for_install_id(app_two_id, &temp));
|
||||
cl_assert_equal_b(true, uuid_equal(&app2.uuid, &temp.uuid));
|
||||
|
||||
// check app_db_get_install_id_for_uuid for app 3
|
||||
memset(&temp, 0, sizeof(AppDBEntry));
|
||||
AppInstallId app_three_id = app_db_get_install_id_for_uuid(&app3.uuid);
|
||||
cl_assert(app_one_id > 0);
|
||||
cl_assert_equal_i(S_SUCCESS, app_db_get_app_entry_for_install_id(app_three_id, &temp));
|
||||
cl_assert_equal_b(true, uuid_equal(&app3.uuid, &temp.uuid));
|
||||
}
|
||||
|
||||
void test_app_db__retrieve_app_db_entries_by_uuid(void) {
|
||||
AppDBEntry temp;
|
||||
|
||||
// check app_db_get_install_id_for_uuid for app 1
|
||||
memset(&temp, 0, sizeof(AppDBEntry));
|
||||
cl_assert_equal_i(S_SUCCESS, app_db_get_app_entry_for_uuid(&app1.uuid, &temp));
|
||||
cl_assert_equal_b(true, uuid_equal(&app1.uuid, &temp.uuid));
|
||||
|
||||
// check app_db_get_install_id_for_uuid for app 2
|
||||
memset(&temp, 0, sizeof(AppDBEntry));
|
||||
cl_assert_equal_i(S_SUCCESS, app_db_get_app_entry_for_uuid(&app2.uuid, &temp));
|
||||
cl_assert_equal_b(true, uuid_equal(&app2.uuid, &temp.uuid));
|
||||
|
||||
// check app_db_get_install_id_for_uuid for app 3
|
||||
memset(&temp, 0, sizeof(AppDBEntry));
|
||||
cl_assert_equal_i(S_SUCCESS, app_db_get_app_entry_for_uuid(&app3.uuid, &temp));
|
||||
cl_assert_equal_b(true, uuid_equal(&app3.uuid, &temp.uuid));
|
||||
}
|
||||
|
||||
void test_app_db__overwrite(void) {
|
||||
// add 3 of the same. Confirm that the entry was overwritten by checking next ID.
|
||||
cl_assert_equal_i(S_SUCCESS, app_db_insert((uint8_t*)&app1.uuid, sizeof(Uuid), (uint8_t*)&app1,
|
||||
sizeof(AppDBEntry)));
|
||||
cl_assert_equal_i(S_SUCCESS, app_db_insert((uint8_t*)&app1.uuid, sizeof(Uuid), (uint8_t*)&app1,
|
||||
sizeof(AppDBEntry)));
|
||||
cl_assert_equal_i(S_SUCCESS, app_db_insert((uint8_t*)&app1.uuid, sizeof(Uuid), (uint8_t*)&app1,
|
||||
sizeof(AppDBEntry)));
|
||||
cl_assert(app_db_check_next_unique_id() == 4);
|
||||
|
||||
// add two more duplicates of a different app. Confirm it only increments by 1.
|
||||
cl_assert_equal_i(S_SUCCESS, app_db_insert((uint8_t*)&app2.uuid, sizeof(Uuid), (uint8_t*)&app2,
|
||||
sizeof(AppDBEntry)));
|
||||
cl_assert_equal_i(S_SUCCESS, app_db_insert((uint8_t*)&app2.uuid, sizeof(Uuid), (uint8_t*)&app2,
|
||||
sizeof(AppDBEntry)));
|
||||
cl_assert(app_db_check_next_unique_id() == 4);
|
||||
}
|
||||
|
||||
void test_app_db__test_exists(void) {
|
||||
cl_assert_equal_b(false, app_db_exists_install_id(-1));
|
||||
cl_assert_equal_b(false, app_db_exists_install_id(0));
|
||||
cl_assert_equal_b(true, app_db_exists_install_id(1));
|
||||
cl_assert_equal_b(true, app_db_exists_install_id(2));
|
||||
cl_assert_equal_b(true, app_db_exists_install_id(3));
|
||||
cl_assert_equal_b(false, app_db_exists_install_id(4));
|
||||
}
|
||||
|
||||
static const uint8_t some_data[] = {0x01, 0x02, 0x17, 0x54};
|
||||
|
||||
void prv_enumerate_entries(AppInstallId install_id, AppDBEntry *entry, void *data) {
|
||||
switch(install_id) {
|
||||
case 1:
|
||||
cl_assert_equal_m(&app1, entry, sizeof(AppDBEntry));
|
||||
break;
|
||||
case 2:
|
||||
cl_assert_equal_m(&app2, entry, sizeof(AppDBEntry));
|
||||
break;
|
||||
case 3:
|
||||
cl_assert_equal_m(&app3, entry, sizeof(AppDBEntry));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
cl_assert_equal_m((uint8_t *)some_data, (uint8_t *)data, sizeof(some_data));
|
||||
}
|
||||
|
||||
void test_app_db__enumerate(void) {
|
||||
app_db_enumerate_entries(prv_enumerate_entries, (void *)&some_data);
|
||||
}
|
568
tests/fw/services/blob_db/test_app_glance_db.c
Normal file
568
tests/fw/services/blob_db/test_app_glance_db.c
Normal file
|
@ -0,0 +1,568 @@
|
|||
/*
|
||||
* 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 "clar.h"
|
||||
|
||||
#include "applib/app_glance.h"
|
||||
#include "drivers/rtc.h"
|
||||
#include "kernel/pbl_malloc.h"
|
||||
#include "resource/resource_ids.auto.h"
|
||||
#include "services/normal/app_glances/app_glance_service.h"
|
||||
#include "services/normal/blob_db/app_glance_db.h"
|
||||
#include "services/normal/blob_db/app_glance_db_private.h"
|
||||
#include "services/normal/filesystem/pfs.h"
|
||||
#include "util/uuid.h"
|
||||
|
||||
// Fakes
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "fake_settings_file.h"
|
||||
#include "fake_events.h"
|
||||
|
||||
// Stubs
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "stubs_logging.h"
|
||||
#include "stubs_mutex.h"
|
||||
#include "stubs_passert.h"
|
||||
#include "stubs_pbl_malloc.h"
|
||||
|
||||
status_t pfs_remove(const char *name) {
|
||||
fake_settings_file_reset();
|
||||
return S_SUCCESS;
|
||||
}
|
||||
|
||||
static bool s_app_cache_entry_exists = true;
|
||||
bool app_cache_entry_exists(AppInstallId app_id) {
|
||||
return s_app_cache_entry_exists;
|
||||
}
|
||||
|
||||
static int s_launch_count = 0;
|
||||
status_t app_cache_app_launched(AppInstallId app_id) {
|
||||
s_launch_count++;
|
||||
return S_SUCCESS;
|
||||
}
|
||||
|
||||
static AppInstallId s_app_install_id = 1;
|
||||
AppInstallId app_install_get_id_for_uuid(const Uuid *uuid) {
|
||||
if (!uuid) {
|
||||
return INSTALL_ID_INVALID;
|
||||
}
|
||||
return s_app_install_id;
|
||||
}
|
||||
|
||||
bool app_install_id_from_system(AppInstallId id) {
|
||||
return (id < INSTALL_ID_INVALID);
|
||||
}
|
||||
|
||||
bool app_install_id_from_app_db(AppInstallId id) {
|
||||
return (id > INSTALL_ID_INVALID);
|
||||
}
|
||||
|
||||
#define APP_GLANCE_TEST_UUID \
|
||||
(UuidMake(0x3d, 0xc6, 0xb9, 0x4c, 0x4, 0x2, 0x48, 0xf4, \
|
||||
0xbe, 0x14, 0x81, 0x17, 0xf1, 0xa, 0xa9, 0xc4))
|
||||
|
||||
static const uint8_t s_app_glance_basic[] = {
|
||||
// Version
|
||||
APP_GLANCE_DB_CURRENT_VERSION,
|
||||
// Creation time
|
||||
0x14, 0x13, 0x4E, 0x57, // 1464734484 (Tue, 31 May 2016 22:41:24 GMT)
|
||||
|
||||
// Slice 1
|
||||
0x22, 0x00, // Total size
|
||||
0x00, // AppGlanceSliceType - AppGlanceSliceType_IconAndSubtitle
|
||||
0x03, // Number of attributes
|
||||
// Slice Attributes
|
||||
0x25, // Attribute ID - AttributeIdTimestamp
|
||||
0x04, 0x00, // Attribute Length
|
||||
// Slice expiration time:
|
||||
0x94, 0x64, 0x4F, 0x57, // 1464820884 (Wed, 1 June 2016 22:41:24 GMT)
|
||||
0x30, // Attribute ID - AttributeIdIcon
|
||||
0x04, 0x00, // Attribute Length
|
||||
// Slice icon resource ID:
|
||||
0x69, 0x00, 0x00, 0x00, //
|
||||
0x2F, // Attribute ID - AttributeIdSubtitleTemplateString
|
||||
0x0D, 0x00, // Attribute Length
|
||||
// Slice subtitle:
|
||||
'T', 'e', 's', 't', ' ', 's', 'u', 'b', 't', 'i', 't', 'l', 'e',
|
||||
};
|
||||
|
||||
// Note that `APP_GLANCE_DB_MAX_SLICES_PER_GLANCE` is reduced for the unit tests!
|
||||
static const uint8_t s_app_glance_with_too_many_slices[] = {
|
||||
// Version
|
||||
APP_GLANCE_DB_CURRENT_VERSION,
|
||||
// Creation time
|
||||
0x14, 0x13, 0x4E, 0x57, // 1464734484 (Tue, 31 May 2016 22:41:24 GMT)
|
||||
|
||||
// Slice 1
|
||||
0x0B, 0x00, // Total size
|
||||
0x00, // AppGlanceSliceType - AppGlanceSliceType_IconAndSubtitle
|
||||
0x01, // Number of attributes
|
||||
// Slice Attributes
|
||||
0x25, // Attribute ID - AttributeIdTimestamp
|
||||
0x04, 0x00, // Attribute Length
|
||||
// Slice expiration time:
|
||||
0x94, 0x64, 0x4F, 0x57, // 1464820884 (Wed, 1 June 2016 22:41:24 GMT)
|
||||
|
||||
// Slice 2
|
||||
0x0B, 0x00, // Total size
|
||||
0x00, // AppGlanceSliceType - AppGlanceSliceType_IconAndSubtitle
|
||||
0x01, // Number of attributes
|
||||
// Slice Attributes
|
||||
0x25, // Attribute ID - AttributeIdTimestamp
|
||||
0x04, 0x00, // Attribute Length
|
||||
// Slice expiration time:
|
||||
0x95, 0x64, 0x4F, 0x57, // 1464820884 (Wed, 1 June 2016 22:41:25 GMT)
|
||||
|
||||
// Slice 3
|
||||
0x0B, 0x00, // Total size
|
||||
0x00, // AppGlanceSliceType - AppGlanceSliceType_IconAndSubtitle
|
||||
0x01, // Number of attributes
|
||||
// Slice Attributes
|
||||
0x25, // Attribute ID - AttributeIdTimestamp
|
||||
0x04, 0x00, // Attribute Length
|
||||
// Slice expiration time:
|
||||
0x96, 0x64, 0x4F, 0x57, // 1464820884 (Wed, 1 June 2016 22:41:26 GMT)
|
||||
};
|
||||
|
||||
static const uint8_t s_app_glance_with_invalid_slice_total_sizes[] = {
|
||||
// Version
|
||||
APP_GLANCE_DB_CURRENT_VERSION,
|
||||
// Creation time
|
||||
0x14, 0x13, 0x4E, 0x57, // 1464734484 (Tue, 31 May 2016 22:41:24 GMT)
|
||||
|
||||
// Slice 1 (valid)
|
||||
0x0B, 0x00, // Total size
|
||||
0x00, // AppGlanceSliceType - AppGlanceSliceType_IconAndSubtitle
|
||||
0x01, // Number of attributes
|
||||
// Slice Attributes
|
||||
0x25, // Attribute ID - AttributeIdTimestamp
|
||||
0x04, 0x00, // Attribute Length
|
||||
// Slice expiration time:
|
||||
0x94, 0x64, 0x4F, 0x57, // 1464820884 (Wed, 1 June 2016 22:41:24 GMT)
|
||||
|
||||
// Slice 2 (invalid total_size)
|
||||
0xFF, 0x00, // Total size
|
||||
0x00, // AppGlanceSliceType - AppGlanceSliceType_IconAndSubtitle
|
||||
0x01, // Number of attributes
|
||||
// Slice Attributes
|
||||
0x25, // Attribute ID - AttributeIdTimestamp
|
||||
0x04, 0x00, // Attribute Length
|
||||
// Slice expiration time:
|
||||
0x95, 0x64, 0x4F, 0x57, // 1464820884 (Wed, 1 June 2016 22:41:25 GMT)
|
||||
};
|
||||
|
||||
// Setup
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void test_app_glance_db__initialize(void) {
|
||||
s_app_cache_entry_exists = true;
|
||||
s_app_install_id = 1;
|
||||
s_launch_count = 0;
|
||||
|
||||
fake_event_init();
|
||||
fake_settings_file_reset();
|
||||
app_glance_db_init();
|
||||
}
|
||||
|
||||
void app_glance_db_deinit(void);
|
||||
|
||||
void test_app_glance_db__cleanup(void) {
|
||||
app_glance_db_deinit();
|
||||
}
|
||||
|
||||
// Blob Tests
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void test_app_glance_db__blob_insertion_with_invalid_key_or_val_length_fails(void) {
|
||||
// Invalid key length should fail
|
||||
const size_t invalid_key_length = 1337;
|
||||
cl_assert_equal_i(app_glance_db_insert((uint8_t *)&APP_GLANCE_TEST_UUID, invalid_key_length,
|
||||
(uint8_t *)&s_app_glance_basic,
|
||||
sizeof(s_app_glance_basic)),
|
||||
E_INVALID_ARGUMENT);
|
||||
|
||||
// Invalid val length should fail
|
||||
const size_t invalid_val_size = sizeof(SerializedAppGlanceHeader) - 1;
|
||||
cl_assert_equal_i(app_glance_db_insert((uint8_t *)&APP_GLANCE_TEST_UUID, UUID_SIZE,
|
||||
(uint8_t *)&s_app_glance_basic, invalid_val_size),
|
||||
E_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
void test_app_glance_db__basic_glance_blob_insert_and_read(void) {
|
||||
const size_t glance_size = sizeof(s_app_glance_basic);
|
||||
|
||||
cl_assert_equal_i(app_glance_db_insert((uint8_t *)&APP_GLANCE_TEST_UUID, UUID_SIZE,
|
||||
(uint8_t *)&s_app_glance_basic, glance_size),
|
||||
S_SUCCESS);
|
||||
cl_assert_equal_i(app_glance_db_get_len((uint8_t *)&APP_GLANCE_TEST_UUID, UUID_SIZE),
|
||||
glance_size);
|
||||
|
||||
uint8_t *glance_out = kernel_malloc(glance_size);
|
||||
cl_assert_equal_i(app_glance_db_read((uint8_t *)&APP_GLANCE_TEST_UUID, UUID_SIZE, glance_out,
|
||||
glance_size),
|
||||
S_SUCCESS);
|
||||
cl_assert_equal_m(glance_out, (uint8_t *)s_app_glance_basic, glance_size);
|
||||
kernel_free(glance_out);
|
||||
}
|
||||
|
||||
void test_app_glance_db__blob_read_with_invalid_key_length_or_null_val_out_fails(void) {
|
||||
// Call the basic glance blob insert test to insert the basic glance blob
|
||||
test_app_glance_db__basic_glance_blob_insert_and_read();
|
||||
|
||||
const size_t glance_size = sizeof(s_app_glance_basic);
|
||||
uint8_t glance_out[glance_size];
|
||||
|
||||
// Trying to read the basic glance blob back with an invalid key length should fail
|
||||
const size_t invalid_key_length = 1337;
|
||||
cl_assert_equal_i(app_glance_db_read((uint8_t *)&APP_GLANCE_TEST_UUID, invalid_key_length,
|
||||
glance_out, glance_size),
|
||||
E_INVALID_ARGUMENT);
|
||||
|
||||
// Trying to read the basic glance blob back with a NULL glance_out argument should fail
|
||||
uint8_t *invalid_glance_out = NULL;
|
||||
cl_assert_equal_i(app_glance_db_read((uint8_t *)&APP_GLANCE_TEST_UUID, UUID_SIZE,
|
||||
invalid_glance_out, glance_size),
|
||||
E_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
void test_app_glance_db__basic_glance_blob_delete(void) {
|
||||
// Call the basic glance blob insert test to insert the basic glance blob
|
||||
test_app_glance_db__basic_glance_blob_insert_and_read();
|
||||
|
||||
// Delete the basic glance blob
|
||||
cl_assert_equal_i(app_glance_db_delete((uint8_t *)&APP_GLANCE_TEST_UUID, UUID_SIZE),
|
||||
S_SUCCESS);
|
||||
|
||||
const size_t glance_size = sizeof(s_app_glance_basic);
|
||||
uint8_t glance_out[glance_size];
|
||||
|
||||
// Trying to read the basic glance blob now should fail because it should no longer exist
|
||||
cl_assert_equal_i(app_glance_db_read((uint8_t *)&APP_GLANCE_TEST_UUID, UUID_SIZE, glance_out,
|
||||
glance_size),
|
||||
E_DOES_NOT_EXIST);
|
||||
}
|
||||
|
||||
void test_app_glance_db__delete_non_existing_blob_does_nothing(void) {
|
||||
// Trying to delete a glance that is not actually in the database should do nothing
|
||||
cl_assert_equal_i(app_glance_db_delete((uint8_t *)&APP_GLANCE_TEST_UUID, UUID_SIZE),
|
||||
S_SUCCESS);
|
||||
}
|
||||
|
||||
void test_app_glance_db__delete_blob_with_invalid_key_length_fails(void) {
|
||||
// Call the basic glance blob insert test to insert the basic glance blob
|
||||
test_app_glance_db__basic_glance_blob_insert_and_read();
|
||||
|
||||
// Trying to delete the basic glance blob with an invalid key length should fail
|
||||
const size_t invalid_key_length = 1337;
|
||||
cl_assert_equal_i(app_glance_db_delete((uint8_t *)&APP_GLANCE_TEST_UUID, invalid_key_length),
|
||||
E_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
void test_app_glance_db__glance_blob_with_older_creation_time_than_existing_not_inserted(void) {
|
||||
// Insert the first glance blob
|
||||
SerializedAppGlanceHeader app_glance_1 = (SerializedAppGlanceHeader) {
|
||||
.version = APP_GLANCE_DB_CURRENT_VERSION,
|
||||
.creation_time = 1464734484, // Tue, 31 May 2016 22:41:24 GMT
|
||||
};
|
||||
const size_t glance_1_size = sizeof(app_glance_1);
|
||||
cl_assert_equal_i(app_glance_db_insert((uint8_t *)&APP_GLANCE_TEST_UUID, UUID_SIZE,
|
||||
(uint8_t *)&app_glance_1, glance_1_size),
|
||||
S_SUCCESS);
|
||||
cl_assert_equal_i(app_glance_db_get_len((uint8_t *)&APP_GLANCE_TEST_UUID, UUID_SIZE),
|
||||
glance_1_size);
|
||||
|
||||
// Try to insert a different glance blob with an older creation time; this should fail
|
||||
SerializedAppGlanceHeader app_glance_2 = (SerializedAppGlanceHeader) {
|
||||
.version = APP_GLANCE_DB_CURRENT_VERSION,
|
||||
.creation_time = 1464648084, // Mon, 30 May 2016 22:41:24 GMT
|
||||
};
|
||||
const size_t glance_2_size = sizeof(app_glance_2);
|
||||
cl_assert_equal_i(app_glance_db_insert((uint8_t *)&APP_GLANCE_TEST_UUID, UUID_SIZE,
|
||||
(uint8_t *)&app_glance_2, glance_2_size),
|
||||
E_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
void test_app_glance_db__glance_blob_with_too_many_slices_inserted_but_trimmed(void) {
|
||||
const size_t original_glance_size = sizeof(s_app_glance_with_too_many_slices);
|
||||
const size_t excess_slices_size = 11;
|
||||
const size_t trimmed_glance_size = original_glance_size - excess_slices_size;
|
||||
|
||||
// Insert the glance blob with too many slices; this should succeed
|
||||
cl_assert_equal_i(app_glance_db_insert((uint8_t *)&APP_GLANCE_TEST_UUID, UUID_SIZE,
|
||||
(uint8_t *)&s_app_glance_with_too_many_slices,
|
||||
original_glance_size),
|
||||
S_SUCCESS);
|
||||
// But the length we read back should be trimmed of the excess slices
|
||||
cl_assert_equal_i(app_glance_db_get_len((uint8_t *)&APP_GLANCE_TEST_UUID, UUID_SIZE),
|
||||
trimmed_glance_size);
|
||||
|
||||
// The glance blob read back from the database should match everything up to where we trimmed
|
||||
uint8_t glance_out[trimmed_glance_size];
|
||||
cl_assert_equal_i(app_glance_db_read((uint8_t *)&APP_GLANCE_TEST_UUID, UUID_SIZE, glance_out,
|
||||
trimmed_glance_size),
|
||||
S_SUCCESS);
|
||||
cl_assert_equal_m(glance_out, (uint8_t *)s_app_glance_with_too_many_slices, trimmed_glance_size);
|
||||
}
|
||||
|
||||
static void prv_check_invalid_version_code_blob_not_inserted(uint8_t version) {
|
||||
const SerializedAppGlanceHeader app_glance = (SerializedAppGlanceHeader) {
|
||||
.version = version,
|
||||
};
|
||||
|
||||
cl_assert_equal_i(app_glance_db_insert((uint8_t *)&APP_GLANCE_TEST_UUID, UUID_SIZE,
|
||||
(uint8_t *)&app_glance, sizeof(app_glance)),
|
||||
E_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
void test_app_glance_db__lower_version_blob_not_inserted(void) {
|
||||
for (uint8_t version = 0; version < APP_GLANCE_DB_CURRENT_VERSION; version++) {
|
||||
prv_check_invalid_version_code_blob_not_inserted(version);
|
||||
}
|
||||
}
|
||||
|
||||
void test_app_glance_db__higher_version_not_blob_inserted(void) {
|
||||
prv_check_invalid_version_code_blob_not_inserted(APP_GLANCE_DB_CURRENT_VERSION + 1);
|
||||
}
|
||||
|
||||
static status_t prv_insert_dummy_glance_blob_with_size(uint16_t blob_size) {
|
||||
const uint8_t dummy_app_glance[] = {
|
||||
// Version
|
||||
APP_GLANCE_DB_CURRENT_VERSION,
|
||||
// Creation time
|
||||
0x14, 0x13, 0x4E, 0x57, // 1464734484 (Tue, 31 May 2016 22:41:24 GMT)
|
||||
|
||||
// Slice 1
|
||||
(uint8_t)(blob_size & 0xFF), (uint8_t)(blob_size >> 8), // Total size
|
||||
};
|
||||
return app_glance_db_insert((uint8_t *)&APP_GLANCE_TEST_UUID, UUID_SIZE,
|
||||
(uint8_t *)&dummy_app_glance, sizeof(dummy_app_glance));
|
||||
}
|
||||
|
||||
void test_app_glance_db__check_too_small_blob_not_inserted(void) {
|
||||
cl_assert_equal_i(prv_insert_dummy_glance_blob_with_size(APP_GLANCE_DB_SLICE_MIN_SIZE - 1),
|
||||
E_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
void test_app_glance_db__check_too_large_blob_not_inserted(void) {
|
||||
cl_assert_equal_i(prv_insert_dummy_glance_blob_with_size(APP_GLANCE_DB_SLICE_MAX_SIZE + 1),
|
||||
E_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
void test_app_glance_db__check_invalid_slice_total_sizes_blob_not_inserted(void) {
|
||||
cl_assert_equal_i(app_glance_db_insert((uint8_t *)&APP_GLANCE_TEST_UUID, UUID_SIZE,
|
||||
(uint8_t *)&s_app_glance_with_invalid_slice_total_sizes,
|
||||
sizeof(s_app_glance_with_invalid_slice_total_sizes)),
|
||||
E_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
status_t app_glance_db_insert_stale(const uint8_t *key, int key_len, const uint8_t *val,
|
||||
int val_len);
|
||||
|
||||
void test_app_glance_db__read_stale_glance_blob(void) {
|
||||
// Force the insertion of a stale glance blob (outdated version)
|
||||
const SerializedAppGlanceHeader app_glance = (SerializedAppGlanceHeader) {
|
||||
.version = APP_GLANCE_DB_CURRENT_VERSION - 1,
|
||||
};
|
||||
cl_assert_equal_i(app_glance_db_insert_stale((uint8_t *)&APP_GLANCE_TEST_UUID, UUID_SIZE,
|
||||
(uint8_t *)&app_glance, sizeof(app_glance)),
|
||||
S_SUCCESS);
|
||||
|
||||
// Verify that trying to read the blob back fails due to it not existing
|
||||
SerializedAppGlanceHeader glance_out = {};
|
||||
cl_assert_equal_i(app_glance_db_read((uint8_t *)&APP_GLANCE_TEST_UUID, UUID_SIZE,
|
||||
(uint8_t *)&glance_out, sizeof(SerializedAppGlanceHeader)),
|
||||
E_DOES_NOT_EXIST);
|
||||
}
|
||||
|
||||
void test_app_glance_db__glance_blob_with_slice_missing_expiration_time_gets_default_value(void) {
|
||||
const uint8_t app_glance_with_slice_missing_expiration_time[] = {
|
||||
// Version
|
||||
APP_GLANCE_DB_CURRENT_VERSION,
|
||||
// Creation time
|
||||
0x14, 0x13, 0x4E, 0x57, // 1464734484 (Tue, 31 May 2016 22:41:24 GMT)
|
||||
|
||||
// Slice 1
|
||||
0x1B, 0x00, // Total size
|
||||
0x00, // AppGlanceSliceType - AppGlanceSliceType_IconAndSubtitle
|
||||
0x02, // Number of attributes
|
||||
// Slice Attributes
|
||||
0x30, // Attribute ID - AttributeIdIcon
|
||||
0x04, 0x00, // Attribute Length
|
||||
// Slice icon resource ID:
|
||||
0x69, 0x00, 0x00, 0x00, //
|
||||
0x2F, // Attribute ID - AttributeIdSubtitleTemplateString
|
||||
0x0D, 0x00, // Attribute Length
|
||||
// Slice subtitle:
|
||||
'T', 'e', 's', 't', ' ', 's', 'u', 'b', 't', 'i', 't', 'l', 'e',
|
||||
};
|
||||
const size_t app_glance_with_slice_missing_expiration_time_size =
|
||||
sizeof(app_glance_with_slice_missing_expiration_time);
|
||||
|
||||
cl_assert_equal_i(app_glance_db_insert((uint8_t *)&APP_GLANCE_TEST_UUID, UUID_SIZE,
|
||||
(uint8_t *)&app_glance_with_slice_missing_expiration_time,
|
||||
app_glance_with_slice_missing_expiration_time_size),
|
||||
S_SUCCESS);
|
||||
|
||||
AppGlance read_back_glance = {};
|
||||
cl_assert_equal_i(app_glance_db_read_glance(&APP_GLANCE_TEST_UUID, &read_back_glance), S_SUCCESS);
|
||||
cl_assert_equal_i(read_back_glance.slices[0].expiration_time, APP_GLANCE_SLICE_NO_EXPIRATION);
|
||||
}
|
||||
|
||||
// Glance Tests
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void test_app_glance_db__basic_glance_insert_and_read(void) {
|
||||
const AppGlance glance = (AppGlance) {
|
||||
.num_slices = 2,
|
||||
.slices = {
|
||||
{
|
||||
.expiration_time = 1464734484, // (Tue, 31 May 2016 22:41:24 GMT)
|
||||
.type = AppGlanceSliceType_IconAndSubtitle,
|
||||
.icon_and_subtitle = {
|
||||
.icon_resource_id = RESOURCE_ID_SETTINGS_ICON_AIRPLANE,
|
||||
.template_string = "Test subtitle",
|
||||
},
|
||||
},
|
||||
{
|
||||
.expiration_time = 1465579430, // (Fri, 10 Jun 2016 17:23:50 GMT)
|
||||
.type = AppGlanceSliceType_IconAndSubtitle,
|
||||
.icon_and_subtitle = {
|
||||
.icon_resource_id = RESOURCE_ID_SETTINGS_ICON_BLUETOOTH,
|
||||
.template_string = "Test subtitle 2",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
cl_assert_equal_i(app_glance_db_insert_glance(&APP_GLANCE_TEST_UUID, &glance), S_SUCCESS);
|
||||
|
||||
AppGlance read_back_glance = {};
|
||||
cl_assert_equal_i(app_glance_db_read_glance(&APP_GLANCE_TEST_UUID, &read_back_glance),
|
||||
S_SUCCESS);
|
||||
cl_assert_equal_m(&glance, &read_back_glance, sizeof(AppGlance));
|
||||
}
|
||||
|
||||
void test_app_glance_db__reading_nonexistent_glance_returns_does_not_exist(void) {
|
||||
AppGlance glance = {};
|
||||
cl_assert_equal_i(app_glance_db_read_glance(&UUID_INVALID, &glance), E_DOES_NOT_EXIST);
|
||||
}
|
||||
|
||||
void test_app_glance_db__reading_glance_with_invalid_arguments_fails(void) {
|
||||
// NULL UUID fails
|
||||
AppGlance glance_out = {};
|
||||
cl_assert_equal_i(app_glance_db_read_glance(NULL, &glance_out), E_INVALID_ARGUMENT);
|
||||
|
||||
// NULL glance_out fails
|
||||
cl_assert_equal_i(app_glance_db_read_glance(&APP_GLANCE_TEST_UUID, NULL), E_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
void test_app_glance_db__inserting_glance_with_invalid_arguments_fails(void) {
|
||||
// NULL UUID fails
|
||||
const AppGlance glance = {};
|
||||
cl_assert_equal_i(app_glance_db_insert_glance(NULL, &glance), E_INVALID_ARGUMENT);
|
||||
|
||||
// NULL glance fails
|
||||
cl_assert_equal_i(app_glance_db_insert_glance(&APP_GLANCE_TEST_UUID, NULL), E_INVALID_ARGUMENT);
|
||||
|
||||
// Glance with too many slices fails
|
||||
const AppGlance glance_with_too_many_slices = (AppGlance) {
|
||||
.num_slices = 1337,
|
||||
};
|
||||
cl_assert(glance_with_too_many_slices.num_slices > APP_GLANCE_DB_MAX_SLICES_PER_GLANCE);
|
||||
cl_assert_equal_i(app_glance_db_insert_glance(&APP_GLANCE_TEST_UUID,
|
||||
&glance_with_too_many_slices), E_INVALID_ARGUMENT);
|
||||
|
||||
// Glance containing a slice with an invalid type fails
|
||||
const AppGlance glance_containing_slice_with_invalid_type = (AppGlance) {
|
||||
.num_slices = 1,
|
||||
.slices = {
|
||||
{
|
||||
.expiration_time = 1464734484, // (Tue, 31 May 2016 22:41:24 GMT)
|
||||
.type = (AppGlanceSliceType)200,
|
||||
},
|
||||
},
|
||||
};
|
||||
cl_assert(glance_containing_slice_with_invalid_type.slices[0].type >= AppGlanceSliceTypeCount);
|
||||
cl_assert_equal_i(app_glance_db_insert_glance(&APP_GLANCE_TEST_UUID,
|
||||
&glance_containing_slice_with_invalid_type),
|
||||
E_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
void test_app_glance_db__read_glance_creation_time(void) {
|
||||
time_t time_out;
|
||||
|
||||
// Reading the creation time of a glance that doesn't exist should return "does not exist"
|
||||
cl_assert_equal_i(app_glance_db_read_creation_time(&APP_GLANCE_TEST_UUID, &time_out),
|
||||
E_DOES_NOT_EXIST);
|
||||
|
||||
// Insert a glance and check that the creation time we read back matches
|
||||
test_app_glance_db__basic_glance_blob_insert_and_read();
|
||||
cl_assert_equal_i(app_glance_db_read_creation_time(&APP_GLANCE_TEST_UUID, &time_out),
|
||||
S_SUCCESS);
|
||||
cl_assert_equal_i(time_out, 1464734484);
|
||||
}
|
||||
|
||||
void test_app_glance_db__read_glance_creation_time_with_invalid_arguments_fails(void) {
|
||||
// NULL UUID fails
|
||||
time_t time_out;
|
||||
cl_assert_equal_i(app_glance_db_read_creation_time(NULL, &time_out), E_INVALID_ARGUMENT);
|
||||
|
||||
// NULL time_out fails
|
||||
cl_assert_equal_i(app_glance_db_read_creation_time(&APP_GLANCE_TEST_UUID, NULL),
|
||||
E_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
void test_app_glance_db__empty_glance_insert_after_basic_glance_insert_succeeds(void) {
|
||||
// Call the basic glance insert test to insert the basic glance
|
||||
test_app_glance_db__basic_glance_insert_and_read();
|
||||
|
||||
// Let some time pass so the creation time of this next glance insertion is newer
|
||||
rtc_set_time(rtc_get_time() + 10);
|
||||
|
||||
// Try inserting an empty glance; this should succeed and clear the glance
|
||||
AppGlance empty_glance = {};
|
||||
cl_assert_equal_i(app_glance_db_insert_glance(&APP_GLANCE_TEST_UUID, &empty_glance), S_SUCCESS);
|
||||
AppGlance read_back_glance = {};
|
||||
cl_assert_equal_i(app_glance_db_read_glance(&APP_GLANCE_TEST_UUID, &read_back_glance),
|
||||
S_SUCCESS);
|
||||
cl_assert_equal_m(&empty_glance, &read_back_glance, sizeof(AppGlance));
|
||||
}
|
||||
|
||||
void test_app_glance_db__insert_no_app_installed(void) {
|
||||
s_app_install_id = INSTALL_ID_INVALID;
|
||||
cl_assert_equal_i(app_glance_db_insert((uint8_t *)&APP_GLANCE_TEST_UUID, UUID_SIZE,
|
||||
s_app_glance_basic, sizeof(s_app_glance_basic)), E_DOES_NOT_EXIST);
|
||||
}
|
||||
|
||||
void test_app_glance_db__insert_app_not_in_cache(void) {
|
||||
s_app_install_id = 10;
|
||||
s_app_cache_entry_exists = false;
|
||||
cl_assert_equal_i(app_glance_db_insert((uint8_t *)&APP_GLANCE_TEST_UUID, UUID_SIZE,
|
||||
s_app_glance_basic, sizeof(s_app_glance_basic)), S_SUCCESS);
|
||||
|
||||
cl_assert_equal_i(fake_event_get_count(), 1);
|
||||
PebbleEvent e = fake_event_get_last();
|
||||
cl_assert_equal_i(e.type, PEBBLE_APP_FETCH_REQUEST_EVENT);
|
||||
cl_assert(!e.app_fetch_request.with_ui);
|
||||
cl_assert_equal_i(e.app_fetch_request.id, 10);
|
||||
}
|
||||
|
||||
void test_app_glance_db__insert_app_in_cache(void) {
|
||||
cl_assert_equal_i(app_glance_db_insert((uint8_t *)&APP_GLANCE_TEST_UUID, UUID_SIZE,
|
||||
s_app_glance_basic, sizeof(s_app_glance_basic)), S_SUCCESS);
|
||||
cl_assert_equal_i(s_launch_count, 1);
|
||||
}
|
302
tests/fw/services/blob_db/test_blob_db2_endpoint.c
Normal file
302
tests/fw/services/blob_db/test_blob_db2_endpoint.c
Normal file
|
@ -0,0 +1,302 @@
|
|||
/*
|
||||
* 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 "clar.h"
|
||||
|
||||
#include "services/common/comm_session/session.h"
|
||||
#include "services/common/bluetooth/bluetooth_persistent_storage.h"
|
||||
#include "services/normal/blob_db/api.h"
|
||||
#include "services/normal/blob_db/endpoint.h"
|
||||
#include "services/normal/blob_db/sync.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
// Fakes
|
||||
////////////////////////////////////
|
||||
#include "fake_system_task.h"
|
||||
|
||||
// Stubs
|
||||
////////////////////////////////////
|
||||
#include "stubs_analytics.h"
|
||||
#include "stubs_app_cache.h"
|
||||
#include "stubs_ios_notif_pref_db.h"
|
||||
#include "stubs_app_db.h"
|
||||
#include "stubs_contacts_db.h"
|
||||
#include "stubs_notif_db.h"
|
||||
#include "stubs_pin_db.h"
|
||||
#include "stubs_prefs_db.h"
|
||||
#include "stubs_reminder_db.h"
|
||||
#include "stubs_watch_app_prefs_db.h"
|
||||
#include "stubs_weather_db.h"
|
||||
#include "stubs_bt_lock.h"
|
||||
#include "stubs_evented_timer.h"
|
||||
#include "stubs_events.h"
|
||||
#include "stubs_hexdump.h"
|
||||
#include "stubs_logging.h"
|
||||
#include "stubs_passert.h"
|
||||
#include "stubs_pbl_malloc.h"
|
||||
#include "stubs_reminders.h"
|
||||
#include "stubs_regular_timer.h"
|
||||
|
||||
|
||||
CommSession *comm_session_get_system_session(void) {
|
||||
return (CommSession *)1 ;
|
||||
}
|
||||
|
||||
void blob_db_set_accepting_messages(bool ehh) {
|
||||
}
|
||||
|
||||
static const uint8_t *s_expected_msg;
|
||||
static bool did_sync_next = false;
|
||||
static bool did_sync_cancel = false;
|
||||
static bool did_sync_db = false;
|
||||
|
||||
|
||||
static uint8_t sendbuffer[100];
|
||||
static int sendbuffer_length;
|
||||
static int sendbuffer_write_index;
|
||||
|
||||
extern void blob_db2_protocol_msg_callback(CommSession *session, const uint8_t* data, size_t length);
|
||||
|
||||
typedef void SendBuffer;
|
||||
|
||||
SendBuffer *comm_session_send_buffer_begin_write(CommSession *session, uint16_t endpoint_id,
|
||||
size_t required_payload_length,
|
||||
uint32_t timeout_ms) {
|
||||
cl_assert(required_payload_length < 100);
|
||||
sendbuffer_length = required_payload_length;
|
||||
sendbuffer_write_index = 0;
|
||||
return (void*)(uintptr_t)1;
|
||||
}
|
||||
|
||||
bool comm_session_send_buffer_write(SendBuffer *sb, const uint8_t *data, size_t length) {
|
||||
memcpy(&sendbuffer[sendbuffer_write_index], data, length);
|
||||
sendbuffer_write_index += length;
|
||||
return true;
|
||||
}
|
||||
|
||||
void comm_session_send_buffer_end_write(SendBuffer *sb) {
|
||||
cl_assert(sendbuffer_length > 0);
|
||||
cl_assert_equal_m(sendbuffer, s_expected_msg, sendbuffer_length);
|
||||
}
|
||||
|
||||
bool comm_session_send_data(CommSession *session, uint16_t endpoint_id,
|
||||
const uint8_t *data, size_t length, uint32_t timeout_ms) {
|
||||
cl_assert_equal_m(data, s_expected_msg, length);
|
||||
return true;
|
||||
}
|
||||
|
||||
extern void prv_send_response(CommSession *session, uint8_t *response, uint8_t response_length) {
|
||||
cl_assert_equal_m(response, s_expected_msg, response_length);
|
||||
}
|
||||
|
||||
static const BlobDBToken token = 0x22;
|
||||
extern BlobDBToken prv_new_token(void) {
|
||||
return token;
|
||||
}
|
||||
|
||||
void blob_db_sync_next(BlobDBSyncSession *session) {
|
||||
did_sync_next = true;
|
||||
}
|
||||
|
||||
void blob_db_sync_cancel(BlobDBSyncSession *session) {
|
||||
did_sync_cancel = true;
|
||||
}
|
||||
|
||||
status_t blob_db_sync_db(BlobDBId db_id) {
|
||||
did_sync_db = true;
|
||||
return S_SUCCESS;
|
||||
}
|
||||
|
||||
BlobDBSyncSession *blob_db_sync_get_session_for_token(BlobDBToken token) {
|
||||
// Don't return NULL
|
||||
return (BlobDBSyncSession *)1;
|
||||
}
|
||||
|
||||
extern void blob_db2_set_accepting_messages(bool ehh);
|
||||
void test_blob_db2_endpoint__initialize(void) {
|
||||
blob_db2_set_accepting_messages(true);
|
||||
did_sync_next = false;
|
||||
did_sync_cancel = false;
|
||||
did_sync_db = false;
|
||||
sendbuffer_length = 0;
|
||||
sendbuffer_write_index = 0;
|
||||
memset(sendbuffer, 0, sizeof(sendbuffer));
|
||||
}
|
||||
|
||||
void test_blob_db2_endpoint__cleanup(void) {
|
||||
}
|
||||
|
||||
|
||||
static const uint8_t s_dirty_dbs_request[] = {
|
||||
BLOB_DB_COMMAND_DIRTY_DBS, // cmd
|
||||
0x12, 0x34, // token
|
||||
};
|
||||
|
||||
static const uint8_t s_dirty_dbs_response[] = {
|
||||
BLOB_DB_COMMAND_DIRTY_DBS_RESPONSE, // cmd
|
||||
0x12, 0x34, // token
|
||||
BLOB_DB_SUCCESS, // status
|
||||
0x01, // num db_ids
|
||||
BlobDBIdiOSNotifPref // dirty db
|
||||
};
|
||||
|
||||
void test_blob_db2_endpoint__handle_dirty_dbs_request(void) {
|
||||
s_expected_msg = s_dirty_dbs_response;
|
||||
blob_db2_protocol_msg_callback(NULL, s_dirty_dbs_request, sizeof(s_dirty_dbs_request));
|
||||
}
|
||||
|
||||
|
||||
static const uint8_t s_start_sync_request[] = {
|
||||
BLOB_DB_COMMAND_START_SYNC, // cmd
|
||||
0x12, 0x34, // token
|
||||
BlobDBIdiOSNotifPref, // db id
|
||||
};
|
||||
|
||||
static const uint8_t s_start_sync_response[] = {
|
||||
BLOB_DB_COMMAND_START_SYNC_RESPONSE, // cmd
|
||||
0x12, 0x34, // token
|
||||
BLOB_DB_SUCCESS, // status
|
||||
};
|
||||
|
||||
void test_blob_db2_endpoint__handle_start_sync_request(void) {
|
||||
s_expected_msg = s_start_sync_response;
|
||||
blob_db2_protocol_msg_callback(NULL, s_start_sync_request, sizeof(s_start_sync_request));
|
||||
cl_assert(did_sync_db);
|
||||
}
|
||||
|
||||
|
||||
static const uint8_t s_start_write_response_success[] = {
|
||||
BLOB_DB_COMMAND_WRITE_RESPONSE, // cmd
|
||||
0x12, 0x34, // token
|
||||
BLOB_DB_SUCCESS, // response
|
||||
};
|
||||
|
||||
static const uint8_t s_start_write_response_error[] = {
|
||||
BLOB_DB_COMMAND_WRITE_RESPONSE, // cmd
|
||||
0x56, 0x78, // token
|
||||
BLOB_DB_GENERAL_FAILURE, // response
|
||||
};
|
||||
|
||||
void test_blob_db2_endpoint__handle_write_response(void) {
|
||||
blob_db2_protocol_msg_callback(NULL, s_start_write_response_success,
|
||||
sizeof(s_start_write_response_success));
|
||||
cl_assert(did_sync_next);
|
||||
|
||||
blob_db2_protocol_msg_callback(NULL, s_start_write_response_error,
|
||||
sizeof(s_start_write_response_error));
|
||||
cl_assert(did_sync_cancel);
|
||||
}
|
||||
|
||||
|
||||
static const uint8_t s_start_writeback_response_success[] = {
|
||||
BLOB_DB_COMMAND_WRITEBACK_RESPONSE, // cmd
|
||||
0x12, 0x34, // token
|
||||
BLOB_DB_SUCCESS, // response
|
||||
};
|
||||
|
||||
static const uint8_t s_start_writeback_response_error[] = {
|
||||
BLOB_DB_COMMAND_WRITEBACK_RESPONSE, // cmd
|
||||
0x56, 0x78, // token
|
||||
BLOB_DB_GENERAL_FAILURE, // response
|
||||
};
|
||||
|
||||
void test_blob_db2_endpoint__handle_writeback_response(void) {
|
||||
blob_db2_protocol_msg_callback(NULL, s_start_writeback_response_success,
|
||||
sizeof(s_start_writeback_response_success));
|
||||
cl_assert(did_sync_next);
|
||||
|
||||
blob_db2_protocol_msg_callback(NULL, s_start_writeback_response_error,
|
||||
sizeof(s_start_writeback_response_error));
|
||||
cl_assert(did_sync_cancel);
|
||||
}
|
||||
|
||||
static const uint8_t s_sync_done_response[] = {
|
||||
BLOB_DB_COMMAND_SYNC_DONE_RESPONSE, // cmd
|
||||
0x56, 0x78, // token
|
||||
BLOB_DB_SUCCESS, // response
|
||||
};
|
||||
|
||||
void test_blob_db2_endpoint__handle_sync_done_response(void) {
|
||||
blob_db2_protocol_msg_callback(NULL, s_sync_done_response, sizeof(s_sync_done_response));
|
||||
// We currently don't do anything with this message
|
||||
}
|
||||
|
||||
const uint8_t INVALID_CMD = 123;
|
||||
|
||||
static const uint8_t s_invalid_cmd[] = {
|
||||
INVALID_CMD, // invalid cmd
|
||||
0x56, 0x78, // token
|
||||
BLOB_DB_SUCCESS, // response
|
||||
};
|
||||
|
||||
static const uint8_t s_invalid_cmd_response[] = {
|
||||
INVALID_CMD | RESPONSE_MASK, // cmd
|
||||
0x56, 0x78, // token
|
||||
BLOB_DB_INVALID_OPERATION, // status
|
||||
};
|
||||
|
||||
void test_blob_db2_endpoint__handle_unknown_cmd_id(void) {
|
||||
s_expected_msg = s_invalid_cmd_response;
|
||||
blob_db2_protocol_msg_callback(NULL, s_invalid_cmd, sizeof(s_invalid_cmd));
|
||||
}
|
||||
|
||||
static const uint8_t s_sync_done_message[] = {
|
||||
BLOB_DB_COMMAND_SYNC_DONE, // cmd
|
||||
0x22, 0x00, // token
|
||||
BlobDBIdiOSNotifPref, // db id
|
||||
};
|
||||
|
||||
void test_blob_db2_endpoint__send_sync_done(void) {
|
||||
s_expected_msg = s_sync_done_message;
|
||||
blob_db_endpoint_send_sync_done(BlobDBIdiOSNotifPref);
|
||||
}
|
||||
|
||||
static const time_t last_updated = 1;
|
||||
static const uint8_t key = 9;
|
||||
static const uint8_t val = 2;
|
||||
|
||||
static const uint8_t s_writeback_message[] = {
|
||||
BLOB_DB_COMMAND_WRITEBACK, // cmd
|
||||
0x22, 0x00, // token
|
||||
BlobDBIdiOSNotifPref, // db id
|
||||
0x01, 0x00, 0x00, 0x00, // last updated
|
||||
0x01, // key_len
|
||||
key, // key
|
||||
0x01, 0x00, // val_len
|
||||
val, // val
|
||||
};
|
||||
|
||||
void test_blob_db2_endpoint__send_writeback(void) {
|
||||
s_expected_msg = s_writeback_message;
|
||||
blob_db_endpoint_send_writeback(BlobDBIdiOSNotifPref, last_updated, &key, 1, &val, 1);
|
||||
}
|
||||
|
||||
static const uint8_t s_write_message[] = {
|
||||
BLOB_DB_COMMAND_WRITE, // cmd
|
||||
0x22, 0x00, // token
|
||||
BlobDBIdiOSNotifPref, // db id
|
||||
0x01, 0x00, 0x00, 0x00, // last updated
|
||||
0x01, // key_len
|
||||
key, // key
|
||||
0x01, 0x00, // val_len
|
||||
val, // val
|
||||
};
|
||||
|
||||
void test_blob_db2_endpoint__send_write(void) {
|
||||
s_expected_msg = s_write_message;
|
||||
blob_db_endpoint_send_write(BlobDBIdiOSNotifPref, last_updated, &key, 1, &val, 1);
|
||||
}
|
563
tests/fw/services/blob_db/test_blob_db_endpoint.c
Normal file
563
tests/fw/services/blob_db/test_blob_db_endpoint.c
Normal file
|
@ -0,0 +1,563 @@
|
|||
/*
|
||||
* 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 "clar.h"
|
||||
|
||||
#include "services/common/comm_session/session.h"
|
||||
#include "services/common/bluetooth/bluetooth_persistent_storage.h"
|
||||
#include "services/normal/blob_db/api.h"
|
||||
#include "services/normal/blob_db/endpoint.h"
|
||||
#include "util/attributes.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
// Fakes
|
||||
////////////////////////////////////
|
||||
#include "fake_system_task.h"
|
||||
#include "fake_session.h"
|
||||
|
||||
// Stubs
|
||||
////////////////////////////////////
|
||||
#include "stubs_analytics.h"
|
||||
#include "stubs_app_cache.h"
|
||||
#include "stubs_ios_notif_pref_db.h"
|
||||
#include "stubs_app_db.h"
|
||||
#include "stubs_contacts_db.h"
|
||||
#include "stubs_notif_db.h"
|
||||
#include "stubs_pin_db.h"
|
||||
#include "stubs_prefs_db.h"
|
||||
#include "stubs_reminder_db.h"
|
||||
#include "stubs_watch_app_prefs_db.h"
|
||||
#include "stubs_weather_db.h"
|
||||
#include "stubs_bt_lock.h"
|
||||
#include "stubs_evented_timer.h"
|
||||
#include "stubs_events.h"
|
||||
#include "stubs_hexdump.h"
|
||||
#include "stubs_logging.h"
|
||||
#include "stubs_passert.h"
|
||||
#include "stubs_pbl_malloc.h"
|
||||
#include "stubs_reminders.h"
|
||||
#include "stubs_regular_timer.h"
|
||||
|
||||
void bt_persistent_storage_set_unfaithful(bool is_unfaithful) {
|
||||
return;
|
||||
}
|
||||
|
||||
void blob_db2_set_accepting_messages(bool ehh) {
|
||||
}
|
||||
|
||||
typedef struct PACKED {
|
||||
uint16_t length;
|
||||
uint16_t endpoint_id;
|
||||
} PebbleProtocolHeader;
|
||||
|
||||
extern void blob_db_protocol_msg_callback(CommSession *session, const uint8_t* data, size_t length);
|
||||
|
||||
static const uint16_t BLOB_DB_ENDPOINT_ID = 0xb1db;
|
||||
|
||||
// used to test the filling of the system_task queue
|
||||
static uint32_t system_task_queue_size = 7;
|
||||
|
||||
// used to examine sending buffer for valid contents
|
||||
static uint8_t s_data[1024];
|
||||
static uint16_t s_sending_endpoint_id = 0;
|
||||
static uint32_t s_sending_data_length = 0;
|
||||
static CommSession *s_session;
|
||||
|
||||
static const uint8_t TEST_KEY_SIZE = 16;
|
||||
static const uint16_t TEST_VALUE_SIZE = 320;
|
||||
static const uint8_t TEST_DB_ID = 0x01;
|
||||
|
||||
/* Helper functions */
|
||||
|
||||
static void prv_sent_data_cb(uint16_t endpoint_id,
|
||||
const uint8_t* data, unsigned int data_length) {
|
||||
s_sending_endpoint_id = endpoint_id;
|
||||
s_sending_data_length = data_length;
|
||||
memcpy(s_data, data, data_length);
|
||||
}
|
||||
|
||||
static uint8_t *process_blob_db_command(const uint8_t *command, uint32_t length) {
|
||||
s_sending_endpoint_id = 0;
|
||||
s_sending_data_length = 0;
|
||||
|
||||
blob_db_protocol_msg_callback(s_session, command, length);
|
||||
fake_system_task_callbacks_invoke_pending();
|
||||
fake_comm_session_process_send_next();
|
||||
cl_assert(BLOB_DB_ENDPOINT_ID == s_sending_endpoint_id);
|
||||
return s_data;
|
||||
}
|
||||
|
||||
/* Start of test */
|
||||
|
||||
extern void blob_db_set_accepting_messages(bool enabled);
|
||||
void test_blob_db_endpoint__initialize(void) {
|
||||
blob_db_set_accepting_messages(true);
|
||||
fake_comm_session_init();
|
||||
Transport *transport = fake_transport_create(TransportDestinationSystem, NULL, prv_sent_data_cb);
|
||||
s_session = fake_transport_set_connected(transport, true /* connected */);
|
||||
system_task_set_available_space(system_task_queue_size);
|
||||
}
|
||||
|
||||
void test_blob_db_endpoint__cleanup(void) {
|
||||
fake_comm_session_cleanup();
|
||||
}
|
||||
|
||||
/*************************************
|
||||
* Checking for valid INSERT command *
|
||||
*************************************/
|
||||
|
||||
static const uint8_t s_insert_cmd_success[] = {
|
||||
// Message Header
|
||||
0x01, // Pebble protocol message ID: INSERT
|
||||
0x17, 0x00, // Token
|
||||
TEST_DB_ID, // BlobDBDatabaseId: 0x01
|
||||
0x10, // Size primary key: sizeof(Uuid) = 16 = 0x10
|
||||
|
||||
// Primary Key: UUID:16
|
||||
0x6b, 0xf6, 0x21, 0x5b, 0xc9, 0x7f, 0x40, 0x9e,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4,
|
||||
|
||||
0x40, 0x01, // Size value
|
||||
|
||||
// value (made up for now)
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4, 0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4, 0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4, 0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4, 0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4, 0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4, 0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4, 0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4, 0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4, 0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4, 0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4, 0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4, 0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4, 0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4, 0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4, 0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4, 0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4, 0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4, 0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4, 0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4, 0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4,
|
||||
|
||||
};
|
||||
|
||||
void test_blob_db_endpoint__handle_insert_command_success(void) {
|
||||
uint8_t *cmd_ptr = (uint8_t*)s_insert_cmd_success;
|
||||
|
||||
// check for INSERT
|
||||
cl_assert(BLOB_DB_COMMAND_INSERT == *(uint8_t*)cmd_ptr);
|
||||
cmd_ptr += sizeof(uint8_t);
|
||||
|
||||
// check for token
|
||||
uint16_t token = *(uint16_t*)cmd_ptr;
|
||||
cl_assert(0 < token);
|
||||
cmd_ptr += sizeof(uint16_t);
|
||||
|
||||
// check for a Database entry
|
||||
cl_assert(TEST_DB_ID == *(uint8_t*)cmd_ptr);
|
||||
cmd_ptr += sizeof(uint8_t);
|
||||
|
||||
// check for a key size
|
||||
cl_assert(TEST_KEY_SIZE == *(uint8_t*)cmd_ptr);
|
||||
cmd_ptr += sizeof(uint8_t);
|
||||
|
||||
// go past key_bytes
|
||||
cmd_ptr += TEST_KEY_SIZE;
|
||||
|
||||
// size value
|
||||
cl_assert(TEST_VALUE_SIZE == *(uint16_t*)cmd_ptr);
|
||||
cmd_ptr += sizeof(uint16_t);
|
||||
|
||||
// go past value_bytes
|
||||
cmd_ptr += TEST_VALUE_SIZE;
|
||||
|
||||
cl_assert((cmd_ptr - s_insert_cmd_success) == sizeof(s_insert_cmd_success));
|
||||
|
||||
// Process Command
|
||||
uint8_t *resp_ptr = process_blob_db_command(s_insert_cmd_success, sizeof(s_insert_cmd_success));
|
||||
|
||||
// Check Response
|
||||
cl_assert(token == *(uint16_t*)resp_ptr);
|
||||
resp_ptr += sizeof(uint16_t);
|
||||
|
||||
cl_assert(BLOB_DB_SUCCESS == *resp_ptr);
|
||||
resp_ptr += sizeof(uint8_t);
|
||||
|
||||
cl_assert((resp_ptr - s_data) == s_sending_data_length);
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Checking for key size zero INSERT command *
|
||||
**************************************************/
|
||||
|
||||
static const uint8_t s_insert_cmd_zero_key_size[] = {
|
||||
// Message Header
|
||||
0x01, // Pebble protocol message ID: INSERT
|
||||
0x17, 0x00, // Token
|
||||
TEST_DB_ID, // BlobDBDatabaseId: 0x01
|
||||
0x00, // Size primary key: sizeof(Uuid) = 16 = 0x10
|
||||
|
||||
// garbage data to put message above minimum
|
||||
0x01, 0x02, 0x03, 0x04, 0x05,
|
||||
|
||||
// no value size
|
||||
};
|
||||
|
||||
void test_blob_db_endpoint__handle_insert_command_zero_key_size(void) {
|
||||
|
||||
// Ensure key length is 0
|
||||
cl_assert(s_insert_cmd_zero_key_size[2] == 0);
|
||||
|
||||
// Process Command
|
||||
uint8_t *resp_ptr = process_blob_db_command(s_insert_cmd_zero_key_size, sizeof(s_insert_cmd_zero_key_size));
|
||||
|
||||
// Check Response
|
||||
cl_assert(0 < *(uint16_t*)resp_ptr);
|
||||
resp_ptr += sizeof(uint16_t);
|
||||
|
||||
cl_assert(BLOB_DB_INVALID_DATA == *resp_ptr);
|
||||
resp_ptr += sizeof(uint8_t);
|
||||
|
||||
cl_assert((resp_ptr - s_data) == s_sending_data_length);
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Checking for value size of zero INSERT command *
|
||||
* This is valid because one can ZERO out a value *
|
||||
**************************************************/
|
||||
|
||||
static const uint8_t s_insert_cmd_zero_value_size[] = {
|
||||
// Message Header
|
||||
0x01, // Pebble protocol message ID: INSERT
|
||||
0x17, 0x00, // Token
|
||||
TEST_DB_ID, // BlobDBDatabaseId: 0x01
|
||||
0x10, // Size primary key: sizeof(Uuid) = 16 = 0x10
|
||||
|
||||
// Primary Key: UUID:16
|
||||
0x6b, 0xf6, 0x21, 0x5b, 0xc9, 0x7f, 0x40, 0x9e,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4,
|
||||
|
||||
0x00, 0x00, // Size value
|
||||
};
|
||||
|
||||
void test_blob_db_endpoint__handle_insert_command_zero_value_size(void) {
|
||||
|
||||
// Process Command
|
||||
uint8_t *resp_ptr = process_blob_db_command(s_insert_cmd_zero_value_size, sizeof(s_insert_cmd_zero_value_size));
|
||||
|
||||
// Check Response
|
||||
cl_assert(0 < *(uint16_t*)resp_ptr);
|
||||
resp_ptr += sizeof(uint16_t);
|
||||
|
||||
cl_assert(BLOB_DB_INVALID_DATA == *resp_ptr);
|
||||
resp_ptr += sizeof(uint8_t);
|
||||
|
||||
cl_assert((resp_ptr - s_data) == s_sending_data_length);
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Checking for below minimum size INSERT command *
|
||||
**************************************************/
|
||||
|
||||
static const uint8_t s_insert_cmd_no_value_size[] = {
|
||||
// Message Header
|
||||
0x01, // Pebble protocol message ID: INSERT
|
||||
0x17, 0x00, // Token
|
||||
TEST_DB_ID, // BlobDBDatabaseId: 0x01
|
||||
0x01, // Size primary key: 1 byte
|
||||
|
||||
// Primary Key: byte
|
||||
0x6b
|
||||
|
||||
// no value size
|
||||
};
|
||||
|
||||
void test_blob_db_endpoint__handle_insert_command_no_value_size(void) {
|
||||
|
||||
// Ensure packet is too small
|
||||
cl_assert(sizeof(s_insert_cmd_no_value_size) < 8);
|
||||
|
||||
// Process Command
|
||||
uint8_t *resp_ptr = process_blob_db_command(s_insert_cmd_no_value_size, sizeof(s_insert_cmd_no_value_size));
|
||||
|
||||
// Check Response
|
||||
cl_assert(0 < *(uint16_t*)resp_ptr);
|
||||
resp_ptr += sizeof(uint16_t);
|
||||
|
||||
cl_assert(BLOB_DB_INVALID_DATA == *resp_ptr);
|
||||
resp_ptr += sizeof(uint8_t);
|
||||
|
||||
cl_assert((resp_ptr - s_data) == s_sending_data_length);
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Checking for length data mismatch INSERT command *
|
||||
**************************************************/
|
||||
|
||||
static const uint8_t s_insert_cmd_size_value_wrong[] = {
|
||||
// Message Header
|
||||
0x01, // Pebble protocol message ID: INSERT
|
||||
0x17, 0x00, // Token
|
||||
TEST_DB_ID, // BlobDBDatabaseId: 0x01
|
||||
0x10, // Size primary key: sizeof(Uuid) = 16 = 0x10
|
||||
|
||||
// Primary Key: UUID:16
|
||||
0x6b, 0xf6, 0x21, 0x5b, 0xc9, 0x7f, 0x40, 0x9e,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4,
|
||||
|
||||
0x21, 0x00, // Size value is 1 more than it should be
|
||||
|
||||
// value (made up for now)
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4,
|
||||
};
|
||||
|
||||
void test_blob_db_endpoint__handle_insert_command_length_data_mismatch(void) {
|
||||
|
||||
// Process Command
|
||||
uint8_t *resp_ptr = process_blob_db_command(s_insert_cmd_size_value_wrong, sizeof(s_insert_cmd_size_value_wrong));
|
||||
|
||||
// Check Response
|
||||
cl_assert(0 < *(uint16_t*)resp_ptr);
|
||||
resp_ptr += sizeof(uint16_t);
|
||||
|
||||
cl_assert(BLOB_DB_INVALID_DATA == *resp_ptr);
|
||||
resp_ptr += sizeof(uint8_t);
|
||||
|
||||
cl_assert((resp_ptr - s_data) == s_sending_data_length);
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Checking for smallest possible valid INSERT command *
|
||||
**************************************************/
|
||||
|
||||
static const uint8_t s_insert_cmd_smallest_length[] = {
|
||||
// Message Header
|
||||
0x01, // Pebble protocol message ID: INSERT
|
||||
0x17, 0x00, // Token
|
||||
TEST_DB_ID, // BlobDBDatabaseId: 0x01
|
||||
0x01, // Size primary key: 1 byte
|
||||
|
||||
// Primary Key: 1 byte
|
||||
0x00,
|
||||
|
||||
0x01, 0x00, // Size value is 1 more than it should be
|
||||
|
||||
// value (made up for now)
|
||||
0x00
|
||||
};
|
||||
|
||||
void test_blob_db_endpoint__handle_insert_command_smallest_length(void) {
|
||||
|
||||
// Process Command
|
||||
uint8_t *resp_ptr = process_blob_db_command(s_insert_cmd_smallest_length, sizeof(s_insert_cmd_smallest_length));
|
||||
|
||||
// Check Response
|
||||
cl_assert(0 < *(uint16_t*)resp_ptr);
|
||||
resp_ptr += sizeof(uint16_t);
|
||||
|
||||
cl_assert(BLOB_DB_SUCCESS == *resp_ptr);
|
||||
resp_ptr += sizeof(uint8_t);
|
||||
|
||||
cl_assert((resp_ptr - s_data) == s_sending_data_length);
|
||||
}
|
||||
|
||||
/*************************************
|
||||
* Checking for valid DELETE command *
|
||||
*************************************/
|
||||
|
||||
static const uint8_t s_delete_cmd_success[] = {
|
||||
// Message Header
|
||||
0x04, // Pebble protocol message ID: DELETE
|
||||
0x17, 0x00, // Token
|
||||
TEST_DB_ID, // BlobDBDatabaseId: 0x01
|
||||
0x10, // Size primary key: sizeof(Uuid) = 16 = 0x10
|
||||
|
||||
// Primary Key: UUID:16
|
||||
0x6b, 0xf6, 0x21, 0x5b, 0xc9, 0x7f, 0x40, 0x9e,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4,
|
||||
};
|
||||
|
||||
void test_blob_db_endpoint__handle_delete_command_success(void) {
|
||||
uint8_t *cmd_ptr = (uint8_t*)s_delete_cmd_success;
|
||||
|
||||
// check for DELETE
|
||||
cl_assert(BLOB_DB_COMMAND_DELETE == *(uint8_t*)cmd_ptr);
|
||||
cmd_ptr += sizeof(uint8_t);
|
||||
|
||||
// check for token
|
||||
uint16_t token = *(uint16_t*)cmd_ptr;
|
||||
cl_assert(0 < token);
|
||||
cmd_ptr += sizeof(uint16_t);
|
||||
|
||||
// check for a Database entry
|
||||
cl_assert(TEST_DB_ID == *(uint8_t*)cmd_ptr);
|
||||
cmd_ptr += sizeof(uint8_t);
|
||||
|
||||
// check for a key size
|
||||
cl_assert(TEST_KEY_SIZE == *(uint8_t*)cmd_ptr);
|
||||
cmd_ptr += sizeof(uint8_t);
|
||||
|
||||
// go past key_bytes
|
||||
cmd_ptr += TEST_KEY_SIZE;
|
||||
|
||||
cl_assert((cmd_ptr - s_delete_cmd_success) == sizeof(s_delete_cmd_success)) ;
|
||||
|
||||
// Process Command
|
||||
uint8_t *resp_ptr = process_blob_db_command(s_delete_cmd_success, sizeof(s_delete_cmd_success));
|
||||
|
||||
// Check Response
|
||||
cl_assert(token == *(uint16_t*)resp_ptr);
|
||||
resp_ptr += sizeof(uint16_t);
|
||||
|
||||
cl_assert(BLOB_DB_SUCCESS == *resp_ptr);
|
||||
resp_ptr += sizeof(uint8_t);
|
||||
|
||||
cl_assert((resp_ptr - s_data) == s_sending_data_length);
|
||||
}
|
||||
|
||||
/*************************************
|
||||
* Checking for valid CLEAR command *
|
||||
*************************************/
|
||||
|
||||
static const uint8_t s_clear_cmd_success[] = {
|
||||
// Message Header
|
||||
0x05, // Pebble protocol message ID: DELETE
|
||||
0x17, 0x00, // Token
|
||||
TEST_DB_ID, // BlobDBDatabaseId: 0x01
|
||||
};
|
||||
|
||||
void test_blob_db_endpoint__handle_clear_command_success(void) {
|
||||
uint8_t *cmd_ptr = (uint8_t*)s_clear_cmd_success;
|
||||
|
||||
// check for CLEAR
|
||||
cl_assert(BLOB_DB_COMMAND_CLEAR == *(uint8_t*)cmd_ptr);
|
||||
cmd_ptr += sizeof(uint8_t);
|
||||
|
||||
// check for token
|
||||
uint16_t token = *(uint16_t*)cmd_ptr;
|
||||
cl_assert(0 < token);
|
||||
cmd_ptr += sizeof(uint16_t);
|
||||
|
||||
// check for a Database entry
|
||||
cl_assert(TEST_DB_ID == *(uint8_t*)cmd_ptr);
|
||||
cmd_ptr += sizeof(uint8_t);
|
||||
|
||||
cl_assert((cmd_ptr - s_clear_cmd_success) == sizeof(s_clear_cmd_success)) ;
|
||||
|
||||
// Process Command
|
||||
uint8_t *resp_ptr = process_blob_db_command(s_clear_cmd_success, sizeof(s_clear_cmd_success));
|
||||
|
||||
// Check Response
|
||||
cl_assert_equal_i(token, *(uint16_t*)resp_ptr);
|
||||
resp_ptr += sizeof(uint16_t);
|
||||
|
||||
cl_assert(BLOB_DB_SUCCESS == *resp_ptr);
|
||||
resp_ptr += sizeof(uint8_t);
|
||||
|
||||
cl_assert_equal_i((resp_ptr - s_data), s_sending_data_length);
|
||||
}
|
||||
|
||||
/*************************************
|
||||
* Checking for invalid operation *
|
||||
*************************************/
|
||||
|
||||
static const uint8_t s_invalid_operation_cmd[] = {
|
||||
// Message Header
|
||||
0x42, // Pebble protocol message ID: This does not exist
|
||||
0x17, 0x00, // Token
|
||||
TEST_DB_ID, // BlobDBDatabaseId: 0x01
|
||||
};
|
||||
|
||||
void test_blob_db_endpoint__handle_invalid_operation_command(void) {
|
||||
uint8_t *cmd_ptr = (uint8_t*)s_invalid_operation_cmd;
|
||||
|
||||
cmd_ptr += sizeof(uint8_t);
|
||||
|
||||
// check for token
|
||||
uint16_t token = *(uint16_t*)cmd_ptr;
|
||||
cl_assert(0 < token);
|
||||
cmd_ptr += sizeof(uint16_t);
|
||||
|
||||
// check for a Database entry
|
||||
cl_assert(TEST_DB_ID == *(uint8_t*)cmd_ptr);
|
||||
cmd_ptr += sizeof(uint8_t);
|
||||
|
||||
cl_assert((cmd_ptr - s_invalid_operation_cmd) == sizeof(s_invalid_operation_cmd)) ;
|
||||
|
||||
// Process Command
|
||||
uint8_t *resp_ptr = process_blob_db_command(s_invalid_operation_cmd, sizeof(s_invalid_operation_cmd));
|
||||
|
||||
// Check Response
|
||||
cl_assert(token == *(uint16_t*)resp_ptr);
|
||||
resp_ptr += sizeof(uint16_t);
|
||||
|
||||
cl_assert(BLOB_DB_INVALID_OPERATION == *resp_ptr);
|
||||
resp_ptr += sizeof(uint8_t);
|
||||
|
||||
cl_assert((resp_ptr - s_data) == s_sending_data_length);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// BLOBDB SYNC TESTS
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static const uint8_t *s_expected_data;
|
||||
|
||||
extern void prv_send_v2_response(CommSession *session, uint8_t *response, uint8_t response_length) {
|
||||
cl_assert_equal_m(response, s_expected_data, response_length);
|
||||
}
|
||||
|
||||
|
||||
static const uint8_t s_dirty_dbs_request[] = {
|
||||
BLOB_DB_COMMAND_DIRTY_DBS, // cmd
|
||||
0x12, 0x34, // token
|
||||
};
|
||||
|
||||
static const uint8_t s_dirty_dbs_response[] = {
|
||||
BLOB_DB_COMMAND_DIRTY_DBS_RESPONSE, // cmd
|
||||
0x12, 0x34, // token
|
||||
BLOB_DB_SUCCESS, // status
|
||||
0x01, // num db_ids
|
||||
BlobDBIdiOSNotifPref // dirty db
|
||||
};
|
||||
|
||||
void test_blob_db_endpoint__handle_dirty_dbs_request(void) {
|
||||
s_expected_data = s_dirty_dbs_response;
|
||||
blob_db_protocol_msg_callback(NULL, s_dirty_dbs_request, sizeof(s_dirty_dbs_request));
|
||||
}
|
||||
|
||||
static const uint8_t s_start_sync_request[] = {
|
||||
BLOB_DB_COMMAND_START_SYNC, // cmd
|
||||
0x12, 0x34, // token
|
||||
};
|
||||
|
||||
static const uint8_t s_start_sync_response[] = {
|
||||
BLOB_DB_COMMAND_START_SYNC_RESPONSE, // cmd
|
||||
0x12, 0x34, // token
|
||||
BLOB_DB_SUCCESS, // status
|
||||
};
|
||||
|
||||
void test_blob_db_endpoint__handle_start_sync_request(void) {
|
||||
s_expected_data = s_start_sync_response;
|
||||
blob_db_protocol_msg_callback(NULL, s_start_sync_request, sizeof(s_start_sync_request));
|
||||
}
|
||||
|
337
tests/fw/services/blob_db/test_blob_db_sync.c
Normal file
337
tests/fw/services/blob_db/test_blob_db_sync.c
Normal file
|
@ -0,0 +1,337 @@
|
|||
/*
|
||||
* 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 "clar.h"
|
||||
|
||||
// Fakes
|
||||
/////////////
|
||||
#include "fake_system_task.h"
|
||||
#include "fake_regular_timer.h"
|
||||
#include "fake_blobdb.h"
|
||||
|
||||
// Stubs
|
||||
/////////////
|
||||
#include "stubs_pbl_malloc.h"
|
||||
#include "stubs_logging.h"
|
||||
#include "stubs_passert.h"
|
||||
#include "stubs_session.h"
|
||||
|
||||
// FW Includes
|
||||
///////////////
|
||||
#include "services/normal/blob_db/api.h"
|
||||
#include "services/normal/blob_db/util.h"
|
||||
#include "services/normal/blob_db/sync.h"
|
||||
#include "util/size.h"
|
||||
|
||||
|
||||
// Writebacks counter
|
||||
////////////////////////
|
||||
|
||||
static int s_num_writebacks;
|
||||
static int s_num_until_timeout;
|
||||
|
||||
void blob_db_endpoint_send_sync_done(BlobDBId db_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
static void prv_handle_response_from_phone(void *data) {
|
||||
s_num_writebacks++;
|
||||
BlobDBSyncSession *session = data;
|
||||
blob_db_sync_next(session);
|
||||
}
|
||||
|
||||
static void prv_generate_responses_from_phone(void) {
|
||||
while (fake_system_task_count_callbacks()) {
|
||||
fake_system_task_callbacks_invoke_pending();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
BlobDBToken blob_db_endpoint_send_writeback(BlobDBId db_id,
|
||||
time_t last_updated,
|
||||
const void *key,
|
||||
int key_len,
|
||||
const void *val,
|
||||
int val_len) {
|
||||
BlobDBSyncSession *session = blob_db_sync_get_session_for_id(db_id);
|
||||
cl_assert(session != NULL);
|
||||
if (s_num_until_timeout != 0 && s_num_writebacks >= s_num_until_timeout) {
|
||||
fake_regular_timer_trigger(&session->timeout_timer);
|
||||
} else {
|
||||
system_task_add_callback(prv_handle_response_from_phone, session);
|
||||
}
|
||||
|
||||
return 12345;
|
||||
}
|
||||
|
||||
BlobDBToken blob_db_endpoint_send_write(BlobDBId db_id,
|
||||
time_t last_updated,
|
||||
const void *key,
|
||||
int key_len,
|
||||
const void *val,
|
||||
int val_len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Tests
|
||||
////////////////////////
|
||||
|
||||
void test_blob_db_sync__initialize(void) {
|
||||
fake_blob_db_set_id(BlobDBIdTest);
|
||||
blob_db_init_dbs();
|
||||
s_num_until_timeout = 0;
|
||||
s_num_writebacks = 0;
|
||||
}
|
||||
|
||||
void test_blob_db_sync__cleanup(void) {
|
||||
blob_db_flush(BlobDBIdTest);
|
||||
fake_system_task_callbacks_cleanup();
|
||||
}
|
||||
|
||||
void test_blob_db_sync__no_dirty(void) {
|
||||
uint8_t ids[NumBlobDBs];
|
||||
uint8_t num_ids;
|
||||
blob_db_get_dirty_dbs(ids, &num_ids);
|
||||
cl_assert_equal_i(num_ids, 0);
|
||||
cl_assert(blob_db_get_dirty_list(BlobDBIdTest) == NULL);
|
||||
|
||||
// insert one
|
||||
char *key = "key";
|
||||
char *value = "value";
|
||||
cl_assert_equal_i(S_SUCCESS, blob_db_insert(BlobDBIdTest,
|
||||
(uint8_t *)key,
|
||||
strlen(key),
|
||||
(uint8_t *)value,
|
||||
strlen(value)));
|
||||
blob_db_get_dirty_dbs(ids, &num_ids);
|
||||
cl_assert_equal_i(num_ids, 1);
|
||||
cl_assert(blob_db_get_dirty_list(BlobDBIdTest) != NULL);
|
||||
|
||||
// mark it synced
|
||||
cl_assert_equal_i(S_SUCCESS, blob_db_mark_synced(BlobDBIdTest, (uint8_t *)key, strlen(key)));
|
||||
blob_db_get_dirty_dbs(ids, &num_ids);
|
||||
cl_assert_equal_i(num_ids, 0);
|
||||
cl_assert(blob_db_get_dirty_list(BlobDBIdTest) == NULL);
|
||||
}
|
||||
|
||||
static bool prv_list_key_comparator(ListNode *cur_node, void *data) {
|
||||
BlobDBDirtyItem *dirty_item = (BlobDBDirtyItem *)cur_node;
|
||||
char *key = data;
|
||||
return (memcmp(dirty_item->key, key, dirty_item->key_len) == 0);
|
||||
}
|
||||
|
||||
void test_blob_db_sync__dirty_list(void) {
|
||||
uint8_t ids[NumBlobDBs];
|
||||
uint8_t num_ids;
|
||||
blob_db_get_dirty_dbs(ids, &num_ids);
|
||||
cl_assert_equal_i(num_ids, 0);
|
||||
BlobDBDirtyItem *dirty_list = blob_db_get_dirty_list(BlobDBIdTest);
|
||||
cl_assert(dirty_list == NULL);
|
||||
blob_db_util_free_dirty_list(dirty_list);
|
||||
|
||||
char *keys[] = { "key1", "key2", "key3", "key4", "key5" };
|
||||
int key_len = strlen(keys[0]);
|
||||
char *values[] = { "val1", "val2", "val3", "val4", "val5" };
|
||||
int value_len = strlen(values[0]);
|
||||
|
||||
// insert all keys
|
||||
for (int i = 0; i < ARRAY_LENGTH(keys); ++i) {
|
||||
blob_db_insert(BlobDBIdTest, (uint8_t *)keys[i], key_len, (uint8_t *)values[i], value_len);
|
||||
}
|
||||
|
||||
// check the dirty list
|
||||
blob_db_get_dirty_dbs(ids, &num_ids);
|
||||
cl_assert_equal_i(num_ids, 1);
|
||||
dirty_list = blob_db_get_dirty_list(BlobDBIdTest);
|
||||
cl_assert_equal_i(list_count(&dirty_list->node), ARRAY_LENGTH(keys));
|
||||
|
||||
for (int i = 0; i < ARRAY_LENGTH(keys); ++i) {
|
||||
cl_assert(list_find(&dirty_list->node, prv_list_key_comparator, keys[i]) != NULL);
|
||||
}
|
||||
|
||||
blob_db_util_free_dirty_list(dirty_list);
|
||||
|
||||
// mark one as synced and re-check
|
||||
for (int synced_idx = 1; synced_idx < ARRAY_LENGTH(keys); ++synced_idx) {
|
||||
blob_db_mark_synced(BlobDBIdTest, (uint8_t *)keys[synced_idx - 1], key_len);
|
||||
dirty_list = blob_db_get_dirty_list(BlobDBIdTest);
|
||||
cl_assert_equal_i(list_count(&dirty_list->node), ARRAY_LENGTH(keys) - synced_idx);
|
||||
for (int i = synced_idx; i < ARRAY_LENGTH(keys); ++i) {
|
||||
cl_assert(list_find(&dirty_list->node, prv_list_key_comparator, keys[i]) != NULL);
|
||||
}
|
||||
blob_db_util_free_dirty_list(dirty_list);
|
||||
}
|
||||
}
|
||||
|
||||
void test_blob_db_sync__sync_all(void) {
|
||||
char *keys[] = { "key1", "key2", "key3", "key4", "key5" };
|
||||
int key_len = strlen(keys[0]);
|
||||
char *values[] = { "val1", "val2", "val3", "val4", "val5" };
|
||||
int value_len = strlen(values[0]);
|
||||
|
||||
// insert all keys
|
||||
for (int i = 0; i < ARRAY_LENGTH(keys); ++i) {
|
||||
blob_db_insert(BlobDBIdTest, (uint8_t *)keys[i], key_len, (uint8_t *)values[i], value_len);
|
||||
}
|
||||
|
||||
cl_assert(blob_db_sync_db(BlobDBIdTest) == S_SUCCESS);
|
||||
prv_generate_responses_from_phone();
|
||||
|
||||
cl_assert_equal_i(s_num_writebacks, 5);
|
||||
}
|
||||
|
||||
void test_blob_db_sync__sync_oom(void) {
|
||||
char *keys[] = { "key1", "key2", "key3", "key4", "key5" };
|
||||
int key_len = strlen(keys[0]);
|
||||
char *values[] = { "val1", "val2", "val3", "val4", "val5" };
|
||||
int value_len = strlen(values[0]);
|
||||
|
||||
// insert all keys
|
||||
for (int i = 0; i < ARRAY_LENGTH(keys); ++i) {
|
||||
blob_db_insert(BlobDBIdTest, (uint8_t *)keys[i], key_len, (uint8_t *)values[i], value_len);
|
||||
}
|
||||
|
||||
cl_assert(blob_db_sync_db(BlobDBIdTest) == S_SUCCESS);
|
||||
|
||||
// We have built the dirty list, add more entries.
|
||||
// This mimics us performing writes while the sync is ongoing or not having enough memory to
|
||||
// build the initial list
|
||||
char *extra_keys[] = { "keyA", "keyB" };
|
||||
char *extra_values[] = { "valA", "valB" };
|
||||
for (int i = 0; i < ARRAY_LENGTH(extra_keys); ++i) {
|
||||
blob_db_insert(BlobDBIdTest, (uint8_t *)extra_keys[i], key_len,
|
||||
(uint8_t *)extra_values[i], value_len);
|
||||
}
|
||||
|
||||
prv_generate_responses_from_phone();
|
||||
|
||||
cl_assert_equal_i(s_num_writebacks, 7);
|
||||
}
|
||||
|
||||
void test_blob_db_sync__sync_some(void) {
|
||||
char *keys[] = { "key1", "key2", "key3", "key4", "key5" };
|
||||
int key_len = strlen(keys[0]);
|
||||
char *values[] = { "val1", "val2", "val3", "val4", "val5" };
|
||||
int value_len = strlen(values[0]);
|
||||
|
||||
// insert all keys, mark some as synced
|
||||
for (int i = 0; i < ARRAY_LENGTH(keys); ++i) {
|
||||
blob_db_insert(BlobDBIdTest, (uint8_t *)keys[i], key_len, (uint8_t *)values[i], value_len);
|
||||
// choose two that are not consecutive, that leaves 3 still to be synced
|
||||
if (i == 1 || i == 3) {
|
||||
blob_db_mark_synced(BlobDBIdTest, (uint8_t *)keys[i], key_len);
|
||||
}
|
||||
}
|
||||
|
||||
cl_assert(blob_db_sync_db(BlobDBIdTest) == S_SUCCESS);
|
||||
prv_generate_responses_from_phone();
|
||||
|
||||
cl_assert_equal_i(s_num_writebacks, 3);
|
||||
}
|
||||
|
||||
void test_blob_db_sync__timeout_and_retry(void) {
|
||||
char *keys[] = { "key1", "key2", "key3", "key4", "key5" };
|
||||
int key_len = strlen(keys[0]);
|
||||
char *values[] = { "val1", "val2", "val3", "val4", "val5" };
|
||||
int value_len = strlen(values[0]);
|
||||
|
||||
// insert all keys, mark some as synced
|
||||
for (int i = 0; i < ARRAY_LENGTH(keys); ++i) {
|
||||
blob_db_insert(BlobDBIdTest, (uint8_t *)keys[i], key_len, (uint8_t *)values[i], value_len);
|
||||
}
|
||||
|
||||
s_num_until_timeout = 3;
|
||||
s_num_writebacks = 0;
|
||||
cl_assert(blob_db_sync_db(BlobDBIdTest) == S_SUCCESS);
|
||||
prv_generate_responses_from_phone();
|
||||
cl_assert_equal_i(s_num_writebacks, s_num_until_timeout);
|
||||
s_num_until_timeout = 0;
|
||||
cl_assert(blob_db_sync_db(BlobDBIdTest) == S_SUCCESS);
|
||||
prv_generate_responses_from_phone();
|
||||
cl_assert_equal_i(s_num_writebacks, 5);
|
||||
}
|
||||
|
||||
void test_blob_db_sync__sync_while_syncing(void) {
|
||||
char *keys[] = { "key1", "key2", "key3", "key4", "key5" };
|
||||
int key_len = strlen(keys[0]);
|
||||
char *values[] = { "val1", "val2", "val3", "val4", "val5" };
|
||||
int value_len = strlen(values[0]);
|
||||
|
||||
for (int i = 0; i < ARRAY_LENGTH(keys); ++i) {
|
||||
blob_db_insert(BlobDBIdTest, (uint8_t *)keys[i], key_len, (uint8_t *)values[i], value_len);
|
||||
}
|
||||
|
||||
cl_assert(blob_db_sync_db(BlobDBIdTest) == S_SUCCESS);
|
||||
|
||||
// We should throw an error if we get a sync while a db sync in in progress
|
||||
cl_assert(blob_db_sync_db(BlobDBIdTest) == E_BUSY);
|
||||
|
||||
// Generate some responses so the sync session gets cleaned up
|
||||
prv_generate_responses_from_phone();
|
||||
}
|
||||
|
||||
static void prv_fill_stop_return_session(BlobDBId id) {
|
||||
char *keys[] = { "key1", "key2", "key3", "key4", "key5" };
|
||||
int key_len = strlen(keys[0]);
|
||||
char *values[] = { "val1", "val2", "val3", "val4", "val5" };
|
||||
int value_len = strlen(values[0]);
|
||||
|
||||
fake_blob_db_set_id(id);
|
||||
blob_db_init_dbs();
|
||||
for (int i = 0; i < ARRAY_LENGTH(keys); ++i) {
|
||||
blob_db_insert(id, (uint8_t *)keys[i], key_len, (uint8_t *)values[i], value_len);
|
||||
}
|
||||
s_num_writebacks = 0;
|
||||
cl_assert(blob_db_sync_db(id) == S_SUCCESS);
|
||||
}
|
||||
|
||||
void test_blob_db_sync__find_session(void) {
|
||||
// create a few sync sessions
|
||||
prv_fill_stop_return_session(BlobDBIdTest);
|
||||
prv_fill_stop_return_session(BlobDBIdPins);
|
||||
prv_fill_stop_return_session(BlobDBIdReminders);
|
||||
|
||||
// check we can conjure them by id
|
||||
BlobDBSyncSession *test_session = blob_db_sync_get_session_for_id(BlobDBIdTest);
|
||||
cl_assert(test_session);
|
||||
cl_assert_equal_i(test_session->db_id, BlobDBIdTest);
|
||||
BlobDBSyncSession *pins_session = blob_db_sync_get_session_for_id(BlobDBIdPins);
|
||||
cl_assert(pins_session);
|
||||
cl_assert_equal_i(pins_session->db_id, BlobDBIdPins);
|
||||
BlobDBSyncSession *reminders_session = blob_db_sync_get_session_for_id(BlobDBIdReminders);
|
||||
cl_assert(reminders_session);
|
||||
cl_assert_equal_i(reminders_session->db_id, BlobDBIdReminders);
|
||||
|
||||
test_session->current_token = 1;
|
||||
pins_session->current_token = 2;
|
||||
reminders_session->current_token = 3;
|
||||
|
||||
// check we can conjure them by token
|
||||
cl_assert(test_session == blob_db_sync_get_session_for_token(1));
|
||||
cl_assert(pins_session == blob_db_sync_get_session_for_token(2));
|
||||
cl_assert(reminders_session == blob_db_sync_get_session_for_token(3));
|
||||
|
||||
// Cancel the sync sessions so they get cleaned up
|
||||
blob_db_sync_cancel(test_session);
|
||||
blob_db_sync_cancel(pins_session);
|
||||
blob_db_sync_cancel(reminders_session);
|
||||
|
||||
// reset fake blob db so cleanup doesn't assert
|
||||
fake_blob_db_set_id(BlobDBIdTest);
|
||||
blob_db_init_dbs();
|
||||
}
|
||||
|
162
tests/fw/services/blob_db/test_contacts_db.c
Normal file
162
tests/fw/services/blob_db/test_contacts_db.c
Normal file
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* 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 "clar.h"
|
||||
|
||||
#include "services/normal/filesystem/pfs.h"
|
||||
#include "services/normal/blob_db/contacts_db.h"
|
||||
#include "services/normal/contacts/contacts.h"
|
||||
#include "util/uuid.h"
|
||||
|
||||
// Fixture
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// Fakes
|
||||
////////////////////////////////////////////////////////////////
|
||||
#include "fake_spi_flash.h"
|
||||
#include "fake_system_task.h"
|
||||
#include "fake_kernel_services_notifications.h"
|
||||
|
||||
// Stubs
|
||||
////////////////////////////////////////////////////////////////
|
||||
#include "stubs_analytics.h"
|
||||
#include "stubs_hexdump.h"
|
||||
#include "stubs_layout_layer.h"
|
||||
#include "stubs_logging.h"
|
||||
#include "stubs_mutex.h"
|
||||
#include "stubs_passert.h"
|
||||
#include "stubs_pbl_malloc.h"
|
||||
#include "stubs_prompt.h"
|
||||
#include "stubs_rand_ptr.h"
|
||||
#include "stubs_sleep.h"
|
||||
#include "stubs_task_watchdog.h"
|
||||
|
||||
#define CONTACT_1_UUID 0x0a, 0x04, 0x98, 0x00, 0x39, 0x18, 0x47, 0xaa, 0x9c, 0x16, 0x8e, 0xa0, 0xa8, 0x2a, 0x2e, 0xb8
|
||||
#define ADDRESS_1_UUID 0xd3, 0x72, 0x2d, 0x75, 0x6b, 0x21, 0x49, 0x2a, 0x9c, 0xc7, 0x5f, 0xf8, 0x4d, 0xd2, 0x5a, 0x9c
|
||||
#define ADDRESS_2_UUID 0x43, 0x03, 0x91, 0x06, 0x80, 0x39, 0x48, 0xea, 0x92, 0x72, 0xf3, 0x4c, 0xd5, 0x35, 0x9c, 0xcf
|
||||
|
||||
static const uint8_t s_contact_1[] = {
|
||||
// Uuid
|
||||
CONTACT_1_UUID,
|
||||
// Flags
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
// Number of Attributes,
|
||||
0x01,
|
||||
// Number of Addresses,
|
||||
0x02,
|
||||
|
||||
// Attribute 1
|
||||
0x01, // Attribute ID - Title
|
||||
0x08, 0x00, // Attribute Length
|
||||
// Attribute text: "John Doe"
|
||||
'J', 'o', 'h', 'n', ' ', 'D', 'o', 'e',
|
||||
|
||||
// Address 1
|
||||
// Uuid
|
||||
ADDRESS_1_UUID,
|
||||
0x01, // AddressType - PhoneNumber
|
||||
0x02, // Number of attributes
|
||||
// Address Attributes
|
||||
0x01, // Attribute ID - Title
|
||||
0x06, 0x00, // Attribute Length
|
||||
// Attribute text:
|
||||
'm', 'o', 'b', 'i', 'l', 'e',
|
||||
0x27, // Attribute ID - Address
|
||||
0x0a, 0x00, // Attribute Length
|
||||
// Attribute text:
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
|
||||
// Address 2
|
||||
// Uuid
|
||||
ADDRESS_2_UUID,
|
||||
0x02, // AddressType - Email
|
||||
0x02, // Number of attributes
|
||||
// Address Attributes
|
||||
0x01, // Attribute ID - Title
|
||||
0x04, 0x00, // Attribute Length
|
||||
// Attribute text:
|
||||
'h', 'o', 'm', 'e',
|
||||
0x27, // Attribute ID - Address
|
||||
0x10, 0x00, // Attribute Length
|
||||
// Attribute text:
|
||||
'n', 'a', 'm', 'e', '@', 'e', 'x', 'a', 'm', 'p', 'l', 'e', '.', 'c', 'o', 'm',
|
||||
};
|
||||
|
||||
|
||||
// Setup
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void test_contacts_db__initialize(void) {
|
||||
fake_spi_flash_init(0, 0x1000000);
|
||||
pfs_init(false);
|
||||
contacts_db_init();
|
||||
}
|
||||
|
||||
void test_contacts_db__cleanup(void) {
|
||||
}
|
||||
|
||||
// Tests
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void test_contacts_db__insert(void) {
|
||||
uint8_t contact[sizeof(s_contact_1)];
|
||||
memcpy(contact, s_contact_1, sizeof(s_contact_1));
|
||||
|
||||
cl_assert_equal_i(contacts_db_insert((uint8_t *)&contact, UUID_SIZE,
|
||||
(uint8_t *)&contact, sizeof(contact)), 0);
|
||||
cl_assert_equal_i(contacts_db_get_len((uint8_t *)&contact, UUID_SIZE), sizeof(contact));
|
||||
|
||||
uint8_t *contact_out = kernel_malloc(sizeof(contact));
|
||||
cl_assert_equal_i(contacts_db_read((uint8_t *)&contact, UUID_SIZE,
|
||||
contact_out, sizeof(contact)), 0);
|
||||
cl_assert_equal_m((uint8_t *)s_contact_1, contact_out, sizeof(contact));
|
||||
kernel_free(contact_out);
|
||||
}
|
||||
|
||||
void test_contacts_db__insert_remove(void) {
|
||||
uint8_t contact[sizeof(s_contact_1)];
|
||||
memcpy(contact, s_contact_1, sizeof(s_contact_1));
|
||||
|
||||
cl_assert_equal_i(contacts_db_insert((uint8_t *)&contact, UUID_SIZE, (uint8_t *)&contact, sizeof(contact)), 0);
|
||||
cl_assert_equal_i(contacts_db_delete((uint8_t *)&contact, UUID_SIZE), 0);
|
||||
cl_assert_equal_i(contacts_db_get_len((uint8_t *)&contact, UUID_SIZE), 0);
|
||||
}
|
||||
|
||||
void test_contacts_db__flush(void) {
|
||||
uint8_t contact[sizeof(s_contact_1)];
|
||||
memcpy(contact, s_contact_1, sizeof(s_contact_1));
|
||||
|
||||
cl_assert_equal_i(contacts_db_insert((uint8_t *)&contact, UUID_SIZE, (uint8_t *)&contact, sizeof(contact)), 0);
|
||||
cl_assert_equal_i(contacts_db_flush(), 0);
|
||||
fake_system_task_callbacks_invoke_pending();
|
||||
cl_assert_equal_i(contacts_db_get_len((uint8_t *)&contact, UUID_SIZE), 0);
|
||||
}
|
||||
|
||||
void test_contacts_db__get_serialized_contact(void) {
|
||||
uint8_t contact[sizeof(s_contact_1)];
|
||||
memcpy(contact, s_contact_1, sizeof(s_contact_1));
|
||||
|
||||
cl_assert_equal_i(contacts_db_insert((uint8_t *)&contact, UUID_SIZE,
|
||||
(uint8_t *)&contact, sizeof(contact)), 0);
|
||||
cl_assert_equal_i(contacts_db_get_len((uint8_t *)&contact, UUID_SIZE), sizeof(contact));
|
||||
|
||||
SerializedContact *serialized_contact;
|
||||
contacts_db_get_serialized_contact((Uuid *)&contact, &serialized_contact);
|
||||
cl_assert_equal_i(serialized_contact->flags, 0);
|
||||
cl_assert_equal_i(serialized_contact->num_attributes, 1);
|
||||
cl_assert_equal_i(serialized_contact->num_addresses, 2);
|
||||
contacts_db_free_serialized_contact(serialized_contact);
|
||||
}
|
467
tests/fw/services/blob_db/test_health_db.c
Normal file
467
tests/fw/services/blob_db/test_health_db.c
Normal file
|
@ -0,0 +1,467 @@
|
|||
/*
|
||||
* 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 "clar.h"
|
||||
|
||||
#include "services/normal/filesystem/pfs.h"
|
||||
#include "services/normal/blob_db/health_db.h"
|
||||
#include "util/size.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "fake_settings_file.h"
|
||||
|
||||
// Stubs
|
||||
////////////////////////////////////////////////////////////////
|
||||
#include "stubs_app_state.h"
|
||||
#include "stubs_hexdump.h"
|
||||
#include "stubs_logging.h"
|
||||
#include "stubs_mutex.h"
|
||||
#include "stubs_passert.h"
|
||||
#include "stubs_pebble_tasks.h"
|
||||
#include "stubs_pbl_malloc.h"
|
||||
#include "stubs_prompt.h"
|
||||
#include "stubs_worker_state.h"
|
||||
|
||||
status_t pfs_remove(const char *name) {
|
||||
fake_settings_file_reset();
|
||||
return S_SUCCESS;
|
||||
}
|
||||
|
||||
status_t blob_db_insert(BlobDBId db_id,
|
||||
const uint8_t *key, int key_len, const uint8_t *val, int val_len) {
|
||||
return settings_file_set(NULL, key, key_len, val, val_len);
|
||||
}
|
||||
|
||||
RtcTicks rtc_get_ticks(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Fakes
|
||||
////////////////////////////////////////////////////////////////
|
||||
static const time_t NOW = 1471269600; // Mon, 15 Aug 2016 14:00:00 GMT
|
||||
time_t rtc_get_time(void) {
|
||||
return NOW;
|
||||
}
|
||||
|
||||
bool activity_get_metric(ActivityMetric metric, uint32_t history_len, int32_t *history) {
|
||||
*history = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int s_metric_updated_count = 0;
|
||||
void activity_metrics_prv_set_metric(ActivityMetric metric, DayInWeek day, int32_t value) {
|
||||
printf("s_metric_updated_count: %d\n", s_metric_updated_count);
|
||||
s_metric_updated_count++;
|
||||
}
|
||||
|
||||
// Setup
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void test_health_db__initialize(void) {
|
||||
fake_settings_file_reset();
|
||||
health_db_init();
|
||||
s_metric_updated_count = 0;
|
||||
}
|
||||
|
||||
|
||||
void test_health_db__cleanup(void) {
|
||||
}
|
||||
|
||||
// Dummy Data
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NUM_CURRENT_MOVEMENT_METRICS 5
|
||||
#define NUM_CURRENT_SLEEP_METRICS 4
|
||||
#define NUM_CURRENT_HR_ZONE_METRICS 3
|
||||
|
||||
typedef enum MovementDataFields {
|
||||
MD_Version,
|
||||
MD_Timestamp,
|
||||
MD_Steps,
|
||||
MD_ActiveKCalories,
|
||||
MD_RestingKCalories,
|
||||
MD_Distance,
|
||||
MD_ActiveTime
|
||||
} MovementDataFields;
|
||||
|
||||
static uint32_t s_movement_data[] = {
|
||||
1, // Version
|
||||
NOW, // Timestamp
|
||||
1234, // Steps
|
||||
1111, // Active K Calories
|
||||
2222, // Resting K Calories
|
||||
3333, // Distance
|
||||
4444, // Active Time
|
||||
};
|
||||
|
||||
static uint32_t s_old_movement_data[] = {
|
||||
1, // Version
|
||||
NOW - (7 * SECONDS_PER_DAY),
|
||||
1234, // Steps
|
||||
1111, // Active K Calories
|
||||
2222, // Resting K Calories
|
||||
3333, // Distance
|
||||
4444, // Active Time
|
||||
};
|
||||
|
||||
static uint32_t s_future_movement_data[] = {
|
||||
1, // Version
|
||||
NOW + SECONDS_PER_DAY,
|
||||
1234, // Steps
|
||||
1111, // Active K Calories
|
||||
2222, // Resting K Calories
|
||||
3333, // Distance
|
||||
4444, // Active Time
|
||||
};
|
||||
|
||||
typedef enum SleepDataFields {
|
||||
SD_Version,
|
||||
SD_Timestamp,
|
||||
SD_SleepDuration,
|
||||
SD_DeepSleepDuration,
|
||||
SD_FallAsleepTime,
|
||||
SD_WakeupTime,
|
||||
SD_TypicalSleepDuration,
|
||||
SD_TypicalDeepSleepDuration,
|
||||
SD_TypicalFallAsleepTime,
|
||||
SD_TypicalWakeupTime,
|
||||
} SleepDataFields;
|
||||
|
||||
static uint32_t s_sleep_data[] = {
|
||||
1, // Version
|
||||
NOW, // Timestamp
|
||||
1234, // Sleep Duration
|
||||
1111, // Deep Sleep Duration
|
||||
2222, // Fall Asleep Time
|
||||
3333, // Wakeup Time
|
||||
4444, // Active Time
|
||||
|
||||
5555, // Typical sleep duration
|
||||
6666, // Typical deep sleep duration
|
||||
7777, // Typical fall asleep time
|
||||
8888, // Typical wakeup time
|
||||
};
|
||||
|
||||
static uint32_t s_old_sleep_data[] = {
|
||||
1, // Version
|
||||
NOW - (7 * SECONDS_PER_DAY),
|
||||
1234, // Sleep Duration
|
||||
1111, // Deep Sleep Duration
|
||||
2222, // Fall Asleep Time
|
||||
3333, // Wakeup Time
|
||||
4444, // Active Time
|
||||
|
||||
5555, // Typical sleep duration
|
||||
6666, // Typical deep sleep duration
|
||||
7777, // Typical fall asleep time
|
||||
8888, // Typical wakeup time
|
||||
};
|
||||
|
||||
static uint32_t s_invalid_sleep_data[] = {
|
||||
5, // Version
|
||||
NOW, // Timestamp
|
||||
1234, // Sleep Duration
|
||||
1111, // Deep Sleep Duration
|
||||
2222, // Fall Asleep Time
|
||||
3333, // Wakeup Time
|
||||
4444, // Active Time
|
||||
|
||||
5555, // Typical sleep duration
|
||||
6666, // Typical deep sleep duration
|
||||
7777, // Typical fall asleep time
|
||||
8888, // Typical wakeup time
|
||||
};
|
||||
|
||||
static uint32_t s_hr_zone_data[] = {
|
||||
1, // Version
|
||||
NOW, // Timestamp
|
||||
3, // Number of zones
|
||||
60, // Minutes in zone 1
|
||||
30, // Minutes in zone 2
|
||||
15, // Minutes in zone 3
|
||||
};
|
||||
|
||||
// Tests
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void test_health_db__blob_db_api(void) {
|
||||
const char *key = "monday_sleepData";
|
||||
|
||||
// insert one
|
||||
cl_assert_equal_i(health_db_insert((uint8_t *)key, strlen(key),
|
||||
(uint8_t *)s_sleep_data, sizeof(s_sleep_data)),
|
||||
S_SUCCESS);
|
||||
|
||||
// check
|
||||
int32_t val_out;
|
||||
cl_assert(health_db_get_typical_value(ActivityMetricSleepTotalSeconds, Monday, &val_out));
|
||||
cl_assert_equal_i(val_out, s_sleep_data[SD_TypicalSleepDuration]);
|
||||
|
||||
// delete
|
||||
cl_assert_equal_i(health_db_delete((uint8_t *)key, strlen(key)),
|
||||
S_SUCCESS);
|
||||
|
||||
// check
|
||||
cl_assert(!health_db_get_typical_value(ActivityMetricSleepTotalSeconds, Monday, &val_out));
|
||||
|
||||
// insert again
|
||||
cl_assert_equal_i(health_db_insert((uint8_t *)key, strlen(key),
|
||||
(uint8_t *)s_sleep_data, sizeof(s_sleep_data)),
|
||||
S_SUCCESS);
|
||||
|
||||
// check
|
||||
cl_assert(health_db_get_typical_value(ActivityMetricSleepTotalSeconds, Monday, &val_out));
|
||||
cl_assert_equal_i(val_out, s_sleep_data[SD_TypicalSleepDuration]);
|
||||
|
||||
// flush
|
||||
cl_assert_equal_i(health_db_flush(), S_SUCCESS);
|
||||
|
||||
// check
|
||||
cl_assert(!health_db_get_typical_value(ActivityMetricSleepTotalSeconds, Monday, &val_out));
|
||||
|
||||
// insert something with an older version (this will succeed)
|
||||
cl_assert_equal_i(health_db_insert((uint8_t *)key, strlen(key),
|
||||
(uint8_t *)s_invalid_sleep_data, sizeof(s_sleep_data)),
|
||||
S_SUCCESS);
|
||||
// check
|
||||
cl_assert(!health_db_get_typical_value(ActivityMetricSleepTotalSeconds, Monday, &val_out));
|
||||
}
|
||||
|
||||
void test_health_db__movement_data(void) {
|
||||
const char *key = "monday_movementData";
|
||||
cl_assert_equal_i(health_db_insert((uint8_t *)key, strlen(key),
|
||||
(uint8_t *)s_movement_data, sizeof(s_movement_data)),
|
||||
S_SUCCESS);
|
||||
|
||||
cl_assert_equal_i(s_metric_updated_count, NUM_CURRENT_MOVEMENT_METRICS);
|
||||
|
||||
// check typicals (not stored)
|
||||
int32_t val_out;
|
||||
|
||||
cl_assert(!health_db_get_typical_value(ActivityMetricStepCount, Monday, &val_out));
|
||||
|
||||
cl_assert(!health_db_get_typical_value(ActivityMetricActiveSeconds, Monday, &val_out));
|
||||
|
||||
cl_assert(!health_db_get_typical_value(ActivityMetricRestingKCalories, Monday, &val_out));
|
||||
|
||||
cl_assert(!health_db_get_typical_value(ActivityMetricActiveKCalories, Monday, &val_out));
|
||||
|
||||
cl_assert(!health_db_get_typical_value(ActivityMetricDistanceMeters, Monday, &val_out));
|
||||
}
|
||||
|
||||
void test_health_db__sleep_data(void) {
|
||||
const char *key = "monday_sleepData";
|
||||
cl_assert_equal_i(health_db_insert((uint8_t *)key, strlen(key),
|
||||
(uint8_t *)s_sleep_data, sizeof(s_sleep_data)),
|
||||
S_SUCCESS);
|
||||
|
||||
cl_assert_equal_i(s_metric_updated_count, NUM_CURRENT_SLEEP_METRICS);
|
||||
|
||||
// check typicals
|
||||
int32_t val_out;
|
||||
|
||||
cl_assert(health_db_get_typical_value(ActivityMetricSleepTotalSeconds, Monday, &val_out));
|
||||
cl_assert_equal_i(val_out, s_sleep_data[SD_TypicalSleepDuration]);
|
||||
|
||||
cl_assert(health_db_get_typical_value(ActivityMetricSleepRestfulSeconds, Monday, &val_out));
|
||||
cl_assert_equal_i(val_out, s_sleep_data[SD_TypicalDeepSleepDuration]);
|
||||
|
||||
cl_assert(health_db_get_typical_value(ActivityMetricSleepEnterAtSeconds, Monday, &val_out));
|
||||
cl_assert_equal_i(val_out, s_sleep_data[SD_TypicalFallAsleepTime]);
|
||||
|
||||
cl_assert(health_db_get_typical_value(ActivityMetricSleepExitAtSeconds, Monday, &val_out));
|
||||
cl_assert_equal_i(val_out, s_sleep_data[SD_TypicalWakeupTime]);
|
||||
}
|
||||
|
||||
void test_health_db__hr_zone_data(void) {
|
||||
const char *key = "monday_heartRateZoneData";
|
||||
cl_assert_equal_i(health_db_insert((uint8_t *)key, strlen(key),
|
||||
(uint8_t *)s_hr_zone_data, sizeof(s_hr_zone_data)),
|
||||
S_SUCCESS);
|
||||
|
||||
cl_assert_equal_i(s_metric_updated_count, NUM_CURRENT_HR_ZONE_METRICS);
|
||||
|
||||
// check typicals (not stored)
|
||||
int32_t val_out;
|
||||
|
||||
cl_assert(!health_db_get_typical_value(ActivityMetricHeartRateZone1Minutes, Monday, &val_out));
|
||||
cl_assert(!health_db_get_typical_value(ActivityMetricHeartRateZone2Minutes, Monday, &val_out));
|
||||
cl_assert(!health_db_get_typical_value(ActivityMetricHeartRateZone3Minutes, Monday, &val_out));
|
||||
}
|
||||
|
||||
void test_health_db__step_averages(void) {
|
||||
const struct {
|
||||
const char *key;
|
||||
const char *val;
|
||||
} entries[] = {
|
||||
{
|
||||
.key = "sunday_steps",
|
||||
.val = "l4tHpFsFGE6UINneFPMnf2lgINlYuXlDS6xh6vizK9jbDen5mHQgWF6E8jOzBVnEdV0j2DNOzONfJbsWoSWH0QoQpPmm1NSW" \
|
||||
"l4tHpFsFGE6UINneFPMnf2lgINlYuXlDS6xh6vizK9jbDen5mHQgWF6E8jOzBVnEdV0j2DNOzONfJbsWoSWH0QoQpPmm1NSW",
|
||||
}, {
|
||||
.key = "monday_steps",
|
||||
.val = "Rhgc3Q7ajjydH8CA9qxVJH0FpVDjdGwwoKCLE2F55x62EZZ6MCIjUMynVq13U8vOHhaWoygDf0zwOIdAEUOrZRwvJmYVzW7J" \
|
||||
"Rhgc3Q7ajjydH8CA9qxVJH0FpVDjdGwwoKCLE2F55x62EZZ6MCIjUMynVq13U8vOHhaWoygDf0zwOIdAEUOrZRwvJmYVzW7J",
|
||||
}, {
|
||||
.key = "tuesday_steps",
|
||||
.val = "V6PrBVc4suqCYjLceUl6a1UXYO8qwL5w3WZY00KeGoHAcuST7OxGnMBVCEskty0q4OIdTeyyZOljrGif09kZOFldu3BjJqJO" \
|
||||
"V6PrBVc4suqCYjLceUl6a1UXYO8qwL5w3WZY00KeGoHAcuST7OxGnMBVCEskty0q4OIdTeyyZOljrGif09kZOFldu3BjJqJO",
|
||||
}, {
|
||||
.key = "wednesday_steps",
|
||||
.val = "wufD6hzhFUrkZkLObfn2dFKUDs0kNNWp6CFiS2XBS3spSFDQUnFLuxWPEq7Dql2HjdkVobMcOA8DiOcanhZvziN6hbteMbg8" \
|
||||
"wufD6hzhFUrkZkLObfn2dFKUDs0kNNWp6CFiS2XBS3spSFDQUnFLuxWPEq7Dql2HjdkVobMcOA8DiOcanhZvziN6hbteMbg8",
|
||||
}, {
|
||||
.key = "thursday_steps",
|
||||
.val = "FXKAfWwOueL4jLJfZRxzINDITxaThvFIpOrzYfgPVmqbbYoCZKkKkbgyvP1UaCEstr9WjptLszgMocgGSEsqmoipqqWdk7dq" \
|
||||
"FXKAfWwOueL4jLJfZRxzINDITxaThvFIpOrzYfgPVmqbbYoCZKkKkbgyvP1UaCEstr9WjptLszgMocgGSEsqmoipqqWdk7dq",
|
||||
}, {
|
||||
.key = "friday_steps",
|
||||
.val = "uxFhoWTzJxDOmyBX2g3n7wdoPKxeleBR7iwKGn7utn8qTEj0tB7aw65EEFZ5QldgAkg6lctSmamf2p95l2CpHXNgVL22hQFx" \
|
||||
"uxFhoWTzJxDOmyBX2g3n7wdoPKxeleBR7iwKGn7utn8qTEj0tB7aw65EEFZ5QldgAkg6lctSmamf2p95l2CpHXNgVL22hQFx",
|
||||
}, {
|
||||
.key = "saturday_steps",
|
||||
.val = "SSxw7WtwGnhobAOXwqbvGDDwElpRG6cll8CwM9Wysh01Mj0aFWxEVN0z5w7yQHt8bwiWVabrMeUUAek2J5zCoXiGIkav4cW8" \
|
||||
"SSxw7WtwGnhobAOXwqbvGDDwElpRG6cll8CwM9Wysh01Mj0aFWxEVN0z5w7yQHt8bwiWVabrMeUUAek2J5zCoXiGIkav4cW8",
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
for (int i = 0; i < ARRAY_LENGTH(entries); ++i) {
|
||||
cl_assert_equal_i(health_db_insert((uint8_t *)entries[i].key,
|
||||
strlen(entries[i].key),
|
||||
(uint8_t *)entries[i].val,
|
||||
strlen(entries[i].val)),
|
||||
S_SUCCESS);
|
||||
|
||||
ActivityMetricAverages averages;
|
||||
health_db_get_typical_step_averages(i, &averages);
|
||||
|
||||
int idx = i * 10;
|
||||
uint16_t val_expected = ((uint16_t *)entries[i].val)[idx];
|
||||
cl_assert_equal_i(averages.average[idx], val_expected);
|
||||
}
|
||||
}
|
||||
|
||||
void test_health_db__monthly_averages(void) {
|
||||
int32_t val_out;
|
||||
|
||||
const char *average_step_key = "average_dailySteps";
|
||||
int32_t average_steps_val = 123456;
|
||||
cl_assert_equal_i(health_db_insert((uint8_t *)average_step_key, strlen(average_step_key),
|
||||
(uint8_t *)&average_steps_val, sizeof(average_steps_val)),
|
||||
S_SUCCESS);
|
||||
|
||||
cl_assert(health_db_get_monthly_average_value(ActivityMetricStepCount, &val_out));
|
||||
cl_assert_equal_i(val_out, average_steps_val);
|
||||
|
||||
const char *average_sleep_key = "average_sleepDuration";
|
||||
int32_t average_sleep_val = 654321;
|
||||
cl_assert_equal_i(health_db_insert((uint8_t *)average_sleep_key, strlen(average_sleep_key),
|
||||
(uint8_t *)&average_sleep_val, sizeof(average_sleep_val)),
|
||||
S_SUCCESS);
|
||||
|
||||
cl_assert(health_db_get_monthly_average_value(ActivityMetricSleepTotalSeconds, &val_out));
|
||||
cl_assert_equal_i(val_out, average_sleep_val);
|
||||
}
|
||||
|
||||
void test_health_db__notify_listeners(void) {
|
||||
char *key;
|
||||
|
||||
s_metric_updated_count = 0;
|
||||
key = "tuesday_sleepData";
|
||||
cl_assert_equal_i(health_db_insert((uint8_t *)key, strlen(key),
|
||||
(uint8_t *)s_sleep_data, sizeof(s_sleep_data)),
|
||||
S_SUCCESS);
|
||||
cl_assert_equal_i(s_metric_updated_count, NUM_CURRENT_SLEEP_METRICS);
|
||||
|
||||
s_metric_updated_count = 0;
|
||||
key = "wednesday_movementData";
|
||||
cl_assert_equal_i(health_db_insert((uint8_t *)key, strlen(key),
|
||||
(uint8_t *)s_movement_data, sizeof(s_movement_data)),
|
||||
S_SUCCESS);
|
||||
cl_assert_equal_i(s_metric_updated_count, NUM_CURRENT_MOVEMENT_METRICS);
|
||||
|
||||
s_metric_updated_count = 0;
|
||||
key = "thursday_sleepData";
|
||||
cl_assert_equal_i(health_db_insert((uint8_t *)key, strlen(key),
|
||||
(uint8_t *)s_sleep_data, sizeof(s_sleep_data)),
|
||||
S_SUCCESS);
|
||||
cl_assert_equal_i(s_metric_updated_count, NUM_CURRENT_SLEEP_METRICS);
|
||||
|
||||
s_metric_updated_count = 0;
|
||||
key = "friday_movementData";
|
||||
cl_assert_equal_i(health_db_insert((uint8_t *)key, strlen(key),
|
||||
(uint8_t *)s_movement_data, sizeof(s_movement_data)),
|
||||
S_SUCCESS);
|
||||
cl_assert_equal_i(s_metric_updated_count, NUM_CURRENT_MOVEMENT_METRICS);
|
||||
|
||||
s_metric_updated_count = 0;
|
||||
key = "saturday_sleepData";
|
||||
cl_assert_equal_i(health_db_insert((uint8_t *)key, strlen(key),
|
||||
(uint8_t *)s_sleep_data, sizeof(s_sleep_data)),
|
||||
S_SUCCESS);
|
||||
cl_assert_equal_i(s_metric_updated_count, NUM_CURRENT_SLEEP_METRICS);
|
||||
|
||||
s_metric_updated_count = 0;
|
||||
key = "sunday_movementData";
|
||||
cl_assert_equal_i(health_db_insert((uint8_t *)key, strlen(key),
|
||||
(uint8_t *)s_movement_data, sizeof(s_movement_data)),
|
||||
S_SUCCESS);
|
||||
cl_assert_equal_i(s_metric_updated_count, NUM_CURRENT_MOVEMENT_METRICS);
|
||||
|
||||
|
||||
s_metric_updated_count = 0;
|
||||
key = "monday_movementData";
|
||||
cl_assert_equal_i(health_db_insert((uint8_t *)key, strlen(key),
|
||||
(uint8_t *)s_movement_data, sizeof(s_movement_data)),
|
||||
S_SUCCESS);
|
||||
cl_assert_equal_i(s_metric_updated_count, NUM_CURRENT_MOVEMENT_METRICS);
|
||||
|
||||
s_metric_updated_count = 0;
|
||||
key = "monday_sleepData";
|
||||
cl_assert_equal_i(health_db_insert((uint8_t *)key, strlen(key),
|
||||
(uint8_t *)s_sleep_data, sizeof(s_sleep_data)),
|
||||
S_SUCCESS);
|
||||
cl_assert_equal_i(s_metric_updated_count, NUM_CURRENT_SLEEP_METRICS);
|
||||
|
||||
|
||||
// Test inserting something which is more than a week old.
|
||||
// We shouldn't update our internal storage
|
||||
s_metric_updated_count = 0;
|
||||
key = "monday_movementData";
|
||||
cl_assert_equal_i(health_db_insert((uint8_t *)key, strlen(key),
|
||||
(uint8_t *)s_old_movement_data, sizeof(s_old_movement_data)),
|
||||
S_SUCCESS);
|
||||
cl_assert_equal_i(s_metric_updated_count, 0);
|
||||
|
||||
s_metric_updated_count = 0;
|
||||
key = "monday_sleepData";
|
||||
cl_assert_equal_i(health_db_insert((uint8_t *)key, strlen(key),
|
||||
(uint8_t *)s_old_sleep_data, sizeof(s_old_sleep_data)),
|
||||
S_SUCCESS);
|
||||
cl_assert_equal_i(s_metric_updated_count, 0);
|
||||
|
||||
// Insert something which has a future timestamp
|
||||
s_metric_updated_count = 0;
|
||||
key = "monday_movementData";
|
||||
cl_assert_equal_i(health_db_insert((uint8_t *)key, strlen(key),
|
||||
(uint8_t *)s_future_movement_data, sizeof(s_movement_data)),
|
||||
S_SUCCESS);
|
||||
cl_assert_equal_i(s_metric_updated_count, 0);
|
||||
|
||||
}
|
240
tests/fw/services/blob_db/test_ios_notif_pref_db.c
Normal file
240
tests/fw/services/blob_db/test_ios_notif_pref_db.c
Normal file
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
* 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 "clar.h"
|
||||
|
||||
#include "services/normal/blob_db/ios_notif_pref_db.h"
|
||||
#include "util/size.h"
|
||||
|
||||
// Fixture
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// Fakes
|
||||
////////////////////////////////////////////////////////////////
|
||||
#include "fake_system_task.h"
|
||||
#include "fake_settings_file.h"
|
||||
|
||||
// Stubs
|
||||
////////////////////////////////////////////////////////////////
|
||||
#include "stubs_analytics.h"
|
||||
#include "stubs_layout_layer.h"
|
||||
#include "stubs_logging.h"
|
||||
#include "stubs_mutex.h"
|
||||
#include "stubs_passert.h"
|
||||
#include "stubs_pbl_malloc.h"
|
||||
#include "stubs_rand_ptr.h"
|
||||
#include "stubs_pfs.h"
|
||||
#include "stubs_blob_db_sync.h"
|
||||
#include "stubs_prompt.h"
|
||||
|
||||
extern const char *iOS_NOTIF_PREF_DB_FILE_NAME;
|
||||
extern const int iOS_NOTIF_PREF_MAX_SIZE;
|
||||
|
||||
//! Data from iOS notif pref INSERT
|
||||
//! 00 00 00 00 00 01 02 0d 03 01 05 00 52 65 70 6c ........ ....Repl
|
||||
//! 79 08 71 00 4f 6b 00 59 65 73 00 4e 6f 00 43 61 y.q.Ok.Y es.No.Ca
|
||||
//! 6c 6c 20 6d 65 00 43 61 6c 6c 20 79 6f 75 20 6c ll me.Ca ll you l
|
||||
//! 61 74 65 72 00 54 68 61 6e 6b 20 79 6f 75 00 53 ater.Tha nk you.S
|
||||
//! 65 65 20 79 6f 75 20 73 6f 6f 6e 00 52 75 6e 6e ee you s oon.Runn
|
||||
//! 69 6e 67 20 6c 61 74 65 00 4f 6e 20 6d 79 20 77 ing late .On my w
|
||||
//! 61 79 00 42 75 73 79 20 72 69 67 68 74 20 6e 6f ay.Busy right no
|
||||
//! 77 20 2d 20 67 69 76 65 20 6d 65 20 61 20 73 65 w - give me a se
|
||||
//! 63 6f 6e 64 3f 21 01 00 00 cond?!.. .
|
||||
|
||||
static const uint8_t s_ios_pref_db_insert_dict[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x0d, 0x03, 0x01, 0x05, 0x00, 0x52, 0x65, 0x70, 0x6c,
|
||||
0x79, 0x08, 0x71, 0x00, 0x4f, 0x6b, 0x00, 0x59, 0x65, 0x73, 0x00, 0x4e, 0x6f, 0x00, 0x43, 0x61,
|
||||
0x6c, 0x6c, 0x20, 0x6d, 0x65, 0x00, 0x43, 0x61, 0x6c, 0x6c, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6c,
|
||||
0x61, 0x74, 0x65, 0x72, 0x00, 0x54, 0x68, 0x61, 0x6e, 0x6b, 0x20, 0x79, 0x6f, 0x75, 0x00, 0x53,
|
||||
0x65, 0x65, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x73, 0x6f, 0x6f, 0x6e, 0x00, 0x52, 0x75, 0x6e, 0x6e,
|
||||
0x69, 0x6e, 0x67, 0x20, 0x6c, 0x61, 0x74, 0x65, 0x00, 0x4f, 0x6e, 0x20, 0x6d, 0x79, 0x20, 0x77,
|
||||
0x61, 0x79, 0x00, 0x42, 0x75, 0x73, 0x79, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x6e, 0x6f,
|
||||
0x77, 0x20, 0x2d, 0x20, 0x67, 0x69, 0x76, 0x65, 0x20, 0x6d, 0x65, 0x20, 0x61, 0x20, 0x73, 0x65,
|
||||
0x63, 0x6f, 0x6e, 0x64, 0x3f, 0x21, 0x01, 0x00, 0x00
|
||||
};
|
||||
|
||||
const uint8_t key[] = { 0x01, 0x02, 0x03 };
|
||||
|
||||
void test_ios_notif_pref_db__initialize(void) {
|
||||
}
|
||||
|
||||
void test_ios_notif_pref_db__cleanup(void) {
|
||||
fake_settings_file_reset();
|
||||
}
|
||||
|
||||
void test_ios_notif_pref_db__insert_inverts_flags(void) {
|
||||
// Make a local copy of dict since ios_notif_pref_db_insert() modifies val
|
||||
uint8_t val[sizeof(s_ios_pref_db_insert_dict)];
|
||||
memcpy(val, s_ios_pref_db_insert_dict, sizeof(s_ios_pref_db_insert_dict));
|
||||
|
||||
ios_notif_pref_db_insert(key, sizeof(key), val, sizeof(val));
|
||||
|
||||
SettingsFile file;
|
||||
settings_file_open(&file, iOS_NOTIF_PREF_DB_FILE_NAME, iOS_NOTIF_PREF_MAX_SIZE);
|
||||
|
||||
const unsigned prefs_len = settings_file_get_len(&file, key, sizeof(key));
|
||||
void *prefs_out = kernel_zalloc(prefs_len);
|
||||
settings_file_get(&file, key, sizeof(key), prefs_out, prefs_len);
|
||||
settings_file_close(&file);
|
||||
|
||||
uint32_t flags = *((uint32_t *) prefs_out);
|
||||
cl_assert_equal_i(flags, ~0);
|
||||
|
||||
kernel_free(prefs_out);
|
||||
}
|
||||
|
||||
void test_ios_notif_pref_db__read_flags(void) {
|
||||
// Make a local copy of dict since ios_notif_pref_db_insert() modifies val
|
||||
uint8_t val[sizeof(s_ios_pref_db_insert_dict)];
|
||||
memcpy(val, s_ios_pref_db_insert_dict, sizeof(s_ios_pref_db_insert_dict));
|
||||
|
||||
ios_notif_pref_db_insert(key, sizeof(key), val, sizeof(val));
|
||||
|
||||
uint32_t flags = ios_notif_pref_db_get_flags(key, sizeof(key));
|
||||
cl_assert_equal_i(flags, 0);
|
||||
}
|
||||
|
||||
void test_ios_notif_pref_db__store_prefs(void) {
|
||||
// Create an attribute list and action group
|
||||
AttributeList attr_list;
|
||||
attribute_list_init_list(0, &attr_list);
|
||||
attribute_list_add_cstring(&attr_list, AttributeIdShortTitle, "Title");
|
||||
attribute_list_add_uint8(&attr_list, AttributeIdMuteDayOfWeek, 0x1F);
|
||||
attribute_list_add_cstring(&attr_list, AttributeIdAppName, "GMail");
|
||||
TimelineItemActionGroup action_group = {
|
||||
.num_actions = 0,
|
||||
};
|
||||
|
||||
// Store them in the DB
|
||||
char *key = "key1";
|
||||
int key_len = strlen(key);
|
||||
ios_notif_pref_db_store_prefs((uint8_t *)key, key_len, &attr_list, &action_group);
|
||||
|
||||
// Make sure we can get the data back
|
||||
iOSNotifPrefs *notif_prefs = ios_notif_pref_db_get_prefs((uint8_t *)key, key_len);
|
||||
cl_assert(notif_prefs);
|
||||
Attribute *title = attribute_find(¬if_prefs->attr_list, AttributeIdShortTitle);
|
||||
cl_assert(title);
|
||||
cl_assert_equal_s(title->cstring, "Title");
|
||||
Attribute *mute = attribute_find(¬if_prefs->attr_list, AttributeIdMuteDayOfWeek);
|
||||
cl_assert(mute);
|
||||
cl_assert_equal_i(mute->uint8, 0x1F);
|
||||
Attribute *name = attribute_find(¬if_prefs->attr_list, AttributeIdAppName);
|
||||
cl_assert(name);
|
||||
cl_assert_equal_s(name->cstring, "GMail");
|
||||
|
||||
|
||||
// Update the current entry with a new attribute
|
||||
attribute_list_add_uint32(&attr_list, AttributeIdLastUpdated, 123456);
|
||||
ios_notif_pref_db_store_prefs((uint8_t *)key, key_len, &attr_list, &action_group);
|
||||
|
||||
// Make sure we can get all the data back
|
||||
notif_prefs = ios_notif_pref_db_get_prefs((uint8_t *)key, key_len);
|
||||
cl_assert(notif_prefs);
|
||||
title = attribute_find(¬if_prefs->attr_list, AttributeIdShortTitle);
|
||||
cl_assert(title);
|
||||
cl_assert_equal_s(title->cstring, "Title");
|
||||
mute = attribute_find(¬if_prefs->attr_list, AttributeIdMuteDayOfWeek);
|
||||
cl_assert(mute);
|
||||
cl_assert_equal_i(mute->uint8, 0x1F);
|
||||
name = attribute_find(¬if_prefs->attr_list, AttributeIdAppName);
|
||||
cl_assert(name);
|
||||
cl_assert_equal_s(name->cstring, "GMail");
|
||||
Attribute *updated = attribute_find(¬if_prefs->attr_list, AttributeIdLastUpdated);
|
||||
cl_assert(updated);
|
||||
cl_assert_equal_i(updated->uint32, 123456);
|
||||
|
||||
attribute_list_destroy_list(&attr_list);
|
||||
ios_notif_pref_db_free_prefs(notif_prefs);
|
||||
}
|
||||
|
||||
void test_ios_notif_pref_db__store_empty_prefs(void) {
|
||||
// Store empty prefs
|
||||
char *key = "key1";
|
||||
int key_len = strlen(key);
|
||||
ios_notif_pref_db_store_prefs((uint8_t *)key, key_len, NULL, NULL);
|
||||
|
||||
// Read them back
|
||||
iOSNotifPrefs *notif_prefs = ios_notif_pref_db_get_prefs((uint8_t *)key, key_len);
|
||||
cl_assert(notif_prefs);
|
||||
cl_assert_equal_i(notif_prefs->attr_list.num_attributes, 0);
|
||||
cl_assert_equal_i(notif_prefs->action_group.num_actions, 0);
|
||||
|
||||
ios_notif_pref_db_free_prefs(notif_prefs);
|
||||
}
|
||||
|
||||
void test_ios_notif_pref_db__is_dirty_insert_from_phone(void) {
|
||||
char *keys[] = { "key1", "key2", "key3", "key4", "key5" };
|
||||
int key_len = strlen(keys[0]);
|
||||
char *values[] = { "val1", "val2", "val3", "val4", "val5" };
|
||||
int value_len = strlen(values[0]);
|
||||
|
||||
// Insert a bunch of known apps "from the phone"
|
||||
// They should NOT be dirty (the phone is the source of truth)
|
||||
for (int i = 0; i < ARRAY_LENGTH(keys); ++i) {
|
||||
ios_notif_pref_db_insert((uint8_t *)keys[i], key_len, (uint8_t *)values[i], value_len);
|
||||
}
|
||||
|
||||
bool is_dirty = true;
|
||||
cl_assert_equal_i(ios_notif_pref_db_is_dirty(&is_dirty), S_SUCCESS);
|
||||
cl_assert(!is_dirty);
|
||||
|
||||
BlobDBDirtyItem *dirty_list = ios_notif_pref_db_get_dirty_list();
|
||||
cl_assert(!dirty_list);
|
||||
}
|
||||
|
||||
void test_ios_notif_pref_db__is_dirty_insert_locally(void) {
|
||||
char *keys[] = { "key1", "key2", "key3", "key4", "key5" };
|
||||
int key_len = strlen(keys[0]);
|
||||
|
||||
// Insert a bunch of known apps "from the watch"
|
||||
// These should be dirty (the phone is the source of truth)
|
||||
for (int i = 0; i < ARRAY_LENGTH(keys); ++i) {
|
||||
ios_notif_pref_db_store_prefs((uint8_t *)keys[i], key_len, NULL, NULL);
|
||||
}
|
||||
|
||||
bool is_dirty = false;
|
||||
cl_assert_equal_i(ios_notif_pref_db_is_dirty(&is_dirty), S_SUCCESS);
|
||||
cl_assert(is_dirty);
|
||||
|
||||
BlobDBDirtyItem *dirty_list = ios_notif_pref_db_get_dirty_list();
|
||||
cl_assert(dirty_list);
|
||||
cl_assert(list_count((ListNode *)dirty_list) == ARRAY_LENGTH(keys));
|
||||
|
||||
// Mark some items as synced
|
||||
ios_notif_pref_db_mark_synced((uint8_t *)keys[0], key_len);
|
||||
ios_notif_pref_db_mark_synced((uint8_t *)keys[1], key_len);
|
||||
ios_notif_pref_db_mark_synced((uint8_t *)keys[2], key_len);
|
||||
|
||||
// We should now only have 2 dirty items
|
||||
cl_assert_equal_i(ios_notif_pref_db_is_dirty(&is_dirty), S_SUCCESS);
|
||||
cl_assert(is_dirty);
|
||||
|
||||
dirty_list = ios_notif_pref_db_get_dirty_list();
|
||||
cl_assert(dirty_list);
|
||||
cl_assert_equal_i(list_count((ListNode *)dirty_list), 2);
|
||||
|
||||
// Mark the final 2 items as synced
|
||||
ios_notif_pref_db_mark_synced((uint8_t *)keys[3], key_len);
|
||||
ios_notif_pref_db_mark_synced((uint8_t *)keys[4], key_len);
|
||||
|
||||
// And nothing should be dirty
|
||||
cl_assert_equal_i(ios_notif_pref_db_is_dirty(&is_dirty), S_SUCCESS);
|
||||
cl_assert(!is_dirty);
|
||||
|
||||
dirty_list = ios_notif_pref_db_get_dirty_list();
|
||||
cl_assert(!dirty_list);
|
||||
}
|
123
tests/fw/services/blob_db/test_notif_db.c
Normal file
123
tests/fw/services/blob_db/test_notif_db.c
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* 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 "clar.h"
|
||||
|
||||
#include "util/uuid.h"
|
||||
#include "services/normal/filesystem/pfs.h"
|
||||
#include "services/normal/blob_db/notif_db.h"
|
||||
#include "services/normal/notifications/notification_storage.h"
|
||||
|
||||
// Fixture
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// Fakes
|
||||
////////////////////////////////////////////////////////////////
|
||||
#include "fake_spi_flash.h"
|
||||
#include "fake_system_task.h"
|
||||
#include "fake_kernel_services_notifications.h"
|
||||
|
||||
// Stubs
|
||||
////////////////////////////////////////////////////////////////
|
||||
#include "stubs_analytics.h"
|
||||
#include "stubs_hexdump.h"
|
||||
#include "stubs_layout_layer.h"
|
||||
#include "stubs_logging.h"
|
||||
#include "stubs_mutex.h"
|
||||
#include "stubs_passert.h"
|
||||
#include "stubs_pbl_malloc.h"
|
||||
#include "stubs_prompt.h"
|
||||
#include "stubs_rand_ptr.h"
|
||||
#include "stubs_sleep.h"
|
||||
#include "stubs_task_watchdog.h"
|
||||
|
||||
void test_notif_db__initialize(void) {
|
||||
fake_spi_flash_init(0, 0x1000000);
|
||||
pfs_init(false);
|
||||
notification_storage_reset();
|
||||
}
|
||||
|
||||
void test_notif_db__cleanup(void) {
|
||||
}
|
||||
|
||||
void test_notif_db__get_length(void) {
|
||||
SerializedTimelineItemHeader hdr = {
|
||||
.common = {
|
||||
.ancs_uid = 1,
|
||||
.layout = 0,
|
||||
.flags = 0,
|
||||
.timestamp = 0,
|
||||
},
|
||||
};
|
||||
uuid_generate(&hdr.common.id);
|
||||
cl_assert_equal_i(notif_db_insert((uint8_t *)&hdr, UUID_SIZE, (uint8_t *)&hdr, sizeof(hdr)), 0);
|
||||
cl_assert_equal_i(notif_db_get_len((uint8_t *)&hdr, UUID_SIZE), sizeof(hdr));
|
||||
}
|
||||
|
||||
void test_notif_db__insert_remove(void) {
|
||||
SerializedTimelineItemHeader hdr = {
|
||||
.common = {
|
||||
.ancs_uid = 1,
|
||||
.layout = 0,
|
||||
.flags = 0,
|
||||
.timestamp = 0,
|
||||
},
|
||||
};
|
||||
uuid_generate(&hdr.common.id);
|
||||
cl_assert_equal_i(notif_db_insert((uint8_t *)&hdr, UUID_SIZE, (uint8_t *)&hdr, sizeof(hdr)), 0);
|
||||
cl_assert_equal_i(notif_db_delete((uint8_t *)&hdr, UUID_SIZE), 0);
|
||||
cl_assert_equal_i(notif_db_get_len((uint8_t *)&hdr, UUID_SIZE), 0);
|
||||
}
|
||||
|
||||
void test_notif_db__flush(void) {
|
||||
SerializedTimelineItemHeader hdr1 = {
|
||||
.common = {
|
||||
.ancs_uid = 1,
|
||||
.layout = 0,
|
||||
.flags = 0,
|
||||
.timestamp = 0,
|
||||
},
|
||||
};
|
||||
uuid_generate(&hdr1.common.id);
|
||||
SerializedTimelineItemHeader hdr2 = {
|
||||
.common = {
|
||||
.ancs_uid = 1,
|
||||
.layout = 0,
|
||||
.flags = 0,
|
||||
.timestamp = 0,
|
||||
},
|
||||
};
|
||||
uuid_generate(&hdr2.common.id);
|
||||
SerializedTimelineItemHeader hdr3 = {
|
||||
.common = {
|
||||
.ancs_uid = 1,
|
||||
.layout = 0,
|
||||
.flags = 0,
|
||||
.timestamp = 0,
|
||||
},
|
||||
};
|
||||
uuid_generate(&hdr3.common.id);
|
||||
|
||||
cl_assert_equal_i(notif_db_insert((uint8_t *)&hdr1, UUID_SIZE, (uint8_t *)&hdr1, sizeof(hdr1)), 0);
|
||||
cl_assert_equal_i(notif_db_insert((uint8_t *)&hdr2, UUID_SIZE, (uint8_t *)&hdr2, sizeof(hdr2)), 0);
|
||||
cl_assert_equal_i(notif_db_insert((uint8_t *)&hdr3, UUID_SIZE, (uint8_t *)&hdr3, sizeof(hdr3)), 0);
|
||||
cl_assert_equal_i(notif_db_flush(), 0);
|
||||
fake_system_task_callbacks_invoke_pending();
|
||||
cl_assert_equal_i(notif_db_get_len((uint8_t *)&hdr1, UUID_SIZE), 0);
|
||||
cl_assert_equal_i(notif_db_get_len((uint8_t *)&hdr2, UUID_SIZE), 0);
|
||||
cl_assert_equal_i(notif_db_get_len((uint8_t *)&hdr3, UUID_SIZE), 0);
|
||||
}
|
||||
|
200
tests/fw/services/blob_db/test_pin_db.c
Normal file
200
tests/fw/services/blob_db/test_pin_db.c
Normal file
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
* 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 "clar.h"
|
||||
|
||||
#include "services/normal/blob_db/pin_db.h"
|
||||
#include "services/normal/timeline/timeline.h"
|
||||
|
||||
// Fixture
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// Fakes
|
||||
////////////////////////////////////////////////////////////////
|
||||
#include "fake_settings_file.h"
|
||||
#include "fake_system_task.h"
|
||||
|
||||
// Stubs
|
||||
////////////////////////////////////////////////////////////////
|
||||
#include "stubs_analytics.h"
|
||||
#include "stubs_app_cache.h"
|
||||
#include "stubs_app_install_manager.h"
|
||||
#include "stubs_blob_db.h"
|
||||
#include "stubs_blob_db_sync.h"
|
||||
#include "stubs_bt_lock.h"
|
||||
#include "stubs_events.h"
|
||||
#include "stubs_hexdump.h"
|
||||
#include "stubs_layout_layer.h"
|
||||
#include "stubs_logging.h"
|
||||
#include "stubs_mutex.h"
|
||||
#include "stubs_passert.h"
|
||||
#include "stubs_pbl_malloc.h"
|
||||
#include "stubs_prompt.h"
|
||||
#include "stubs_rand_ptr.h"
|
||||
#include "stubs_regular_timer.h"
|
||||
#include "stubs_reminder_db.h"
|
||||
#include "stubs_sleep.h"
|
||||
#include "stubs_task_watchdog.h"
|
||||
|
||||
const char *timeline_get_private_data_source(Uuid *parent_id) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static TimelineItem item1 = {
|
||||
.header = {
|
||||
.id = {0x6b, 0xf6, 0x21, 0x5b, 0xc9, 0x7f, 0x40, 0x9e,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4},
|
||||
.parent_id = {0xff, 0xf6, 0x21, 0x5b, 0xc9, 0x7f, 0x40, 0x9e,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0x01},
|
||||
.timestamp = 1,
|
||||
.duration = 0,
|
||||
.type = TimelineItemTypePin,
|
||||
.layout = LayoutIdTest,
|
||||
// don't care about the rest
|
||||
}
|
||||
};
|
||||
|
||||
static TimelineItem item2 = {
|
||||
.header = {
|
||||
.id = {0x55, 0xcb, 0x7c, 0x75, 0x8a, 0x35, 0x44, 0x87,
|
||||
0x90, 0xa4, 0x91, 0x3f, 0x1f, 0xa6, 0x76, 0x01},
|
||||
.parent_id = {0xff, 0xf6, 0x21, 0x5b, 0xc9, 0x7f, 0x40, 0x9e,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0x01},
|
||||
.timestamp = 3,
|
||||
.duration = 0,
|
||||
.type = TimelineItemTypePin,
|
||||
.layout = LayoutIdTest,
|
||||
},
|
||||
};
|
||||
|
||||
static TimelineItem item3 = {
|
||||
.header = {
|
||||
.id = {0x7c, 0x65, 0x2e, 0xb9, 0x26, 0xd6, 0x44, 0x2c,
|
||||
0x98, 0x68, 0xa4, 0x36, 0x79, 0x7d, 0xe2, 0x05},
|
||||
.parent_id = {0xff, 0xf6, 0x21, 0x5b, 0xc9, 0x7f, 0x40, 0x9e,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0x02},
|
||||
.timestamp = 4,
|
||||
.duration = 0,
|
||||
.type = TimelineItemTypePin,
|
||||
.layout = LayoutIdTest,
|
||||
}
|
||||
};
|
||||
|
||||
static TimelineItem item4 = {
|
||||
.header = {
|
||||
.id = {0x8c, 0x65, 0x2e, 0xb9, 0x26, 0xd6, 0x44, 0x2c,
|
||||
0x98, 0x68, 0xa4, 0x36, 0x79, 0x7d, 0xe2, 0x05},
|
||||
.parent_id = {0xff, 0xf6, 0x21, 0x5b, 0xc9, 0x7f, 0x40, 0x9e,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0x03},
|
||||
.timestamp = 4,
|
||||
.duration = 0,
|
||||
.type = TimelineItemTypePin,
|
||||
.layout = LayoutIdTest,
|
||||
}
|
||||
};
|
||||
|
||||
static TimelineItem reminder_app_item = {
|
||||
.header = {
|
||||
.id = {0x9c, 0x65, 0x2e, 0xb9, 0x26, 0xd6, 0x44, 0x2c,
|
||||
0x98, 0x68, 0xa4, 0x36, 0x79, 0x7d, 0xe2, 0x05},
|
||||
.parent_id = UUID_REMINDERS_DATA_SOURCE,
|
||||
.timestamp = 4,
|
||||
.duration = 0,
|
||||
.type = TimelineItemTypePin,
|
||||
.layout = LayoutIdTest,
|
||||
}
|
||||
};
|
||||
|
||||
// Setup
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void test_pin_db__initialize(void) {
|
||||
pin_db_init();
|
||||
}
|
||||
|
||||
void test_pin_db__cleanup(void) {
|
||||
pin_db_deinit();
|
||||
fake_settings_file_reset();
|
||||
}
|
||||
|
||||
// Tests
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void test_pin_db__is_dirty_insert_from_phone(void) {
|
||||
// Insert a bunch of pins "from the phone"
|
||||
// They should NOT be dirty (the phone is the source of truth)
|
||||
pin_db_insert((uint8_t *)&item1.header.id, sizeof(TimelineItemId),
|
||||
(uint8_t *)&item1, sizeof(TimelineItem));
|
||||
pin_db_insert((uint8_t *)&item2.header.id, sizeof(TimelineItemId),
|
||||
(uint8_t *)&item2, sizeof(TimelineItem));
|
||||
pin_db_insert((uint8_t *)&item3.header.id, sizeof(TimelineItemId),
|
||||
(uint8_t *)&item3, sizeof(TimelineItem));
|
||||
pin_db_insert((uint8_t *)&item4.header.id, sizeof(TimelineItemId),
|
||||
(uint8_t *)&item4, sizeof(TimelineItem));
|
||||
|
||||
bool is_dirty = true;
|
||||
cl_assert_equal_i(pin_db_is_dirty(&is_dirty), S_SUCCESS);
|
||||
cl_assert(!is_dirty);
|
||||
|
||||
BlobDBDirtyItem *dirty_list = pin_db_get_dirty_list();
|
||||
cl_assert(!dirty_list);
|
||||
}
|
||||
|
||||
void test_pin_db__is_dirty_insert_locally(void) {
|
||||
// Insert a bunch of pins "from the watch"
|
||||
// These should not be dirty because they are not from the reminders app
|
||||
pin_db_insert_item(&item1);
|
||||
pin_db_insert_item(&item2);
|
||||
pin_db_insert_item(&item3);
|
||||
pin_db_insert_item(&item4);
|
||||
|
||||
bool is_dirty = true;
|
||||
cl_assert_equal_i(pin_db_is_dirty(&is_dirty), S_SUCCESS);
|
||||
cl_assert(!is_dirty);
|
||||
|
||||
BlobDBDirtyItem *dirty_list = pin_db_get_dirty_list();
|
||||
cl_assert(!dirty_list);
|
||||
|
||||
pin_db_insert_item(&reminder_app_item);
|
||||
cl_assert_equal_i(pin_db_is_dirty(&is_dirty), S_SUCCESS);
|
||||
cl_assert(is_dirty);
|
||||
|
||||
dirty_list = pin_db_get_dirty_list();
|
||||
cl_assert(dirty_list);
|
||||
cl_assert(list_count((ListNode *)dirty_list) == 1);
|
||||
|
||||
// Mark the reminder item as synced
|
||||
pin_db_mark_synced((uint8_t *)&reminder_app_item.header.id, sizeof(TimelineItemId));
|
||||
|
||||
// And nothing should be dirty
|
||||
cl_assert_equal_i(pin_db_is_dirty(&is_dirty), S_SUCCESS);
|
||||
cl_assert(!is_dirty);
|
||||
|
||||
dirty_list = pin_db_get_dirty_list();
|
||||
cl_assert(!dirty_list);
|
||||
}
|
||||
|
||||
void test_pin_db__set_status_bits(void) {
|
||||
pin_db_insert_item(&item1);
|
||||
TimelineItem item;
|
||||
cl_must_pass(pin_db_read_item_header(&item, &item1.header.id));
|
||||
cl_assert_equal_i(item.header.status, 0);
|
||||
|
||||
cl_must_pass(pin_db_set_status_bits(&item1.header.id, TimelineItemStatusDismissed));
|
||||
cl_must_pass(pin_db_read_item_header(&item, &item1.header.id));
|
||||
cl_assert_equal_i(item.header.status, TimelineItemStatusDismissed);
|
||||
}
|
141
tests/fw/services/blob_db/test_prefs_db.c
Normal file
141
tests/fw/services/blob_db/test_prefs_db.c
Normal file
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* 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 "clar.h"
|
||||
|
||||
#include "util/uuid.h"
|
||||
#include "services/normal/filesystem/pfs.h"
|
||||
#include "services/normal/blob_db/prefs_db.h"
|
||||
#include "shell/prefs.h"
|
||||
#include "shell/prefs_private.h"
|
||||
|
||||
// Fixture
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// Fakes
|
||||
////////////////////////////////////////////////////////////////
|
||||
#include "fake_spi_flash.h"
|
||||
#include "fake_system_task.h"
|
||||
#include "fake_kernel_services_notifications.h"
|
||||
|
||||
// Stubs
|
||||
////////////////////////////////////////////////////////////////
|
||||
#include "stubs_analytics.h"
|
||||
#include "stubs_app_install_manager.h"
|
||||
#include "stubs_hexdump.h"
|
||||
#include "stubs_logging.h"
|
||||
#include "stubs_mfg_info.h"
|
||||
#include "stubs_mutex.h"
|
||||
#include "stubs_passert.h"
|
||||
#include "stubs_pbl_malloc.h"
|
||||
#include "stubs_prompt.h"
|
||||
#include "stubs_rand_ptr.h"
|
||||
#include "stubs_sleep.h"
|
||||
#include "stubs_system_theme.h"
|
||||
#include "stubs_task_watchdog.h"
|
||||
|
||||
void i18n_enable(bool enable) {
|
||||
}
|
||||
|
||||
void display_set_offset(GPoint offset) {
|
||||
}
|
||||
|
||||
void test_prefs_db__initialize(void) {
|
||||
fake_spi_flash_init(0, 0x1000000);
|
||||
pfs_init(false);
|
||||
}
|
||||
|
||||
void test_prefs_db__cleanup(void) {
|
||||
}
|
||||
|
||||
void test_prefs_db__get_length(void) {
|
||||
Uuid uuid = {0, 1, 2, 3};
|
||||
const char *key = "workerId";
|
||||
int key_len = strlen(key);
|
||||
cl_assert_equal_i(prefs_db_insert((uint8_t *)key, key_len, (uint8_t *)&uuid, sizeof(uuid)), 0);
|
||||
cl_assert_equal_i(prefs_db_get_len((uint8_t *)key, key_len), sizeof(uuid));
|
||||
}
|
||||
|
||||
void test_prefs_db__insert_and_read(void) {
|
||||
uint32_t set_value = 42;
|
||||
|
||||
// NOTE: We intentionally put one garbage character after the key to catch errors
|
||||
// that assume the key is 0 terminated
|
||||
const char *key = "lightTimeoutMsX";
|
||||
int key_len = strlen(key) - 1;
|
||||
|
||||
|
||||
// Set initial value
|
||||
backlight_set_timeout_ms(set_value + 1);
|
||||
|
||||
|
||||
// Insert and check the length
|
||||
cl_assert_equal_i(prefs_db_insert((uint8_t *)key, key_len, (uint8_t *)&set_value,
|
||||
sizeof(set_value)), 0);
|
||||
cl_assert_equal_i(prefs_db_get_len((uint8_t *)key, key_len), sizeof(set_value));
|
||||
|
||||
|
||||
// Read it back
|
||||
uint32_t get_value;
|
||||
cl_assert_equal_i(prefs_db_read((uint8_t *)key, key_len, (uint8_t *)&get_value,
|
||||
sizeof(get_value)), 0);
|
||||
cl_assert_equal_i(set_value, get_value);
|
||||
|
||||
|
||||
// If we get the pref setting now, it should still be the old value because we haven't
|
||||
// issued the blob_db update event yet
|
||||
uint32_t get_pref = backlight_get_timeout_ms();
|
||||
cl_assert_equal_i(get_pref, set_value + 1);
|
||||
|
||||
// Issue the blob_db update event
|
||||
PebbleBlobDBEvent event = (PebbleBlobDBEvent) {
|
||||
.db_id = BlobDBIdPrefs,
|
||||
.type = BlobDBEventTypeInsert,
|
||||
.key = (uint8_t *)key,
|
||||
.key_len = key_len,
|
||||
};
|
||||
prefs_private_handle_blob_db_event(&event);
|
||||
get_pref = backlight_get_timeout_ms();
|
||||
cl_assert(get_pref == get_value);
|
||||
|
||||
|
||||
// Set new value using the set call and read it back using prefs_db
|
||||
uint32_t new_set_value = 4242;
|
||||
backlight_set_timeout_ms(new_set_value);
|
||||
cl_assert_equal_i(prefs_db_read((uint8_t *)key, key_len, (uint8_t *)&get_value,
|
||||
sizeof(get_value)), 0);
|
||||
cl_assert_equal_i(new_set_value, get_value);
|
||||
|
||||
|
||||
// Try and insert an unknown key. It should fail
|
||||
const char *bad_key = "bad_key";
|
||||
int bad_key_len = strlen(bad_key);
|
||||
cl_assert(prefs_db_insert((uint8_t *)bad_key, bad_key_len, (uint8_t *)&set_value,
|
||||
sizeof(set_value)) < 0);
|
||||
cl_assert(prefs_db_get_len((uint8_t *)bad_key, bad_key_len) < 0);
|
||||
cl_assert(prefs_db_read((uint8_t *)bad_key, bad_key_len, (uint8_t *)&get_value,
|
||||
sizeof(get_value)) < 0);
|
||||
|
||||
|
||||
// Try and insert the wrong size for a known key, it should fail
|
||||
cl_assert(prefs_db_insert((uint8_t *)key, key_len, (uint8_t *)&set_value,
|
||||
sizeof(set_value) + 1) < 0);
|
||||
// Read it back
|
||||
cl_assert(prefs_db_read((uint8_t *)key, key_len, (uint8_t *)&get_value,
|
||||
sizeof(get_value) + 1) < 0);
|
||||
}
|
||||
|
||||
|
390
tests/fw/services/blob_db/test_reminder_db.c
Normal file
390
tests/fw/services/blob_db/test_reminder_db.c
Normal file
|
@ -0,0 +1,390 @@
|
|||
/*
|
||||
* 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 "clar.h"
|
||||
|
||||
#include "services/normal/blob_db/reminder_db.h"
|
||||
|
||||
// Fixture
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// Fakes
|
||||
////////////////////////////////////////////////////////////////
|
||||
#include "fake_settings_file.h"
|
||||
|
||||
// Stubs
|
||||
////////////////////////////////////////////////////////////////
|
||||
#include "stubs_analytics.h"
|
||||
#include "stubs_blob_db_sync.h"
|
||||
#include "stubs_hexdump.h"
|
||||
#include "stubs_layout_layer.h"
|
||||
#include "stubs_logging.h"
|
||||
#include "stubs_mutex.h"
|
||||
#include "stubs_passert.h"
|
||||
#include "stubs_pbl_malloc.h"
|
||||
#include "stubs_pebble_tasks.h"
|
||||
#include "stubs_prompt.h"
|
||||
#include "stubs_rand_ptr.h"
|
||||
#include "stubs_regular_timer.h"
|
||||
#include "stubs_reminders.h"
|
||||
#include "stubs_sleep.h"
|
||||
#include "stubs_task_watchdog.h"
|
||||
|
||||
void reminders_handle_reminder_removed(const Uuid *reminder_id) {
|
||||
}
|
||||
|
||||
static TimelineItem item1 = {
|
||||
.header = {
|
||||
.id = {0x6b, 0xf6, 0x21, 0x5b, 0xc9, 0x7f, 0x40, 0x9e,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0xb4},
|
||||
.parent_id = {0xff, 0xf6, 0x21, 0x5b, 0xc9, 0x7f, 0x40, 0x9e,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0x01},
|
||||
.timestamp = 1,
|
||||
.duration = 0,
|
||||
.type = TimelineItemTypeReminder,
|
||||
.layout = LayoutIdTest,
|
||||
// don't care about the rest
|
||||
}
|
||||
};
|
||||
|
||||
static TimelineItem item2 = {
|
||||
.header = {
|
||||
.id = {0x55, 0xcb, 0x7c, 0x75, 0x8a, 0x35, 0x44, 0x87,
|
||||
0x90, 0xa4, 0x91, 0x3f, 0x1f, 0xa6, 0x76, 0x01},
|
||||
.parent_id = {0xff, 0xf6, 0x21, 0x5b, 0xc9, 0x7f, 0x40, 0x9e,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0x01},
|
||||
.timestamp = 3,
|
||||
.duration = 0,
|
||||
.type = TimelineItemTypeReminder,
|
||||
.layout = LayoutIdTest,
|
||||
},
|
||||
};
|
||||
|
||||
static TimelineItem item3 = {
|
||||
.header = {
|
||||
.id = {0x7c, 0x65, 0x2e, 0xb9, 0x26, 0xd6, 0x44, 0x2c,
|
||||
0x98, 0x68, 0xa4, 0x36, 0x79, 0x7d, 0xe2, 0x05},
|
||||
.parent_id = {0xff, 0xf6, 0x21, 0x5b, 0xc9, 0x7f, 0x40, 0x9e,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0x02},
|
||||
.timestamp = 4,
|
||||
.duration = 0,
|
||||
.type = TimelineItemTypeReminder,
|
||||
.layout = LayoutIdTest,
|
||||
}
|
||||
};
|
||||
|
||||
static TimelineItem item4 = {
|
||||
.header = {
|
||||
.id = {0x8c, 0x65, 0x2e, 0xb9, 0x26, 0xd6, 0x44, 0x2c,
|
||||
0x98, 0x68, 0xa4, 0x36, 0x79, 0x7d, 0xe2, 0x05},
|
||||
.parent_id = {0xff, 0xf6, 0x21, 0x5b, 0xc9, 0x7f, 0x40, 0x9e,
|
||||
0x8c, 0x31, 0x4f, 0x55, 0x65, 0x72, 0x22, 0x03},
|
||||
.timestamp = 4,
|
||||
.duration = 0,
|
||||
.type = TimelineItemTypeReminder,
|
||||
.layout = LayoutIdTest,
|
||||
}
|
||||
};
|
||||
|
||||
static SerializedTimelineItemHeader bad_item = {
|
||||
.common = {
|
||||
.id = {0x8c, 0x65, 0x2e, 0xb9, 0x26, 0xd6, 0x42, 0x2c,
|
||||
0x98, 0x68, 0xa4, 0x36, 0x79, 0x7d, 0xe2, 0x05},
|
||||
.timestamp = 3,
|
||||
.duration = 0,
|
||||
.type = TimelineItemTypeReminder,
|
||||
.layout = LayoutIdTest,
|
||||
},
|
||||
.num_attributes = 3,
|
||||
};
|
||||
|
||||
static TimelineItem title_item1 = {
|
||||
.header = {
|
||||
.id = {0x9c, 0x65, 0x2e, 0xb9, 0x26, 0xd6, 0x44, 0x2c,
|
||||
0x98, 0x68, 0xa4, 0x36, 0x79, 0x7d, 0xe2, 0x05},
|
||||
.timestamp = 1,
|
||||
.duration = 0,
|
||||
.type = TimelineItemTypeReminder,
|
||||
.layout = LayoutIdTest,
|
||||
},
|
||||
.attr_list = (AttributeList) {
|
||||
.num_attributes = 1,
|
||||
.attributes = (Attribute[1]) {{ .id = AttributeIdTitle, .cstring = "test 1" }}
|
||||
}
|
||||
};
|
||||
|
||||
static TimelineItem title_item2 = {
|
||||
.header = {
|
||||
.id = {0xac, 0x65, 0x2e, 0xb9, 0x26, 0xd6, 0x44, 0x2c,
|
||||
0x98, 0x68, 0xa4, 0x36, 0x79, 0x7d, 0xe2, 0x05},
|
||||
.timestamp = 1,
|
||||
.duration = 0,
|
||||
.type = TimelineItemTypeReminder,
|
||||
.layout = LayoutIdTest,
|
||||
},
|
||||
.attr_list = (AttributeList) {
|
||||
.num_attributes = 1,
|
||||
.attributes = (Attribute[1]) {{ .id = AttributeIdTitle, .cstring = "test 2" }}
|
||||
}
|
||||
};
|
||||
|
||||
static void prv_insert_default_reminders(void) {
|
||||
// add all four explicitly out of order
|
||||
cl_assert_equal_i(S_SUCCESS, reminder_db_insert_item(&item4));
|
||||
|
||||
cl_assert_equal_i(S_SUCCESS, reminder_db_insert_item(&item2));
|
||||
|
||||
cl_assert_equal_i(S_SUCCESS, reminder_db_insert_item(&item1));
|
||||
|
||||
cl_assert_equal_i(S_SUCCESS, reminder_db_insert_item(&item3));
|
||||
}
|
||||
|
||||
// Setup
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void test_reminder_db__initialize(void) {
|
||||
reminder_db_init();
|
||||
}
|
||||
|
||||
void test_reminder_db__cleanup(void) {
|
||||
reminder_db_deinit();
|
||||
fake_settings_file_reset();
|
||||
}
|
||||
|
||||
// Tests
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void test_reminder_db__basic_test(void) {
|
||||
prv_insert_default_reminders();
|
||||
|
||||
// confirm all three are there
|
||||
cl_assert(reminder_db_get_len((uint8_t*)&item1.header.id, sizeof(Uuid)) > 0);
|
||||
cl_assert(reminder_db_get_len((uint8_t*)&item2.header.id, sizeof(Uuid)) > 0);
|
||||
cl_assert(reminder_db_get_len((uint8_t*)&item3.header.id, sizeof(Uuid)) > 0);
|
||||
|
||||
// remove #1 and confirm it's deleted
|
||||
cl_assert(S_SUCCESS == reminder_db_delete((uint8_t*)&item1.header.id, sizeof(Uuid)));
|
||||
cl_assert(reminder_db_get_len((uint8_t *)&item1.header.id, sizeof(Uuid)) == 0);
|
||||
|
||||
// add 1 back so it's clean
|
||||
cl_assert(S_SUCCESS == reminder_db_insert_item(&item1));
|
||||
TimelineItem temp = {{{0}}};
|
||||
cl_assert(S_SUCCESS == reminder_db_read((uint8_t*)&item1.header.id, sizeof(Uuid), (uint8_t*)&temp,
|
||||
sizeof(CommonTimelineItemHeader)));
|
||||
|
||||
// Note: we set things to null because it makes it easier to compare two
|
||||
// TimelineItems with memcmp
|
||||
// check item 1
|
||||
memset(&temp, 0, sizeof(TimelineItem));
|
||||
cl_assert(S_SUCCESS == reminder_db_next_item_header(&temp));
|
||||
cl_assert(uuid_equal(&item1.header.id, &temp.header.id));
|
||||
temp.attr_list.attributes = NULL;
|
||||
cl_assert(memcmp(&item1, &temp, sizeof(TimelineItem)) == 0);
|
||||
cl_assert(S_SUCCESS == reminder_db_delete_item(&temp.header.id, true /* send_event */));
|
||||
cl_assert(reminder_db_get_len((uint8_t *)&item1.header.id, sizeof(Uuid)) == 0);
|
||||
|
||||
// check item 2
|
||||
memset(&temp, 0, sizeof(TimelineItem));
|
||||
cl_assert(S_SUCCESS == reminder_db_next_item_header(&temp));
|
||||
cl_assert(uuid_equal(&item2.header.id, &temp.header.id));
|
||||
temp.attr_list.attributes = NULL;
|
||||
cl_assert(memcmp(&item2, &temp, sizeof(TimelineItem)) == 0);
|
||||
cl_assert(S_SUCCESS == reminder_db_delete_item(&temp.header.id, true /* send_event */));
|
||||
cl_assert(reminder_db_get_len((uint8_t *)&item2.header.id, sizeof(Uuid)) == 0);
|
||||
|
||||
// check item 3 or 4
|
||||
memset(&temp, 0, sizeof(TimelineItem));
|
||||
cl_assert(S_SUCCESS == reminder_db_next_item_header(&temp));
|
||||
if (uuid_equal(&item3.header.id, &temp.header.id)) {
|
||||
temp.attr_list.attributes = NULL;
|
||||
timeline_item_free_allocated_buffer(&temp);
|
||||
cl_assert(memcmp(&item3, &temp, sizeof(TimelineItem)) == 0);
|
||||
cl_assert(S_SUCCESS == reminder_db_delete_item(&temp.header.id, true /* send_event */));
|
||||
cl_assert(reminder_db_get_len((uint8_t *) &item3, sizeof(Uuid)) == 0);
|
||||
|
||||
memset(&temp, 0, sizeof(TimelineItem));
|
||||
cl_assert(S_SUCCESS == reminder_db_next_item_header(&temp));
|
||||
temp.attr_list.attributes = NULL;
|
||||
cl_assert(memcmp(&item4, &temp, sizeof(TimelineItem)) == 0);
|
||||
cl_assert(S_SUCCESS == reminder_db_delete_item(&temp.header.id, true /* send_event */));
|
||||
cl_assert(reminder_db_get_len((uint8_t *)&item4.header.id, sizeof(Uuid)) == 0);
|
||||
} else {
|
||||
temp.attr_list.attributes = NULL;
|
||||
cl_assert(memcmp(&item4, &temp, sizeof(TimelineItem)) == 0);
|
||||
cl_assert(S_SUCCESS == reminder_db_delete_item(&temp.header.id, true /* send_event */));
|
||||
cl_assert(reminder_db_get_len((uint8_t *) &item4, sizeof(Uuid)) == 0);
|
||||
|
||||
memset(&temp, 0, sizeof(TimelineItem));
|
||||
cl_assert(S_SUCCESS == reminder_db_next_item_header(&temp));
|
||||
temp.attr_list.attributes = NULL;
|
||||
cl_assert(memcmp(&item3, &temp, sizeof(TimelineItem)) == 0);
|
||||
cl_assert(S_SUCCESS == reminder_db_delete_item(&temp.header.id, true /* send_event */));
|
||||
cl_assert(reminder_db_get_len((uint8_t *)&item3.header.id, sizeof(Uuid)) == 0);
|
||||
}
|
||||
|
||||
cl_assert(S_NO_MORE_ITEMS == reminder_db_next_item_header(&temp));
|
||||
}
|
||||
|
||||
void test_reminder_db__size_test(void) {
|
||||
prv_insert_default_reminders();
|
||||
|
||||
cl_assert(sizeof(SerializedTimelineItemHeader) == reminder_db_get_len((uint8_t*) &item1.header.id, sizeof(TimelineItemId)));
|
||||
|
||||
cl_assert(sizeof(SerializedTimelineItemHeader) == reminder_db_get_len((uint8_t*) &item2.header.id, sizeof(TimelineItemId)));
|
||||
|
||||
cl_assert(sizeof(SerializedTimelineItemHeader) == reminder_db_get_len((uint8_t*) &item3.header.id, sizeof(TimelineItemId)));
|
||||
}
|
||||
|
||||
void test_reminder_db__wrong_type_test(void) {
|
||||
TimelineItem not_a_reminder = {
|
||||
.header = {
|
||||
.id = {0x99, 0xcb, 0x7c, 0x75, 0x8a, 0x35, 0x44, 0x87,
|
||||
0x90, 0xa4, 0x91, 0x3f, 0x1f, 0xa6, 0x76, 0x01},
|
||||
.timestamp = 0,
|
||||
.duration = 0,
|
||||
.type = TimelineItemTypeNotification
|
||||
}
|
||||
};
|
||||
|
||||
cl_assert(E_INVALID_ARGUMENT == reminder_db_insert_item(¬_a_reminder));
|
||||
}
|
||||
|
||||
void test_reminder_db__delete_parent(void) {
|
||||
prv_insert_default_reminders();
|
||||
|
||||
const TimelineItemId *parent_id = &item1.header.parent_id;
|
||||
// cnfirm the two are here
|
||||
cl_assert(reminder_db_get_len((uint8_t *)&item1.header.id, sizeof(Uuid)) > 0);
|
||||
cl_assert(reminder_db_get_len((uint8_t *)&item2.header.id, sizeof(Uuid)) > 0);
|
||||
// remove the two that share a parent
|
||||
cl_assert_equal_i(reminder_db_delete_with_parent(parent_id), S_SUCCESS);
|
||||
// confirm the two are gone
|
||||
cl_assert(reminder_db_get_len((uint8_t *)&item1.header.id, sizeof(Uuid)) == 0);
|
||||
cl_assert(reminder_db_get_len((uint8_t *)&item2.header.id, sizeof(Uuid)) == 0);
|
||||
// confirm the others are still here
|
||||
cl_assert(reminder_db_get_len((uint8_t*)&item3.header.id, sizeof(Uuid)) > 0);
|
||||
cl_assert(reminder_db_get_len((uint8_t*)&item4.header.id, sizeof(Uuid)) > 0);
|
||||
}
|
||||
|
||||
void test_reminder_db__bad_item(void) {
|
||||
cl_assert(S_SUCCESS != reminder_db_insert((uint8_t *)&bad_item.common.id, UUID_SIZE, (uint8_t *)&bad_item, sizeof(bad_item)));
|
||||
}
|
||||
|
||||
void test_reminder_db__read_nonexistant(void) {
|
||||
TimelineItem item = {{{0}}};
|
||||
cl_assert_equal_i(E_DOES_NOT_EXIST, reminder_db_read_item(&item, &bad_item.common.id));
|
||||
}
|
||||
|
||||
void test_reminder_db__find_by_timestamp_title(void) {
|
||||
prv_insert_default_reminders();
|
||||
|
||||
// Add items with title attributes for searching (out of order for worst-case scenario)
|
||||
cl_assert(S_SUCCESS == reminder_db_insert_item(&title_item2));
|
||||
cl_assert(S_SUCCESS == reminder_db_insert_item(&title_item1));
|
||||
|
||||
TimelineItem reminder;
|
||||
|
||||
// Test non-matching title and timestamp
|
||||
cl_assert_equal_b(reminder_db_find_by_timestamp_title(0, "nonexistent title", NULL, &reminder),
|
||||
false);
|
||||
|
||||
// Test matching timstamp, but not title
|
||||
cl_assert_equal_b(reminder_db_find_by_timestamp_title(title_item1.header.timestamp,
|
||||
"nonexistent title", NULL, &reminder), false);
|
||||
|
||||
// Test matching title, but not timestamp
|
||||
cl_assert_equal_b(reminder_db_find_by_timestamp_title(0,
|
||||
title_item1.attr_list.attributes[0].cstring, NULL, &reminder), false);
|
||||
|
||||
// Confirm proper item is returned for search criteria
|
||||
cl_assert_equal_b(reminder_db_find_by_timestamp_title(title_item1.header.timestamp,
|
||||
title_item1.attr_list.attributes[0].cstring, NULL, &reminder), true);
|
||||
cl_assert(uuid_equal(&reminder.header.id, &title_item1.header.id));
|
||||
}
|
||||
|
||||
void test_reminder_db__is_dirty_insert_from_phone(void) {
|
||||
// Insert a bunch of reminders "from the phone"
|
||||
// They should NOT be dirty (the phone is the source of truth)
|
||||
reminder_db_insert((uint8_t *)&item1.header.id, sizeof(TimelineItemId),
|
||||
(uint8_t *)&item1, sizeof(TimelineItem));
|
||||
reminder_db_insert((uint8_t *)&item2.header.id, sizeof(TimelineItemId),
|
||||
(uint8_t *)&item2, sizeof(TimelineItem));
|
||||
reminder_db_insert((uint8_t *)&item3.header.id, sizeof(TimelineItemId),
|
||||
(uint8_t *)&item3, sizeof(TimelineItem));
|
||||
reminder_db_insert((uint8_t *)&item4.header.id, sizeof(TimelineItemId),
|
||||
(uint8_t *)&item4, sizeof(TimelineItem));
|
||||
|
||||
bool is_dirty = true;
|
||||
cl_assert_equal_i(reminder_db_is_dirty(&is_dirty), S_SUCCESS);
|
||||
cl_assert(!is_dirty);
|
||||
|
||||
BlobDBDirtyItem *dirty_list = reminder_db_get_dirty_list();
|
||||
cl_assert(!dirty_list);
|
||||
}
|
||||
|
||||
void test_reminder_db__is_dirty_insert_locally(void) {
|
||||
// Insert a bunch of reminders "from the watch"
|
||||
// These should be dirty (the phone is the source of truth)
|
||||
const int num_reminders = 4;
|
||||
reminder_db_insert_item(&item1);
|
||||
reminder_db_insert_item(&item2);
|
||||
reminder_db_insert_item(&item3);
|
||||
reminder_db_insert_item(&item4);
|
||||
|
||||
bool is_dirty = false;
|
||||
cl_assert_equal_i(reminder_db_is_dirty(&is_dirty), S_SUCCESS);
|
||||
cl_assert(is_dirty);
|
||||
|
||||
BlobDBDirtyItem *dirty_list = reminder_db_get_dirty_list();
|
||||
cl_assert(dirty_list);
|
||||
cl_assert(list_count((ListNode *)dirty_list) == num_reminders);
|
||||
|
||||
// Mark some items as synced
|
||||
reminder_db_mark_synced((uint8_t *)&item1.header.id, sizeof(TimelineItemId));
|
||||
reminder_db_mark_synced((uint8_t *)&item3.header.id, sizeof(TimelineItemId));
|
||||
|
||||
// We should now only have 2 dirty items
|
||||
cl_assert_equal_i(reminder_db_is_dirty(&is_dirty), S_SUCCESS);
|
||||
cl_assert(is_dirty);
|
||||
|
||||
dirty_list = reminder_db_get_dirty_list();
|
||||
cl_assert(dirty_list);
|
||||
cl_assert_equal_i(list_count((ListNode *)dirty_list), 2);
|
||||
|
||||
// Mark the final 2 items as synced
|
||||
reminder_db_mark_synced((uint8_t *)&item2.header.id, sizeof(TimelineItemId));
|
||||
reminder_db_mark_synced((uint8_t *)&item4.header.id, sizeof(TimelineItemId));
|
||||
|
||||
// And nothing should be dirty
|
||||
cl_assert_equal_i(reminder_db_is_dirty(&is_dirty), S_SUCCESS);
|
||||
cl_assert(!is_dirty);
|
||||
|
||||
dirty_list = reminder_db_get_dirty_list();
|
||||
cl_assert(!dirty_list);
|
||||
}
|
||||
|
||||
void test_reminder_db__set_status_bits(void) {
|
||||
reminder_db_insert_item(&item1);
|
||||
SerializedTimelineItemHeader item;
|
||||
cl_must_pass(reminder_db_read((uint8_t *)&item1.header.id, sizeof(Uuid), (uint8_t *)&item,
|
||||
sizeof(SerializedTimelineItemHeader)));
|
||||
cl_assert_equal_i(item.common.status & 0xFF, 0);
|
||||
|
||||
cl_must_pass(reminder_db_set_status_bits(&item1.header.id, TimelineItemStatusReminded));
|
||||
cl_must_pass(reminder_db_read((uint8_t *)&item1.header.id, sizeof(Uuid), (uint8_t *)&item,
|
||||
sizeof(SerializedTimelineItemHeader)));
|
||||
cl_assert_equal_i(item.common.status & 0xFF, TimelineItemStatusReminded);
|
||||
}
|
1511
tests/fw/services/blob_db/test_timeline.c
Normal file
1511
tests/fw/services/blob_db/test_timeline.c
Normal file
File diff suppressed because it is too large
Load diff
194
tests/fw/services/blob_db/test_watch_app_prefs_db.c
Normal file
194
tests/fw/services/blob_db/test_watch_app_prefs_db.c
Normal file
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* 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 "clar.h"
|
||||
|
||||
#include "services/normal/blob_db/watch_app_prefs_db.h"
|
||||
#include "services/normal/filesystem/pfs.h"
|
||||
#include "services/normal/weather/weather_service_private.h"
|
||||
#include "util/uuid.h"
|
||||
|
||||
// Fixture
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// Fakes
|
||||
////////////////////////////////////////////////////////////////
|
||||
#include "fake_spi_flash.h"
|
||||
#include "fake_system_task.h"
|
||||
#include "fake_kernel_services_notifications.h"
|
||||
|
||||
// Stubs
|
||||
////////////////////////////////////////////////////////////////
|
||||
#include "stubs_analytics.h"
|
||||
#include "stubs_hexdump.h"
|
||||
#include "stubs_layout_layer.h"
|
||||
#include "stubs_logging.h"
|
||||
#include "stubs_mutex.h"
|
||||
#include "stubs_passert.h"
|
||||
#include "stubs_pbl_malloc.h"
|
||||
#include "stubs_prompt.h"
|
||||
#include "stubs_rand_ptr.h"
|
||||
#include "stubs_sleep.h"
|
||||
#include "stubs_task_watchdog.h"
|
||||
|
||||
extern const char *PREF_KEY_SEND_TEXT_APP;
|
||||
#define SEND_TEXT_KEY ((uint8_t *)PREF_KEY_SEND_TEXT_APP)
|
||||
#define SEND_TEXT_KEY_LEN (strlen(PREF_KEY_SEND_TEXT_APP))
|
||||
|
||||
#define INVALID_KEY ((uint8_t *)"thisIsNotAnApp")
|
||||
#define INVALID_KEY_LEN strlen((char *)INVALID_KEY)
|
||||
|
||||
#define NUM_SEND_TEXT_CONTACTS (5)
|
||||
#define SEND_TEXT_DATA_LEN (sizeof(SerializedSendTextPrefs) + \
|
||||
(sizeof(SerializedSendTextContact) * NUM_SEND_TEXT_CONTACTS))
|
||||
static uint8_t s_send_text_prefs[SEND_TEXT_DATA_LEN];
|
||||
|
||||
#define WEATHER_KEY ((uint8_t *)PREF_KEY_WEATHER_APP)
|
||||
#define WEATHER_KEY_LEN (strlen(PREF_KEY_WEATHER_APP))
|
||||
#define NUM_WEATHER_LOCATIONS (4)
|
||||
#define WEATHER_DATA_SIZE (sizeof(SerializedWeatherAppPrefs) + \
|
||||
(sizeof(Uuid) * NUM_WEATHER_LOCATIONS))
|
||||
static uint8_t s_weather_prefs[WEATHER_DATA_SIZE];
|
||||
|
||||
// Setup
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void test_watch_app_prefs_db__initialize(void) {
|
||||
fake_spi_flash_init(0, 0x1000000);
|
||||
pfs_init(false);
|
||||
watch_app_prefs_db_init();
|
||||
|
||||
// Set up our test prefs with some random data
|
||||
SerializedSendTextPrefs *prefs = (SerializedSendTextPrefs *)s_send_text_prefs;
|
||||
prefs->num_contacts = NUM_SEND_TEXT_CONTACTS;
|
||||
for (int i = 0; i < NUM_SEND_TEXT_CONTACTS; ++i) {
|
||||
prefs->contacts[i] = (SerializedSendTextContact) {
|
||||
.is_fav = (i < (NUM_SEND_TEXT_CONTACTS/2)),
|
||||
};
|
||||
uuid_generate(&prefs->contacts[i].contact_uuid);
|
||||
uuid_generate(&prefs->contacts[i].address_uuid);
|
||||
}
|
||||
|
||||
SerializedWeatherAppPrefs *weather_prefs = (SerializedWeatherAppPrefs *)s_weather_prefs;
|
||||
weather_prefs->num_locations = NUM_WEATHER_LOCATIONS;
|
||||
for (int i = 0; i < NUM_WEATHER_LOCATIONS; i++) {
|
||||
uuid_generate(&weather_prefs->locations[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void test_watch_app_prefs_db__cleanup(void) {
|
||||
}
|
||||
|
||||
// Tests
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void test_watch_app_prefs_db__insert_send_text(void) {
|
||||
const int data_len = sizeof(s_send_text_prefs);
|
||||
|
||||
cl_assert_equal_i(
|
||||
watch_app_prefs_db_insert(SEND_TEXT_KEY, SEND_TEXT_KEY_LEN, s_send_text_prefs, data_len),
|
||||
S_SUCCESS);
|
||||
cl_assert_equal_i(watch_app_prefs_db_get_len(SEND_TEXT_KEY, SEND_TEXT_KEY_LEN), data_len);
|
||||
|
||||
// Make sure we get back the correct data
|
||||
uint8_t send_text_prefs_out[data_len];
|
||||
cl_assert_equal_i(
|
||||
watch_app_prefs_db_read(SEND_TEXT_KEY, SEND_TEXT_KEY_LEN, send_text_prefs_out, data_len),
|
||||
S_SUCCESS);
|
||||
cl_assert_equal_m(s_send_text_prefs, send_text_prefs_out, data_len);
|
||||
|
||||
// Make sure we reject malformed data (not aligned to list size)
|
||||
cl_assert_equal_i(watch_app_prefs_db_insert(SEND_TEXT_KEY, SEND_TEXT_KEY_LEN, s_send_text_prefs,
|
||||
(data_len + 1)), E_INVALID_ARGUMENT);
|
||||
|
||||
// Make sure we reject data that is too small to hold all entries
|
||||
cl_assert_equal_i(watch_app_prefs_db_insert(SEND_TEXT_KEY, SEND_TEXT_KEY_LEN, s_send_text_prefs,
|
||||
(data_len - sizeof(SerializedSendTextContact))), E_INVALID_ARGUMENT);
|
||||
|
||||
// Make sure we reject keys we don't recognize
|
||||
cl_assert_equal_i(watch_app_prefs_db_insert(INVALID_KEY, INVALID_KEY_LEN, s_send_text_prefs,
|
||||
data_len), E_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
void test_watch_app_prefs_db__insert_weather(void) {
|
||||
const int data_len = sizeof(s_weather_prefs);
|
||||
|
||||
cl_assert_equal_i(
|
||||
watch_app_prefs_db_insert(WEATHER_KEY, WEATHER_KEY_LEN, s_weather_prefs, data_len),
|
||||
S_SUCCESS);
|
||||
cl_assert_equal_i(watch_app_prefs_db_get_len(WEATHER_KEY, WEATHER_KEY_LEN), data_len);
|
||||
|
||||
// Make sure we get back the correct data
|
||||
uint8_t weather_prefs_out[data_len];
|
||||
cl_assert_equal_i(
|
||||
watch_app_prefs_db_read(WEATHER_KEY, WEATHER_KEY_LEN, weather_prefs_out, data_len),
|
||||
S_SUCCESS);
|
||||
cl_assert_equal_m(s_weather_prefs, weather_prefs_out, data_len);
|
||||
|
||||
// Make sure we reject malformed data (not aligned to list size)
|
||||
cl_assert_equal_i(watch_app_prefs_db_insert(WEATHER_KEY, WEATHER_KEY_LEN, s_weather_prefs,
|
||||
(data_len + 1)), E_INVALID_ARGUMENT);
|
||||
|
||||
// Make sure we reject data that is too small to hold all entries
|
||||
cl_assert_equal_i(watch_app_prefs_db_insert(WEATHER_KEY, WEATHER_KEY_LEN, s_weather_prefs,
|
||||
(data_len - sizeof(SerializedWeatherAppPrefs))), E_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
void test_watch_app_prefs_db__insert_remove(void) {
|
||||
cl_assert_equal_i(watch_app_prefs_db_insert(SEND_TEXT_KEY, SEND_TEXT_KEY_LEN, s_send_text_prefs,
|
||||
sizeof(s_send_text_prefs)), S_SUCCESS);
|
||||
cl_assert_equal_i(watch_app_prefs_db_delete(SEND_TEXT_KEY, SEND_TEXT_KEY_LEN), S_SUCCESS);
|
||||
cl_assert_equal_i(watch_app_prefs_db_get_len(SEND_TEXT_KEY, SEND_TEXT_KEY_LEN), 0);
|
||||
|
||||
cl_assert_equal_i(watch_app_prefs_db_insert(WEATHER_KEY, WEATHER_KEY_LEN, s_weather_prefs,
|
||||
sizeof(s_weather_prefs)), S_SUCCESS);
|
||||
cl_assert_equal_i(watch_app_prefs_db_delete(WEATHER_KEY, WEATHER_KEY_LEN), S_SUCCESS);
|
||||
cl_assert_equal_i(watch_app_prefs_db_get_len(WEATHER_KEY, WEATHER_KEY_LEN), 0);
|
||||
}
|
||||
|
||||
void test_watch_app_prefs_db__flush(void) {
|
||||
cl_assert_equal_i(watch_app_prefs_db_insert(SEND_TEXT_KEY, SEND_TEXT_KEY_LEN, s_send_text_prefs,
|
||||
sizeof(s_send_text_prefs)), S_SUCCESS);
|
||||
cl_assert_equal_i(watch_app_prefs_db_insert(WEATHER_KEY, WEATHER_KEY_LEN, s_weather_prefs,
|
||||
sizeof(s_weather_prefs)), S_SUCCESS);
|
||||
cl_assert_equal_i(watch_app_prefs_db_flush(), S_SUCCESS);
|
||||
fake_system_task_callbacks_invoke_pending();
|
||||
cl_assert_equal_i(watch_app_prefs_db_get_len(SEND_TEXT_KEY, SEND_TEXT_KEY_LEN), 0);
|
||||
}
|
||||
|
||||
void test_watch_app_prefs_db__get_send_text(void) {
|
||||
const int data_len = sizeof(s_send_text_prefs);
|
||||
|
||||
cl_assert_equal_i(watch_app_prefs_db_insert(SEND_TEXT_KEY, SEND_TEXT_KEY_LEN,
|
||||
s_send_text_prefs, data_len), S_SUCCESS);
|
||||
cl_assert_equal_i(watch_app_prefs_db_get_len(SEND_TEXT_KEY, SEND_TEXT_KEY_LEN), data_len);
|
||||
|
||||
SerializedSendTextPrefs *send_text_prefs_out = watch_app_prefs_get_send_text();
|
||||
cl_assert_equal_m(s_send_text_prefs, send_text_prefs_out, data_len);
|
||||
task_free(send_text_prefs_out);
|
||||
}
|
||||
|
||||
void test_watch_app_prefs_db__get_weather(void) {
|
||||
const int data_len = sizeof(s_weather_prefs);
|
||||
|
||||
cl_assert_equal_i(watch_app_prefs_db_insert(WEATHER_KEY, WEATHER_KEY_LEN,
|
||||
s_weather_prefs, data_len), S_SUCCESS);
|
||||
cl_assert_equal_i(watch_app_prefs_db_get_len(WEATHER_KEY, WEATHER_KEY_LEN), data_len);
|
||||
|
||||
SerializedWeatherAppPrefs *weather_prefs_out = watch_app_prefs_get_weather();
|
||||
cl_assert_equal_m(s_weather_prefs, weather_prefs_out, data_len);
|
||||
watch_app_prefs_destroy_weather(weather_prefs_out);
|
||||
}
|
174
tests/fw/services/blob_db/test_weather_db.c
Normal file
174
tests/fw/services/blob_db/test_weather_db.c
Normal file
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* 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 "clar.h"
|
||||
|
||||
#include "util/attributes.h"
|
||||
#include "util/pstring.h"
|
||||
|
||||
#include "services/normal/blob_db/weather_db.h"
|
||||
#include "services/normal/filesystem/pfs.h"
|
||||
#include "services/normal/weather/weather_types.h"
|
||||
#include "weather_data_shared.h"
|
||||
|
||||
// Fixture
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// Fakes
|
||||
////////////////////////////////////////////////////////////////
|
||||
#include "fake_pbl_malloc.h"
|
||||
#include "fake_spi_flash.h"
|
||||
|
||||
// Stubs
|
||||
////////////////////////////////////////////////////////////////
|
||||
#include "stubs_analytics.h"
|
||||
#include "stubs_hexdump.h"
|
||||
#include "stubs_logging.h"
|
||||
#include "stubs_mutex.h"
|
||||
#include "stubs_passert.h"
|
||||
#include "stubs_prompt.h"
|
||||
#include "stubs_task_watchdog.h"
|
||||
#include "stubs_pebble_tasks.h"
|
||||
#include "stubs_sleep.h"
|
||||
|
||||
bool weather_service_supported_by_phone(void) {
|
||||
return true;
|
||||
}
|
||||
// Setup
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void test_weather_db__initialize(void) {
|
||||
fake_spi_flash_init(0, 0x1000000);
|
||||
pfs_init(false);
|
||||
weather_db_init();
|
||||
weather_shared_data_init();
|
||||
}
|
||||
|
||||
void test_weather_db__cleanup(void) {
|
||||
weather_shared_data_cleanup();
|
||||
}
|
||||
|
||||
// Tests
|
||||
////////////////////////////////////////////////////////////////
|
||||
static void prv_db_iterator_cb(WeatherDBKey *key, WeatherDBEntry *entry, void *unused) {
|
||||
weather_shared_data_assert_entries_equal(key, entry,
|
||||
weather_shared_data_get_entry(weather_shared_data_get_index_of_key(key)));
|
||||
}
|
||||
|
||||
void test_weather_db__get_entries(void) {
|
||||
cl_assert_equal_i(S_SUCCESS, weather_db_for_each(prv_db_iterator_cb, NULL));
|
||||
}
|
||||
|
||||
void test_weather_db__check_records_in_db(void) {
|
||||
for (int index = 0; index < WEATHER_DATA_SHARED_WEATHER_DB_NUM_DB_ENTRIES; index++) {
|
||||
WeatherDBEntry *to_check = task_zalloc_check(weather_shared_data_get_entry_size(index));
|
||||
const WeatherDBKey *key = weather_shared_data_get_key(index);
|
||||
cl_assert_equal_i(S_SUCCESS, weather_db_read((uint8_t*)key,
|
||||
sizeof(WeatherDBKey),
|
||||
(uint8_t*)to_check,
|
||||
weather_shared_data_get_entry_size(index)));
|
||||
|
||||
WeatherDBEntry *original = weather_shared_data_get_entry(index);
|
||||
weather_shared_data_assert_entries_equal(key, to_check, original);
|
||||
task_free(to_check);
|
||||
}
|
||||
}
|
||||
|
||||
void test_weather_db__check_small_record_not_inserted(void) {
|
||||
const size_t entry_size = MIN_ENTRY_SIZE - 1;
|
||||
void *entry = task_zalloc_check(entry_size);
|
||||
WeatherDBKey key = (WeatherDBKey) {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5
|
||||
};
|
||||
|
||||
cl_assert_equal_i(E_INVALID_ARGUMENT, weather_db_insert((uint8_t*)&key,
|
||||
sizeof(WeatherDBKey),
|
||||
(uint8_t*)entry,
|
||||
entry_size));
|
||||
task_free(entry);
|
||||
}
|
||||
|
||||
void test_weather_db__check_too_large_record_not_inserted(void) {
|
||||
const size_t entry_size = MAX_ENTRY_SIZE + 1;
|
||||
void *entry = task_zalloc_check(entry_size);
|
||||
WeatherDBKey key = (WeatherDBKey) {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5
|
||||
};
|
||||
|
||||
cl_assert_equal_i(E_INVALID_ARGUMENT, weather_db_insert((uint8_t*)&key,
|
||||
sizeof(WeatherDBKey),
|
||||
(uint8_t*)entry,
|
||||
entry_size));
|
||||
task_free(entry);
|
||||
}
|
||||
|
||||
static void prv_check_invalid_version_code_not_inserted(uint8_t version) {
|
||||
const WeatherDBEntry *existing_entry = weather_shared_data_get_entry(0);
|
||||
const size_t entry_size = sizeof(*existing_entry);
|
||||
|
||||
WeatherDBEntry *new_entry = task_zalloc_check(entry_size);
|
||||
*new_entry = *existing_entry;
|
||||
new_entry->version = version;
|
||||
|
||||
WeatherDBKey key = (WeatherDBKey) {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5
|
||||
};
|
||||
cl_assert_equal_i(E_INVALID_ARGUMENT, weather_db_insert((uint8_t*)&key,
|
||||
sizeof(WeatherDBKey),
|
||||
(uint8_t*)new_entry,
|
||||
entry_size));
|
||||
task_free(new_entry);
|
||||
}
|
||||
|
||||
void test_weather_db__lower_version_not_inserted(void) {
|
||||
for (size_t version = 0; version < WEATHER_DB_CURRENT_VERSION; version++) {
|
||||
prv_check_invalid_version_code_not_inserted(version);
|
||||
}
|
||||
}
|
||||
|
||||
void test_weather_db__higher_version_not_inserted(void) {
|
||||
prv_check_invalid_version_code_not_inserted(WEATHER_DB_CURRENT_VERSION + 1);
|
||||
}
|
||||
|
||||
status_t weather_db_get_num_keys(uint16_t *val_out);
|
||||
|
||||
void test_weather_db__test_get_num_keys(void) {
|
||||
uint16_t num_keys;
|
||||
cl_assert_equal_i(S_SUCCESS, weather_db_get_num_keys(&num_keys));
|
||||
cl_assert_equal_i(num_keys, WEATHER_DATA_SHARED_WEATHER_DB_NUM_DB_ENTRIES);
|
||||
}
|
||||
|
||||
status_t weather_db_get_keys(WeatherDBKey *keys);
|
||||
|
||||
void test_weather_db__test_get_keys(void) {
|
||||
WeatherDBKey keys[WEATHER_DATA_SHARED_WEATHER_DB_NUM_DB_ENTRIES];
|
||||
cl_assert_equal_i(S_SUCCESS, weather_db_get_keys(keys));
|
||||
|
||||
for(int x = 0; x < WEATHER_DATA_SHARED_WEATHER_DB_NUM_DB_ENTRIES; x++) {
|
||||
cl_assert(weather_shared_data_get_key_exists(&keys[x]));
|
||||
}
|
||||
}
|
||||
|
||||
void test_weather_db__read_stale_entries(void) {
|
||||
WeatherDBKey key = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
|
||||
size_t entry_size = weather_shared_data_insert_stale_entry(&key);
|
||||
uint8_t *buf = task_zalloc_check(entry_size);
|
||||
|
||||
cl_assert_equal_i(E_DOES_NOT_EXIST, weather_db_read((uint8_t*)&key,
|
||||
sizeof(WeatherDBKey),
|
||||
buf,
|
||||
entry_size));
|
||||
}
|
303
tests/fw/services/blob_db/weather_data_shared.c
Normal file
303
tests/fw/services/blob_db/weather_data_shared.c
Normal file
|
@ -0,0 +1,303 @@
|
|||
/*
|
||||
* 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];
|
||||
}
|
60
tests/fw/services/blob_db/weather_data_shared.h
Normal file
60
tests/fw/services/blob_db/weather_data_shared.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "services/normal/blob_db/weather_db.h"
|
||||
|
||||
#define WEATHER_DATA_SHARED_WEATHER_DB_NUM_DB_ENTRIES (5)
|
||||
#define WEATHER_DATA_SHARED_NUM_VALID_TIMESTAMP_ENTRIES \
|
||||
(WEATHER_DATA_SHARED_WEATHER_DB_NUM_DB_ENTRIES - 1)
|
||||
|
||||
#define TEST_WEATHER_DB_LOCATION_PALO_ALTO "Palo Alto"
|
||||
#define TEST_WEATHER_DB_LOCATION_KITCHENER "Kitchener"
|
||||
#define TEST_WEATHER_DB_LOCATION_WATERLOO "Waterloo"
|
||||
#define TEST_WEATHER_DB_LOCATION_RWC "Redwood City"
|
||||
#define TEST_WEATHER_DB_LOCATION_SF "San Francisco"
|
||||
|
||||
#define TEST_WEATHER_DB_SHORT_PHRASE_SUNNY "Sunny"
|
||||
#define TEST_WEATHER_DB_SHORT_PHRASE_PARTLY_CLOUDY "Partly Cloudy"
|
||||
#define TEST_WEATHER_DB_SHORT_PHRASE_HEAVY_SNOW "Heavy Snow"
|
||||
#define TEST_WEATHER_DB_SHORT_PHRASE_HEAVY_RAIN "Heavy Rain"
|
||||
|
||||
void weather_shared_data_initialize_locations_order(void);
|
||||
|
||||
void weather_shared_data_init(void);
|
||||
|
||||
void weather_shared_data_cleanup(void);
|
||||
|
||||
int weather_shared_data_get_index_of_key(const WeatherDBKey *key);
|
||||
|
||||
const WeatherDBKey *weather_shared_data_get_key(int index);
|
||||
|
||||
WeatherDBEntry *weather_shared_data_get_entry(int index);
|
||||
|
||||
size_t weather_shared_data_get_entry_size(int index);
|
||||
|
||||
char *weather_shared_data_get_entry_name(int index);
|
||||
|
||||
char *weather_shared_data_get_entry_phrase(int index);
|
||||
|
||||
void weather_shared_data_assert_entries_equal(const WeatherDBKey *key, WeatherDBEntry *to_check,
|
||||
WeatherDBEntry *original);
|
||||
|
||||
bool weather_shared_data_get_key_exists(WeatherDBKey *key);
|
||||
|
||||
size_t weather_shared_data_insert_stale_entry(WeatherDBKey *key);
|
||||
|
254
tests/fw/services/blob_db/wscript
Normal file
254
tests/fw/services/blob_db/wscript
Normal file
|
@ -0,0 +1,254 @@
|
|||
from waftools.pebble_test import clar
|
||||
|
||||
|
||||
def build(ctx):
|
||||
|
||||
def test_timeline_service(test_name, defines=None):
|
||||
clar(ctx,
|
||||
test_name=test_name,
|
||||
defines=defines,
|
||||
sources_ant_glob=(
|
||||
"src/fw/services/normal/blob_db/pin_db.c "
|
||||
"src/fw/services/normal/blob_db/sync_util.c "
|
||||
"src/fw/services/normal/blob_db/timeline_item_storage.c "
|
||||
"src/fw/services/normal/timeline/attribute.c "
|
||||
"src/fw/services/normal/timeline/attribute_group.c "
|
||||
"src/fw/services/normal/timeline/attributes_actions.c "
|
||||
"src/fw/services/normal/timeline/item.c "
|
||||
"src/fw/services/normal/timeline/timeline.c "
|
||||
"src/fw/util/crc8.c "
|
||||
"src/fw/util/time/mktime.c "
|
||||
"src/fw/util/time/time.c "
|
||||
"tests/fakes/fake_rtc.c "
|
||||
"tests/fakes/fake_settings_file.c "
|
||||
),
|
||||
test_sources_ant_glob="test_timeline.c",
|
||||
override_includes=['dummy_board'])
|
||||
|
||||
test_timeline_service(test_name='test_timeline')
|
||||
test_timeline_service(test_name='test_timeline~ux4',
|
||||
defines=['CAPABILITY_HAS_CORE_NAVIGATION4=1'])
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob=(
|
||||
"src/fw/services/normal/blob_db/pin_db.c "
|
||||
"src/fw/services/normal/blob_db/sync_util.c "
|
||||
"src/fw/services/normal/blob_db/timeline_item_storage.c "
|
||||
"src/fw/services/normal/blob_db/util.c "
|
||||
"src/fw/services/normal/timeline/attribute.c "
|
||||
"src/fw/services/normal/timeline/attribute_group.c "
|
||||
"src/fw/services/normal/timeline/attributes_actions.c "
|
||||
"src/fw/services/normal/timeline/item.c "
|
||||
"src/fw/util/crc8.c "
|
||||
"src/fw/util/time/mktime.c "
|
||||
"src/fw/util/time/time.c "
|
||||
"tests/fakes/fake_blobdb.c "
|
||||
"tests/fakes/fake_rtc.c "
|
||||
"tests/fakes/fake_session.c "
|
||||
"tests/fakes/fake_settings_file.c "
|
||||
"tests/fakes/ram_storage.c "
|
||||
"tests/fakes/test_db.c "
|
||||
),
|
||||
test_sources_ant_glob="test_pin_db.c")
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = \
|
||||
" src/fw/services/normal/blob_db/util.c" \
|
||||
" src/fw/services/normal/blob_db/sync.c" \
|
||||
" tests/fakes/ram_storage.c" \
|
||||
" tests/fakes/test_db.c" \
|
||||
" tests/fakes/fake_blobdb.c",
|
||||
test_sources_ant_glob = "test_blob_db_sync.c")
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = \
|
||||
" src/fw/services/normal/blob_db/api.c" \
|
||||
" src/fw/services/normal/blob_db/endpoint.c " \
|
||||
" src/fw/services/normal/blob_db/endpoint_private.c " \
|
||||
" src/fw/services/normal/blob_db/util.c" \
|
||||
" tests/fakes/fake_session.c",
|
||||
test_sources_ant_glob = "test_blob_db_endpoint.c")
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = \
|
||||
" src/fw/services/normal/blob_db/api.c" \
|
||||
" src/fw/services/normal/blob_db/endpoint2.c " \
|
||||
" src/fw/services/normal/blob_db/endpoint_private.c " \
|
||||
" src/fw/services/normal/blob_db/util.c",
|
||||
test_sources_ant_glob = "test_blob_db2_endpoint.c")
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = \
|
||||
" src/fw/util/crc8.c" \
|
||||
" src/fw/util/legacy_checksum.c" \
|
||||
" tests/fakes/fake_spi_flash.c" \
|
||||
" src/fw/util/rand/rand.c" \
|
||||
" src/fw/vendor/tinymt32/tinymt32.c" \
|
||||
" tests/fakes/fake_rtc.c" \
|
||||
" src/fw/flash_region/flash_region.c" \
|
||||
" src/fw/flash_region/filesystem_regions.c" \
|
||||
" src/fw/services/normal/settings/settings_file.c" \
|
||||
" src/fw/services/normal/settings/settings_raw_iter.c" \
|
||||
" src/fw/services/normal/filesystem/flash_translation.c" \
|
||||
" src/fw/services/normal/filesystem/pfs.c" \
|
||||
" src/fw/services/normal/blob_db/app_db.c",
|
||||
test_sources_ant_glob = "test_app_db.c",
|
||||
override_includes=['dummy_board'])
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = \
|
||||
" src/fw/services/normal/blob_db/app_glance_db.c" \
|
||||
" src/fw/services/normal/timeline/attribute.c" \
|
||||
" src/fw/util/crc8.c" \
|
||||
" tests/fakes/fake_rtc.c" \
|
||||
" tests/fakes/fake_settings_file.c" \
|
||||
" tests/fakes/fake_events.c" \
|
||||
"",
|
||||
test_sources_ant_glob = "test_app_glance_db.c",
|
||||
override_includes=['dummy_board'])
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = \
|
||||
" src/fw/util/crc8.c" \
|
||||
" src/fw/util/legacy_checksum.c" \
|
||||
" tests/fakes/fake_spi_flash.c" \
|
||||
" src/fw/util/rand/rand.c" \
|
||||
" src/fw/vendor/tinymt32/tinymt32.c" \
|
||||
" tests/fakes/fake_rtc.c" \
|
||||
" src/fw/flash_region/flash_region.c" \
|
||||
" src/fw/flash_region/filesystem_regions.c" \
|
||||
" src/fw/services/normal/settings/settings_file.c" \
|
||||
" src/fw/services/normal/settings/settings_raw_iter.c" \
|
||||
" src/fw/services/normal/filesystem/flash_translation.c" \
|
||||
" src/fw/services/normal/filesystem/pfs.c" \
|
||||
" src/fw/services/normal/blob_db/contacts_db.c",
|
||||
test_sources_ant_glob = "test_contacts_db.c",
|
||||
override_includes=['dummy_board'])
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = \
|
||||
" src/fw/util/crc8.c" \
|
||||
" src/fw/util/legacy_checksum.c" \
|
||||
" tests/fakes/fake_spi_flash.c" \
|
||||
" src/fw/util/rand/rand.c" \
|
||||
" src/fw/vendor/tinymt32/tinymt32.c" \
|
||||
" tests/fakes/fake_rtc.c" \
|
||||
" src/fw/flash_region/flash_region.c" \
|
||||
" src/fw/flash_region/filesystem_regions.c" \
|
||||
" src/fw/services/normal/settings/settings_file.c" \
|
||||
" src/fw/services/normal/settings/settings_raw_iter.c" \
|
||||
" src/fw/services/normal/filesystem/flash_translation.c" \
|
||||
" src/fw/services/normal/filesystem/pfs.c" \
|
||||
" src/fw/services/normal/blob_db/watch_app_prefs_db.c",
|
||||
test_sources_ant_glob = "test_watch_app_prefs_db.c",
|
||||
override_includes=['dummy_board'])
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = \
|
||||
" src/fw/util/crc8.c" \
|
||||
" src/fw/util/rand/rand.c" \
|
||||
" src/fw/vendor/tinymt32/tinymt32.c" \
|
||||
" tests/fakes/fake_rtc.c" \
|
||||
" src/fw/util/time/time.c" \
|
||||
" src/fw/services/normal/blob_db/timeline_item_storage.c" \
|
||||
" tests/fakes/fake_settings_file.c" \
|
||||
" src/fw/services/normal/blob_db/reminder_db.c" \
|
||||
" src/fw/services/normal/blob_db/sync_util.c" \
|
||||
" src/fw/services/normal/timeline/attribute.c" \
|
||||
" src/fw/services/normal/timeline/attributes_actions.c" \
|
||||
" src/fw/services/normal/timeline/attribute_group.c" \
|
||||
" src/fw/services/normal/timeline/item.c",
|
||||
test_sources_ant_glob = "test_reminder_db.c",
|
||||
override_includes=['dummy_board'])
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = \
|
||||
" src/fw/util/crc8.c" \
|
||||
" src/fw/util/legacy_checksum.c" \
|
||||
" tests/fakes/fake_spi_flash.c" \
|
||||
" tests/fakes/fake_kernel_services_notifications.c" \
|
||||
" src/fw/util/rand/rand.c" \
|
||||
" src/fw/vendor/tinymt32/tinymt32.c" \
|
||||
" tests/fakes/fake_rtc.c" \
|
||||
" src/fw/flash_region/filesystem_regions.c" \
|
||||
" src/fw/flash_region/flash_region.c" \
|
||||
" src/fw/util/time/time.c" \
|
||||
" src/fw/services/normal/filesystem/flash_translation.c" \
|
||||
" src/fw/services/normal/filesystem/pfs.c" \
|
||||
" src/fw/services/normal/notifications/notification_storage.c" \
|
||||
" src/fw/services/normal/timeline/attribute.c" \
|
||||
" src/fw/services/normal/timeline/item.c" \
|
||||
" src/fw/services/normal/timeline/attributes_actions.c" \
|
||||
" src/fw/services/normal/timeline/attribute_group.c" \
|
||||
" src/fw/services/normal/blob_db/notif_db.c",
|
||||
test_sources_ant_glob = "test_notif_db.c",
|
||||
override_includes=['dummy_board'])
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = \
|
||||
" src/fw/util/pstring.c" \
|
||||
" src/fw/util/time/time.c" \
|
||||
" src/fw/util/crc8.c" \
|
||||
" src/fw/util/legacy_checksum.c" \
|
||||
" tests/fakes/fake_rtc.c" \
|
||||
" tests/fakes/fake_spi_flash.c" \
|
||||
" src/fw/flash_region/flash_region.c" \
|
||||
" src/fw/flash_region/filesystem_regions.c" \
|
||||
" src/fw/services/normal/settings/settings_file.c" \
|
||||
" src/fw/services/normal/settings/settings_raw_iter.c" \
|
||||
" src/fw/services/normal/filesystem/flash_translation.c" \
|
||||
" src/fw/services/normal/filesystem/pfs.c" \
|
||||
" src/fw/services/normal/blob_db/weather_db.c" \
|
||||
" tests/fw/services/blob_db/weather_data_shared.c",
|
||||
test_sources_ant_glob = "test_weather_db.c",
|
||||
override_includes=['dummy_board'])
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = \
|
||||
" src/fw/util/rand/rand.c" \
|
||||
" src/fw/vendor/tinymt32/tinymt32.c" \
|
||||
" src/fw/util/time/time.c" \
|
||||
" src/fw/flash_region/filesystem_regions.c" \
|
||||
" src/fw/flash_region/flash_region.c" \
|
||||
" src/fw/services/normal/filesystem/flash_translation.c" \
|
||||
" src/fw/services/normal/filesystem/pfs.c" \
|
||||
" src/fw/services/normal/settings/settings_file.c" \
|
||||
" src/fw/services/normal/settings/settings_raw_iter.c" \
|
||||
" src/fw/services/normal/blob_db/prefs_db.c" \
|
||||
" src/fw/shell/normal/prefs.c" \
|
||||
" src/fw/util/crc8.c" \
|
||||
" src/fw/util/legacy_checksum.c" \
|
||||
" tests/fakes/fake_spi_flash.c" \
|
||||
" tests/fakes/fake_rtc.c",
|
||||
test_sources_ant_glob = "test_prefs_db.c",
|
||||
override_includes=['dummy_board'])
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = \
|
||||
" src/fw/util/crc8.c" \
|
||||
" src/libutil/uuid.c" \
|
||||
" src/fw/util/rand/rand.c" \
|
||||
" src/fw/vendor/tinymt32/tinymt32.c" \
|
||||
" tests/fakes/fake_rtc.c" \
|
||||
" tests/fakes/fake_settings_file.c" \
|
||||
" src/fw/util/time/time.c" \
|
||||
" src/fw/services/normal/timeline/attribute.c" \
|
||||
" src/fw/services/normal/timeline/item.c" \
|
||||
" src/fw/services/normal/timeline/attributes_actions.c" \
|
||||
" src/fw/services/normal/timeline/attribute_group.c"
|
||||
" src/fw/services/normal/blob_db/sync_util.c" \
|
||||
" src/fw/services/normal/blob_db/ios_notif_pref_db.c" ,
|
||||
test_sources_ant_glob = "test_ios_notif_pref_db.c",
|
||||
override_includes=['dummy_board'])
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = \
|
||||
" src/fw/util/crc8.c" \
|
||||
" src/fw/util/time/time.c" \
|
||||
" tests/fakes/fake_settings_file.c" \
|
||||
" src/fw/services/normal/blob_db/health_db.c" ,
|
||||
test_sources_ant_glob = "test_health_db.c",
|
||||
override_includes=['dummy_board'])
|
||||
|
||||
|
||||
# vim:filetype=python
|
Loading…
Add table
Add a link
Reference in a new issue