diff --git a/components/esp_event/test_apps/main/test_event.c b/components/esp_event/test_apps/main/test_event.c index 3caef2a921..7e6b58ac10 100644 --- a/components/esp_event/test_apps/main/test_event.c +++ b/components/esp_event/test_apps/main/test_event.c @@ -31,6 +31,7 @@ static const char* TAG = "test_event"; #define TEST_CONFIG_ITEMS_TO_REGISTER 5 #define TEST_CONFIG_TASKS_TO_SPAWN 2 +_Static_assert(TEST_CONFIG_TASKS_TO_SPAWN >= 2); // some tests test simultaneous posting of events, etc. /* General wait time for tests, e.g. waiting for background task to finish, expected timeout, etc. */ @@ -44,12 +45,10 @@ static const char* TAG = "test_event"; #define TEST_SETUP() \ ESP_LOGI(TAG, "initializing test"); \ size_t free_mem_before = heap_caps_get_free_size(MALLOC_CAP_DEFAULT); \ - test_setup(); \ s_test_core_id = xPortGetCoreID(); \ s_test_priority = uxTaskPriorityGet(NULL); #define TEST_TEARDOWN() \ - test_teardown(); \ vTaskDelay(pdMS_TO_TICKS(TEST_CONFIG_TEARDOWN_WAIT)); \ TEST_ASSERT_EQUAL(free_mem_before, heap_caps_get_free_size(MALLOC_CAP_DEFAULT)); @@ -101,9 +100,11 @@ static UBaseType_t s_test_priority; ESP_EVENT_DECLARE_BASE(s_test_base1); ESP_EVENT_DECLARE_BASE(s_test_base2); +ESP_EVENT_DECLARE_BASE(s_semphr_base); ESP_EVENT_DEFINE_BASE(s_test_base1); ESP_EVENT_DEFINE_BASE(s_test_base2); +ESP_EVENT_DEFINE_BASE(s_semphr_base); enum { TEST_EVENT_BASE1_EV1, @@ -144,6 +145,13 @@ static esp_event_loop_args_t test_event_get_default_loop_args(void) return loop_config; } +static void pass_4byte_event(void* event_handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data) +{ + uint32_t* target = (uint32_t*) event_handler_arg; + uint32_t data = *((uint32_t*) event_data); + *target = data; +} + static void test_event_simple_handler(void* event_handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { if (!event_handler_arg) { @@ -163,6 +171,12 @@ static void test_event_simple_handler(void* event_handler_arg, esp_event_base_t xSemaphoreGive(arg->mutex); } +static void post_sem(void* event_handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data) +{ + SemaphoreHandle_t *sem = (SemaphoreHandle_t*) event_handler_arg; + xSemaphoreGive(*sem); +} + static void test_event_ordered_dispatch(void* event_handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { int *arg = (int*) event_handler_arg; @@ -304,17 +318,6 @@ static void test_post_from_handler_loop_task(void* args) } } -static void test_setup(void) -{ - TEST_ASSERT_TRUE(TEST_CONFIG_TASKS_TO_SPAWN >= 2); - TEST_ESP_OK(esp_event_loop_create_default()); -} - -static void test_teardown(void) -{ - TEST_ESP_OK(esp_event_loop_delete_default()); -} - TEST_CASE("can create and delete event loops", "[event]") { /* this test aims to verify that: @@ -815,6 +818,9 @@ TEST_CASE("can register/unregister handlers for all events/all events for a spec loop_args.task_name = NULL; TEST_ESP_OK(esp_event_loop_create(&loop_args, &loop)); + SemaphoreHandle_t sem = xSemaphoreCreateBinary(); + TEST_ASSERT(sem); + /* Register the handler twice to the same base and id but with a different argument (expects to return ESP_OK and log a warning) * This aims to verify: 1) Handler's argument to be updated * 2) Registration not to leak memory @@ -828,6 +834,9 @@ TEST_CASE("can register/unregister handlers for all events/all events for a spec TEST_ESP_OK(esp_event_handler_register_with(loop, s_test_base1, TEST_EVENT_BASE1_EV2, test_event_simple_handler, &arg)); TEST_ESP_OK(esp_event_handler_register_with(loop, s_test_base2, TEST_EVENT_BASE1_EV1, test_event_simple_handler, &arg)); + // Will only be called after all the main tests have finished + TEST_ESP_OK(esp_event_handler_register_with(loop, s_semphr_base, TEST_EVENT_BASE1_EV3, post_sem, &sem)); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_event_post_to(loop, ESP_EVENT_ANY_BASE, ESP_EVENT_ANY_ID, NULL, 0, portMAX_DELAY)); TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_event_post_to(loop, s_test_base1, ESP_EVENT_ANY_ID, NULL, 0, portMAX_DELAY)); TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_event_post_to(loop, ESP_EVENT_ANY_BASE, TEST_EVENT_BASE1_EV1, NULL, 0, portMAX_DELAY)); @@ -837,14 +846,18 @@ TEST_CASE("can register/unregister handlers for all events/all events for a spec // Post unknown events. Respective loop level and base level handlers should still execute. TEST_ESP_OK(esp_event_post_to(loop, s_test_base1, TEST_EVENT_BASE1_MAX, NULL, 0, portMAX_DELAY)); // exec loop and base level (+2) TEST_ESP_OK(esp_event_post_to(loop, s_test_base2, TEST_EVENT_BASE2_MAX, NULL, 0, portMAX_DELAY)); // exec loop level (+1) + TEST_ESP_OK(esp_event_post_to(loop, s_semphr_base, TEST_EVENT_BASE1_EV3, NULL, 0, portMAX_DELAY)); - TEST_ESP_OK(esp_event_loop_run(loop, pdMS_TO_TICKS(10))); + while (xSemaphoreTake(sem, 0) != pdTRUE) { + TEST_ESP_OK(esp_event_loop_run(loop, pdMS_TO_TICKS(10))); + } - TEST_ASSERT_EQUAL(9, count); // 3 + 3 + 2 + 1 + TEST_ASSERT_EQUAL(10, count); // 3 + 3 + 2 + 1 + 1 TEST_ESP_OK(esp_event_loop_delete(loop)); vSemaphoreDelete(arg.mutex); + vSemaphoreDelete(sem); TEST_TEARDOWN(); } @@ -861,36 +874,51 @@ TEST_CASE("can unregister handler", "[event]") loop_args.task_name = NULL; TEST_ESP_OK(esp_event_loop_create(&loop_args, &loop)); - int count = 0; + SemaphoreHandle_t sem = xSemaphoreCreateBinary(); + TEST_ASSERT(sem); - simple_arg_t arg = { - .data = &count, - .mutex = xSemaphoreCreateMutex() - }; + uint32_t handler_0_record; + uint32_t handler_1_record; - TEST_ESP_OK(esp_event_handler_register_with(loop, s_test_base1, TEST_EVENT_BASE1_EV1, test_event_simple_handler, &arg)); - TEST_ESP_OK(esp_event_handler_register_with(loop, s_test_base2, TEST_EVENT_BASE1_EV1, test_event_simple_handler, &arg)); + uint32_t a = 0xA; + uint32_t b = 0xB; + uint32_t c = 0xC; + uint32_t d = 0xD; - TEST_ESP_OK(esp_event_post_to(loop, s_test_base1, TEST_EVENT_BASE1_EV1, NULL, 0, portMAX_DELAY)); - TEST_ESP_OK(esp_event_post_to(loop, s_test_base2, TEST_EVENT_BASE1_EV1, NULL, 0, portMAX_DELAY)); + TEST_ESP_OK(esp_event_handler_register_with(loop, s_test_base1, TEST_EVENT_BASE1_EV1, pass_4byte_event, &handler_0_record)); + TEST_ESP_OK(esp_event_handler_register_with(loop, s_test_base2, TEST_EVENT_BASE1_EV1, pass_4byte_event, &handler_1_record)); - TEST_ESP_OK(esp_event_loop_run(loop, pdMS_TO_TICKS(10))); + // Will only be called after all the main tests have finished + TEST_ESP_OK(esp_event_handler_register_with(loop, s_semphr_base, TEST_EVENT_BASE1_EV3, post_sem, &sem)); - TEST_ASSERT_EQUAL(2, count); + TEST_ESP_OK(esp_event_post_to(loop, s_test_base1, TEST_EVENT_BASE1_EV1, &a, sizeof(uint32_t), portMAX_DELAY)); + TEST_ESP_OK(esp_event_post_to(loop, s_test_base2, TEST_EVENT_BASE1_EV1, &b, sizeof(uint32_t), portMAX_DELAY)); + TEST_ESP_OK(esp_event_post_to(loop, s_semphr_base, TEST_EVENT_BASE1_EV3, &b, sizeof(uint32_t), portMAX_DELAY)); - TEST_ESP_OK(esp_event_handler_unregister_with(loop, s_test_base1, TEST_EVENT_BASE1_EV1, test_event_simple_handler)); + while (xSemaphoreTake(sem, 0) != pdTRUE) { + TEST_ESP_OK(esp_event_loop_run(loop, pdMS_TO_TICKS(10))); + } - TEST_ESP_OK(esp_event_post_to(loop, s_test_base1, TEST_EVENT_BASE1_EV1, NULL, 0, portMAX_DELAY)); - TEST_ESP_OK(esp_event_post_to(loop, s_test_base2, TEST_EVENT_BASE1_EV1, NULL, 0, portMAX_DELAY)); + TEST_ASSERT_EQUAL(0xA, handler_0_record); + TEST_ASSERT_EQUAL(0xB, handler_1_record); - TEST_ESP_OK(esp_event_loop_run(loop, pdMS_TO_TICKS(10))); + TEST_ESP_OK(esp_event_handler_unregister_with(loop, s_test_base1, TEST_EVENT_BASE1_EV1, pass_4byte_event)); - TEST_ASSERT_EQUAL(3, count); + TEST_ESP_OK(esp_event_post_to(loop, s_test_base1, TEST_EVENT_BASE1_EV1, &c, sizeof(uint32_t), portMAX_DELAY)); + TEST_ESP_OK(esp_event_post_to(loop, s_test_base2, TEST_EVENT_BASE1_EV1, &d, sizeof(uint32_t), portMAX_DELAY)); + TEST_ESP_OK(esp_event_post_to(loop, s_semphr_base, TEST_EVENT_BASE1_EV3, &b, sizeof(uint32_t), portMAX_DELAY)); + while (xSemaphoreTake(sem, 0) != pdTRUE) { + TEST_ESP_OK(esp_event_loop_run(loop, pdMS_TO_TICKS(10))); + } + + + TEST_ASSERT_EQUAL(0xA, handler_0_record); + TEST_ASSERT_EQUAL(0xD, handler_1_record); + + vSemaphoreDelete(sem); TEST_ESP_OK(esp_event_loop_delete(loop)); - vSemaphoreDelete(arg.mutex); - TEST_TEARDOWN(); } @@ -1029,7 +1057,8 @@ TEST_CASE("handler instance can unregister itself", "[event]") TEST_TEARDOWN(); } -TEST_CASE("can exit running loop at approximately the set amount of time", "[event]") +// Ignore this test on QEMU for now since it relies on esp_timer which is based on the host run time on ESP32-QEMU +TEST_CASE("can exit running loop at approximately the set amount of time", "[event][qemu-ignore]") { /* this test aims to verify that running loop does not block indefinitely in cases where * events are posted frequently */ @@ -1082,7 +1111,7 @@ TEST_CASE("can exit running loop at approximately the set amount of time", "[eve diff = (esp_timer_get_time() - start); // Threshold is 25 percent. - TEST_ASSERT(diff < runtime_us * 1.25f); + TEST_ASSERT_LESS_THAN_INT(runtime_us * 1.25f, diff); // Verify that the post task still continues TEST_ASSERT_NOT_EQUAL(pdTRUE, xSemaphoreTake(post_event_arg.done, pdMS_TO_TICKS(10))); @@ -1921,6 +1950,9 @@ TEST_CASE("events are dispatched in the order they are registered", "[event]") int data_arr[12] = {0}; + SemaphoreHandle_t sem = xSemaphoreCreateBinary(); + TEST_ASSERT(sem); + TEST_ESP_OK(esp_event_handler_register_with(loop, s_test_base2, TEST_EVENT_BASE2_EV1, test_event_ordered_dispatch, id_arr + 0)); TEST_ESP_OK(esp_event_handler_register_with(loop, ESP_EVENT_ANY_BASE, ESP_EVENT_ANY_ID, test_event_ordered_dispatch, id_arr + 1)); TEST_ESP_OK(esp_event_handler_register_with(loop, s_test_base1, ESP_EVENT_ANY_ID, test_event_ordered_dispatch, id_arr + 2)); @@ -1929,6 +1961,9 @@ TEST_CASE("events are dispatched in the order they are registered", "[event]") TEST_ESP_OK(esp_event_handler_register_with(loop, s_test_base2, ESP_EVENT_ANY_ID, test_event_ordered_dispatch, id_arr + 5)); TEST_ESP_OK(esp_event_handler_register_with(loop, s_test_base1, TEST_EVENT_BASE1_EV2, test_event_ordered_dispatch, id_arr + 6)); + // Will only be called after all the main tests have finished + TEST_ESP_OK(esp_event_handler_register_with(loop, s_semphr_base, TEST_EVENT_BASE1_EV3, post_sem, &sem)); + esp_event_dump(stdout); ordered_data_t data = { @@ -1943,15 +1978,20 @@ TEST_CASE("events are dispatched in the order they are registered", "[event]") TEST_ESP_OK(esp_event_post_to(loop, s_test_base1, TEST_EVENT_BASE1_EV2, &dptr, sizeof(dptr), portMAX_DELAY)); TEST_ESP_OK(esp_event_post_to(loop, s_test_base2, TEST_EVENT_BASE1_EV1, &dptr, sizeof(dptr), portMAX_DELAY)); - TEST_ESP_OK(esp_event_loop_run(loop, pdMS_TO_TICKS(10))); + // This is just to signal that all test handlers have run + TEST_ESP_OK(esp_event_post_to(loop, s_semphr_base, TEST_EVENT_BASE1_EV3, &dptr, sizeof(dptr), portMAX_DELAY)); - // Expected data executing the posts above - int ref_arr[12] = {1, 3, 5, 1, 2, 4, 1, 2, 6, 0, 1, 5}; - - for (int i = 0; i < 12; i++) { - TEST_ASSERT_EQUAL(ref_arr[i], data_arr[i]); + while (xSemaphoreTake(sem, 0) != pdTRUE) { + TEST_ESP_OK(esp_event_loop_run(loop, pdMS_TO_TICKS(10))); } + // Expected data executing the posts above + int ref_arr[13] = {1, 3, 5, 1, 2, 4, 1, 2, 6, 0, 1, 5, 0}; // the last element is not checked anymore because + // we send one event to post the semaphore + + TEST_ASSERT_EQUAL_INT_ARRAY(ref_arr, data_arr, 12); + + vSemaphoreDelete(sem); TEST_ESP_OK(esp_event_loop_delete(loop)); TEST_TEARDOWN(); @@ -2013,6 +2053,8 @@ bool test_event_on_timer_alarm(gptimer_handle_t timer, const gptimer_alarm_event TEST_CASE("can post events from interrupt handler", "[event]") { + TEST_ESP_OK(esp_event_loop_create_default()); + /* Lazy allocated resources in gptimer/intr_alloc */ set_leak_threshold(-150); @@ -2038,17 +2080,18 @@ TEST_CASE("can post events from interrupt handler", "[event]") TEST_ESP_OK(gptimer_enable(gptimer)); TEST_ESP_OK(gptimer_start(gptimer)); - TEST_SETUP(); - TEST_ESP_OK(esp_event_handler_register(s_test_base1, TEST_EVENT_BASE1_EV1, test_handler_post_from_isr, &sem)); xSemaphoreTake(sem, portMAX_DELAY); - TEST_TEARDOWN(); + vTaskDelay(pdMS_TO_TICKS(TEST_CONFIG_TEARDOWN_WAIT)); + vSemaphoreDelete(sem); TEST_ESP_OK(gptimer_disable(gptimer)); TEST_ESP_OK(gptimer_del_timer(gptimer)); + + TEST_ESP_OK(esp_event_loop_delete_default()); } #endif // CONFIG_ESP_EVENT_POST_FROM_ISR diff --git a/components/esp_event/test_apps/pytest_esp_event.py b/components/esp_event/test_apps/pytest_esp_event.py index d511dbf39e..7d17321c10 100644 --- a/components/esp_event/test_apps/pytest_esp_event.py +++ b/components/esp_event/test_apps/pytest_esp_event.py @@ -14,10 +14,24 @@ def test_esp_event(dut: Dut) -> None: @pytest.mark.esp32 -@pytest.mark.esp32c3 @pytest.mark.host_test @pytest.mark.qemu -def test_esp_event_qemu(dut: Dut) -> None: +@pytest.mark.parametrize('qemu_extra_args', [ + '-global driver=timer.esp32.timg,property=wdt_disable,value=true', +], indirect=True) # need to disable wdt since it is not synchronized with target cpu clock on QEMU for ESP32 +def test_esp_event_qemu_esp32(dut: Dut) -> None: + for case in dut.test_menu: + if 'qemu-ignore' not in case.groups and not case.is_ignored and case.type == 'normal': + dut._run_normal_case(case) + + +@pytest.mark.esp32c3 +@pytest.mark.host_test +@pytest.mark.qemu +@pytest.mark.parametrize('qemu_extra_args', [ + '-icount 3', +], indirect=True) # need to add -icount 3 to make WDT accurate on QEMU for ESP32-C3 +def test_esp_event_qemu_esp32c3(dut: Dut) -> None: for case in dut.test_menu: if 'qemu-ignore' not in case.groups and not case.is_ignored and case.type == 'normal': dut._run_normal_case(case)