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 <[email protected]> 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"; } }
