This commit is contained in:
2025-10-07 00:18:25 -04:00
parent 970e081f64
commit 909dddeb77
1612 changed files with 0 additions and 159018 deletions

View File

@@ -1,4 +0,0 @@
idf_component_register(SRCS test_mqtt_connection.c
INCLUDE_DIRS ${CMAKE_CURRENT_LIST_DIR}/include
PRIV_REQUIRES unity esp_event esp_netif esp_eth)

View File

@@ -1,18 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "soc/soc_caps.h"
/**
* Connection test fixture setup, so we expect the broker is available
* on network
*/
void connect_test_fixture_setup(void);
/**
* Cleans up the connection
*/
void connect_test_fixture_teardown(void);

View File

@@ -1,144 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021-2022 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_netif.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";
static EventGroupHandle_t s_eth_event_group = NULL;
static esp_netif_t *s_eth_netif = NULL;
static esp_eth_mac_t *s_mac = NULL;
static esp_eth_phy_t *s_phy = NULL;
static esp_eth_handle_t s_eth_handle = NULL;
static esp_eth_netif_glue_handle_t s_eth_glue = NULL;
/** 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;
}
}
void connect_test_fixture_setup(void)
{
EventBits_t bits;
s_eth_event_group = xEventGroupCreate();
TEST_ASSERT(s_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();
s_eth_netif = esp_netif_new(&netif_cfg);
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
s_mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
s_phy = esp_eth_phy_new_ip101(&phy_config);
esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(s_mac, s_phy);
// install Ethernet driver
TEST_ESP_OK(esp_eth_driver_install(&eth_config, &s_eth_handle));
// combine driver with netif
s_eth_glue = esp_eth_new_netif_glue(s_eth_handle);
TEST_ESP_OK(esp_netif_attach(s_eth_netif, s_eth_glue));
// register user defined event handlers
TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, s_eth_event_group));
TEST_ESP_OK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, s_eth_event_group));
// start Ethernet driver
TEST_ESP_OK(esp_eth_start(s_eth_handle));
/* wait for IP lease */
bits = xEventGroupWaitBits(s_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 connect_test_fixture_teardown(void)
{
EventBits_t bits;
// stop Ethernet driver
TEST_ESP_OK(esp_eth_stop(s_eth_handle));
/* wait for connection stop */
bits = xEventGroupWaitBits(s_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(s_eth_glue));
/* driver should be uninstalled within 2 seconds */
TEST_ESP_OK(test_uninstall_driver(s_eth_handle, 2000));
TEST_ESP_OK(s_phy->del(s_phy));
TEST_ESP_OK(s_mac->del(s_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(s_eth_netif);
TEST_ESP_OK(esp_event_loop_delete_default());
vEventGroupDelete(s_eth_event_group);
}
#endif // SOC_EMAC_SUPPORTED

View File

@@ -1,16 +0,0 @@
#This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(EXTRA_COMPONENT_DIRS "../common")
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER "5.5")
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/test_apps/components")
else()
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
endif()
idf_build_set_property(MINIMAL_BUILD ON)
project(esp_mqtt_client_test)

View File

@@ -1,2 +0,0 @@
| Supported Targets | ESP32 | ESP32-C3 |
| ----------------- | ----- | -------- |

View File

@@ -1,8 +0,0 @@
set(srcs test_mqtt_client_broker.c test_mqtt.c)
if(CONFIG_MQTT_PROTOCOL_5)
list(APPEND srcs test_mqtt5_client_broker.c test_mqtt5.c)
endif()
idf_component_register(SRCS "${srcs}"
PRIV_REQUIRES cmock test_utils mqtt nvs_flash app_update spi_flash common)

View File

@@ -1,14 +0,0 @@
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.
config MQTT5_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

View File

@@ -1,5 +0,0 @@
dependencies:
espressif/mqtt:
version: "*"
override_path: "../../../.."

View File

@@ -1,122 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*
* This test code is in the Public Domain (or CC0 licensed, at your option.)
*
* Unless required by applicable law or agreed to in writing, this
* software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied.
*/
#include <sys/time.h>
#include "unity_fixture.h"
#include "unity_fixture_extras.h"
#include "test_utils.h"
#include "memory_checks.h"
#include "mqtt_client.h"
#include "esp_ota_ops.h"
#include "test_mqtt_client_broker.h"
#include "test_mqtt_connection.h"
#include "esp_partition.h"
TEST_GROUP(mqtt);
TEST_SETUP(mqtt){
test_utils_record_free_mem();
TEST_ESP_OK(test_utils_set_leak_level(0, ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_GENERAL));
}
TEST_TEAR_DOWN(mqtt){
test_utils_finish_and_evaluate_leaks(test_utils_get_leak_level(ESP_LEAK_TYPE_WARNING, ESP_COMP_LEAK_ALL),
test_utils_get_leak_level(ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_ALL));
}
TEST(mqtt, init_with_invalid_url)
{
const esp_mqtt_client_config_t mqtt_cfg = {
.broker.address.uri = "INVALID",
};
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
TEST_ASSERT_EQUAL(NULL, client );
}
TEST(mqtt, init_and_deinit)
{
const esp_mqtt_client_config_t mqtt_cfg = {
// no connection takes place, but the uri has to be valid for init() to succeed
.broker.address.uri = "mqtts://localhost:8883",
};
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
TEST_ASSERT_NOT_EQUAL(NULL, client );
esp_mqtt_client_destroy(client);
}
static const char* this_bin_addr(void)
{
esp_partition_mmap_handle_t out_handle;
const void *binary_address;
const esp_partition_t* partition = esp_ota_get_running_partition();
esp_partition_mmap(partition, 0, partition->size, ESP_PARTITION_MMAP_DATA, &binary_address, &out_handle);
return binary_address;
}
TEST(mqtt, enqueue_and_destroy_outbox)
{
const char * bin_addr = this_bin_addr();
// Reseting leak detection since this_bin_addr adds to allocated memory.
test_utils_record_free_mem();
TEST_ESP_OK(test_utils_set_leak_level(0, ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_GENERAL));
const int messages = 20;
const int size = 2000;
const esp_mqtt_client_config_t mqtt_cfg = {
// no connection takes place, but the uri has to be valid for init() to succeed
.broker.address.uri = "mqtts://localhost:8883",
};
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
TEST_ASSERT_NOT_EQUAL(NULL, client );
int bytes_before = esp_get_free_heap_size();
for (int i=0; i<messages; ++i) {
esp_mqtt_client_publish(client, "test", bin_addr, size, 1, 0);
}
int bytes_after = esp_get_free_heap_size();
// check that outbox allocated all messages on heap
TEST_ASSERT_GREATER_OR_EQUAL(messages*size, bytes_before - bytes_after);
esp_mqtt_client_destroy(client);
}
#if SOC_EMAC_SUPPORTED
/**
* This test cases uses ethernet kit, so build and use it only if EMAC supported
*/
TEST(mqtt, broker_tests)
{
test_case_uses_tcpip();
connect_test_fixture_setup();
RUN_MQTT_BROKER_TEST(mqtt_connect_disconnect);
RUN_MQTT_BROKER_TEST(mqtt_subscribe_publish);
RUN_MQTT_BROKER_TEST(mqtt_lwt_clean_disconnect);
RUN_MQTT_BROKER_TEST(mqtt_subscribe_payload);
connect_test_fixture_teardown();
}
#endif // SOC_EMAC_SUPPORTED
TEST_GROUP_RUNNER(mqtt) {
RUN_TEST_CASE(mqtt, init_with_invalid_url);
RUN_TEST_CASE(mqtt, init_and_deinit);
RUN_TEST_CASE(mqtt, enqueue_and_destroy_outbox);
#if SOC_EMAC_SUPPORTED
RUN_TEST_CASE(mqtt, broker_tests);
#endif // SOC_EMAC_SUPPORTED
}
void app_main(void){
UNITY_MAIN(mqtt);
}

View File

@@ -1,227 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "mqtt_client.h"
#include "esp_log.h"
#include "esp_mac.h"
#define WAIT_FOR_EVENT(event) \
TEST_ASSERT_TRUE(xEventGroupWaitBits(s_event_group, event, pdTRUE, pdTRUE, pdMS_TO_TICKS(COMMON_OPERATION_TIMEOUT)) & event);
#define TEST_ASSERT_TRUE(condition) TEST_ASSERT_TRUE_LINE(condition, __LINE__)
#define TEST_ASSERT_TRUE_LINE(condition, line) \
do { \
if (!(condition)) { \
ESP_LOGE("test_mqtt_client_broker.c", \
"Assertion failed in line %d", line); \
return false; \
} \
} while(0)
static const int COMMON_OPERATION_TIMEOUT = 10000;
static const int CONNECT_BIT = BIT0;
static const int DISCONNECT_BIT = BIT1;
static const int DATA_BIT = BIT2;
static EventGroupHandle_t s_event_group;
static char* append_mac(const char* string)
{
uint8_t mac[6];
char *id_string = NULL;
esp_read_mac(mac, ESP_MAC_WIFI_STA);
asprintf(&id_string, "%s_%02x%02X%02X", string, mac[3], mac[4], mac[5]);
return id_string;
}
static void mqtt_data_handler_qos(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
if (event_id == MQTT_EVENT_DATA) {
esp_mqtt_event_handle_t event = event_data;
int * qos = handler_args;
*qos = event->qos;
xEventGroupSetBits(s_event_group, DATA_BIT);
}
}
static void mqtt_data_handler_lwt(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
if (event_id == MQTT_EVENT_DATA) {
esp_mqtt_event_handle_t event = event_data;
ESP_LOGI("mqtt-lwt", "MQTT_EVENT_DATA");
ESP_LOGI("mqtt-lwt", "TOPIC=%.*s", event->topic_len, event->topic);
ESP_LOGI("mqtt-lwt", "DATA=%.*s", event->data_len, event->data);
if (strncmp(event->data, "no-lwt", event->data_len) == 0) {
// no lwt, just to indicate the test has finished
xEventGroupSetBits(s_event_group, DATA_BIT);
} else {
// count up any potential lwt message
int * count = handler_args;
*count = *count + 1;
ESP_LOGE("mqtt-lwt", "count=%d", *count);
}
}
}
static void mqtt_data_handler_subscribe(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
if (event_id == MQTT_EVENT_SUBSCRIBED) {
esp_mqtt_event_handle_t event = event_data;
ESP_LOGI("mqtt-subscribe", "MQTT_EVENT_SUBSCRIBED, data size=%d", event->data_len);
int * sub_payload = handler_args;
if (event->data_len == 1) {
ESP_LOGI("mqtt-subscribe", "DATA=%d", *(uint8_t*)event->data);
*sub_payload = *(uint8_t*)event->data;
}
xEventGroupSetBits(s_event_group, DATA_BIT);
}
}
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
switch ((esp_mqtt_event_id_t)event_id) {
case MQTT_EVENT_CONNECTED:
xEventGroupSetBits(s_event_group, CONNECT_BIT);
break;
case MQTT_EVENT_DISCONNECTED:
xEventGroupSetBits(s_event_group, DISCONNECT_BIT);
break;
default:
break;
}
}
bool mqtt_connect_disconnect(void)
{
const esp_mqtt_client_config_t mqtt_cfg = {
.broker.address.uri = CONFIG_MQTT_TEST_BROKER_URI,
.network.disable_auto_reconnect = true,
};
s_event_group = xEventGroupCreate();
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
TEST_ASSERT_TRUE(NULL != client );
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
TEST_ASSERT_TRUE(ESP_OK == esp_mqtt_client_start(client));
WAIT_FOR_EVENT(CONNECT_BIT);
esp_mqtt_client_disconnect(client);
WAIT_FOR_EVENT(DISCONNECT_BIT);
esp_mqtt_client_reconnect(client);
WAIT_FOR_EVENT(CONNECT_BIT);
esp_mqtt_client_destroy(client);
vEventGroupDelete(s_event_group);
return true;
}
bool mqtt_subscribe_publish(void)
{
const esp_mqtt_client_config_t mqtt_cfg = {
.broker.address.uri = CONFIG_MQTT_TEST_BROKER_URI,
};
char* topic = append_mac("topic");
TEST_ASSERT_TRUE(NULL != topic);
s_event_group = xEventGroupCreate();
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
TEST_ASSERT_TRUE(NULL != client );
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
TEST_ASSERT_TRUE(ESP_OK == esp_mqtt_client_start(client));
WAIT_FOR_EVENT(CONNECT_BIT);
int qos = -1;
esp_mqtt_client_register_event(client, MQTT_EVENT_DATA, mqtt_data_handler_qos, &qos);
TEST_ASSERT_TRUE(esp_mqtt_client_subscribe(client, topic, 2) != -1);
TEST_ASSERT_TRUE(esp_mqtt_client_publish(client, topic, "message", 0, 2, 0) != -1);
WAIT_FOR_EVENT(DATA_BIT);
TEST_ASSERT_TRUE(qos == 2);
TEST_ASSERT_TRUE(esp_mqtt_client_publish(client, topic, "message", 0, 1, 0) != -1);
WAIT_FOR_EVENT(DATA_BIT);
TEST_ASSERT_TRUE(qos == 1);
esp_mqtt_client_destroy(client);
vEventGroupDelete(s_event_group);
free(topic);
return true;
}
bool mqtt_lwt_clean_disconnect(void)
{
char* lwt = append_mac("lwt");
TEST_ASSERT_TRUE(lwt);
const esp_mqtt_client_config_t mqtt_cfg1 = {
.broker.address.uri = CONFIG_MQTT_TEST_BROKER_URI,
.credentials.set_null_client_id = true,
.session.last_will.topic = lwt,
.session.last_will.msg = "lwt_msg"
};
const esp_mqtt_client_config_t mqtt_cfg2 = {
.broker.address.uri = CONFIG_MQTT_TEST_BROKER_URI,
.credentials.set_null_client_id = true,
.session.last_will.topic = lwt,
.session.last_will.msg = "lwt_msg"
};
s_event_group = xEventGroupCreate();
esp_mqtt_client_handle_t client1 = esp_mqtt_client_init(&mqtt_cfg1);
esp_mqtt_client_handle_t client2 = esp_mqtt_client_init(&mqtt_cfg2);
TEST_ASSERT_TRUE(NULL != client1 && NULL != client2 );
esp_mqtt_client_register_event(client1, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
esp_mqtt_client_register_event(client2, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
TEST_ASSERT_TRUE(esp_mqtt_client_start(client1) == ESP_OK);
WAIT_FOR_EVENT(CONNECT_BIT);
TEST_ASSERT_TRUE(esp_mqtt_client_start(client2) == ESP_OK);
WAIT_FOR_EVENT(CONNECT_BIT);
int counter = 0;
esp_mqtt_client_register_event(client1, MQTT_EVENT_DATA, mqtt_data_handler_lwt, &counter);
esp_mqtt_client_register_event(client2, MQTT_EVENT_DATA, mqtt_data_handler_lwt, &counter);
TEST_ASSERT_TRUE(esp_mqtt_client_subscribe(client1, lwt, 0) != -1);
TEST_ASSERT_TRUE(esp_mqtt_client_subscribe(client2, lwt, 0) != -1);
esp_mqtt_client_disconnect(client1);
WAIT_FOR_EVENT(DISCONNECT_BIT);
esp_mqtt_client_reconnect(client1);
WAIT_FOR_EVENT(CONNECT_BIT);
TEST_ASSERT_TRUE(esp_mqtt_client_subscribe(client1, lwt, 0) != -1);
esp_mqtt_client_stop(client2);
esp_mqtt_client_start(client2);
WAIT_FOR_EVENT(CONNECT_BIT);
TEST_ASSERT_TRUE(esp_mqtt_client_subscribe(client2, lwt, 0) != -1);
TEST_ASSERT_TRUE(esp_mqtt_client_publish(client1, lwt, "no-lwt", 0, 0, 0) != -1);
WAIT_FOR_EVENT(DATA_BIT);
TEST_ASSERT_TRUE(counter == 0);
esp_mqtt_client_destroy(client1);
esp_mqtt_client_destroy(client2);
vEventGroupDelete(s_event_group);
free(lwt);
return true;
}
bool mqtt_subscribe_payload(void)
{
const esp_mqtt_client_config_t mqtt_cfg = {
.broker.address.uri = CONFIG_MQTT_TEST_BROKER_URI,
.network.disable_auto_reconnect = true,
};
char* topic = append_mac("topic");
TEST_ASSERT_TRUE(NULL != topic);
s_event_group = xEventGroupCreate();
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
TEST_ASSERT_TRUE(NULL != client );
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
TEST_ASSERT_TRUE(ESP_OK == esp_mqtt_client_start(client));
WAIT_FOR_EVENT(CONNECT_BIT);
int qos_payload = -1;
esp_mqtt_client_register_event(client, MQTT_EVENT_SUBSCRIBED, mqtt_data_handler_subscribe, &qos_payload);
TEST_ASSERT_TRUE(esp_mqtt_client_subscribe(client, topic, 2) != -1);
WAIT_FOR_EVENT(DATA_BIT);
TEST_ASSERT_TRUE(qos_payload == 2);
TEST_ASSERT_TRUE(esp_mqtt_client_subscribe(client, topic, 0) != -1);
WAIT_FOR_EVENT(DATA_BIT);
TEST_ASSERT_TRUE(qos_payload == 0);
esp_mqtt_client_destroy(client);
vEventGroupDelete(s_event_group);
free(topic);
return true;
}

View File

@@ -1,50 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_log.h"
/**
* @brief MQTT client-broker tests are not implemented as separate test cases
* due to time consuming connection setup/teardown.
* This utility macro is used to run functional cases as MQTT tests
* and evaluate as separate assertions in one "mqtt broker tests" test case.
*/
#define RUN_MQTT_BROKER_TEST(test_name) \
do { \
ESP_LOGI("mqtt_test", "Running test:" #test_name "()"); \
TEST_ASSERT_TRUE_MESSAGE(test_name(), "Mqtt test failed: " #test_name "() "); \
ESP_LOGI("mqtt_test", "Test:" #test_name "() passed "); \
} while(0)
/**
* @brief This module contains mqtt test cases interacting the client with a (real) broker
*/
/**
* @brief The client subscribes and publishes on the same topic
* and verifies the received published qos in the event
*/
bool mqtt_subscribe_publish(void);
/**
* @brief The client connects, disconnects and reconnects.
* Tests basic client state transitions
*/
bool mqtt_connect_disconnect(void);
/**
* @brief Two clients with defined lwt connect and subscribe to lwt topic.
* This test verifies that no lwt is send when each of the client disconnects.
* (we expect a clean disconnection, so no last-will being sent)
*/
bool mqtt_lwt_clean_disconnect(void);
/**
* @brief The client subscribes to a topic with certain qos
* and verifies the qos in SUBACK message from the broker.
*/
bool mqtt_subscribe_payload(void);

View File

@@ -1,11 +0,0 @@
# SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
import pytest
from pytest_embedded import Dut
from pytest_embedded_idf.utils import idf_parametrize
@pytest.mark.ethernet
@idf_parametrize('target', ['esp32'], indirect=['target'])
def test_mqtt_client(dut: Dut) -> None:
dut.expect_unity_test_output()

View File

@@ -1,4 +0,0 @@
CONFIG_MQTT_TEST_BROKER_URI="mqtt://${EXAMPLE_MQTT_BROKER_TCP}"
CONFIG_MQTT5_TEST_BROKER_URI="mqtt://${EXAMPLE_MQTT_BROKER_TCP}"
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_UNITY_ENABLE_FIXTURE=y

View File

@@ -1,3 +0,0 @@
# General options for additional checks
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_UNITY_ENABLE_FIXTURE=y

View File

@@ -1,16 +0,0 @@
#This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(EXTRA_COMPONENT_DIRS "../common")
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER "5.5")
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/test_apps/components")
else()
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
endif()
idf_build_set_property(MINIMAL_BUILD ON)
project(esp_mqtt5_client_test)

View File

@@ -1,2 +0,0 @@
| Supported Targets | ESP32 | ESP32-C3 |
| ----------------- | ----- | -------- |

View File

@@ -1,4 +0,0 @@
set(srcs test_mqtt5_client_broker.c test_mqtt5.c)
idf_component_register(SRCS "${srcs}"
PRIV_REQUIRES cmock test_utils mqtt nvs_flash app_update spi_flash common)

View File

@@ -1,14 +0,0 @@
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.
config MQTT5_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

View File

@@ -1,4 +0,0 @@
dependencies:
espressif/mqtt:
version: "*"
override_path: "../../../.."

View File

@@ -1,172 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <sys/time.h>
#include "unity_fixture.h"
#include "unity_fixture_extras.h"
#include "test_utils.h"
#include "memory_checks.h"
#include "mqtt_client.h"
#include "esp_ota_ops.h"
#include "test_mqtt5_client_broker.h"
#include "test_mqtt_connection.h"
#include "esp_partition.h"
TEST_GROUP(mqtt5);
TEST_SETUP(mqtt5)
{
test_utils_record_free_mem();
TEST_ESP_OK(test_utils_set_leak_level(0, ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_GENERAL));
}
TEST_TEAR_DOWN(mqtt5)
{
test_utils_finish_and_evaluate_leaks(test_utils_get_leak_level(ESP_LEAK_TYPE_WARNING, ESP_COMP_LEAK_ALL),
test_utils_get_leak_level(ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_ALL));
}
static esp_mqtt5_user_property_item_t user_property_arr[3] = {
{"board", "esp32"},
{"u", "user"},
{"p", "password"}
};
TEST(mqtt5, init_with_invalid_url)
{
const esp_mqtt_client_config_t mqtt5_cfg = {
.broker.address.uri = "INVALID",
.session.protocol_ver = MQTT_PROTOCOL_V_5,
};
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt5_cfg);
TEST_ASSERT_EQUAL(NULL, client );
}
TEST(mqtt5, init_and_deinit)
{
const esp_mqtt_client_config_t mqtt5_cfg = {
// no connection takes place, but the uri has to be valid for init() to succeed
.broker.address.uri = "mqtts://localhost:8883",
.session.protocol_ver = MQTT_PROTOCOL_V_5,
.credentials.username = "123",
.credentials.authentication.password = "456",
.session.last_will.topic = "/topic/will",
.session.last_will.msg = "i will leave",
.session.last_will.msg_len = 12,
.session.last_will.qos = 1,
.session.last_will.retain = true,
};
esp_mqtt5_connection_property_config_t connect_property = {
.session_expiry_interval = 10,
.maximum_packet_size = 1024,
.receive_maximum = 65535,
.topic_alias_maximum = 2,
.request_resp_info = true,
.request_problem_info = true,
.will_delay_interval = 10,
.payload_format_indicator = true,
.message_expiry_interval = 10,
.content_type = "json",
.response_topic = "/test/response",
.correlation_data = "123456",
.correlation_data_len = 6,
};
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt5_cfg);
esp_mqtt5_client_set_user_property(&connect_property.user_property, user_property_arr, 3);
esp_mqtt5_client_set_user_property(&connect_property.will_user_property, user_property_arr, 3);
esp_mqtt5_client_set_connect_property(client, &connect_property);
esp_mqtt5_client_delete_user_property(connect_property.user_property);
esp_mqtt5_client_delete_user_property(connect_property.will_user_property);
TEST_ASSERT_NOT_EQUAL(NULL, client );
esp_mqtt_client_destroy(client);
}
static const char *this_bin_addr(void)
{
esp_partition_mmap_handle_t out_handle;
const void *binary_address;
const esp_partition_t *partition = esp_ota_get_running_partition();
esp_partition_mmap(partition, 0, partition->size, ESP_PARTITION_MMAP_DATA, &binary_address, &out_handle);
return binary_address;
}
TEST(mqtt5, enqueue_and_destroy_outbox)
{
const char *bin_addr = this_bin_addr();
// Reseting leak detection since this_bin_addr adds to allocated memory.
test_utils_record_free_mem();
TEST_ESP_OK(test_utils_set_leak_level(0, ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_GENERAL));
const int messages = 20;
const int size = 2000;
const esp_mqtt_client_config_t mqtt5_cfg = {
// no connection takes place, but the uri has to be valid for init() to succeed
.broker.address.uri = "mqtts://localhost:8883",
.session.protocol_ver = MQTT_PROTOCOL_V_5,
};
esp_mqtt5_publish_property_config_t publish_property = {
.payload_format_indicator = 1,
.message_expiry_interval = 1000,
.topic_alias = 0,
.response_topic = "/topic/test/response",
.correlation_data = "123456",
.correlation_data_len = 6,
.content_type = "json",
};
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt5_cfg);
TEST_ASSERT_NOT_EQUAL(NULL, client );
int bytes_before = esp_get_free_heap_size();
for (int i = 0; i < messages; i ++) {
esp_mqtt5_client_set_user_property(&publish_property.user_property, user_property_arr, 3);
esp_mqtt5_client_set_publish_property(client, &publish_property);
esp_mqtt_client_publish(client, "test", bin_addr, size, 1, 0);
esp_mqtt5_client_delete_user_property(publish_property.user_property);
publish_property.user_property = NULL;
}
int bytes_after = esp_get_free_heap_size();
// check that outbox allocated all messages on heap
TEST_ASSERT_GREATER_OR_EQUAL(messages * size, bytes_before - bytes_after);
esp_mqtt_client_destroy(client);
}
#if SOC_EMAC_SUPPORTED
/**
* This test cases uses ethernet kit, so build and use it only if EMAC supported
*/
TEST(mqtt5, broker_tests)
{
test_case_uses_tcpip();
connect_test_fixture_setup();
RUN_MQTT5_BROKER_TEST(mqtt5_connect_disconnect);
RUN_MQTT5_BROKER_TEST(mqtt5_subscribe_publish);
RUN_MQTT5_BROKER_TEST(mqtt5_lwt_clean_disconnect);
RUN_MQTT5_BROKER_TEST(mqtt5_subscribe_payload);
connect_test_fixture_teardown();
}
#endif // SOC_EMAC_SUPPORTED
TEST_GROUP_RUNNER(mqtt5)
{
#if !DISABLED_FOR_TARGETS(ESP32H2)
RUN_TEST_CASE(mqtt5, init_with_invalid_url);
RUN_TEST_CASE(mqtt5, init_and_deinit);
RUN_TEST_CASE(mqtt5, enqueue_and_destroy_outbox);
#if SOC_EMAC_SUPPORTED
RUN_TEST_CASE(mqtt5, broker_tests);
#endif // SOC_EMAC_SUPPORTED
#endif //!DISABLED_FOR_TARGETS(ESP32H2)
}
void app_main(void)
{
UNITY_MAIN(mqtt5);
}

View File

@@ -1,285 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "mqtt_client.h"
#include "esp_log.h"
#include "esp_mac.h"
#define WAIT_FOR_EVENT(event) \
TEST_ASSERT_TRUE(xEventGroupWaitBits(s_event_group, event, pdTRUE, pdTRUE, pdMS_TO_TICKS(COMMON_OPERATION_TIMEOUT)) & event);
#define TEST_ASSERT_TRUE(condition) TEST_ASSERT_TRUE_LINE(condition, __LINE__)
#define TEST_ASSERT_TRUE_LINE(condition, line) \
do { \
if (!(condition)) { \
ESP_LOGE("test_mqtt5_client_broker.c", \
"Assertion failed in line %d", line); \
return false; \
} \
} while(0)
static const int COMMON_OPERATION_TIMEOUT = 10000;
static const int CONNECT_BIT = BIT0;
static const int DISCONNECT_BIT = BIT1;
static const int DATA_BIT = BIT2;
static EventGroupHandle_t s_event_group;
static esp_mqtt5_user_property_item_t user_property_arr[3] = {
{"board", "esp32"},
{"u", "user"},
{"p", "password"}
};
static char* append_mac(const char* string)
{
uint8_t mac[6];
char *id_string = NULL;
esp_read_mac(mac, ESP_MAC_WIFI_STA);
asprintf(&id_string, "%s_%02x%02X%02X", string, mac[3], mac[4], mac[5]);
return id_string;
}
static void mqtt5_data_handler_qos(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
if (event_id == MQTT_EVENT_DATA) {
esp_mqtt_event_handle_t event = event_data;
int * qos = handler_args;
*qos = event->qos;
xEventGroupSetBits(s_event_group, DATA_BIT);
}
}
static void mqtt5_data_handler_lwt(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
if (event_id == MQTT_EVENT_DATA) {
esp_mqtt_event_handle_t event = event_data;
ESP_LOGI("mqtt-lwt", "MQTT_EVENT_DATA");
ESP_LOGI("mqtt-lwt", "TOPIC=%.*s", event->topic_len, event->topic);
ESP_LOGI("mqtt-lwt", "DATA=%.*s", event->data_len, event->data);
if (strncmp(event->data, "no-lwt", event->data_len) == 0) {
// no lwt, just to indicate the test has finished
xEventGroupSetBits(s_event_group, DATA_BIT);
} else {
// count up any potential lwt message
int * count = handler_args;
*count = *count + 1;
ESP_LOGE("mqtt5-lwt", "count=%d", *count);
}
}
}
static void mqtt5_data_handler_subscribe(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
if (event_id == MQTT_EVENT_SUBSCRIBED) {
esp_mqtt_event_handle_t event = event_data;
ESP_LOGI("mqtt5-subscribe", "MQTT_EVENT_SUBSCRIBED, data size=%d", event->data_len);
int * sub_payload = handler_args;
if (event->data_len == 1) {
ESP_LOGI("mqtt5-subscribe", "DATA=%d", *(uint8_t*)event->data);
*sub_payload = *(uint8_t*)event->data;
}
xEventGroupSetBits(s_event_group, DATA_BIT);
}
}
static void mqtt5_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
switch ((esp_mqtt_event_id_t)event_id) {
case MQTT_EVENT_CONNECTED:
xEventGroupSetBits(s_event_group, CONNECT_BIT);
break;
case MQTT_EVENT_DISCONNECTED:
xEventGroupSetBits(s_event_group, DISCONNECT_BIT);
break;
default:
break;
}
}
bool mqtt5_connect_disconnect(void)
{
const esp_mqtt_client_config_t mqtt5_cfg = {
.broker.address.uri = CONFIG_MQTT5_TEST_BROKER_URI,
.network.disable_auto_reconnect = true,
.session.protocol_ver = MQTT_PROTOCOL_V_5,
};
esp_mqtt5_connection_property_config_t connect_property = {
.session_expiry_interval = 10,
.maximum_packet_size = 1024,
.receive_maximum = 65535,
.topic_alias_maximum = 2,
.request_resp_info = true,
.request_problem_info = true,
};
esp_mqtt5_disconnect_property_config_t disconnect_property = {
.session_expiry_interval = 10,
.disconnect_reason = 0,
};
s_event_group = xEventGroupCreate();
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt5_cfg);
TEST_ASSERT_TRUE(NULL != client );
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt5_event_handler, NULL);
TEST_ASSERT_TRUE(ESP_OK == esp_mqtt5_client_set_user_property(&connect_property.user_property, user_property_arr, 3));
TEST_ASSERT_TRUE(ESP_OK == esp_mqtt5_client_set_connect_property(client, &connect_property));
esp_mqtt5_client_delete_user_property(connect_property.user_property);
TEST_ASSERT_TRUE(ESP_OK == esp_mqtt_client_start(client));
WAIT_FOR_EVENT(CONNECT_BIT);
TEST_ASSERT_TRUE(ESP_OK == esp_mqtt5_client_set_user_property(&disconnect_property.user_property, user_property_arr, 3));
TEST_ASSERT_TRUE(ESP_OK == esp_mqtt5_client_set_disconnect_property(client, &disconnect_property));
esp_mqtt5_client_delete_user_property(disconnect_property.user_property);
esp_mqtt_client_disconnect(client);
WAIT_FOR_EVENT(DISCONNECT_BIT);
esp_mqtt_client_reconnect(client);
WAIT_FOR_EVENT(CONNECT_BIT);
esp_mqtt_client_destroy(client);
vEventGroupDelete(s_event_group);
return true;
}
bool mqtt5_subscribe_publish(void)
{
const esp_mqtt_client_config_t mqtt5_cfg = {
.broker.address.uri = CONFIG_MQTT5_TEST_BROKER_URI,
.session.protocol_ver = MQTT_PROTOCOL_V_5,
};
esp_mqtt5_publish_property_config_t publish_property = {
.payload_format_indicator = 1,
.message_expiry_interval = 1000,
.topic_alias = 1,
.response_topic = "/topic/test/response",
.correlation_data = "123456",
.correlation_data_len = 6,
.content_type = "json",
};
esp_mqtt5_subscribe_property_config_t subscribe_property = {
.subscribe_id = 25555,
.no_local_flag = false,
.retain_as_published_flag = true,
.retain_handle = 0,
};
char* topic = append_mac("topic");
TEST_ASSERT_TRUE(NULL != topic);
s_event_group = xEventGroupCreate();
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt5_cfg);
TEST_ASSERT_TRUE(NULL != client );
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt5_event_handler, NULL);
TEST_ASSERT_TRUE(ESP_OK == esp_mqtt_client_start(client));
WAIT_FOR_EVENT(CONNECT_BIT);
int qos = -1;
esp_mqtt_client_register_event(client, MQTT_EVENT_DATA, mqtt5_data_handler_qos, &qos);
TEST_ASSERT_TRUE(ESP_OK == esp_mqtt5_client_set_subscribe_property(client, &subscribe_property));
TEST_ASSERT_TRUE(esp_mqtt_client_subscribe(client, topic, 2) != -1);
TEST_ASSERT_TRUE(ESP_OK == esp_mqtt5_client_set_publish_property(client, &publish_property));
TEST_ASSERT_TRUE(esp_mqtt_client_publish(client, topic, "message", 0, 2, 0) != -1);
WAIT_FOR_EVENT(DATA_BIT);
TEST_ASSERT_TRUE(qos == 2);
TEST_ASSERT_TRUE(esp_mqtt_client_publish(client, topic, "message", 0, 1, 0) != -1);
WAIT_FOR_EVENT(DATA_BIT);
TEST_ASSERT_TRUE(qos == 1);
esp_mqtt_client_destroy(client);
vEventGroupDelete(s_event_group);
free(topic);
return true;
}
bool mqtt5_lwt_clean_disconnect(void)
{
char* lwt = append_mac("lwt");
TEST_ASSERT_TRUE(lwt);
const esp_mqtt_client_config_t mqtt5_cfg1 = {
.broker.address.uri = CONFIG_MQTT5_TEST_BROKER_URI,
.credentials.set_null_client_id = true,
.session.last_will.topic = lwt,
.session.last_will.msg = "lwt_msg",
.session.protocol_ver = MQTT_PROTOCOL_V_5,
};
const esp_mqtt_client_config_t mqtt5_cfg2 = {
.broker.address.uri = CONFIG_MQTT5_TEST_BROKER_URI,
.credentials.set_null_client_id = true,
.session.last_will.topic = lwt,
.session.last_will.msg = "lwt_msg",
.session.protocol_ver = MQTT_PROTOCOL_V_5,
};
esp_mqtt5_connection_property_config_t connect_property = {
.will_delay_interval = 10,
.payload_format_indicator = true,
.message_expiry_interval = 10,
.content_type = "json",
.response_topic = "/test/response",
.correlation_data = "123456",
.correlation_data_len = 6,
};
s_event_group = xEventGroupCreate();
esp_mqtt_client_handle_t client1 = esp_mqtt_client_init(&mqtt5_cfg1);
esp_mqtt_client_handle_t client2 = esp_mqtt_client_init(&mqtt5_cfg2);
TEST_ASSERT_TRUE(NULL != client1 && NULL != client2 );
esp_mqtt_client_register_event(client1, ESP_EVENT_ANY_ID, mqtt5_event_handler, NULL);
esp_mqtt_client_register_event(client2, ESP_EVENT_ANY_ID, mqtt5_event_handler, NULL);
TEST_ASSERT_TRUE(ESP_OK == esp_mqtt5_client_set_connect_property(client1, &connect_property));
TEST_ASSERT_TRUE(ESP_OK == esp_mqtt5_client_set_connect_property(client2, &connect_property));
TEST_ASSERT_TRUE(esp_mqtt_client_start(client1) == ESP_OK);
WAIT_FOR_EVENT(CONNECT_BIT);
TEST_ASSERT_TRUE(esp_mqtt_client_start(client2) == ESP_OK);
WAIT_FOR_EVENT(CONNECT_BIT);
int counter = 0;
esp_mqtt_client_register_event(client1, MQTT_EVENT_DATA, mqtt5_data_handler_lwt, &counter);
esp_mqtt_client_register_event(client2, MQTT_EVENT_DATA, mqtt5_data_handler_lwt, &counter);
TEST_ASSERT_TRUE(esp_mqtt_client_subscribe(client1, lwt, 0) != -1);
TEST_ASSERT_TRUE(esp_mqtt_client_subscribe(client2, lwt, 0) != -1);
esp_mqtt_client_disconnect(client1);
WAIT_FOR_EVENT(DISCONNECT_BIT);
esp_mqtt_client_reconnect(client1);
WAIT_FOR_EVENT(CONNECT_BIT);
TEST_ASSERT_TRUE(esp_mqtt_client_subscribe(client1, lwt, 0) != -1);
esp_mqtt_client_stop(client2);
esp_mqtt_client_start(client2);
WAIT_FOR_EVENT(CONNECT_BIT);
TEST_ASSERT_TRUE(esp_mqtt_client_subscribe(client2, lwt, 0) != -1);
TEST_ASSERT_TRUE(esp_mqtt_client_publish(client1, lwt, "no-lwt", 0, 0, 0) != -1);
WAIT_FOR_EVENT(DATA_BIT);
TEST_ASSERT_TRUE(counter == 0);
esp_mqtt_client_destroy(client1);
esp_mqtt_client_destroy(client2);
vEventGroupDelete(s_event_group);
free(lwt);
return true;
}
bool mqtt5_subscribe_payload(void)
{
const esp_mqtt_client_config_t mqtt5_cfg = {
.broker.address.uri = CONFIG_MQTT5_TEST_BROKER_URI,
.network.disable_auto_reconnect = true,
.session.protocol_ver = MQTT_PROTOCOL_V_5,
};
char* topic = append_mac("topic");
TEST_ASSERT_TRUE(NULL != topic);
s_event_group = xEventGroupCreate();
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt5_cfg);
TEST_ASSERT_TRUE(NULL != client );
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt5_event_handler, NULL);
TEST_ASSERT_TRUE(ESP_OK == esp_mqtt_client_start(client));
WAIT_FOR_EVENT(CONNECT_BIT);
int qos_payload = -1;
esp_mqtt_client_register_event(client, MQTT_EVENT_SUBSCRIBED, mqtt5_data_handler_subscribe, &qos_payload);
TEST_ASSERT_TRUE(esp_mqtt_client_subscribe(client, topic, 2) != -1);
WAIT_FOR_EVENT(DATA_BIT);
TEST_ASSERT_TRUE(qos_payload == 2);
TEST_ASSERT_TRUE(esp_mqtt_client_subscribe(client, topic, 0) != -1);
WAIT_FOR_EVENT(DATA_BIT);
TEST_ASSERT_TRUE(qos_payload == 0);
esp_mqtt_client_destroy(client);
vEventGroupDelete(s_event_group);
free(topic);
return true;
}

