This is an automated email from the ASF dual-hosted git repository.
pnoltes pushed a commit to branch feature/585-celix-conditions
in repository https://gitbox.apache.org/repos/asf/celix.git
The following commit(s) were added to refs/heads/feature/585-celix-conditions
by this push:
new 908f932b Add error injection tests for fw bundle and factory
908f932b is described below
commit 908f932b8d8b3e232d783434e6e89cd6a5ff2e77
Author: Pepijn Noltes <[email protected]>
AuthorDate: Sat Jul 1 13:41:26 2023 +0200
Add error injection tests for fw bundle and factory
---
libs/framework/gtest/CMakeLists.txt | 7 +-
...onsTestSuite.cc => FrameworkBundleTestSuite.cc} | 52 ++++++--------
.../FrameworkBundleWithErrorInjectionTestSuite.cc | 84 ++++++++++++++++++++++
...ryTestSuite.cc => FrameworkFactoryTestSuite.cc} | 18 ++---
.../FrameworkFactoryWithErrorInjectionTestSuite.cc | 61 ++++++++++++++++
libs/framework/include/celix/Framework.h | 3 +-
libs/framework/include/celix/FrameworkFactory.h | 39 +++++-----
libs/framework/include/celix_framework_factory.h | 5 +-
libs/framework/src/celix_framework_bundle.c | 56 +++++++++------
libs/framework/src/celix_framework_bundle.h | 7 ++
libs/framework/src/celix_framework_factory.c | 22 +++---
libs/framework/src/framework.c | 42 ++++++++---
12 files changed, 297 insertions(+), 99 deletions(-)
diff --git a/libs/framework/gtest/CMakeLists.txt
b/libs/framework/gtest/CMakeLists.txt
index 695053ab..ceac5a3f 100644
--- a/libs/framework/gtest/CMakeLists.txt
+++ b/libs/framework/gtest/CMakeLists.txt
@@ -53,13 +53,13 @@ set(CELIX_FRAMEWORK_TEST_SOURCES
src/DependencyManagerTestSuite.cc
src/CxxBundleContextTestSuite.cc
src/HelloWorldCxxActivator.cc
- src/CxxFrameworkFactoryTestSuite.cc
+ src/FrameworkFactoryTestSuite.cc
src/CxxBundleActivatorTestSuite.cc
src/BundleArchiveTestSuite.cc
src/CelixLauncherTestSuite.cc
src/CelixBundleCacheTestSuite.cc
src/ScheduledEventTestSuite.cc
- src/FrameworkConditionsTestSuite.cc
+ src/FrameworkBundleTestSuite.cc
)
add_executable(test_framework ${CELIX_FRAMEWORK_TEST_SOURCES})
@@ -134,6 +134,8 @@ if (LINKER_WRAP_SUPPORTED)
src/CelixBundleContextBundlesWithErrorTestSuite.cc
src/CelixBundleCacheErrorInjectionTestSuite.cc
src/ScheduledEventWithErrorInjectionTestSuite.cc
+ src/FrameworkBundleWithErrorInjectionTestSuite.cc
+ src/FrameworkFactoryWithErrorInjectionTestSuite.cc
)
target_compile_definitions(test_framework_with_ei PRIVATE
SIMPLE_TEST_BUNDLE1_LOCATION="${SIMPLE_TEST_BUNDLE1}"
@@ -152,6 +154,7 @@ if (LINKER_WRAP_SUPPORTED)
Celix::unistd_ei
Celix::hash_map_ei
Celix::properties_ei
+ Celix::threads_ei
GTest::gtest GTest::gtest_main
)
diff --git a/libs/framework/gtest/src/FrameworkConditionsTestSuite.cc
b/libs/framework/gtest/src/FrameworkBundleTestSuite.cc
similarity index 70%
rename from libs/framework/gtest/src/FrameworkConditionsTestSuite.cc
rename to libs/framework/gtest/src/FrameworkBundleTestSuite.cc
index cb955f99..1eb7c626 100644
--- a/libs/framework/gtest/src/FrameworkConditionsTestSuite.cc
+++ b/libs/framework/gtest/src/FrameworkBundleTestSuite.cc
@@ -23,106 +23,100 @@
#include "celix/FrameworkFactory.h"
#include "celix_condition.h"
-class FrameworkConditionsTestSuite : public ::testing::Test {
+class FrameworkBundleTestSuite : public ::testing::Test {
public:
const int USE_SERVICE_TIMEOUT_IN_MS = 500;
+ const std::string trueFilter = std::string{"("} + CELIX_CONDITION_ID + "="
+ CELIX_CONDITION_ID_TRUE + ")";
+ const std::string readyFilter =
+ std::string{"("} + CELIX_CONDITION_ID + "=" +
CELIX_CONDITION_ID_FRAMEWORK_READY + ")";
+ const std::string errorFilter =
+ std::string{"("} + CELIX_CONDITION_ID + "=" +
CELIX_CONDITION_ID_FRAMEWORK_ERROR + ")";
- FrameworkConditionsTestSuite() = default;
+ FrameworkBundleTestSuite() = default;
};
-TEST_F(FrameworkConditionsTestSuite, ConditionTrueAndFrameworkReadyTest) {
+TEST_F(FrameworkBundleTestSuite, ConditionTrueAndFrameworkReadyTest) {
// Given a Celix framework (with conditions enabled (default))
auto fw = celix::createFramework();
auto ctx = fw->getFrameworkBundleContext();
// Then the condition service with id "true" is available
- auto filter = std::string{"("} + CELIX_CONDITION_ID + "=" +
CELIX_CONDITION_ID_TRUE + ")";
- auto count =
ctx->useService<celix_condition>(CELIX_CONDITION_SERVICE_NAME).setFilter(filter).build();
+ auto count =
ctx->useService<celix_condition>(CELIX_CONDITION_SERVICE_NAME).setFilter(trueFilter).build();
EXPECT_EQ(1, count);
// And the condition service with id "framework.error" will not become
available
- filter = std::string{"("} + CELIX_CONDITION_ID + "=" +
CELIX_CONDITION_ID_FRAMEWORK_ERROR + ")";
count = ctx->useService<celix_condition>(CELIX_CONDITION_SERVICE_NAME)
- .setFilter(filter)
+ .setFilter(errorFilter)
.setTimeout(std::chrono::milliseconds{USE_SERVICE_TIMEOUT_IN_MS})
.build();
EXPECT_EQ(0, count);
// But the condition service with id "framework.ready" will become
available
- filter = std::string{"("} + CELIX_CONDITION_ID + "=" +
CELIX_CONDITION_ID_FRAMEWORK_READY + ")";
count = ctx->useService<celix_condition>(CELIX_CONDITION_SERVICE_NAME)
- .setFilter(filter)
+ .setFilter(readyFilter)
.setTimeout(std::chrono::milliseconds{USE_SERVICE_TIMEOUT_IN_MS})
.build();
EXPECT_EQ(1, count);
}
-TEST_F(FrameworkConditionsTestSuite, ConditionTrueAndFrameworkErrorTest) {
+TEST_F(FrameworkBundleTestSuite, ConditionTrueAndFrameworkErrorTest) {
// Given a Celix framework which is configured to start an invalid bundle
auto fw = celix::createFramework({{celix::AUTO_START_0,
"non-existing-bundle.zip"}});
auto ctx = fw->getFrameworkBundleContext();
// Then the condition service with id "true" is available
- auto filter = std::string{"("} + CELIX_CONDITION_ID + "=" +
CELIX_CONDITION_ID_TRUE + ")";
- auto count =
ctx->useService<celix_condition>(CELIX_CONDITION_SERVICE_NAME).setFilter(filter).build();
+ auto count =
ctx->useService<celix_condition>(CELIX_CONDITION_SERVICE_NAME).setFilter(trueFilter).build();
EXPECT_EQ(1, count);
// And the condition service with id "framework.ready" does not become
available (framework startup error)
- filter = std::string{"("} + CELIX_CONDITION_ID + "=" +
CELIX_CONDITION_ID_FRAMEWORK_READY + ")";
count = ctx->useService<celix_condition>(CELIX_CONDITION_SERVICE_NAME)
- .setFilter(filter)
+ .setFilter(readyFilter)
.setTimeout(std::chrono::milliseconds{USE_SERVICE_TIMEOUT_IN_MS})
.build();
EXPECT_EQ(0, count);
// But the condition service with id "framework.error" will become
available
- filter = std::string{"("} + CELIX_CONDITION_ID + "=" +
CELIX_CONDITION_ID_FRAMEWORK_ERROR + ")";
count = ctx->useService<celix_condition>(CELIX_CONDITION_SERVICE_NAME)
- .setFilter(filter)
+ .setFilter(errorFilter)
.setTimeout(std::chrono::milliseconds{USE_SERVICE_TIMEOUT_IN_MS})
.build();
EXPECT_EQ(1, count);
}
-TEST_F(FrameworkConditionsTestSuite, FrameworkReadyRegisteredLastTest) {
+TEST_F(FrameworkBundleTestSuite, FrameworkReadyRegisteredLastTest) {
// Given a Celix framework which is configured to start a bundle with a
condition test service
auto fw = celix::createFramework({{celix::AUTO_START_0,
COND_TEST_BUNDLE_LOC}});
auto ctx = fw->getFrameworkBundleContext();
// Then the condition service with id "true" is available
- auto filter = std::string{"("} + CELIX_CONDITION_ID + "=" +
CELIX_CONDITION_ID_TRUE + ")";
- auto count =
ctx->useService<celix_condition>(CELIX_CONDITION_SERVICE_NAME).setFilter(filter).build();
+ auto count =
ctx->useService<celix_condition>(CELIX_CONDITION_SERVICE_NAME).setFilter(trueFilter).build();
EXPECT_EQ(1, count);
// And the condition service with id "framework.error" will not become
available
- filter = std::string{"("} + CELIX_CONDITION_ID + "=" +
CELIX_CONDITION_ID_FRAMEWORK_ERROR + ")";
count = ctx->useService<celix_condition>(CELIX_CONDITION_SERVICE_NAME)
- .setFilter(filter)
+ .setFilter(errorFilter)
.setTimeout(std::chrono::milliseconds{USE_SERVICE_TIMEOUT_IN_MS})
.build();
EXPECT_EQ(0, count);
// But the condition service with id "framework.ready" will become
available
- filter = std::string{"("} + CELIX_CONDITION_ID + "=" +
CELIX_CONDITION_ID_FRAMEWORK_READY + ")";
count = ctx->useService<celix_condition>(CELIX_CONDITION_SERVICE_NAME)
- .setFilter(filter)
+ .setFilter(readyFilter)
.setTimeout(std::chrono::milliseconds{USE_SERVICE_TIMEOUT_IN_MS})
.build();
EXPECT_EQ(1, count);
// And the condition service with id "test" is available
- filter = std::string{"("} + CELIX_CONDITION_ID + "=test)";
+ auto testFilter = std::string{"("} + CELIX_CONDITION_ID + "=test)";
count = ctx->useService<celix_condition>(CELIX_CONDITION_SERVICE_NAME)
- .setFilter(filter)
+ .setFilter(testFilter)
.setTimeout(std::chrono::milliseconds{USE_SERVICE_TIMEOUT_IN_MS})
.build();
EXPECT_EQ(1, count);
// And the service.id of the framework.ready condition is higher than the
service.id of the test condition
//(white-box test, framework.ready condition is registered last)
- filter = std::string{"("} + CELIX_CONDITION_ID + "=" +
CELIX_CONDITION_ID_FRAMEWORK_READY + ")";
- long readySvcId = ctx->findServiceWithName(CELIX_CONDITION_SERVICE_NAME,
filter);
- filter = std::string{"("} + CELIX_CONDITION_ID + "=test)";
- long testySvcId = ctx->findServiceWithName(CELIX_CONDITION_SERVICE_NAME,
filter);
+ long readySvcId = ctx->findServiceWithName(CELIX_CONDITION_SERVICE_NAME,
readyFilter);
+ long testySvcId = ctx->findServiceWithName(CELIX_CONDITION_SERVICE_NAME,
testFilter);
EXPECT_GT(readySvcId, testySvcId);
}
diff --git
a/libs/framework/gtest/src/FrameworkBundleWithErrorInjectionTestSuite.cc
b/libs/framework/gtest/src/FrameworkBundleWithErrorInjectionTestSuite.cc
new file mode 100644
index 00000000..3f9f4938
--- /dev/null
+++ b/libs/framework/gtest/src/FrameworkBundleWithErrorInjectionTestSuite.cc
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "celix/FrameworkFactory.h"
+#include "celix_condition.h"
+#include "celix_framework_bundle.h"
+
+#include "celix_properties_ei.h"
+#include "celix_threads_ei.h"
+#include "malloc_ei.h"
+
+class FrameworkBundleWithErrorInjectionTestSuite : public ::testing::Test {
+ public:
+ const int USE_SERVICE_TIMEOUT_IN_MS = 500;
+ const std::string readyFilter =
+ std::string{"("} + CELIX_CONDITION_ID + "=" +
CELIX_CONDITION_ID_FRAMEWORK_READY + ")";
+
+ FrameworkBundleWithErrorInjectionTestSuite() = default;
+
+ ~FrameworkBundleWithErrorInjectionTestSuite() noexcept override {
+ // reset error injections
+ celix_ei_expect_calloc(nullptr, 0, nullptr);
+ celix_ei_expect_celixThreadMutex_create(nullptr, 0, CELIX_SUCCESS);
+ celix_ei_expect_celix_properties_create(nullptr, 0, nullptr);
+ }
+};
+
+TEST_F(FrameworkBundleWithErrorInjectionTestSuite,
ErroCreatingFrameworkBundleTest) {
+ // Wen an error injection for calloc is primed when called from
celix_frameworkBundle_create
+ celix_ei_expect_calloc((void*)celix_frameworkBundle_create, 0, nullptr);
+ ;
+
+ // Then an exception is expected when creating a framework instance
+ EXPECT_ANY_THROW(celix::createFramework());
+
+ // When an error injection for celixThreadMutex_create is primed when
called from celix_frameworkBundle_create
+
celix_ei_expect_celixThreadMutex_create((void*)celix_frameworkBundle_create, 0,
ENOMEM);
+
+ // Then an exception is expected when creating a framework instance
+ EXPECT_ANY_THROW(celix::createFramework());
+}
+
+TEST_F(FrameworkBundleWithErrorInjectionTestSuite,
ErrorStartingFrameworkBundleTest) {
+ // Wen an error injection for celix_properties_create is primed when
called (indirectly) from
+ // celix_frameworkBundle_start
+
celix_ei_expect_celix_properties_create((void*)celix_frameworkBundle_start, 1,
nullptr);
+
+ // Then an exception is expected when creating a framework instance
+ EXPECT_ANY_THROW(celix::createFramework());
+}
+
+TEST_F(FrameworkBundleWithErrorInjectionTestSuite,
ErrorRegisteringFrameworkReadyConditionTest) {
+ // When an error injection for celix_properties_create is primed when
called from celix_frameworkBundle_readyCheck
+
celix_ei_expect_celix_properties_create((void*)celix_frameworkBundle_readyCheck,
0, nullptr);
+
+ // And a framework instance is created
+ auto fw = celix::createFramework();
+ auto ctx = fw->getFrameworkBundleContext();
+
+ // Then the framework.ready condition will not become available, due to an
error creating properties for the service
+ auto count = ctx->useService<celix_condition>(CELIX_CONDITION_SERVICE_NAME)
+ .setFilter(readyFilter)
+ .setTimeout(std::chrono::milliseconds
{USE_SERVICE_TIMEOUT_IN_MS})
+ .build();
+ EXPECT_EQ(count, 0);
+}
diff --git a/libs/framework/gtest/src/CxxFrameworkFactoryTestSuite.cc
b/libs/framework/gtest/src/FrameworkFactoryTestSuite.cc
similarity index 76%
rename from libs/framework/gtest/src/CxxFrameworkFactoryTestSuite.cc
rename to libs/framework/gtest/src/FrameworkFactoryTestSuite.cc
index 04ce44c8..9f7c0204 100644
--- a/libs/framework/gtest/src/CxxFrameworkFactoryTestSuite.cc
+++ b/libs/framework/gtest/src/FrameworkFactoryTestSuite.cc
@@ -23,18 +23,17 @@
#include "celix/FrameworkFactory.h"
-class CxxFrameworkFactoryTestSuite : public ::testing::Test {
+class FrameworkFactoryTestSuite : public ::testing::Test {
public:
- std::shared_ptr<celix::Framework> framework{};
- std::vector<std::shared_ptr<celix::ServiceRegistration>> registrations{};
+ FrameworkFactoryTestSuite() = default;
};
-TEST_F(CxxFrameworkFactoryTestSuite, CreateDestroy) {
- auto fw = celix::createFramework();
- EXPECT_TRUE(fw->getFrameworkBundleContext()->getBundle().isSystemBundle());
+TEST_F(FrameworkFactoryTestSuite, CreateDestroy) {
+ auto framework = celix::createFramework();
+
EXPECT_TRUE(framework->getFrameworkBundleContext()->getBundle().isSystemBundle());
}
-TEST_F(CxxFrameworkFactoryTestSuite, WaitForStop) {
+TEST_F(FrameworkFactoryTestSuite, WaitForStop) {
auto fw = celix::createFramework();
std::future<void> sync;
std::thread wait{[fw] {
@@ -46,9 +45,10 @@ TEST_F(CxxFrameworkFactoryTestSuite, WaitForStop) {
struct cService{};
-TEST_F(CxxFrameworkFactoryTestSuite, DestroyFrameworkAndUnregisterServices) {
- framework = celix::createFramework();
+TEST_F(FrameworkFactoryTestSuite, DestroyFrameworkAndUnregisterServices) {
+ auto framework = celix::createFramework();
auto ctx = framework->getFrameworkBundleContext();
+ std::vector<std::shared_ptr<celix::ServiceRegistration>> registrations{};
for (int i = 0; i < 10; ++i) {
auto reg = ctx->registerService<cService>(std::make_shared<cService>())
.build();
diff --git
a/libs/framework/gtest/src/FrameworkFactoryWithErrorInjectionTestSuite.cc
b/libs/framework/gtest/src/FrameworkFactoryWithErrorInjectionTestSuite.cc
new file mode 100644
index 00000000..d8b4241c
--- /dev/null
+++ b/libs/framework/gtest/src/FrameworkFactoryWithErrorInjectionTestSuite.cc
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "celix/FrameworkFactory.h"
+#include "celix_framework_factory.h"
+
+#include "celix_properties_ei.h"
+#include "malloc_ei.h"
+
+class FrameworkFactoryWithErrorInjectionTestSuite : public ::testing::Test {
+public:
+ FrameworkFactoryWithErrorInjectionTestSuite() = default;
+
+ ~FrameworkFactoryWithErrorInjectionTestSuite() noexcept override {
+ //reset the error injection
+ celix_ei_expect_malloc(nullptr, 0, nullptr);
+ celix_ei_expect_celix_properties_create(nullptr, 0, nullptr);
+ celix_ei_expect_celix_properties_copy(nullptr, 0, nullptr);
+ }
+};
+
+TEST_F(FrameworkFactoryWithErrorInjectionTestSuite,
ErrorCreatingFrameworkTest) {
+ //When an error injection for celix_properties_copy is primed when called
from anywhere
+ celix_ei_expect_celix_properties_copy(CELIX_EI_UNKNOWN_CALLER, 0, nullptr);
+
+ //Then an exception is expected when creating a framework instance
+ EXPECT_ANY_THROW(celix::createFramework());
+
+ //When an error injection for celix_properties_create is primed when
called from
+ //celix_frameworkFactory_createFramework
+
celix_ei_expect_celix_properties_create((void*)celix_frameworkFactory_createFramework,
0, nullptr);
+
+ //Then a nullptr is returned when calling
celix_frameworkFactory_createFramework with a nullptr properties
+ //(note celix::createFramework will always call
celix_frameworkFactory_createFramework with a non-null properties)
+ EXPECT_EQ(nullptr, celix_frameworkFactory_createFramework(nullptr));
+
+ //When an error injection for calloc is primed when called (indirectly)
from celix_frameworkFactory_createFramework
+ celix_ei_expect_calloc((void*)celix_frameworkFactory_createFramework, 1,
nullptr);
+
+ //Then an exception is expected when creating a framework instance
+ EXPECT_ANY_THROW(celix::createFramework());
+}
+
diff --git a/libs/framework/include/celix/Framework.h
b/libs/framework/include/celix/Framework.h
index e0e62eeb..ae86923b 100644
--- a/libs/framework/include/celix/Framework.h
+++ b/libs/framework/include/celix/Framework.h
@@ -20,6 +20,7 @@
#pragma once
#include <memory>
+#include <functional>
#include "celix_framework.h"
@@ -105,7 +106,7 @@ namespace celix {
* @warning Try not the depend on the C API from a C++ bundle. If
features are missing these should be added to
* the C++ API.
*/
- celix_framework_t * getCFramework() const {
+ celix_framework_t* getCFramework() const {
return cFw.get();
}
private:
diff --git a/libs/framework/include/celix/FrameworkFactory.h
b/libs/framework/include/celix/FrameworkFactory.h
index 4f1f3a2e..4872a8b0 100644
--- a/libs/framework/include/celix/FrameworkFactory.h
+++ b/libs/framework/include/celix/FrameworkFactory.h
@@ -22,24 +22,31 @@
#include <memory>
#include "celix/Properties.h"
-#include "celix/BundleContext.h"
#include "celix/Framework.h"
+#include "celix/BundleContext.h"
#include "celix_framework_factory.h"
namespace celix {
- /**
- * @brief Create a new celix Framework instance.
- */
- inline std::shared_ptr<celix::Framework> createFramework(const
celix::Properties& properties = {}) {
- auto* copy = celix_properties_copy(properties.getCProperties());
- auto* cFw= celix_frameworkFactory_createFramework(copy);
- auto fwCtx =
std::make_shared<celix::BundleContext>(celix_framework_getFrameworkContext(cFw));
- std::shared_ptr<celix::Framework> framework{new
celix::Framework{std::move(fwCtx), cFw}, [](celix::Framework* fw) {
- auto* cFw = fw->getCFramework();
- delete fw;
- celix_framework_waitForEmptyEventQueue(cFw);
- celix_frameworkFactory_destroyFramework(cFw);
- }};
- return framework;
+/**
+ * @brief Create a new celix Framework instance.
+ * @throws celix::Exception if the framework could not be created.
+ */
+inline std::shared_ptr<celix::Framework> createFramework(const
celix::Properties& properties = {}) {
+ auto* copy = celix_properties_copy(properties.getCProperties());
+ if (!copy) {
+ throw celix::Exception{"Could not copy properties"};
}
-}
\ No newline at end of file
+
+ auto* cFw = celix_frameworkFactory_createFramework(copy);
+ if (!cFw) {
+ throw celix::Exception{"Could not create framework"};
+ }
+
+ auto fwCtx =
std::make_shared<celix::BundleContext>(celix_framework_getFrameworkContext(cFw));
+ return std::shared_ptr<celix::Framework>{new
celix::Framework{std::move(fwCtx), cFw}, [](celix::Framework* fw) {
+ auto* cFw =
fw->getCFramework();
+ delete fw;
+
celix_frameworkFactory_destroyFramework(cFw);
+ }};
+}
+} // namespace celix
\ No newline at end of file
diff --git a/libs/framework/include/celix_framework_factory.h
b/libs/framework/include/celix_framework_factory.h
index 73b97ae0..bbb69c3d 100644
--- a/libs/framework/include/celix_framework_factory.h
+++ b/libs/framework/include/celix_framework_factory.h
@@ -29,8 +29,9 @@ extern "C" {
/**
* Creates a new framework. The framework will be in the started state.
- * @param config The framework configuration. Can be NULL.
- * @return a started framework or NULL
+ * @param[in] config The framework configuration. Can be NULL. This call will
take ownership of the config and
+ * also destroy it when the call fails.
+ * @return a started framework or NULL. If NULL is returned the framework is
not started.
*/
CELIX_FRAMEWORK_EXPORT celix_framework_t*
celix_frameworkFactory_createFramework(celix_properties_t *config);
diff --git a/libs/framework/src/celix_framework_bundle.c
b/libs/framework/src/celix_framework_bundle.c
index 00e2aecb..65c91b8e 100644
--- a/libs/framework/src/celix_framework_bundle.c
+++ b/libs/framework/src/celix_framework_bundle.c
@@ -62,20 +62,28 @@ static celix_status_t
celix_frameworkBundle_frameworkEvent(void* handle, framewo
celix_status_t celix_frameworkBundle_create(celix_bundle_context_t* ctx,
void** userData) {
*userData = NULL;
celix_framework_bundle_activator_t* act = calloc(1, sizeof(*act));
- if (act) {
- act->ctx = ctx;
- act->trueConditionSvcId = -1L;
- act->listener.handle = act;
- act->listener.frameworkEvent = celix_frameworkBundle_frameworkEvent;
- act->frameworkStartedEventReceived = false;
- act->frameworkErrorEventReceived = false;
- act->frameworkReadyOrErrorConditionSvcId = -1L;
- act->checkFrameworkScheduledEventId = -1L;
- act->conditionInstance.handle = act;
- celixThreadMutex_create(&act->mutex, NULL);
- *userData = act;
+ if (!act) {
+ return ENOMEM;
+ }
+
+ celix_status_t status = celixThreadMutex_create(&act->mutex, NULL);
+ if (status != CELIX_SUCCESS) {
+ free(act);
+ return status;
}
- return act != NULL ? CELIX_SUCCESS : CELIX_ENOMEM;
+
+ act->ctx = ctx;
+ act->trueConditionSvcId = -1L;
+ act->listener.handle = act;
+ act->listener.frameworkEvent = celix_frameworkBundle_frameworkEvent;
+ act->frameworkStartedEventReceived = false;
+ act->frameworkErrorEventReceived = false;
+ act->frameworkReadyOrErrorConditionSvcId = -1L;
+ act->checkFrameworkScheduledEventId = -1L;
+ act->conditionInstance.handle = act;
+ *userData = act;
+
+ return CELIX_SUCCESS;
}
static void
celix_frameworkBundle_registerTrueCondition(celix_framework_bundle_activator_t*
act) {
@@ -92,7 +100,7 @@ static void
celix_frameworkBundle_registerTrueCondition(celix_framework_bundle_a
}
}
-static void celix_frameworkBundle_readyCheck(void* data) {
+void celix_frameworkBundle_readyCheck(void* data) {
celix_framework_bundle_activator_t* act = data;
celixThreadMutex_lock(&act->mutex);
@@ -141,21 +149,25 @@ celix_status_t celix_frameworkBundle_start(void*
userData, celix_bundle_context_
bool conditionsEnabled = celix_bundleContext_getPropertyAsBool(
ctx, CELIX_FRAMEWORK_CONDITION_SERVICES_ENABLED,
CELIX_FRAMEWORK_CONDITION_SERVICES_ENABLED_DEFAULT);
- if (conditionsEnabled) {
- celix_frameworkBundle_registerTrueCondition(act);
- fw_addFrameworkListener(
- celix_bundleContext_getFramework(ctx),
celix_bundleContext_getBundle(ctx), &act->listener);
- celix_frameworkBundle_startReadyCheck(act);
- return act->trueConditionSvcId >= 0 ? CELIX_SUCCESS :
CELIX_BUNDLE_EXCEPTION;
+ if (!conditionsEnabled) {
+ return CELIX_SUCCESS;
}
+ celix_frameworkBundle_registerTrueCondition(act);
+ if (act->trueConditionSvcId < 0) {
+ return CELIX_BUNDLE_EXCEPTION;
+ }
+
+ fw_addFrameworkListener(
+ celix_bundleContext_getFramework(ctx),
celix_bundleContext_getBundle(ctx), &act->listener);
+ celix_frameworkBundle_startReadyCheck(act);
+
return CELIX_SUCCESS;
}
celix_status_t celix_frameworkBundle_stop(void* userData,
celix_bundle_context_t* ctx) {
celix_framework_bundle_activator_t* act = userData;
celix_framework_t* framework = celix_bundleContext_getFramework(ctx);
- celix_status_t status = CELIX_SUCCESS;
// remove framework listener
fw_removeFrameworkListener(framework, celix_bundleContext_getBundle(ctx),
&act->listener);
@@ -179,7 +191,7 @@ celix_status_t celix_frameworkBundle_stop(void* userData,
celix_bundle_context_t
// framework shutdown
celix_framework_shutdownAsync(framework);
- return status;
+ return CELIX_SUCCESS;
}
celix_status_t celix_frameworkBundle_destroy(void* userData,
celix_bundle_context_t* ctx __attribute__((unused))) {
diff --git a/libs/framework/src/celix_framework_bundle.h
b/libs/framework/src/celix_framework_bundle.h
index 29776bc5..5a43cd03 100644
--- a/libs/framework/src/celix_framework_bundle.h
+++ b/libs/framework/src/celix_framework_bundle.h
@@ -47,6 +47,13 @@ celix_status_t celix_frameworkBundle_stop(void* userData,
celix_bundle_context_t
*/
celix_status_t celix_frameworkBundle_destroy(void* userData,
celix_bundle_context_t* ctx);
+/**
+ * @brief The scheduled event callback for the framework bundle bundle ready
check.
+ * @note Part of the header for testing purposes.
+ * @param[in] data The framework bundle bundle activator.
+ */
+void celix_frameworkBundle_readyCheck(void* data);
+
#ifdef __cplusplus
}
#endif
diff --git a/libs/framework/src/celix_framework_factory.c
b/libs/framework/src/celix_framework_factory.c
index f97b8c54..c3b8f95a 100644
--- a/libs/framework/src/celix_framework_factory.c
+++ b/libs/framework/src/celix_framework_factory.c
@@ -27,16 +27,22 @@ framework_t*
celix_frameworkFactory_createFramework(celix_properties_t *config)
config = celix_properties_create();
}
- if (config != NULL) {
- framework_create(&fw, config);
+ if (config == NULL) {
+ return NULL;
}
- if (fw != NULL) {
- celix_status_t rc = framework_start(fw);
- if (rc != CELIX_SUCCESS) {
- framework_destroy(fw);
- fw = NULL;
- }
+
+ celix_status_t status = framework_create(&fw, config);
+ if (status != CELIX_SUCCESS) {
+ celix_properties_destroy(config);
+ return NULL;
}
+
+ status = framework_start(fw);
+ if (status != CELIX_SUCCESS) {
+ framework_destroy(fw);
+ return NULL;
+ }
+
return fw;
}
diff --git a/libs/framework/src/framework.c b/libs/framework/src/framework.c
index d84b2a22..88633507 100644
--- a/libs/framework/src/framework.c
+++ b/libs/framework/src/framework.c
@@ -183,6 +183,7 @@ static celix_status_t
framework_autoInstallConfiguredBundles(celix_framework_t *
static celix_status_t
framework_autoInstallConfiguredBundlesForList(celix_framework_t *fw, const char
*autoStart, celix_array_list_t *installedBundles);
static celix_status_t
framework_autoStartConfiguredBundlesForList(celix_framework_t* fw, const
celix_array_list_t *installedBundles);
static void celix_framework_addToEventQueue(celix_framework_t *fw, const
celix_framework_event_t* event);
+static void celix_framework_stopAndJoinEventQueue(celix_framework_t* fw);
struct fw_bundleListener {
bundle_pt bundle;
@@ -237,6 +238,9 @@ typedef struct fw_frameworkListener *
fw_framework_listener_pt;
celix_status_t framework_create(framework_pt *out, celix_properties_t* config)
{
celix_framework_t* framework = calloc(1, sizeof(*framework));
+ if (!framework) {
+ return ENOMEM;
+ }
celixThreadCondition_init(&framework->shutdown.cond, NULL);
celixThreadMutex_create(&framework->shutdown.mutex, NULL);
@@ -442,9 +446,14 @@ celix_status_t fw_init(framework_pt framework) {
status = CELIX_DO_IF(status,
bundle_setActivator(framework->bundle, activator));
status = CELIX_DO_IF(status, bundle_getContext(framework->bundle,
&validateContext));
status = CELIX_DO_IF(status, activator->create(validateContext,
&activator->userData));
+ bool fwBundleCreated = status == CELIX_SUCCESS;
status = CELIX_DO_IF(status, activator->start(activator->userData,
validateContext));
+
if (status != CELIX_SUCCESS) {
+ if (fwBundleCreated) {
+ activator->destroy(activator->userData, validateContext);
+ }
free(activator);
}
} else {
@@ -453,7 +462,8 @@ celix_status_t fw_init(framework_pt framework) {
}
if (status != CELIX_SUCCESS) {
- fw_logCode(framework->logger, CELIX_LOG_LEVEL_ERROR, status, "Could not
init framework");
+ fw_logCode(framework->logger, CELIX_LOG_LEVEL_ERROR, status, "Could
not init framework");
+ celix_framework_stopAndJoinEventQueue(framework);
}
return status;
@@ -475,6 +485,11 @@ celix_status_t framework_start(celix_framework_t*
framework) {
bundle_setState(framework->bundle, CELIX_BUNDLE_STATE_ACTIVE);
}
+ if (status != CELIX_SUCCESS) {
+ fw_log(framework->logger, CELIX_LOG_LEVEL_ERROR, "Could not initialize
framework");
+ return status;
+ }
+
celix_framework_bundle_entry_t* entry =
celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(framework,
framework->bundleId);
CELIX_DO_IF(status, fw_fireBundleEvent(framework,
OSGI_FRAMEWORK_BUNDLE_EVENT_STARTED, entry));
@@ -482,8 +497,9 @@ celix_status_t framework_start(celix_framework_t*
framework) {
if (status != CELIX_SUCCESS) {
status = CELIX_BUNDLE_EXCEPTION;
- fw_logCode(framework->logger, CELIX_LOG_LEVEL_ERROR, status, "Could
not start framework");
+ fw_logCode(framework->logger, CELIX_LOG_LEVEL_ERROR, status, "Could
not start framework bundle");
fw_fireFrameworkEvent(framework, OSGI_FRAMEWORK_EVENT_ERROR, status);
+ return status;
}
celix_status_t startStatus =
framework_autoStartConfiguredBundles(framework);
@@ -1181,6 +1197,19 @@ celix_status_t framework_waitForStop(framework_pt
framework) {
return CELIX_SUCCESS;
}
+static void celix_framework_stopAndJoinEventQueue(celix_framework_t* fw) {
+ fw_log(fw->logger,
+ CELIX_LOG_LEVEL_TRACE,
+ "Stop and joining event loop thread for framework %s",
+ celix_framework_getUUID(fw));
+ celixThreadMutex_lock(&fw->dispatcher.mutex);
+ fw->dispatcher.active = false;
+ celixThreadCondition_broadcast(&fw->dispatcher.cond);
+ celixThreadMutex_unlock(&fw->dispatcher.mutex);
+ celixThread_join(fw->dispatcher.thread, NULL);
+ fw_log(fw->logger, CELIX_LOG_LEVEL_DEBUG, "Joined event loop thread for
framework %s", celix_framework_getUUID(fw));
+}
+
static void* framework_shutdown(void *framework) {
framework_pt fw = (framework_pt) framework;
@@ -1236,14 +1265,7 @@ static void* framework_shutdown(void *framework) {
celix_framework_bundleEntry_decreaseUseCount(fwEntry);
}
- //join dispatcher thread
- celixThreadMutex_lock(&fw->dispatcher.mutex);
- fw->dispatcher.active = false;
- celixThreadCondition_broadcast(&fw->dispatcher.cond);
- celixThreadMutex_unlock(&fw->dispatcher.mutex);
- celixThread_join(fw->dispatcher.thread, NULL);
- fw_log(fw->logger, CELIX_LOG_LEVEL_TRACE, "Joined event loop thread for
framework %s", celix_framework_getUUID(framework));
-
+ celix_framework_stopAndJoinEventQueue(fw);
celixThreadMutex_lock(&fw->shutdown.mutex);
fw->shutdown.done = true;