This is an automated email from the ASF dual-hosted git repository. pnoltes pushed a commit to branch feature/685-update-container-config-properties-usage in repository https://gitbox.apache.org/repos/asf/celix.git
commit 2c28348ee8a5d4c166a6b2635f620269c3af3a60 Author: Pepijn Noltes <[email protected]> AuthorDate: Fri May 24 12:54:25 2024 +0200 gh-685: Remove of old properties load and store Also introduces some additional error test to check the handling of properties load/save with an error return. --- .../gtest/src/rsa_client_server_tests.cc | 42 ++-- .../gtest/src/rsa_tests.cc | 25 +- cmake/cmake_celix/ContainerPackaging.cmake | 9 +- .../BundleArchiveWithErrorInjectionTestSuite.cc | 27 ++- .../src/CelixBundleCacheErrorInjectionTestSuite.cc | 42 +++- .../framework/gtest/src/CelixFrameworkTestSuite.cc | 3 +- libs/framework/src/bundle_archive.c | 14 +- libs/framework/src/celix_bundle_cache.c | 9 +- libs/framework/src/celix_launcher.c | 176 +++++++------- .../error_injector/celix_properties/CMakeLists.txt | 2 + .../celix_properties/include/celix_properties_ei.h | 2 + .../celix_properties/src/celix_properties_ei.cc | 22 ++ libs/utils/gtest/src/CxxPropertiesTestSuite.cc | 22 -- libs/utils/gtest/src/FileUtilsTestSuite.cc | 13 +- .../gtest/src/PropertiesErrorInjectionTestSuite.cc | 127 ---------- libs/utils/gtest/src/PropertiesTestSuite.cc | 68 ------ libs/utils/include/celix/Properties.h | 40 ---- libs/utils/include/celix_properties.h | 51 ---- libs/utils/src/properties.c | 264 --------------------- 19 files changed, 250 insertions(+), 708 deletions(-) diff --git a/bundles/remote_services/remote_service_admin_dfi/gtest/src/rsa_client_server_tests.cc b/bundles/remote_services/remote_service_admin_dfi/gtest/src/rsa_client_server_tests.cc index 7e903e1e9..a5d241cf1 100644 --- a/bundles/remote_services/remote_service_admin_dfi/gtest/src/rsa_client_server_tests.cc +++ b/bundles/remote_services/remote_service_admin_dfi/gtest/src/rsa_client_server_tests.cc @@ -44,16 +44,16 @@ typedef struct rsa_dfi_exception_test_service { int (*func1)(void *handle); }rsa_dfi_exception_test_service_t; - static celix_framework_t *serverFramework = NULL; - static celix_bundle_context_t *serverContext = NULL; + static celix_framework_t *serverFramework = nullptr; + static celix_bundle_context_t *serverContext = nullptr; - static celix_framework_t *clientFramework = NULL; - static celix_bundle_context_t *clientContext = NULL; + static celix_framework_t *clientFramework = nullptr; + static celix_bundle_context_t *clientContext = nullptr; - static rsa_dfi_exception_test_service_t *exceptionTestService = NULL; + static rsa_dfi_exception_test_service_t *exceptionTestService = nullptr; static long exceptionTestSvcId = -1L; - static remote_interceptor_t *serverSvcInterceptor=NULL; - static remote_interceptor_t *clientSvcInterceptor=NULL; + static remote_interceptor_t *serverSvcInterceptor=nullptr; + static remote_interceptor_t *clientSvcInterceptor=nullptr; static long serverSvcInterceptorSvcId = -1L; static long clientSvcInterceptorSvcId = -1L; static bool clientInterceptorPreProxyCallRetval=true; @@ -61,21 +61,23 @@ typedef struct rsa_dfi_exception_test_service { static void setupFm(bool useCurlShare) { //server - celix_properties_t *serverProps = celix_properties_load("server.properties"); - ASSERT_TRUE(serverProps != NULL); + celix_properties_t *serverProps = nullptr; + ASSERT_EQ(CELIX_SUCCESS, celix_properties_load2("server.properties", 0, &serverProps)); + ASSERT_TRUE(serverProps != nullptr); serverFramework = celix_frameworkFactory_createFramework(serverProps); - ASSERT_TRUE(serverFramework != NULL); + ASSERT_TRUE(serverFramework != nullptr); serverContext = celix_framework_getFrameworkContext(serverFramework); - ASSERT_TRUE(serverContext != NULL); + ASSERT_TRUE(serverContext != nullptr); //client - celix_properties_t *clientProperties = celix_properties_load("client.properties"); + celix_properties_t *clientProperties = nullptr; + ASSERT_EQ(CELIX_SUCCESS, celix_properties_load2("client.properties", 0, &clientProperties)); celix_properties_setBool(clientProperties, "RSA_DFI_USE_CURL_SHARE_HANDLE", useCurlShare); - ASSERT_TRUE(clientProperties != NULL); + ASSERT_TRUE(clientProperties != nullptr); clientFramework = celix_frameworkFactory_createFramework(clientProperties); - ASSERT_TRUE(clientFramework != NULL); + ASSERT_TRUE(clientFramework != nullptr); clientContext = celix_framework_getFrameworkContext(clientFramework); - ASSERT_TRUE(clientContext != NULL); + ASSERT_TRUE(clientContext != nullptr); } static void teardownFm(void) { @@ -92,7 +94,7 @@ typedef struct rsa_dfi_exception_test_service { celix_properties_set(properties, CELIX_RSA_SERVICE_EXPORTED_INTERFACES, RSA_DIF_EXCEPTION_TEST_SERVICE); celix_properties_set(properties, CELIX_RSA_SERVICE_EXPORTED_CONFIGS, "org.amdatu.remote.admin.http"); exceptionTestService = (rsa_dfi_exception_test_service_t *)calloc(1,sizeof(*exceptionTestService)); - exceptionTestService->handle = NULL; + exceptionTestService->handle = nullptr; exceptionTestService->func1 = rsaDfi_excepTestFunc1; exceptionTestSvcId = celix_bundleContext_registerService(serverContext, exceptionTestService, RSA_DIF_EXCEPTION_TEST_SERVICE, properties); } @@ -137,7 +139,7 @@ typedef struct rsa_dfi_exception_test_service { static void registerInterceptorService(void) { svcInterceptorPreExportCallRetval = true; serverSvcInterceptor = (remote_interceptor_t *)calloc(1,sizeof(*serverSvcInterceptor)); - serverSvcInterceptor->handle = NULL; + serverSvcInterceptor->handle = nullptr; serverSvcInterceptor->preProxyCall = serverServiceInterceptor_preProxyCall; serverSvcInterceptor->postProxyCall = serverServiceInterceptor_postProxyCall; serverSvcInterceptor->preExportCall = serverServiceInterceptor_preExportCall; @@ -153,7 +155,7 @@ typedef struct rsa_dfi_exception_test_service { clientInterceptorPreProxyCallRetval = true; clientSvcInterceptor = (remote_interceptor_t *)calloc(1,sizeof(*clientSvcInterceptor)); - clientSvcInterceptor->handle = NULL; + clientSvcInterceptor->handle = nullptr; clientSvcInterceptor->preProxyCall = clientServiceInterceptor_preProxyCall; clientSvcInterceptor->postProxyCall = clientServiceInterceptor_postProxyCall; clientSvcInterceptor->preExportCall = clientServiceInterceptor_preExportCall; @@ -472,8 +474,8 @@ public: char calcIdStr[32] = {0}; snprintf(calcIdStr, 32, "%li", calcId); - celix_array_list_t *svcRegistrations = NULL; - auto status = serverRsaSvc->exportService(serverRsaSvc->admin, calcIdStr, NULL, &svcRegistrations); + celix_array_list_t *svcRegistrations = nullptr; + auto status = serverRsaSvc->exportService(serverRsaSvc->admin, calcIdStr, nullptr, &svcRegistrations); ASSERT_EQ(CELIX_SUCCESS, status); ASSERT_EQ(1, celix_arrayList_size(svcRegistrations)); export_registration_t *exportedReg = static_cast<export_registration_t*>(celix_arrayList_get(svcRegistrations, 0)); diff --git a/bundles/remote_services/remote_service_admin_dfi/gtest/src/rsa_tests.cc b/bundles/remote_services/remote_service_admin_dfi/gtest/src/rsa_tests.cc index 3195b4630..8d8fef378 100644 --- a/bundles/remote_services/remote_service_admin_dfi/gtest/src/rsa_tests.cc +++ b/bundles/remote_services/remote_service_admin_dfi/gtest/src/rsa_tests.cc @@ -33,18 +33,19 @@ extern "C" { #define TST_CONFIGURATION_TYPE "org.amdatu.remote.admin.http" - static celix_framework_t *framework = NULL; - static celix_bundle_context_t *context = NULL; + static celix_framework_t *framework = nullptr; + static celix_bundle_context_t *context = nullptr; long calcSvcId = -1L; static void setupFm(void) { - celix_properties_t *fwProperties = celix_properties_load("config.properties"); - ASSERT_TRUE(fwProperties != NULL); + celix_properties_t *fwProperties = nullptr; + EXPECT_EQ(CELIX_SUCCESS, celix_properties_load2("config.properties", 0, &fwProperties)); + ASSERT_TRUE(fwProperties != nullptr); framework = celix_frameworkFactory_createFramework(fwProperties); - ASSERT_TRUE(framework != NULL); + ASSERT_TRUE(framework != nullptr); context = celix_framework_getFrameworkContext(framework); - ASSERT_TRUE(context != NULL); + ASSERT_TRUE(context != nullptr); calcSvcId = celix_bundleContext_findService(context, CALCULATOR_SERVICE); @@ -87,8 +88,8 @@ extern "C" { char strSvcId[64]; snprintf(strSvcId, 64, "%li", calcSvcId); - celix_array_list_t *svcRegistration = NULL; - int rc = rsa->exportService(rsa->admin, strSvcId, NULL, &svcRegistration); + celix_array_list_t *svcRegistration = nullptr; + int rc = rsa->exportService(rsa->admin, strSvcId, nullptr, &svcRegistration); ASSERT_EQ(CELIX_SUCCESS, rc); ASSERT_EQ(1, celix_arrayList_size(svcRegistration)); @@ -155,7 +156,7 @@ extern "C" { } static void testBundles(void) { - celix_array_list_t* bundles = NULL; + celix_array_list_t* bundles = nullptr; int rc = bundleContext_getBundles(context, &bundles); ASSERT_EQ(0, rc); @@ -165,9 +166,9 @@ extern "C" { int size = arrayList_size(bundles); int i; for (i = 0; i < size; i += 1) { - celix_bundle_t *bundle = NULL; - module_pt module = NULL; - char *name = NULL; + celix_bundle_t *bundle = nullptr; + module_pt module = nullptr; + char *name = nullptr; bundle = (celix_bundle_t *) arrayList_get(bundles, i); bundle_getCurrentModule(bundle, &module); diff --git a/cmake/cmake_celix/ContainerPackaging.cmake b/cmake/cmake_celix/ContainerPackaging.cmake index 78e799eb9..382a2bd16 100644 --- a/cmake/cmake_celix/ContainerPackaging.cmake +++ b/cmake/cmake_celix/ContainerPackaging.cmake @@ -221,6 +221,8 @@ function(add_celix_container) file(GENERATE OUTPUT "${STAGE1_LAUNCHER_SRC}" CONTENT "#include <celix_launcher.h> +#include <celix_err.h> + int main(int argc, char *argv[]) { const char * config = \"\\ CELIX_CONTAINER_NAME=$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_NAME>\\n\\ @@ -236,7 +238,12 @@ $<$<BOOL:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_INSTALL>>:CELIX $<JOIN:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_EMBEDDED_PROPERTIES>,\\n\\ >\"; - celix_properties_t *embeddedProps = celix_properties_loadFromString(config); + celix_properties_t *embeddedProps; + celix_status_t status = celix_properties_loadFromString2(config, 0, &embeddedProps); + if (status != CELIX_SUCCESS) { + celix_err_printErrors(stderr, \"Error creating embedded properties.\", NULL); + return -1; + } return celixLauncher_launchAndWaitForShutdown(argc, argv, embeddedProps); } " diff --git a/libs/framework/gtest/src/BundleArchiveWithErrorInjectionTestSuite.cc b/libs/framework/gtest/src/BundleArchiveWithErrorInjectionTestSuite.cc index 03100ddff..b7d1e5568 100644 --- a/libs/framework/gtest/src/BundleArchiveWithErrorInjectionTestSuite.cc +++ b/libs/framework/gtest/src/BundleArchiveWithErrorInjectionTestSuite.cc @@ -57,6 +57,7 @@ class BundleArchiveWithErrorInjectionTestSuite : public ::testing::Test { void teardownErrorInjectors() { celix_ei_expect_celix_properties_create(nullptr, 0, nullptr); + celix_ei_expect_celix_properties_save(nullptr, 0, CELIX_SUCCESS); celix_ei_expect_asprintf(nullptr, 0, 0); celix_ei_expect_calloc(nullptr, 0, nullptr); celix_ei_expect_malloc(nullptr, 0, nullptr); @@ -257,4 +258,28 @@ TEST_F(CelixBundleArchiveErrorInjectionTestSuite, ArchiveCreateErrorTest) { teardownErrorInjectors(); EXPECT_EQ(CELIX_SUCCESS, celix_bundleCache_destroy(cache)); -} \ No newline at end of file +} + +TEST_F(CelixBundleArchiveErrorInjectionTestSuite, StoreBundleStatePropertiesErrorTest) { + // Given a framework + auto fw = celix::createFramework({ + {CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE, "true"}, + }); + auto ctx = fw->getFrameworkBundleContext(); + + // When an error is prepped for celix_properties_save + celix_ei_expect_celix_properties_save((void*)celix_bundleCache_findBundleIdForLocation, 1, CELIX_FILE_IO_EXCEPTION); + + // When the bundle install, a bundle id is returned (async bundle install) + long bndId = ctx->installBundle(SIMPLE_TEST_BUNDLE1_LOCATION); + EXPECT_GE(bndId, 0); + + // Then the bundle is not successfully installed + + celix_bundleContext_useBundle( + ctx->getCBundleContext(), bndId, nullptr, [](void* /*handle*/, const celix_bundle_t* bnd) { + auto status = celix_bundle_getState(bnd); + // TODO fixme, bundle is installed and active, this is not correct + EXPECT_EQ(CELIX_BUNDLE_EVENT_INSTALLED, status); + }); +} diff --git a/libs/framework/gtest/src/CelixBundleCacheErrorInjectionTestSuite.cc b/libs/framework/gtest/src/CelixBundleCacheErrorInjectionTestSuite.cc index 2082013e4..732119441 100644 --- a/libs/framework/gtest/src/CelixBundleCacheErrorInjectionTestSuite.cc +++ b/libs/framework/gtest/src/CelixBundleCacheErrorInjectionTestSuite.cc @@ -21,6 +21,7 @@ #include <string> +#include "celix/FrameworkFactory.h" #include "celix_bundle_cache.h" #include "celix_constants.h" #include "celix_file_utils.h" @@ -28,6 +29,7 @@ #include "celix_log.h" #include "celix_properties.h" #include "celix_utils_ei.h" +#include "celix_properties_ei.h" #include "asprintf_ei.h" #include "bundle_archive_private.h" @@ -54,6 +56,7 @@ class CelixBundleCacheErrorInjectionTestSuite : public ::testing::Test { celix_ei_expect_celix_stringHashMap_create(nullptr, 0, nullptr); celix_ei_expect_malloc(nullptr, 0, nullptr); celix_ei_expect_calloc(nullptr, 0, nullptr); + celix_ei_expect_celix_properties_load2(nullptr, 0, CELIX_SUCCESS); celix_frameworkLogger_destroy(fw.logger); celix_properties_destroy(fw.configurationMap); } @@ -163,4 +166,41 @@ TEST_F(CelixBundleCacheErrorInjectionTestSuite, CreateBundleArchivesCacheErrorTe celix_ei_expect_celix_utils_writeOrCreateString((void*)celix_bundleCache_createArchive, 0, nullptr); EXPECT_EQ(CELIX_ENOMEM, celix_bundleCache_createBundleArchivesCache(&fw, true)); EXPECT_EQ(CELIX_SUCCESS, celix_bundleCache_destroy(cache)); -} \ No newline at end of file +} + +TEST_F(CelixBundleCacheErrorInjectionTestSuite, LoadBundleStatePropertiesErrorTest) { + // Given a celix framework + auto fw = celix::createFramework( + {{"CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL", "trace"}, {CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE, "true"}}); + auto ctx = fw->getFrameworkBundleContext(); + + // And an installed bundle (with a bundle cache) + long bndId = ctx->installBundle(SIMPLE_TEST_BUNDLE1_LOCATION); + EXPECT_GT(bndId, -1); + + // When framework is stopped + ctx.reset(); + fw.reset(); + + // And a new framework is created + fw = celix::createFramework( + {{"CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL", "trace"}, {CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE, "false"}}); + ctx = fw->getFrameworkBundleContext(); + + // When the bundle is uninstalled + celix_bundleContext_uninstallBundle(ctx->getCBundleContext(), bndId); + + // And a celix_properties_load error is injected + celix_ei_expect_celix_properties_load2( + (void*)celix_bundleCache_findBundleIdForLocation, 1, CELIX_FILE_IO_EXCEPTION); + + // Then installing the bundle will fail + bndId = ctx->installBundle(SIMPLE_TEST_BUNDLE1_LOCATION); + EXPECT_GT(bndId, -1); //async install, so bundle id is returned + celix_bundleContext_useBundle( + ctx->getCBundleContext(), bndId, nullptr, [](void* /*handle*/, const celix_bundle_t* bnd) { + auto status = celix_bundle_getState(bnd); + // TODO fixme, bundle is installed and active, this is not correct + EXPECT_EQ(CELIX_BUNDLE_EVENT_INSTALLED, status); + }); +} diff --git a/libs/framework/gtest/src/CelixFrameworkTestSuite.cc b/libs/framework/gtest/src/CelixFrameworkTestSuite.cc index 3eae055c6..5af8f391f 100644 --- a/libs/framework/gtest/src/CelixFrameworkTestSuite.cc +++ b/libs/framework/gtest/src/CelixFrameworkTestSuite.cc @@ -324,7 +324,8 @@ TEST_F(FrameworkFactoryTestSuite, LaunchFrameworkWithConfigTest) { * the specified bundles will be installed and - if needed - started. */ - auto* config = celix_properties_load(INSTALL_AND_START_BUNDLES_CONFIG_PROPERTIES_FILE); + celix_properties_t* config = nullptr; + ASSERT_EQ(CELIX_SUCCESS, celix_properties_load2(INSTALL_AND_START_BUNDLES_CONFIG_PROPERTIES_FILE, 0, &config)); ASSERT_TRUE(config != nullptr); framework_t* fw = celix_frameworkFactory_createFramework(config); diff --git a/libs/framework/src/bundle_archive.c b/libs/framework/src/bundle_archive.c index 688567345..b3cdd5e83 100644 --- a/libs/framework/src/bundle_archive.c +++ b/libs/framework/src/bundle_archive.c @@ -62,9 +62,9 @@ struct bundleArchive { static celix_status_t celix_bundleArchive_storeBundleStateProperties(bundle_archive_pt archive) { bool needUpdate = false; - celix_properties_t* bundleStateProperties = NULL; - bundleStateProperties = celix_properties_load(archive->savedBundleStatePropertiesPath); - if (bundleStateProperties == NULL) { + celix_properties_t* bundleStateProperties; + celix_status_t status = celix_properties_load2(archive->savedBundleStatePropertiesPath, 0, &bundleStateProperties); + if (status != CELIX_SUCCESS) { celix_framework_logTssErrors(archive->fw->logger, CELIX_LOG_LEVEL_ERROR); bundleStateProperties = celix_properties_create(); } @@ -91,8 +91,12 @@ static celix_status_t celix_bundleArchive_storeBundleStateProperties(bundle_arch //save bundle cache state properties if (needUpdate) { - celix_properties_store(bundleStateProperties, archive->savedBundleStatePropertiesPath, - "Bundle State Properties"); + status = celix_properties_save( + bundleStateProperties, archive->savedBundleStatePropertiesPath, CELIX_PROPERTIES_ENCODE_PRETTY); + if (status != CELIX_SUCCESS) { + celix_framework_logTssErrors(archive->fw->logger, CELIX_LOG_LEVEL_ERROR); + return status; + } } celix_properties_destroy(bundleStateProperties); return CELIX_SUCCESS; diff --git a/libs/framework/src/celix_bundle_cache.c b/libs/framework/src/celix_bundle_cache.c index d1917e2d2..770d83b33 100644 --- a/libs/framework/src/celix_bundle_cache.c +++ b/libs/framework/src/celix_bundle_cache.c @@ -235,7 +235,14 @@ static void celix_bundleCache_updateIdForLocationLookupMap(celix_bundle_cache_t* "%s/%s/%s", cache->cacheDir, dent->d_name, CELIX_BUNDLE_ARCHIVE_STATE_PROPERTIES_FILE_NAME); if (celix_utils_fileExists(bundleStateProperties)) { - celix_properties_t* props = celix_properties_load(bundleStateProperties); + celix_properties_t* props; + celix_status_t status = celix_properties_load2(bundleStateProperties, 0, &props); //validate the file (and ignore the result + if (status != CELIX_SUCCESS) { + fw_logCode(cache->fw->logger, CELIX_LOG_LEVEL_ERROR, status, + "Cannot load bundle state properties from %s", bundleStateProperties); + celix_framework_logTssErrors(cache->fw->logger, CELIX_LOG_LEVEL_ERROR); + continue; + } const char* visitLoc = celix_properties_get(props, CELIX_BUNDLE_ARCHIVE_LOCATION_PROPERTY_NAME, NULL); long bndId = celix_properties_getAsLong(props, CELIX_BUNDLE_ARCHIVE_BUNDLE_ID_PROPERTY_NAME, -1); if (visitLoc != NULL && bndId >= 0) { diff --git a/libs/framework/src/celix_launcher.c b/libs/framework/src/celix_launcher.c index 8cf32a6f3..e3a72e29c 100644 --- a/libs/framework/src/celix_launcher.c +++ b/libs/framework/src/celix_launcher.c @@ -17,32 +17,33 @@ * under the License. */ - #include "celix_launcher.h" -#include <stdio.h> -#include <string.h> -#include <stdlib.h> #include <libgen.h> #include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #ifndef CELIX_NO_CURLINIT #include <curl/curl.h> #endif -#include "framework.h" -#include "celix_framework_factory.h" #include "celix_constants.h" +#include "celix_framework_factory.h" #include "celix_framework_utils.h" +#include "celix_err.h" static void celixLauncher_shutdownFramework(int signal); static void celixLauncher_ignore(int signal); -static int celixLauncher_launchWithConfigAndProps(const char *configFile, celix_framework_t* *framework, celix_properties_t* packedConfig); -static void celixLauncher_combineProperties(celix_properties_t *original, const celix_properties_t *append); +static int celixLauncher_launchWithConfigAndProps(const char* configFile, + celix_framework_t** framework, + celix_properties_t* packedConfig); +static void celixLauncher_combineProperties(celix_properties_t* original, const celix_properties_t* append); static celix_properties_t* celixLauncher_createConfig(const char* configFile, celix_properties_t* embeddedProperties); static void celixLauncher_printUsage(char* progName); -static void celixLauncher_printProperties(celix_properties_t *embeddedProps, const char* configFile); +static void celixLauncher_printProperties(celix_properties_t* embeddedProps, const char* configFile); static int celixLauncher_createBundleCache(celix_properties_t* embeddedProperties, const char* configFile); #define DEFAULT_CONFIG_FILE "config.properties" @@ -50,11 +51,9 @@ static int celixLauncher_createBundleCache(celix_properties_t* embeddedPropertie #define CELIX_LAUNCHER_OK_EXIT_CODE 0 #define CELIX_LAUNCHER_ERROR_EXIT_CODE 1 -static framework_t *g_fw = NULL; - +static framework_t* g_fw = NULL; - -int celixLauncher_launchAndWaitForShutdown(int argc, char *argv[], celix_properties_t* packedConfig) { +int celixLauncher_launchAndWaitForShutdown(int argc, char* argv[], celix_properties_t* packedConfig) { celix_framework_t* framework = NULL; int rc = celixLauncher_launchWithArgv(argc, argv, packedConfig, &framework); if (rc == 0 && framework != NULL) { @@ -131,43 +130,45 @@ int celixLauncher_launchWithArgv(int argc, } static void celixLauncher_shutdownFramework(int signal) { - if (g_fw != NULL) { - celixLauncher_stop(g_fw); //NOTE main thread will destroy - } + if (g_fw != NULL) { + celixLauncher_stop(g_fw); // NOTE main thread will destroy + } } static void celixLauncher_ignore(int signal) { - //ignoring for signal SIGUSR1, SIGUSR2. Can be used on threads + // ignoring for signal SIGUSR1, SIGUSR2. Can be used on threads } -int celixLauncher_launch(const char *configFile, celix_framework_t* *framework) { - return celixLauncher_launchWithConfigAndProps(configFile, framework, NULL); +int celixLauncher_launch(const char* configFile, celix_framework_t** framework) { + return celixLauncher_launchWithConfigAndProps(configFile, framework, NULL); } -static int celixLauncher_launchWithConfigAndProps(const char *configFile, celix_framework_t** framework, celix_properties_t* packedConfig) { +static int celixLauncher_launchWithConfigAndProps(const char* configFile, + celix_framework_t** framework, + celix_properties_t* packedConfig) { celix_properties_t* config = celixLauncher_createConfig(configFile, packedConfig); + if (!config) { + return CELIX_LAUNCHER_ERROR_EXIT_CODE; + } return celixLauncher_launchWithProperties(config, framework); } - int celixLauncher_launchWithProperties(celix_properties_t* config, celix_framework_t** framework) { #ifndef CELIX_NO_CURLINIT - // Before doing anything else, let's setup Curl - curl_global_init(CURL_GLOBAL_ALL); + // Before doing anything else, let's setup Curl + curl_global_init(CURL_GLOBAL_ALL); #endif - *framework = celix_frameworkFactory_createFramework(config); - return *framework != NULL ? CELIX_LAUNCHER_OK_EXIT_CODE : CELIX_LAUNCHER_ERROR_EXIT_CODE; + *framework = celix_frameworkFactory_createFramework(config); + return *framework != NULL ? CELIX_LAUNCHER_OK_EXIT_CODE : CELIX_LAUNCHER_ERROR_EXIT_CODE; } -void celixLauncher_waitForShutdown(celix_framework_t* framework) { - celix_framework_waitForStop(framework); -} +void celixLauncher_waitForShutdown(celix_framework_t* framework) { celix_framework_waitForStop(framework); } void celixLauncher_destroy(celix_framework_t* framework) { celix_frameworkFactory_destroyFramework(framework); #ifndef CELIX_NO_CURLINIT - // Cleanup Curl - curl_global_cleanup(); + // Cleanup Curl + curl_global_cleanup(); #endif } @@ -175,7 +176,6 @@ void celixLauncher_stop(celix_framework_t* framework) { celix_framework_stopBundle(framework, CELIX_FRAMEWORK_BUNDLE_ID); } - static void celixLauncher_printUsage(char* progName) { printf("Usage:\n %s [-h|-p] [path/to/runtime/config.properties]\n", basename(progName)); printf("Options:\n"); @@ -186,67 +186,69 @@ static void celixLauncher_printUsage(char* progName) { printf("\n"); } -static void celixLauncher_printProperties(celix_properties_t *embeddedProps, const char *configFile) { - celix_properties_t *keys = celix_properties_create(); //only to store the keys +static void celixLauncher_printProperties(celix_properties_t* embeddedProps, const char* configFile) { + celix_properties_t* keys = celix_properties_create(); // only to store the keys - printf("Embedded properties:\n"); - if (embeddedProps == NULL || celix_properties_size(embeddedProps) == 0) { - printf("|- Empty!\n"); - } else { + printf("Embedded properties:\n"); + if (embeddedProps == NULL || celix_properties_size(embeddedProps) == 0) { + printf("|- Empty!\n"); + } else { CELIX_PROPERTIES_ITERATE(embeddedProps, visit) { - printf("|- %s=%s\n", visit.key, visit.entry.value); + printf("|- %s=%s\n", visit.key, visit.entry.value); celix_properties_set(keys, visit.key, NULL); } - } - printf("\n"); - - celix_properties_t *runtimeProps = NULL; - if (configFile != NULL) { - runtimeProps = celix_properties_load(configFile); - } - printf("Runtime properties (input %s):\n", configFile); - if (runtimeProps == NULL || celix_properties_size(runtimeProps) == 0) { - printf("|- Empty!\n"); - } else { + } + printf("\n"); + + celix_properties_t* runtimeProps = NULL; + if (configFile != NULL) { + celix_status_t status = celix_properties_load2(configFile, 0, &runtimeProps); + if (status != CELIX_SUCCESS) { + celix_err_printErrors(stderr, "Error loading config file.", NULL); + } + } + printf("Runtime properties (input %s):\n", configFile); + if (runtimeProps == NULL || celix_properties_size(runtimeProps) == 0) { + printf("|- Empty!\n"); + } else { CELIX_PROPERTIES_ITERATE(runtimeProps, visit) { - printf("|- %s=%s\n", visit.key, visit.entry.value); + printf("|- %s=%s\n", visit.key, visit.entry.value); celix_properties_set(keys, visit.key, NULL); } - } + } printf("\n"); - //combined result - printf("Resolved (env, runtime and embedded) properties:\n"); - if (celix_properties_size(keys) == 0) { - printf("|- Empty!\n"); - } else { + // combined result + printf("Resolved (env, runtime and embedded) properties:\n"); + if (celix_properties_size(keys) == 0) { + printf("|- Empty!\n"); + } else { CELIX_PROPERTIES_ITERATE(keys, visit) { - const char *valEm = celix_properties_get(embeddedProps, visit.key, NULL); - const char *valRt = celix_properties_get(runtimeProps, visit.key, NULL); - const char *envVal = getenv(visit.key); - const char *val = envVal != NULL ? envVal : valRt != NULL ? valRt : valEm; - const char *source = envVal != NULL ? "environment" : valRt != NULL ? "runtime" : "embedded"; - printf("|- %s=%s (source %s)\n", visit.key, val, source); - } - } + const char* valEm = celix_properties_get(embeddedProps, visit.key, NULL); + const char* valRt = celix_properties_get(runtimeProps, visit.key, NULL); + const char* envVal = getenv(visit.key); + const char* val = envVal != NULL ? envVal : valRt != NULL ? valRt : valEm; + const char* source = envVal != NULL ? "environment" : valRt != NULL ? "runtime" : "embedded"; + printf("|- %s=%s (source %s)\n", visit.key, val, source); + } + } printf("\n"); - if (runtimeProps != NULL) { - celix_properties_destroy(runtimeProps); - } - celix_properties_destroy(keys); + if (runtimeProps != NULL) { + celix_properties_destroy(runtimeProps); + } + celix_properties_destroy(keys); } static int celixLauncher_createBundleCache(celix_properties_t* embeddedProperties, const char* configFile) { - celix_framework_t* fw = NULL; celix_properties_t* config = celixLauncher_createConfig(configFile, embeddedProperties); - celix_status_t status = framework_create(&fw, config); - if (status != CELIX_SUCCESS) { + celix_framework_t* fw = celix_frameworkFactory_createFramework(config); + if (!fw) { fprintf(stderr, "Failed to create framework for bundle cache creation\n"); return CELIX_LAUNCHER_ERROR_EXIT_CODE; } - status = celix_framework_utils_createBundleArchivesCache(fw); - (void)framework_destroy(fw); + celix_status_t status = celix_framework_utils_createBundleArchivesCache(fw); + celix_frameworkFactory_destroyFramework(fw); if (status != CELIX_SUCCESS) { fprintf(stderr, "Failed to create bundle cache\n"); return CELIX_LAUNCHER_ERROR_EXIT_CODE; @@ -254,28 +256,24 @@ static int celixLauncher_createBundleCache(celix_properties_t* embeddedPropertie return CELIX_LAUNCHER_OK_EXIT_CODE; } -static void celixLauncher_combineProperties(celix_properties_t *original, const celix_properties_t *append) { - if (original != NULL && append != NULL) { - CELIX_PROPERTIES_ITERATE(append, visit) { - celix_properties_setEntry(original, visit.key, &visit.entry); - } - } +static void celixLauncher_combineProperties(celix_properties_t* original, const celix_properties_t* append) { + if (original != NULL && append != NULL) { + CELIX_PROPERTIES_ITERATE(append, visit) { celix_properties_setEntry(original, visit.key, &visit.entry); } + } } static celix_properties_t* celixLauncher_createConfig(const char* configFile, celix_properties_t* embeddedProperties) { - if (embeddedProperties == NULL) { + if (!embeddedProperties) { embeddedProperties = celix_properties_create(); } - FILE *config = fopen(configFile, "r"); - if (config != NULL) { - celix_properties_t *configProps = celix_properties_loadWithStream(config); - fclose(config); - if (configProps != NULL) { - celixLauncher_combineProperties(embeddedProperties, configProps); - celix_properties_destroy(configProps); - } + celix_autoptr(celix_properties_t) configProperties = NULL; + celix_status_t status = celix_properties_load2(configFile, 0, &configProperties); + if (status != CELIX_SUCCESS) { + fprintf(stderr, "Error loading config file %s\n", configFile); + celix_properties_destroy(embeddedProperties); + return NULL; } - + celixLauncher_combineProperties(embeddedProperties, configProperties); return embeddedProperties; } diff --git a/libs/utils/error_injector/celix_properties/CMakeLists.txt b/libs/utils/error_injector/celix_properties/CMakeLists.txt index 7f65cd902..717cb50a5 100644 --- a/libs/utils/error_injector/celix_properties/CMakeLists.txt +++ b/libs/utils/error_injector/celix_properties/CMakeLists.txt @@ -26,5 +26,7 @@ target_link_options(properties_ei INTERFACE LINKER:--wrap,celix_properties_set LINKER:--wrap,celix_properties_setLong LINKER:--wrap,celix_properties_setVersion + LINKER:--wrap,celix_properties_save + LINKER:--wrap,celix_properties_load2 ) add_library(Celix::properties_ei ALIAS properties_ei) diff --git a/libs/utils/error_injector/celix_properties/include/celix_properties_ei.h b/libs/utils/error_injector/celix_properties/include/celix_properties_ei.h index ad5f7184d..c4076ec46 100644 --- a/libs/utils/error_injector/celix_properties/include/celix_properties_ei.h +++ b/libs/utils/error_injector/celix_properties/include/celix_properties_ei.h @@ -31,6 +31,8 @@ CELIX_EI_DECLARE(celix_properties_copy, celix_properties_t*); CELIX_EI_DECLARE(celix_properties_set, celix_status_t); CELIX_EI_DECLARE(celix_properties_setLong, celix_status_t); CELIX_EI_DECLARE(celix_properties_setVersion, celix_status_t); +CELIX_EI_DECLARE(celix_properties_save, celix_status_t); +CELIX_EI_DECLARE(celix_properties_load2, celix_status_t); #ifdef __cplusplus } diff --git a/libs/utils/error_injector/celix_properties/src/celix_properties_ei.cc b/libs/utils/error_injector/celix_properties/src/celix_properties_ei.cc index 1c9ace21c..1f2eeba60 100644 --- a/libs/utils/error_injector/celix_properties/src/celix_properties_ei.cc +++ b/libs/utils/error_injector/celix_properties/src/celix_properties_ei.cc @@ -55,4 +55,26 @@ celix_status_t __wrap_celix_properties_setVersion(celix_properties_t *properties return __real_celix_properties_setVersion(properties, key, version); } +celix_status_t +__real_celix_properties_save(const celix_properties_t* properties, const char* filename, int encodeFlags); +CELIX_EI_DEFINE(celix_properties_save, celix_status_t) +celix_status_t +__wrap_celix_properties_save(const celix_properties_t* properties, const char* filename, int encodeFlags) { + CELIX_EI_IMPL(celix_properties_save); + return __real_celix_properties_save(properties, filename, encodeFlags); +} + +celix_status_t +__real_celix_properties_load2(const char* filename, + int decodeFlags, + celix_properties_t** out); +CELIX_EI_DEFINE(celix_properties_load2, celix_status_t) +celix_status_t +__wrap_celix_properties_load2(const char* filename, + int decodeFlags, + celix_properties_t** out) { + CELIX_EI_IMPL(celix_properties_load2); + return __real_celix_properties_load2(filename, decodeFlags, out); +} + } \ No newline at end of file diff --git a/libs/utils/gtest/src/CxxPropertiesTestSuite.cc b/libs/utils/gtest/src/CxxPropertiesTestSuite.cc index 1e65bb4f7..c95986743 100644 --- a/libs/utils/gtest/src/CxxPropertiesTestSuite.cc +++ b/libs/utils/gtest/src/CxxPropertiesTestSuite.cc @@ -325,25 +325,3 @@ TEST_F(CxxPropertiesTestSuite, ArrayListTest) { EXPECT_EQ(versions.size(), 1); EXPECT_EQ(versions[0], checkVersion); } - -TEST_F(CxxPropertiesTestSuite, StoreAndLoadTest) { - std::string path{"cxx_store_and_load_test.properties"}; - - celix::Properties props{}; - props.set("key1", "1"); - props.set("key2", "2"); - - EXPECT_NO_THROW(props.store(path)); - - celix::Properties loadedProps{}; - EXPECT_NO_THROW(loadedProps = celix::Properties::load(path)); - EXPECT_TRUE(loadedProps == props); - - try { - loadedProps = celix::Properties::load("non-existence"); - (void)loadedProps; - FAIL() << "Expected exception not thrown"; - } catch (const celix::IOException& e) { - EXPECT_TRUE(strstr(e.what(), "Cannot load celix::Properties")); - } -} diff --git a/libs/utils/gtest/src/FileUtilsTestSuite.cc b/libs/utils/gtest/src/FileUtilsTestSuite.cc index 6ff80d79c..775bcb108 100644 --- a/libs/utils/gtest/src/FileUtilsTestSuite.cc +++ b/libs/utils/gtest/src/FileUtilsTestSuite.cc @@ -178,13 +178,14 @@ TEST_F(FileUtilsTestSuite, ExtractZipFileTest) { EXPECT_EQ(status, CELIX_SUCCESS); EXPECT_TRUE(celix_utils_fileExists(file1)); - auto* props = celix_properties_load(file1); - EXPECT_NE(props, nullptr); + celix_properties_t* props = nullptr; + EXPECT_EQ(CELIX_SUCCESS, celix_properties_load2(file1, 0, &props)); EXPECT_EQ(celix_properties_getAsLong(props, "level", 0), 1); celix_properties_destroy(props); EXPECT_TRUE(celix_utils_fileExists(file2)); - props = celix_properties_load(file2); + props = nullptr; + EXPECT_EQ(CELIX_SUCCESS, celix_properties_load2(file2, 0, &props)); EXPECT_NE(props, nullptr); EXPECT_EQ(celix_properties_getAsLong(props, "level", 0), 2); celix_properties_destroy(props); @@ -262,13 +263,15 @@ TEST_F(FileUtilsTestSuite, ExtractZipDataTest) { EXPECT_EQ(status, CELIX_SUCCESS); EXPECT_TRUE(celix_utils_fileExists(file1)); - auto* props = celix_properties_load(file1); + celix_properties_t* props = nullptr; + EXPECT_EQ(CELIX_SUCCESS, celix_properties_load2(file1, 0, &props)); EXPECT_NE(props, nullptr); EXPECT_EQ(celix_properties_getAsLong(props, "level", 0), 1); celix_properties_destroy(props); EXPECT_TRUE(celix_utils_fileExists(file2)); - props = celix_properties_load(file2); + props = nullptr; + EXPECT_EQ(CELIX_SUCCESS, celix_properties_load2(file2, 0, &props)); EXPECT_NE(props, nullptr); EXPECT_EQ(celix_properties_getAsLong(props, "level", 0), 2); celix_properties_destroy(props); diff --git a/libs/utils/gtest/src/PropertiesErrorInjectionTestSuite.cc b/libs/utils/gtest/src/PropertiesErrorInjectionTestSuite.cc index e7916ea38..2ff3ff66c 100644 --- a/libs/utils/gtest/src/PropertiesErrorInjectionTestSuite.cc +++ b/libs/utils/gtest/src/PropertiesErrorInjectionTestSuite.cc @@ -50,14 +50,8 @@ class PropertiesErrorInjectionTestSuite : public ::testing::Test { celix_ei_expect_celix_stringHashMap_createWithOptions(nullptr, 0, nullptr); celix_ei_expect_celix_arrayList_copy(nullptr, 0, nullptr); celix_ei_expect_celix_utils_strdup(nullptr, 0, nullptr); - celix_ei_expect_fopen(nullptr, 0, nullptr); - celix_ei_expect_fputc(nullptr, 0, 0); - celix_ei_expect_fseek(nullptr, 0, 0); - celix_ei_expect_ftell(nullptr, 0, 0); - celix_ei_expect_celix_utils_strdup(nullptr, 0, nullptr); celix_ei_expect_celix_stringHashMap_put(nullptr, 0, 0); celix_ei_expect_celix_version_copy(nullptr, 0, nullptr); - celix_ei_expect_celix_arrayList_createWithOptions(nullptr, 0, nullptr); celix_ei_expect_celix_arrayList_copy(nullptr, 0, nullptr); } @@ -176,116 +170,6 @@ TEST_F(PropertiesErrorInjectionTestSuite, SetFailureTest) { ASSERT_THROW(cxxProps.set("key", "value"), std::bad_alloc); } -TEST_F(PropertiesErrorInjectionTestSuite, StoreFailureTest) { - // C API - // Given a celix properties object - celix_autoptr(celix_properties_t) props = celix_properties_create(); - celix_properties_set(props, "key", "value"); - - // When a fopen error injection is set for celix_properties_store (during fopen) - celix_ei_expect_fopen((void*)celix_properties_store, 0, nullptr); - // Then the celix_properties_store call fails - auto status = celix_properties_store(props, "file", nullptr); - ASSERT_EQ(status, CELIX_FILE_IO_EXCEPTION); - // And a celix err msg is set - ASSERT_EQ(1, celix_err_getErrorCount()); - celix_err_resetErrors(); - - // When a fputc error injection is set for celix_properties_store (during fputc) - celix_ei_expect_fputc((void*)celix_properties_store, 0, EOF); - // Then the celix_properties_store call fails - status = celix_properties_store(props, "file", nullptr); - ASSERT_EQ(status, CELIX_FILE_IO_EXCEPTION); - // And a celix err msg is set - ASSERT_EQ(1, celix_err_getErrorCount()); - celix_err_resetErrors(); - - // C++ API - // Given a C++ celix properties object. - auto cxxProps = celix::Properties{}; - cxxProps.set("key", "value"); - - // When a fopen error injection is set for celix_properties_store (during fopen) - celix_ei_expect_fopen((void*)celix_properties_store, 0, nullptr); - // Then the Properties:store throws a celix::IOException exception - EXPECT_THROW(cxxProps.store("file"), celix::IOException); - // And a celix err msg is set - ASSERT_EQ(1, celix_err_getErrorCount()); - celix_err_resetErrors(); -} - -TEST_F(PropertiesErrorInjectionTestSuite, LoadFailureTest) { - // C API - // Given a fmemstream buffer with a properties file - const char* content = "key=value\n"; - auto* memStream = fmemopen((void*)content, strlen(content), "r"); - - // When a fopen error injection is set for celix_properties_load (during fopen) - celix_ei_expect_fopen((void*)celix_properties_load, 0, nullptr); - // Then the celix_properties_load call fails - auto props = celix_properties_load("file"); - ASSERT_EQ(nullptr, props); - // And a celix err msg is set - ASSERT_EQ(1, celix_err_getErrorCount()); - celix_err_resetErrors(); - - // When a malloc error injection is set for celix_properties_loadWithStream (during properties create) - celix_ei_expect_malloc((void*)celix_properties_create, 0, nullptr); - // Then the celix_properties_loadWithStream call fails - props = celix_properties_loadWithStream(memStream); - ASSERT_EQ(nullptr, props); - // And a celix err msg is set - ASSERT_EQ(1, celix_err_getErrorCount()); - celix_err_resetErrors(); - - // When a fseek error injection is set for celix_properties_loadWithStream - celix_ei_expect_fseek((void*)celix_properties_loadWithStream, 0, -1); - // Then the celix_properties_loadWithStream call fails - props = celix_properties_loadWithStream(memStream); - ASSERT_EQ(nullptr, props); - // And a celix err msg is set - ASSERT_EQ(1, celix_err_getErrorCount()); - celix_err_resetErrors(); - - // When a fseek error injection is set for celix_properties_loadWithStream, ordinal 2 - celix_ei_expect_fseek((void*)celix_properties_loadWithStream, 0, -1, 2); - // Then the celix_properties_loadWithStream call fails - props = celix_properties_loadWithStream(memStream); - ASSERT_EQ(nullptr, props); - // And a celix err msg is set - ASSERT_EQ(1, celix_err_getErrorCount()); - celix_err_resetErrors(); - - // When a ftell error injection is set for celix_properties_loadWithStream - celix_ei_expect_ftell((void*)celix_properties_loadWithStream, 0, -1); - // Then the celix_properties_loadWithStream call fails - props = celix_properties_loadWithStream(memStream); - ASSERT_EQ(nullptr, props); - // And a celix err msg is set - ASSERT_EQ(1, celix_err_getErrorCount()); - celix_err_resetErrors(); - - // When a malloc error injection is set for celix_properties_loadWithStream - celix_ei_expect_malloc((void*)celix_properties_loadWithStream, 0, nullptr); - // Then the celix_properties_loadWithStream call fails - props = celix_properties_loadWithStream(memStream); - ASSERT_EQ(nullptr, props); - // And a celix err msg is set - ASSERT_EQ(1, celix_err_getErrorCount()); - celix_err_resetErrors(); - - //C++ API - // When a fopen error injection is set for celix_properties_load (during fopen) - celix_ei_expect_fopen((void*)celix_properties_load, 0, nullptr); - // Then the celix::Properties::load call throws a celix::IOException exception - EXPECT_THROW(celix::Properties::load("file"), celix::IOException); - // And a celix err msg is set - ASSERT_EQ(1, celix_err_getErrorCount()); - celix_err_resetErrors(); - - fclose(memStream); -} - TEST_F(PropertiesErrorInjectionTestSuite, GetAsVersionWithVersionCopyFailedTest) { //Given a properties set with a version celix_autoptr(celix_properties_t) props = celix_properties_create(); @@ -428,17 +312,6 @@ TEST_F(PropertiesErrorInjectionTestSuite, AssignFailureTest) { celix_err_resetErrors(); } -TEST_F(PropertiesErrorInjectionTestSuite, LoadFromStringFailureTest) { - // When a strdup error injection is set for celix_properties_loadFromString (during strdup) - celix_ei_expect_celix_utils_strdup((void*)celix_properties_loadFromString, 0, nullptr); - // Then the celix_properties_loadFromString call fails - auto props = celix_properties_loadFromString("key=value"); - ASSERT_EQ(nullptr, props); - // And a celix err msg is set - ASSERT_EQ(1, celix_err_getErrorCount()); - celix_err_resetErrors(); -} - TEST_F(PropertiesErrorInjectionTestSuite, SetVersionFailureTest) { // Given a celix properties object celix_autoptr(celix_properties_t) props = celix_properties_create(); diff --git a/libs/utils/gtest/src/PropertiesTestSuite.cc b/libs/utils/gtest/src/PropertiesTestSuite.cc index f44e0b077..391488c4c 100644 --- a/libs/utils/gtest/src/PropertiesTestSuite.cc +++ b/libs/utils/gtest/src/PropertiesTestSuite.cc @@ -54,69 +54,6 @@ TEST_F(PropertiesTestSuite, CreateTest) { celix_properties_destroy(properties); } -TEST_F(PropertiesTestSuite, LoadTest) { - char propertiesFile[] = "resources-test/properties.txt"; - auto* properties = celix_properties_load(propertiesFile); - EXPECT_EQ(4, celix_properties_size(properties)); - - const char keyA[] = "a"; - const char *valueA = celix_properties_get(properties, keyA, nullptr); - EXPECT_STREQ("b", valueA); - - const char keyNiceA[] = "nice_a"; - const char *valueNiceA = celix_properties_get(properties, keyNiceA, nullptr); - EXPECT_STREQ("nice_b", valueNiceA); - - const char keyB[] = "b"; - const char *valueB = celix_properties_get(properties, keyB, nullptr); - EXPECT_STREQ("c \t d", valueB); - - celix_properties_destroy(properties); -} - -TEST_F(PropertiesTestSuite, LoadFromStringTest) { - const char* string = "key1=value1\nkey2=value2"; - auto* props = celix_properties_loadFromString(string); - EXPECT_EQ(2, celix_properties_size(props)); - EXPECT_STREQ("value1", celix_properties_get(props, "key1", "")); - EXPECT_STREQ("value2", celix_properties_get(props, "key2", "")); - celix_properties_destroy(props); -} - - -TEST_F(PropertiesTestSuite, StoreTest) { - const char* propertiesFile = "resources-test/properties_out.txt"; - celix_autoptr(celix_properties_t) properties = celix_properties_create(); - celix_properties_set(properties, "keyA", "valueA"); - celix_properties_set(properties, "keyB", "valueB"); - celix_properties_store(properties, propertiesFile, nullptr); - - celix_autoptr(celix_properties_t) properties2 = celix_properties_load(propertiesFile); - EXPECT_EQ(celix_properties_size(properties), celix_properties_size(properties2)); - EXPECT_STREQ(celix_properties_get(properties, "keyA", ""), celix_properties_get(properties2, "keyA", "")); - EXPECT_STREQ(celix_properties_get(properties, "keyB", ""), celix_properties_get(properties2, "keyB", "")); -} - -TEST_F(PropertiesTestSuite, StoreWithHeaderTest) { - const char* propertiesFile = "resources-test/properties_with_header_out.txt"; - celix_autoptr(celix_properties_t) properties = celix_properties_create(); - celix_properties_set(properties, "keyA", "valueA"); - celix_properties_set(properties, "keyB", "valueB"); - celix_properties_store(properties, propertiesFile, "header"); - - celix_autoptr(celix_properties_t) properties2 = celix_properties_load(propertiesFile); - EXPECT_EQ(celix_properties_size(properties), celix_properties_size(properties2)); - EXPECT_STREQ(celix_properties_get(properties, "keyA", ""), celix_properties_get(properties2, "keyA", "")); - EXPECT_STREQ(celix_properties_get(properties, "keyB", ""), celix_properties_get(properties2, "keyB", "")); - - //check if provided header text is present in file - FILE *f = fopen(propertiesFile, "r"); - char line[1024]; - fgets(line, sizeof(line), f); - EXPECT_STREQ("#header\n", line); - fclose(f); -} - TEST_F(PropertiesTestSuite, GetAsLongTest) { celix_properties_t *props = celix_properties_create(); celix_properties_set(props, "t1", "42"); @@ -662,11 +599,6 @@ TEST_F(PropertiesTestSuite, PropertiesAutoCleanupTest) { celix_autoptr(celix_properties_t) props = celix_properties_create(); } -TEST_F(PropertiesTestSuite, NullArgumentsTest) { - auto props = celix_properties_loadWithStream(nullptr); - EXPECT_EQ(nullptr, props); -} - TEST_F(PropertiesTestSuite, PropertiesEqualsTest) { EXPECT_TRUE(celix_properties_equals(nullptr, nullptr)); diff --git a/libs/utils/include/celix/Properties.h b/libs/utils/include/celix/Properties.h index ee71925ea..2ca9672d1 100644 --- a/libs/utils/include/celix/Properties.h +++ b/libs/utils/include/celix/Properties.h @@ -932,21 +932,6 @@ namespace celix { return result; } - /** - * @brief Store the property set to the given file path. - * - * This function writes the properties in the given set to the specified file path in a format suitable - * for loading with the load() function. - * If a non-empty header string is provided, it will be written as a comment at the beginning of the file. - * - * @param[in] file The file to store the properties to. - * @param[in] header An optional (single line) header string to include as a comment at the beginning of the file. - * @throws celix::IOException If an error occurs while writing to the file. - */ - void store(const std::string& path, const std::string& header = {}) const { - storeTo(path.data(), header.empty() ? nullptr : header.data()); - } - /** * @brief Enum class for encoding flags used in Celix properties JSON encoding. * @@ -1044,16 +1029,6 @@ namespace celix { Strict = CELIX_PROPERTIES_DECODE_STRICT /**< If set, decoding will fail if there are any errors. */ }; - /** - * @brief Loads properties from the file at the given path. - * @param[in] path The path to the file containing the properties. - * @return A new Properties object containing the properties from the file. - * @throws celix::IOException If the file cannot be opened or read. - * @throws celix::IllegalArgumentException if the provided input cannot be decoded to a properties object. - * @throws std::bad_alloc If there was not enough memory to load the properties. - */ - static Properties load(const std::string& path) { return loadFrom(path.data()); } - /** * @brief Load a Properties object from a file. * @@ -1153,21 +1128,6 @@ namespace celix { } } - static celix::Properties loadFrom(const char* path) { - auto* cProps = celix_properties_load(path); - if (cProps) { - return celix::Properties::own(cProps); - } - throw celix::IOException{"Cannot load celix::Properties from path " + std::string{path}}; - } - - void storeTo(const char* path, const char* header) const { - auto status = celix_properties_store(cProps.get(), path, header); - if (status != CELIX_SUCCESS) { - throw celix::IOException{"Cannot store celix::Properties to " + std::string{path}}; - } - } - template<typename T> std::vector<T> convertToVector(const celix_array_list_t* list, const std::vector<T>& defaultValue, T (*get)(const celix_array_list_t*, int index)) const { if (list) { diff --git a/libs/utils/include/celix_properties.h b/libs/utils/include/celix_properties.h index f49d4628b..bf927935e 100644 --- a/libs/utils/include/celix_properties.h +++ b/libs/utils/include/celix_properties.h @@ -129,57 +129,6 @@ CELIX_UTILS_EXPORT void celix_properties_destroy(celix_properties_t* properties) CELIX_DEFINE_AUTOPTR_CLEANUP_FUNC(celix_properties_t, celix_properties_destroy) -/** - * @brief Load properties from a file. - * - * If the return status is an error, an error message is logged to celix_err. - * - * @param[in] filename The name of the file to load properties from. - * @return A property set containing the properties from the file. - * @retval NULL If an error occurred (e.g. file not found). - */ -CELIX_UTILS_EXPORT celix_properties_t* celix_properties_load(const char* filename); - -/** - * @brief Load properties from a stream. - * - * If the return status is an error, an error message is logged to celix_err. - * - * @param[in,out] stream The stream to load properties from. - * @return A property set containing the properties from the stream. - * @retval NULL If an error occurred (e.g. invalid format). - */ -CELIX_UTILS_EXPORT celix_properties_t* celix_properties_loadWithStream(FILE* stream); - -/** - * @brief Load properties from a string. - * - * If the return status is an error, an error message is logged to celix_err. - * - * @param[in] input The string to load properties from. - * @return A property set containing the properties from the string. - * @retval NULL If an error occurred (e.g. invalid format). - */ -CELIX_UTILS_EXPORT celix_properties_t* celix_properties_loadFromString(const char* input); - -/** - * @brief Store properties to a file. - * - * @note Properties values are always stored as string values, regardless of their actual underlining types. - * - * If the return status is an error, an error message is logged to celix_err. - * - * @param[in] properties The property set to store. - * @param[in] file The name of the file to store the properties to. - * @param[in] header An optional - single line - header to write to the file before the properties. - * Will be prefix with a '#' character. - * @return CELIX_SUCCESS if the operation was successful, CELIX_FILE_IO_EXCEPTION if there was an error writing to the - * file. - */ -CELIX_UTILS_EXPORT celix_status_t celix_properties_store(celix_properties_t* properties, - const char* file, - const char* header); - /** * @brief Get the entry for a given key in a property set. * diff --git a/libs/utils/src/properties.c b/libs/utils/src/properties.c index 5c8b657e0..53f84fff1 100644 --- a/libs/utils/src/properties.c +++ b/libs/utils/src/properties.c @@ -74,27 +74,6 @@ struct celix_properties { int currentEntriesBufferIndex; }; -#define MALLOC_BLOCK_SIZE 5 - -static celix_status_t celix_properties_parseLine(const char* line, celix_properties_t* props); - -static void -celix_properties_updateBuffers(char** key, char** value, char** output, int outputPos, int* key_len, int* value_len) { - if (*output == *key) { - if (outputPos == (*key_len) - 1) { - (*key_len) += MALLOC_BLOCK_SIZE; - *key = realloc(*key, *key_len); - *output = *key; - } - } else { - if (outputPos == (*value_len) - 1) { - (*value_len) += MALLOC_BLOCK_SIZE; - *value = realloc(*value, *value_len); - *output = *value; - } - } -} - /** * Create a new string from the provided str by either using strdup or storing the string the short properties * optimization string buffer. @@ -347,249 +326,6 @@ void celix_properties_destroy(celix_properties_t* props) { } } -celix_properties_t* celix_properties_load(const char* filename) { - FILE* file = fopen(filename, "r"); - if (file == NULL) { - celix_err_pushf("Cannot open file '%s'", filename); - return NULL; - } - celix_properties_t* props = celix_properties_loadWithStream(file); - fclose(file); - return props; -} - -static celix_status_t celix_properties_parseLine(const char* line, celix_properties_t* props) { - int linePos; - int outputPos; - - bool precedingCharIsBackslash = false; - char* output = NULL; - int key_len = MALLOC_BLOCK_SIZE; - int value_len = MALLOC_BLOCK_SIZE; - linePos = 0; - precedingCharIsBackslash = false; - output = NULL; - outputPos = 0; - - // Ignore empty lines - if (line[0] == '\n' && line[1] == '\0') { - return CELIX_SUCCESS; - } - - celix_autofree char* key = calloc(1, key_len); - celix_autofree char* value = calloc(1, value_len); - if (!key || !value) { - celix_err_pushf("Cannot allocate memory for key or value. Got error %i", errno); - return CELIX_ENOMEM; - } - - key[0] = '\0'; - value[0] = '\0'; - - while (line[linePos] != '\0') { - if (line[linePos] == ' ' || line[linePos] == '\t') { - if (output == NULL) { - // ignore - linePos += 1; - continue; - } - } else { - if (output == NULL) { - output = key; - } - } - if (line[linePos] == '=' || line[linePos] == ':' || line[linePos] == '#' || line[linePos] == '!') { - if (precedingCharIsBackslash) { - // escaped special character - output[outputPos++] = line[linePos]; - celix_properties_updateBuffers(&key, &value, &output, outputPos, &key_len, &value_len); - precedingCharIsBackslash = false; - } else { - if (line[linePos] == '#' || line[linePos] == '!') { - if (outputPos == 0) { - // comment line, ignore - return CELIX_SUCCESS; - } else { - output[outputPos++] = line[linePos]; - celix_properties_updateBuffers(&key, &value, &output, outputPos, &key_len, &value_len); - } - } else { // = or : - if (output == value) { // already have a seperator - output[outputPos++] = line[linePos]; - celix_properties_updateBuffers(&key, &value, &output, outputPos, &key_len, &value_len); - } else { - output[outputPos++] = '\0'; - celix_properties_updateBuffers(&key, &value, &output, outputPos, &key_len, &value_len); - output = value; - outputPos = 0; - } - } - } - } else if (line[linePos] == '\\') { - if (precedingCharIsBackslash) { // double backslash -> backslash - output[outputPos++] = '\\'; - celix_properties_updateBuffers(&key, &value, &output, outputPos, &key_len, &value_len); - } - precedingCharIsBackslash = true; - } else { // normal character - precedingCharIsBackslash = false; - output[outputPos++] = line[linePos]; - celix_properties_updateBuffers(&key, &value, &output, outputPos, &key_len, &value_len); - } - linePos += 1; - } - if (output != NULL) { - output[outputPos] = '\0'; - } - - return celix_properties_set(props, celix_utils_trimInPlace(key), celix_utils_trimInPlace(value)); -} - -celix_properties_t* celix_properties_loadWithStream(FILE* file) { - if (file == NULL) { - return NULL; - } - - - celix_autoptr(celix_properties_t) props = celix_properties_create(); - if (!props) { - return NULL; - } - - int rc = fseek(file, 0, SEEK_END); - if (rc != 0) { - celix_err_pushf("Cannot seek to end of file. Got error %i", errno); - return NULL; - } - - long fileSize = ftell(file); - if (fileSize < 0) { - celix_err_pushf("Cannot get file size. Got error %i", errno); - return NULL; - } - - rc = fseek(file, 0, SEEK_SET); - if (rc != 0) { - celix_err_pushf("Cannot seek to start of file. Got error %i", errno); - return NULL; - } - - celix_autofree char* fileBuffer = malloc(fileSize + 1); - if (fileBuffer == NULL) { - celix_err_pushf("Cannot allocate memory for file buffer. Got error %i", errno); - return NULL; - } - - size_t rs = fread(fileBuffer, sizeof(char), fileSize, file); - if (rs < fileSize) { - celix_err_pushf("fread read only %zu bytes out of %zu\n", rs, fileSize); - return NULL; - } - fileBuffer[fileSize] = '\0'; // ensure a '\0' at the end of the fileBuffer - - char* savePtr = NULL; - char* line = strtok_r(fileBuffer, "\n", &savePtr); - while (line != NULL) { - celix_status_t status = celix_properties_parseLine(line, props); - if (status != CELIX_SUCCESS) { - celix_err_pushf("Failed to parse line '%s'", line); - return NULL; - } - line = strtok_r(NULL, "\n", &savePtr); - } - - return celix_steal_ptr(props); -} - -celix_properties_t* celix_properties_loadFromString(const char* input) { - celix_autoptr(celix_properties_t) props = celix_properties_create(); - celix_autofree char* in = celix_utils_strdup(input); - if (!props || !in) { - celix_err_push("Failed to create properties or duplicate input string"); - return NULL; - } - - char* line = NULL; - char* saveLinePointer = NULL; - line = strtok_r(in, "\n", &saveLinePointer); - while (line != NULL) { - celix_status_t status = celix_properties_parseLine(line, props); - if (status != CELIX_SUCCESS) { - celix_err_pushf("Failed to parse line '%s'", line); - return NULL; - } - line = strtok_r(NULL, "\n", &saveLinePointer); - } - return celix_steal_ptr(props); -} - -/** - * @brief Store properties string to file and escape the characters '#', '!', '=' and ':' if encountered. - */ -static int celix_properties_storeEscapedString(FILE* file, const char* str) { - int rc = 0; - size_t len = strlen(str); - for (size_t i = 0; i < len && rc != EOF; i += 1) { - if (str[i] == '#' || str[i] == '!' || str[i] == '=' || str[i] == ':') { - rc = fputc('\\', file); - if (rc == EOF) { - continue; - } - } - rc = fputc(str[i], file); - } - return rc; -} - -celix_status_t celix_properties_store(celix_properties_t* properties, const char* filename, const char* header) { - FILE* file = fopen(filename, "w+"); - - if (file == NULL) { - celix_err_pushf("Cannot open file '%s'", filename); - return CELIX_FILE_IO_EXCEPTION; - } - - int rc = 0; - - if (header && strstr("\n", header)) { - celix_err_push("Header cannot contain newlines. Ignoring header."); - } else if (header) { - rc = fputc('#', file); - if (rc != EOF) { - rc = fputs(header, file); - } - if (rc != EOF) { - rc = fputc('\n', file); - } - } - - CELIX_PROPERTIES_ITERATE(properties, iter) { - const char* val = iter.entry.value; - if (rc != EOF) { - rc = celix_properties_storeEscapedString(file, iter.key); - } - if (rc != EOF) { - rc = fputc('=', file); - } - if (rc != EOF) { - rc = celix_properties_storeEscapedString(file, val); - } - if (rc != EOF) { - rc = fputc('\n', file); - } - } - if (rc != EOF) { - rc = fclose(file); - } else { - fclose(file); - } - if (rc == EOF) { - celix_err_push("Failed to write properties to file"); - return CELIX_FILE_IO_EXCEPTION; - } - return CELIX_SUCCESS; -} - celix_properties_t* celix_properties_copy(const celix_properties_t* properties) { celix_properties_t* copy = celix_properties_create();
