/* * 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/rockyjs/rocky_res.h" #include "process_management/process_manager.h" #include "process_management/app_install_manager.h" #include "process_management/pebble_process_info.h" #include "util/size.h" // Stubs #include "stubs_accel_service.h" #include "stubs_analytics.h" #include "stubs_analytics_external.h" #include "stubs_animation_service.h" #include "stubs_app_cache.h" #include "stubs_app_manager.h" #include "stubs_app_state.h" #include "stubs_dls.h" #include "stubs_evented_timer.h" #include "stubs_expandable_dialog.h" #include "stubs_freertos.h" #include "stubs_heap.h" #include "stubs_i18n.h" #include "stubs_logging.h" #include "stubs_modal_manager.h" #include "stubs_new_timer.h" #include "stubs_passert.h" #include "stubs_pbl_malloc.h" #include "stubs_pebble_process_md.h" #include "stubs_pebble_tasks.h" #include "stubs_persist.h" #include "stubs_queue.h" #include "stubs_resources.h" #include "stubs_syscalls.h" #include "stubs_task.h" #include "stubs_tick.h" #include "stubs_watchface.h" #include "stubs_worker_manager.h" #include "stubs_worker_state.h" char __APP_RAM__[1024*128]; char *__APP_RAM_end__ = &__APP_RAM__[1024*128]; char __WORKER_RAM__[1024*12]; char *__WORKER_RAM_end__ = &__APP_RAM__[1024*12]; typedef struct { AppInstallEntry entry; bool should_pass; } AppInstallEntryTestCase; static AppInstallEntryTestCase s_test_cases[] = { { .entry = (AppInstallEntry) { .install_id = 1, .sdk_version = (Version) { .major = PROCESS_INFO_CURRENT_SDK_VERSION_MAJOR, .minor = PROCESS_INFO_CURRENT_SDK_VERSION_MINOR } }, .should_pass = true }, { .entry = (AppInstallEntry) { .install_id = 2, .sdk_version = (Version) { .major = PROCESS_INFO_CURRENT_SDK_VERSION_MAJOR - 1, .minor = PROCESS_INFO_CURRENT_SDK_VERSION_MINOR } }, .should_pass = false }, { .entry = (AppInstallEntry) { .install_id = 3, .sdk_version = (Version) { .major = PROCESS_INFO_CURRENT_SDK_VERSION_MAJOR + 1, .minor = PROCESS_INFO_CURRENT_SDK_VERSION_MINOR } }, .should_pass = false }, { .entry = (AppInstallEntry) { .install_id = 4, .sdk_version = (Version) { .major = PROCESS_INFO_CURRENT_SDK_VERSION_MAJOR, .minor = PROCESS_INFO_CURRENT_SDK_VERSION_MINOR - 10 } }, .should_pass = true }, { .entry = (AppInstallEntry) { .install_id = 5, .sdk_version = (Version) { .major = PROCESS_INFO_CURRENT_SDK_VERSION_MAJOR, .minor = PROCESS_INFO_CURRENT_SDK_VERSION_MINOR + 10 } }, .should_pass = false }, { .entry = (AppInstallEntry) { .install_id = 6, .sdk_version = (Version) { .major = PROCESS_INFO_CURRENT_SDK_VERSION_MAJOR + 1, .minor = PROCESS_INFO_CURRENT_SDK_VERSION_MINOR + 10 } }, .should_pass = false }, { .entry = (AppInstallEntry) { .install_id = 7, .sdk_version = (Version) { .major = PROCESS_INFO_CURRENT_SDK_VERSION_MAJOR - 1, .minor = PROCESS_INFO_CURRENT_SDK_VERSION_MINOR - 10 } }, .should_pass = false } }; PlatformType process_metadata_get_app_sdk_platform(const PebbleProcessMd *md) { cl_fail("should not be called"); return (PlatformType)-1; } UBaseType_t uxQueueMessagesWaiting(const QueueHandle_t xQueue) { return 0; } BaseType_t event_queue_cleanup_and_reset(QueueHandle_t queue) { return pdPASS; } void event_service_clear_process_subscriptions(void) { } bool app_install_entry_is_watchface(const AppInstallEntry *entry) { return false; } AppInstallId app_install_get_id_for_uuid(const Uuid *uuid) { return 1; } bool app_install_get_entry_for_install_id(AppInstallId install_id, AppInstallEntry *entry) { *entry = s_test_cases[install_id - 1].entry; return true; } bool app_install_id_from_app_db(AppInstallId id) { return (id > INSTALL_ID_INVALID); } bool app_install_entry_is_SDK_compatible(const AppInstallEntry *entry) { return (entry->sdk_version.major == PROCESS_INFO_CURRENT_SDK_VERSION_MAJOR && entry->sdk_version.minor <= PROCESS_INFO_CURRENT_SDK_VERSION_MINOR); } static PebbleProcessMd *s_app_install_get_md__result; const PebbleProcessMd *app_install_get_md(AppInstallId id, bool worker) { return s_app_install_get_md__result; } void app_install_release_md(const PebbleProcessMd *md) { } static int s_process_metadata_get_res_bank_num__result; int process_metadata_get_res_bank_num(const PebbleProcessMd *md) { return s_process_metadata_get_res_bank_num__result; } static RockyResourceValidation s_rocky_app_validate_resources__result; RockyResourceValidation rocky_app_validate_resources(const PebbleProcessMd *md) { return s_rocky_app_validate_resources__result; } static PebbleEvent* s_event_put__event; void event_put(PebbleEvent* event) { s_event_put__event = event; cl_assert(event != NULL); } void event_put_from_app(PebbleEvent* event) { cl_fail("unexpected"); } void event_put_from_process(PebbleTask task, PebbleEvent* event) { cl_fail("unexpected"); } void event_reset_from_process_queue(PebbleTask task) { cl_fail("unexpected"); } void test_process_manager__initialize(void) { s_app_install_get_md__result = NULL; s_process_metadata_get_res_bank_num__result = 123; s_rocky_app_validate_resources__result = RockyResourceValidation_NotRocky; s_app_manager_launch_new_app__callcount = 0; s_app_manager_launch_new_app__config = (__typeof__(s_app_manager_launch_new_app__config)){}; s_event_put__event = NULL; } void test_process_manager__check_SDK_compatible(void) { for (uint32_t i = 0; i < ARRAY_LENGTH(s_test_cases); i++) { // skipping 0, since it's INSTALL_ID_INVALID cl_assert_equal_b(process_manager_check_SDK_compatible(i + 1), s_test_cases[i].should_pass); } } void test_process_manager__launch_valid_rocky_app(void) { s_app_install_get_md__result = &(PebbleProcessMd){.is_rocky_app = true}; s_rocky_app_validate_resources__result = RockyResourceValidation_Valid; process_manager_launch_process(&(ProcessLaunchConfig){.id=1}); // app was launched, no events (especially no fetch event) on the queue cl_assert_equal_b(1, s_app_manager_launch_new_app__callcount); cl_assert_equal_p(s_app_install_get_md__result, s_app_manager_launch_new_app__config.md); cl_assert(s_event_put__event == NULL); } void test_process_manager__launch_invalid_rocky_app(void) { s_app_install_get_md__result = &(PebbleProcessMd){.is_rocky_app = true}; s_rocky_app_validate_resources__result = RockyResourceValidation_Invalid; process_manager_launch_process(&(ProcessLaunchConfig){.id=1}); // app wasn't launched, instead we see a fetch request cl_assert_equal_b(0, s_app_manager_launch_new_app__callcount); cl_assert(s_event_put__event != NULL); cl_assert_equal_i(PEBBLE_APP_FETCH_REQUEST_EVENT, s_event_put__event->type); }