From 0660ece128466a89aa75a5fc96b00789c0a8a244 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Mon, 22 Jul 2024 19:02:46 +0200 Subject: [PATCH 1/2] feat(mdns): Unit tests for add/remove/update deleg/selfhosted services --- .../mdns/tests/unit_test/main/test_mdns.c | 144 +++++++++++++++++- 1 file changed, 143 insertions(+), 1 deletion(-) diff --git a/components/mdns/tests/unit_test/main/test_mdns.c b/components/mdns/tests/unit_test/main/test_mdns.c index 3ac613c3b1..83e6f1b295 100644 --- a/components/mdns/tests/unit_test/main/test_mdns.c +++ b/components/mdns/tests/unit_test/main/test_mdns.c @@ -1,9 +1,10 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ +#include #include "mdns.h" #include "esp_event.h" #include "unity.h" @@ -142,12 +143,153 @@ TEST(mdns, query_api_fails_with_expected_err) esp_event_loop_delete_default(); } +TEST(mdns, add_remove_service) +{ + mdns_result_t *results = NULL; + test_case_uses_tcpip(); + TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_create_default()); + TEST_ASSERT_EQUAL(ESP_OK, mdns_init() ); + TEST_ASSERT_EQUAL(ESP_OK, mdns_hostname_set(MDNS_HOSTNAME)); + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_add(MDNS_INSTANCE, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_SERVICE_PORT, NULL, 0)); + yield_to_all_priorities(); // Make sure that mdns task has executed to add the hostname + TEST_ASSERT_EQUAL(ESP_OK, mdns_lookup_selfhosted_service(NULL, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, 1, &results)); + TEST_ASSERT_NOT_EQUAL(NULL, results); + TEST_ASSERT_EQUAL_STRING(MDNS_INSTANCE, results->instance_name); + TEST_ASSERT_EQUAL_STRING(MDNS_SERVICE_NAME, results->service_type); + TEST_ASSERT_EQUAL(MDNS_SERVICE_PORT, results->port); + TEST_ASSERT_EQUAL(NULL, results->txt); + mdns_query_results_free(results); + + // Update service properties: port + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_port_set(MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_SERVICE_PORT + 1)); + yield_to_all_priorities(); // Make sure that mdns task has executed to add the hostname + TEST_ASSERT_EQUAL(ESP_OK, mdns_lookup_selfhosted_service(NULL, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, 1, &results)); + TEST_ASSERT_NOT_EQUAL(NULL, results); + TEST_ASSERT_EQUAL(MDNS_SERVICE_PORT + 1, results->port); + mdns_query_results_free(results); + + // Update service properties: instance + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_instance_name_set(MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_INSTANCE "1" )); + yield_to_all_priorities(); // Make sure that mdns task has executed to add the hostname + TEST_ASSERT_EQUAL(ESP_OK, mdns_lookup_selfhosted_service(MDNS_INSTANCE "1", MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, 1, &results)); + TEST_ASSERT_NOT_EQUAL(NULL, results); + TEST_ASSERT_EQUAL_STRING(MDNS_INSTANCE "1", results->instance_name); + mdns_query_results_free(results); + + // Update service properties: txt + mdns_txt_item_t txt_data[] = { + {"key1", "esp32"}, + {"key2", "value"}, + {"key3", "value3"}, + }; + const size_t txt_data_cout = sizeof(txt_data) / sizeof(txt_data[0]); + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_txt_set(MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, txt_data, txt_data_cout)); + yield_to_all_priorities(); // Make sure that mdns task has executed to add the hostname + TEST_ASSERT_EQUAL(ESP_OK, mdns_lookup_selfhosted_service(NULL, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, 1, &results)); + TEST_ASSERT_NOT_EQUAL(NULL, results); + TEST_ASSERT_NOT_EQUAL(NULL, results->txt); + TEST_ASSERT_EQUAL(txt_data_cout, results->txt_count); + // compare txt values by keys + size_t matches = 0; + for (int i = 0; i < results->txt_count; ++i) // iterates over the results we get from mdns_lookup() + for (int j = 0; j < txt_data_cout; ++j) // iterates over our test records + if (strcmp(results->txt[i].key, txt_data[j].key) == 0) { // we compare the value only if the key matches + TEST_ASSERT_EQUAL_STRING(results->txt[i].value, txt_data[j].value); + ++matches; + } + TEST_ASSERT_EQUAL(txt_data_cout, matches); // checks that we went over all our txt items + mdns_query_results_free(results); + + // Now remove the service + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_remove(MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO)); + yield_to_all_priorities(); // Make sure that mdns task has executed to add the hostname + TEST_ASSERT_EQUAL(ESP_OK, mdns_lookup_selfhosted_service(NULL, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, 1, &results)); + TEST_ASSERT_EQUAL(NULL, results); + + mdns_free(); + esp_event_loop_delete_default(); +} + +TEST(mdns, add_remove_deleg_service) +{ + mdns_ip_addr_t addr; + addr.addr.type = ESP_IPADDR_TYPE_V4; + addr.addr.u_addr.ip4.addr = esp_ip4addr_aton("127.0.0.1"); + addr.next = NULL; + mdns_result_t *results = NULL; + test_case_uses_tcpip(); + TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_create_default()); + TEST_ASSERT_EQUAL(ESP_OK, mdns_init() ); + TEST_ASSERT_EQUAL(ESP_OK, mdns_hostname_set(MDNS_HOSTNAME)); + TEST_ASSERT_EQUAL(ESP_OK, mdns_delegate_hostname_add(MDNS_DELEGATE_HOSTNAME, &addr) ); + + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_add_for_host(MDNS_INSTANCE, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_DELEGATE_HOSTNAME, MDNS_SERVICE_PORT, NULL, 0)); + yield_to_all_priorities(); // Make sure that mdns task has executed to add the hostname + TEST_ASSERT_EQUAL(ESP_OK, mdns_lookup_delegated_service(NULL, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, 1, &results)); + TEST_ASSERT_NOT_EQUAL(NULL, results); + TEST_ASSERT_EQUAL_STRING(MDNS_INSTANCE, results->instance_name); + TEST_ASSERT_EQUAL_STRING(MDNS_SERVICE_NAME, results->service_type); + TEST_ASSERT_EQUAL(MDNS_SERVICE_PORT, results->port); + TEST_ASSERT_EQUAL(NULL, results->txt); + mdns_query_results_free(results); + + // Update service properties: port + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_port_set_for_host(NULL, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_DELEGATE_HOSTNAME, MDNS_SERVICE_PORT + 1)); + yield_to_all_priorities(); // Make sure that mdns task has executed to add the hostname + TEST_ASSERT_EQUAL(ESP_OK, mdns_lookup_delegated_service(NULL, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, 1, &results)); + TEST_ASSERT_NOT_EQUAL(NULL, results); + TEST_ASSERT_EQUAL(MDNS_SERVICE_PORT + 1, results->port); + mdns_query_results_free(results); + + // Update service properties: instance + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_instance_name_set_for_host(NULL, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_DELEGATE_HOSTNAME, MDNS_INSTANCE "1" )); + yield_to_all_priorities(); // Make sure that mdns task has executed to add the hostname + TEST_ASSERT_EQUAL(ESP_OK, mdns_lookup_delegated_service(MDNS_INSTANCE "1", MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, 1, &results)); + TEST_ASSERT_NOT_EQUAL(NULL, results); + TEST_ASSERT_EQUAL_STRING(MDNS_INSTANCE "1", results->instance_name); + mdns_query_results_free(results); + + // Update service properties: txt + mdns_txt_item_t txt_data[] = { + {"key1", "esp32"}, + {"key2", "value"}, + }; + const size_t txt_data_cout = sizeof(txt_data) / sizeof(txt_data[0]); + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_txt_set_for_host(NULL, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_DELEGATE_HOSTNAME, txt_data, txt_data_cout)); + yield_to_all_priorities(); // Make sure that mdns task has executed to add the hostname + TEST_ASSERT_EQUAL(ESP_OK, mdns_lookup_delegated_service(NULL, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, 1, &results)); + TEST_ASSERT_NOT_EQUAL(NULL, results); + TEST_ASSERT_NOT_EQUAL(NULL, results->txt); + TEST_ASSERT_EQUAL(txt_data_cout, results->txt_count); + // compare txt values by keys + size_t matches = 0; + for (int i = 0; i < results->txt_count; ++i) // iterates over the results we get from mdns_lookup() + for (int j = 0; j < txt_data_cout; ++j) // iterates over our test records + if (strcmp(results->txt[i].key, txt_data[j].key) == 0) { // we compare the value only if the key matches + TEST_ASSERT_EQUAL_STRING(results->txt[i].value, txt_data[j].value); + ++matches; + } + TEST_ASSERT_EQUAL(txt_data_cout, matches); // checks that we went over all our txt items + mdns_query_results_free(results); + + // Now remove the service + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_remove_for_host(NULL, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_DELEGATE_HOSTNAME)); + yield_to_all_priorities(); // Make sure that mdns task has executed to add the hostname + TEST_ASSERT_EQUAL(ESP_OK, mdns_lookup_delegated_service(NULL, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, 1, &results)); + TEST_ASSERT_EQUAL(NULL, results); + + mdns_free(); + esp_event_loop_delete_default(); +} TEST_GROUP_RUNNER(mdns) { RUN_TEST_CASE(mdns, api_fails_with_invalid_state) RUN_TEST_CASE(mdns, api_fails_with_expected_err) RUN_TEST_CASE(mdns, query_api_fails_with_expected_err) RUN_TEST_CASE(mdns, init_deinit) + RUN_TEST_CASE(mdns, add_remove_service) + RUN_TEST_CASE(mdns, add_remove_deleg_service) + } void app_main(void) From d4da9cb079cb13ff7aab6e19360962155882c101 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Mon, 19 Aug 2024 11:28:50 +0200 Subject: [PATCH 2/2] fix(mdns): Fix mdns mdns_lookup_service() to handle empty TXT the lookup_service API calls _copy_mdns_txt_items(), which tries to allocate new TXT records, but didn't handle the case with no TXT. Originally the _copy_mdns_txt_items() called calloc() with zero's which returned NULL (on espressif toolchain), so it's safe, but we could see an error message: E (1170) mdns: Cannot allocate memory (line: 6191, free heap: 281368 bytes) This commit addresses the empty TXT case and gets rid of the error message. --- components/mdns/mdns.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index cc359c8032..d3961ab49d 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -6185,6 +6185,10 @@ static mdns_txt_item_t *_copy_mdns_txt_items(mdns_txt_linked_item_t *items, uint ret_index++; } *txt_count = ret_index; + if (ret_index == 0) { // handle empty TXT + *txt_value_len = NULL; + return NULL; + } ret = (mdns_txt_item_t *)calloc(ret_index, sizeof(mdns_txt_item_t)); *txt_value_len = (uint8_t *)calloc(ret_index, sizeof(uint8_t)); if (!ret || !(*txt_value_len)) {