You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@celix.apache.org by pn...@apache.org on 2022/05/17 17:04:14 UTC

[celix] 01/05: Adds initial gtest for additional dm cmp states

This is an automated email from the ASF dual-hosted git repository.

pnoltes pushed a commit to branch pnoltes/feature/update_component_and_pattern_documentation
in repository https://gitbox.apache.org/repos/asf/celix.git

commit 35b3ab71a5605e0125902cb83f0bb8ee963ab069
Author: Pepijn Noltes <pn...@apache.org>
AuthorDate: Tue May 17 11:42:24 2022 +0200

    Adds initial gtest for additional dm cmp states
---
 .../gtest/src/DependencyManagerTestSuite.cc        | 116 +++++++++++++++++++++
 libs/framework/src/dm_component_impl.c             |  28 ++---
 2 files changed, 132 insertions(+), 12 deletions(-)

diff --git a/libs/framework/gtest/src/DependencyManagerTestSuite.cc b/libs/framework/gtest/src/DependencyManagerTestSuite.cc
index a07cbde9..a31b2db4 100644
--- a/libs/framework/gtest/src/DependencyManagerTestSuite.cc
+++ b/libs/framework/gtest/src/DependencyManagerTestSuite.cc
@@ -486,6 +486,122 @@ TEST_F(DependencyManagerTestSuite, RequiredDepsAreInjectedDuringStartStop) {
     celix_bundleContext_unregisterService(dm.bundleContext(), svcId);
 }
 
