From 74882b18f0182ad89ad792e3412468038ecabacd Mon Sep 17 00:00:00 2001 From: David Cermak Date: Mon, 4 Oct 2021 10:24:31 +0200 Subject: [PATCH] MQTT: Add more unit tests with actual broker --- components/mqtt/test/Kconfig | 9 ++ components/mqtt/test/connection.c | 138 ++++++++++++++++++++++++++++++ components/mqtt/test/test_mqtt.c | 54 +++++++++++- 3 files changed, 199 insertions(+), 2 deletions(-) create mode 100644 components/mqtt/test/Kconfig create mode 100644 components/mqtt/test/connection.c diff --git a/components/mqtt/test/Kconfig b/components/mqtt/test/Kconfig new file mode 100644 index 0000000..e006f92 --- /dev/null +++ b/components/mqtt/test/Kconfig @@ -0,0 +1,9 @@ +menu "ESP-MQTT Unit Test Config" + + config MQTT_TEST_BROKER_URI + string "URI of the test broker" + default "mqtt://mqtt.eclipseprojects.io" + help + URL of an mqtt broker which this test connects to. + +endmenu diff --git a/components/mqtt/test/connection.c b/components/mqtt/test/connection.c new file mode 100644 index 0000000..213d6b3 --- /dev/null +++ b/components/mqtt/test/connection.c @@ -0,0 +1,138 @@ +/* + * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "unity.h" +#include "esp_event.h" +#include "esp_eth.h" +#include "esp_log.h" + +#if SOC_EMAC_SUPPORTED +#define ETH_START_BIT BIT(0) +#define ETH_STOP_BIT BIT(1) +#define ETH_CONNECT_BIT BIT(2) +#define ETH_GOT_IP_BIT BIT(3) +#define ETH_STOP_TIMEOUT_MS (10000) +#define ETH_GET_IP_TIMEOUT_MS (60000) + +static const char *TAG = "esp32_eth_test_fixture"; + +/** Event handler for Ethernet events */ +static void eth_event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + EventGroupHandle_t eth_event_group = (EventGroupHandle_t)arg; + switch (event_id) { + case ETHERNET_EVENT_CONNECTED: + xEventGroupSetBits(eth_event_group, ETH_CONNECT_BIT); + ESP_LOGI(TAG, "Ethernet Link Up"); + break; + case ETHERNET_EVENT_DISCONNECTED: + ESP_LOGI(TAG, "Ethernet Link Down"); + break; + case ETHERNET_EVENT_START: + xEventGroupSetBits(eth_event_group, ETH_START_BIT); + ESP_LOGI(TAG, "Ethernet Started"); + break; + case ETHERNET_EVENT_STOP: + xEventGroupSetBits(eth_event_group, ETH_STOP_BIT); + ESP_LOGI(TAG, "Ethernet Stopped"); + break; + default: + break; + } +} + +/** Event handler for IP_EVENT_ETH_GOT_IP */ +static void got_ip_event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + EventGroupHandle_t eth_event_group = (EventGroupHandle_t)arg; + ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data; + const esp_netif_ip_info_t *ip_info = &event->ip_info; + ESP_LOGI(TAG, "Ethernet Got IP Address"); + ESP_LOGI(TAG, "~~~~~~~~~~~"); + ESP_LOGI(TAG, "ETHIP:" IPSTR, IP2STR(&ip_info->ip)); + ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip_info->netmask)); + ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip_info->gw)); + ESP_LOGI(TAG, "~~~~~~~~~~~"); + xEventGroupSetBits(eth_event_group, ETH_GOT_IP_BIT); +} + +static esp_err_t test_uninstall_driver(esp_eth_handle_t eth_hdl, uint32_t ms_to_wait) +{ + int i = 0; + ms_to_wait += 100; + for (i = 0; i < ms_to_wait / 100; i++) { + vTaskDelay(pdMS_TO_TICKS(100)); + if (esp_eth_driver_uninstall(eth_hdl) == ESP_OK) { + break; + } + } + if (i < ms_to_wait / 10) { + return ESP_OK; + } else { + return ESP_FAIL; + } +} +static EventGroupHandle_t eth_event_group; +static esp_netif_t *eth_netif; +static esp_eth_mac_t *mac; +static esp_eth_phy_t *phy; +static esp_eth_handle_t eth_handle = NULL; +static esp_eth_netif_glue_handle_t glue; + +void eth_test_fixture_connect(void) +{ + EventBits_t bits; + eth_event_group = xEventGroupCreate(); + TEST_ASSERT(eth_event_group != NULL); + TEST_ESP_OK(esp_event_loop_create_default()); + // create TCP/IP netif + esp_netif_config_t netif_cfg = ESP_NETIF_DEFAULT_ETH(); + eth_netif = esp_netif_new(&netif_cfg); + + eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); + mac = esp_eth_mac_new_esp32(&mac_config); + eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); + phy = esp_eth_phy_new_ip101(&phy_config); + esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy); + + // install Ethernet driver + TEST_ESP_OK(esp_eth_driver_install(ð_config, ð_handle)); + // combine driver with netif + glue = esp_eth_new_netif_glue(eth_handle); + TEST_ESP_OK(esp_netif_attach(eth_netif, glue)); + // register user defined event handers + TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, eth_event_group)); + TEST_ESP_OK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, eth_event_group)); + // start Ethernet driver + TEST_ESP_OK(esp_eth_start(eth_handle)); + /* wait for IP lease */ + bits = xEventGroupWaitBits(eth_event_group, ETH_GOT_IP_BIT, true, true, pdMS_TO_TICKS(ETH_GET_IP_TIMEOUT_MS)); + TEST_ASSERT((bits & ETH_GOT_IP_BIT) == ETH_GOT_IP_BIT); +} + +void eth_test_fixture_deinit(void) +{ + EventBits_t bits; + // stop Ethernet driver + TEST_ESP_OK(esp_eth_stop(eth_handle)); + /* wait for connection stop */ + bits = xEventGroupWaitBits(eth_event_group, ETH_STOP_BIT, true, true, pdMS_TO_TICKS(ETH_STOP_TIMEOUT_MS)); + TEST_ASSERT((bits & ETH_STOP_BIT) == ETH_STOP_BIT); + TEST_ESP_OK(esp_eth_del_netif_glue(glue)); + /* driver should be uninstalled within 2 seconds */ + TEST_ESP_OK(test_uninstall_driver(eth_handle, 2000)); + TEST_ESP_OK(phy->del(phy)); + TEST_ESP_OK(mac->del(mac)); + TEST_ESP_OK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_ETH_GOT_IP, got_ip_event_handler)); + TEST_ESP_OK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler)); + esp_netif_destroy(eth_netif); + TEST_ESP_OK(esp_event_loop_delete_default()); + vEventGroupDelete(eth_event_group); +} +#endif // SOC_EMAC_SUPPORTED diff --git a/components/mqtt/test/test_mqtt.c b/components/mqtt/test/test_mqtt.c index 1cf0618..5cc0e47 100644 --- a/components/mqtt/test/test_mqtt.c +++ b/components/mqtt/test/test_mqtt.c @@ -1,9 +1,13 @@ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "unity.h" #include "test_utils.h" #include "mqtt_client.h" -#include "unity.h" -#include #include "nvs_flash.h" #include "esp_ota_ops.h" +#include "sdkconfig.h" +#include "soc/soc_caps.h" static void test_leak_setup(const char * file, long line) { @@ -68,3 +72,49 @@ TEST_CASE("mqtt enqueue and destroy outbox", "[mqtt][leaks=0]") esp_mqtt_client_destroy(client); } + +#if SOC_EMAC_SUPPORTED + +void eth_test_fixture_connect(void); +void eth_test_fixture_deinit(void); + +static const int CONNECT_BIT = BIT0; +static const int DISCONNECT_BIT = BIT1; + +static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) +{ + EventGroupHandle_t *event_group = handler_args; + switch ((esp_mqtt_event_id_t)event_id) { + case MQTT_EVENT_CONNECTED: + xEventGroupSetBits(*event_group, CONNECT_BIT); + break; + case MQTT_EVENT_DISCONNECTED: + xEventGroupSetBits(*event_group, DISCONNECT_BIT); + break; + default: + break; + } +} + +TEST_CASE("connect disconnect", "[mqtt][test_env=UT_T2_Ethernet]") +{ + test_leak_setup(__FILE__, __LINE__); + test_case_uses_tcpip(); + eth_test_fixture_connect(); + const int TEST_CONNECT_TIMEOUT = 10000; + const esp_mqtt_client_config_t mqtt_cfg = { + // no connection takes place, but the uri has to be valid for init() to succeed + .uri = CONFIG_MQTT_TEST_BROKER_URI, + }; + EventGroupHandle_t event_group = xEventGroupCreate(); + esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg); + TEST_ASSERT_NOT_EQUAL(NULL, client ); + esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, &event_group); + TEST_ASSERT_EQUAL(ESP_OK, esp_mqtt_client_start(client)); + TEST_ASSERT_TRUE(xEventGroupWaitBits(event_group, CONNECT_BIT, pdTRUE, pdTRUE, pdMS_TO_TICKS(TEST_CONNECT_TIMEOUT)) & CONNECT_BIT); + esp_mqtt_client_disconnect(client); + TEST_ASSERT_TRUE(xEventGroupWaitBits(event_group, DISCONNECT_BIT, pdTRUE, pdTRUE, pdMS_TO_TICKS(TEST_CONNECT_TIMEOUT)) & DISCONNECT_BIT); + esp_mqtt_client_destroy(client); + eth_test_fixture_deinit(); +} +#endif // SOC_EMAC_SUPPORTED