From 545e5b0bec08bd3a133a7c947a6b7d7e769df5e9 Mon Sep 17 00:00:00 2001 From: Ahmed Messaoud Date: Wed, 15 Jun 2022 14:33:58 -0700 Subject: [PATCH] Add modulestest logs to CI report (#259) --- .github/workflows/ci.yml | 10 ++ .../scripts/generate_moduletest_metadata.sh | 2 +- src/modules/test/CMakeLists.txt | 9 +- src/modules/test/Common.h | 27 +--- src/modules/test/ManagementModule.h | 123 ++++++++++++++++++ .../test/recipes/CommandRunnerTests.json | 4 +- 6 files changed, 139 insertions(+), 36 deletions(-) create mode 100644 src/modules/test/ManagementModule.h diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e0e5cd3b5..3a39edcdc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -69,6 +69,16 @@ jobs: working-directory: ${{ env.container-workspace }}/build cmd: ctest + - name: Run modulestest + if: success() || failure() + uses: ./.github/actions/container-exec + with: + container: ${{ steps.container.outputs.id }} + working-directory: ${{ env.container-workspace }}/build/modules/test + cmd: | + mkdir -p /etc/osconfig/ + ./modulestest --gtest_output=xml:${{ env.container-workspace }}/build/gtest-output/TestRecipes.xml testplate.json + - uses: ./.github/actions/gtest-xml if: success() || failure() with: diff --git a/devops/scripts/generate_moduletest_metadata.sh b/devops/scripts/generate_moduletest_metadata.sh index b1a004411..21744dc92 100755 --- a/devops/scripts/generate_moduletest_metadata.sh +++ b/devops/scripts/generate_moduletest_metadata.sh @@ -26,7 +26,7 @@ while IFS= read -r line ; if [ ! -z "$recipepath" ] && [ ! -z "$mimpath" ]; then # Create entry if both mim+recipe are found - echo "Found '$modulename' module adding to test metadata" + echo "Found '$modulename' module adding to recipe configuration" json="[{ \"ModulePath\": \"$line\", \"MimPath\": \"$mimpath\", \"TestRecipesPath\": \"$recipepath\" }]" testJSON=$(echo $testJSON | jq --argjson testMetadata "$json" '. |= . + $testMetadata') fi diff --git a/src/modules/test/CMakeLists.txt b/src/modules/test/CMakeLists.txt index 6bfbecfd1..f2f9db625 100644 --- a/src/modules/test/CMakeLists.txt +++ b/src/modules/test/CMakeLists.txt @@ -1,7 +1,6 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -include(GoogleTest) project(modulestest) set(CMAKE_CXX_STANDARD 17) @@ -15,8 +14,7 @@ target_link_libraries(testfactorylib parsonlib) target_include_directories(testfactorylib PUBLIC - ${MODULES_INC_DIR} - ${PLATFORM_INC_DIR}) + ${MODULES_INC_DIR}) add_executable(modulestest main.cpp) target_link_libraries(modulestest gtest gtest_main pthread testfactorylib) @@ -37,11 +35,6 @@ else() ) endif() -gtest_discover_tests(modulestest - EXTRA_ARGS ${CMAKE_CURRENT_BINARY_DIR}/testplate.json - XML_OUTPUT_DIR ${GTEST_OUTPUT_DIR} -) - if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8) target_link_libraries(modulestest stdc++fs) endif() diff --git a/src/modules/test/Common.h b/src/modules/test/Common.h index 7df4db76e..70e5c3c5d 100644 --- a/src/modules/test/Common.h +++ b/src/modules/test/Common.h @@ -45,30 +45,7 @@ #include "RecipeInvoker.h" #include "MimParser.h" -constexpr const size_t g_lineLength = 256; - -inline void TestLogInfo(const char* log) -{ - std::cout << log << std::endl; -} - -inline void TestLogInfo(const char* format, const char* args...) -{ - char buf[g_lineLength] = {0}; - std::snprintf(buf, g_lineLength, format, args); - std::cout << buf << std::endl; -} - -inline void TestLogError(const char* log) -{ - std::cerr << log << std::endl; -} - -inline void TestLogError(const char* format, const char* args...) -{ - char buf[g_lineLength] = {0}; - std::snprintf(buf, g_lineLength, format, args); - std::cerr << buf << std::endl; -} +#define TestLogInfo(format, ...) {printf(format, ##__VA_ARGS__); std::cout << std::endl;} +#define TestLogError(format, ...) {fprintf(stderr, format, ##__VA_ARGS__); std::cerr << std::endl;} #endif // MODULESTESTCOMMON_H \ No newline at end of file diff --git a/src/modules/test/ManagementModule.h b/src/modules/test/ManagementModule.h new file mode 100644 index 000000000..3e99eb6f0 --- /dev/null +++ b/src/modules/test/ManagementModule.h @@ -0,0 +1,123 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef MANAGEMENTMODULE_H +#define MANAGEMENTMODULE_H + +// MMI function definitions +using Mmi_GetInfo = int (*)(const char*, MMI_JSON_STRING*, int*); +using Mmi_Free = void (*)(MMI_JSON_STRING); +using Mmi_Open = MMI_HANDLE (*)(const char*, const unsigned int); +using Mmi_Set = int (*)(MMI_HANDLE, const char*, const char*, const MMI_JSON_STRING, const int); +using Mmi_Get = int (*)(MMI_HANDLE, const char*, const char*, MMI_JSON_STRING*, int*); +using Mmi_Close = void (*)(MMI_HANDLE); + +class ManagementModule +{ +public: + // Lifetime of the operation - see MmiGetInfo Schema for Lifetime property + enum Lifetime + { + Undefined = 0, + KeepAlive = 1, + Short = 2 + }; + + struct Version + { + unsigned int major = 0; + unsigned int minor = 0; + unsigned int patch = 0; + unsigned int tweak = 0; + + // Only defining "<" as we are only using that operator in comparisons + bool operator < (const Version &rhs) const + { + return (((major < rhs.major) || + ((major == rhs.major) && (minor < rhs.minor)) || + ((major == rhs.major) && (minor == rhs.minor) && (patch < rhs.patch)) || + ((major == rhs.major) && (minor == rhs.minor) && (patch == rhs.patch) && (tweak < rhs.tweak))) + ? true : false); + } + + std::string ToString() const + { + std::ostringstream ostream; + ostream << major << "." << minor << "." << patch << "." << tweak; + return ostream.str(); + } + }; + + // Structure maps to the MmiGetInfo JSON Schema - see src/modules/schema/mmi-get-info.schema.json for more info + struct Info + { + std::string name; + std::string description; + std::string manufacturer; + Version version; + std::string versionInfo; + std::vector components; + Lifetime lifetime; + std::string licenseUri; + std::string projectUri; + unsigned int userAccount; + + static int Deserialize(const rapidjson::Value& object, Info& info); + }; + + ManagementModule(); + ManagementModule(const std::string path); + virtual ~ManagementModule(); + + virtual int Load(); + virtual void Unload(); + + Info GetInfo() const; + +protected: + const std::string m_modulePath; + + // The handle retuned by dlopen() + void* m_handle; + + // Management Module Interface (MMI) imported functions + Mmi_GetInfo m_mmiGetInfo; + Mmi_Open m_mmiOpen; + Mmi_Close m_mmiClose; + Mmi_Set m_mmiSet; + Mmi_Get m_mmiGet; + Mmi_Free m_mmiFree; + + Info m_info; + + virtual int CallMmiGetInfo(const char* clientName, MMI_JSON_STRING* payload, int* payloadSizeBytes); + virtual MMI_HANDLE CallMmiOpen(const char* componentName, unsigned int maxPayloadSizeBytes); + virtual void CallMmiClose(MMI_HANDLE handle); + virtual int CallMmiSet(MMI_HANDLE handle, const char* componentName, const char* objectName, const MMI_JSON_STRING payload, const int payloadSizeBytes); + virtual int CallMmiGet(MMI_HANDLE handle, const char* componentName, const char* objectName, MMI_JSON_STRING *payload, int *payloadSizeBytes); + + friend class MmiSession; +}; + +class MmiSession +{ +public: + MmiSession(std::shared_ptr module, const std::string& clientName, unsigned int maxPayloadSizeBytes = 0); + ~MmiSession(); + + int Open(); + void Close(); + + int Set(const char* componentName, const char* objectName, const MMI_JSON_STRING payload, const int payloadSizeBytes); + int Get(const char* componentName, const char* objectName, MMI_JSON_STRING *payload, int *payloadSizeBytes); + + ManagementModule::Info GetInfo(); +private: + const std::string m_clientName; + const unsigned int m_maxPayloadSizeBytes; + std::shared_ptr m_module; + + MMI_HANDLE m_mmiHandle; +}; + +#endif // MANAGEMENTMODULE_H \ No newline at end of file diff --git a/src/modules/test/recipes/CommandRunnerTests.json b/src/modules/test/recipes/CommandRunnerTests.json index 20b52c7aa..5082d5391 100644 --- a/src/modules/test/recipes/CommandRunnerTests.json +++ b/src/modules/test/recipes/CommandRunnerTests.json @@ -22,13 +22,13 @@ "Payload": "{\"commandId\": \"test1\", \"arguments\": \"echo Hello World\", \"timeout\": 0, \"singleLineTextResult\": true, \"action\": 3}", "PayloadSizeBytes": 123, "ExpectedResult": 0, - "WaitSeconds": 10 + "WaitSeconds": 5 }, { "ComponentName": "CommandRunner", "ObjectName": "commandStatus", "Desired": false, - "Payload": "{\"commandId\":\"test1\",\"resultCode\":0,\"textResult\":\"Hello World\",\"currentState\":2}", + "Payload": "{\"commandId\":\"test1\",\"resultCode\":0,\"textResult\":\"\",\"currentState\":2}", "ExpectedResult": 0 } ] \ No newline at end of file