Reorganize mqtt build structure

- Integrate build definitions from idf
- Changes CMakeLists to allow import
- Added host test from idf
- Added test code from idf
This commit is contained in:
Euripedes Rocha
2022-10-17 12:21:52 +02:00
parent f27cb47c0f
commit 159b1638b2
28 changed files with 56 additions and 1408 deletions

17
host_test/CMakeLists.txt Normal file
View File

@@ -0,0 +1,17 @@
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(COMPONENTS main)
list(APPEND EXTRA_COMPONENT_DIRS
"mocks/heap/"
"$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)

30
host_test/README.md Normal file
View File

@@ -0,0 +1,30 @@
| 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

@@ -0,0 +1,3 @@
idf_component_register(SRCS "test_mqtt_client.cpp"
INCLUDE_DIRS "$ENV{IDF_PATH}/tools/catch"
REQUIRES cmock mqtt esp_timer esp_hw_support http_parser log)

View File

@@ -0,0 +1,126 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#define CATCH_CONFIG_MAIN // This tells the catch header to generate a main
#include "catch.hpp"
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"
#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;
}
}
#include "mqtt_client.h"
struct ClientInitializedFixture {
esp_mqtt_client_handle_t client;
ClientInitializedFixture()
{
[[maybe_unused]] auto protect = TEST_PROTECT();
int mtx;
int transport_list;
int transport;
int event_group;
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_parse_url_IgnoreAndReturn(0);
http_parser_url_init_ExpectAnyArgs();
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);
vEventGroupDelete_Ignore();
vQueueDelete_Ignore();
esp_mqtt_client_config_t config{};
client = esp_mqtt_client_init(&config);
}
~ClientInitializedFixture()
{
esp_mqtt_client_destroy(client);
}
};
TEST_CASE_METHOD(ClientInitializedFixture, "Client set 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, " ");
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, " ");
REQUIRE(res == ESP_FAIL);
}
}
TEST_CASE_METHOD(ClientInitializedFixture, "Client Start")
{
SECTION("Successful start") {
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_StopIgnore();
http_parser_parse_url_ExpectAnyArgsAndReturn(0);
http_parser_parse_url_ReturnThruPtr_u(&ret_uri);
xTaskCreatePinnedToCore_ExpectAnyArgsAndReturn(pdTRUE);
auto res = esp_mqtt_set_config(client, &config);
REQUIRE(res == ESP_OK);
res = esp_mqtt_client_start(client);
REQUIRE(res == ESP_OK);
}
SECTION("Failed on initialization") {
xTaskCreatePinnedToCore_ExpectAnyArgsAndReturn(pdFALSE);
auto res = esp_mqtt_client_start(nullptr);
REQUIRE(res == ESP_ERR_INVALID_ARG);
}
SECTION("Client already started") {}
SECTION("Failed to start task") {
xTaskCreatePinnedToCore_ExpectAnyArgsAndReturn(pdFALSE);
auto res = esp_mqtt_client_start(client);
REQUIRE(res == ESP_FAIL);
}
}

View File

@@ -0,0 +1,4 @@
idf_component_get_property(original_heap_dir heap COMPONENT_OVERRIDEN_DIR)
idf_component_register(SRCS heap_mock.c
INCLUDE_DIRS "${original_heap_dir}/include")

View File

@@ -0,0 +1,11 @@
#include "esp_heap_caps.h"
#include <stdint.h>
#include <stdlib.h>
void *heap_caps_calloc(size_t n, size_t size, uint32_t caps) {
(void)caps;
return calloc(n, size);
}

View File

@@ -0,0 +1,66 @@
#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

@@ -0,0 +1,6 @@
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_NONE=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n