+TEST_F(DependencyManagerTestSuite, IntermediaStatesDuringInitDeinitStartingAndStopping) {
+    class LifecycleComponent {
+    public:
+        enum class InMethod {
+            NO_METHOD,
+            INIT,
+            DEINIT,
+            START,
+            STOP
+        };
+
+        void init() {
+            std::cout << "in init callback\n";
+            std::unique_lock<std::mutex> lck{mutex};
+            inMethod = InMethod::INIT;
+            cond.notify_all();
+            cond.wait_for(lck, std::chrono::seconds{1});
+            inMethod = InMethod::NO_METHOD;
+        }
+
+        void deinit() {
+            std::cout << "in deinit callback\n";
+            std::unique_lock<std::mutex> lck{mutex};
+            inMethod = InMethod::DEINIT;
+            cond.notify_all();
+            cond.wait_for(lck, std::chrono::seconds{1});
+            inMethod = InMethod::NO_METHOD;
+        }
+
+        void start() {
+            std::cout << "in start callback\n";
+            std::unique_lock<std::mutex> lck{mutex};
+            inMethod = InMethod::START;
+            cond.notify_all();
+            cond.wait_for(lck, std::chrono::seconds{1});
+            inMethod = InMethod::NO_METHOD;
+        }
+
+        void stop() {
+            std::cout << "in stop callback\n";
+            std::unique_lock<std::mutex> lck{mutex};
+            inMethod = InMethod::STOP;
+            cond.notify_all();
+            cond.wait_for(lck, std::chrono::seconds{1});
+            inMethod = InMethod::NO_METHOD;
+        }
+
+        void waitFor(InMethod s) {
+            std::unique_lock<std::mutex> lck{mutex};
+            cond.wait_for(lck, std::chrono::seconds{1}, [&]{return inMethod == s;});
+        }
+
+        void cont() {
+            std::lock_guard<std::mutex> lck{mutex};
+            cond.notify_all();
+        }
+
+    private:
+        std::mutex mutex{};
+        std::condition_variable cond{};
+        InMethod inMethod = InMethod::NO_METHOD;
+    };
+
+    celix::dm::DependencyManager dm{ctx};
+    auto lifecycleCmp = std::make_shared<LifecycleComponent>();
+    auto& cmp = dm.createComponent<LifecycleComponent>(lifecycleCmp)
+            .setCallbacks(&LifecycleComponent::init, &LifecycleComponent::start, &LifecycleComponent::stop, &LifecycleComponent::deinit);
+    cmp.createServiceDependency<TestService>()
+            .setRequired(false);
+    cmp.build();
+
+    using celix::dm::ComponentState;
+    lifecycleCmp->waitFor(LifecycleComponent::InMethod::INIT);
+    EXPECT_EQ(cmp.getState(), ComponentState::INITIALIZING);
+    lifecycleCmp->cont();
+
+    lifecycleCmp->waitFor(LifecycleComponent::InMethod::START);
+    EXPECT_EQ(cmp.getState(), ComponentState::STARTING);
+    lifecycleCmp->cont();
+
+    lifecycleCmp->waitFor(LifecycleComponent::InMethod::START);
+    EXPECT_EQ(cmp.getState(), ComponentState::STARTING);
+    lifecycleCmp->cont();
+
+    //Adding service should lead to a suspend/resume (stop/start)
+    TestService svc;
+    std::string svcName = celix::typeName<TestService>();
+    celix_service_registration_options opts{};
+    opts.svc = &svc;
+    opts.serviceName = svcName.c_str();
+    long svcId = celix_bundleContext_registerServiceWithOptions(dm.bundleContext(), &opts);
+    EXPECT_GE(svcId, 0);
+
+    lifecycleCmp->waitFor(LifecycleComponent::InMethod::STOP);
+    EXPECT_EQ(cmp.getState(), ComponentState::SUSPENDING);
+    lifecycleCmp->cont();
+
+    //svc will be injected
+
+    lifecycleCmp->waitFor(LifecycleComponent::InMethod::START);
+    EXPECT_EQ(cmp.getState(), ComponentState::RESUMING);
+    lifecycleCmp->cont();
+
+    //Adding a required svc should lead to INSTANTIATED_AND_WAITING_FOR_REQUIRED
+    cmp.createServiceDependency<TestService>()
+            .setFilter("(non-existing=*)")
+            .setRequired(true)
+            .build();
+
+    lifecycleCmp->waitFor(LifecycleComponent::InMethod::STOP);
+    EXPECT_EQ(cmp.getState(), ComponentState::STOPPING);
+    lifecycleCmp->cont();
+
+    celix_bundleContext_unregisterService(dm.bundleContext(), svcId);
+}
+
 TEST_F(DependencyManagerTestSuite, DepsAreInjectedAsSharedPointers) {
     class LifecycleComponent {
     public:
diff --git a/libs/framework/src/dm_component_impl.c b/libs/framework/src/dm_component_impl.c
index c4544f75..ca213435 100644
--- a/libs/framework/src/dm_component_impl.c
+++ b/libs/framework/src/dm_component_impl.c
@@ -290,7 +290,11 @@ celix_dm_component_state_t component_currentState(celix_dm_component_t *cmp) {
 }
 
 celix_dm_component_state_t celix_dmComponent_currentState(celix_dm_component_t *cmp) {
-    return cmp->state;
+    celix_dm_component_state_t state;
+    celixThreadMutex_lock(&cmp->mutex);
+    state = cmp->state;
+    celixThreadMutex_unlock(&cmp->mutex);
+    return state;
 }
 
 void* component_getImplementation(celix_dm_component_t *cmp) {
@@ -1088,26 +1092,26 @@ bool celix_dmComponent_isActive(celix_dm_component_t *component) {
 const char* celix_dmComponent_stateToString(celix_dm_component_state_t state) {
     switch(state) {
         case CELIX_DM_CMP_STATE_WAITING_FOR_REQUIRED:
-            return "CELIX_DM_CMP_STATE_WAITING_FOR_REQUIRED";
+            return "WAITING_FOR_REQUIRED";
         case CELIX_DM_CMP_STATE_INITIALIZING:
-            return "CELIX_DM_CMP_STATE_INITIALIZING";
+            return "INITIALIZING";
         case CELIX_DM_CMP_STATE_DEINITIALIZING:
-            return "CELIX_DM_CMP_STATE_DEINITIALIZING";
+            return "DEINITIALIZING";
         case CELIX_DM_CMP_STATE_INITIALIZED_AND_WAITING_FOR_REQUIRED:
-            return "CELIX_DM_CMP_STATE_INITIALIZED_AND_WAITING_FOR_REQUIRED";
+            return "INITIALIZED_AND_WAITING_FOR_REQUIRED";
         case CELIX_DM_CMP_STATE_STARTING:
-            return "CELIX_DM_CMP_STATE_STARTING";
+            return "STARTING";
         case CELIX_DM_CMP_STATE_STOPPING:
-            return "CELIX_DM_CMP_STATE_STOPPING";
+            return "STOPPING";
         case CELIX_DM_CMP_STATE_TRACKING_OPTIONAL:
-            return "CELIX_DM_CMP_STATE_TRACKING_OPTIONAL";
+            return "TRACKING_OPTIONAL";
         case CELIX_DM_CMP_STATE_SUSPENDING:
-            return "CELIX_DM_CMP_STATE_SUSPENDING";
+            return "SUSPENDING";
         case CELIX_DM_CMP_STATE_SUSPENDED:
-            return "CELIX_DM_CMP_STATE_SUSPENDED";
+            return "SUSPENDED";
         case CELIX_DM_CMP_STATE_RESUMING:
-            return "CELIX_DM_CMP_STATE_RESUMING";
+            return "RESUMING";
         default: //only CELIX_DM_CMP_STATE_INACTIVE left
-            return "CELIX_DM_CMP_STATE_INACTIVE";
+            return "INACTIVE";
     }
 }