Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/extensions/extension_manager/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,12 @@ endif ()

target_link_libraries (${target_name} PRIVATE libaducpal)

target_compile_definitions (${target_name} PRIVATE ADUC_TEST_DATA_FOLDER="${ADUC_TEST_DATA_FOLDER}")
target_compile_definitions (
${target_name}
PRIVATE
ADUC_TEST_DATA_FOLDER="${ADUC_TEST_DATA_FOLDER}"
ADUC_CONTENT_DOWNLOADER_EXTENSION_PATH="${ADUC_EXTENSIONS_FOLDER}/${ADUC_EXTENSIONS_SUBDIR_CONTENT_DOWNLOADER}/${ADUC_EXTENSION_REG_FILENAME}"
ADUC_COMPONENT_ENUMERATOR_EXTENSION_PATH="${ADUC_EXTENSIONS_FOLDER}/${ADUC_EXTENSIONS_SUBDIR_COMPONENT_ENUMERATOR}/${ADUC_EXTENSION_REG_FILENAME}")

include (CTest)
include (Catch)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,67 @@
* Licensed under the MIT License.
*/

#include <aduc/config_utils.h>
#include <aduc/extension_manager_download_options.h>
#include <aduc/extension_manager_helper.hpp>
#include <aduc/result.h>
#include <aduc/types/update_content.h>

#include <catch2/catch_all.hpp>

#include <cstdlib> // setenv, getenv
#include <cstring> // memset
#include <string>

namespace
{

// RAII guard that forces ADUC_ConfigInfo_GetInstance() to return nullptr by
// temporarily pointing the config folder env var at a non-existent directory
// and draining any existing singleton refcount.
struct ScopedInvalidateConfig
{
std::string savedEnv;
bool hadEnv = false;

ScopedInvalidateConfig()
{
const char* env = getenv("ADUC_CONF_FOLDER");
if (env != nullptr)
{
hadEnv = true;
savedEnv = env;
}
// Drain any existing singleton so re-init is attempted next time
// (ReleaseInstance is a no-op once refCount reaches 0).
const ADUC_ConfigInfo* cfg = ADUC_ConfigInfo_GetInstance();
if (cfg != nullptr)
{
// Release the ref we just took
ADUC_ConfigInfo_ReleaseInstance(cfg);
// Release again to drop refcount to 0 and uninit the singleton
ADUC_ConfigInfo_ReleaseInstance(cfg);
}
setenv("ADUC_CONF_FOLDER", "/nonexistent_path_for_test", 1);
}

~ScopedInvalidateConfig()
{
if (hadEnv)
{
setenv("ADUC_CONF_FOLDER", savedEnv.c_str(), 1);
}
else
{
unsetenv("ADUC_CONF_FOLDER");
}
}

ScopedInvalidateConfig(const ScopedInvalidateConfig&) = delete;
ScopedInvalidateConfig& operator=(const ScopedInvalidateConfig&) = delete;
};

} // namespace

