From 7b5090ec4b0b9c51dff180370798d78fb6fa9277 Mon Sep 17 00:00:00 2001 From: Euripedes Rocha Filho Date: Mon, 21 Sep 2026 15:56:43 +0200 Subject: [PATCH] ci: Introduce property ownership test --- test/host/main/mqtt5_client_test_adapter.c | 28 ++++++++ test/host/main/test_mqtt5_client.cpp | 84 ++++++++++++++++++++++ 2 files changed, 112 insertions(+) diff --git a/test/host/main/mqtt5_client_test_adapter.c b/test/host/main/mqtt5_client_test_adapter.c index 3bf1452..1d46349 100644 --- a/test/host/main/mqtt5_client_test_adapter.c +++ b/test/host/main/mqtt5_client_test_adapter.c @@ -4,9 +4,37 @@ * SPDX-License-Identifier: Apache-2.0 */ #include +#include #include "mqtt_client_priv.h" +static struct esp_mqtt_client s_client; +static mqtt5_config_storage_t s_mqtt5_config; + +esp_mqtt_client_handle_t test_mqtt5_property_client_reset(void) +{ + memset(&s_client, 0, sizeof(s_client)); + memset(&s_mqtt5_config, 0, sizeof(s_mqtt5_config)); + s_client.mqtt5_config = &s_mqtt5_config; + s_client.mqtt_state.connection.information.protocol_ver = MQTT_PROTOCOL_V_5; + return &s_client; +} + +mqtt5_staged_property_t *test_mqtt5_publish_property_slot(void) +{ + return &s_mqtt5_config.publish_property; +} + +mqtt5_staged_property_t *test_mqtt5_subscribe_property_slot(void) +{ + return &s_mqtt5_config.subscribe_property; +} + +mqtt5_staged_property_t *test_mqtt5_unsubscribe_property_slot(void) +{ + return &s_mqtt5_config.unsubscribe_property; +} + esp_err_t test_mqtt5_check_inflight_maximum(uint16_t send_count, uint16_t receive_maximum) { struct esp_mqtt_client client = {0}; diff --git a/test/host/main/test_mqtt5_client.cpp b/test/host/main/test_mqtt5_client.cpp index 99d0a60..52ed1fc 100644 --- a/test/host/main/test_mqtt5_client.cpp +++ b/test/host/main/test_mqtt5_client.cpp @@ -11,6 +11,10 @@ #include "mqtt5_client.h" extern "C" { +#include "Mockqueue.h" +#include "Mocktask.h" +#include "mqtt5_client_priv.h" + esp_err_t test_mqtt5_check_inflight_maximum(uint16_t send_count, uint16_t receive_maximum); int test_mqtt5_increment_packet_counter_with_dup(void); esp_err_t test_mqtt5_set_connect_null_property(void); @@ -18,6 +22,22 @@ extern "C" { esp_err_t test_mqtt5_set_subscribe_null_property(void); esp_err_t test_mqtt5_set_unsubscribe_null_property(void); esp_err_t test_mqtt5_set_disconnect_null_property(void); + esp_mqtt_client_handle_t test_mqtt5_property_client_reset(void); + mqtt5_staged_property_t *test_mqtt5_publish_property_slot(void); + mqtt5_staged_property_t *test_mqtt5_subscribe_property_slot(void); + mqtt5_staged_property_t *test_mqtt5_unsubscribe_property_slot(void); +} + +static void use_task(TaskHandle_t task) +{ + xTaskGetCurrentTaskHandle_IgnoreAndReturn(task); +} + +static esp_mqtt_client_handle_t prepare_property_client() +{ + xQueueTakeMutexRecursive_IgnoreAndReturn(pdTRUE); + xQueueGiveMutexRecursive_IgnoreAndReturn(pdTRUE); + return test_mqtt5_property_client_reset(); } TEST_CASE("MQTT5 inflight quota uses an exact upper bound") @@ -53,3 +73,67 @@ TEST_CASE("MQTT5 property setters reject a null client") REQUIRE(esp_mqtt5_client_set_unsubscribe_property(nullptr, &unsubscribe) == ESP_ERR_INVALID_ARG); REQUIRE(esp_mqtt5_client_set_disconnect_property(nullptr, &disconnect) == ESP_ERR_INVALID_ARG); } + +TEST_CASE("MQTT5 staged property enforces task ownership") +{ + int task_a_storage; + int task_b_storage; + int property_a = 1; + int property_b = 2; + int replacement = 3; + TaskHandle_t task_a = reinterpret_cast(&task_a_storage); + TaskHandle_t task_b = reinterpret_cast(&task_b_storage); + mqtt5_staged_property_t slot = {}; + use_task(task_a); + REQUIRE(esp_mqtt5_staged_property_set(&slot, &property_a) == ESP_OK); + REQUIRE(esp_mqtt5_staged_property_get(&slot) == &property_a); + use_task(task_b); + REQUIRE(esp_mqtt5_staged_property_get(&slot) == nullptr); + esp_mqtt5_staged_property_clear(&slot); + REQUIRE(slot.property == &property_a); + REQUIRE(slot.owner == task_a); + REQUIRE(esp_mqtt5_staged_property_set(&slot, &property_b) == ESP_ERR_INVALID_STATE); + REQUIRE(slot.property == &property_a); + REQUIRE(slot.owner == task_a); + use_task(task_a); + REQUIRE(esp_mqtt5_staged_property_set(&slot, &replacement) == ESP_OK); + REQUIRE(esp_mqtt5_staged_property_get(&slot) == &replacement); + esp_mqtt5_staged_property_clear(&slot); + REQUIRE(slot.property == nullptr); + REQUIRE(slot.owner == nullptr); + use_task(task_b); + REQUIRE(esp_mqtt5_staged_property_set(&slot, &property_b) == ESP_OK); + REQUIRE(esp_mqtt5_staged_property_get(&slot) == &property_b); +} + +TEST_CASE("MQTT5 property setters use task-owned slots") +{ + int task_a_storage; + int task_b_storage; + TaskHandle_t task_a = reinterpret_cast(&task_a_storage); + TaskHandle_t task_b = reinterpret_cast(&task_b_storage); + esp_mqtt5_publish_property_config_t publish_a = {}; + esp_mqtt5_publish_property_config_t publish_b = {}; + esp_mqtt5_subscribe_property_config_t subscribe_a = {}; + esp_mqtt5_subscribe_property_config_t subscribe_b = {}; + esp_mqtt5_unsubscribe_property_config_t unsubscribe_a = {}; + esp_mqtt5_unsubscribe_property_config_t unsubscribe_b = {}; + esp_mqtt_client_handle_t client = prepare_property_client(); + use_task(task_a); + REQUIRE(esp_mqtt5_client_set_publish_property(client, &publish_a) == ESP_OK); + REQUIRE(esp_mqtt5_client_set_subscribe_property(client, &subscribe_a) == ESP_OK); + REQUIRE(esp_mqtt5_client_set_unsubscribe_property(client, &unsubscribe_a) == ESP_OK); + REQUIRE(test_mqtt5_publish_property_slot()->property == &publish_a); + REQUIRE(test_mqtt5_subscribe_property_slot()->property == &subscribe_a); + REQUIRE(test_mqtt5_unsubscribe_property_slot()->property == &unsubscribe_a); + REQUIRE(test_mqtt5_publish_property_slot()->owner == task_a); + REQUIRE(test_mqtt5_subscribe_property_slot()->owner == task_a); + REQUIRE(test_mqtt5_unsubscribe_property_slot()->owner == task_a); + use_task(task_b); + REQUIRE(esp_mqtt5_client_set_publish_property(client, &publish_b) == ESP_ERR_INVALID_STATE); + REQUIRE(esp_mqtt5_client_set_subscribe_property(client, &subscribe_b) == ESP_ERR_INVALID_STATE); + REQUIRE(esp_mqtt5_client_set_unsubscribe_property(client, &unsubscribe_b) == ESP_ERR_INVALID_STATE); + REQUIRE(test_mqtt5_publish_property_slot()->property == &publish_a); + REQUIRE(test_mqtt5_subscribe_property_slot()->property == &subscribe_a); + REQUIRE(test_mqtt5_unsubscribe_property_slot()->property == &unsubscribe_a); +}