diff --git a/src/common/data_provider/CMakeLists.txt b/src/common/data_provider/CMakeLists.txt index e685481eea..a8361e503e 100644 --- a/src/common/data_provider/CMakeLists.txt +++ b/src/common/data_provider/CMakeLists.txt @@ -65,6 +65,7 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) if(CMAKE_SYSTEM_NAME STREQUAL "Windows") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) + add_definitions(-DWIN32=1 -DWIN_EXPORT) else() set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) endif() @@ -168,7 +169,7 @@ add_library(sysinfo STATIC target_include_directories(sysinfo PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include/) if(CMAKE_SYSTEM_NAME STREQUAL "Windows") - target_link_libraries(sysinfo PUBLIC psapi iphlpapi ws2_32) + target_link_libraries(sysinfo PUBLIC psapi iphlpapi ws2_32 wbemuuid uuid wuguid ole32 oleaut32) elseif(APPLE) find_library(iokit_lib IOKit) if(NOT iokit_lib) diff --git a/src/common/data_provider/src/sysInfoWin.cpp b/src/common/data_provider/src/sysInfoWin.cpp index cda3e8a9cb..1ed90b90b5 100644 --- a/src/common/data_provider/src/sysInfoWin.cpp +++ b/src/common/data_provider/src/sysInfoWin.cpp @@ -41,12 +41,15 @@ #include "packages/packagesPYPI.hpp" #include "packages/packagesNPM.hpp" #include "packages/modernPackageDataRetriever.hpp" +#include "utilsWrapperWin.hpp" + constexpr auto CENTRAL_PROCESSOR_REGISTRY {"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"}; const std::string UNINSTALL_REGISTRY{"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"}; constexpr auto SYSTEM_IDLE_PROCESS_NAME {"System Idle Process"}; constexpr auto SYSTEM_PROCESS_NAME {"System"}; + static const std::map gs_firmwareTableProviderSignature { {"ACPI", 0x41435049}, @@ -912,9 +915,43 @@ void SysInfo::getPackages(std::function callback) const ModernFactoryPackagesCreator::getPackages(searchPaths, callback); } + nlohmann::json SysInfo::getHotfixes() const { std::set hotfixes; + std::ostringstream oss; + ComHelper comHelper; + + // Initialize COM + HRESULT hres = CoInitializeEx(0, COINIT_MULTITHREADED); + + if (SUCCEEDED(hres)) + { + try + { + // Query hotfixes using WMI + QueryWMIHotFixes(hotfixes, comHelper); + } + catch (...) + { + // Ignore the error. The OS does not support WMI API. + } + + + try + { + // Query hotfixes using Windows Update API + QueryWUHotFixes(hotfixes, comHelper); + } + catch (...) + { + // Ignore the error. The OS does not support WUA API. + } + + // Uninitialize COM + CoUninitialize(); + } + PackageWindowsHelper::getHotFixFromReg(HKEY_LOCAL_MACHINE, PackageWindowsHelper::WIN_REG_HOTFIX, hotfixes); PackageWindowsHelper::getHotFixFromRegNT(HKEY_LOCAL_MACHINE, PackageWindowsHelper::VISTA_REG_HOTFIX, hotfixes); PackageWindowsHelper::getHotFixFromRegWOW(HKEY_LOCAL_MACHINE, PackageWindowsHelper::WIN_REG_WOW_HOTFIX, hotfixes); diff --git a/src/common/data_provider/src/utilsWrapperWin.cpp b/src/common/data_provider/src/utilsWrapperWin.cpp new file mode 100644 index 0000000000..738f6c4ad9 --- /dev/null +++ b/src/common/data_provider/src/utilsWrapperWin.cpp @@ -0,0 +1,254 @@ +/* + * Wazuh SysInfo + * Copyright (C) 2015, Wazuh Inc. + * December 22, 2021. + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General Public + * License (version 2) as published by the FSF - Free Software + * Foundation + */ + +#include +#include // For std::ostringstream +#include // For std::hex +#include // For std::runtime_error +#include // For std::string and std::wstring +#include // For localization utilities (if needed for string conversion) + +#include "utilsWrapperWin.hpp" + + +// Implement WMI functions +HRESULT ComHelper::CreateWmiLocator(IWbemLocator*& pLoc) +{ + return CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&pLoc); +} + +HRESULT ComHelper::ConnectToWmiServer(IWbemLocator* pLoc, IWbemServices*& pSvc) +{ + return pLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), NULL, NULL, 0, 0, 0, 0, &pSvc); +} + +HRESULT ComHelper::SetProxyBlanket(IWbemServices* pSvc) +{ + return CoSetProxyBlanket(pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, + RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE); +} + +HRESULT ComHelper::ExecuteWmiQuery(IWbemServices* pSvc, IEnumWbemClassObject*& pEnumerator) +{ + return pSvc->ExecQuery(bstr_t("WQL"), bstr_t("SELECT * FROM Win32_QuickFixEngineering"), + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator); +} + +// Implement Windows Update API functions +HRESULT ComHelper::CreateUpdateSearcher(IUpdateSearcher*& pUpdateSearcher) +{ + return CoCreateInstance(CLSID_UpdateSearcher, NULL, CLSCTX_INPROC_SERVER, IID_IUpdateSearcher, (LPVOID*)&pUpdateSearcher); +} + +HRESULT ComHelper::GetTotalHistoryCount(IUpdateSearcher* pUpdateSearcher, LONG& count) +{ + return pUpdateSearcher->GetTotalHistoryCount(&count); +} + +HRESULT ComHelper::QueryHistory(IUpdateSearcher* pUpdateSearcher, IUpdateHistoryEntryCollection*& pHistory, LONG& count) +{ + return pUpdateSearcher->QueryHistory(0, count, &pHistory); +} + +HRESULT ComHelper::GetCount(IUpdateHistoryEntryCollection* pHistory, LONG& count) +{ + return pHistory->get_Count(&count); +} + +HRESULT ComHelper::GetItem(IUpdateHistoryEntryCollection* pHistory, LONG index, IUpdateHistoryEntry** pEntry) +{ + return pHistory->get_Item(index, pEntry); +} + +HRESULT ComHelper::GetTitle(IUpdateHistoryEntry* pEntry, BSTR& title) +{ + return pEntry->get_Title(&title); +} + +// This function provides a minimal implementation for converting C strings to BSTRs, +// avoiding the need to include a full COM library. This can be useful when you only need this specific functionality +// and want to minimize dependencies. +namespace _com_util +{ + BSTR ConvertStringToBSTR(const char* str) + { + int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); + BSTR bstr = SysAllocStringLen(0, len); + MultiByteToWideChar(CP_ACP, 0, str, -1, bstr, len); + return bstr; + } +} + +// The BstrToString function takes a Windows-specific string (BSTR) and converts it into +// a standard C++ string (std::string) that can be more easily used in the application. +std::string BstrToString(BSTR bstr) +{ + std::wstring_convert> converter; + std::wstring wstr(bstr, SysStringLen(bstr)); + return converter.to_bytes(wstr); +} + +void QueryWMIHotFixes(std::set& hotfixSet, IComHelper& comHelper) +{ + HRESULT hres; + IWbemLocator* pLoc = NULL; + IWbemServices* pSvc = NULL; + std::ostringstream oss; + + hres = comHelper.CreateWmiLocator(pLoc); + + if (FAILED(hres)) + { + oss << "WMI: Error creating IWbemLocator. Code: " << std::hex << hres; + throw std::runtime_error(oss.str()); + } + + hres = comHelper.ConnectToWmiServer(pLoc, pSvc); + + if (FAILED(hres)) + { + if (pLoc) pLoc->Release(); + + oss << "WMI: connection failed. Code: " << std::hex << hres; + throw std::runtime_error(oss.str()); + } + + hres = comHelper.SetProxyBlanket(pSvc); + + if (FAILED(hres)) + { + if (pSvc) pSvc->Release(); + + if (pLoc) pLoc->Release(); + + oss << "WMI: security error. Code: " << std::hex << hres; + throw std::runtime_error(oss.str()); + } + + IEnumWbemClassObject* pEnumerator = NULL; + hres = comHelper.ExecuteWmiQuery(pSvc, pEnumerator); + + if (FAILED(hres)) + { + if (pLoc) pLoc->Release(); + + if (pLoc) pSvc->Release(); + + oss << "WMI: query error. Code: " << std::hex << hres; + throw std::runtime_error(oss.str()); + } + + IWbemClassObject* pclsObj = NULL; + ULONG uReturn = 0; + + while (pEnumerator) + { + HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); + + if (0 == uReturn) + { + break; + } + + VARIANT vtProp; + hr = pclsObj->Get(L"HotFixID", 0, &vtProp, 0, 0); + + if (SUCCEEDED(hr) && vtProp.vt == VT_BSTR) + { + std::string hotfix = BstrToString(vtProp.bstrVal); + + if (hotfixSet.find(hotfix) == hotfixSet.end()) + { + // New HotFix found + hotfixSet.insert(hotfix); + } + } + + VariantClear(&vtProp); + pclsObj->Release(); + } + + pSvc->Release(); + pLoc->Release(); + pEnumerator->Release(); +} + +void QueryWUHotFixes(std::set& hotfixSet, IComHelper& comHelper) +{ + HRESULT hres; + IUpdateSearcher* pUpdateSearcher = NULL; + IUpdateHistoryEntryCollection* pHistory = NULL; + std::regex hotfixRegex("KB[0-9]+"); + std::ostringstream oss; + + hres = comHelper.CreateUpdateSearcher(pUpdateSearcher); + + if (FAILED(hres)) + { + oss << "WUA: UpdateSearcher error. Code: " << std::hex << hres; + throw std::runtime_error(oss.str()); + } + + LONG count; + hres = comHelper.GetTotalHistoryCount(pUpdateSearcher, count); + + if (FAILED(hres)) + { + if (pUpdateSearcher) pUpdateSearcher->Release(); + + oss << "WUA: Error getting total update history count. Code: 0x" << std::hex << hres; + throw std::runtime_error(oss.str()); + } + + hres = comHelper.QueryHistory(pUpdateSearcher, pHistory, count); + + if (FAILED(hres)) + { + if (pUpdateSearcher) pUpdateSearcher->Release(); + + oss << "WUA: Error querying update history. Code: 0x" << std::hex << hres; + throw std::runtime_error(oss.str()); + } + + LONG historyCount; + hres = comHelper.GetCount(pHistory, historyCount); + + for (LONG i = 0; i < historyCount; ++i) + { + IUpdateHistoryEntry* pEntry = NULL; + comHelper.GetItem(pHistory, i, &pEntry); + BSTR title; + comHelper.GetTitle(pEntry, title); + std::string titleStr = BstrToString(title); + + std::smatch match; + + if (std::regex_search(titleStr, match, hotfixRegex)) + { + std::string hotfix = match[0]; + + if (hotfixSet.find(hotfix) == hotfixSet.end()) + { + // New HotFix found + hotfixSet.insert(hotfix); + } + } + + if (pEntry) pEntry->Release(); + + SysFreeString(title); + } + + if (pHistory) pHistory->Release(); + + if (pUpdateSearcher) pUpdateSearcher->Release(); +} + diff --git a/src/common/data_provider/src/utilsWrapperWin.hpp b/src/common/data_provider/src/utilsWrapperWin.hpp new file mode 100644 index 0000000000..4107fb7d68 --- /dev/null +++ b/src/common/data_provider/src/utilsWrapperWin.hpp @@ -0,0 +1,79 @@ +/* + * Wazuh SysInfo + * Copyright (C) 2015, Wazuh Inc. + * December 22, 2021. + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General Public + * License (version 2) as published by the FSF - Free Software + * Foundation + */ +#pragma once + +#ifdef _WIN32 +#ifdef WIN_EXPORT +#define EXPORTED __declspec(dllexport) +#else +#define EXPORTED __declspec(dllimport) +#endif +#endif + +/* Hotfixes APIs */ +#include +#include +#include +#include +#include +#include +#include "wuapi.h" + + +// Define GUID manually for CLSID_UpdateSearcher +DEFINE_GUID(CLSID_UpdateSearcher, 0x5A2A5E6E, 0xD633, 0x4C3A, 0x8A, 0x7E, 0x69, 0x4D, 0xBF, 0x9E, 0xCE, 0xD4); + +class EXPORTED IComHelper +{ + public: + virtual ~IComHelper() = default; + + // Abstracted methods for WMI functions + virtual HRESULT CreateWmiLocator(IWbemLocator*& pLoc) = 0; + virtual HRESULT ConnectToWmiServer(IWbemLocator* pLoc, IWbemServices*& pSvc) = 0; + virtual HRESULT SetProxyBlanket(IWbemServices* pSvc) = 0; + virtual HRESULT ExecuteWmiQuery(IWbemServices* pSvc, IEnumWbemClassObject*& pEnumerator) = 0; + + // Abstracted methods for Windows Update API functions + virtual HRESULT CreateUpdateSearcher(IUpdateSearcher*& pUpdateSearcher) = 0; + virtual HRESULT GetTotalHistoryCount(IUpdateSearcher* pUpdateSearcher, LONG& count) = 0; + virtual HRESULT QueryHistory(IUpdateSearcher* pUpdateSearcher, IUpdateHistoryEntryCollection*& pHistory, LONG& count) = 0; + virtual HRESULT GetCount(IUpdateHistoryEntryCollection* pHistory, LONG& count) = 0; + virtual HRESULT GetItem(IUpdateHistoryEntryCollection* pHistory, LONG index, IUpdateHistoryEntry** pEntry) = 0; + virtual HRESULT GetTitle(IUpdateHistoryEntry* pEntry, BSTR& title) = 0; +}; + +class EXPORTED ComHelper : public IComHelper +{ + public: + // Implement WMI functions + HRESULT CreateWmiLocator(IWbemLocator*& pLoc) override; + HRESULT ConnectToWmiServer(IWbemLocator* pLoc, IWbemServices*& pSvc) override; + HRESULT SetProxyBlanket(IWbemServices* pSvc) override; + HRESULT ExecuteWmiQuery(IWbemServices* pSvc, IEnumWbemClassObject*& pEnumerator) override; + + // Implement Windows Update API functions + HRESULT CreateUpdateSearcher(IUpdateSearcher*& pUpdateSearcher) override; + HRESULT GetTotalHistoryCount(IUpdateSearcher* pUpdateSearcher, LONG& count) override; + HRESULT QueryHistory(IUpdateSearcher* pUpdateSearcher, IUpdateHistoryEntryCollection*& pHistory, LONG& count) override; + HRESULT GetCount(IUpdateHistoryEntryCollection* pHistory, LONG& count) override; + HRESULT GetItem(IUpdateHistoryEntryCollection* pHistory, LONG index, IUpdateHistoryEntry** pEntry) override; + HRESULT GetTitle(IUpdateHistoryEntry* pEntry, BSTR& title) override; +}; + +// Queries Windows Management Instrumentation (WMI) to retrieve installed hotfixes +// and stores them in the provided set. +EXPORTED void QueryWMIHotFixes(std::set& hotfixSet, IComHelper& comHelper); + + +// Queries Windows Update Agent (WUA) for installed update history, +// extracts hotfixes, and adds them to the provided set. +EXPORTED void QueryWUHotFixes(std::set& hotfixSet, IComHelper& comHelper); diff --git a/src/common/data_provider/tests/sysInfoWin/CMakeLists.txt b/src/common/data_provider/tests/sysInfoWin/CMakeLists.txt index ba331b2a47..7f96227b52 100644 --- a/src/common/data_provider/tests/sysInfoWin/CMakeLists.txt +++ b/src/common/data_provider/tests/sysInfoWin/CMakeLists.txt @@ -7,10 +7,18 @@ set(CMAKE_CXX_FLAGS_DEBUG "-g --coverage") file(GLOB sysinfo_UNIT_TEST_SRC "*.cpp") - add_executable(sysInfoWindows_unit_test - ${sysinfo_UNIT_TEST_SRC}) +file(GLOB SYSINFO_SRC + "${CMAKE_SOURCE_DIR}/src/utilsWrapperWin.cpp") + +add_executable(sysInfoWindows_unit_test + ${sysinfo_UNIT_TEST_SRC} + ${SYSINFO_SRC}) + +link_directories("${CMAKE_SOURCE_DIR}/lib/") target_link_libraries(sysInfoWindows_unit_test + wbemuuid + wuguid debug gtestd debug gmockd debug gtest_maind diff --git a/src/common/data_provider/tests/sysInfoWin/sysInfoWin_test.cpp b/src/common/data_provider/tests/sysInfoWin/sysInfoWin_test.cpp index 8cf5d58dc2..e7e59a9991 100644 --- a/src/common/data_provider/tests/sysInfoWin/sysInfoWin_test.cpp +++ b/src/common/data_provider/tests/sysInfoWin/sysInfoWin_test.cpp @@ -9,13 +9,16 @@ * Foundation. */ -#include "sysInfoWin_test.h" + +#include +#include #include "packages/packagesWindowsParserHelper.h" +#include "sysInfoWin_test.h" +#include -void SysInfoWinTest::SetUp() {}; -void SysInfoWinTest::TearDown() -{}; +void SysInfoWinTest::SetUp() {}; +void SysInfoWinTest::TearDown() {}; TEST_F(SysInfoWinTest, test_extract_HFValue_7618) { @@ -102,3 +105,170 @@ TEST_F(SysInfoWinTest, testHF_PRODUCT_Valids_Format) EXPECT_FALSE(std::regex_match(hf, std::regex(KB_WITH_NUMBERS_AND_LETTERS_FORMAT_REGEX))); } } + +// Test: Windows Management Instrumentation (WMI) to retrieve installed hotfixes +TEST_F(SysInfoWinTest, WmiLocatorCreationFailure) +{ + MockComHelper mockHelper; + std::set hotfixSet; + + EXPECT_CALL(mockHelper, CreateWmiLocator(::testing::_)) + .WillOnce(testing::Return(E_FAIL)); + + EXPECT_THROW(QueryWMIHotFixes(hotfixSet, mockHelper), std::runtime_error); +} + +TEST_F(SysInfoWinTest, WmiConnectToWmiServerFailure) +{ + MockComHelper mockComHelper; + std::set hotfixSet; + + EXPECT_CALL(mockComHelper, CreateWmiLocator(testing::_)) + .WillOnce(testing::Return(S_OK)); + + EXPECT_CALL(mockComHelper, ConnectToWmiServer(testing::_, testing::_)) + .WillOnce(testing::Return(E_FAIL)); + + EXPECT_THROW(QueryWMIHotFixes(hotfixSet, mockComHelper), std::runtime_error); +} + +TEST_F(SysInfoWinTest, WmiSetProxyBlanket) +{ + MockComHelper mockComHelper; + std::set hotfixSet; + + EXPECT_CALL(mockComHelper, CreateWmiLocator(testing::_)) + .WillOnce(testing::Return(S_OK)); + + EXPECT_CALL(mockComHelper, ConnectToWmiServer(testing::_, testing::_)) + .WillOnce(testing::Return(S_OK)); + + EXPECT_CALL(mockComHelper, SetProxyBlanket(testing::_)) + .WillOnce(testing::Return(E_FAIL)); + + EXPECT_THROW(QueryWMIHotFixes(hotfixSet, mockComHelper), std::runtime_error); +} + +TEST_F(SysInfoWinTest, WmiExecuteQuery) +{ + MockComHelper mockComHelper; + std::set hotfixSet; + + EXPECT_CALL(mockComHelper, CreateWmiLocator(testing::_)) + .WillOnce(testing::Return(S_OK)); + + EXPECT_CALL(mockComHelper, ConnectToWmiServer(testing::_, testing::_)) + .WillOnce(testing::Return(S_OK)); + + EXPECT_CALL(mockComHelper, SetProxyBlanket(testing::_)) + .WillOnce(testing::Return(S_OK)); + + EXPECT_CALL(mockComHelper, ExecuteWmiQuery(testing::_, testing::_)) + .WillOnce(testing::Return(E_FAIL)); + + EXPECT_THROW(QueryWMIHotFixes(hotfixSet, mockComHelper), std::runtime_error); +} + +TEST_F(SysInfoWinTest, WmiPopulatesWMIHotfixSetCorrectly) +{ + std::set hotfixSet; + ComHelper comHelper; + + HRESULT hres = CoInitializeEx(0, COINIT_MULTITHREADED); + EXPECT_TRUE(SUCCEEDED(hres)) << "COM Initialization failed with HRESULT: " << std::hex << hres; + + QueryWMIHotFixes(hotfixSet, comHelper); + + constexpr auto KB_NO_NUMBERS_FORMAT_REGEX { "(KB+[a-z])"}; + constexpr auto KB_WITH_NUMBERS_AND_LETTERS_FORMAT_REGEX { "(KB+[0-9]{6,}+[aA-zZ])"}; + + for (const auto& hf : hotfixSet) + { + EXPECT_FALSE(std::regex_match(hf, std::regex(KB_NO_NUMBERS_FORMAT_REGEX))); + EXPECT_FALSE(std::regex_match(hf, std::regex(KB_WITH_NUMBERS_AND_LETTERS_FORMAT_REGEX))); + } + + CoUninitialize(); +} + +// Test: Windows Update Agent (WUA) for installed update history, +TEST_F(SysInfoWinTest, WuaLocatorCreationFailure) +{ + MockComHelper mockHelper; + std::set hotfixSet; + + EXPECT_CALL(mockHelper, CreateUpdateSearcher(::testing::_)) + .WillOnce(testing::Return(E_FAIL)); + + EXPECT_THROW(QueryWUHotFixes(hotfixSet, mockHelper), std::runtime_error); +} + +TEST_F(SysInfoWinTest, WuaGetTotalHistoryCount) +{ + MockComHelper mockHelper; + std::set hotfixSet; + + EXPECT_CALL(mockHelper, CreateUpdateSearcher(::testing::_)) + .WillOnce(testing::Return(S_OK)); + + EXPECT_CALL(mockHelper, GetTotalHistoryCount(::testing::_, ::testing::_)) + .WillOnce(testing::Return(E_FAIL)); + + EXPECT_THROW(QueryWUHotFixes(hotfixSet, mockHelper), std::runtime_error); +} + +TEST_F(SysInfoWinTest, WuaQueryHistory) +{ + MockComHelper mockHelper; + std::set hotfixSet; + + EXPECT_CALL(mockHelper, CreateUpdateSearcher(::testing::_)) + .WillOnce(testing::Return(S_OK)); + + EXPECT_CALL(mockHelper, GetTotalHistoryCount(::testing::_, ::testing::_)) + .WillOnce(testing::Return(S_OK)); + + EXPECT_CALL(mockHelper, QueryHistory(::testing::_, ::testing::_, ::testing::_)) + .WillOnce(testing::Return(E_FAIL)); + + EXPECT_THROW(QueryWUHotFixes(hotfixSet, mockHelper), std::runtime_error); +} + +TEST_F(SysInfoWinTest, GetHistoryTest) +{ + MockComHelper mockHelper; + std::set hotfixSet; + + EXPECT_CALL(mockHelper, CreateUpdateSearcher(::testing::_)) + .WillOnce(testing::Return(S_OK)); + + EXPECT_CALL(mockHelper, GetTotalHistoryCount(::testing::_, ::testing::_)) + .WillOnce(testing::Return(S_OK)); + + EXPECT_CALL(mockHelper, QueryHistory(::testing::_, ::testing::_, ::testing::_)) + .WillOnce(testing::Return(S_OK)); + + long count = 4; + EXPECT_CALL(mockHelper, GetCount(testing::_, testing::_)) + .WillOnce(testing::DoAll(testing::SetArgReferee<1>(count), testing::Return(S_OK))); + + for (int i = 0 ; i < count; i++) + { + + EXPECT_CALL(mockHelper, GetItem(testing::_, i, testing::_)) + .WillOnce(testing::Return(S_OK)); + + // Simulate getting the title + EXPECT_CALL(mockHelper, GetTitle(testing::_, testing::_)) + .WillRepeatedly(testing::Invoke([](IUpdateHistoryEntry*, BSTR & title) -> HRESULT + { + title = SysAllocString(L"Security Update KB123456"); + return S_OK; + })); + } + + QueryWUHotFixes(hotfixSet, mockHelper); + + EXPECT_EQ(hotfixSet.size(), static_cast(1)); + EXPECT_EQ(*hotfixSet.begin(), "KB123456"); +} diff --git a/src/common/data_provider/tests/sysInfoWin/sysInfoWin_test.h b/src/common/data_provider/tests/sysInfoWin/sysInfoWin_test.h index dfdfefa8fd..9069410b81 100644 --- a/src/common/data_provider/tests/sysInfoWin/sysInfoWin_test.h +++ b/src/common/data_provider/tests/sysInfoWin/sysInfoWin_test.h @@ -9,12 +9,13 @@ * Foundation. */ -#ifndef _SYSINFO_WIN_TEST_H -#define _SYSINFO_WIN_TEST_H +#pragma once #include "gtest/gtest.h" #include "gmock/gmock.h" +#include "utilsWrapperWin.hpp" + class SysInfoWinTest : public ::testing::Test { protected: @@ -26,4 +27,18 @@ class SysInfoWinTest : public ::testing::Test void TearDown() override; }; -#endif //_SYSINFO_WIN_TEST_H + +class MockComHelper : public IComHelper +{ + public: + MOCK_METHOD(HRESULT, CreateWmiLocator, (IWbemLocator*& pLoc), (override)); + MOCK_METHOD(HRESULT, ConnectToWmiServer, (IWbemLocator* pLoc, IWbemServices*& pSvc), (override)); + MOCK_METHOD(HRESULT, SetProxyBlanket, (IWbemServices* pSvc), (override)); + MOCK_METHOD(HRESULT, ExecuteWmiQuery, (IWbemServices* pSvc, IEnumWbemClassObject*& pEnumerator), (override)); + MOCK_METHOD(HRESULT, CreateUpdateSearcher, (IUpdateSearcher*& pUpdateSearcher), (override)); + MOCK_METHOD(HRESULT, GetTotalHistoryCount, (IUpdateSearcher* pUpdateSearcher, LONG& count), (override)); + MOCK_METHOD(HRESULT, QueryHistory, (IUpdateSearcher* pUpdateSearcher, IUpdateHistoryEntryCollection*& pHistory, LONG& count), (override)); + MOCK_METHOD(HRESULT, GetCount, (IUpdateHistoryEntryCollection* pHistory, LONG& count), (override)); + MOCK_METHOD(HRESULT, GetItem, (IUpdateHistoryEntryCollection* pHistory, LONG index, IUpdateHistoryEntry** pEntry), (override)); + MOCK_METHOD(HRESULT, GetTitle, (IUpdateHistoryEntry* pEntry, BSTR& title), (override)); +};