// =====================================================================
// ProcessDownloadHandlerExtensibility - Bad argument tests
Expand Down Expand Up @@ -130,15 +183,14 @@ TEST_CASE("GetDownloadTimeoutInMinutes returns default when downloadOptions is n

TEST_CASE("GetDownloadTimeoutInMinutes returns downloadOptions value when config has zero timeout")
{
ScopedInvalidateConfig noConfig;
ExtensionManager_Download_Options options{};
options.timeoutInMinutes = 42;

unsigned int timeout = GetDownloadTimeoutInMinutes(&options);

// When config singleton is not initialized, it falls through to the
// downloadOptions path but config is nullptr so we get default.
// The config singleton returns nullptr if not initialized, so we
// get the default value.
// Config singleton is not initialized (env points to invalid path),
// so the function returns the default.
CHECK(timeout == CONTENT_DOWNLOADER_MAX_TIMEOUT_IN_MINUTES_DEFAULT);
}

Expand Down Expand Up @@ -166,6 +218,7 @@ TEST_CASE("Default_ExtensionManager_Download_Options has default timeout")

TEST_CASE("GetDownloadTimeoutInMinutes returns default when downloadOptions has zero timeout")
{
ScopedInvalidateConfig noConfig;
ExtensionManager_Download_Options options{};
options.timeoutInMinutes = 0;

Expand All @@ -177,6 +230,7 @@ TEST_CASE("GetDownloadTimeoutInMinutes returns default when downloadOptions has

TEST_CASE("GetDownloadTimeoutInMinutes returns default for large timeout value in options")
{
ScopedInvalidateConfig noConfig;
ExtensionManager_Download_Options options{};
options.timeoutInMinutes = 99999;

Expand All @@ -188,6 +242,7 @@ TEST_CASE("GetDownloadTimeoutInMinutes returns default for large timeout value i

TEST_CASE("Default_ExtensionManager_Download_Options can be modified and used")
{
ScopedInvalidateConfig noConfig;
ExtensionManager_Download_Options opts = Default_ExtensionManager_Download_Options;
opts.timeoutInMinutes = 120;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <aduc/calloc_wrapper.hpp>
#include <aduc/workflow_internal.h>
#include <aduc/workflow_utils.h>
#include <cstdio> // std::rename
#include <fstream>
#include <memory>
#include <parson.h>
Expand Down Expand Up @@ -59,6 +60,33 @@ struct ExtMgrCleanup
}
};

// RAII guard that temporarily hides a file by renaming it so that
// tests do not accidentally pick up real extension registrations
// installed on the host (e.g. /var/lib/adu/extensions/…/extension.json).
struct ScopedHideFile
{
std::string original;
std::string hidden;
bool renamed = false;

explicit ScopedHideFile(const std::string& path)
: original(path), hidden(path + ".hidden_by_test")
{
renamed = (std::rename(original.c_str(), hidden.c_str()) == 0);
}

~ScopedHideFile()
{
if (renamed)
{
std::rename(hidden.c_str(), original.c_str());
}
}

ScopedHideFile(const ScopedHideFile&) = delete;
ScopedHideFile& operator=(const ScopedHideFile&) = delete;
};

} // namespace

// =====================================================================
Expand Down Expand Up @@ -417,6 +445,7 @@ TEST_CASE("LoadContentDownloaderLibrary returns cached downloader")
TEST_CASE("LoadContentDownloaderLibrary fails when extension load fails and no cached")
{
ExtMgrCleanup cleanup;
ScopedHideFile hideExtJson(ADUC_CONTENT_DOWNLOADER_EXTENSION_PATH);
ExtensionManager::SetContentDownloaderLibrary(nullptr);

void* lib = nullptr;
Expand All @@ -431,6 +460,7 @@ TEST_CASE("LoadContentDownloaderLibrary fails when extension load fails and no c
TEST_CASE("IsComponentsEnumeratorRegistered returns false when no enumerator loaded")
{
ExtMgrCleanup cleanup;
ScopedHideFile hideExtJson(ADUC_COMPONENT_ENUMERATOR_EXTENSION_PATH);
bool registered = ExtensionManager::IsComponentsEnumeratorRegistered();
CHECK_FALSE(registered);
}
Expand All @@ -442,6 +472,7 @@ TEST_CASE("IsComponentsEnumeratorRegistered returns false when no enumerator loa
TEST_CASE("LoadComponentEnumeratorLibrary fails when extension not found")
{
ExtMgrCleanup cleanup;
ScopedHideFile hideExtJson(ADUC_COMPONENT_ENUMERATOR_EXTENSION_PATH);
void* lib = nullptr;
ADUC_Result result = ExtensionManager::LoadComponentEnumeratorLibrary(&lib);
CHECK(result.ResultCode == 0);
Expand All @@ -454,6 +485,7 @@ TEST_CASE("LoadComponentEnumeratorLibrary fails when extension not found")
TEST_CASE("InitializeContentDownloader fails when downloader lib not loaded")
{
ExtMgrCleanup cleanup;
ScopedHideFile hideExtJson(ADUC_CONTENT_DOWNLOADER_EXTENSION_PATH);
ExtensionManager::SetContentDownloaderLibrary(nullptr);

ADUC_Result result = ExtensionManager::InitializeContentDownloader("test", ADUC_LOG_DEBUG);
Expand Down Expand Up @@ -481,6 +513,7 @@ TEST_CASE("InitializeContentDownloader fails when contract version is unsupporte
TEST_CASE("GetAllComponents fails when component enumerator not loadable")
{
ExtMgrCleanup cleanup;
ScopedHideFile hideExtJson(ADUC_COMPONENT_ENUMERATOR_EXTENSION_PATH);
std::string output;
ADUC_Result result = ExtensionManager::GetAllComponents(output);
CHECK(result.ResultCode == 0);
Expand All @@ -490,6 +523,7 @@ TEST_CASE("GetAllComponents fails when component enumerator not loadable")
TEST_CASE("SelectComponents fails when component enumerator not loadable")
{
ExtMgrCleanup cleanup;
ScopedHideFile hideExtJson(ADUC_COMPONENT_ENUMERATOR_EXTENSION_PATH);
std::string output;
ADUC_Result result = ExtensionManager::SelectComponents("{}", output);
CHECK(result.ResultCode == 0);
Expand All @@ -508,6 +542,7 @@ TEST_CASE("ExtensionManager_Uninit wraps Uninit")
TEST_CASE("ExtensionManager_InitializeContentDownloader wrapper returns failure when no downloader")
{
ExtMgrCleanup cleanup;
ScopedHideFile hideExtJson(ADUC_CONTENT_DOWNLOADER_EXTENSION_PATH);
ExtensionManager::SetContentDownloaderLibrary(nullptr);

ADUC_Result result = ExtensionManager_InitializeContentDownloader("test", ADUC_LOG_DEBUG);
Expand Down Expand Up @@ -761,6 +796,7 @@ TEST_CASE("Download returns hash-type-not-supported when entity has no hashes")
TEST_CASE("ExtensionManager_Download C wrapper fails when no downloader library loaded")
{
ExtMgrCleanup cleanup;
ScopedHideFile hideExtJson(ADUC_CONTENT_DOWNLOADER_EXTENSION_PATH);
ExtensionManager::SetContentDownloaderLibrary(nullptr);

const std::string testWorkfolder = std::string{ ADUC_TEST_DATA_FOLDER } + "/extension_manager";
Expand Down