From 93158d5d1819da943f296daeec0f2f73a71f313a Mon Sep 17 00:00:00 2001 From: Euripedes Rocha Filho Date: Tue, 16 Feb 2021 15:47:10 +0000 Subject: [PATCH] mqtt: Adds host tests for mqtt client --- components/mqtt/CMakeLists.txt | 132 +++++++++++- components/mqtt/host_test/CMakeLists.txt | 6 + components/mqtt/host_test/README.md | 27 +++ components/mqtt/host_test/main/CMakeLists.txt | 3 + .../mqtt/host_test/main/test_mqtt_client.cpp | 109 ++++++++++ components/mqtt/host_test/mocks/config.yaml | 23 ++ .../mocks/include/freertos/FreeRTOSConfig.h | 133 ++++++++++++ .../mocks/include/freertos/portmacro.h | 199 ++++++++++++++++++ .../host_test/mocks/include/machine/endian.h | 2 + .../mqtt/host_test/mocks/include/sys/queue.h | 66 ++++++ components/mqtt/host_test/sdkconfig.defaults | 6 + 11 files changed, 705 insertions(+), 1 deletion(-) create mode 100644 components/mqtt/host_test/CMakeLists.txt create mode 100644 components/mqtt/host_test/README.md create mode 100644 components/mqtt/host_test/main/CMakeLists.txt create mode 100644 components/mqtt/host_test/main/test_mqtt_client.cpp create mode 100644 components/mqtt/host_test/mocks/config.yaml create mode 100644 components/mqtt/host_test/mocks/include/freertos/FreeRTOSConfig.h create mode 100644 components/mqtt/host_test/mocks/include/freertos/portmacro.h create mode 100644 components/mqtt/host_test/mocks/include/machine/endian.h create mode 100644 components/mqtt/host_test/mocks/include/sys/queue.h create mode 100644 components/mqtt/host_test/sdkconfig.defaults diff --git a/components/mqtt/CMakeLists.txt b/components/mqtt/CMakeLists.txt index 1c30e3a..e88c582 100644 --- a/components/mqtt/CMakeLists.txt +++ b/components/mqtt/CMakeLists.txt @@ -4,4 +4,134 @@ idf_component_register(SRCS "esp-mqtt/mqtt_client.c" "esp-mqtt/lib/platform_esp32_idf.c" INCLUDE_DIRS esp-mqtt/include PRIV_INCLUDE_DIRS "esp-mqtt/lib/include" - REQUIRES lwip nghttp mbedtls tcp_transport) + ) + +if(TEST_BUILD) +message(STATUS "building MOCKS") +idf_component_get_property(tcp_transport_dir tcp_transport COMPONENT_DIR) +idf_component_get_property(esp_hw_support_dir esp_hw_support COMPONENT_DIR) +idf_component_get_property(esp_event_dir esp_event COMPONENT_DIR) +idf_component_get_property(log_dir log COMPONENT_DIR) +idf_component_get_property(freertos_dir freertos COMPONENT_DIR) +idf_component_get_property(nghttp_dir nghttp COMPONENT_DIR) +idf_component_get_property(esp_wifi_dir esp_wifi COMPONENT_DIR) +idf_component_get_property(esp_hw_support_dir esp_hw_support COMPONENT_DIR) +idf_component_get_property(esp_tls_dir esp-tls COMPONENT_DIR) +idf_component_get_property(esp_netif_dir esp_netif COMPONENT_DIR) +idf_component_get_property(esp_common_dir esp_common COMPONENT_DIR) +idf_component_get_property(esp_rom_dir esp_rom COMPONENT_DIR) +idf_component_get_property(esp_system_dir esp_system COMPONENT_DIR) +idf_component_get_property(mbedtls_dir mbedtls COMPONENT_DIR) + + idf_component_get_property(cmock_lib cmock COMPONENT_LIB) + set(IDF_PATH $ENV{IDF_PATH}) + set(CMOCK_DIR "${IDF_PATH}/components/cmock/CMock") + set(MOCK_GEN_DIR "${CMAKE_CURRENT_BINARY_DIR}/mocks") + set(ENV{UNITY_DIR} "$ENV{IDF_PATH}/components/cmock/CMock") + file(MAKE_DIRECTORY ${MOCK_GEN_DIR}) + + set(MOCK_OUTPUT + "${MOCK_GEN_DIR}/Mockesp_transport.c" "${MOCK_GEN_DIR}/Mockesp_transport.h" + "${MOCK_GEN_DIR}/Mockesp_transport_ssl.c" "${MOCK_GEN_DIR}/Mockesp_transport_ssl.h" + "${MOCK_GEN_DIR}/Mockesp_transport_ws.c" "${MOCK_GEN_DIR}/Mockesp_transport_ws.h" + "${MOCK_GEN_DIR}/Mockesp_transport_tcp.c" "${MOCK_GEN_DIR}/Mockesp_transport_tcp.h" + "${MOCK_GEN_DIR}/Mockesp_event.c" "${MOCK_GEN_DIR}/Mockesp_event.h" + "${MOCK_GEN_DIR}/Mockesp_mac.c" "${MOCK_GEN_DIR}/Mockesp_mac.h" + "${MOCK_GEN_DIR}/Mockesp_random.c" "${MOCK_GEN_DIR}/Mockesp_random.h" + "${MOCK_GEN_DIR}/Mockesp_system.c" "${MOCK_GEN_DIR}/Mockesp_system.h" + "${MOCK_GEN_DIR}/Mockesp_tls.c" "${MOCK_GEN_DIR}/Mockesp_tls.h" + "${MOCK_GEN_DIR}/Mockevent_groups.c" "${MOCK_GEN_DIR}/Mockevent_groups.h" + "${MOCK_GEN_DIR}/Mockqueue.c" "${MOCK_GEN_DIR}/Mockqueue.h" + "${MOCK_GEN_DIR}/Mocktask.c" "${MOCK_GEN_DIR}/Mocktask.h" + "${MOCK_GEN_DIR}/Mockesp_log.c" "${MOCK_GEN_DIR}/Mockesp_log.h" + "${MOCK_GEN_DIR}/Mockhttp_parser.c" "${MOCK_GEN_DIR}/Mockhttp_parser.h" + ) + + set(HEADERS_TO_MOCK + ${tcp_transport_dir}/include/esp_transport_tcp.h + ${tcp_transport_dir}/include/esp_transport_ws.h + ${tcp_transport_dir}/include/esp_transport_ssl.h + ${tcp_transport_dir}/include/esp_transport.h + ${esp_event_dir}/include/esp_event.h + ${esp_hw_support_dir}/include/esp_mac.h + ${esp_hw_support_dir}/include/esp_random.h + ${esp_system_dir}/include/esp_system.h + ${esp_tls_dir}/esp_tls.h + ${freertos_dir}/include/freertos/queue.h + ${freertos_dir}/include/freertos/task.h + ${freertos_dir}/include/freertos/event_groups.h + ${log_dir}/include/esp_log.h + ${nghttp_dir}/port/include/http_parser.h + ) + + set(srcs + ${MOCK_GEN_DIR}/Mockesp_transport.c + ${MOCK_GEN_DIR}/Mockesp_transport_ws.c + ${MOCK_GEN_DIR}/Mockesp_transport_ssl.c + ${MOCK_GEN_DIR}/Mockesp_transport_tcp.c + ${MOCK_GEN_DIR}/Mockesp_transport_tcp.c + ${MOCK_GEN_DIR}/Mockesp_event.c + ${MOCK_GEN_DIR}/Mockesp_mac.c + ${MOCK_GEN_DIR}/Mockesp_random.c + ${MOCK_GEN_DIR}/Mockesp_system.c + ${MOCK_GEN_DIR}/Mockesp_tls.c + ${MOCK_GEN_DIR}/Mockesp_log.c + ${MOCK_GEN_DIR}/Mockhttp_parser.c + ${MOCK_GEN_DIR}/Mockevent_groups.c + ${MOCK_GEN_DIR}/Mockqueue.c + ${MOCK_GEN_DIR}/Mocktask.c + ) + + add_custom_command( + OUTPUT ruby_found SYMBOLIC + COMMAND "ruby" "-v" + COMMENT "Try to find ruby. If this fails, you need to install ruby" + ) + + add_custom_command( + OUTPUT ${MOCK_OUTPUT} + DEPENDS ruby_found + COMMAND ${CMAKE_COMMAND} -E env "UNITY_DIR=${IDF_PATH}/components/unity/unity" + ruby + ${CMOCK_DIR}/lib/cmock.rb + -o${CMAKE_CURRENT_SOURCE_DIR}/host_test/mocks/config.yaml + ${HEADERS_TO_MOCK} + ) + + add_library(mocks ${srcs}) + target_include_directories(mocks PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/host_test/mocks/include + ${tcp_transport_dir}/include + ${esp_tls_dir} + ${freertos_dir}/include + ${esp_event_dir}/include + ${esp_system_dir}/include + ${esp_common_dir}/include + ${esp_wifi_dir}/include + ${esp_hw_support_dir}/include + ${esp_netif_dir}/include + ${log_dir}/include + ${esp_rom_dir}/include + ${mbedtls_dir}/port/include + ${nghttp_dir}/port/include + ${mbedtls_dir}/mbedtls/include + ${freertos_dir}/include/freertos + esp-mqtt/lib/include + ${MOCK_GEN_DIR} + ) + target_link_libraries(mocks PUBLIC ${cmock_lib}) + target_compile_definitions(mocks PUBLIC + CONFIG_LOG_MAXIMUM_LEVEL=5 + CONFIG_LOG_DEFAULT_LEVEL=3 + CONFIG_ESP_TLS_USING_MBEDTLS + CONFIG_ESP_TLS_SERVER + CONFIG_LOG_TIMESTAMP_SOURCE_RTOS) + target_link_options(${COMPONENT_LIB} INTERFACE -fsanitize=address) + + target_link_libraries(${COMPONENT_LIB} PUBLIC mocks) + +else() + idf_component_get_property(nghttp_lib nghttp COMPONENT_LIB) + idf_component_get_property(tcp_transport_lib tcp_transport COMPONENT_LIB) + target_link_libraries(${COMPONENT_LIB} PUBLIC ${nghttp_lib} ${tcp_transport_lib}) +endif() diff --git a/components/mqtt/host_test/CMakeLists.txt b/components/mqtt/host_test/CMakeLists.txt new file mode 100644 index 0000000..312ad1e --- /dev/null +++ b/components/mqtt/host_test/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +set(COMPONENTS main) +option(TEST_BUILD "" ON) +project(host_mqtt_client_test) diff --git a/components/mqtt/host_test/README.md b/components/mqtt/host_test/README.md new file mode 100644 index 0000000..071cd94 --- /dev/null +++ b/components/mqtt/host_test/README.md @@ -0,0 +1,27 @@ +# 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. + + diff --git a/components/mqtt/host_test/main/CMakeLists.txt b/components/mqtt/host_test/main/CMakeLists.txt new file mode 100644 index 0000000..c89e9bf --- /dev/null +++ b/components/mqtt/host_test/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "test_mqtt_client.cpp" + INCLUDE_DIRS "$ENV{IDF_PATH}/tools/catch" + REQUIRES cmock mqtt) diff --git a/components/mqtt/host_test/main/test_mqtt_client.cpp b/components/mqtt/host_test/main/test_mqtt_client.cpp new file mode 100644 index 0000000..51ef9cf --- /dev/null +++ b/components/mqtt/host_test/main/test_mqtt_client.cpp @@ -0,0 +1,109 @@ +#define CATCH_CONFIG_MAIN // This tells the catch header to generate a main +#include "catch.hpp" +#include "mqtt_client.h" + +extern "C" { +#include "Mockesp_event.h" +#include "Mockesp_log.h" +#include "Mockesp_system.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" + + /* + * The following functions are not directly called but the generation of them + * from cmock is broken, so we need to define them here. + */ + BaseType_t xQueueTakeMutexRecursive(QueueHandle_t xMutex, + TickType_t xTicksToWait) + { + return 0; + } + BaseType_t xQueueGiveMutexRecursive(QueueHandle_t xMutex) + { + return 0; + } +} + +struct ClientInitializedFixture { + esp_mqtt_client_handle_t client; + ClientInitializedFixture() + { + TEST_PROTECT(); + int mtx; + int transport_list; + int transport; + int event_group; + uint8_t mac[] = {0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55}; + esp_log_write_Ignore(); + xQueueCreateMutex_ExpectAnyArgsAndReturn( + reinterpret_cast(&mtx)); + xEventGroupCreate_IgnoreAndReturn(reinterpret_cast(&event_group)); + esp_log_timestamp_IgnoreAndReturn(0); + esp_transport_list_init_IgnoreAndReturn(reinterpret_cast(&transport_list)); + esp_transport_tcp_init_IgnoreAndReturn(reinterpret_cast(&transport)); + esp_transport_ssl_init_IgnoreAndReturn(reinterpret_cast(&transport)); + esp_transport_ws_init_IgnoreAndReturn(reinterpret_cast(&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; + 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") { + xTaskCreatePinnedToCore_ExpectAnyArgsAndReturn(pdTRUE); + auto 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); + } +} diff --git a/components/mqtt/host_test/mocks/config.yaml b/components/mqtt/host_test/mocks/config.yaml new file mode 100644 index 0000000..8fc80e9 --- /dev/null +++ b/components/mqtt/host_test/mocks/config.yaml @@ -0,0 +1,23 @@ + :cmock: + :plugins: + - expect + - expect_any_args + - return_thru_ptr + - ignore + - array + - callback + :includes_h_pre_orig_header: + - FreeRTOS.h + - net/if.h + :strippables: + - '(?:__attribute__\s*\(+.*?\)+)' + - '(?:vQueueAddToRegistry\s*\(+.*?\)+)' + - '(?:vQueueUnregisterQueue\s*\(+.*?\)+)' + - '(?:pcQueueGetName\s*\(+.*?\)+)' + - '(?:xQueueTakeMutexRecursive\s*\(+.*?\)+)' + - '(?:xQueueGiveMutexRecursive\s*\(+.*?\)+)' + - '(?:vTaskSetThreadLocalStoragePointerAndDelCallback\s*\(+.*?\)+)' + - '(?:esp_log_writev\s*\(+.*?\)+)' + - '(?:esp_restart\s*\(+.*?\)+)' + - '(?:esp_system_abort\s*\(+.*?\)+)' + - PRIVILEGED_FUNCTION diff --git a/components/mqtt/host_test/mocks/include/freertos/FreeRTOSConfig.h b/components/mqtt/host_test/mocks/include/freertos/FreeRTOSConfig.h new file mode 100644 index 0000000..0492f81 --- /dev/null +++ b/components/mqtt/host_test/mocks/include/freertos/FreeRTOSConfig.h @@ -0,0 +1,133 @@ +/* + FreeRTOS V8.2.0 - Copyright (C) 2015 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +#include "esp_attr.h" + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * See http://www.freertos.org/a00110.html. + *----------------------------------------------------------*/ + +#define configUSE_PREEMPTION 1 +#define configUSE_IDLE_HOOK 1 +#define configUSE_TICK_HOOK 1 +#define configTICK_RATE_HZ ((TickType_t)1000) +#define configMINIMAL_STACK_SIZE ((unsigned short)256) /* This can be made smaller if required. */ +#define configTOTAL_HEAP_SIZE ((size_t)(32 * 1024)) +#define configMAX_TASK_NAME_LEN (16) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 1 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_CO_ROUTINES 1 +#define configUSE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configCHECK_FOR_STACK_OVERFLOW 0 /* Do not use this option on the PC port. */ +#define configUSE_APPLICATION_TASK_TAG 1 +#define configQUEUE_REGISTRY_SIZE 0 + +#define configMAX_PRIORITIES (10) +#define configMAX_CO_ROUTINE_PRIORITIES (2) + +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. */ + +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 1 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 0 /* Do not use this option on the PC port. */ + +/* This demo makes use of one or more example stats formatting functions. These +format the raw data provided by the uxTaskGetSystemState() function in to human +readable ASCII form. See the notes in the implementation of vTaskList() within +FreeRTOS/Source/tasks.c for limitations. */ +#define configUSE_STATS_FORMATTING_FUNCTIONS 1 + +/* An example "task switched in" hook macro definition. */ +#define traceTASK_SWITCHED_IN() xTaskCallApplicationTaskHook(NULL, (void*)0xabcd) + +extern void vMainQueueSendPassed(void); +#define traceQUEUE_SEND(pxQueue) vMainQueueSendPassed() + +#endif /* FREERTOS_CONFIG_H */ diff --git a/components/mqtt/host_test/mocks/include/freertos/portmacro.h b/components/mqtt/host_test/mocks/include/freertos/portmacro.h new file mode 100644 index 0000000..67ce5f0 --- /dev/null +++ b/components/mqtt/host_test/mocks/include/freertos/portmacro.h @@ -0,0 +1,199 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ +#ifndef PORTMACRO_H +#define PORTMACRO_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __ASSEMBLER__ + +/*----------------------------------------------------------- + * Port specific definitions. + * + * The settings in this file configure FreeRTOS correctly for the + * given hardware and compiler. + * + * These settings should not be altered. + *----------------------------------------------------------- + */ + +/* Type definitions. */ +#define portCHAR uint8_t +#define portFLOAT float +#define portDOUBLE double +#define portLONG int32_t +#define portSHORT int16_t +#define portSTACK_TYPE uint8_t +#define portBASE_TYPE int +// interrupt module will mask interrupt with priority less than threshold +#define RVHAL_EXCM_LEVEL 4 + +typedef portSTACK_TYPE StackType_t; +typedef portBASE_TYPE BaseType_t; +typedef unsigned portBASE_TYPE UBaseType_t; + +#if (configUSE_16_BIT_TICKS == 1) +typedef uint16_t TickType_t; +#define portMAX_DELAY (TickType_t)0xffff +#else +typedef uint32_t TickType_t; +#define portMAX_DELAY (TickType_t)0xffffffffUL +#endif +/*------------------------------------------------------*/ + +/* Architecture specifics. */ +#define portSTACK_GROWTH (-1) +#define portTICK_PERIOD_MS ((TickType_t)(1000 / configTICK_RATE_HZ)) +#define portBYTE_ALIGNMENT 16 +/*-----------------------------------------------------------*/ + +#define portCRITICAL_NESTING_IN_TCB 0 + +/* + * Send an interrupt to another core in order to make the task running + * on it yield for a higher-priority task. + */ +void vPortYieldOtherCore(BaseType_t coreid); + +/* + Callback to set a watchpoint on the end of the stack. Called every context switch to change the stack + watchpoint around. + */ +void vPortSetStackWatchpoint(void *pxStackStart); + +/* + * Returns true if the current core is in ISR context; low prio ISR, med prio ISR or timer tick ISR. High prio ISRs + * aren't detected here, but they normally cannot call C code, so that should not be an issue anyway. + */ +BaseType_t xPortInIsrContext(void); + +/* + * This function will be called in High prio ISRs. Returns true if the current core was in ISR context + * before calling into high prio ISR context. + */ +BaseType_t xPortInterruptedFromISRContext(void); + +/* "mux" data structure (spinlock) */ +typedef struct { + /* owner field values: + * 0 - Uninitialized (invalid) + * portMUX_FREE_VAL - Mux is free, can be locked by either CPU + * CORE_ID_REGVAL_PRO / CORE_ID_REGVAL_APP - Mux is locked to the particular core + * + * + * Any value other than portMUX_FREE_VAL, CORE_ID_REGVAL_PRO, CORE_ID_REGVAL_APP indicates corruption + */ + uint32_t owner; + /* count field: + * If mux is unlocked, count should be zero. + * If mux is locked, count is non-zero & represents the number of recursive locks on the mux. + */ + uint32_t count; +#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG + const char *lastLockedFn; + int lastLockedLine; +#endif +} portMUX_TYPE; + +#define portMUX_FREE_VAL SPINLOCK_FREE + +/* Special constants for vPortCPUAcquireMutexTimeout() */ +#define portMUX_NO_TIMEOUT SPINLOCK_WAIT_FOREVER /* When passed for 'timeout_cycles', spin forever if necessary */ +#define portMUX_TRY_LOCK SPINLOCK_NO_WAIT /* Try to acquire the spinlock a single time only */ + +// Keep this in sync with the portMUX_TYPE struct definition please. +#ifndef CONFIG_FREERTOS_PORTMUX_DEBUG +#define portMUX_INITIALIZER_UNLOCKED \ + { .owner = portMUX_FREE_VAL, .count = 0, } +#else +#define portMUX_INITIALIZER_UNLOCKED \ + { .owner = portMUX_FREE_VAL, .count = 0, .lastLockedFn = "(never locked)", .lastLockedLine = -1 } +#endif + +/* Scheduler utilities. */ +extern void vPortYield(void); +extern void vPortYieldFromISR(void); + +#define portYIELD() vPortYield() +#define portYIELD_FROM_ISR() vPortYieldFromISR() + +/* Yielding within an API call (when interrupts are off), means the yield should be delayed + until interrupts are re-enabled. + To do this, we use the "cross-core" interrupt as a trigger to yield on this core when interrupts are re-enabled.This + is the same interrupt & code path which is used to trigger a yield between CPUs, although in this case the yield is + happening on the same CPU. +*/ +#define portYIELD_WITHIN_API() portYIELD() +/*-----------------------------------------------------------*/ + +/* Critical section management. */ +extern int vPortSetInterruptMask(void); +extern void vPortClearInterruptMask(int); + +void vPortCPUInitializeMutex(portMUX_TYPE *mux); +void vPortCPUAcquireMutex(portMUX_TYPE *mux); +bool vPortCPUAcquireMutexTimeout(portMUX_TYPE *mux, int timeout_cycles); +void vPortCPUReleaseMutex(portMUX_TYPE *mux); + +extern void vPortEnterCritical(void); +extern void vPortExitCritical(void); + +extern void esp_vApplicationIdleHook(void); +extern void esp_vApplicationTickHook(void); + +#ifndef CONFIG_FREERTOS_LEGACY_HOOKS +#define vApplicationIdleHook esp_vApplicationIdleHook +#define vApplicationTickHook esp_vApplicationTickHook +#endif /* !CONFIG_FREERTOS_LEGACY_HOOKS */ + +/* Task function macros as described on the FreeRTOS.org WEB site. */ +#define portTASK_FUNCTION_PROTO(vFunction, pvParameters) void vFunction(void* pvParameters) +#define portTASK_FUNCTION(vFunction, pvParameters) void vFunction(void* pvParameters) + +void vApplicationSleep(TickType_t xExpectedIdleTime); +#define portSUPPRESS_TICKS_AND_SLEEP(idleTime) vApplicationSleep(idleTime) + +#define portNOP() //__asm volatile ( " nop " ) + +#define portVALID_TCB_MEM(ptr) // esp_ptr_byte_accessible(ptr) +#define portVALID_STACK_MEM(ptr) // esp_ptr_byte_accessible(ptr) + +#endif //__ASSEMBLER__ + +#ifdef __cplusplus +} +#endif + +#endif /* PORTMACRO_H */ diff --git a/components/mqtt/host_test/mocks/include/machine/endian.h b/components/mqtt/host_test/mocks/include/machine/endian.h new file mode 100644 index 0000000..228316d --- /dev/null +++ b/components/mqtt/host_test/mocks/include/machine/endian.h @@ -0,0 +1,2 @@ +#pragma once +#include_next diff --git a/components/mqtt/host_test/mocks/include/sys/queue.h b/components/mqtt/host_test/mocks/include/sys/queue.h new file mode 100644 index 0000000..5ec7fec --- /dev/null +++ b/components/mqtt/host_test/mocks/include/sys/queue.h @@ -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) diff --git a/components/mqtt/host_test/sdkconfig.defaults b/components/mqtt/host_test/sdkconfig.defaults new file mode 100644 index 0000000..c126429 --- /dev/null +++ b/components/mqtt/host_test/sdkconfig.defaults @@ -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