From e5571e4392b3532f0bcaa13fe9b404c53cc39124 Mon Sep 17 00:00:00 2001 From: Ramiro Recchia Date: Wed, 8 Oct 2025 15:01:40 -0300 Subject: [PATCH 01/18] TC_SU_2_8 test with base class --- examples/ota-provider-app/linux/main.cpp | 816 +++++++++--------- .../ota-provider-common/BdxOtaSender.cpp | 451 +++++----- .../ota-provider-common/BdxOtaSender.h | 62 +- .../suites/certification/Test_TC_SU_2_8.yaml | 91 -- src/python_testing/TC_SUTestBase.py | 492 +++++++++++ src/python_testing/TC_SU_2_8.py | 459 ++++++++++ .../matter/testing/apps.py | 137 +-- .../matter/typings/matter/testing/apps.pyi | 18 +- src/python_testing/test_metadata.yaml | 6 +- 9 files changed, 1726 insertions(+), 806 deletions(-) delete mode 100644 src/app/tests/suites/certification/Test_TC_SU_2_8.yaml create mode 100644 src/python_testing/TC_SUTestBase.py create mode 100644 src/python_testing/TC_SU_2_8.py diff --git a/examples/ota-provider-app/linux/main.cpp b/examples/ota-provider-app/linux/main.cpp index 2b0743a421c137..58c7181bc4e728 100644 --- a/examples/ota-provider-app/linux/main.cpp +++ b/examples/ota-provider-app/linux/main.cpp @@ -16,400 +16,422 @@ * limitations under the License. */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "AppMain.h" - -#include -#include -#include -#include - -using chip::BitFlags; -using chip::app::Clusters::OTAProviderDelegate; -using chip::ArgParser::OptionDef; -using chip::ArgParser::OptionSet; -using chip::ArgParser::PrintArgError; -using chip::bdx::TransferControlFlags; -using chip::Messaging::ExchangeManager; -using namespace chip::app::Clusters::OtaSoftwareUpdateProvider; - -// TODO: this should probably be done dynamically -constexpr chip::EndpointId kOtaProviderEndpoint = 0; - -constexpr uint16_t kOptionUpdateAction = 'a'; -constexpr uint16_t kOptionUserConsentNeeded = 'c'; -constexpr uint16_t kOptionFilepath = 'f'; -constexpr uint16_t kOptionImageUri = 'i'; -constexpr uint16_t kOptionMaxBDXBlockSize = 'm'; -constexpr uint16_t kOptionOtaImageList = 'o'; -constexpr uint16_t kOptionDelayedApplyActionTimeSec = 'p'; -constexpr uint16_t kOptionQueryImageStatus = 'q'; -constexpr uint16_t kOptionDelayedQueryActionTimeSec = 't'; -constexpr uint16_t kOptionUserConsentState = 'u'; -constexpr uint16_t kOptionIgnoreQueryImage = 'x'; -constexpr uint16_t kOptionIgnoreApplyUpdate = 'y'; -constexpr uint16_t kOptionPollInterval = 'P'; - -OTAProviderExample gOtaProvider; -chip::ota::DefaultOTAProviderUserConsent gUserConsentProvider; - -// Global variables used for passing the CLI arguments to the OTAProviderExample object -static OTAQueryStatus gQueryImageStatus = OTAQueryStatus::kUpdateAvailable; -static OTAApplyUpdateAction gOptionUpdateAction = OTAApplyUpdateAction::kProceed; -static uint32_t gDelayedQueryActionTimeSec = 0; -static uint32_t gDelayedApplyActionTimeSec = 0; -static const char * gOtaFilepath = nullptr; -static const char * gOtaImageListFilepath = nullptr; -static const char * gImageUri = nullptr; -static chip::ota::UserConsentState gUserConsentState = chip::ota::UserConsentState::kUnknown; -static bool gUserConsentNeeded = false; -static uint32_t gIgnoreQueryImageCount = 0; -static uint32_t gIgnoreApplyUpdateCount = 0; -static uint32_t gPollInterval = 0; -static std::optional gMaxBDXBlockSize = std::nullopt; - -// Parses the JSON filepath and extracts DeviceSoftwareVersionModel parameters -static bool ParseJsonFileAndPopulateCandidates(const char * filepath, - std::vector & candidates) -{ - bool ret = false; - Json::Value root; - Json::CharReaderBuilder builder; - JSONCPP_STRING errs; - std::ifstream ifs; - - builder["collectComments"] = true; // allow C/C++ type comments in JSON file - ifs.open(filepath); - - if (!ifs.good()) - { - ChipLogError(SoftwareUpdate, "Error opening ifstream with file: \"%s\"", filepath); - return ret; - } - - if (!parseFromStream(builder, ifs, &root, &errs)) - { - ChipLogError(SoftwareUpdate, "Error parsing JSON from file: \"%s\"", filepath); - return ret; - } - - const Json::Value devSofVerModValue = root["deviceSoftwareVersionModel"]; - if (!devSofVerModValue || !devSofVerModValue.isArray()) - { - ChipLogError(SoftwareUpdate, "Error: Key deviceSoftwareVersionModel not found or its value is not of type Array"); - } - else - { - for (auto iter : devSofVerModValue) - { - OTAProviderExample::DeviceSoftwareVersionModel candidate; - candidate.vendorId = static_cast(iter.get("vendorId", 1).asUInt()); - candidate.productId = static_cast(iter.get("productId", 1).asUInt()); - candidate.softwareVersion = static_cast(iter.get("softwareVersion", 10).asUInt64()); - chip::Platform::CopyString(candidate.softwareVersionString, iter.get("softwareVersionString", "1.0.0").asCString()); - candidate.cDVersionNumber = static_cast(iter.get("cDVersionNumber", 0).asUInt()); - candidate.softwareVersionValid = iter.get("softwareVersionValid", true).asBool() ? true : false; - candidate.minApplicableSoftwareVersion = static_cast(iter.get("minApplicableSoftwareVersion", 0).asUInt64()); - candidate.maxApplicableSoftwareVersion = - static_cast(iter.get("maxApplicableSoftwareVersion", 1000).asUInt64()); - chip::Platform::CopyString(candidate.otaURL, iter.get("otaURL", "https://test.com").asCString()); - candidates.push_back(candidate); - ret = true; - } - } - return ret; -} - -bool HandleOptions(const char * aProgram, OptionSet * aOptions, int aIdentifier, const char * aName, const char * aValue) -{ - bool retval = true; - static bool kOptionFilepathSelected; - static bool kOptionOtaImageListSelected; - - switch (aIdentifier) - { - case kOptionFilepath: - kOptionFilepathSelected = true; - if (0 != access(aValue, R_OK)) - { - PrintArgError("%s: not permitted to read %s\n", aProgram, aValue); - retval = false; - } - else if (kOptionOtaImageListSelected) - { - PrintArgError("%s: Cannot have both OptionOtaImageList and kOptionOtaFilepath \n", aProgram); - retval = false; - } - else - { - gOtaFilepath = aValue; - } - break; - case kOptionImageUri: - gImageUri = aValue; - break; - case kOptionOtaImageList: - kOptionOtaImageListSelected = true; - if (0 != access(aValue, R_OK)) - { - PrintArgError("%s: not permitted to read %s\n", aProgram, aValue); - retval = false; - } - else if (kOptionFilepathSelected) - { - PrintArgError("%s: Cannot have both OptionOtaImageList and kOptionOtaFilepath \n", aProgram); - retval = false; - } - else - { - gOtaImageListFilepath = aValue; - } - break; - case kOptionQueryImageStatus: - if (strcmp(aValue, "updateAvailable") == 0) - { - gQueryImageStatus = OTAQueryStatus::kUpdateAvailable; - } - else if (strcmp(aValue, "busy") == 0) - { - gQueryImageStatus = OTAQueryStatus::kBusy; - } - else if (strcmp(aValue, "updateNotAvailable") == 0) - { - gQueryImageStatus = OTAQueryStatus::kNotAvailable; - } - else - { - PrintArgError("%s: ERROR: Invalid queryImageStatus parameter: %s\n", aProgram, aValue); - retval = false; - } - break; - case kOptionIgnoreQueryImage: - gIgnoreQueryImageCount = static_cast(strtoul(aValue, NULL, 0)); - break; - case kOptionIgnoreApplyUpdate: - gIgnoreApplyUpdateCount = static_cast(strtoul(aValue, NULL, 0)); - break; - case kOptionUpdateAction: - if (strcmp(aValue, "proceed") == 0) - { - gOptionUpdateAction = OTAApplyUpdateAction::kProceed; - } - else if (strcmp(aValue, "awaitNextAction") == 0) - { - gOptionUpdateAction = OTAApplyUpdateAction::kAwaitNextAction; - } - else if (strcmp(aValue, "discontinue") == 0) - { - gOptionUpdateAction = OTAApplyUpdateAction::kDiscontinue; - } - else - { - PrintArgError("%s: ERROR: Invalid applyUpdateAction parameter: %s\n", aProgram, aValue); - retval = false; - } - break; - case kOptionDelayedQueryActionTimeSec: - gDelayedQueryActionTimeSec = static_cast(strtoul(aValue, NULL, 0)); - break; - case kOptionDelayedApplyActionTimeSec: - gDelayedApplyActionTimeSec = static_cast(strtoul(aValue, NULL, 0)); - break; - case kOptionUserConsentState: - if (strcmp(aValue, "granted") == 0) - { - gUserConsentState = chip::ota::UserConsentState::kGranted; - } - else if (strcmp(aValue, "denied") == 0) - { - gUserConsentState = chip::ota::UserConsentState::kDenied; - } - else if (strcmp(aValue, "deferred") == 0) - { - gUserConsentState = chip::ota::UserConsentState::kObtaining; - } - else - { - PrintArgError("%s: ERROR: Invalid UserConsent parameter: %s\n", aProgram, aValue); - retval = false; - } - break; - case kOptionUserConsentNeeded: - gUserConsentNeeded = true; - break; - case kOptionPollInterval: - gPollInterval = static_cast(strtoul(aValue, NULL, 0)); - break; - case kOptionMaxBDXBlockSize: { - auto blockSize = static_cast(strtoul(aValue, NULL, 0)); - if (blockSize == 0) - { - PrintArgError("%s: ERROR: Invalid maxBDXBlockSize parameter: %s\n", aProgram, aValue); - retval = false; - } - else - { - gMaxBDXBlockSize = blockSize; - } - break; - } - - default: - PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", aProgram, aName); - retval = false; - break; - } - - return (retval); -} - -OptionDef cmdLineOptionsDef[] = { - { "applyUpdateAction", chip::ArgParser::kArgumentRequired, kOptionUpdateAction }, - { "userConsentNeeded", chip::ArgParser::kNoArgument, kOptionUserConsentNeeded }, - { "filepath", chip::ArgParser::kArgumentRequired, kOptionFilepath }, - { "imageUri", chip::ArgParser::kArgumentRequired, kOptionImageUri }, - { "otaImageList", chip::ArgParser::kArgumentRequired, kOptionOtaImageList }, - { "delayedApplyActionTimeSec", chip::ArgParser::kArgumentRequired, kOptionDelayedApplyActionTimeSec }, - { "queryImageStatus", chip::ArgParser::kArgumentRequired, kOptionQueryImageStatus }, - { "delayedQueryActionTimeSec", chip::ArgParser::kArgumentRequired, kOptionDelayedQueryActionTimeSec }, - { "userConsentState", chip::ArgParser::kArgumentRequired, kOptionUserConsentState }, - { "ignoreQueryImage", chip::ArgParser::kArgumentRequired, kOptionIgnoreQueryImage }, - { "ignoreApplyUpdate", chip::ArgParser::kArgumentRequired, kOptionIgnoreApplyUpdate }, - { "pollInterval", chip::ArgParser::kArgumentRequired, kOptionPollInterval }, - { "maxBDXBlockSize", chip::ArgParser::kArgumentRequired, kOptionMaxBDXBlockSize }, - {}, -}; - -OptionSet cmdLineOptions = { HandleOptions, cmdLineOptionsDef, "PROGRAM OPTIONS", - " -a, --applyUpdateAction \n" - " Value for the Action field in the first ApplyUpdateResponse.\n" - " For all subsequent responses, the value of proceed will be used.\n" - " -c, --userConsentNeeded\n" - " If supplied, value of the UserConsentNeeded field in the QueryImageResponse\n" - " is set to true. This is only applicable if value of the RequestorCanConsent\n" - " field in QueryImage Command is true.\n" - " Otherwise, value of the UserConsentNeeded field is false.\n" - " -f, --filepath \n" - " Path to a file containing an OTA image\n" - " -i, --imageUri \n" - " Value for the ImageURI field in the QueryImageResponse.\n" - " If none is supplied, a valid URI is generated.\n" - " -m, --maxBDXBlockSize \n" - " Value for the maximum BDX block size to use for the transfer.\n" - " If none is supplied, a default value will be used.\n" - " -o, --otaImageList \n" - " Path to a file containing a list of OTA images\n" - " -p, --delayedApplyActionTimeSec