From 02ed31f084f18aab082bdba15cce67a5c1c5c5e0 Mon Sep 17 00:00:00 2001 From: Reuben Cartwright Date: Tue, 6 Aug 2024 09:08:23 +0100 Subject: [PATCH 1/6] aws-iot-mock: Add subset of functionalities This commit expands mock coverage across the FRI codebase, adding and modifying existing mocks. The mocks added are intended to support testing of `ota_agent_task.c`. Signed-off-by: Reuben Cartwright --- .../helpers/events/mocks/inc/events.h | 6 + .../helpers/events/mocks/src/events.c | 4 + .../library_mocks/inc/core_mqtt_serializer.h | 3 +- .../integration_mocks/CMakeLists.txt | 1 + .../integration_mocks/inc/mqtt_agent_task.h | 45 ++++++ .../inc/subscription_manager.h | 9 ++ .../integration_mocks/src/mqtt_agent_task.c | 31 +++++ .../src/subscription_manager.c | 7 + .../tests/test_mqtt_agent_task.cpp | 6 +- .../library_mocks/inc/core_mqtt_agent.h | 13 ++ .../library_mocks/src/core_mqtt_agent.c | 12 ++ .../CMakeLists.txt | 8 +- .../integration/CMakeLists.txt | 55 ++++---- .../integration/src/ota_agent_task.c | 7 + .../integration/tests/CMakeLists.txt | 7 + .../tests/config_mocks/CMakeLists.txt | 17 +++ .../tests/config_mocks/inc/app_config.h | 14 ++ .../tests/config_mocks/inc/demo_config.h | 13 ++ .../inc/iot_default_root_certificates.h | 12 ++ .../tests/config_mocks/inc/ota_config.h | 14 ++ .../library_mocks/CMakeLists.txt | 16 +++ .../library_mocks/inc/ota.h | 130 ++++++++++++++++++ .../library_mocks/inc/ota_appversion32.h | 30 ++++ .../library_mocks/inc/ota_mqtt_interface.h | 57 ++++++++ .../library_mocks/inc/ota_os_interface.h | 112 +++++++++++++++ .../inc/ota_platform_interface.h | 75 ++++++++++ .../library_mocks/inc/ota_private.h | 73 ++++++++++ .../portable/os/ota_os_freertos.h | 30 ++++ .../library_mocks/src/ota.c | 55 ++++++++ .../library_mocks/CMakeLists.txt | 1 + .../library_mocks/inc/FreeRTOS.h | 4 +- .../library_mocks/inc/portmacro.h | 2 + .../library_mocks/inc/semphr.h | 16 +++ .../freertos_kernel/library_mocks/inc/task.h | 6 + .../library_mocks/src/semphr.c | 46 +++++++ .../freertos_kernel/library_mocks/src/tasks.c | 4 + .../freertos_ota_pal_psa/CMakeLists.txt | 2 + .../library_mocks/CMakeLists.txt | 19 +++ .../library_mocks/inc/ota_pal.h | 32 +++++ .../inc/version/application_version.h | 50 +++++++ .../src/version/application_version.c | 29 ++++ .../library_mocks/inc/psa/fwu_config.h | 12 ++ .../library_mocks/inc/psa/update.h | 11 ++ 43 files changed, 1062 insertions(+), 34 deletions(-) create mode 100644 components/aws_iot/coremqtt_agent/integration/integration_mocks/inc/mqtt_agent_task.h create mode 100644 components/aws_iot/coremqtt_agent/integration/integration_mocks/src/mqtt_agent_task.c create mode 100644 components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/CMakeLists.txt create mode 100644 components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/config_mocks/CMakeLists.txt create mode 100644 components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/config_mocks/inc/app_config.h create mode 100644 components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/config_mocks/inc/demo_config.h create mode 100644 components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/config_mocks/inc/iot_default_root_certificates.h create mode 100644 components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/config_mocks/inc/ota_config.h create mode 100644 components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/CMakeLists.txt create mode 100644 components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/inc/ota.h create mode 100644 components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/inc/ota_appversion32.h create mode 100644 components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/inc/ota_mqtt_interface.h create mode 100644 components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/inc/ota_os_interface.h create mode 100644 components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/inc/ota_platform_interface.h create mode 100644 components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/inc/ota_private.h create mode 100644 components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/portable/os/ota_os_freertos.h create mode 100644 components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/src/ota.c create mode 100644 components/freertos_kernel/library_mocks/src/semphr.c create mode 100644 components/security/freertos_ota_pal_psa/library_mocks/CMakeLists.txt create mode 100644 components/security/freertos_ota_pal_psa/library_mocks/inc/ota_pal.h create mode 100644 components/security/freertos_ota_pal_psa/library_mocks/inc/version/application_version.h create mode 100644 components/security/freertos_ota_pal_psa/library_mocks/src/version/application_version.c create mode 100644 components/security/trusted_firmware-m/library_mocks/inc/psa/fwu_config.h create mode 100644 components/security/trusted_firmware-m/library_mocks/inc/psa/update.h diff --git a/applications/helpers/events/mocks/inc/events.h b/applications/helpers/events/mocks/inc/events.h index c49eeb3..b51acae 100644 --- a/applications/helpers/events/mocks/inc/events.h +++ b/applications/helpers/events/mocks/inc/events.h @@ -7,6 +7,7 @@ #define EVENT_H #include "fff.h" +#include #define EVENT_MASK_MQTT_INIT 0x02 #define EVENT_MASK_MQTT_CONNECTED 0x04 @@ -15,6 +16,11 @@ typedef void * EventGroupHandle_t; extern EventGroupHandle_t xSystemEvents; +DECLARE_FAKE_VALUE_FUNC( bool, + xIsMqttAgentConnected ); DECLARE_FAKE_VOID_FUNC( vWaitUntilNetworkIsUp ); +DECLARE_FAKE_VOID_FUNC( vWaitUntilMQTTAgentReady ); +DECLARE_FAKE_VOID_FUNC( vWaitUntilMQTTAgentConnected ); + #endif /* EVENT_H */ diff --git a/applications/helpers/events/mocks/src/events.c b/applications/helpers/events/mocks/src/events.c index 5edba0f..ec00f0d 100644 --- a/applications/helpers/events/mocks/src/events.c +++ b/applications/helpers/events/mocks/src/events.c @@ -7,4 +7,8 @@ EventGroupHandle_t xSystemEvents; +DEFINE_FAKE_VALUE_FUNC( bool, + xIsMqttAgentConnected ); DEFINE_FAKE_VOID_FUNC( vWaitUntilNetworkIsUp ); +DEFINE_FAKE_VOID_FUNC( vWaitUntilMQTTAgentReady ); +DEFINE_FAKE_VOID_FUNC( vWaitUntilMQTTAgentConnected ); diff --git a/components/aws_iot/coremqtt/library_mocks/inc/core_mqtt_serializer.h b/components/aws_iot/coremqtt/library_mocks/inc/core_mqtt_serializer.h index 86ca96f..fb12241 100644 --- a/components/aws_iot/coremqtt/library_mocks/inc/core_mqtt_serializer.h +++ b/components/aws_iot/coremqtt/library_mocks/inc/core_mqtt_serializer.h @@ -33,7 +33,8 @@ typedef enum MQTTStatus { MQTTSuccess = 0, MQTTBadParameter, - MQTTSendFailed + MQTTSendFailed, + MQTTRecvFailed } MQTTStatus_t; typedef struct MQTTConnectInfo diff --git a/components/aws_iot/coremqtt_agent/integration/integration_mocks/CMakeLists.txt b/components/aws_iot/coremqtt_agent/integration/integration_mocks/CMakeLists.txt index 97d0424..a4763e9 100644 --- a/components/aws_iot/coremqtt_agent/integration/integration_mocks/CMakeLists.txt +++ b/components/aws_iot/coremqtt_agent/integration/integration_mocks/CMakeLists.txt @@ -5,6 +5,7 @@ add_library(coremqtt-agent-integration-mock src/freertos_agent_message.c src/freertos_command_pool.c + src/mqtt_agent_task.c src/subscription_manager.c ) diff --git a/components/aws_iot/coremqtt_agent/integration/integration_mocks/inc/mqtt_agent_task.h b/components/aws_iot/coremqtt_agent/integration/integration_mocks/inc/mqtt_agent_task.h new file mode 100644 index 0000000..8fbc068 --- /dev/null +++ b/components/aws_iot/coremqtt_agent/integration/integration_mocks/inc/mqtt_agent_task.h @@ -0,0 +1,45 @@ +/* + * FreeRTOS V202012.00 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2023-2024 Arm Limited and/or its affiliates + * + * + * 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. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +#ifndef MQTT_AGENT_H +#define MQTT_AGENT_H + +#include "core_mqtt.h" +#include "core_mqtt_agent.h" +#include "task.h" + +struct MQTTAgentCommandContext +{ + MQTTStatus_t xReturnStatus; + TaskHandle_t xTaskToNotify; + void * pArgs; +}; + +extern MQTTAgentContext_t xGlobalMqttAgentContext; + +#endif /* MQTT_AGENT_H */ diff --git a/components/aws_iot/coremqtt_agent/integration/integration_mocks/inc/subscription_manager.h b/components/aws_iot/coremqtt_agent/integration/integration_mocks/inc/subscription_manager.h index d0f9aa8..27a2494 100644 --- a/components/aws_iot/coremqtt_agent/integration/integration_mocks/inc/subscription_manager.h +++ b/components/aws_iot/coremqtt_agent/integration/integration_mocks/inc/subscription_manager.h @@ -44,6 +44,15 @@ typedef struct SubscriptionElement #define SUBSCRIPTION_MANAGER_MAX_SUBSCRIPTIONS 10U #endif +typedef void (* IncomingPubCallback_t)( void * pvIncomingPublishCallbackContext, + MQTTPublishInfo_t * pxPublishInfo ); + +DECLARE_FAKE_VALUE_FUNC( bool, + addSubscription, + const char *, + uint16_t, + IncomingPubCallback_t, + void * ); DECLARE_FAKE_VOID_FUNC( removeSubscription, const char *, uint16_t ); diff --git a/components/aws_iot/coremqtt_agent/integration/integration_mocks/src/mqtt_agent_task.c b/components/aws_iot/coremqtt_agent/integration/integration_mocks/src/mqtt_agent_task.c new file mode 100644 index 0000000..79cbff7 --- /dev/null +++ b/components/aws_iot/coremqtt_agent/integration/integration_mocks/src/mqtt_agent_task.c @@ -0,0 +1,31 @@ +/* + * FreeRTOS V202012.00 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2023-2024 Arm Limited and/or its affiliates + * + * + * 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. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +#include "mqtt_agent_task.h" + +MQTTAgentContext_t xGlobalMqttAgentContext; diff --git a/components/aws_iot/coremqtt_agent/integration/integration_mocks/src/subscription_manager.c b/components/aws_iot/coremqtt_agent/integration/integration_mocks/src/subscription_manager.c index 00d782a..d5949cf 100644 --- a/components/aws_iot/coremqtt_agent/integration/integration_mocks/src/subscription_manager.c +++ b/components/aws_iot/coremqtt_agent/integration/integration_mocks/src/subscription_manager.c @@ -26,8 +26,15 @@ * */ +#include "fff.h" #include "subscription_manager.h" +DEFINE_FAKE_VALUE_FUNC( bool, + addSubscription, + const char *, + uint16_t, + IncomingPubCallback_t, + void * ); DEFINE_FAKE_VOID_FUNC( removeSubscription, const char *, uint16_t ); diff --git a/components/aws_iot/coremqtt_agent/integration/tests/test_mqtt_agent_task.cpp b/components/aws_iot/coremqtt_agent/integration/tests/test_mqtt_agent_task.cpp index d7b50d6..a64f5b7 100644 --- a/components/aws_iot/coremqtt_agent/integration/tests/test_mqtt_agent_task.cpp +++ b/components/aws_iot/coremqtt_agent/integration/tests/test_mqtt_agent_task.cpp @@ -541,7 +541,7 @@ TEST_F( TestMqttAgentTask, Publish_callback_calls_publish_handler ) EXPECT_EQ( handleIncomingPublishes_fake.call_count, 0 ); int dummy = 5; - MQTTAgentContext_t mqttAgentContext = { &dummy }; + MQTTAgentContext_t mqttAgentContext = { nullptr, &dummy }; uint16_t dummyId = 10; MQTTPublishInfo_t xPublishInfo; xPublishInfo.qos = MQTTQoS0; @@ -561,7 +561,7 @@ TEST_F( TestMqttAgentTask, Publish_callback_does_not_error_if_publish_handled ) handleIncomingPublishes_fake.return_val = handled; int dummy = 5; - MQTTAgentContext_t mqttAgentContext = { &dummy }; + MQTTAgentContext_t mqttAgentContext = { nullptr, &dummy }; uint16_t dummyId = 10; MQTTPublishInfo_t xPublishInfo; xPublishInfo.qos = MQTTQoS0; @@ -581,7 +581,7 @@ TEST_F( TestMqttAgentTask, Publish_callback_generates_log_if_handler_fails ) handleIncomingPublishes_fake.return_val = handled; int dummy = 5; - MQTTAgentContext_t mqttAgentContext = { &dummy }; + MQTTAgentContext_t mqttAgentContext = { nullptr, &dummy }; uint16_t dummyId = 10; MQTTPublishInfo_t xPublishInfo; xPublishInfo.qos = MQTTQoS0; diff --git a/components/aws_iot/coremqtt_agent/library_mocks/inc/core_mqtt_agent.h b/components/aws_iot/coremqtt_agent/library_mocks/inc/core_mqtt_agent.h index dda0dfe..3ce26f5 100644 --- a/components/aws_iot/coremqtt_agent/library_mocks/inc/core_mqtt_agent.h +++ b/components/aws_iot/coremqtt_agent/library_mocks/inc/core_mqtt_agent.h @@ -41,6 +41,7 @@ typedef struct MQTTAgentCommand MQTTAgentCommand_t; typedef struct MQTTAgentContext { + MQTTAgentCommand_t * pArgs; void * mqttContext; } MQTTAgentContext_t; @@ -102,4 +103,16 @@ DECLARE_FAKE_VALUE_FUNC( MQTTStatus_t, MQTTAgent_CancelAll, MQTTAgentContext_t * ); +DECLARE_FAKE_VALUE_FUNC( MQTTStatus_t, + MQTTAgent_Publish, + const MQTTAgentContext_t *, + MQTTPublishInfo_t *, + const MQTTAgentCommandInfo_t * ); + +DECLARE_FAKE_VALUE_FUNC( MQTTStatus_t, + MQTTAgent_Unsubscribe, + const MQTTAgentContext_t *, + MQTTAgentSubscribeArgs_t *, + const MQTTAgentCommandInfo_t * ); + #endif /* CORE_MQTT_AGENT_H */ diff --git a/components/aws_iot/coremqtt_agent/library_mocks/src/core_mqtt_agent.c b/components/aws_iot/coremqtt_agent/library_mocks/src/core_mqtt_agent.c index 6efa4ad..e5c32a9 100644 --- a/components/aws_iot/coremqtt_agent/library_mocks/src/core_mqtt_agent.c +++ b/components/aws_iot/coremqtt_agent/library_mocks/src/core_mqtt_agent.c @@ -58,3 +58,15 @@ DEFINE_FAKE_VALUE_FUNC( MQTTStatus_t, DEFINE_FAKE_VALUE_FUNC( MQTTStatus_t, MQTTAgent_CancelAll, MQTTAgentContext_t * ); + +DEFINE_FAKE_VALUE_FUNC( MQTTStatus_t, + MQTTAgent_Publish, + const MQTTAgentContext_t *, + MQTTPublishInfo_t *, + const MQTTAgentCommandInfo_t * ); + +DEFINE_FAKE_VALUE_FUNC( MQTTStatus_t, + MQTTAgent_Unsubscribe, + const MQTTAgentContext_t *, + MQTTAgentSubscribeArgs_t *, + const MQTTAgentCommandInfo_t * ); diff --git a/components/aws_iot/ota_for_aws_iot_embedded_sdk/CMakeLists.txt b/components/aws_iot/ota_for_aws_iot_embedded_sdk/CMakeLists.txt index 59f6ba9..ee65579 100644 --- a/components/aws_iot/ota_for_aws_iot_embedded_sdk/CMakeLists.txt +++ b/components/aws_iot/ota_for_aws_iot_embedded_sdk/CMakeLists.txt @@ -2,7 +2,9 @@ # # SPDX-License-Identifier: MIT -if(CMAKE_CROSSCOMPILING) +if(BUILD_TESTING AND NOT CMAKE_CROSSCOMPILING) + add_subdirectory(library_mocks) +else() set(ota_for_aws_iot_embedded_sdk_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/library CACHE INTERNAL @@ -14,6 +16,6 @@ if(CMAKE_CROSSCOMPILING) set(PATCH_FILES_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/integration/patches") set(PATCH_FILES "${PATCH_FILES_DIRECTORY}/0001-Add-non-constant-appFirmwareVersion-extern.patch") iot_reference_arm_corstone3xx_apply_patches("${ota_for_aws_iot_embedded_sdk_SOURCE_DIR}" "${PATCH_FILES}") - - add_subdirectory(integration) endif() + +add_subdirectory(integration) diff --git a/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/CMakeLists.txt b/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/CMakeLists.txt index 96b70d2..db3cb78 100644 --- a/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/CMakeLists.txt +++ b/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/CMakeLists.txt @@ -2,32 +2,37 @@ # # SPDX-License-Identifier: MIT -include(${ota_for_aws_iot_embedded_sdk_SOURCE_DIR}/otaFilePaths.cmake) -add_library(ota-for-aws-iot-embedded-sdk - ${OTA_SOURCES} - ${OTA_MQTT_SOURCES} - ${OTA_OS_FREERTOS_SOURCES} - src/ota_agent_task.c -) +if(BUILD_TESTING AND NOT CMAKE_CROSSCOMPILING) + add_subdirectory(tests) +else() + include(${ota_for_aws_iot_embedded_sdk_SOURCE_DIR}/otaFilePaths.cmake) -target_include_directories(ota-for-aws-iot-embedded-sdk - PUBLIC - ${OTA_INCLUDE_PUBLIC_DIRS} - ${OTA_INCLUDE_OS_FREERTOS_DIRS} -) + add_library(ota-for-aws-iot-embedded-sdk + ${OTA_SOURCES} + ${OTA_MQTT_SOURCES} + ${OTA_OS_FREERTOS_SOURCES} + src/ota_agent_task.c + ) -add_library(ota-for-aws-iot-embedded-sdk-config INTERFACE) + target_include_directories(ota-for-aws-iot-embedded-sdk + PUBLIC + ${OTA_INCLUDE_PUBLIC_DIRS} + ${OTA_INCLUDE_OS_FREERTOS_DIRS} + ) -target_link_libraries(ota-for-aws-iot-embedded-sdk - PUBLIC - ota-for-aws-iot-embedded-sdk-config - PRIVATE - corejson - coremqtt - coremqtt-agent - freertos-ota-pal-psa - helpers-events - helpers-logging - tinycbor -) + add_library(ota-for-aws-iot-embedded-sdk-config INTERFACE) + + target_link_libraries(ota-for-aws-iot-embedded-sdk + PUBLIC + ota-for-aws-iot-embedded-sdk-config + PRIVATE + corejson + coremqtt + coremqtt-agent + freertos-ota-pal-psa + helpers-events + helpers-logging + tinycbor + ) +endif() diff --git a/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/src/ota_agent_task.c b/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/src/ota_agent_task.c index a9a845d..af6ebd2 100644 --- a/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/src/ota_agent_task.c +++ b/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/src/ota_agent_task.c @@ -38,6 +38,7 @@ #include "events.h" /* includes for TFM */ +#include "psa/fwu_config.h" #include "psa/update.h" /* includes for OTA PAL PSA */ @@ -72,6 +73,12 @@ /* Include platform abstraction header. */ #include "ota_pal.h" +/* Added for implicit inclusions */ +#include "core_mqtt_agent.h" +#include "logging_stack.h" +#include "ota_private.h" +#include "subscription_manager.h" + extern void vOtaNotActiveHook( void ); extern void vOtaActiveHook( void ); diff --git a/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/CMakeLists.txt b/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/CMakeLists.txt new file mode 100644 index 0000000..b6a6423 --- /dev/null +++ b/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright 2024 Arm Limited and/or its affiliates +# +# SPDX-License-Identifier: MIT + +# application-specific mocks +add_subdirectory(config_mocks) + diff --git a/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/config_mocks/CMakeLists.txt b/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/config_mocks/CMakeLists.txt new file mode 100644 index 0000000..9751fbc --- /dev/null +++ b/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/config_mocks/CMakeLists.txt @@ -0,0 +1,17 @@ +# Copyright 2024 Arm Limited and/or its affiliates +# +# SPDX-License-Identifier: MIT + +# Add helpers for testing mqtt_agent_task.c. Helpers are application-specific. +# E.g. app_config.h is a helper since it varies by application. +add_library(ota-for-aws-iot-embedded-sdk-test-specific-mock + INTERFACE +) +target_include_directories(ota-for-aws-iot-embedded-sdk-test-specific-mock + INTERFACE + inc +) +target_link_libraries(ota-for-aws-iot-embedded-sdk-test-specific-mock + INTERFACE + fff +) diff --git a/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/config_mocks/inc/app_config.h b/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/config_mocks/inc/app_config.h new file mode 100644 index 0000000..9324175 --- /dev/null +++ b/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/config_mocks/inc/app_config.h @@ -0,0 +1,14 @@ +/* Copyright 2024 Arm Limited and/or its affiliates + * + * SPDX-License-Identifier: MIT + */ + +#ifndef APP_CONFIG_H +#define APP_CONFIG_H + +#define appCONFIG_MQTT_AGENT_TASK_STACK_SIZE 4096 +#define appCONFIG_MQTT_AGENT_TASK_PRIORITY 2 +#define appCONFIG_OTA_MQTT_AGENT_TASK_STACK_SIZE ( 4096 ) +#define appCONFIG_OTA_MQTT_AGENT_TASK_PRIORITY ( 1 ) + +#endif diff --git a/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/config_mocks/inc/demo_config.h b/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/config_mocks/inc/demo_config.h new file mode 100644 index 0000000..86bb5cc --- /dev/null +++ b/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/config_mocks/inc/demo_config.h @@ -0,0 +1,13 @@ +/* Copyright 2024 Arm Limited and/or its affiliates + * + * SPDX-License-Identifier: MIT + */ + +#ifndef DEMO_CONFIG_H +#define DEMO_CONFIG_H + +#define democonfigMQTT_BROKER_ENDPOINT "dummy endpoint" +#define democonfigMQTT_BROKER_PORT 8883 +#define democonfigCLIENT_IDENTIFIER "dummy client identifier" + +#endif /* DEMO_CONFIG_H */ diff --git a/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/config_mocks/inc/iot_default_root_certificates.h b/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/config_mocks/inc/iot_default_root_certificates.h new file mode 100644 index 0000000..8e0b080 --- /dev/null +++ b/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/config_mocks/inc/iot_default_root_certificates.h @@ -0,0 +1,12 @@ +/* Copyright 2024 Arm Limited and/or its affiliates + * + * SPDX-License-Identifier: MIT + */ + +#ifndef __DEFAULT__ROOT__CERTIFICATES__H__ +#define __DEFAULT__ROOT__CERTIFICATES__H__ + +static const char tlsATS1_ROOT_CERTIFICATE_PEM[] = "dummy"; +static const uint32_t tlsATS1_ROOT_CERTIFICATE_LENGTH = sizeof( tlsATS1_ROOT_CERTIFICATE_PEM ); + +#endif /* ifndef __DEFAULT__ROOT__CERTIFICATES__H__ */ diff --git a/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/config_mocks/inc/ota_config.h b/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/config_mocks/inc/ota_config.h new file mode 100644 index 0000000..a862681 --- /dev/null +++ b/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/config_mocks/inc/ota_config.h @@ -0,0 +1,14 @@ +/* Copyright 2024 Arm Limited and/or its affiliates + * + * SPDX-License-Identifier: MIT + */ + +#ifndef OTA_CONFIG_H_ +#define OTA_CONFIG_H_ + +#define otaconfigLOG2_FILE_BLOCK_SIZE 12UL + +#define otaconfigMAX_NUM_OTA_DATA_BUFFERS 10 + + +#endif /* OTA_CONFIG_H_ */ diff --git a/components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/CMakeLists.txt b/components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/CMakeLists.txt new file mode 100644 index 0000000..8397fa1 --- /dev/null +++ b/components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/CMakeLists.txt @@ -0,0 +1,16 @@ + +add_library(ota-for-aws-iot-embedded-sdk-mock + src/ota.c +) + +target_include_directories(ota-for-aws-iot-embedded-sdk-mock + PUBLIC + inc + + portable/os +) + +target_link_libraries(ota-for-aws-iot-embedded-sdk-mock + PRIVATE + fff +) diff --git a/components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/inc/ota.h b/components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/inc/ota.h new file mode 100644 index 0000000..03e0c4f --- /dev/null +++ b/components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/inc/ota.h @@ -0,0 +1,130 @@ +/* + * AWS IoT Over-the-air Update v3.4.0 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2024 Arm Limited and/or its affiliates + * + * + * SPDX-License-Identifier: MIT + * + * 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. + */ + +#ifndef OTA_H +#define OTA_H + +#include +#include "fff.h" +#include "ota_private.h" +#include "ota_os_interface.h" +#include "ota_mqtt_interface.h" +#include "ota_platform_interface.h" + +typedef struct OtaInterface +{ + OtaOSInterface_t os; + OtaMqttInterface_t mqtt; + OtaPalInterface_t pal; +} OtaInterfaces_t; + +typedef struct OtaAppBuffer +{ + uint8_t * pUpdateFilePath; + uint16_t updateFilePathsize; + uint8_t * pCertFilePath; + uint16_t certFilePathSize; + uint8_t * pStreamName; + uint16_t streamNameSize; + uint8_t * pDecodeMemory; + uint32_t decodeMemorySize; + uint8_t * pFileBitmap; + uint16_t fileBitmapSize; + uint8_t * pUrl; + uint16_t urlSize; + uint8_t * pAuthScheme; + uint16_t authSchemeSize; +} OtaAppBuffer_t; + +typedef enum OtaJobEvent +{ + OtaJobEventActivate = 0, + OtaJobEventFail = 1, + OtaJobEventStartTest = 2, + OtaJobEventProcessed = 3, + OtaJobEventSelfTestFailed = 4, + OtaJobEventParseCustomJob = 5, + OtaJobEventReceivedJob = 6, + OtaJobEventUpdateComplete = 7, + OtaJobEventNoActiveJob = 8, + OtaLastJobEvent = OtaJobEventStartTest +} OtaJobEvent_t; + +typedef enum OtaErr +{ + OtaErrNone = 0, + OtaErrUninitialized = 1 +} OtaErr_t; + +typedef enum OtaState +{ + OtaAgentStateNoTransition = 0, + OtaAgentStateInit = 1, + OtaAgentStateReady = 2, + OtaAgentStateRequestingJob = 3, + OtaAgentStateWaitingForJob = 4, + OtaAgentStateCreatingFile = 5, + OtaAgentStateRequestingFileBlock = 6, + OtaAgentStateWaitingForFileBlock = 7, + OtaAgentStateClosingFile = 8, + OtaAgentStateSuspended = 9, + OtaAgentStateShuttingDown = 10, + OtaAgentStateStopped = 11, + OtaAgentStateAll = 12 +} OtaState_t; + +typedef void (* OtaAppCallback_t)( OtaJobEvent_t eEvent, + void * pData ); + +DECLARE_FAKE_VALUE_FUNC( OtaErr_t, OTA_ActivateNewImage ); +DECLARE_FAKE_VALUE_FUNC( OtaState_t, OTA_GetState ); +DECLARE_FAKE_VALUE_FUNC( OtaState_t, + OTA_Shutdown, + uint32_t, + uint8_t ); +DECLARE_FAKE_VALUE_FUNC( OtaErr_t, + OTA_SetImageState, + OtaImageState_t ); +DECLARE_FAKE_VALUE_FUNC( bool, + OTA_SignalEvent, + const OtaEventMsg_t * const ); +DECLARE_FAKE_VALUE_FUNC( OtaErr_t, + OTA_Suspend ); +DECLARE_FAKE_VALUE_FUNC( OtaErr_t, + OTA_Resume ); +DECLARE_FAKE_VALUE_FUNC( OtaErr_t, + OTA_Init, + const OtaAppBuffer_t *, + const OtaInterfaces_t *, + const uint8_t *, + OtaAppCallback_t ); +DECLARE_FAKE_VALUE_FUNC( OtaErr_t, + OTA_GetStatistics, + OtaAgentStatistics_t * ); +DECLARE_FAKE_VOID_FUNC( OTA_EventProcessingTask, + const void * ); + +#endif /* OTA_H */ diff --git a/components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/inc/ota_appversion32.h b/components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/inc/ota_appversion32.h new file mode 100644 index 0000000..501f9b3 --- /dev/null +++ b/components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/inc/ota_appversion32.h @@ -0,0 +1,30 @@ +/* + * AWS IoT Over-the-air Update v3.4.0 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2024 Arm Limited and/or its affiliates + * + * + * SPDX-License-Identifier: MIT + * + * 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. + */ + +#ifndef IOT_APPVERSION32_H +#define IOT_APPVERSION32_H + +#endif /* IOT_APPVERSION32_H */ diff --git a/components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/inc/ota_mqtt_interface.h b/components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/inc/ota_mqtt_interface.h new file mode 100644 index 0000000..4afa2db --- /dev/null +++ b/components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/inc/ota_mqtt_interface.h @@ -0,0 +1,57 @@ +/* + * AWS IoT Over-the-air Update v3.4.0 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2024 Arm Limited and/or its affiliates + * + * + * SPDX-License-Identifier: MIT + * + * 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. + */ + +#ifndef OTA_MQTT_INTERFACE_H +#define OTA_MQTT_INTERFACE_H + +typedef enum OtaMqttStatus +{ + OtaMqttSuccess = 0, + OtaMqttPublishFailed = 1, + OtaMqttSubscribeFailed = 2, + OtaMqttUnsubscribeFailed = 3 +} OtaMqttStatus_t; + +typedef OtaMqttStatus_t ( * OtaMqttSubscribe_t ) ( const char * pTopicFilter, + uint16_t topicFilterLength, + uint8_t ucQoS ); +typedef OtaMqttStatus_t ( * OtaMqttUnsubscribe_t ) ( const char * pTopicFilter, + uint16_t topicFilterLength, + uint8_t ucQoS ); +typedef OtaMqttStatus_t ( * OtaMqttPublish_t )( const char * const pacTopic, + uint16_t usTopicLen, + const char * pcMsg, + uint32_t ulMsgSize, + uint8_t ucQoS ); + +typedef struct OtaMqttInterface +{ + OtaMqttSubscribe_t subscribe; /*!< @brief Interface for subscribing to Mqtt topics. */ + OtaMqttUnsubscribe_t unsubscribe; /*!< @brief interface for unsubscribing to MQTT topics. */ + OtaMqttPublish_t publish; /*!< @brief Interface for publishing MQTT messages. */ +} OtaMqttInterface_t; + +#endif /* OTA_MQTT_INTERFACE_H */ diff --git a/components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/inc/ota_os_interface.h b/components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/inc/ota_os_interface.h new file mode 100644 index 0000000..6e603ac --- /dev/null +++ b/components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/inc/ota_os_interface.h @@ -0,0 +1,112 @@ +/* + * AWS IoT Over-the-air Update v3.4.0 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2024 Arm Limited and/or its affiliates + * + * + * SPDX-License-Identifier: MIT + * + * 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. + */ + +#ifndef OTA_OS_INTERFACE_H +#define OTA_OS_INTERFACE_H + +/* *INDENT-OFF* */ +#ifdef __cplusplus + extern "C" { +#endif +/* *INDENT-ON* */ + +/* Dummy enums added for mocking. Would normally be functions. */ +typedef enum +{ + OtaInitEvent_FreeRTOS = 1, +} OtaInitEvent_t; +typedef enum +{ + OtaSendEvent_FreeRTOS = 1, +} OtaSendEvent_t; +typedef enum +{ + OtaReceiveEvent_FreeRTOS = 1, +} OtaReceiveEvent_t; +typedef enum +{ + OtaDeinitEvent_FreeRTOS = 1, +} OtaDeinitEvent_t; + +typedef enum +{ + OtaStartTimer_FreeRTOS = 1, +} OtaStartTimer_t; +typedef enum +{ + OtaStopTimer_FreeRTOS = 1, +} OtaStopTimer_t; +typedef enum +{ + OtaDeleteTimer_FreeRTOS = 1, +} OtaDeleteTimer_t; + +typedef enum +{ + Malloc_FreeRTOS = 1, +} OtaMalloc_t; +typedef enum +{ + Free_FreeRTOS = 1, +} OtaFree_t; + +typedef struct OtaEventInterface +{ + OtaInitEvent_t init; + OtaSendEvent_t send; + OtaReceiveEvent_t recv; + OtaDeinitEvent_t deinit; +} OtaEventInterface_t; + +typedef struct OtaTimerInterface +{ + OtaStartTimer_t start; + OtaStopTimer_t stop; + OtaDeleteTimer_t delete; +} OtaTimerInterface_t; + +typedef struct OtaMallocInterface +{ + OtaMalloc_t malloc; + OtaFree_t free; +} OtaMallocInterface_t; + + +typedef struct OtaOSInterface +{ + OtaEventInterface_t event; + OtaTimerInterface_t timer; + OtaMallocInterface_t mem; +} OtaOSInterface_t; + + +/* *INDENT-OFF* */ +#ifdef __cplusplus + } +#endif +/* *INDENT-ON* */ + +#endif /* ifndef OTA_OS_INTERFACE_H */ diff --git a/components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/inc/ota_platform_interface.h b/components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/inc/ota_platform_interface.h new file mode 100644 index 0000000..9e93117 --- /dev/null +++ b/components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/inc/ota_platform_interface.h @@ -0,0 +1,75 @@ +/* + * AWS IoT Over-the-air Update v3.4.0 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2024 Arm Limited and/or its affiliates + * + * + * SPDX-License-Identifier: MIT + * + * 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. + */ + +#ifndef OTA_PLATFORM_INTERFACE +#define OTA_PLATFORM_INTERFACE + +typedef enum +{ + otaPal_Abort = 1, +} OtaPalAbort_t; +typedef enum +{ + otaPal_CreateFileForRx = 1, +} OtaPalCreateFileForRx_t; +typedef enum +{ + otaPal_ResetDevice = 1, +} OtaPalResetDevice_t; +typedef enum +{ + otaPal_CloseFile = 1, +} OtaPalCloseFile_t; +typedef enum +{ + otaPal_ActivateNewImage = 1, +} OtaPalActivateNewImage_t; +typedef enum +{ + otaPal_WriteBlock = 1, +} OtaPalWriteBlock_t; +typedef enum +{ + otaPal_SetPlatformImageState = 1, +} OtaPalSetPlatformImageState_t; +typedef enum +{ + otaPal_GetPlatformImageState = 1, +} OtaPalGetPlatformImageState_t; + +typedef struct OtaPalInterface +{ + OtaPalAbort_t abort; + OtaPalCreateFileForRx_t createFile; + OtaPalCloseFile_t closeFile; + OtaPalWriteBlock_t writeBlock; + OtaPalActivateNewImage_t activate; + OtaPalResetDevice_t reset; + OtaPalSetPlatformImageState_t setPlatformImageState; + OtaPalGetPlatformImageState_t getPlatformImageState; +} OtaPalInterface_t; + +#endif /* OTA_PLATFORM_INTERFACE */ diff --git a/components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/inc/ota_private.h b/components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/inc/ota_private.h new file mode 100644 index 0000000..2b4a919 --- /dev/null +++ b/components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/inc/ota_private.h @@ -0,0 +1,73 @@ +/* + * AWS IoT Over-the-air Update v3.4.0 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2024 Arm Limited and/or its affiliates + * + * + * SPDX-License-Identifier: MIT + * + * 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. + */ + +#ifndef OTA_PRIVATE_H +#define OTA_PRIVATE_H + +#include +#include + +#define OTA_MAX_BLOCK_BITMAP_SIZE 128U + +typedef struct OtaAgentStatistics +{ + uint32_t otaPacketsReceived; + uint32_t otaPacketsQueued; + uint32_t otaPacketsProcessed; + uint32_t otaPacketsDropped; +} OtaAgentStatistics_t; + +typedef enum OtaImageState +{ + OtaImageStateUnknown = 0, + OtaImageStateTesting = 1, + OtaImageStateAccepted = 2, + OtaImageStateRejected = 3, + OtaImageStateAborted = 4, + OtaLastImageState = OtaImageStateAborted +} OtaImageState_t; + +typedef enum OtaEvent +{ + OtaAgentEventStart = 0, + OtaAgentEventReceivedJobDocument, + OtaAgentEventReceivedFileBlock +} OtaEvent_t; + +typedef struct OtaEventData +{ + uint8_t data[ 10 ]; + uint32_t dataLength; + bool bufferUsed; +} OtaEventData_t; + +typedef struct OtaEventMsg +{ + OtaEventData_t * pEventData; + OtaEvent_t eventId; +} OtaEventMsg_t; + +#endif /* OTA_PRIVATE_H */ diff --git a/components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/portable/os/ota_os_freertos.h b/components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/portable/os/ota_os_freertos.h new file mode 100644 index 0000000..22e6b2a --- /dev/null +++ b/components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/portable/os/ota_os_freertos.h @@ -0,0 +1,30 @@ +/* + * AWS IoT Over-the-air Update v3.4.0 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2024 Arm Limited and/or its affiliates + * + * + * SPDX-License-Identifier: MIT + * + * 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. + */ + +#ifndef _OTA_OS_FREERTOS_H_ +#define _OTA_OS_FREERTOS_H_ + +#endif /* OTA_OS_FREERTOS_H_ */ diff --git a/components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/src/ota.c b/components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/src/ota.c new file mode 100644 index 0000000..56ecd1c --- /dev/null +++ b/components/aws_iot/ota_for_aws_iot_embedded_sdk/library_mocks/src/ota.c @@ -0,0 +1,55 @@ +/* + * AWS IoT Over-the-air Update v3.4.0 + * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2024 Arm Limited and/or its affiliates + * + * + * SPDX-License-Identifier: MIT + * + * 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. + */ + +#include "ota.h" + +DEFINE_FAKE_VALUE_FUNC( OtaErr_t, OTA_ActivateNewImage ); +DEFINE_FAKE_VALUE_FUNC( OtaState_t, OTA_GetState ); +DEFINE_FAKE_VALUE_FUNC( OtaState_t, + OTA_Shutdown, + uint32_t, + uint8_t ); +DEFINE_FAKE_VALUE_FUNC( OtaErr_t, + OTA_SetImageState, + OtaImageState_t ); +DEFINE_FAKE_VALUE_FUNC( bool, + OTA_SignalEvent, + const OtaEventMsg_t * const ); +DEFINE_FAKE_VALUE_FUNC( OtaErr_t, + OTA_Suspend ); +DEFINE_FAKE_VALUE_FUNC( OtaErr_t, + OTA_Resume ); +DEFINE_FAKE_VALUE_FUNC( OtaErr_t, + OTA_Init, + const OtaAppBuffer_t *, + const OtaInterfaces_t *, + const uint8_t *, + OtaAppCallback_t ); +DEFINE_FAKE_VALUE_FUNC( OtaErr_t, + OTA_GetStatistics, + OtaAgentStatistics_t * ); +DEFINE_FAKE_VOID_FUNC( OTA_EventProcessingTask, + const void * ); diff --git a/components/freertos_kernel/library_mocks/CMakeLists.txt b/components/freertos_kernel/library_mocks/CMakeLists.txt index 95c178d..ef117e5 100644 --- a/components/freertos_kernel/library_mocks/CMakeLists.txt +++ b/components/freertos_kernel/library_mocks/CMakeLists.txt @@ -4,6 +4,7 @@ add_library(freertos-kernel-mock src/event_groups.c + src/semphr.c src/tasks.c src/queue.c ) diff --git a/components/freertos_kernel/library_mocks/inc/FreeRTOS.h b/components/freertos_kernel/library_mocks/inc/FreeRTOS.h index 9c9364e..bdeb219 100644 --- a/components/freertos_kernel/library_mocks/inc/FreeRTOS.h +++ b/components/freertos_kernel/library_mocks/inc/FreeRTOS.h @@ -38,8 +38,8 @@ typedef int StaticQueue_t; /* * Definitions found in FreeTOSConfig.h. - * Because for testing `freertos_command_pool.c` we cannot - * directly include FreeRTOSConfig.h (this causes build failure), + * Because for testing `freertos_command_pool.c` and other files we cannot + * directly include FreeRTOSConfig.h in the source file (as this causes build failure), * nor can we prototype the configAssert macro from within the file. */ diff --git a/components/freertos_kernel/library_mocks/inc/portmacro.h b/components/freertos_kernel/library_mocks/inc/portmacro.h index 3dd06dd..75c7e35 100644 --- a/components/freertos_kernel/library_mocks/inc/portmacro.h +++ b/components/freertos_kernel/library_mocks/inc/portmacro.h @@ -35,4 +35,6 @@ typedef long BaseType_t; typedef unsigned short UBaseType_t; typedef unsigned long TickType_t; +#define portMAX_DELAY ( TickType_t ) 0xFFFFFFFFUL + #endif /* ifndef PORTMACRO_H */ diff --git a/components/freertos_kernel/library_mocks/inc/semphr.h b/components/freertos_kernel/library_mocks/inc/semphr.h index c05c5ff..c20f09a 100644 --- a/components/freertos_kernel/library_mocks/inc/semphr.h +++ b/components/freertos_kernel/library_mocks/inc/semphr.h @@ -31,5 +31,21 @@ #ifndef SEMAPHORE_H #define SEMAPHORE_H +#include "fff.h" +#include "portmacro.h" + +typedef int SemaphoreHandle_t; + +DECLARE_FAKE_VALUE_FUNC( BaseType_t, + xSemaphoreTake, + SemaphoreHandle_t, + TickType_t ); +DECLARE_FAKE_VALUE_FUNC( BaseType_t, + xSemaphoreGive, + SemaphoreHandle_t ); +DECLARE_FAKE_VALUE_FUNC( SemaphoreHandle_t, + xSemaphoreCreateMutex ); +DECLARE_FAKE_VOID_FUNC( vSemaphoreDelete, + SemaphoreHandle_t ); #endif /* SEMAPHORE_H */ diff --git a/components/freertos_kernel/library_mocks/inc/task.h b/components/freertos_kernel/library_mocks/inc/task.h index 8a724c0..bf5f8ac 100644 --- a/components/freertos_kernel/library_mocks/inc/task.h +++ b/components/freertos_kernel/library_mocks/inc/task.h @@ -36,6 +36,8 @@ #include "projdefs.h" #include +#define tskIDLE_PRIORITY ( ( UBaseType_t ) 0U ) + typedef int * TaskHandle_t; typedef enum @@ -69,4 +71,8 @@ DECLARE_FAKE_VALUE_FUNC( BaseType_t, DECLARE_FAKE_VOID_FUNC( vTaskDelete, TaskHandle_t ); DECLARE_FAKE_VOID_FUNC( vTaskDelay, const TickType_t ); +DECLARE_FAKE_VALUE_FUNC( BaseType_t, + xTaskNotifyStateClear, + TaskHandle_t ); + #endif /* INC_TASK_H */ diff --git a/components/freertos_kernel/library_mocks/src/semphr.c b/components/freertos_kernel/library_mocks/src/semphr.c new file mode 100644 index 0000000..385e5eb --- /dev/null +++ b/components/freertos_kernel/library_mocks/src/semphr.c @@ -0,0 +1,46 @@ +/* + * FreeRTOS Kernel V11.1.0 + * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2024 Arm Limited and/or its affiliates + * + * + * SPDX-License-Identifier: MIT + * + * 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. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +/* This file has no equivalent in the FreeRTOS kernel */ +/* but has been added for ease of unit testing. */ + +#include "semphr.h" + +DEFINE_FAKE_VALUE_FUNC( BaseType_t, + xSemaphoreTake, + SemaphoreHandle_t, + TickType_t ); +DEFINE_FAKE_VALUE_FUNC( BaseType_t, + xSemaphoreGive, + SemaphoreHandle_t ); +DEFINE_FAKE_VALUE_FUNC( SemaphoreHandle_t, + xSemaphoreCreateMutex ); +DEFINE_FAKE_VOID_FUNC( vSemaphoreDelete, + SemaphoreHandle_t ); diff --git a/components/freertos_kernel/library_mocks/src/tasks.c b/components/freertos_kernel/library_mocks/src/tasks.c index bc2d8ec..18b45cd 100644 --- a/components/freertos_kernel/library_mocks/src/tasks.c +++ b/components/freertos_kernel/library_mocks/src/tasks.c @@ -55,3 +55,7 @@ DEFINE_FAKE_VALUE_FUNC( BaseType_t, DEFINE_FAKE_VOID_FUNC( vTaskDelete, TaskHandle_t ); DEFINE_FAKE_VOID_FUNC( vTaskDelay, const TickType_t ); + +DEFINE_FAKE_VALUE_FUNC( BaseType_t, + xTaskNotifyStateClear, + TaskHandle_t ); diff --git a/components/security/freertos_ota_pal_psa/CMakeLists.txt b/components/security/freertos_ota_pal_psa/CMakeLists.txt index 5595b52..8ce106b 100644 --- a/components/security/freertos_ota_pal_psa/CMakeLists.txt +++ b/components/security/freertos_ota_pal_psa/CMakeLists.txt @@ -18,4 +18,6 @@ if(CMAKE_CROSSCOMPILING) iot_reference_arm_corstone3xx_apply_patches("${freertos_ota_pal_psa_SOURCE_DIR}" "${PATCH_FILES}") add_subdirectory(integration) +else() + add_subdirectory(library_mocks) endif() diff --git a/components/security/freertos_ota_pal_psa/library_mocks/CMakeLists.txt b/components/security/freertos_ota_pal_psa/library_mocks/CMakeLists.txt new file mode 100644 index 0000000..3ca32d1 --- /dev/null +++ b/components/security/freertos_ota_pal_psa/library_mocks/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright 2024 Arm Limited and/or its affiliates +# +# SPDX-License-Identifier: MIT + +add_library(freertos-ota-pal-psa-mock + ./src/version/application_version.c +) + +target_include_directories(freertos-ota-pal-psa-mock + PUBLIC + inc + + inc/version +) + +target_link_libraries(freertos-ota-pal-psa-mock + PRIVATE + fff +) diff --git a/components/security/freertos_ota_pal_psa/library_mocks/inc/ota_pal.h b/components/security/freertos_ota_pal_psa/library_mocks/inc/ota_pal.h new file mode 100644 index 0000000..1203c48 --- /dev/null +++ b/components/security/freertos_ota_pal_psa/library_mocks/inc/ota_pal.h @@ -0,0 +1,32 @@ +/* + * FreeRTOS V202107.00 + * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2024 Arm Limited and/or its affiliates + * + * + * 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://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + + +#ifndef OTA_PAL_H_ +#define OTA_PAL_H_ + +#endif /* OTA_PAL_H_ */ diff --git a/components/security/freertos_ota_pal_psa/library_mocks/inc/version/application_version.h b/components/security/freertos_ota_pal_psa/library_mocks/inc/version/application_version.h new file mode 100644 index 0000000..d768dce --- /dev/null +++ b/components/security/freertos_ota_pal_psa/library_mocks/inc/version/application_version.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020-2024 Arm Limited. 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. + * + */ + +#ifndef APPLICATION_VERSION_H_ +#define APPLICATION_VERSION_H_ + +#include "fff.h" +#include +#include + +typedef struct +{ + union + { + struct version + { + uint8_t major; + uint8_t minor; + + uint16_t build; + } x; + } u; +} AppVersion32_t; + +DECLARE_FAKE_VALUE_FUNC( int, + GetImageVersionPSA, + uint8_t ); + +extern const AppVersion32_t appFirmwareVersion; + +#endif /* APPLICATION_VERSION_H */ diff --git a/components/security/freertos_ota_pal_psa/library_mocks/src/version/application_version.c b/components/security/freertos_ota_pal_psa/library_mocks/src/version/application_version.c new file mode 100644 index 0000000..8cfef0f --- /dev/null +++ b/components/security/freertos_ota_pal_psa/library_mocks/src/version/application_version.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020-2024 Arm Limited. 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. + * + */ + +#include "application_version.h" + +DEFINE_FAKE_VALUE_FUNC( int, + GetImageVersionPSA, + uint8_t ); + +const AppVersion32_t appFirmwareVersion; diff --git a/components/security/trusted_firmware-m/library_mocks/inc/psa/fwu_config.h b/components/security/trusted_firmware-m/library_mocks/inc/psa/fwu_config.h new file mode 100644 index 0000000..2b3ceb0 --- /dev/null +++ b/components/security/trusted_firmware-m/library_mocks/inc/psa/fwu_config.h @@ -0,0 +1,12 @@ +/* Copyright 2024 Arm Limited and/or its affiliates + * + * SPDX-License-Identifier: MIT + */ + +#ifndef __FWU_CONFIG_H__ +#define __FWU_CONFIG_H__ + +#define FWU_COMPONENT_ID_SECURE 0x00U +#define FWU_COMPONENT_ID_NONSECURE 0x01U + +#endif /* __FWU_CONFIG_H__ */ diff --git a/components/security/trusted_firmware-m/library_mocks/inc/psa/update.h b/components/security/trusted_firmware-m/library_mocks/inc/psa/update.h new file mode 100644 index 0000000..7c7ad2b --- /dev/null +++ b/components/security/trusted_firmware-m/library_mocks/inc/psa/update.h @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2021-2024, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef PSA_UPDATE_H +#define PSA_UPDATE_H + +#endif /* PSA_UPDATE_H */ From a4129c3d2d0288e741d6f0869fc8dee9ee105c55 Mon Sep 17 00:00:00 2001 From: Reuben Cartwright Date: Wed, 28 Aug 2024 09:15:15 +0100 Subject: [PATCH 2/6] aws-iot: Make #include explicit Some files were used by ota_agent_task.c but not directly included. This commit fixes this. Signed-off-by: Reuben Cartwright --- .../integration/src/ota_agent_task.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/src/ota_agent_task.c b/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/src/ota_agent_task.c index af6ebd2..5282e2b 100644 --- a/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/src/ota_agent_task.c +++ b/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/src/ota_agent_task.c @@ -74,8 +74,13 @@ #include "ota_pal.h" /* Added for implicit inclusions */ +#include "core_mqtt.h" #include "core_mqtt_agent.h" +#include "events.h" #include "logging_stack.h" +#include "ota_os_interface.h" +#include "ota_mqtt_interface.h" +#include "ota_platform_interface.h" #include "ota_private.h" #include "subscription_manager.h" From 23acd9f91c5aebb44030299ad2e84ddd82516ba2 Mon Sep 17 00:00:00 2001 From: Reuben Cartwright Date: Mon, 2 Sep 2024 10:46:44 +0100 Subject: [PATCH 3/6] aws-iot: Expose ota_agent_task.c statics This commit makes the static functions in ota_agent_task.c visible if the UNIT_TESTING macro is defined. The methodology is documented already in `unit_testing.md`. This is justified because: - These functions need to be tested. - Functions other than `vStartOtaTask` cannot be refactored to be non-static, as only `vStartOtaTask` should be called in another file. Signed-off-by: Reuben Cartwright --- .../integration/src/ota_agent_task.c | 73 +++++++++++-------- 1 file changed, 42 insertions(+), 31 deletions(-) diff --git a/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/src/ota_agent_task.c b/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/src/ota_agent_task.c index 5282e2b..56a6de6 100644 --- a/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/src/ota_agent_task.c +++ b/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/src/ota_agent_task.c @@ -87,6 +87,13 @@ extern void vOtaNotActiveHook( void ); extern void vOtaActiveHook( void ); +/* Provides external linkage only when running unit test */ +#ifdef UNIT_TESTING + #define STATIC /* as nothing */ +#else /* ifdef UNIT_TESTING */ + #define STATIC static +#endif /* UNIT_TESTING */ + /*------------- Demo configurations -------------------------*/ /** @@ -221,6 +228,7 @@ typedef struct OtaTopicFilterCallback * @brief Buffer used to store the firmware image file path. * Buffer is passed to the OTA agent during initialization. */ + static uint8_t updateFilePath[ otaexampleMAX_FILE_PATH_SIZE ]; /** @@ -281,7 +289,7 @@ extern MQTTAgentContext_t xGlobalMqttAgentContext; * * @return A pointer to an unusued buffer. NULL if there are no buffers available. */ -static OtaEventData_t * prvOTAEventBufferGet( void ); +STATIC OtaEventData_t * prvOTAEventBufferGet( void ); /** * @brief Free an event buffer back to pool @@ -294,7 +302,7 @@ static OtaEventData_t * prvOTAEventBufferGet( void ); * * @param[in] pxBuffer Pointer to the buffer to be freed. */ -static void prvOTAEventBufferFree( OtaEventData_t * const pxBuffer ); +STATIC void prvOTAEventBufferFree( OtaEventData_t * const pxBuffer ); /** * @brief The function which runs the OTA agent task. @@ -306,7 +314,7 @@ static void prvOTAEventBufferFree( OtaEventData_t * const pxBuffer ); * * @param[in] pvParam Any parameters to be passed to OTA agent task. */ -static void prvOTAAgentTask( void * pvParam ); +STATIC void prvOTAAgentTask( void * pvParam ); /** @@ -318,14 +326,14 @@ static void prvOTAAgentTask( void * pvParam ); * * @param[in] pvParam Any parameters to be passed to OTA Demo task. */ -static void vOtaDemoTask( void * pvParam ); +STATIC void vOtaDemoTask( void * pvParam ); /** * @brief The function which implements the flow for OTA demo. * * @return pdPASS if success or pdFAIL. */ -static BaseType_t prvRunOTADemo( void ); +STATIC BaseType_t prvRunOTADemo( void ); /** * @brief Callback registered with the OTA library that notifies the OTA agent @@ -335,7 +343,7 @@ static BaseType_t prvRunOTADemo( void ); * @param[in] pPublishInfo MQTT packet information which stores details of the * job document. */ -static void prvMqttJobCallback( void * pContext, +STATIC void prvMqttJobCallback( void * pContext, MQTTPublishInfo_t * pPublish ); @@ -345,7 +353,7 @@ static void prvMqttJobCallback( void * pContext, * @param[in] pContext MQTT context which stores the connection. * @param[in] pPublishInfo MQTT packet that stores the information of the file block. */ -static void prvMqttDataCallback( void * pContext, +STATIC void prvMqttDataCallback( void * pContext, MQTTPublishInfo_t * pPublish ); /** @@ -359,7 +367,7 @@ static void prvMqttDataCallback( void * pContext, * @param[in] pvIncomingPublishCallbackContext MQTT context which stores the connection. * @param[in] pPublishInfo MQTT packet that stores the information of the file block. */ -static void prvMqttDefaultCallback( void * pvIncomingPublishCallbackContext, +STATIC void prvMqttDefaultCallback( void * pvIncomingPublishCallbackContext, MQTTPublishInfo_t * pxPublishInfo ); /** @@ -369,7 +377,7 @@ static void prvMqttDefaultCallback( void * pvIncomingPublishCallbackContext, * @param[in] topicFilterLength length of the topic filter. * */ -static void prvRegisterOTACallback( const char * pTopicFilter, +STATIC void prvRegisterOTACallback( const char * pTopicFilter, uint16_t topicFilterLength ); /** @@ -377,14 +385,14 @@ static void prvRegisterOTACallback( const char * pTopicFilter, * * @return pPASS or pdFAIL. */ -static BaseType_t prvSuspendOTA( void ); +STATIC BaseType_t prvSuspendOTA( void ); /** * @brief Resume OTA demo. * * @return pPASS or pdFAIL. */ -static BaseType_t prvResumeOTA( void ); +STATIC BaseType_t prvResumeOTA( void ); /** * @brief Set OTA interfaces. @@ -393,7 +401,7 @@ static BaseType_t prvResumeOTA( void ); * * @return None. */ -static void setOtaInterfaces( OtaInterfaces_t * pOtaInterfaces ); +STATIC void setOtaInterfaces( OtaInterfaces_t * pOtaInterfaces ); /** * @brief Structure containing all application allocated buffers used by the OTA agent. @@ -437,7 +445,7 @@ static OtaTopicFilterCallback_t otaTopicFilterCallbacks[] = /*-----------------------------------------------------------*/ -static void prvOTAEventBufferFree( OtaEventData_t * const pxBuffer ) +STATIC void prvOTAEventBufferFree( OtaEventData_t * const pxBuffer ) { if( xSemaphoreTake( xBufferSemaphore, portMAX_DELAY ) == pdTRUE ) { @@ -448,7 +456,7 @@ static void prvOTAEventBufferFree( OtaEventData_t * const pxBuffer ) /*-----------------------------------------------------------*/ -static OtaEventData_t * prvOTAEventBufferGet( void ) +STATIC OtaEventData_t * prvOTAEventBufferGet( void ) { OtaEventData_t * pFreeBuffer = NULL; @@ -493,7 +501,8 @@ static OtaEventData_t * prvOTAEventBufferGet( void ) * @param[in] pData Data associated with the event. * @return None. */ -static void otaAppCallback( OtaJobEvent_t event, + +STATIC void otaAppCallback( OtaJobEvent_t event, void * pData ) { OtaErr_t err = OtaErrUninitialized; @@ -620,7 +629,7 @@ static void otaAppCallback( OtaJobEvent_t event, } } -static void prvMqttJobCallback( void * pvIncomingPublishCallbackContext, +STATIC void prvMqttJobCallback( void * pvIncomingPublishCallbackContext, MQTTPublishInfo_t * pxPublishInfo ) { OtaEventData_t * pData; @@ -650,7 +659,8 @@ static void prvMqttJobCallback( void * pvIncomingPublishCallbackContext, } /*-----------------------------------------------------------*/ -static void prvMqttDefaultCallback( void * pvIncomingPublishCallbackContext, + +STATIC void prvMqttDefaultCallback( void * pvIncomingPublishCallbackContext, MQTTPublishInfo_t * pxPublishInfo ) { bool isMatch = false; @@ -668,7 +678,8 @@ static void prvMqttDefaultCallback( void * pvIncomingPublishCallbackContext, } /*-----------------------------------------------------------*/ -static void prvMqttDataCallback( void * pvIncomingPublishCallbackContext, + +STATIC void prvMqttDataCallback( void * pvIncomingPublishCallbackContext, MQTTPublishInfo_t * pxPublishInfo ) { OtaEventData_t * pxData; @@ -699,7 +710,7 @@ static void prvMqttDataCallback( void * pvIncomingPublishCallbackContext, /*-----------------------------------------------------------*/ -static void prvRegisterOTACallback( const char * pTopicFilter, +STATIC void prvRegisterOTACallback( const char * pTopicFilter, uint16_t topicFilterLength ) { bool isMatch = false; @@ -741,7 +752,7 @@ static void prvRegisterOTACallback( const char * pTopicFilter, } } -static void prvMQTTSubscribeCompleteCallback( MQTTAgentCommandContext_t * pxCommandContext, +STATIC void prvMQTTSubscribeCompleteCallback( MQTTAgentCommandContext_t * pxCommandContext, MQTTAgentReturnInfo_t * pxReturnInfo ) { if( pxReturnInfo->returnCode == MQTTSuccess ) @@ -763,7 +774,7 @@ static void prvMQTTSubscribeCompleteCallback( MQTTAgentCommandContext_t * pxComm } } -static void prvMQTTUnsubscribeCompleteCallback( MQTTAgentCommandContext_t * pxCommandContext, +STATIC void prvMQTTUnsubscribeCompleteCallback( MQTTAgentCommandContext_t * pxCommandContext, MQTTAgentReturnInfo_t * pxReturnInfo ) { /* Store the result in the application defined context so the task that @@ -779,7 +790,7 @@ static void prvMQTTUnsubscribeCompleteCallback( MQTTAgentCommandContext_t * pxCo } } -static OtaMqttStatus_t prvMQTTSubscribe( const char * pTopicFilter, +STATIC OtaMqttStatus_t prvMQTTSubscribe( const char * pTopicFilter, uint16_t topicFilterLength, uint8_t ucQoS ) { @@ -848,7 +859,7 @@ static OtaMqttStatus_t prvMQTTSubscribe( const char * pTopicFilter, return otaRet; } -static void prvOTAPublishCommandCallback( MQTTAgentCommandContext_t * pxCommandContext, +STATIC void prvOTAPublishCommandCallback( MQTTAgentCommandContext_t * pxCommandContext, MQTTAgentReturnInfo_t * pxReturnInfo ) { pxCommandContext->xReturnStatus = pxReturnInfo->returnCode; @@ -859,7 +870,7 @@ static void prvOTAPublishCommandCallback( MQTTAgentCommandContext_t * pxCommandC } } -static OtaMqttStatus_t prvMQTTPublish( const char * const pacTopic, +STATIC OtaMqttStatus_t prvMQTTPublish( const char * const pacTopic, uint16_t topicLen, const char * pMsg, uint32_t msgSize, @@ -921,7 +932,7 @@ static OtaMqttStatus_t prvMQTTPublish( const char * const pacTopic, return otaRet; } -static OtaMqttStatus_t prvMQTTUnsubscribe( const char * pTopicFilter, +STATIC OtaMqttStatus_t prvMQTTUnsubscribe( const char * pTopicFilter, uint16_t topicFilterLength, uint8_t ucQoS ) { @@ -993,7 +1004,7 @@ static OtaMqttStatus_t prvMQTTUnsubscribe( const char * pTopicFilter, return otaRet; } -static void setOtaInterfaces( OtaInterfaces_t * pOtaInterfaces ) +STATIC void setOtaInterfaces( OtaInterfaces_t * pOtaInterfaces ) { configASSERT( pOtaInterfaces != NULL ); @@ -1026,7 +1037,7 @@ static void setOtaInterfaces( OtaInterfaces_t * pOtaInterfaces ) /*-----------------------------------------------------------*/ -static void prvOTAAgentTask( void * pParam ) +STATIC void prvOTAAgentTask( void * pParam ) { /* Calling OTA agent task. */ OTA_EventProcessingTask( pParam ); @@ -1035,7 +1046,7 @@ static void prvOTAAgentTask( void * pParam ) vTaskDelete( NULL ); } -static BaseType_t prvSuspendOTA( void ) +STATIC BaseType_t prvSuspendOTA( void ) { /* OTA library return status. */ OtaErr_t otaRet = OtaErrNone; @@ -1069,7 +1080,7 @@ static BaseType_t prvSuspendOTA( void ) return status; } -static BaseType_t prvResumeOTA( void ) +STATIC BaseType_t prvResumeOTA( void ) { /* OTA library return status. */ OtaErr_t otaRet = OtaErrNone; @@ -1103,7 +1114,7 @@ static BaseType_t prvResumeOTA( void ) return status; } -static BaseType_t prvRunOTADemo( void ) +STATIC BaseType_t prvRunOTADemo( void ) { /* Status indicating a successful demo or not. */ BaseType_t xStatus = pdPASS; @@ -1234,7 +1245,7 @@ static BaseType_t prvRunOTADemo( void ) * the OTA agent. If not, it is simply ignored. * */ -static void vOtaDemoTask( void * pvParam ) +STATIC void vOtaDemoTask( void * pvParam ) { ( void ) pvParam; From 17412c1bc99c6875bc33bb67123d95820353df92 Mon Sep 17 00:00:00 2001 From: Reuben Cartwright Date: Thu, 5 Sep 2024 10:39:38 +0100 Subject: [PATCH 4/6] aws-iot: Refactor ota_agent_task redundant code The function `otaAppCallback` is called upon an event such as a new file block being received, or the OTA image being activated. The function then redundantly checks the OTA state via `OTA_GetState`, which reduces code clarity via duplication including redundant calls to the ota update's active and inactive hooks. This fix has been tested via passing Arm's internal CI. Signed-off-by: Reuben Cartwright --- .../integration/src/ota_agent_task.c | 28 ------------------- 1 file changed, 28 deletions(-) diff --git a/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/src/ota_agent_task.c b/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/src/ota_agent_task.c index 56a6de6..989f2f2 100644 --- a/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/src/ota_agent_task.c +++ b/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/src/ota_agent_task.c @@ -599,34 +599,6 @@ STATIC void otaAppCallback( OtaJobEvent_t event, LogWarn( ( "Received an unhandled callback event from OTA Agent, event = %d", event ) ); break; } - - OtaState_t state = OTA_GetState(); - - switch( state ) - { - case OtaAgentStateNoTransition: - case OtaAgentStateInit: - case OtaAgentStateReady: - case OtaAgentStateSuspended: - case OtaAgentStateShuttingDown: - case OtaAgentStateStopped: - LogInfo( ( "OTA not active state `%d` from OTA Agent.", state ) ); - vOtaNotActiveHook(); - break; - - case OtaAgentStateRequestingJob: - case OtaAgentStateCreatingFile: - case OtaAgentStateRequestingFileBlock: - case OtaAgentStateWaitingForFileBlock: - case OtaAgentStateClosingFile: - LogInfo( ( "OTA active state `%d` from OTA Agent.", state ) ); - vOtaActiveHook(); - break; - - case OtaAgentStateWaitingForJob: - default: - break; - } } STATIC void prvMqttJobCallback( void * pvIncomingPublishCallbackContext, From be40ea6c48e52197db341167bd54f7aa64d62c7a Mon Sep 17 00:00:00 2001 From: Reuben Cartwright Date: Wed, 11 Sep 2024 13:57:00 +0100 Subject: [PATCH 5/6] aws-iot: Add unit tests for ota_agent_task.c Adds 76 unit tests. The CMakeLists.txt within the tests subdirectory are also modified so that the tests run on calling ctest. Signed-off-by: Reuben Cartwright --- .../integration/tests/CMakeLists.txt | 28 + .../integration/tests/test_ota_agent_task.cpp | 1247 +++++++++++++++++ 2 files changed, 1275 insertions(+) create mode 100644 components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/test_ota_agent_task.cpp diff --git a/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/CMakeLists.txt b/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/CMakeLists.txt index b6a6423..5fb403d 100644 --- a/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/CMakeLists.txt +++ b/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/CMakeLists.txt @@ -5,3 +5,31 @@ # application-specific mocks add_subdirectory(config_mocks) +add_executable(ota-agent-task-test + test_ota_agent_task.cpp + ../src/ota_agent_task.c +) +target_include_directories(ota-agent-task-test + PRIVATE + . + + ../../library_mocks/inc + + # ota_agent_task.c has no .h file, so we include 'src' not 'inc' + ../src +) +target_link_libraries(ota-agent-task-test + PRIVATE + coremqtt-agent-integration-mock + coremqtt-agent-mock + coremqtt-mock + fff + freertos-kernel-mock + freertos-ota-pal-psa-mock + helpers-events-mock + helpers-logging-mock + trusted-firmware-m-mock + ota-for-aws-iot-embedded-sdk-mock + ota-for-aws-iot-embedded-sdk-test-specific-mock +) +iot_reference_arm_corstone3xx_add_test(ota-agent-task-test) diff --git a/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/test_ota_agent_task.cpp b/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/test_ota_agent_task.cpp new file mode 100644 index 0000000..88e0080 --- /dev/null +++ b/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/tests/test_ota_agent_task.cpp @@ -0,0 +1,1247 @@ +/* Copyright 2024 Arm Limited and/or its affiliates + * + * SPDX-License-Identifier: MIT + */ + +#include "fff.h" + +#include "gtest/gtest.h" + +#include + +using namespace std; +using namespace std::placeholders; + + +extern "C" { +/* Header files for types used in this test file */ +#include "application_version.h" +#include "core_mqtt_agent.h" +#include "core_mqtt_serializer.h" +#include "FreeRTOS.h" +#include "logging_stack.h" +#include "ota_mqtt_interface.h" +#include "ota_private.h" +#include "ota_config.h" +/* ota.h depends on ota_os_interface.h, which uses the reserved C++ keyword 'delete' */ +#define delete unreserved_delete +#include "ota.h" +#undef delete +#include "portmacro.h" +#include "semphr.h" +#include "subscription_manager.h" +#include "task.h" +#include "events.h" +/* File under test */ +/* Functions usually defined in main.c */ +DECLARE_FAKE_VOID_FUNC( vOtaActiveHook ); +DEFINE_FAKE_VOID_FUNC( vOtaActiveHook ); +DECLARE_FAKE_VOID_FUNC( vOtaNotActiveHook ); +DEFINE_FAKE_VOID_FUNC( vOtaNotActiveHook ); +/* Struct usually defined by the application. */ +struct MQTTAgentCommandContext +{ + MQTTStatus_t xReturnStatus; + TaskHandle_t xTaskToNotify; + void * pArgs; +}; +/* Static functions we are testing */ +extern void vStartOtaTask( void ); +extern OtaEventData_t * prvOTAEventBufferGet( void ); +extern void prvOTAEventBufferFree( OtaEventData_t * const ); +extern void prvOTAAgentTask( void * ); +extern void vOtaDemoTask( void * ); +extern BaseType_t prvRunOTADemo( void ); +extern BaseType_t prvResumeOTA( void ); +extern BaseType_t prvSuspendOTA( void ); +extern void setOtaInterfaces( OtaInterfaces_t * ); +extern OtaMqttStatus_t prvMQTTUnsubscribe( const char *, + uint16_t, + uint8_t ); +extern OtaMqttStatus_t prvMQTTPublish( const char * const, + uint16_t, + const char *, + uint32_t, + uint8_t ); +extern void prvOTAPublishCommandCallback( MQTTAgentCommandContext_t *, + MQTTAgentReturnInfo_t * ); +extern OtaMqttStatus_t prvMQTTSubscribe( const char *, + uint16_t, + uint8_t ); +extern void prvMQTTUnsubscribeCompleteCallback( MQTTAgentCommandContext_t *, + MQTTAgentReturnInfo_t * ); +extern void prvMQTTSubscribeCompleteCallback( MQTTAgentCommandContext_t *, + MQTTAgentReturnInfo_t * ); +extern void prvMqttJobCallback( void *, + MQTTPublishInfo_t * ); +extern void prvMqttDataCallback( void *, + MQTTPublishInfo_t * ); +extern void prvMqttDefaultCallback( void *, + MQTTPublishInfo_t * ); +extern void prvRegisterOTACallback( const char *, + uint16_t ); +extern void prvMqttDataCallback( void *, + MQTTPublishInfo_t * ); +extern void otaAppCallback( OtaJobEvent_t, + void * ); +extern OtaEventData_t * prvOTAEventBufferGet( void ); +extern void prvOTAEventBufferFree( OtaEventData_t * const ); +/* Mocks of .h files in the same submodule as ota_agent_task.c that are also used by ota_agent_task.c */ + +/* Functions usually defined by main.c */ +DEFINE_FAKE_VOID_FUNC( vAssertCalled, + const char *, + unsigned long ); +DEFINE_FAKE_VOID_FUNC_VARARG( SdkLogError, + const char *, + ... ); +DEFINE_FAKE_VOID_FUNC_VARARG( SdkLogWarn, + const char *, + ... ); +DEFINE_FAKE_VOID_FUNC_VARARG( SdkLogInfo, + const char *, + ... ); +DEFINE_FAKE_VOID_FUNC_VARARG( SdkLogDebug, + const char *, + ... ); +} + +DEFINE_FFF_GLOBALS + + +/* Being under this test class denotes a valid test that needs a corresponding fix, but we do not want clogging the testsuite. */ +class SkipTest : public ::testing::Test { +protected: + void SetUp() override + { + GTEST_SKIP() << "Skipping all tests under this suite"; + } +}; + +#define ASSERTION_FAILURE 1 +/* used to indicate a context switch should have happened, but cannot be mocked. */ +/* E.g. After Activating the OTA image we do not expect the otaAppCallback test code to continue running. */ +#define CONTEXT_SWITCH_FAKE 2 + + +/* Mock for vAssertCalled */ +void throw_assertion_failure( const char * pcFile, + unsigned long ulLine ) +{ + throw( ASSERTION_FAILURE ); /* stop tests running. */ +} + +/* Mock for SdkLogError */ +void fail_and_display_error( const char * msg, + va_list args ) +{ + char buf[ 1000 ]; + + vsnprintf( buf, 1000, msg, args ); + FAIL() << "Failed because of unexpected error message: '" << buf << "' \n"; +} +void do_nothing_if_an_error_occurs( const char * msg, + va_list args ) /* do nothing */ +{ +} + +/* Mock for xTaskNotifyWait */ +BaseType_t stop_the_rest_of_the_program_running( int unused1, + int unused2, + void * unused3, + TickType_t unused4 ) +{ + throw ( CONTEXT_SWITCH_FAKE ); + return pdPASS; +} + +/* Mocks for MQTT_MatchTopic */ +MQTTStatus_t set_match_true( const char * unused1, + const uint16_t unused2, + const char * unused3, + const uint16_t unused4, + bool * pIsMatch ) +{ + *pIsMatch = true; + return MQTTSuccess; +} +MQTTStatus_t set_match_false( const char * unused1, + const uint16_t unused2, + const char * unused3, + const uint16_t unused4, + bool * pIsMatch ) +{ + *pIsMatch = false; + return MQTTSuccess; +} + +/* We use a global variable because it is not possible to use C++ std::function alongside C function pointers. + * FFF uses C function pointers. + * So it not possible to use partial function application via std::bind to pass a parameter to a mock. */ +int global_counter = 0; +MQTTStatus_t match_while_global_counter_is_positive( const char * unused1, + const uint16_t unused2, + const char * unused3, + const uint16_t unused4, + bool * pIsMatch ) +{ + if( global_counter > 0 ) + { + *pIsMatch = true; + global_counter = global_counter - 1; + } + else + { + *pIsMatch = false; + } + + return MQTTSuccess; +} + +/* Mock for OTA_SignalEvent */ +bool expect_block_received_signal( const OtaEventMsg_t * const pEventMsg ) +{ + EXPECT_EQ( pEventMsg->eventId, OtaAgentEventReceivedFileBlock ); + return true; +} + +void expect_errors() +{ + EXPECT_NE( SdkLogError_fake.call_count, 0 ); +} + +/* Mock for MQTTAgent_Publish */ +MQTTStatus_t set_return_status_to_mqtt_success( const MQTTAgentContext_t * pMqttAgentContext, + MQTTPublishInfo_t * pPublishInfo, + const MQTTAgentCommandInfo_t * pCommandInfo ) +{ + MQTTAgentCommandContext_t * ctxt = ( MQTTAgentCommandContext_t * ) pCommandInfo->pCmdCompleteCallbackContext; + + ctxt->xReturnStatus = MQTTSuccess; + return MQTTSuccess; +} +MQTTStatus_t set_return_status_to_mqtt_bad_parameter( const MQTTAgentContext_t * pMqttAgentContext, + MQTTPublishInfo_t * pPublishInfo, + const MQTTAgentCommandInfo_t * pCommandInfo ) +{ + MQTTAgentCommandContext_t * ctxt = ( MQTTAgentCommandContext_t * ) pCommandInfo->pCmdCompleteCallbackContext; + + ctxt->xReturnStatus = MQTTBadParameter; /* the command returns failure */ + return MQTTSuccess; /* the publish itself succeeded. */ +} + +/* Mock for xTaskNotify */ +BaseType_t expect_task_to_notify_is_five( TaskHandle_t handle, + uint32_t unused1, + eNotifyAction unused2 ) +{ + EXPECT_EQ( *handle, 5 ); + return pdPASS; +} + +/* Mock for MQTTAgent_Subscribe and MQTTAgent_Unsubscribe */ +MQTTStatus_t fake_successful_subscription( const MQTTAgentContext_t * pMqttAgentContext, + MQTTAgentSubscribeArgs_t * pSubscriptionArgs, + const MQTTAgentCommandInfo_t * pCommandInfo ) +{ + MQTTAgentCommandContext_t * ctxt = ( MQTTAgentCommandContext_t * ) pCommandInfo->pCmdCompleteCallbackContext; + + ctxt->xReturnStatus = MQTTSuccess; + return MQTTSuccess; +} +MQTTStatus_t fake_bad_subscribe_parameter( const MQTTAgentContext_t * pMqttAgentContext, + MQTTAgentSubscribeArgs_t * pSubscriptionArgs, + const MQTTAgentCommandInfo_t * pCommandInfo ) +{ + MQTTAgentCommandContext_t * ctxt = ( MQTTAgentCommandContext_t * ) pCommandInfo->pCmdCompleteCallbackContext; + + ctxt->xReturnStatus = MQTTBadParameter; + return MQTTBadParameter; +} +MQTTStatus_t fake_subscribe_command_failure_only( const MQTTAgentContext_t * pMqttAgentContext, + MQTTAgentSubscribeArgs_t * pSubscriptionArgs, + const MQTTAgentCommandInfo_t * pCommandInfo ) +{ + MQTTAgentCommandContext_t * ctxt = ( MQTTAgentCommandContext_t * ) pCommandInfo->pCmdCompleteCallbackContext; + + ctxt->xReturnStatus = MQTTBadParameter; + return MQTTSuccess; +} + +/* Mock for MQTTAgent_Publish */ +MQTTStatus_t fake_successful_publish( const MQTTAgentContext_t * pMqttAgentContext, + MQTTPublishInfo_t * pPublishInfo, + const MQTTAgentCommandInfo_t * pCommandInfo ) +{ + MQTTAgentCommandContext_t * ctxt = ( MQTTAgentCommandContext_t * ) pCommandInfo->pCmdCompleteCallbackContext; + + ctxt->xReturnStatus = MQTTSuccess; + return MQTTSuccess; +} +MQTTStatus_t fake_bad_publish_parameter( const MQTTAgentContext_t * pMqttAgentContext, + MQTTPublishInfo_t * pPublishInfo, + const MQTTAgentCommandInfo_t * pCommandInfo ) +{ + MQTTAgentCommandContext_t * ctxt = ( MQTTAgentCommandContext_t * ) pCommandInfo->pCmdCompleteCallbackContext; + + ctxt->xReturnStatus = MQTTBadParameter; + return MQTTBadParameter; +} + +/* Mock for OTA_Suspend */ +OtaErr_t fake_successful_ota_suspend( void ) +{ + OTA_GetState_fake.return_val = OtaAgentStateSuspended; + return OtaErrNone; +} +OtaErr_t fake_unsuccessful_ota_suspend( void ) +{ + OTA_GetState_fake.return_val = OtaAgentStateWaitingForFileBlock; + return OtaErrUninitialized; +} +OtaErr_t fake_successful_ota_suspend_but_state_is_incorrect( void ) +{ + OTA_GetState_fake.return_val = OtaAgentStateShuttingDown; + return OtaErrNone; +} + +/* Mock for OTA_Resume */ +OtaErr_t fake_successful_ota_resume( void ) +{ + OTA_GetState_fake.return_val = OtaAgentStateWaitingForFileBlock; + return OtaErrNone; +} +OtaErr_t fake_unsuccessful_ota_resume( void ) +{ + OTA_GetState_fake.return_val = OtaAgentStateSuspended; + return OtaErrUninitialized; +} +OtaErr_t fake_successful_ota_resume_but_state_is_still_suspended( void ) +{ + OTA_GetState_fake.return_val = OtaAgentStateSuspended; + return OtaErrNone; +} + +class TestOtaAgentTask : public ::testing::Test { +public: + TestOtaAgentTask() + { + RESET_FAKE( addSubscription ); + RESET_FAKE( GetImageVersionPSA ); + RESET_FAKE( MQTTAgent_Subscribe ); + RESET_FAKE( MQTTAgent_Publish ); + RESET_FAKE( MQTTAgent_Unsubscribe ); + RESET_FAKE( MQTTAgent_Subscribe ); + RESET_FAKE( MQTT_MatchTopic ); + RESET_FAKE( OTA_ActivateNewImage ); + RESET_FAKE( OTA_EventProcessingTask ); + RESET_FAKE( OTA_GetState ); + RESET_FAKE( OTA_Init ); + RESET_FAKE( OTA_Resume ); + RESET_FAKE( OTA_SetImageState ); + RESET_FAKE( OTA_Shutdown ); + RESET_FAKE( OTA_SignalEvent ); + RESET_FAKE( OTA_Suspend ); + RESET_FAKE( removeSubscription ); + RESET_FAKE( SdkLogError ); + RESET_FAKE( SdkLogWarn ); + RESET_FAKE( SdkLogDebug ); + RESET_FAKE( vAssertCalled ); + RESET_FAKE( vOtaActiveHook ); + RESET_FAKE( vOtaNotActiveHook ); + RESET_FAKE( vTaskDelay ); + RESET_FAKE( vSemaphoreDelete ); + RESET_FAKE( vWaitUntilMQTTAgentConnected ); + RESET_FAKE( vWaitUntilMQTTAgentReady ); + RESET_FAKE( xIsMqttAgentConnected ); + RESET_FAKE( xSemaphoreCreateMutex ); + RESET_FAKE( xSemaphoreTake ); + RESET_FAKE( xSemaphoreGive ); + RESET_FAKE( xTaskGetCurrentTaskHandle ); + RESET_FAKE( xTaskNotify ) + RESET_FAKE( xTaskNotifyStateClear ); + RESET_FAKE( xTaskNotifyWait ); + RESET_FAKE( xTaskCreate ); + + /* Default values. + * Do not overwrite these here, instead use inheritance or + * overwrite the mock return values in individual tests. */ + addSubscription_fake.return_val = true; /* success. */ + MQTTAgent_Subscribe_fake.custom_fake = fake_successful_subscription; + MQTTAgent_Publish_fake.custom_fake = fake_successful_publish; + MQTTAgent_Unsubscribe_fake.return_val = MQTTSuccess; + MQTTAgent_Subscribe_fake.return_val = MQTTSuccess; + MQTT_MatchTopic_fake.return_val = MQTTSuccess; + OTA_ActivateNewImage_fake.return_val = OtaErrNone; + OTA_GetState_fake.return_val = OtaAgentStateReady; + OTA_Init_fake.return_val = OtaErrNone; + OTA_SetImageState_fake.return_val = OtaErrNone; + OTA_Shutdown_fake.return_val = OtaAgentStateShuttingDown; + OTA_SignalEvent_fake.return_val = true; + OTA_Suspend_fake.custom_fake = fake_successful_ota_suspend; + OTA_Resume_fake.custom_fake = fake_successful_ota_resume; + xIsMqttAgentConnected_fake.return_val = true; + xTaskGetCurrentTaskHandle_fake.return_val = nullptr; + xTaskNotify_fake.return_val = pdPASS; + xTaskNotifyStateClear_fake.return_val = pdTRUE; + xTaskNotifyWait_fake.return_val = pdPASS; + + /* + * These default semaphore values are relied on by nearly all tests. + * Do not change them here. + */ + xSemaphoreTake_fake.return_val = pdTRUE; + xSemaphoreGive_fake.return_val = pdTRUE; + xTaskCreate_fake.return_val = pdPASS; + + /* + * Wrap functions expected to fail an assertion in EXPECT_THROW from GoogleTest. + * Overwrite these in the test if you expect a test's inputs to cause an error. + * Note that overwriting a custom fake requires another custom fake, setting return_val + * is not sufficient. + */ + vAssertCalled_fake.custom_fake = throw_assertion_failure; + /* assume every unexpected error log is a problem. */ + SdkLogError_fake.custom_fake = fail_and_display_error; + } +}; + +/* Mock for OTA_SetImageState */ +OtaErr_t should_set_image_to_accepted_state( OtaImageState_t state ) +{ + /* Assume the image is valid. */ + EXPECT_EQ( state, OtaImageStateAccepted ); + return OtaErrNone; +} + +/* The file under test contains static functions which the tests in this file assume are made visible + * by conditional compiling macros. This test verifies these macros are defined. */ +TEST_F( TestOtaAgentTask, can_test_static_functions ) +{ + #ifndef UNIT_TESTING + FAIL() << "The macro UNIT_TESTING is not defined, please add this to your CMake compile definitions."; + #endif /* UNIT_TESTING */ +} + +/* Test prvOTAEventBufferFree */ +TEST_F( TestOtaAgentTask, freeing_ota_event_buffer_frees_buffer ) +{ + OtaEventData_t pxBuffer = { 0 }; + + pxBuffer.bufferUsed = true; + prvOTAEventBufferFree( &pxBuffer ); + EXPECT_FALSE( pxBuffer.bufferUsed ); +} + +/* Test prvOTAEventBufferGet */ +TEST_F( TestOtaAgentTask, buffer_size_is_sufficient_for_these_tests_to_run ) +{ + /* must have at least 2 buffers to for these tests to run. */ + EXPECT_GE( otaconfigMAX_NUM_OTA_DATA_BUFFERS, 2 ); +} + +TEST_F( TestOtaAgentTask, getting_a_single_buffer_does_not_return_nullpointer ) +{ + OtaEventData_t * buffer = prvOTAEventBufferGet(); + + EXPECT_NE( buffer, nullptr ); +} + +TEST_F( TestOtaAgentTask, the_agent_eventually_runs_out_of_data_buffers ) +{ + OtaEventData_t * buffer; + + for( int i = 0; i < otaconfigMAX_NUM_OTA_DATA_BUFFERS + 10; i++ ) + { + buffer = prvOTAEventBufferGet(); + } + + EXPECT_EQ( buffer, nullptr ); +} + +TEST_F( TestOtaAgentTask, tests_do_not_interfere_with_each_other ) +{ + OtaEventData_t * buffer = prvOTAEventBufferGet(); + + EXPECT_NE( buffer, nullptr ); +} + +TEST_F( TestOtaAgentTask, get_uses_all_available_buffers ) +{ + /* This test failing will mean some subsequent tests fail. */ + OtaEventData_t * buffer; + + for( int i = 0; i < otaconfigMAX_NUM_OTA_DATA_BUFFERS - 1; i++ ) + { + buffer = prvOTAEventBufferGet(); + } + + EXPECT_NE( buffer, nullptr ); + buffer = prvOTAEventBufferGet(); + EXPECT_NE( buffer, nullptr ); + buffer = prvOTAEventBufferGet(); + EXPECT_EQ( buffer, nullptr ); +} + +TEST_F( TestOtaAgentTask, getting_buffer_marks_it_as_in_use ) +{ + OtaEventData_t * buffer = prvOTAEventBufferGet(); + + EXPECT_TRUE( buffer->bufferUsed ); +} + +TEST_F( TestOtaAgentTask, freeing_a_buffer_marks_it_as_out_of_use ) +{ + OtaEventData_t * buffer = prvOTAEventBufferGet(); + + EXPECT_TRUE( buffer->bufferUsed ); + prvOTAEventBufferFree( buffer ); + EXPECT_FALSE( buffer->bufferUsed ); +} + +TEST_F( TestOtaAgentTask, buffers_are_reused ) +{ + /* Freeing then getting all buffers marks the initially freed buffer as in use */ + OtaEventData_t * buffer = prvOTAEventBufferGet(); + + EXPECT_TRUE( buffer->bufferUsed ); + prvOTAEventBufferFree( buffer ); + EXPECT_FALSE( buffer->bufferUsed ); + + for( int i = 0; i < otaconfigMAX_NUM_OTA_DATA_BUFFERS; i++ ) + { + OtaEventData_t * unused = prvOTAEventBufferGet(); + } + + EXPECT_TRUE( buffer->bufferUsed ); +} + +TEST_F( TestOtaAgentTask, freeing_a_buffer_causes_previously_failing_buffer_get_to_succeed ) +{ + OtaEventData_t * buffer_1; + + for( int i = 0; i < otaconfigMAX_NUM_OTA_DATA_BUFFERS; i++ ) + { + buffer_1 = prvOTAEventBufferGet(); + EXPECT_NE( buffer_1, nullptr ); + } + + OtaEventData_t * buffer_2 = prvOTAEventBufferGet(); + EXPECT_EQ( buffer_2, nullptr ); + /* Free the last buffer that was claimed. */ + prvOTAEventBufferFree( buffer_1 ); + /* Try to claim a buffer again. Expect to succeed this time. */ + buffer_2 = prvOTAEventBufferGet(); + EXPECT_NE( buffer_2, nullptr ) << "Expected to a buffer to become available after freeing"; +} + +/* Mock for OTA_ActivateImage */ +OtaErr_t stop_running_test_if_image_activated( void ) +{ + throw CONTEXT_SWITCH_FAKE; + return OtaErrNone; +} + +/* otaAppCallback */ +TEST_F( TestOtaAgentTask, agent_activates_image_if_image_is_authenticated_and_ready_to_activate ) +{ + OTA_ActivateNewImage_fake.custom_fake = stop_running_test_if_image_activated; + OTA_Shutdown_fake.return_val = OtaAgentStateShuttingDown; + OTA_SetImageState_fake.return_val = OtaErrNone; + OTA_GetState_fake.return_val = OtaAgentStateReady; + EXPECT_EQ( OTA_ActivateNewImage_fake.call_count, 0 ); + try { + otaAppCallback( OtaJobEventActivate, nullptr ); + } + catch( int num ) { + if( num != CONTEXT_SWITCH_FAKE ) + { + throw num; + } + } + EXPECT_NE( OTA_ActivateNewImage_fake.call_count, 0 ); +} +TEST_F( TestOtaAgentTask, agent_does_not_try_to_activate_image_if_update_rejected ) +{ + OTA_ActivateNewImage_fake.return_val = OtaErrNone; + OTA_Shutdown_fake.return_val = OtaAgentStateShuttingDown; + OTA_SetImageState_fake.return_val = OtaErrNone; + OTA_GetState_fake.return_val = OtaAgentStateReady; + EXPECT_EQ( OTA_ActivateNewImage_fake.call_count, 0 ); + otaAppCallback( OtaJobEventFail, nullptr ); + EXPECT_EQ( OTA_ActivateNewImage_fake.call_count, 0 ); +} +TEST_F( TestOtaAgentTask, agent_frees_event_buffer_once_event_is_processed ) +{ + OtaEventData_t * buffer = prvOTAEventBufferGet(); + + EXPECT_TRUE( buffer->bufferUsed ); + otaAppCallback( OtaJobEventProcessed, buffer ); + EXPECT_FALSE( buffer->bufferUsed ); +} +TEST_F( TestOtaAgentTask, agent_calls_not_active_hook_when_job_received ) +{ + EXPECT_EQ( vOtaActiveHook_fake.call_count, 0 ); + otaAppCallback( OtaJobEventReceivedJob, nullptr ); + EXPECT_NE( vOtaActiveHook_fake.call_count, 0 ); +} +TEST_F( TestOtaAgentTask, agent_calls_active_hook_when_no_job_is_received ) +{ + EXPECT_EQ( vOtaNotActiveHook_fake.call_count, 0 ); + otaAppCallback( OtaJobEventNoActiveJob, nullptr ); + EXPECT_NE( vOtaNotActiveHook_fake.call_count, 0 ); +} +TEST_F( TestOtaAgentTask, agent_tries_to_set_image_state_when_starting_test ) +{ + EXPECT_EQ( OTA_SetImageState_fake.call_count, 0 ); + otaAppCallback( OtaJobEventStartTest, nullptr ); + EXPECT_NE( OTA_SetImageState_fake.call_count, 0 ); +} +TEST_F( TestOtaAgentTask, agent_tries_to_set_image_state_as_accepted_when_starting_test ) +{ + /* Agent marks valid image as accepted */ + EXPECT_EQ( OTA_SetImageState_fake.call_count, 0 ); + otaAppCallback( OtaJobEventStartTest, nullptr ); + OTA_SetImageState_fake.custom_fake = should_set_image_to_accepted_state; +} +TEST_F( TestOtaAgentTask, agent_shuts_down_ota_with_error_message_if_self_test_is_failed ) +{ + /* 'Self test' refers to validating the image using signatures, and checking */ + /* that the version number has increased. */ + /* For more information, see AWS OTA documentation. */ + SdkLogError_fake.custom_fake = do_nothing_if_an_error_occurs; + EXPECT_EQ( SdkLogError_fake.call_count, 0 ); + EXPECT_EQ( OTA_Shutdown_fake.call_count, 0 ); + otaAppCallback( OtaJobEventSelfTestFailed, nullptr ); + EXPECT_NE( OTA_Shutdown_fake.call_count, 0 ); + EXPECT_NE( SdkLogError_fake.call_count, 0 ); +} + +/* prvMqttJobCallback */ +TEST_F( TestOtaAgentTask, job_callback_does_not_error_for_a_normal_call ) +{ + int payload = 15; + MQTTPublishInfo_t pubInfo = { MQTTQoS0, true, true, "topic name", 11, &payload, 1 }; + + prvMqttJobCallback( nullptr, &pubInfo ); +} +TEST_F( TestOtaAgentTask, job_callback_tries_to_send_event_for_valid_data ) +{ + /* Tries to send job document received event when job is done */ + EXPECT_EQ( OTA_SignalEvent_fake.call_count, 0 ); + int payload = 15; + MQTTPublishInfo_t pubInfo = { MQTTQoS0, true, true, "topic name", 11, &payload, 1 }; + prvMqttJobCallback( nullptr, &pubInfo ); + EXPECT_NE( OTA_SignalEvent_fake.call_count, 0 ); +} +TEST_F( TestOtaAgentTask, job_callback_does_not_try_to_send_event_for_too_large_a_mqtt_payload ) +{ + /* This needs to be sanitised because the user controls the payload. */ + /* This test tries to get the job callback to seg fault. E.g. by bad use of memcpy. */ + SdkLogError_fake.custom_fake = do_nothing_if_an_error_occurs; + try { + EXPECT_EQ( OTA_SignalEvent_fake.call_count, 0 ); + uint32_t * largePayload[ 1000 ]; + MQTTPublishInfo_t pubInfo = { MQTTQoS0, true, true, "topic name", 11, ( void * ) largePayload, 1000 }; + prvMqttJobCallback( nullptr, &pubInfo ); + EXPECT_EQ( OTA_SignalEvent_fake.call_count, 0 ); + } + catch( int num ) { + if( num == ASSERTION_FAILURE ) + { + EXPECT_EQ( OTA_SignalEvent_fake.call_count, 0 ); + } + else + { + throw ( num ); + } + } +} +TEST_F( TestOtaAgentTask, job_callback_does_not_send_event_signal_again_if_signal_was_received_correctly ) +{ + OTA_SignalEvent_fake.return_val = true; /* success */ + EXPECT_EQ( OTA_SignalEvent_fake.call_count, 0 ); + int payload = 15; + MQTTPublishInfo_t pubInfo = { MQTTQoS0, true, true, "topic name", 11, &payload, 1 }; + prvMqttJobCallback( nullptr, &pubInfo ); + EXPECT_EQ( OTA_SignalEvent_fake.call_count, 1 ); +} + +/* prvMqttDefaultCallback */ + +TEST_F( TestOtaAgentTask, mqtt_default_handler_redirects_publishes_to_handlers_based_on_topics ) +{ + int payload = 15; + MQTTPublishInfo_t pubInfo = { MQTTQoS0, true, true, "topic name", 11, &payload, 1 }; + + EXPECT_EQ( MQTT_MatchTopic_fake.call_count, 0 ); + prvMqttDefaultCallback( nullptr, &pubInfo ); + EXPECT_NE( MQTT_MatchTopic_fake.call_count, 0 ); +} +TEST_F( TestOtaAgentTask, mqtt_default_handler_handles_very_large_data_packet ) +{ + /* We are trying to break bad use of memcpy in this test. */ + SdkLogError_fake.custom_fake = do_nothing_if_an_error_occurs; + size_t tooLargeForBuffer = 1000; /* probably too big for the mqtt buffer. */ + int payload[ tooLargeForBuffer ]; + + for( int i = 0; i < tooLargeForBuffer; i++ ) + { + payload[ i ] = i; + } + + MQTTPublishInfo_t pubInfo = { MQTTQoS0, true, true, "topic name", 11, &payload, tooLargeForBuffer }; + MQTT_MatchTopic_fake.custom_fake = set_match_true; + prvMqttDefaultCallback( nullptr, &pubInfo ); + MQTT_MatchTopic_fake.custom_fake = set_match_false; + prvMqttDefaultCallback( nullptr, &pubInfo ); + /* Do not SegFault either way. */ +} + +/* prvMqttDataCallback */ + +TEST_F( TestOtaAgentTask, mqtt_data_handler_signals_if_successful ) +{ + EXPECT_EQ( OTA_SignalEvent_fake.call_count, 0 ); + int payload = 12; + MQTTPublishInfo_t pubInfo = { MQTTQoS0, true, true, "topic name", 11, &payload, 1 }; + prvMqttDataCallback( nullptr, &pubInfo ); + EXPECT_NE( OTA_SignalEvent_fake.call_count, 0 ); +} +TEST_F( TestOtaAgentTask, mqtt_data_handler_does_not_segfault_on_large_data_packets ) +{ + SdkLogError_fake.custom_fake = do_nothing_if_an_error_occurs; + size_t tooLargeForBuffer = 1000; /* probably too big for the mqtt buffer. */ + int payload[ tooLargeForBuffer ]; + + for( int i = 0; i < tooLargeForBuffer; i++ ) + { + payload[ i ] = i; + } + + MQTTPublishInfo_t pubInfo = { MQTTQoS0, true, true, "topic name", 11, &payload, tooLargeForBuffer }; + prvMqttDataCallback( nullptr, &pubInfo ); + + if( SdkLogError_fake.call_count > 0 ) + { + /* then expect no event signal to have been sent. */ + EXPECT_EQ( OTA_SignalEvent_fake.call_count, 0 ); + } +} +TEST_F( TestOtaAgentTask, mqtt_data_handler_signals_file_block_received_if_successful ) +{ + int payload = 12; + MQTTPublishInfo_t pubInfo = { MQTTQoS0, true, true, "topic name", 11, &payload, 1 }; + + prvMqttDataCallback( nullptr, &pubInfo ); + OTA_SignalEvent_fake.custom_fake = expect_block_received_signal; +} +TEST_F( TestOtaAgentTask, mqtt_data_handler_errors_if_out_of_ota_data_buffers ) +{ + for( int i = 0; i < otaconfigMAX_NUM_OTA_DATA_BUFFERS; i++ ) + { + OtaEventData_t * buffer = prvOTAEventBufferGet(); + EXPECT_NE( buffer, nullptr ); + } + + OtaEventData_t * buffer = prvOTAEventBufferGet(); + EXPECT_EQ( buffer, nullptr ); + /* Out of data buffers */ + int payload = 15; + MQTTPublishInfo_t pubInfo = { MQTTQoS0, true, true, "topic name", 11, &payload, 1 }; + SdkLogError_fake.custom_fake = do_nothing_if_an_error_occurs; + prvMqttDataCallback( nullptr, &pubInfo ); + expect_errors(); + EXPECT_EQ( OTA_SignalEvent_fake.call_count, 0 ); +} +TEST_F( TestOtaAgentTask, mqtt_data_handler_does_not_send_signal_if_out_of_ota_data_buffers ) +{ + SdkLogError_fake.custom_fake = do_nothing_if_an_error_occurs; /* being out of buffers will cause errors. */ + OtaEventData_t * buffer; + + for( int i = 0; i < otaconfigMAX_NUM_OTA_DATA_BUFFERS + 10; i++ ) + { + buffer = prvOTAEventBufferGet(); + } + + EXPECT_EQ( buffer, nullptr ); + int payload = 15; + MQTTPublishInfo_t pubInfo = { MQTTQoS0, true, true, "topic name", 11, &payload, 1 }; + prvMqttDataCallback( nullptr, &pubInfo ); + EXPECT_EQ( OTA_SignalEvent_fake.call_count, 0 ); +} + +/* prvRegisterOTACallback + * Is a callback for receiving messages intended for the OTA agent, from the broker. + */ + +TEST_F( TestOtaAgentTask, the_ota_callback_does_not_add_a_subscription_if_no_topics_match ) +{ + MQTT_MatchTopic_fake.custom_fake = set_match_false; + prvRegisterOTACallback( "dummy", 6 ); + EXPECT_EQ( addSubscription_fake.call_count, 0 ); +} +TEST_F( TestOtaAgentTask, the_ota_callback_adds_a_subscription_if_topics_match ) +{ + MQTT_MatchTopic_fake.custom_fake = set_match_true; + prvRegisterOTACallback( "dummy", 6 ); + EXPECT_NE( addSubscription_fake.call_count, 0 ); +} +TEST_F( TestOtaAgentTask, the_ota_callback_adds_a_subscription_per_matching_topic ) +{ + /* We also assume there are at least 2 matching topics for this test. */ + global_counter = 2; + int initial_counter_value = global_counter; + MQTT_MatchTopic_fake.custom_fake = match_while_global_counter_is_positive; + prvRegisterOTACallback( "dummy", 6 ); + EXPECT_EQ( addSubscription_fake.call_count, initial_counter_value ); +} + +/* prvMQTTSubscribeCompleteCallback */ + +TEST_F( TestOtaAgentTask, command_return_code_is_stored_in_mqtt_return_info ) +{ + MQTTAgentReturnInfo_t returnInfo; + MQTTSubscribeInfo_t info; + + info.pTopicFilter = "dummy"; + info.topicFilterLength = 6; + info.qos = MQTTQoS0; + MQTTAgentSubscribeArgs_t subscribeArgs; + subscribeArgs.pSubscribeInfo = &info; + MQTTAgentCommandContext_t cmndCtxt; + cmndCtxt.pArgs = &subscribeArgs; + returnInfo.returnCode = MQTTSuccess; + prvMQTTSubscribeCompleteCallback( &cmndCtxt, &returnInfo ); + EXPECT_EQ( cmndCtxt.xReturnStatus, returnInfo.returnCode ); + returnInfo.returnCode = MQTTBadParameter; + prvMQTTSubscribeCompleteCallback( &cmndCtxt, &returnInfo ); + EXPECT_EQ( cmndCtxt.xReturnStatus, returnInfo.returnCode ); +} +TEST_F( TestOtaAgentTask, if_there_is_a_task_to_notify_a_task_is_notified ) +{ + int task = 5; + MQTTAgentReturnInfo_t returnInfo; + MQTTSubscribeInfo_t info; + + info.pTopicFilter = "dummy"; + info.topicFilterLength = 6; + info.qos = MQTTQoS0; + MQTTAgentSubscribeArgs_t subscribeArgs; + subscribeArgs.pSubscribeInfo = &info; + MQTTAgentCommandContext_t cmndCtxt; + cmndCtxt.pArgs = &subscribeArgs; + cmndCtxt.xTaskToNotify = &task; + returnInfo.returnCode = MQTTSuccess; + EXPECT_EQ( xTaskNotify_fake.call_count, 0 ); + prvMQTTSubscribeCompleteCallback( &cmndCtxt, &returnInfo ); + EXPECT_NE( xTaskNotify_fake.call_count, 0 ); +} +TEST_F( TestOtaAgentTask, if_there_is_a_task_to_notify_the_correct_task_is_notified ) +{ + int task = 5; /* do not change this without modifying the fake for xTaskNotify */ + MQTTAgentReturnInfo_t returnInfo; + MQTTSubscribeInfo_t info; + + info.pTopicFilter = "dummy"; + info.topicFilterLength = 6; + info.qos = MQTTQoS0; + MQTTAgentSubscribeArgs_t subscribeArgs; + subscribeArgs.pSubscribeInfo = &info; + MQTTAgentCommandContext_t cmndCtxt; + cmndCtxt.pArgs = &subscribeArgs; + cmndCtxt.xTaskToNotify = &task; + returnInfo.returnCode = MQTTSuccess; + xTaskNotify_fake.custom_fake = expect_task_to_notify_is_five; + EXPECT_EQ( xTaskNotify_fake.call_count, 0 ); + prvMQTTSubscribeCompleteCallback( &cmndCtxt, &returnInfo ); + EXPECT_NE( xTaskNotify_fake.call_count, 0 ); +} +TEST_F( TestOtaAgentTask, if_there_is_no_task_then_task_notify_is_not_called ) +{ + MQTTAgentReturnInfo_t returnInfo; + MQTTSubscribeInfo_t info; + + info.pTopicFilter = "dummy"; + info.topicFilterLength = 6; + info.qos = MQTTQoS0; + MQTTAgentSubscribeArgs_t subscribeArgs; + subscribeArgs.pSubscribeInfo = &info; + MQTTAgentCommandContext_t cmndCtxt; + cmndCtxt.pArgs = &subscribeArgs; + cmndCtxt.xTaskToNotify = nullptr; + returnInfo.returnCode = MQTTSuccess; + prvMQTTSubscribeCompleteCallback( &cmndCtxt, &returnInfo ); + EXPECT_EQ( xTaskNotify_fake.call_count, 0 ); +} + +/* prvMQTTUnsubscribeCompleteCallback */ + +/* These tests duplicate code because it is poor practice to share variables between unit tests. */ +TEST_F( TestOtaAgentTask, command_return_code_is_stored_in_mqtt_return_info_2 ) +{ + MQTTAgentReturnInfo_t returnInfo; + MQTTSubscribeInfo_t info; + + info.pTopicFilter = "dummy"; + info.topicFilterLength = 6; + info.qos = MQTTQoS0; + MQTTAgentSubscribeArgs_t subscribeArgs; + subscribeArgs.pSubscribeInfo = &info; + MQTTAgentCommandContext_t cmndCtxt; + cmndCtxt.pArgs = &subscribeArgs; + returnInfo.returnCode = MQTTSuccess; + prvMQTTUnsubscribeCompleteCallback( &cmndCtxt, &returnInfo ); + EXPECT_EQ( cmndCtxt.xReturnStatus, returnInfo.returnCode ); + returnInfo.returnCode = MQTTBadParameter; + prvMQTTUnsubscribeCompleteCallback( &cmndCtxt, &returnInfo ); + EXPECT_EQ( cmndCtxt.xReturnStatus, returnInfo.returnCode ); +} +TEST_F( TestOtaAgentTask, if_there_is_a_task_to_notify_this_task_is_notified_2 ) +{ + int task = 5; + MQTTAgentReturnInfo_t returnInfo; + MQTTSubscribeInfo_t info; + + info.pTopicFilter = "dummy"; + info.topicFilterLength = 6; + info.qos = MQTTQoS0; + MQTTAgentSubscribeArgs_t subscribeArgs; + subscribeArgs.pSubscribeInfo = &info; + MQTTAgentCommandContext_t cmndCtxt; + cmndCtxt.pArgs = &subscribeArgs; + cmndCtxt.xTaskToNotify = &task; + returnInfo.returnCode = MQTTSuccess; + xTaskNotify_fake.custom_fake = expect_task_to_notify_is_five; + EXPECT_EQ( xTaskNotify_fake.call_count, 0 ); + prvMQTTUnsubscribeCompleteCallback( &cmndCtxt, &returnInfo ); + EXPECT_NE( xTaskNotify_fake.call_count, 0 ); +} + +/* prvMQTTSubscribe */ + +TEST_F( TestOtaAgentTask, mqtt_subscribe_subscribes_to_a_topic ) +{ + EXPECT_EQ( MQTTAgent_Subscribe_fake.call_count, 0 ); + prvMQTTSubscribe( "dummy", 6, 0 ); + EXPECT_NE( MQTTAgent_Subscribe_fake.call_count, 0 ); +} +TEST_F( TestOtaAgentTask, mqtt_subscribe_asks_for_the_current_task_to_be_notified ) +{ + int this_task = 5; + + xTaskGetCurrentTaskHandle_fake.return_val = &this_task; + xTaskNotify_fake.custom_fake = expect_task_to_notify_is_five; + EXPECT_EQ( xTaskGetCurrentTaskHandle_fake.call_count, 0 ); + prvMQTTSubscribe( "dummy", 6, 0 ); + EXPECT_NE( xTaskGetCurrentTaskHandle_fake.call_count, 0 ); +} +/* We do not test this function for null pointer inputs */ +/* because the topic filter not being null could be taken as a */ +/* pre-condition. */ +TEST_F( TestOtaAgentTask, mqtt_subscribe_returns_success_on_successful_subscription ) +{ + int this_task = 8; + + xTaskGetCurrentTaskHandle_fake.return_val = &this_task; + MQTTAgent_Subscribe_fake.custom_fake = fake_successful_subscription; + EXPECT_EQ( prvMQTTSubscribe( "dummy", 6, 0 ), OtaMqttSuccess ); +} +TEST_F( TestOtaAgentTask, mqtt_subscribe_returns_failure_on_unsuccessful_subscription ) +{ + SdkLogError_fake.custom_fake = do_nothing_if_an_error_occurs; + int this_task = 8; + xTaskGetCurrentTaskHandle_fake.return_val = &this_task; + MQTTAgent_Subscribe_fake.custom_fake = fake_bad_subscribe_parameter; + EXPECT_NE( prvMQTTSubscribe( "dummy", 6, 0 ), OtaMqttSuccess ); +} + +/* prvOTAPublishCommandCallback */ +TEST_F( TestOtaAgentTask, publish_callback_sets_return_code ) +{ + MQTTStatus_t expectedReturnStatus = MQTTSuccess; + MQTTAgentCommandContext_t cmndCtxt = { MQTTBadParameter }; + MQTTAgentReturnInfo_t retInfo = { expectedReturnStatus }; + + EXPECT_NE( cmndCtxt.xReturnStatus, expectedReturnStatus ); + prvOTAPublishCommandCallback( &cmndCtxt, &retInfo ); + EXPECT_EQ( cmndCtxt.xReturnStatus, expectedReturnStatus ); + /* Sasme functionality tested, different arguments. */ + expectedReturnStatus = MQTTRecvFailed; + retInfo = { expectedReturnStatus }; + prvOTAPublishCommandCallback( &cmndCtxt, &retInfo ); + EXPECT_EQ( cmndCtxt.xReturnStatus, expectedReturnStatus ); +} +TEST_F( TestOtaAgentTask, publish_callback_notifies_task_if_task_to_notify_is_set ) +{ + int task = 5; + + xTaskNotify_fake.return_val = pdPASS; + MQTTAgentCommandContext_t cmndCtxt = { MQTTBadParameter, &task }; + MQTTAgentReturnInfo_t retInfo = { MQTTSuccess }; + EXPECT_EQ( xTaskNotify_fake.call_count, 0 ); + prvOTAPublishCommandCallback( &cmndCtxt, &retInfo ); + EXPECT_NE( xTaskNotify_fake.call_count, 0 ); +} +TEST_F( TestOtaAgentTask, publish_callback_does_not_notify_task_if_task_to_notify_is_not_set ) +{ + MQTTAgentCommandContext_t cmndCtxt = { MQTTBadParameter, nullptr }; + MQTTAgentReturnInfo_t retInfo = { MQTTSuccess }; + + EXPECT_EQ( xTaskNotify_fake.call_count, 0 ); + prvOTAPublishCommandCallback( &cmndCtxt, &retInfo ); + EXPECT_EQ( xTaskNotify_fake.call_count, 0 ); +} + +/* prvMQTTPublish + * Handles sending a publish via MQTT + */ + +TEST_F( TestOtaAgentTask, publishing_calls_mqtt_publish_api ) +{ + EXPECT_EQ( MQTTAgent_Publish_fake.call_count, 0 ); + prvMQTTPublish( "dummy1", 7, "dummymsg", 9, MQTTQoS0 ); + EXPECT_NE( MQTTAgent_Publish_fake.call_count, 0 ); +} +TEST_F( TestOtaAgentTask, publishing_waits_on_mqtt_publish_to_finish_before_it_can_return_result_of_the_publish ) +{ + EXPECT_EQ( xTaskNotifyWait_fake.call_count, 0 ); + prvMQTTPublish( "dummy1", 7, "dummymsg", 9, MQTTQoS1 ); + EXPECT_NE( xTaskNotifyWait_fake.call_count, 0 ); +} +TEST_F( TestOtaAgentTask, publishing_returns_failure_if_mqtt_publish_fails ) +{ + SdkLogError_fake.custom_fake = do_nothing_if_an_error_occurs; + MQTTAgent_Publish_fake.custom_fake = fake_bad_publish_parameter; + EXPECT_EQ( prvMQTTPublish( "dummy1", 7, "dummymsg", 9, MQTTQoS1 ), OtaMqttPublishFailed ); +} +TEST_F( TestOtaAgentTask, publishing_returns_failure_if_waiting_on_the_publish_command_fails ) +{ + SdkLogError_fake.custom_fake = do_nothing_if_an_error_occurs; + /* i.e. xTaskNotifyWait returns failure, so notification has not happened. */ + xTaskNotifyWait_fake.return_val = pdFAIL; + EXPECT_EQ( prvMQTTPublish( "dummy1", 7, "dummymsg", 9, MQTTQoS1 ), OtaMqttPublishFailed ); +} +TEST_F( TestOtaAgentTask, publishing_returns_success_if_mqtt_publish_succeeds ) +{ + MQTTAgent_Publish_fake.custom_fake = set_return_status_to_mqtt_success; + EXPECT_EQ( prvMQTTPublish( "dummy1", 7, "dummymsg", 9, MQTTQoS1 ), OtaMqttSuccess ); +} +TEST_F( TestOtaAgentTask, publishing_returns_failure_if_scheduling_command_via_mqtt_publish_succeeds_but_the_command_fails ) +{ + SdkLogError_fake.custom_fake = do_nothing_if_an_error_occurs; + MQTTAgent_Publish_fake.custom_fake = set_return_status_to_mqtt_bad_parameter; + EXPECT_EQ( prvMQTTPublish( "dummy1", 7, "dummymsg", 9, MQTTQoS1 ), OtaMqttPublishFailed ); +} + +/* prvMQTTUnsubscribe */ + +TEST_F( TestOtaAgentTask, unsubscribe_calls_mqtt_unsubscribe ) +{ + EXPECT_EQ( MQTTAgent_Unsubscribe_fake.call_count, 0 ); + prvMQTTUnsubscribe( "dummy", 6, 0 ); + EXPECT_NE( MQTTAgent_Unsubscribe_fake.call_count, 0 ); +} +TEST_F( TestOtaAgentTask, unsubscribe_gets_current_task_handle ) +{ + /* presumably to notify the current task once a block arrives that matches a subscription. */ + EXPECT_EQ( xTaskGetCurrentTaskHandle_fake.call_count, 0 ); + prvMQTTUnsubscribe( "dummy", 6, 0 ); + EXPECT_NE( xTaskGetCurrentTaskHandle_fake.call_count, 0 ); +} +TEST_F( TestOtaAgentTask, unsubcribe_tries_to_wait_on_something ) +{ + /* This test is a pre-requisite for verifying that unsubscirbe waits on the MQTTAgent_Unsubscribe command */ + EXPECT_EQ( xTaskNotifyWait_fake.call_count, 0 ); + prvMQTTUnsubscribe( "dummy", 6, 0 ); + EXPECT_NE( xTaskNotifyWait_fake.call_count, 0 ); +} +TEST_F( TestOtaAgentTask, unsubcribe_waits_while_unsubscription_command_completes ) +{ + /* This behaviour is needed because otherwise we cannot return failure if the command fails. + * Nor can we cleanup resources allocated for the unsubscribe call. + * I.e. must call unsubscribe first, and then call wait */ + xTaskNotifyWait_fake.custom_fake = stop_the_rest_of_the_program_running; + EXPECT_EQ( xTaskNotifyWait_fake.call_count, 0 ); + try { + prvMQTTUnsubscribe( "dummy", 6, 0 ); + } + catch( int num ) { + if( num != CONTEXT_SWITCH_FAKE ) + { + throw ( num ); + } + } + /* I.e. Unsubscribe must be called before waiting. */ + EXPECT_NE( MQTTAgent_Unsubscribe_fake.call_count, 0 ); + EXPECT_NE( xTaskNotifyWait_fake.call_count, 0 ); +} +TEST_F( TestOtaAgentTask, unsubscribe_returns_failure_if_mqtt_unsubscribe_fails ) +{ + SdkLogError_fake.custom_fake = do_nothing_if_an_error_occurs; + MQTTAgent_Unsubscribe_fake.custom_fake = fake_bad_subscribe_parameter; + EXPECT_NE( prvMQTTUnsubscribe( "dummy", 6, 0 ), OtaMqttSuccess ); +} +TEST_F( TestOtaAgentTask, unsubscribe_returns_failure_if_mqtt_unsubscribe_succeeds_but_command_fails ) +{ + SdkLogError_fake.custom_fake = do_nothing_if_an_error_occurs; + MQTTAgent_Unsubscribe_fake.custom_fake = fake_subscribe_command_failure_only; + EXPECT_NE( prvMQTTUnsubscribe( "dummy", 6, 0 ), OtaMqttSuccess ); +} +TEST_F( TestOtaAgentTask, unsubscribe_returns_success_if_mqtt_unsubscribe_succeeds_and_command_succeeds ) +{ + MQTTAgent_Unsubscribe_fake.custom_fake = fake_successful_subscription; + EXPECT_EQ( prvMQTTUnsubscribe( "dummy", 6, 0 ), OtaMqttSuccess ); +} + +/* setOtaInterfaces */ +TEST_F( TestOtaAgentTask, setting_ota_interfaces_changes_the_passed_interface_values ) +{ + /* Just check a few fields */ + OtaInterfaces_t * interface = ( OtaInterfaces_t * ) calloc( 1, sizeof( OtaInterfaces_t ) ); + + EXPECT_NE( interface, nullptr ); + OtaFree_t original_free = interface->os.mem.free; + OtaMalloc_t original_malloc = interface->os.mem.malloc; + OtaMqttPublish_t original_publish = interface->mqtt.publish; + OtaPalWriteBlock_t original_writeBlock = interface->pal.writeBlock; + setOtaInterfaces( interface ); + EXPECT_NE( interface->os.mem.free, original_free ); + EXPECT_NE( interface->os.mem.malloc, original_malloc ); + EXPECT_NE( interface->mqtt.publish, original_publish ); + EXPECT_NE( interface->pal.writeBlock, original_writeBlock ); + free( interface ); +} + +/* prvOTAAgentTask */ +TEST_F( TestOtaAgentTask, ota_agent_task_gets_called ) +{ + EXPECT_EQ( OTA_EventProcessingTask_fake.call_count, 0 ); + prvOTAAgentTask( nullptr ); + EXPECT_NE( OTA_EventProcessingTask_fake.call_count, 0 ); +} + +/* prvSuspendOTA */ + +TEST_F( TestOtaAgentTask, suspending_ota_calls_ota_suspend ) +{ + OTA_Suspend_fake.custom_fake = fake_successful_ota_suspend; + EXPECT_EQ( OTA_Suspend_fake.call_count, 0 ); + prvSuspendOTA(); + EXPECT_NE( OTA_Suspend_fake.call_count, 0 ); +} +TEST_F( TestOtaAgentTask, suspend_returns_success_if_ota_suspend_call_does_not_error ) +{ + OTA_Suspend_fake.custom_fake = fake_successful_ota_suspend; + EXPECT_EQ( prvSuspendOTA(), pdPASS ); +} +TEST_F( TestOtaAgentTask, suspend_ota_returns_failure_if_ota_library_suspend_returns_failure ) +{ + SdkLogError_fake.custom_fake = do_nothing_if_an_error_occurs; + OTA_Suspend_fake.custom_fake = fake_unsuccessful_ota_suspend; + OTA_Suspend_fake.return_val = OtaErrUninitialized; + OTA_GetState_fake.return_val = OtaAgentStateShuttingDown; + EXPECT_EQ( prvSuspendOTA(), pdFAIL ); +} +TEST_F( TestOtaAgentTask, suspend_ota_returns_failure_if_ota_suspend_reports_success_but_the_current_ota_state_is_not_suspended ) +{ + SdkLogError_fake.custom_fake = do_nothing_if_an_error_occurs; + OTA_Suspend_fake.custom_fake = fake_successful_ota_suspend_but_state_is_incorrect; + EXPECT_EQ( prvSuspendOTA(), pdFAIL ); +} +/* We do not test what happens if ota suspend returns an unusual error code because */ +/* There are many possible correct behaviours. */ + +/* prvResumeOTA */ + +TEST_F( TestOtaAgentTask, resuming_ota_calls_ota_resume ) +{ + OTA_Resume_fake.return_val = OtaErrNone; + OTA_GetState_fake.return_val = OtaAgentStateWaitingForFileBlock; + EXPECT_EQ( OTA_Resume_fake.call_count, 0 ); + prvResumeOTA(); + EXPECT_NE( OTA_Resume_fake.call_count, 0 ); +} +TEST_F( TestOtaAgentTask, resume_returns_success_if_ota_resume_call_does_not_error ) +{ + OTA_Resume_fake.return_val = OtaErrNone; + OTA_GetState_fake.return_val = OtaAgentStateWaitingForFileBlock; + EXPECT_EQ( prvResumeOTA(), pdPASS ); +} +TEST_F( TestOtaAgentTask, resume_ota_returns_failure_if_resuming_fails ) +{ + SdkLogError_fake.custom_fake = do_nothing_if_an_error_occurs; + OTA_Resume_fake.custom_fake = fake_unsuccessful_ota_resume; + EXPECT_EQ( prvResumeOTA(), pdFAIL ); +} +TEST_F( TestOtaAgentTask, resume_ota_returns_failure_if_ota_resume_reports_success_but_the_current_ota_state_is_not_resumed ) +{ + SdkLogError_fake.custom_fake = do_nothing_if_an_error_occurs; + OTA_Resume_fake.custom_fake = fake_successful_ota_resume_but_state_is_still_suspended; + EXPECT_EQ( prvResumeOTA(), pdFAIL ); +} + +/* Test prvRunOTADemo */ + +TEST_F( TestOtaAgentTask, demo_waits_for_mqtt_agent ) +{ + OTA_GetState_fake.return_val = OtaAgentStateStopped; + EXPECT_EQ( vWaitUntilMQTTAgentReady_fake.call_count, 0 ); + EXPECT_EQ( vWaitUntilMQTTAgentConnected_fake.call_count, 0 ); + prvRunOTADemo(); + EXPECT_NE( vWaitUntilMQTTAgentReady_fake.call_count, 0 ); + EXPECT_NE( vWaitUntilMQTTAgentConnected_fake.call_count, 0 ); +} +TEST_F( TestOtaAgentTask, demo_tries_to_initialise_ota_library ) +{ + OTA_GetState_fake.return_val = OtaAgentStateStopped; + EXPECT_EQ( OTA_Init_fake.call_count, 0 ); + prvRunOTADemo(); + EXPECT_NE( OTA_Init_fake.call_count, 0 ); +} +TEST_F( TestOtaAgentTask, demo_returns_failure_if_cannot_initialise_ota_library ) +{ + SdkLogError_fake.custom_fake = do_nothing_if_an_error_occurs; + OTA_GetState_fake.return_val = OtaAgentStateStopped; + OTA_Init_fake.return_val = OtaErrUninitialized; + EXPECT_EQ( prvRunOTADemo(), pdFAIL ); +} +TEST_F( TestOtaAgentTask, demo_tries_to_create_ota_agent_task ) +{ + OTA_GetState_fake.return_val = OtaAgentStateStopped; + EXPECT_EQ( xTaskCreate_fake.call_count, 0 ); + prvRunOTADemo(); + EXPECT_NE( xTaskCreate_fake.call_count, 0 ); +} +TEST_F( TestOtaAgentTask, demo_removes_subscription_to_broker_once_finished ) +{ + OTA_GetState_fake.return_val = OtaAgentStateStopped; + EXPECT_EQ( removeSubscription_fake.call_count, 0 ); + prvRunOTADemo(); + EXPECT_NE( removeSubscription_fake.call_count, 0 ); +} + +/* + * We do not test this function further because it may use infinite loops, + * and testing these loops will cause the tests to be brittle. + */ + +/* vOtaDemoTask */ + +TEST_F( TestOtaAgentTask, demo_task_tries_to_read_image_version ) +{ + OTA_GetState_fake.return_val = OtaAgentStateStopped; + xSemaphoreCreateMutex_fake.return_val = 100; + GetImageVersionPSA_fake.return_val = 0; + EXPECT_EQ( GetImageVersionPSA_fake.call_count, 0 ); + vOtaDemoTask( nullptr ); + EXPECT_NE( GetImageVersionPSA_fake.call_count, 0 ); +} + +/* Test vStartOtaTask */ +TEST_F( TestOtaAgentTask, starting_ota_task_creates_task ) +{ + EXPECT_EQ( xTaskCreate_fake.call_count, 0 ); + vStartOtaTask(); + EXPECT_NE( xTaskCreate_fake.call_count, 0 ); +} From 7733f676be1700a67eadad3edf24f3bd619e8d65 Mon Sep 17 00:00:00 2001 From: Reuben Cartwright Date: Thu, 12 Sep 2024 13:36:40 +0100 Subject: [PATCH 6/6] ota-agent-task: Fix bugs in ota_agent_task.c This commit fixes usage of memcpy with potentially user-defined inputs, without checking that the buffer could fit these inputs. Signed-off-by: Reuben Cartwright --- .../integration/src/ota_agent_task.c | 42 +++++++++++++------ release_changes/202409121339.change | 2 + 2 files changed, 32 insertions(+), 12 deletions(-) create mode 100644 release_changes/202409121339.change diff --git a/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/src/ota_agent_task.c b/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/src/ota_agent_task.c index 989f2f2..9d42e2d 100644 --- a/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/src/ota_agent_task.c +++ b/components/aws_iot/ota_for_aws_iot_embedded_sdk/integration/src/ota_agent_task.c @@ -470,6 +470,7 @@ STATIC OtaEventData_t * prvOTAEventBufferGet( void ) { eventBuffer[ ulIndex ].bufferUsed = true; pFreeBuffer = &eventBuffer[ ulIndex ]; + pFreeBuffer->dataLength = sizeof( pFreeBuffer->data ); break; } } @@ -616,13 +617,20 @@ STATIC void prvMqttJobCallback( void * pvIncomingPublishCallbackContext, if( pData != NULL ) { - memcpy( pData->data, pxPublishInfo->pPayload, pxPublishInfo->payloadLength ); - pData->dataLength = pxPublishInfo->payloadLength; - eventMsg.eventId = OtaAgentEventReceivedJobDocument; - eventMsg.pEventData = pData; + if( ( size_t ) pData->dataLength >= pxPublishInfo->payloadLength ) + { + memcpy( pData->data, pxPublishInfo->pPayload, pxPublishInfo->payloadLength ); + pData->dataLength = pxPublishInfo->payloadLength; + eventMsg.eventId = OtaAgentEventReceivedJobDocument; + eventMsg.pEventData = pData; - /* Send job document received event. */ - OTA_SignalEvent( &eventMsg ); + /* Send job document received event. */ + OTA_SignalEvent( &eventMsg ); + } + else + { + LogError( ( "Error: OTA data buffers are too small for the Job message provided.\n" ) ); + } } else { @@ -666,13 +674,20 @@ STATIC void prvMqttDataCallback( void * pvIncomingPublishCallbackContext, if( pxData != NULL ) { - memcpy( pxData->data, pxPublishInfo->pPayload, pxPublishInfo->payloadLength ); - pxData->dataLength = pxPublishInfo->payloadLength; - eventMsg.eventId = OtaAgentEventReceivedFileBlock; - eventMsg.pEventData = pxData; + if( ( size_t ) pxData->dataLength >= pxPublishInfo->payloadLength ) + { + memcpy( pxData->data, pxPublishInfo->pPayload, pxPublishInfo->payloadLength ); + pxData->dataLength = pxPublishInfo->payloadLength; + eventMsg.eventId = OtaAgentEventReceivedFileBlock; + eventMsg.pEventData = pxData; - /* Send job document received event. */ - OTA_SignalEvent( &eventMsg ); + /* Send file block received event. */ + OTA_SignalEvent( &eventMsg ); + } + else + { + LogError( ( "Error: OTA data buffers are too small for the data message received.\n" ) ); + } } else { @@ -762,6 +777,9 @@ STATIC void prvMQTTUnsubscribeCompleteCallback( MQTTAgentCommandContext_t * pxCo } } +/* + * Precondition: pTopicFilter is not null. + */ STATIC OtaMqttStatus_t prvMQTTSubscribe( const char * pTopicFilter, uint16_t topicFilterLength, uint8_t ucQoS ) diff --git a/release_changes/202409121339.change b/release_changes/202409121339.change new file mode 100644 index 0000000..53208e9 --- /dev/null +++ b/release_changes/202409121339.change @@ -0,0 +1,2 @@ +aws-iot-unit-test: Add tests for ota_agent_task.c. +ota-agent-task: Debug unsafe memcpy usages in ota_agent_task.c.