View File

@@ -1,51 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_log.h"
/**
* @brief MQTT5 client-broker tests are not implemented as separate test cases
* due to time consuming connection setup/teardown.
* This utility macro is used to run functional cases as MQTT tests
* and evaluate as separate assertions in one "mqtt5 broker tests" test case.
*/
#define RUN_MQTT5_BROKER_TEST(test_name) \
do { \
ESP_LOGI("mqtt5_test", "Running test:" #test_name "()"); \
TEST_ASSERT_TRUE_MESSAGE(test_name(), "Mqtt5 test failed: " #test_name "() "); \
ESP_LOGI("mqtt5_test", "Test:" #test_name "() passed "); \
} while(0)
/**
* @brief This module contains mqtt5 test cases interacting the client with a (real) broker
*/
/**
* @brief The client subscribes and publishes on the same topic
* and verifies the received published qos in the event
*/
bool mqtt5_subscribe_publish(void);
/**
* @brief The client connects, disconnects and reconnects.
* Tests basic client state transitions
*/
bool mqtt5_connect_disconnect(void);
/**
* @brief Two clients with defined lwt connect and subscribe to lwt topic.
* This test verifies that no lwt is send when each of the client disconnects.
* (we expect a clean disconnection, so no last-will being sent)
*/
bool mqtt5_lwt_clean_disconnect(void);
/**
* @brief The client subscribes to a topic with certain qos
* and verifies the qos in SUBACK message from the broker.
*/
bool mqtt5_subscribe_payload(void);

View File

@@ -1,11 +0,0 @@
# SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
import pytest
from pytest_embedded import Dut
from pytest_embedded_idf.utils import idf_parametrize
@pytest.mark.ethernet
@idf_parametrize('target', ['esp32'], indirect=['target'])
def test_mqtt5_client(dut: Dut) -> None:
dut.expect_unity_test_output()

View File

@@ -1,4 +0,0 @@
CONFIG_MQTT_TEST_BROKER_URI="mqtt://${EXAMPLE_MQTT_BROKER_TCP}"
CONFIG_MQTT5_TEST_BROKER_URI="mqtt://${EXAMPLE_MQTT_BROKER_TCP}"
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_UNITY_ENABLE_FIXTURE=y

View File

@@ -1,4 +0,0 @@
# General options for additional checks
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_MQTT_PROTOCOL_5=y
CONFIG_UNITY_ENABLE_FIXTURE=y

View File

@@ -1,16 +0,0 @@
# The following four lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
idf_build_set_property(MINIMAL_BUILD ON)
project(mqtt_publish_connect_test)
target_add_binary_data(mqtt_publish_connect_test.elf "main/mqtt_eclipseprojects_io.pem" TEXT)
target_add_binary_data(mqtt_publish_connect_test.elf "ca.crt" TEXT)
target_add_binary_data(mqtt_publish_connect_test.elf "ca.der" TEXT)
target_add_binary_data(mqtt_publish_connect_test.elf "client_pwd.key" TEXT)
target_add_binary_data(mqtt_publish_connect_test.elf "client_pwd.crt" TEXT)
target_add_binary_data(mqtt_publish_connect_test.elf "client_no_pwd.key" TEXT)
target_add_binary_data(mqtt_publish_connect_test.elf "client_inv.crt" TEXT)

View File

@@ -1,25 +0,0 @@
| Supported Targets | ESP32 | ESP32-C3 | ESP32-S2 |
| ----------------- | ----- | -------- | -------- |
# ESP-MQTT advanced publish and connect test project
Main purpose of this application is to test the MQTT library to correctly publish and receive messages (of different size and sequences) over different transports.
It is possible to run this example manually without any test to exercise how the MQTT library deals with
- reception of fragmented messages
- runtime updates of URI
## Runtime settings
This app waits for user input to provide these parameters:
- test-type: "conn" if connection test (host, port, test-case number)
- publish test:
* transport: string parameter, one of: tcp, ssl, ws, wss
* pattern: sample string to be transmitted as message
* pattern repeats: number of repeats of pattern in one MQTT message
* repeated: number of repeats ESP32 publishes the message, also ESP32 expects to receive the same message the same number of repeats
* qos: number specifying qos, one of: 0, 1, 2
## Hardware Required
This test-app can be executed on any ESP32 board, the only required interface is WiFi and connection to a local network, then depending on the test either a mqtt test broker or a tls server.

View File

@@ -1,19 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDGTCCAgGgAwIBAgIUY6kAA+U+ZPIJYIff8dlbi6NCzKswDQYJKoZIhvcNAQEL
BQAwFDESMBAGA1UEAwwJRXNwcmVzc2lmMB4XDTI1MDQwMjA1MjcwMloXDTM1MDMz
MTA1MjcwMlowFDESMBAGA1UEAwwJRXNwcmVzc2lmMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAwSY/p8zDP8W3f37xfL1jy/WcWVOOS2msWRyxjpXQM2e+
66McSkn8mVKTW5/aZ96sFQbmBBuhp3ypopH+kBQHxK4kla6roEcN/Nx9wpC8X64l
U9EqPmOvcIG8HElEY05LzZ9Rzc4LIBREq/sM8FE5+YHO2za8rN2XIaMii0mm2alf
o1MFEq1nkHBeJKlXkk6eZDwcQ9kqLWBz9YQWygE2pmDCjdCoY97/dZpgAjvkrAGN
9UYno9ZmNOYefL1P1ZmVtdBRW/xDGTDSZCJGYHOrtvfD8VS6cguOOl+rsy3obFdh
A4AgGFEFtfdY/+2fJHFkn6Pep6j+7h8f9n89qpSwswIDAQABo2MwYTAdBgNVHQ4E
FgQUJ+QsjjuS10OtEEcU0Wh2XhXTa1YwHwYDVR0jBBgwFoAUJ+QsjjuS10OtEEcU
0Wh2XhXTa1YwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZI
hvcNAQELBQADggEBABKWpI+QdMYoDwyssIbfwpbqJxb5M1w3PLnMsPzg1d5aEqLh
zwN9EnEQ5TxfeC7Lxdv3hKEGtif/aVxBhs48wPSxD7Fuw17kX6P4l9Cu9Ro2+1Oy
0lUxHi61xXxf7zVkdPQ0JLXdSMUvSUuKfvBtHCwEfdC+lsamxIDmCJys69kDhsCM
VJzY8Yz4MA9WOY3Z2YYMRp6ryFBZ9UgSUEnFxSOpggymkcM5mNxod1jshvSJ3FDG
dmvfbmK0+dN3rCiooORsIYVbopAYxralavA9IY24oiULE+GyVt5pNSONmJ96Y7GK
dL72B8RxX+jUSzgu/N3D1DwbPHP/xRiI7EqaYvg=
-----END CERTIFICATE-----

View File

@@ -1,28 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDBJj+nzMM/xbd/
fvF8vWPL9ZxZU45LaaxZHLGOldAzZ77roxxKSfyZUpNbn9pn3qwVBuYEG6GnfKmi
kf6QFAfEriSVrqugRw383H3CkLxfriVT0So+Y69wgbwcSURjTkvNn1HNzgsgFESr
+wzwUTn5gc7bNrys3ZchoyKLSabZqV+jUwUSrWeQcF4kqVeSTp5kPBxD2SotYHP1
hBbKATamYMKN0Khj3v91mmACO+SsAY31Riej1mY05h58vU/VmZW10FFb/EMZMNJk
IkZgc6u298PxVLpyC446X6uzLehsV2EDgCAYUQW191j/7Z8kcWSfo96nqP7uHx/2
fz2qlLCzAgMBAAECggEAA5+hkxbS1OfzLNenVSVCcYmekMhyA3UskBFrPVcPLF+2
Y7pQJg6kSAYWEKJ7mPZC+TQDbbFNA5Tho9SkV3Sgvq5brlk0DBI5L3S9gUBw4ESm
m59xcPEy0eQFMOyo9Un7PxTNlpRWfhgTP7y6femwMj+er1skCAQyOSXT2JQdpriv
5BnQquVSeoPbFuuObxerG878BDvMEIFzkZGmjWHhWD9P3+2sHcU6R6aZexRnkMrw
A8gagVzIi35QPDtWYLWcybdghJW7BdW8Lsx7HvMzRvNlBxMFnqtzNspuXEyZVlXF
J7cMpktiMQ+dNk18Utq9n19Y5ZWWi5g+XY3V0dHs3QKBgQDgrmdRWD3lLwY0equ6
/kk6Pf+GwgRLTVQy4DfUHPFCUY3+fZgYTL7InLjgcLynSdcHZ6hXjdIsAxwgeD6U
eBjjAhIyRNDTrSD91NQb99kmjSB9PRnPsERFiol5mR/JGUIs67y1a9oGPvhXW/9f
nu5jIacqF5sGZhmVmssYc/yXbQKBgQDcEqcKF+0WxHSNPMBtSFBOf/Uz6cT79lLS
1EoMiIjhQM1TrnRPqOicRegHmW7dWvtnsReprW6/mjz7t8C2kQm0Mf2UAtEm2Hzu
XxHM1Jmj1/oNc5Gzv5PhDMY8XEafzogj2uwL9++On74XNTkt20hl7qM4lcibu86U
f67cuOK0nwKBgQC3e7XEKFvjndNjaAp2WtNSTO8wDaGUHUJ1icYN4tTjY9ahzc83
iPUEv3f7UhW+R/7ifTRsy9SnPKLroUb52Fn6iOZzRt+C/g/DOts9O9qKMRYnMI6z
nS8j208JjpL2lzoDlUA2qC0UjLgiH28dl5z2N7VcGorvXtHl6tOQ1KeiwQKBgQCI
kq7FDcodyfdGuz/z0d+8h55FBDsx3lDR89qsYoMHvy5tUyNtWDZa3Os85BQwHMlO
NVGpBC9piq9zyzo2UlYCVM+4bfMcN1d4mtkyE3HxgxP0CxeNxENic4oGZYGSpRpJ
ng/E8a3iBfJy9p2wfpg0Yd87O4EOXIO8Fm0PH1HZowKBgQCBmYxw+gv7zbY6ejg1
prJsVvaVp5D8jhZ8agqRseWpeUEIrTzACNZ8L+loFMwsAIm5piLMziso1b6ktDmk
A9c7eOOh/kec8T4LXhIglLL49kmb0ZOCMotG1n9+1n/ZuMV8bMNTGWof5QjOMMKE
tC0yOkTvoIqHMbwnLrLLMOxh1w==
-----END PRIVATE KEY-----

View File

@@ -1,19 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIC/zCCAeegAwIBAgIUCpDNnOm701EkM8UghGHxDAXcVWEwDQYJKoZIhvcNAQEL
BQAwDjEMMAoGA1UEAwwDZXNwMCAXDTI1MDEyODEzMjkxMloYDzIyOTgxMTEyMTMy
OTEyWjAOMQwwCgYDVQQDDANlc3AwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQDVLhyorBPIbIS5hi7BCyv+UsrEAr17zfMu31zrj65wrRI2NPjeT/4UXTHB
WLXevsBmxngqa1HfBeJiwbjr0HNt7OAAIePnW0v0qfED6S6SG3ySbL7wOTQiUeZE
JiDmcjBiu3ttBimOeRAYl2RAHVrVzV01ByQ8QZZ5FFynBl6mOnu0lGSwImDCNoVk
g+zDNf9vbZWGUwvjxBoFmjvEdIEVh58c2Bu3Vzlblb/XR4XnQb0hR18VzHTibHdz
UKRDDzgoz1CSThmsNSJxOesS8e2wufHyqBQ1uXW2kJDIHwq+Ew7RkyhPLx6hXhN6
QS99SN5Sbgpucqc8pjJYFv3oHevXAgMBAAGjUzBRMB0GA1UdDgQWBBT5Ja5qUdUf
QRdQBur2UvcJmBmFVzAfBgNVHSMEGDAWgBT5Ja5qUdUfQRdQBur2UvcJmBmFVzAP
BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBrVzCP7OoyVZyZ80+c
+B7Cz1vWmNsyCLHVSuUqr3DuvJa0V71VdMGvr+zfR2/jLW7nGy2I+5d3Yaxs/AIZ
GF4XuDfuiJXjRDgFY8Xh+PgM7L4AxVvml8ZWaj9kurbIWKcsizCygoL4ckIA10QO
wAg7Au1RZT6iDeGW47inz/bP8V/sQnFmupTPN4VipMCUo61c+L0tnKPGbMySnmGq
mf9f/luAh/pgiW/HRjA4bppE5hCxUB8F5wyzAzFMnRVSYptpZdj/AYyAooV7Iit0
Ewjtrnxlr7zhmw4p32FuRDNU5AzbQMxDS4delGHMrNtehmSLNeZ3V7tAyG7EmJZd
y4YP
-----END CERTIFICATE-----

View File

@@ -1,28 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCQ8NP82CE2OJaZ
A07nbHyfhOdv/dnZXcemxFtoiEw1v29t5pldxBPUwy9/eg85+z1H1CTuFfHj2pzK
yyB1eJojTtQlJRZn1cZJ/0/LZu7naNACsndXmQcc0b6Cvn/jOuiqvAqFgLknLdEl
Iun2NSgeot3lafXy/yuLbKWHRDzsZIEpu/1iUlGx6UAQTBL+HVj2VM3hejdt33gn
PwdS+otmv+2A4ZBhbrL7EmtDJLM1wISo5PRp3YSknLJc8PdH5DQE5kaxh8RN/MDe
cm7kTeNeL2eN+nj9HvDUJ2yVF2P3ZaW6RtCwFlj0E3VXfKUNz2yTIowDtSkDeG7T
zjZ8V5cnAgMBAAECggEAB6ZeWfMCVb1I3YyaJobIURcPrA6G5/0WI4wrkunWs+OF
uxQ3tgY6Ubl3kU/c69+BzX+570MDQFZyfhWYgfq6j/CCK++4LgTPcWpjSMYHB/m1
ON84g0wVXwUG/BmX4GNkklZYa9FudE3rwv0DwjXuByfrdEdSbt/e6X3zgp8sZAGZ
oJnIWVvGxqIS1EvPHWkYlmDEnfNk1iYaQyNuYDxCxwwrLdyvhrsh1eiiGbabN7UK
CtqHgpZXXW/3hvCRJkl6EJVLXbegMEt73hN73Mn++iX0MVEDd+GfuEmojbM5rTpz
6CjD//CW43m9mJqq4Vx7QyZVQ9wJg9P4AvrD2gw9GQKBgQDJw+ThwWmmixXnsLxN
CpYqk77cWogTSEzyKnWYUMfiHUdCOVVEYmG4gnrC5NOuoNU2735rwDslUrGVpFRW
lPD8Ocptq6pbtKPlUVucJQVlgfrD2XWd4RuBhEX8mL6lGfTiW82wLeS7QgfDPhnh
YtBA+FASdZtsW34ce4+u6nbQqwKBgQC35qk5vXelRkp3gQpzfPLdmvR0UsSkEdD1
DvEjixGm5VcNRCdRlxeYCPNt4ADe0EGLKQn+oCwIvrAz95ZUjcAy+nLQJA++AyGi
X8TmHhmpJS82Jo2H7h7ZFCBuep+xb4a77DnpK8feYBH7MgL1skwFOJEq3k4Iv40Y
Uydzc/irdQKBgE58q86+RHEK7eyBLd7yXVQWwUpK1WBa4cPajIBB/F+TcCLs1qSR
eN4js8mY5leqLQb/xzf3QYrVTkud70j3C3+yo3JiMxUVgiQ0r+Rf6meAVqJVN5HA
/cg2Qltut8rV/BMKD0uXrsDBgO+MetjYbZa4gb2MjndqZ/aAgnZSswGdAoGAN2Cv
PuLuH4feLsRd+E7893yM9mZiLqHq0ZCxTqm3JBHVt/n4+RnNkgvH+iNFP9NomVY/
WzyyZeO+Pbflvgp9gRxn7IOfdfGNdE7whPc1dPjskZrkbbVn9qiX54znf8/8u6Q0
ACId6rn1UDZMK96IA9534HfW+c1s2JFZxOt8S20CgYBtV6D3iPRzaaDJy7J2Csyu
p+4nIeudRfVmzf2VRQOFqyULWNU35I2tBjq5rzN1yAmJCgE2kW1Z4iyfmLhBrF51
Wm3OY0R8Q5FvO9CCpL6XaZokEyWIcfEqjHKIIHf7lHeC4fs7YplRaxm7n1vV8hHK
UsP/rg6j/qZP+/WKNhsoBg==
-----END PRIVATE KEY-----

View File

@@ -1,18 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIC9DCCAdygAwIBAgIUcPhqC08YW+4RYTuVucv4UXLd2kQwDQYJKoZIhvcNAQEL
BQAwFDESMBAGA1UEAwwJRXNwcmVzc2lmMCAXDTI1MDEyODEzMjkxMloYDzIyOTgx
MTEyMTMyOTEyWjAOMQwwCgYDVQQDDANlc3AwggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQCQ8NP82CE2OJaZA07nbHyfhOdv/dnZXcemxFtoiEw1v29t5pld
xBPUwy9/eg85+z1H1CTuFfHj2pzKyyB1eJojTtQlJRZn1cZJ/0/LZu7naNACsndX
mQcc0b6Cvn/jOuiqvAqFgLknLdElIun2NSgeot3lafXy/yuLbKWHRDzsZIEpu/1i
UlGx6UAQTBL+HVj2VM3hejdt33gnPwdS+otmv+2A4ZBhbrL7EmtDJLM1wISo5PRp
3YSknLJc8PdH5DQE5kaxh8RN/MDecm7kTeNeL2eN+nj9HvDUJ2yVF2P3ZaW6RtCw
Flj0E3VXfKUNz2yTIowDtSkDeG7TzjZ8V5cnAgMBAAGjQjBAMB0GA1UdDgQWBBRT
WBz6pzNCJ5iMbbxr26mwLic+5zAfBgNVHSMEGDAWgBQn5CyOO5LXQ60QRxTRaHZe
FdNrVjANBgkqhkiG9w0BAQsFAAOCAQEAYOfwiCz+pzl9uE0WMOYU0NlSmOchN05m
CInOXuU7d38+QGjbnjs5IFmvquf8Ink6Z9hJitpPWHCN6rudT2BbFzzFQVmckMke
rbTSxUgyG/Xy4YgvTz49MUlK2fZc0Uun20Fu3vnCWvEPEYAfFdaUfegXtdFkI31J
U6EiwwMPzdlX6qLc2h3nKjm5yURvhSlFhKI1DMDhHF0wi09WH0T3CufLY3AQ2npK
4Vg3lP4F5Dh3FsaVj0h7BWhd4RfE6oyHkxRRgTfLuANdv6wOt2IR5OZAPedTGD9e
W0F0EyQXxsKhfqBeZsKpcYGRPWpOfdwR8nMV4QPuTPwTONmIYLFU5w==
-----END CERTIFICATE-----

View File

@@ -1,30 +0,0 @@
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIFNTBfBgkqhkiG9w0BBQ0wUjAxBgkqhkiG9w0BBQwwJAQQHePIq3//PykNJRiP
8SJIiwICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEGd76hqfyLtr9f/w
fETYk2QEggTQaLOK5NeAXOodW9eokEvmLeCSSHMfqXJWVSnHEbEJv5b5/lk6BoR0
y7BYsWwRs0lvX4AZPflJJpM82VUt3HZdv7I6ANHV71BIkaHc8h5aWUoOFhKsGIqf
AibxMYDVs7st6YJFFzXidc0c8zCEDPjtDSdiaXz+lF6cbY7MUz2Ej7yJnECQiRqY
PC8tFJdQeUDbqhDSk4VyevgJPLIYILdg0m9PpJYJr97lFYjWyX6Q1FnAX8NPLnTw
yQ03OJNkuv1h5Y/nJgtAoISS3dPLn2KjDehJ9xbd6TiiBhyU2dRxKGmx71oOZvbj
yLs5TcJs76DcA/0ExxMZz2+pUOpXg/hGtdNCvHL2vrjcQ/f4qpMBd2FiazOzCTtJ
fu7DPYtirt+2xlt2htjWkXlIxE0sw4FxQYJPVVruiTfVpGtDuRGQUmAWFq5JASVi
2GguLex69JxeQb+Gv0SFwn/6eC14qWy+m3gCUdjW+qkSD+0Mk7mOxNnSIyyHXzhz
sXZ7ZncU/5Q3AEtlTYKoFV7BTmaHFRgPG6r7lKKNu2RdPRa8R3fa8HizhnIsdGe/
m8H3ESKnpQLDiqA7cIM6eweErrOGMAwHBQSS3IdblZwdb6BPvpNUfp7lQ7YHdOYA
Vtl7gkwjniWQgSEOWqfvJ66Cr+u4wfV0rroTVP54pPeBGzort7L7Le3/ACO06ELN
Jdv6oTOsSZWs+AzwnU8/NQseB6xjvKafCBEbnYVoajTz29k52UNl/3fru3+e53Wu
WqJs8mCK9SGFLZfSp9Brecz0fpFNpQYAEEbd+HRkzT4lXCPPYGiPt+QdlcJtrwjq
NNSrCxsYxhsqEXpPzYj5ROvRBHjFGCpv6N33f05HoYQZf1hoXrABI/BQIZgXy8oD
AYKgBdrcCzJCuZyP9f66vSW7unxCAedhk4w7l6tozoPIFD2WXJ48ska9xvAjncMa
D3OAg95vEW4jfzTdLNSQnk5alOfqwX2CTHcXrzQn0OVnHG3xr1uCtTw605LoKEdf
6WQFihRnyIZOHAQyu8DVVGkhqpxH9d49VOrx5iVAhxSeK0vyhlKlZcq915VU6+mi
GEqjjywGJlN7Qk1bSfTr3AO6M8+Yd2YsBOzcGxtLkTxiUB94ss8QZzhb8qZWkSJ8
XxhCYyL3brsnQJVjPLyJYwNaJGHcEOeSEFHichicont6tD/FdzS6hiMfVO/367f6
q3tCLeaRYYBpM2600TjhgjfgupRJ3Y94QY0ukjwOPwx2xaciXR3RkXV0C0G4EiKH
zXJSUXxuBtdlHMyNlfh3EKRq17TkzacsbYuZ5jrGV7MIqpLF+dyqkeqMzsGFCnXN
S0gRAb2C1JwB3yWZnKtjZbUCwmwxna4YGEQZsGBxFkphvXZDJJpeDjGZHCKSkdRl
yY5UrKl6KW+n2h3CkWzuZPbAOs89o3N+pZdAxsaLUy3U4GAOev06z9fhwqjs7zsk
R/cDu/D7sIFlJfXW+QT/dXszDuLJmG/fZDBZOOshVmV8AD8nkQG802qPu47VtXLL
4NTb3XNO1ayqcrdEu/kdw9XnsXRvvRZ8Fc53qNp0zYF0/DqVnmGtHp9ttVXKDX7d
9grf6ltOzqlKfaabXTgaLkcYpeRXOLuDTPCUMRVJuxuhoWI6tQgzVx0=
-----END ENCRYPTED PRIVATE KEY-----

View File

@@ -1,4 +0,0 @@
idf_component_register(SRCS "publish_test.c" "connect_test.c" "publish_connect_test.c"
INCLUDE_DIRS "."
REQUIRES mqtt nvs_flash console esp_netif)
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")

View File

@@ -1,94 +0,0 @@
menu "Example Configuration"
config EXAMPLE_BROKER_SSL_URI
string "Broker SSL URL"
default "mqtts://mqtt.eclipseprojects.io:8883"
help
URL of an mqtt broker for ssl transport
config EXAMPLE_BROKER_TCP_URI
string "Broker TCP URL"
default "mqtt://mqtt.eclipseprojects.io:1883"
help
URL of an mqtt broker for tcp transport
config EXAMPLE_BROKER_WS_URI
string "Broker WS URL"
default "ws://mqtt.eclipseprojects.io:80/mqtt"
help
URL of an mqtt broker for ws transport
config EXAMPLE_BROKER_WSS_URI
string "Broker WSS URL"
default "wss://mqtt.eclipseprojects.io:443/mqtt"
help
URL of an mqtt broker for wss transport
config EXAMPLE_BROKER_CERTIFICATE_OVERRIDE
string "Broker certificate override"
default ""
help
Please leave empty if broker certificate included from a textfile; otherwise fill in a base64 part of PEM
format certificate
config EXAMPLE_BROKER_CERTIFICATE_OVERRIDDEN
bool
default y if EXAMPLE_BROKER_CERTIFICATE_OVERRIDE != ""
config EXAMPLE_RUN_LOCAL_BROKER
bool "Run local mosquitto"
default n
help
If enabled, this tests uses local mosquitto broker
running on the same endpoint as the client
config EXAMPLE_BROKER_HOST
string "Broker host address"
default "0.0.0.0"
depends on EXAMPLE_RUN_LOCAL_BROKER
help
Host name of the endpoint to bind the mosquitto listener.
config EXAMPLE_BROKER_PORT
int "Broker port"
default 1234
depends on EXAMPLE_RUN_LOCAL_BROKER
help
Port of the endpoint to bind the mosquitto listener
config EXAMPLE_CONNECT_CASE_NO_CERT
# Note: All the below config values (EXAMPLE_CONNECT_CASE...) are hidden and
# used to give symbolic names to test cases, which are then referenced from both
# the embedded C code as well as the test counterpart in python
int
default 1
config EXAMPLE_CONNECT_CASE_SERVER_CERT
int
default 2
config EXAMPLE_CONNECT_CASE_MUTUAL_AUTH
int
default 3
config EXAMPLE_CONNECT_CASE_INVALID_SERVER_CERT
int
default 4
config EXAMPLE_CONNECT_CASE_SERVER_DER_CERT
int
default 5
config EXAMPLE_CONNECT_CASE_MUTUAL_AUTH_KEY_PWD
int
default 6
config EXAMPLE_CONNECT_CASE_MUTUAL_AUTH_BAD_CRT
int
default 7
config EXAMPLE_CONNECT_CASE_NO_CERT_ALPN
int
default 8
endmenu

View File

@@ -1,197 +0,0 @@
/* MQTT connect test
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdint.h>
#include "esp_console.h"
#include "esp_log.h"
#include "mqtt_client.h"
#include "publish_connect_test.h"
#if (!defined(CONFIG_EXAMPLE_CONNECT_CASE_NO_CERT)) || \
(!defined(CONFIG_EXAMPLE_CONNECT_CASE_SERVER_CERT)) || \
(!defined(CONFIG_EXAMPLE_CONNECT_CASE_MUTUAL_AUTH)) || \
(!defined(CONFIG_EXAMPLE_CONNECT_CASE_INVALID_SERVER_CERT)) || \
(!defined(CONFIG_EXAMPLE_CONNECT_CASE_SERVER_DER_CERT)) || \
(!defined(CONFIG_EXAMPLE_CONNECT_CASE_MUTUAL_AUTH_KEY_PWD)) || \
(!defined(CONFIG_EXAMPLE_CONNECT_CASE_MUTUAL_AUTH_BAD_CRT)) || \
(!defined(CONFIG_EXAMPLE_CONNECT_CASE_NO_CERT_ALPN))
#error "Some mandatory test case not defined!"
#endif
extern const uint8_t ca_local_crt[] asm("_binary_ca_crt_start");
extern const uint8_t ca_der_start[] asm("_binary_ca_der_start");
extern const uint8_t ca_der_end[] asm("_binary_ca_der_end");
extern const uint8_t client_pwd_crt[] asm("_binary_client_pwd_crt_start");
extern const uint8_t client_pwd_key[] asm("_binary_client_pwd_key_start");
extern const uint8_t client_inv_crt[] asm("_binary_client_inv_crt_start");
extern const uint8_t client_no_pwd_key[] asm("_binary_client_no_pwd_key_start");
static const char *TAG = "connect_test";
static int running_test_case = 0;
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
(void)handler_args;
(void)base;
(void)event_id;
esp_mqtt_event_handle_t event = event_data;
ESP_LOGD(TAG, "Event: %d, Test case: %d", event->event_id, running_test_case);
switch (event->event_id) {
case MQTT_EVENT_BEFORE_CONNECT:
break;
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED: Test=%d", running_test_case);
break;
case MQTT_EVENT_DISCONNECTED:
break;
case MQTT_EVENT_ERROR:
ESP_LOGI(TAG, "MQTT_EVENT_ERROR: Test=%d", running_test_case);
if (event->error_handle->error_type == MQTT_ERROR_TYPE_ESP_TLS) {
ESP_LOGI(TAG, "ESP-TLS ERROR: %s", esp_err_to_name(event->error_handle->esp_tls_last_esp_err));
} else if (event->error_handle->error_type == MQTT_ERROR_TYPE_CONNECTION_REFUSED) {
ESP_LOGI(TAG, "MQTT ERROR: 0x%x", event->error_handle->connect_return_code);
} else {
ESP_LOGW(TAG, "Unknown error type: 0x%x", event->error_handle->error_type);
}
break;
default:
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
break;
}
}
static void connect_no_certs(esp_mqtt_client_handle_t client, const char *uri)
{
ESP_LOGI(TAG, "Runnning :CONFIG_EXAMPLE_CONNECT_CASE_NO_CERT");
const esp_mqtt_client_config_t mqtt_cfg = {
.broker.address.uri = uri
};
esp_mqtt_set_config(client, &mqtt_cfg);
}
static void connect_with_client_key_password(esp_mqtt_client_handle_t client, const char *uri)
{
const esp_mqtt_client_config_t mqtt_cfg = {
.broker.address.uri = uri,
.broker.verification.certificate = (const char *)ca_local_crt,
.credentials.authentication.certificate = (const char *)client_pwd_crt,
.credentials.authentication.key = (const char *)client_pwd_key,
.credentials.authentication.key_password = "esp32",
.credentials.authentication.key_password_len = 5
};
esp_mqtt_set_config(client, &mqtt_cfg);
}
static void connect_with_server_der_cert(esp_mqtt_client_handle_t client, const char *uri)
{
const esp_mqtt_client_config_t mqtt_cfg = {
.broker.address.uri = uri,
.broker.verification.certificate = (const char *)ca_der_start,
.broker.verification.certificate_len = ca_der_end - ca_der_start,
.credentials.authentication.certificate = "NULL",
.credentials.authentication.key = "NULL"
};
esp_mqtt_set_config(client, &mqtt_cfg);
}
static void connect_with_wrong_server_cert(esp_mqtt_client_handle_t client, const char *uri)
{
const esp_mqtt_client_config_t mqtt_cfg = {
.broker.address.uri = uri,
.broker.verification.certificate = (const char *)client_pwd_crt,
.credentials.authentication.certificate = "NULL",
.credentials.authentication.key = "NULL"
};
esp_mqtt_set_config(client, &mqtt_cfg);
}
static void connect_with_server_cert(esp_mqtt_client_handle_t client, const char *uri)
{
const esp_mqtt_client_config_t mqtt_cfg = {
.broker.address.uri = uri,
.broker.verification.certificate = (const char *)ca_local_crt,
};
esp_mqtt_set_config(client, &mqtt_cfg);
}
static void connect_with_server_client_certs(esp_mqtt_client_handle_t client, const char *uri)
{
const esp_mqtt_client_config_t mqtt_cfg = {
.broker.address.uri = uri,
.broker.verification.certificate = (const char *)ca_local_crt,
.credentials.authentication.certificate = (const char *)client_pwd_crt,
.credentials.authentication.key = (const char *)client_no_pwd_key
};
esp_mqtt_set_config(client, &mqtt_cfg);
}
static void connect_with_invalid_client_certs(esp_mqtt_client_handle_t client, const char *uri)
{
const esp_mqtt_client_config_t mqtt_cfg = {
.broker.address.uri = uri,
.broker.verification.certificate = (const char *)ca_local_crt,
.credentials.authentication.certificate = (const char *)client_inv_crt,
.credentials.authentication.key = (const char *)client_no_pwd_key
};
esp_mqtt_set_config(client, &mqtt_cfg);
}
static void connect_with_alpn(esp_mqtt_client_handle_t client, const char *uri)
{
const char *alpn_protos[] = { "mymqtt", NULL };
const esp_mqtt_client_config_t mqtt_cfg = {
.broker.address.uri = uri,
.broker.verification.alpn_protos = alpn_protos
};
esp_mqtt_set_config(client, &mqtt_cfg);
}
void connect_setup(command_context_t * ctx) {
esp_mqtt_client_register_event(ctx->mqtt_client, ESP_EVENT_ANY_ID, mqtt_event_handler, ctx->data);
}
void connect_teardown(command_context_t * ctx) {
esp_mqtt_client_unregister_event(ctx->mqtt_client, ESP_EVENT_ANY_ID, mqtt_event_handler);
}
void connection_test(command_context_t * ctx, const char *uri, int test_case)
{
ESP_LOGI(TAG, "CASE:%d, connecting to %s", test_case, uri);
running_test_case = test_case;
switch (test_case) {
case CONFIG_EXAMPLE_CONNECT_CASE_NO_CERT:
connect_no_certs(ctx->mqtt_client, uri);
break;
case CONFIG_EXAMPLE_CONNECT_CASE_SERVER_CERT:
connect_with_server_cert(ctx->mqtt_client, uri);
break;
case CONFIG_EXAMPLE_CONNECT_CASE_MUTUAL_AUTH:
connect_with_server_client_certs(ctx->mqtt_client, uri);
break;
case CONFIG_EXAMPLE_CONNECT_CASE_INVALID_SERVER_CERT:
connect_with_wrong_server_cert(ctx->mqtt_client, uri);
break;
case CONFIG_EXAMPLE_CONNECT_CASE_SERVER_DER_CERT:
connect_with_server_der_cert(ctx->mqtt_client, uri);
break;
case CONFIG_EXAMPLE_CONNECT_CASE_MUTUAL_AUTH_KEY_PWD:
connect_with_client_key_password(ctx->mqtt_client, uri);
break;
case CONFIG_EXAMPLE_CONNECT_CASE_MUTUAL_AUTH_BAD_CRT:
connect_with_invalid_client_certs(ctx->mqtt_client, uri);
break;
case CONFIG_EXAMPLE_CONNECT_CASE_NO_CERT_ALPN:
connect_with_alpn(ctx->mqtt_client, uri);
break;
default:
ESP_LOGE(TAG, "Unknown test case %d ", test_case);
break;
}
ESP_LOGI(TAG, "Test case:%d started", test_case);
}

View File

@@ -1,11 +0,0 @@
## IDF Component Manager Manifest File
dependencies:
espressif/mosquitto:
version: ">=2.0.20"
protocol_examples_common:
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
espressif/mqtt:
version: "*"
override_path: "../../../.."
idf:
version: ">=4.1.0"

View File

@@ -1,30 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw
WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg
RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP
R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx
sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm
NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg
Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG
/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC
AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB
Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA
FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw
AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw
Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB
gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W
PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl
ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz
CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm
lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4
avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2
yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O
yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids
hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+
HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv
MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX
nLRbwHOoq7hHwg==
-----END CERTIFICATE-----

View File

@@ -1,334 +0,0 @@
/* MQTT publish-connect test
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "esp_system.h"
#include "mqtt_client.h"
#include "nvs_flash.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "protocol_examples_common.h"
#include "esp_console.h"
#include "argtable3/argtable3.h"
#include "esp_log.h"
#include "publish_connect_test.h"
#include "mosq_broker.h"
static const char *TAG = "publish_connect_test";
command_context_t command_context;
connection_args_t connection_args;
publish_setup_args_t publish_setup_args;
publish_args_t publish_args;
#define RETURN_ON_PARSE_ERROR(args) do { \
int nerrors = arg_parse(argc, argv, (void **) &(args)); \
if (nerrors != 0) { \
arg_print_errors(stderr, (args).end, argv[0]); \
return 1; \
}} while(0)
static int do_free_heap(int argc, char **argv) {
(void)argc;
(void)argv;
ESP_LOGI(TAG, "Note free memory: %d bytes", esp_get_free_heap_size());
return 0;
}
static int do_init(int argc, char **argv) {
(void)argc;
(void)argv;
const esp_mqtt_client_config_t mqtt_cfg = {
.broker.address.uri = "mqtt://127.0.0.1:1234",
.network.disable_auto_reconnect = true
};
command_context.mqtt_client = esp_mqtt_client_init(&mqtt_cfg);
if(!command_context.mqtt_client) {
ESP_LOGE(TAG, "Failed to initialize client");
return 1;
}
publish_init_flags();
ESP_LOGI(TAG, "Mqtt client initialized");
return 0;
}
static int do_start(int argc, char **argv) {
(void)argc;
(void)argv;
if(esp_mqtt_client_start(command_context.mqtt_client) != ESP_OK) {
ESP_LOGE(TAG, "Failed to start mqtt client task");
return 1;
}
ESP_LOGI(TAG, "Mqtt client started");
return 0;
}
static int do_stop(int argc, char **argv) {
(void)argc;
(void)argv;
if(esp_mqtt_client_stop(command_context.mqtt_client) != ESP_OK) {
ESP_LOGE(TAG, "Failed to stop mqtt client task");
return 1;
}
ESP_LOGI(TAG, "Mqtt client stopped");
return 0;
}
static int do_disconnect(int argc, char **argv) {
(void)argc;
(void)argv;
if(esp_mqtt_client_disconnect(command_context.mqtt_client) != ESP_OK) {
ESP_LOGE(TAG, "Failed to request disconnection");
return 1;
}
ESP_LOGI(TAG, "Mqtt client disconnected");
return 0;
}
static int do_connect_setup(int argc, char **argv) {
(void)argc;
(void)argv;
connect_setup(&command_context);
return 0;
}
static int do_connect_teardown(int argc, char **argv) {
(void)argc;
(void)argv;
connect_teardown(&command_context);
return 0;
}
static int do_reconnect(int argc, char **argv) {
(void)argc;
(void)argv;
if(esp_mqtt_client_reconnect(command_context.mqtt_client) != ESP_OK) {
ESP_LOGE(TAG, "Failed to request reconnection");
return 1;
}
ESP_LOGI(TAG, "Mqtt client will reconnect");
return 0;
;
}
static int do_destroy(int argc, char **argv) {
(void)argc;
(void)argv;
esp_mqtt_client_destroy(command_context.mqtt_client);
command_context.mqtt_client = NULL;
ESP_LOGI(TAG, "mqtt client for tests destroyed");
return 0;
}
static int do_connect(int argc, char **argv)
{
int nerrors = arg_parse(argc, argv, (void **) &connection_args);
if (nerrors != 0) {
arg_print_errors(stderr, connection_args.end, argv[0]);
return 1;
}
if(!command_context.mqtt_client) {
ESP_LOGE(TAG, "MQTT client not initialized, call init first");
return 1;
}
connection_test(&command_context, *connection_args.uri->sval, *connection_args.test_case->ival);
return 0;
}
static int do_publish_setup(int argc, char **argv) {
RETURN_ON_PARSE_ERROR(publish_setup_args);
if(command_context.data) {
free(command_context.data);
}
command_context.data = calloc(1, sizeof(publish_context_t));
((publish_context_t*)command_context.data)->pattern = strdup(*publish_setup_args.pattern->sval);
((publish_context_t*)command_context.data)->pattern_repetitions = *publish_setup_args.pattern_repetitions->ival;
((publish_context_t*)command_context.data)->subscribe_to = strdup(*publish_setup_args.subscribe_to->sval);
((publish_context_t*)command_context.data)->publish_to = strdup(*publish_setup_args.publish_to->sval);
publish_setup(&command_context, *publish_setup_args.transport->sval);
return 0;
}
static int do_publish(int argc, char **argv) {
RETURN_ON_PARSE_ERROR(publish_args);
publish_test(&command_context, publish_args.expected_to_publish->ival[0], publish_args.qos->ival[0], publish_args.enqueue->ival[0]);
return 0;
}
static int do_publish_report(int argc, char **argv) {
(void)argc;
(void)argv;
publish_context_t * ctx = command_context.data;
ESP_LOGI(TAG,"Test Report : Messages received %d, %d expected", ctx->nr_of_msg_received, ctx->nr_of_msg_expected);
return 0;
}
void register_common_commands(void) {
const esp_console_cmd_t init = {
.command = "init",
.help = "Run inition test\n",
.hint = NULL,
.func = &do_init,
};
const esp_console_cmd_t start = {
.command = "start",
.help = "Run startion test\n",
.hint = NULL,
.func = &do_start,
};
const esp_console_cmd_t stop = {
.command = "stop",
.help = "Run stopion test\n",
.hint = NULL,
.func = &do_stop,
};
const esp_console_cmd_t destroy = {
.command = "destroy",
.help = "Run destroyion test\n",
.hint = NULL,
.func = &do_destroy,
};
const esp_console_cmd_t free_heap = {
.command = "free_heap",
.help = "Run destroyion test\n",
.hint = NULL,
.func = &do_free_heap,
};
ESP_ERROR_CHECK(esp_console_cmd_register(&init));
ESP_ERROR_CHECK(esp_console_cmd_register(&start));
ESP_ERROR_CHECK(esp_console_cmd_register(&stop));
ESP_ERROR_CHECK(esp_console_cmd_register(&destroy));
ESP_ERROR_CHECK(esp_console_cmd_register(&free_heap));
}
void register_publish_commands(void) {
publish_setup_args.transport = arg_str1(NULL,NULL,"<transport>", "Selected transport to test");
publish_setup_args.publish_to = arg_str1(NULL,NULL,"<transport>", "Selected publish_to to publish");
publish_setup_args.subscribe_to = arg_str1(NULL,NULL,"<transport>", "Selected subscribe_to to publish");
publish_setup_args.pattern = arg_str1(NULL,NULL,"<pattern>", "Message pattern repeated to build big messages");
publish_setup_args.pattern_repetitions = arg_int1(NULL,NULL,"<pattern repetitions>", "How many times the pattern is repeated");
publish_setup_args.end = arg_end(1);
publish_args.expected_to_publish = arg_int1(NULL,NULL,"<number of messages>", "How many times the pattern is repeated");
publish_args.qos = arg_int1(NULL,NULL,"<qos>", "How many times the pattern is repeated");
publish_args.enqueue = arg_int1(NULL,NULL,"<enqueue>", "How many times the pattern is repeated");
publish_args.end = arg_end(1);
const esp_console_cmd_t publish_setup = {
.command = "publish_setup",
.help = "Set publish test parameters\n",
.hint = NULL,
.func = &do_publish_setup,
.argtable = &publish_setup_args
};
const esp_console_cmd_t publish = {
.command = "publish",
.help = "Run publish test\n",
.hint = NULL,
.func = &do_publish,
.argtable = &publish_args
};
const esp_console_cmd_t publish_report = {
.command = "publish_report",
.help = "Run destroyion test\n",
.hint = NULL,
.func = &do_publish_report,
};
ESP_ERROR_CHECK(esp_console_cmd_register(&publish_setup));
ESP_ERROR_CHECK(esp_console_cmd_register(&publish));
ESP_ERROR_CHECK(esp_console_cmd_register(&publish_report));
}
void register_connect_commands(void){
connection_args.uri = arg_str1(NULL,NULL,"<broker uri>", "Broker address");
connection_args.test_case = arg_int1(NULL, NULL, "<test case>","Selected test case");
connection_args.end = arg_end(1);
const esp_console_cmd_t connect = {
.command = "connect",
.help = "Run connection test\n",
.hint = NULL,
.func = &do_connect,
.argtable = &connection_args
};
const esp_console_cmd_t reconnect = {
.command = "reconnect",
.help = "Run reconnection test\n",
.hint = NULL,
.func = &do_reconnect,
};
const esp_console_cmd_t connection_setup = {
.command = "connection_setup",
.help = "Run reconnection test\n",
.hint = NULL,
.func = &do_connect_setup,
};
const esp_console_cmd_t connection_teardown = {
.command = "connection_teardown",
.help = "Run reconnection test\n",
.hint = NULL,
.func = &do_connect_teardown,
};
const esp_console_cmd_t disconnect = {
.command = "disconnect",
.help = "Run disconnection test\n",
.hint = NULL,
.func = &do_disconnect,
};
ESP_ERROR_CHECK(esp_console_cmd_register(&connect));
ESP_ERROR_CHECK(esp_console_cmd_register(&disconnect));
ESP_ERROR_CHECK(esp_console_cmd_register(&reconnect));
ESP_ERROR_CHECK(esp_console_cmd_register(&connection_setup));
ESP_ERROR_CHECK(esp_console_cmd_register(&connection_teardown));
}
#ifdef CONFIG_EXAMPLE_RUN_LOCAL_BROKER
static void broker_task(void* ctx)
{
// broker continues to run in this task
struct mosq_broker_config config = { .host = CONFIG_EXAMPLE_BROKER_HOST, .port = CONFIG_EXAMPLE_BROKER_PORT };
mosq_broker_run(&config);
}
#endif // CONFIG_EXAMPLE_RUN_LOCAL_BROKER
void app_main(void)
{
static const size_t max_line = 256;
ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
esp_log_level_set("*", ESP_LOG_INFO);
esp_log_level_set("wifi", ESP_LOG_ERROR);
esp_log_level_set("mqtt_client", ESP_LOG_VERBOSE);
esp_log_level_set("outbox", ESP_LOG_VERBOSE);
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
#ifdef CONFIG_EXAMPLE_RUN_LOCAL_BROKER
xTaskCreate(broker_task, "broker", 8192, NULL, 4, NULL);
#endif
ESP_ERROR_CHECK(example_connect());
esp_console_repl_t *repl = NULL;
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
repl_config.prompt = "mqtt>";
repl_config.max_cmdline_length = max_line;
esp_console_register_help_command();
register_common_commands();
register_connect_commands();
register_publish_commands();
esp_console_dev_uart_config_t hw_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_console_new_repl_uart(&hw_config, &repl_config, &repl));
ESP_ERROR_CHECK(esp_console_start_repl(repl));
}

View File

@@ -1,59 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#pragma once
#include "mqtt_client.h"
typedef enum {NONE, TCP, SSL, WS, WSS} transport_t;
typedef struct {
esp_mqtt_client_handle_t mqtt_client;
void * data;
} command_context_t;
typedef struct {
transport_t selected_transport;
char *pattern;
char *subscribe_to;
char *publish_to;
int pattern_repetitions;
int qos;
char *expected;
size_t expected_size;
size_t nr_of_msg_received;
size_t nr_of_msg_expected;
char * received_data;
} publish_context_t ;
typedef struct {
struct arg_str *uri;
struct arg_int *test_case;
struct arg_end *end;
} connection_args_t;
typedef struct {
struct arg_int *expected_to_publish;
struct arg_int *qos;
struct arg_int *enqueue;
struct arg_end *end;
} publish_args_t;
typedef struct {
struct arg_str *transport;
struct arg_str *subscribe_to;
struct arg_str *publish_to;
struct arg_str *pattern;
struct arg_int *pattern_repetitions;
struct arg_end *end;
} publish_setup_args_t;
void publish_init_flags(void);
void publish_setup(command_context_t * ctx, char const * transport);
void publish_teardown(command_context_t * ctx);
void publish_test(command_context_t * ctx, int expect_to_publish, int qos, bool enqueue);
void connection_test(command_context_t * ctx, const char *uri, int test_case);
void connect_setup(command_context_t * ctx);
void connect_teardown(command_context_t * ctx);

View File

@@ -1,229 +0,0 @@
/* MQTT publish test
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include <freertos/event_groups.h>
#include "esp_system.h"
#include "esp_random.h"
#include "esp_log.h"
#include "mqtt_client.h"
#include "sdkconfig.h"
#include "publish_connect_test.h"
static const char *TAG = "publish_test";
static EventGroupHandle_t mqtt_event_group;
const static int CONNECTED_BIT = BIT0;
#define CLIENT_ID_SUFFIX_SIZE 12
#if CONFIG_EXAMPLE_BROKER_CERTIFICATE_OVERRIDDEN == 1
static const uint8_t mqtt_eclipseprojects_io_pem_start[] = "-----BEGIN CERTIFICATE-----\n" CONFIG_EXAMPLE_BROKER_CERTIFICATE_OVERRIDE "\n-----END CERTIFICATE-----";
#else
extern const uint8_t mqtt_eclipseprojects_io_pem_start[] asm("_binary_mqtt_eclipseprojects_io_pem_start");
#endif
extern const uint8_t mqtt_eclipseprojects_io_pem_end[] asm("_binary_mqtt_eclipseprojects_io_pem_end");
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
publish_context_t * test_data = handler_args;
esp_mqtt_event_handle_t event = event_data;
esp_mqtt_client_handle_t client = event->client;
static int msg_id = 0;
static int actual_len = 0;
switch (event->event_id) {
case MQTT_EVENT_BEFORE_CONNECT:
break;
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
xEventGroupSetBits(mqtt_event_group, CONNECTED_BIT);
msg_id = esp_mqtt_client_subscribe(client, test_data->subscribe_to, test_data->qos);
ESP_LOGI(TAG, "sent subscribe successful %s , msg_id=%d", test_data->subscribe_to, msg_id);
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
break;
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_UNSUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_PUBLISHED:
ESP_LOGD(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_DATA:
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
ESP_LOGI(TAG, "TOPIC=%.*s", event->topic_len, event->topic);
ESP_LOGI(TAG, "ID=%d, total_len=%d, data_len=%d, current_data_offset=%d", event->msg_id, event->total_data_len, event->data_len, event->current_data_offset);
if (event->current_data_offset == 0) {
actual_len = event->data_len;
msg_id = event->msg_id;
if (event->total_data_len != test_data->expected_size) {
ESP_LOGE(TAG, "Incorrect message size: %d != %d", event->total_data_len, test_data->expected_size);
abort();
}
} else {
actual_len += event->data_len;
// check consistency with msg_id across multiple data events for single msg
if (msg_id != event->msg_id) {
ESP_LOGE(TAG, "Wrong msg_id in chunked message %d != %d", msg_id, event->msg_id);
abort();
}
}
if (event->current_data_offset + event->data_len > test_data->expected_size) {
ESP_LOGE(TAG, "Buffer overflow detected: offset %d + data_len %d > buffer size %d", event->current_data_offset, event->data_len, test_data->expected_size);
abort();
}
if (memcmp(test_data->expected + event->current_data_offset, event->data, event->data_len) != 0) {
ESP_LOGE(TAG, "Data mismatch at offset %d: \n expected %.*s, \n got %.*s", event->current_data_offset, event->data_len, test_data->expected + event->current_data_offset, event->data_len, event->data);
abort();
}
memcpy(test_data->received_data + event->current_data_offset, event->data, event->data_len);
if (actual_len == event->total_data_len) {
if (0 == memcmp(test_data->received_data, test_data->expected, test_data->expected_size)) {
memset(test_data->received_data, 0, test_data->expected_size);
test_data->nr_of_msg_received++;
if (test_data->nr_of_msg_received == test_data->nr_of_msg_expected) {
ESP_LOGI(TAG, "Correct pattern received exactly x times");
ESP_LOGI(TAG, "Test finished correctly!");
}
} else {
ESP_LOGE(TAG, "FAILED!");
abort();
}
}
break;
case MQTT_EVENT_ERROR:
ESP_LOGE(TAG, "MQTT_EVENT_ERROR");
break;
default:
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
break;
}
}
void test_init(void)
{
ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
}
void pattern_setup(publish_context_t * test_data)
{
int pattern_size = strlen(test_data->pattern);
free(test_data->expected);
free(test_data->received_data);
test_data->nr_of_msg_received = 0;
test_data->expected_size = (size_t)(pattern_size) * test_data->pattern_repetitions;
test_data->expected = malloc(test_data->expected_size);
test_data->received_data = malloc(test_data->expected_size);
for (int i = 0; i < test_data->pattern_repetitions; i++) {
memcpy(test_data->expected + (ptrdiff_t)(i * pattern_size), test_data->pattern, pattern_size);
}
ESP_LOGI(TAG, "EXPECTED STRING %.*s, SIZE:%d", test_data->expected_size, test_data->expected, test_data->expected_size);
}
static void configure_client(command_context_t * ctx, const char *transport)
{
publish_context_t * test_data = ctx->data;
ESP_LOGI(TAG, "Configuration");
transport_t selected_transport;
if (0 == strcmp(transport, "tcp")) {
selected_transport = TCP;
} else if (0 == strcmp(transport, "ssl")) {
selected_transport = SSL;
} else if (0 == strcmp(transport, "ws")) {
selected_transport = WS;
} else if (0 == strcmp(transport, "wss")) {
selected_transport = WSS;
} else {
ESP_LOGE(TAG, "Unexpected transport %s", transport);
abort();
}
if (selected_transport != test_data->selected_transport) {
test_data->selected_transport = selected_transport;
esp_mqtt_client_config_t config = {0};
switch (selected_transport) {
case NONE:
break;
case TCP:
ESP_LOGI(TAG, "[TCP transport] Startup..");
config.broker.address.uri = CONFIG_EXAMPLE_BROKER_TCP_URI;
break;
case SSL:
ESP_LOGI(TAG, "[SSL transport] Startup..");
config.broker.address.uri = CONFIG_EXAMPLE_BROKER_SSL_URI;
break;
case WS:
ESP_LOGI(TAG, "[WS transport] Startup..");
config.broker.address.uri = CONFIG_EXAMPLE_BROKER_WS_URI;
break;
case WSS:
ESP_LOGI(TAG, "[WSS transport] Startup..");
config.broker.address.uri = CONFIG_EXAMPLE_BROKER_WSS_URI;
break;
}
if (selected_transport == SSL || selected_transport == WSS) {
ESP_LOGI(TAG, "Set certificate");
config.broker.verification.certificate = (const char *)mqtt_eclipseprojects_io_pem_start;
}
// Generate a random client id for each iteration
char client_id[CLIENT_ID_SUFFIX_SIZE] = {0};
snprintf(client_id, sizeof(client_id), "esp32-%08X", esp_random());
config.credentials.client_id = client_id;
esp_mqtt_set_config(ctx->mqtt_client, &config);
}
}
void publish_init_flags(void) {
mqtt_event_group = xEventGroupCreate();
}
void publish_setup(command_context_t * ctx, char const * const transport) {
xEventGroupClearBits(mqtt_event_group, CONNECTED_BIT);
publish_context_t * data = (publish_context_t*)ctx->data;
pattern_setup(data);
configure_client(ctx, transport);
esp_mqtt_client_register_event(ctx->mqtt_client, ESP_EVENT_ANY_ID, mqtt_event_handler, data);
}
void publish_teardown(command_context_t * ctx)
{
esp_mqtt_client_unregister_event(ctx->mqtt_client, ESP_EVENT_ANY_ID, mqtt_event_handler);
}
void publish_test(command_context_t * ctx, int expect_to_publish, int qos, bool enqueue)
{
publish_context_t * data = (publish_context_t*)ctx->data;
data->nr_of_msg_expected = expect_to_publish;
ESP_LOGI(TAG, "PATTERN:%s REPEATED:%d PUBLISHED:%d", data->pattern, data->pattern_repetitions, data->nr_of_msg_expected);
xEventGroupWaitBits(mqtt_event_group, CONNECTED_BIT, false, true, portMAX_DELAY);
for (int i = 0; i < data->nr_of_msg_expected; i++) {
int msg_id;
if (enqueue) {
msg_id = esp_mqtt_client_enqueue(ctx->mqtt_client, data->publish_to, data->expected, data->expected_size, qos, 0, true);
} else {
msg_id = esp_mqtt_client_publish(ctx->mqtt_client, data->publish_to, data->expected, data->expected_size, qos, 0);
if(msg_id < 0) {
ESP_LOGE(TAG, "Failed to publish");
break;
}
}
ESP_LOGD(TAG, "Publishing msg_id=%d", msg_id);
}
}

View File

@@ -1,276 +0,0 @@
# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
import contextlib
import logging
import os
import re
import socketserver
import ssl
import subprocess
from threading import Thread
from typing import Any
from typing import Callable
from typing import Dict
from typing import Optional
import pytest
from common_test_methods import get_host_ip4_by_dest_ip
from pytest_embedded import Dut
from pytest_embedded_idf.utils import idf_parametrize
SERVER_PORT = 2222
def _path(f): # type: (str) -> str
return os.path.join(os.path.dirname(os.path.realpath(__file__)), f)
def set_server_cert_cn(ip): # type: (str) -> None
arg_list = [
['openssl', 'req', '-out', _path('srv.csr'), '-key', _path('server.key'), '-subj', '/CN={}'.format(ip), '-new'],
[
'openssl',
'x509',
'-req',
'-in',
_path('srv.csr'),
'-CA',
_path('ca.crt'),
'-CAkey',
_path('ca.key'),
'-CAcreateserial',
'-out',
_path('srv.crt'),
'-days',
'360',
],
]
for args in arg_list:
if subprocess.check_call(args) != 0:
raise RuntimeError('openssl command {} failed'.format(args))
class MQTTHandler(socketserver.StreamRequestHandler):
def handle(self) -> None:
logging.info(' - connection from: {}'.format(self.client_address))
data = bytearray(self.request.recv(1024))
message = ''.join(format(x, '02x') for x in data)
if message[0:16] == '101800044d515454':
if self.server.refuse_connection is False: # type: ignore
logging.info(' - received mqtt connect, sending ACK')
self.request.send(bytearray.fromhex('20020000'))
else:
# injecting connection not authorized error
logging.info(' - received mqtt connect, sending NAK')
self.request.send(bytearray.fromhex('20020005'))
else:
raise Exception(' - error process_mqtt_connect unexpected connect received: {}'.format(message))
# Simple server for mqtt over TLS connection
class TlsServer(socketserver.TCPServer):
timeout = 30.0
allow_reuse_address = True
allow_reuse_port = True
def __init__(
self,
port: int = SERVER_PORT,
ServerHandler: Callable[[Any, Any, Any], socketserver.BaseRequestHandler] = MQTTHandler,
client_cert: bool = False,
refuse_connection: bool = False,
use_alpn: bool = False,
):
self.refuse_connection = refuse_connection
self.context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
self.ssl_error = ''
self.alpn_protocol: Optional[str] = None
if client_cert:
self.context.verify_mode = ssl.CERT_REQUIRED
self.context.load_verify_locations(cafile=_path('ca.crt'))
self.context.load_cert_chain(certfile=_path('srv.crt'), keyfile=_path('server.key'))
if use_alpn:
self.context.set_alpn_protocols(['mymqtt', 'http/1.1'])
self.server_thread = Thread(target=self.serve_forever)
super().__init__(('', port), ServerHandler)
def server_activate(self) -> None:
self.socket = self.context.wrap_socket(self.socket, server_side=True)
super().server_activate()
def __enter__(self): # type: ignore
self.server_thread.start()
return self
def server_close(self) -> None:
try:
self.shutdown()
self.server_thread.join()
super().server_close()
except RuntimeError as e:
logging.exception(e)
# We need to override it here to capture ssl.SSLError
# The implementation is a slightly modified version from cpython original code.
def _handle_request_noblock(self) -> None:
try:
request, client_address = self.get_request()
self.alpn_protocol = request.selected_alpn_protocol() # type: ignore
except ssl.SSLError as e:
self.ssl_error = e.reason
return
except OSError:
return
if self.verify_request(request, client_address):
try:
self.process_request(request, client_address)
except Exception:
self.handle_error(request, client_address)
self.shutdown_request(request)
except: # noqa: E722
self.shutdown_request(request)
raise
else:
self.shutdown_request(request)
def last_ssl_error(self): # type: (TlsServer) -> str
return self.ssl_error
def get_negotiated_protocol(self) -> Optional[str]:
return self.alpn_protocol
def get_test_cases(dut: Dut) -> Any:
cases = {}
try:
# Get connection test cases configuration: symbolic names for test cases
for case in [
'EXAMPLE_CONNECT_CASE_NO_CERT',
'EXAMPLE_CONNECT_CASE_SERVER_CERT',
'EXAMPLE_CONNECT_CASE_MUTUAL_AUTH',
'EXAMPLE_CONNECT_CASE_INVALID_SERVER_CERT',
'EXAMPLE_CONNECT_CASE_SERVER_DER_CERT',
'EXAMPLE_CONNECT_CASE_MUTUAL_AUTH_KEY_PWD',
'EXAMPLE_CONNECT_CASE_MUTUAL_AUTH_BAD_CRT',
'EXAMPLE_CONNECT_CASE_NO_CERT_ALPN',
]:
cases[case] = dut.app.sdkconfig.get(case)
except Exception:
logging.error('ENV_TEST_FAILURE: Some mandatory CONNECTION test case not found in sdkconfig')
raise
return cases
def get_dut_ip(dut: Dut) -> Any:
dut_ip = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', timeout=30).group(1).decode()
logging.info('Got IP={}'.format(dut_ip))
return get_host_ip4_by_dest_ip(dut_ip)
@contextlib.contextmanager
def connect_dut(dut: Dut, uri: str, case_id: int) -> Any:
dut.write('connection_setup')
dut.write(f'connect {uri} {case_id}')
dut.expect(f'Test case:{case_id} started')
dut.write('reconnect')
yield
dut.write('connection_teardown')
dut.write('disconnect')
def run_cases(dut: Dut, uri: str, cases: Dict[str, int]) -> None:
try:
dut.write('init')
dut.write(f'start')
dut.write(f'disconnect')
for case in [
'EXAMPLE_CONNECT_CASE_NO_CERT',
'EXAMPLE_CONNECT_CASE_SERVER_CERT',
'EXAMPLE_CONNECT_CASE_SERVER_DER_CERT',
]:
# All these cases connect to the server with no server verification or with server only verification
with TlsServer(), connect_dut(dut, uri, cases[case]):
logging.info(f'Running {case}: default server - expect to connect normally')
dut.expect(f'MQTT_EVENT_CONNECTED: Test={cases[case]}', timeout=30)
with TlsServer(refuse_connection=True), connect_dut(dut, uri, cases[case]):
logging.info(f'Running {case}: ssl shall connect, but mqtt sends connect refusal')
dut.expect(f'MQTT_EVENT_ERROR: Test={cases[case]}', timeout=30)
dut.expect('MQTT ERROR: 0x5') # expecting 0x5 ... connection not authorized error
with TlsServer(client_cert=True) as server, connect_dut(dut, uri, cases[case]):
logging.info(
f'Running {case}: server with client verification - handshake error since client presents no client certificate'
)
dut.expect(f'MQTT_EVENT_ERROR: Test={cases[case]}', timeout=30)
dut.expect(
'ESP-TLS ERROR: ESP_ERR_MBEDTLS_SSL_HANDSHAKE_FAILED'
) # expect ... handshake error (PEER_DID_NOT_RETURN_A_CERTIFICATE)
assert 'PEER_DID_NOT_RETURN_A_CERTIFICATE' in server.last_ssl_error()
for case in ['EXAMPLE_CONNECT_CASE_MUTUAL_AUTH', 'EXAMPLE_CONNECT_CASE_MUTUAL_AUTH_KEY_PWD']:
# These cases connect to server with both server and client verification (client key might be password protected)
with TlsServer(client_cert=True), connect_dut(dut, uri, cases[case]):
logging.info(f'Running {case}: server with client verification - expect to connect normally')
dut.expect(f'MQTT_EVENT_CONNECTED: Test={cases[case]}', timeout=30)
case = 'EXAMPLE_CONNECT_CASE_INVALID_SERVER_CERT'
with TlsServer() as s, connect_dut(dut, uri, cases[case]):
logging.info(f'Running {case}: invalid server certificate on default server - expect ssl handshake error')
dut.expect(f'MQTT_EVENT_ERROR: Test={cases[case]}', timeout=30)
dut.expect(
'ESP-TLS ERROR: ESP_ERR_MBEDTLS_SSL_HANDSHAKE_FAILED'
) # expect ... handshake error (TLSV1_ALERT_UNKNOWN_CA)
if re.match('.*alert.*unknown.*ca', s.last_ssl_error(), flags=re.I) is None:
raise Exception(f'Unexpected ssl error from the server: {s.last_ssl_error()}')
case = 'EXAMPLE_CONNECT_CASE_MUTUAL_AUTH_BAD_CRT'
with TlsServer(client_cert=True) as s, connect_dut(dut, uri, cases[case]):
logging.info(
f'Running {case}: Invalid client certificate on server with client verification - expect ssl handshake error'
)
dut.expect(f'MQTT_EVENT_ERROR: Test={cases[case]}', timeout=30)
dut.expect(
'ESP-TLS ERROR: ESP_ERR_MBEDTLS_SSL_HANDSHAKE_FAILED'
) # expect ... handshake error (CERTIFICATE_VERIFY_FAILED)
if 'CERTIFICATE_VERIFY_FAILED' not in s.last_ssl_error():
raise Exception('Unexpected ssl error from the server {}'.format(s.last_ssl_error()))
for case in ['EXAMPLE_CONNECT_CASE_NO_CERT', 'EXAMPLE_CONNECT_CASE_NO_CERT_ALPN']:
with TlsServer(use_alpn=True) as s, connect_dut(dut, uri, cases[case]):
logging.info(f'Running {case}: server with alpn - expect connect, check resolved protocol')
dut.expect(f'MQTT_EVENT_CONNECTED: Test={cases[case]}', timeout=30)
if case == 'EXAMPLE_CONNECT_CASE_NO_CERT':
assert s.get_negotiated_protocol() is None
elif case == 'EXAMPLE_CONNECT_CASE_NO_CERT_ALPN':
assert s.get_negotiated_protocol() == 'mymqtt'
else:
assert False, f'Unexpected negotiated protocol {s.get_negotiated_protocol()}'
finally:
dut.write('stop')
dut.write('destroy')
@pytest.mark.ethernet
@idf_parametrize('target', ['esp32'], indirect=['target'])
def test_mqtt_connect(
dut: Dut,
log_performance: Callable[[str, object], None],
) -> None:
"""
steps:
1. join AP
2. connect to uri specified in the config
3. send and receive data
"""
# check and log bin size
binary_file = os.path.join(dut.app.binary_path, 'mqtt_publish_connect_test.bin')
bin_size = os.path.getsize(binary_file)
log_performance('mqtt_publish_connect_test_bin_size', f'{bin_size // 1024} KB')
ip = get_dut_ip(dut)
set_server_cert_cn(ip)
uri = f'mqtts://{ip}:{SERVER_PORT}'
# Look for test case symbolic names and publish configs
cases = get_test_cases(dut)
dut.expect_exact('mqtt>', timeout=30)
run_cases(dut, uri, cases)

View File

@@ -1,335 +0,0 @@
# SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
import contextlib
import difflib
import logging
import os
import random
import re
import ssl
import string
import time
from itertools import count
from itertools import product
from threading import Event
from threading import Lock
from typing import Any
from typing import Dict
from typing import List
from typing import Tuple
from typing import no_type_check
import paho.mqtt.client as mqtt
import pexpect
import pytest
from pytest_embedded import Dut
from pytest_embedded_idf.utils import idf_parametrize
DEFAULT_MSG_SIZE = 16
# Publisher class creating a python client to send/receive published data from esp-mqtt client
class MqttPublisher(mqtt.Client):
def __init__(self, config, log_details=False): # type: (MqttPublisher, dict, bool) -> None
self.log_details = log_details
self.config = config
self.expected_data = f'{config["pattern"] * config["scenario"]["msg_len"]}'
self.received = 0
self.subscribe_mid = 0
self.lock = Lock()
self.event_client_connected = Event()
self.event_client_subscribed = Event()
self.event_client_got_all = Event()
transport = 'websockets' if self.config['transport'] in ['ws', 'wss'] else 'tcp'
client_id = 'MqttTestRunner' + ''.join(
random.choice(string.ascii_uppercase + string.ascii_lowercase) for _ in range(5)
)
super().__init__(client_id, userdata=0, transport=transport)
def print_details(self, text): # type: (str) -> None
if self.log_details:
logging.info(text)
def on_subscribe(self, client: Any, userdata: Any, mid: Any, granted_qos: Any) -> None:
"""Verify successful subscription."""
if mid == self.subscribe_mid:
logging.info(f'Subscribed to {self.config["subscribe_topic"]} successfully with QoS: {granted_qos}')
self.event_client_subscribed.set()
def on_connect(self, mqttc: Any, obj: Any, flags: Any, rc: int) -> None:
self.event_client_connected.set()
def on_connect_fail(self, mqttc: Any, obj: Any) -> None:
logging.error('Connect failed')
def on_message(self, mqttc: mqtt.Client, obj: Any, msg: mqtt.MQTTMessage) -> None:
payload = msg.payload.decode('utf-8')
if payload == self.expected_data:
self.received += 1
if self.received == self.config['scenario']['nr_of_msgs']:
self.event_client_got_all.set()
else:
differences = len(list(filter(lambda data: data[0] != data[1], zip(payload, self.expected_data))))
logging.error(
f'Payload on topic "{msg.topic}" (QoS {msg.qos}) differs in {differences} positions '
'from expected data. '
f'Received size: {len(payload)}, expected size: {len(self.expected_data)}.'
)
logging.info(f'Repetitions: {payload.count(self.config["pattern"])}')
logging.info(f'Pattern: {self.config["pattern"]}')
logging.info(f'First: {payload[:DEFAULT_MSG_SIZE]}')
logging.info(f'Last: {payload[-DEFAULT_MSG_SIZE:]}')
matcher = difflib.SequenceMatcher(a=payload, b=self.expected_data)
for match in matcher.get_matching_blocks():
logging.info(f'Match: {match}')
def __enter__(self) -> Any:
qos = self.config['qos']
broker_host = self.config['broker_host_' + self.config['transport']]
broker_port = self.config['broker_port_' + self.config['transport']]
connect_timeout_seconds = self.config.get('client_connect_timeout', 30)
try:
self.print_details('Connecting...')
if self.config['transport'] in ['ssl', 'wss']:
self.tls_set(None, None, None, cert_reqs=ssl.CERT_NONE, tls_version=ssl.PROTOCOL_TLSv1_2, ciphers=None)
self.tls_insecure_set(True)
self.event_client_connected.clear()
self.loop_start()
self.connect(broker_host, broker_port, 60) # paho's keepalive
except Exception:
self.print_details(f'ENV_TEST_FAILURE: Unexpected error while connecting to broker {broker_host}')
raise
self.print_details(f'Connecting py-client to broker {broker_host}:{broker_port}...')
if not self.event_client_connected.wait(timeout=connect_timeout_seconds):
raise ValueError(
f'ENV_TEST_FAILURE: Test script cannot connect to broker: {broker_host} '
f'within {connect_timeout_seconds}s'
)
self.event_client_got_all.clear()
result, self.subscribe_mid = self.subscribe(self.config['subscribe_topic'], qos)
assert result == 0
return self
def __exit__(self, exc_type, exc_value, traceback): # type: (MqttPublisher, str, str, dict) -> None
self.disconnect()
self.loop_stop()
def get_configurations(dut: Dut, test_case: Any) -> Dict[str, Any]:
publish_cfg = {}
try:
@no_type_check
def get_config_from_dut(dut, config_option):
# logging.info('Option:', config_option, dut.app.sdkconfig.get(config_option))
value = re.search(r'\:\/\/([^:]+)\:([0-9]+)', dut.app.sdkconfig.get(config_option))
if value is None:
return None, None
return value.group(1), int(value.group(2))
# Get publish test configuration
publish_cfg['broker_host_ssl'], publish_cfg['broker_port_ssl'] = get_config_from_dut(
dut, 'EXAMPLE_BROKER_SSL_URI'
)
publish_cfg['broker_host_tcp'], publish_cfg['broker_port_tcp'] = get_config_from_dut(
dut, 'EXAMPLE_BROKER_TCP_URI'
)
publish_cfg['broker_host_ws'], publish_cfg['broker_port_ws'] = get_config_from_dut(dut, 'EXAMPLE_BROKER_WS_URI')
publish_cfg['broker_host_wss'], publish_cfg['broker_port_wss'] = get_config_from_dut(
dut, 'EXAMPLE_BROKER_WSS_URI'
)
except Exception:
logging.info('ENV_TEST_FAILURE: Some mandatory PUBLISH test case not found in sdkconfig')
raise
transport, qos, enqueue, scenario = test_case
if publish_cfg['broker_host_' + transport] is None:
pytest.skip(f'Skipping transport: {transport}...')
publish_cfg['scenario'] = scenario
publish_cfg['qos'] = qos
publish_cfg['enqueue'] = enqueue
publish_cfg['transport'] = transport
publish_cfg['pattern'] = ''.join(
random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(DEFAULT_MSG_SIZE)
)
publish_cfg['client_connect_timeout'] = 30
publish_cfg['dut_subscribe_timeout'] = 60
publish_cfg['publish_ack_timeout'] = 60
publish_cfg['test_timeout'] = get_timeout(test_case)
unique_topic = ''.join(
random.choice(string.ascii_uppercase + string.ascii_lowercase) for _ in range(DEFAULT_MSG_SIZE)
)
publish_cfg['subscribe_topic'] = 'test/subscribe_to/' + unique_topic
publish_cfg['publish_topic'] = 'test/subscribe_to/' + unique_topic
logging.info(f'configuration: {publish_cfg}')
return publish_cfg
@contextlib.contextmanager
def connected_and_subscribed(dut: Dut, config: Dict[str, Any]) -> Any:
dut.write('start')
dut_subscribe_timeout = config.get('dut_subscribe_timeout', 60)
dut.expect(re.compile(rb'MQTT_EVENT_SUBSCRIBED'), timeout=dut_subscribe_timeout)
yield
dut.write('stop')
def get_scenarios() -> List[Dict[str, int]]:
scenarios = []
# Initialize message sizes and repeat counts (if defined in the environment)
for i in count(0):
# Check env variable: MQTT_PUBLISH_MSG_{len|repeat}_{x}
env_dict = {var: 'MQTT_PUBLISH_MSG_' + var + '_' + str(i) for var in ['len', 'repeat']}
if os.getenv(env_dict['len']) and os.getenv(env_dict['repeat']):
scenarios.append({var: int(os.getenv(env_dict[var])) for var in ['len', 'repeat']}) # type: ignore
continue
break
if not scenarios: # No message sizes present in the env - set defaults
logging.info('Using predefined cases')
scenarios = [
{'msg_len': 0, 'nr_of_msgs': 5}, # zero-sized messages
{'msg_len': 2, 'nr_of_msgs': 5}, # short messages
{'msg_len': 200, 'nr_of_msgs': 3}, # long messages
]
return scenarios
def get_timeout(test_case: Any) -> int:
transport, qos, enqueue, scenario = test_case
timeout = int(scenario['nr_of_msgs'] * 20)
if qos == 1:
timeout += 30
if qos == 2:
timeout += 45
if transport in ['ws', 'wss']:
timeout += 30
return timeout
def run_publish_test_case(dut: Dut, config: Any) -> None:
logging.info(
f'Starting Publish test: transport:{config["transport"]}, qos:{config["qos"]},'
f'nr_of_msgs:{config["scenario"]["nr_of_msgs"]},'
f' msg_size:{config["scenario"]["msg_len"]}, enqueue:{config["enqueue"]}'
)
dut.write(
f'publish_setup {config["transport"]} {config["publish_topic"]}'
f' {config["subscribe_topic"]} {config["pattern"]} {config["scenario"]["msg_len"]}'
)
with MqttPublisher(config) as publisher, connected_and_subscribed(dut, config):
py_client_subscribe_timeout = config.get('py_client_subscribe_timeout', config['test_timeout'])
assert publisher.event_client_subscribed.wait(timeout=py_client_subscribe_timeout), 'Runner failed to subscribe'
msgs_published: List[mqtt.MQTTMessageInfo] = []
dut.write(f'publish {config["scenario"]["nr_of_msgs"]} {config["qos"]} {config["enqueue"]}')
assert publisher.event_client_got_all.wait(timeout=config['test_timeout']), (
f'Not all data received from ESP32: {config["transport"]} '
f'qos={config["qos"]} received: {publisher.received} '
f'expected: {config["scenario"]["nr_of_msgs"]}'
)
logging.info(' - all data received from ESP32')
payload = config['pattern'] * config['scenario']['msg_len']
for _ in range(config['scenario']['nr_of_msgs']):
with publisher.lock:
msg = publisher.publish(topic=config['publish_topic'], payload=payload, qos=config['qos'])
if config['qos'] > 0:
msgs_published.append(msg)
logging.info(f'Published: {len(msgs_published)} messages from script with QoS > 0 needing ACK.')
if msgs_published:
publish_ack_timeout_seconds = config.get('publish_ack_timeout', 60) # Default 60s, make configurable
ack_wait_start_time = time.time()
initial_unacked_count = len(msgs_published)
logging.info(f'Waiting {initial_unacked_count} publish ack with timeout {publish_ack_timeout_seconds}s...')
while msgs_published:
if time.time() - ack_wait_start_time > publish_ack_timeout_seconds:
unacked_mids = [msg.mid for msg in msgs_published if msg.mid is not None and not msg.is_published()]
logging.error(
f'Timeout waiting for publish acknowledgements. '
f'{len(unacked_mids)} of {initial_unacked_count} messages remain unacknowledged. '
f'Unacked MIDs: {unacked_mids}'
)
# This will likely cause the test to fail at a later assertion,
# or you could raise an explicit error here.
# e.g. raise Exception('Timeout waiting for publish acknowledgements')
break
msgs_published = [msg for msg in msgs_published if not msg.is_published()]
if msgs_published: # Avoid busy-looping if list is not empty
time.sleep(0.1) # Brief pause
if not msgs_published:
logging.info('All script-published QoS > 0 messages acknowledged by broker.')
logging.info('All messages from runner published (or timed out waiting for ACK).')
try:
dut.expect(re.compile(rb'Correct pattern received exactly x times'), timeout=config['test_timeout'])
except pexpect.exceptions.ExceptionPexpect:
dut.write('publish_report')
dut.expect(re.compile(rb'Test Report'), timeout=30)
raise
logging.info('ESP32 received all data from runner')
stress_scenarios = [{'msg_len': 20, 'nr_of_msgs': 30}] # many medium sized
transport_cases = ['tcp', 'ws', 'wss', 'ssl']
qos_cases = [0, 1, 2]
enqueue_cases = [0, 1]
local_broker_supported_transports = ['tcp']
local_broker_scenarios = [
{'msg_len': 0, 'nr_of_msgs': 5}, # zero-sized messages
{'msg_len': 5, 'nr_of_msgs': 20}, # short messages
{'msg_len': 500, 'nr_of_msgs': 10}, # long messages
{'msg_len': 20, 'nr_of_msgs': 20},
] # many medium sized
def make_cases(transport: Any, scenarios: List[Dict[str, int]]) -> List[Tuple[str, int, int, Dict[str, int]]]:
return [test_case for test_case in product(transport, qos_cases, enqueue_cases, scenarios)]
test_cases = make_cases(transport_cases, get_scenarios())
stress_test_cases = make_cases(transport_cases, stress_scenarios)
@pytest.mark.ethernet
@pytest.mark.parametrize('test_case', test_cases)
@pytest.mark.parametrize('config', ['default'], indirect=True)
@idf_parametrize('target', ['esp32'], indirect=['target'])
@pytest.mark.flaky(reruns=1, reruns_delay=1)
def test_mqtt_publish(dut: Dut, test_case: Any) -> None:
publish_cfg = get_configurations(dut, test_case)
dut.expect(re.compile(rb'mqtt>'), timeout=30)
dut.confirm_write('init', expect_pattern='init', timeout=30)
run_publish_test_case(dut, publish_cfg)
@pytest.mark.ethernet_stress
@pytest.mark.nightly_run
@pytest.mark.parametrize('test_case', stress_test_cases)
@pytest.mark.parametrize('config', ['default'], indirect=True)
@pytest.mark.flaky(reruns=1, reruns_delay=1)
@idf_parametrize('target', ['esp32'], indirect=['target'])
def test_mqtt_publish_stress(dut: Dut, test_case: Any) -> None:
publish_cfg = get_configurations(dut, test_case)
dut.expect(re.compile(rb'mqtt>'), timeout=30)
dut.write('init')
run_publish_test_case(dut, publish_cfg)
@pytest.mark.ethernet
@pytest.mark.parametrize('test_case', make_cases(local_broker_supported_transports, local_broker_scenarios))
@pytest.mark.parametrize('config', ['local_broker'], indirect=True)
@idf_parametrize('target', ['esp32'], indirect=['target'])
def test_mqtt_publish_local(dut: Dut, test_case: Any) -> None:
if test_case[0] not in local_broker_supported_transports:
pytest.skip(f'Skipping transport: {test_case[0]}...')
dut_ip = dut.expect(r'esp_netif_handlers: .+ ip: (\d+\.\d+\.\d+\.\d+),').group(1)
publish_cfg = get_configurations(dut, test_case)
publish_cfg['broker_host_tcp'] = dut_ip
publish_cfg['broker_port_tcp'] = 1234
dut.expect(re.compile(rb'mqtt>'), timeout=30)
dut.confirm_write('init', expect_pattern='init', timeout=30)
run_publish_test_case(dut, publish_cfg)

View File

@@ -1,20 +0,0 @@
CONFIG_EXAMPLE_BROKER_SSL_URI="mqtts://${EXAMPLE_MQTT_BROKER_SSL}"
CONFIG_EXAMPLE_BROKER_TCP_URI="mqtt://${EXAMPLE_MQTT_BROKER_TCP}"
CONFIG_EXAMPLE_BROKER_WS_URI="ws://${EXAMPLE_MQTT_BROKER_WS}/ws"
CONFIG_EXAMPLE_BROKER_WSS_URI="wss://${EXAMPLE_MQTT_BROKER_WSS}/ws"
CONFIG_EXAMPLE_BROKER_CERTIFICATE_OVERRIDE="${EXAMPLE_MQTT_BROKER_CERTIFICATE}"
CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y
CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384
CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=16384
CONFIG_ESP_TLS_INSECURE=y
CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY=y
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_ESP_NETIF_RECEIVE_REPORT_ERRORS=y
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
CONFIG_EXAMPLE_CONNECT_IPV6=y

View File

@@ -1,13 +0,0 @@
CONFIG_EXAMPLE_BROKER_SSL_URI=""
CONFIG_EXAMPLE_BROKER_TCP_URI="mqtt://127.0.0.1:1234"
CONFIG_EXAMPLE_BROKER_WS_URI=""
CONFIG_EXAMPLE_BROKER_WSS_URI=""
CONFIG_EXAMPLE_BROKER_CERTIFICATE_OVERRIDE=""
CONFIG_ESP_TLS_INSECURE=y
CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY=y
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_MQTT_USE_CUSTOM_CONFIG=y
CONFIG_MQTT_POLL_READ_TIMEOUT_MS=50
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
CONFIG_EXAMPLE_RUN_LOCAL_BROKER=y

View File

@@ -1,27 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAlUCywNhVv4RO2y9h/XGKZ1azzk3jzHpSBzIGO9LoiA8trC/p
1ykGaUfYPJllYK4HMhC4fUyE3J7tVL2Eskzl26LNPLbEoaBWZM9NhV3iA1/1EtOu
p6umLx+y3sDfvK35YAOUbjdAlBfhnJ4r8h7oTsxl3J5jZ18zgjJnJi2NEFq/yTpO
MiwHLWPjy25fDFixfV9UzSvbgt1JaGPmC7c4QkhHzjyp0+ikuvRIw0p9BBNeqBV2
da3qBMB5FtodUJTAz6o6OKWbTalLjQi6C1H6z9TnY7IrJBUOy/FWkQH/sEsLdscD
hHa1Dz2oT203QjhzyOSfnNF95D/1MdNcMt6l0wIDAQABAoIBAC1JJTOoMFRc48RT
myrYQYNbZlEphv3q+2qdfhC2zMFDwbrmCtCy7PQSzYSNkpoEE8DYG/JAvmtmeWJl
4pZrCK9ctWM/nWfhC3WpBL97nfEiM20T94F+bn0L5Cz8XqaULv839th+QUTt/hGU
WIctY5VNJXcMQ+MAmtNdUbjex1d3iuxiKHUo4nDoZ8digKFNdtdP5B5nlMq5chCL
mxNRcsGsx2dDAxbGUapdTVPWHPJKpLOBoSkluDsfd2KZADFU2R1SJpAX9+RYh3HM
5FTUdHTUaISxbKkgeDKlEM0lqk2TtGUwCyEj098ewi7Wzsu9w60IplPPUJx5FRG6
jp3wzLkCgYEAxKp5T20rf/7ysX7x053I7VCjDXUxAaWOEj1uS3AhOkl0NaZg7Di+
y53fWNkcHdkt2n2LqMt/43UgMYq3TVVcq2eunPNF11e1bJw8CjDafwDs4omwwyVn
lYhPuB4dK2OAib+vU5Zqpp0kZMoxk2MZVgon8z+s8DW/zmB6aFqAWeUCgYEAwkhC
OgmXKMdjOCVy5t2f5UbY8Y9rV3w8eUATuJ47MMwLr4pGYnKoEn9JB4ltWrHv/u5S
fOv3tIrrCEvnCoCbOILwCsY5LqTNXgqova8FB6RpMUQCzhDd8LHuvdHv0WMnMzX1
3PKuqwh8JS55m4WqZRhzr5BFKG4fHPVs4IcaJVcCgYAzzCaJSdqUKqTnJOUydDNQ
ddWMHNqccWs62J0tF0pZHLGT089hSAzQejMyJnSmU+Ykzr4y5e44DUg+ZCelIZ93
saYmxlgVwI8THQ8fLADQRIEfpV4996MRmkZM2vmZzOo03Zyi6lIKsga82Rg3lnk8
1Q3ynknBNpbfF0AGLhfyFQKBgBYlxJ73HutAJ5hr9HhLBYJOnEaVUehMOlycKGNg
bmD2sdJWEgYBChXpurqIORYguLo4EuE4ySkkuPxeIr14wbkkfBbOWBBwKxUwY+IT
xKAFZxR9q1AwbgyVTCEJgKw/AGX/HcMNS0omEnjunmBTUYRq0C1QZgHg490aQUor
PJjLAoGAevzdTpFlVeuKeYh1oDubGO1LinyXpBv7fPFjl+zu4AVbjojcU6yC4OO6
QvqopE6SyAECKy8kAOFcESPsGc9Lta2XUvI203z7pIVlNVEcJ0+90mQh3Mn1U46l
sZ49PdRvNwNb5wvkh1UqNsMlGFbRlzMbIk45ou4311kCobowZek=
-----END RSA PRIVATE KEY-----

View File

@@ -1,17 +0,0 @@
# The following four lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
idf_build_set_property(MINIMAL_BUILD ON)
list(APPEND EXTRA_COMPONENT_DIRS
"$ENV{IDF_PATH}/tools/mocks/esp_hw_support/"
"$ENV{IDF_PATH}/tools/mocks/freertos/"
"$ENV{IDF_PATH}/tools/mocks/esp_timer/"
"$ENV{IDF_PATH}/tools/mocks/esp_event/"
"$ENV{IDF_PATH}/tools/mocks/lwip/"
"$ENV{IDF_PATH}/tools/mocks/esp-tls/"
"$ENV{IDF_PATH}/tools/mocks/http_parser/"
"$ENV{IDF_PATH}/tools/mocks/tcp_transport/")
project(host_mqtt_client_test)

View File

@@ -1,30 +0,0 @@
| Supported Targets | Linux |
| ----------------- | ----- |
# Description
This directory contains test code for the mqtt client that runs on host.
Tests are written using [Catch2](https://github.com/catchorg/Catch2) test framework
# Build
Tests build regularly like an idf project.
```
idf.py build
```
# Run
The build produces an executable in the build folder.
Just run:
```
./build/host_mqtt_client_test.elf
```
The test executable have some options provided by the test framework.

View File

@@ -1,21 +0,0 @@
idf_component_register(SRCS "test_mqtt_client.cpp"
REQUIRES cmock mqtt esp_timer esp_hw_support http_parser log
WHOLE_ARCHIVE)
target_compile_options(${COMPONENT_LIB} PUBLIC -fsanitize=address -Wno-missing-field-initializers)
target_link_options(${COMPONENT_LIB} PUBLIC -fsanitize=address)
target_link_libraries(${COMPONENT_LIB} PUBLIC Catch2::Catch2WithMain)
idf_component_get_property(mqtt mqtt COMPONENT_LIB)
target_compile_definitions(${mqtt} PRIVATE SOC_WIFI_SUPPORTED=1)
target_compile_options(${mqtt} PUBLIC -fsanitize=address)
target_link_options(${mqtt} PUBLIC -fsanitize=address)
if(CONFIG_GCOV_ENABLED)
target_compile_options(${COMPONENT_LIB} PUBLIC --coverage -fprofile-arcs -ftest-coverage)
target_link_options(${COMPONENT_LIB} PUBLIC --coverage -fprofile-arcs -ftest-coverage)
idf_component_get_property(mqtt mqtt COMPONENT_LIB)
target_compile_options(${mqtt} PUBLIC --coverage -fprofile-arcs -ftest-coverage)
target_link_options(${mqtt} PUBLIC --coverage -fprofile-arcs -ftest-coverage)
endif()

View File

@@ -1,9 +0,0 @@
menu "Host-test config"
config GCOV_ENABLED
bool "Coverage analyzer"
default n
help
Enables coverage analyzing for host tests.
endmenu

View File

@@ -1,9 +0,0 @@
## IDF Component Manager Manifest File
dependencies:
espressif/catch2: "^3.5.2"
espressif/mqtt:
version: "*"
override_path: "../../.."
## Required IDF version
idf:
version: ">=5.0.0"

View File

@@ -1,171 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <algorithm>
#include <memory>
#include <net/if.h>
#include <random>
#include <string_view>
#include <type_traits>
#include "esp_transport.h"
#include <catch2/catch_test_macros.hpp>
#include "mqtt_client.h"
extern "C" {
#include "Mockesp_event.h"
#include "Mockesp_mac.h"
#include "Mockesp_transport.h"
#include "Mockesp_transport_ssl.h"
#include "Mockesp_transport_tcp.h"
#include "Mockesp_transport_ws.h"
#include "Mockevent_groups.h"
#include "Mockhttp_parser.h"
#include "Mockqueue.h"
#include "Mocktask.h"
#if __has_include ("Mockidf_additions.h")
/* Some functions were moved from "task.h" to "idf_additions.h" */
#include "Mockidf_additions.h"
#endif
#include "Mockesp_timer.h"
/*
* The following functions are not directly called but the generation of them
* from cmock is broken, so we need to define them here.
*/
esp_err_t esp_tls_get_and_clear_last_error(esp_tls_error_handle_t h, int *esp_tls_code, int *esp_tls_flags)
{
return ESP_OK;
}
}
auto random_string(std::size_t n)
{
static constexpr std::string_view char_set = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456790";
std::string str;
std::sample(char_set.begin(), char_set.end(), std::back_inserter(str), n,
std::mt19937 {std::random_device{}()});
return str;
}
using unique_mqtt_client = std::unique_ptr < std::remove_pointer_t<esp_mqtt_client_handle_t>, decltype([](esp_mqtt_client_handle_t client)
{
esp_mqtt_client_destroy(client);
}) >;
SCENARIO("MQTT Client Operation")
{
// Set expectations for the mocked calls.
int mtx = 0;
int transport_list = 0;
int transport = 0;
int event_group = 0;
uint8_t mac[] = {0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55};
esp_timer_get_time_IgnoreAndReturn(0);
xQueueTakeMutexRecursive_IgnoreAndReturn(true);
xQueueGiveMutexRecursive_IgnoreAndReturn(true);
xQueueCreateMutex_ExpectAnyArgsAndReturn(
reinterpret_cast<QueueHandle_t>(&mtx));
xEventGroupCreate_IgnoreAndReturn(reinterpret_cast<EventGroupHandle_t>(&event_group));
esp_transport_list_init_IgnoreAndReturn(reinterpret_cast<esp_transport_list_handle_t>(&transport_list));
esp_transport_tcp_init_IgnoreAndReturn(reinterpret_cast<esp_transport_handle_t>(&transport));
esp_transport_ssl_init_IgnoreAndReturn(reinterpret_cast<esp_transport_handle_t>(&transport));
esp_transport_ws_init_IgnoreAndReturn(reinterpret_cast<esp_transport_handle_t>(&transport));
esp_transport_ws_set_subprotocol_IgnoreAndReturn(ESP_OK);
esp_transport_list_add_IgnoreAndReturn(ESP_OK);
esp_transport_set_default_port_IgnoreAndReturn(ESP_OK);
http_parser_url_init_Ignore();
esp_event_loop_create_IgnoreAndReturn(ESP_OK);
esp_read_mac_IgnoreAndReturn(ESP_OK);
esp_read_mac_ReturnThruPtr_mac(mac);
esp_transport_list_destroy_IgnoreAndReturn(ESP_OK);
esp_transport_destroy_IgnoreAndReturn(ESP_OK);
vEventGroupDelete_Ignore();
vQueueDelete_Ignore();
GIVEN("An a minimal config") {
esp_mqtt_client_config_t config{};
config.broker.address.uri = "mqtt://1.1.1.1";
struct http_parser_url ret_uri = {
.field_set = 1 | (1 << 1),
.port = 0,
.field_data = { { 0, 4 } /*mqtt*/, { 7, 1 } } // at least *scheme* and *host*
};
http_parser_parse_url_ExpectAnyArgsAndReturn(0);
http_parser_parse_url_ReturnThruPtr_u(&ret_uri);
xTaskCreatePinnedToCore_ExpectAnyArgsAndReturn(pdTRUE);
SECTION("Client with minimal config") {
auto client = unique_mqtt_client{esp_mqtt_client_init(&config)};
REQUIRE(client != nullptr);
SECTION("User will set a new uri") {
struct http_parser_url ret_uri = {
.field_set = 1,
.port = 0,
.field_data = { { 0, 1} }
};
SECTION("User set a correct URI") {
http_parser_parse_url_StopIgnore();
http_parser_parse_url_ExpectAnyArgsAndReturn(0);
http_parser_parse_url_ReturnThruPtr_u(&ret_uri);
auto res = esp_mqtt_client_set_uri(client.get(), " ");
REQUIRE(res == ESP_OK);
}
SECTION("Incorrect URI from user") {
http_parser_parse_url_StopIgnore();
http_parser_parse_url_ExpectAnyArgsAndReturn(1);
http_parser_parse_url_ReturnThruPtr_u(&ret_uri);
auto res = esp_mqtt_client_set_uri(client.get(), " ");
REQUIRE(res == ESP_FAIL);
}
}
SECTION("User set interface to use"){
http_parser_parse_url_ExpectAnyArgsAndReturn(0);
http_parser_parse_url_ReturnThruPtr_u(&ret_uri);
struct ifreq if_name = {};
strncpy(if_name.ifr_name, "custom", IFNAMSIZ - 1);
if_name.ifr_name[IFNAMSIZ - 1] = '\0';;
config.network.if_name = &if_name;
SECTION("Client is not started"){
REQUIRE(esp_mqtt_set_config(client.get(), &config)== ESP_OK);
}
}
SECTION("After Start Client Is Cleanly destroyed") {
REQUIRE(esp_mqtt_client_start(client.get()) == ESP_OK);
// Only need to start the client, destroy is called automatically at the end of
// scope
}
}
SECTION("Client with all allocating configuration set") {
auto host = random_string(20);
auto path = random_string(10);
auto username = random_string(10);
auto client_id = random_string(10);
auto password = random_string(10);
auto lw_topic = random_string(10);
auto lw_msg = random_string(10);
config.broker = {.address = {
.hostname = host.data(),
.path = path.data()
}
};
config.credentials = {
.username = username.data(),
.client_id = client_id.data(),
.authentication = {
.password = password.data()
}
};
config.session = {
.last_will {
.topic = lw_topic.data(),
.msg = lw_msg.data()
}
};
auto client = unique_mqtt_client{esp_mqtt_client_init(&config)};
REQUIRE(client != nullptr);
}
}
}

View File

@@ -1,71 +0,0 @@
/*
* SPDX-FileCopyrightText: 1991-1993 The Regents of the University of California
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#pragma once
/* Implementation from BSD headers*/
#define QMD_SAVELINK(name, link) void **name = (void *)&(link)
#define TRASHIT(x) do {(x) = (void *)-1;} while (0)
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
#define STAILQ_FIRST(head) ((head)->stqh_first)
#define STAILQ_HEAD(name, type) \
struct name { \
struct type *stqh_first;/* first element */ \
struct type **stqh_last;/* addr of last next element */ \
}
#define STAILQ_ENTRY(type) \
struct { \
struct type *stqe_next; /* next element */ \
}
#define STAILQ_INSERT_TAIL(head, elm, field) do { \
STAILQ_NEXT((elm), field) = NULL; \
*(head)->stqh_last = (elm); \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
} while (0)
#define STAILQ_INIT(head) do { \
STAILQ_FIRST((head)) = NULL; \
(head)->stqh_last = &STAILQ_FIRST((head)); \
} while (0)
#define STAILQ_FOREACH(var, head, field) \
for((var) = STAILQ_FIRST((head)); \
(var); \
(var) = STAILQ_NEXT((var), field))
#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = STAILQ_FIRST((head)); \
(var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#define STAILQ_REMOVE_AFTER(head, elm, field) do { \
if ((STAILQ_NEXT(elm, field) = \
STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
} while (0)
#define STAILQ_REMOVE_HEAD(head, field) do { \
if ((STAILQ_FIRST((head)) = \
STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \
(head)->stqh_last = &STAILQ_FIRST((head)); \
} while (0)
#define STAILQ_REMOVE(head, elm, type, field) do { \
QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \
if (STAILQ_FIRST((head)) == (elm)) { \
STAILQ_REMOVE_HEAD((head), field); \
} \
else { \
struct type *curelm = STAILQ_FIRST((head)); \
while (STAILQ_NEXT(curelm, field) != (elm)) \
curelm = STAILQ_NEXT(curelm, field); \
STAILQ_REMOVE_AFTER(head, curelm, field); \
} \
TRASHIT(*oldnext); \
} while (0)

View File

@@ -1,6 +0,0 @@
CONFIG_IDF_TARGET="linux"
CONFIG_COMPILER_CXX_EXCEPTIONS=y
CONFIG_COMPILER_CXX_RTTI=y
CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=0
CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n