From 58068535d9c2faf95e27a3d30e196931aaa09957 Mon Sep 17 00:00:00 2001 From: RobertPiet <70648461+RobertPiet@users.noreply.github.com> Date: Fri, 30 Oct 2020 15:14:08 +0100 Subject: [PATCH] [EGD-4053] unit tests framework for Settings (#864) [EGD-4053] update queries [EGD-4053] connect Settings, SettingsAgent, SettingsMessages and queries [EGD-4053] change settings interface to async [EGD-4053] mock-logs.cpp commented out -duplicated symbol in linking [EGD-4053] review issues solved --- module-services/service-db/ServiceDB.cpp | 1 - .../service-db/agents/settings/Settings.cpp | 182 ++++----- .../service-db/agents/settings/Settings.hpp | 24 +- .../agents/settings/SettingsAgent.cpp | 359 +++++++++++++++++- .../agents/settings/SettingsAgent.hpp | 49 ++- .../service-db/messages/SettingsMessages.hpp | 5 +- .../service-db/test/CMakeLists.txt | 1 + .../test/test-service-db-settings-api.cpp | 228 ++++++----- .../test-service-db-settings-testapps.hpp | 244 ++++++++++++ .../test-service-db-settings-testmsgs.hpp | 177 +++++++++ .../test-service-db-settings-testservices.hpp | 184 +++++++++ .../workers/settings/settings_queries.hpp | 39 +- test/mock-logs.cpp | 4 +- 13 files changed, 1244 insertions(+), 253 deletions(-) create mode 100644 module-services/service-db/test/test-service-db-settings-testapps.hpp create mode 100644 module-services/service-db/test/test-service-db-settings-testmsgs.hpp create mode 100644 module-services/service-db/test/test-service-db-settings-testservices.hpp diff --git a/module-services/service-db/ServiceDB.cpp b/module-services/service-db/ServiceDB.cpp index 83f9832c6d1756057942fa68062de0c046c2bcec..38ce1d0d5ebf90b48e5de951eed1dabd1b32c1d7 100644 --- a/module-services/service-db/ServiceDB.cpp +++ b/module-services/service-db/ServiceDB.cpp @@ -643,7 +643,6 @@ sys::ReturnCodes ServiceDB::InitHandler() sys::ReturnCodes ServiceDB::DeinitHandler() { - return sys::ReturnCodes::Success; } diff --git a/module-services/service-db/agents/settings/Settings.cpp b/module-services/service-db/agents/settings/Settings.cpp index 2c9a3f8c403d00f968b1dbb9c6e6297009114dc3..3b17fc2874ce01c4a1cf5f176fdaef31a0670319 100644 --- a/module-services/service-db/agents/settings/Settings.cpp +++ b/module-services/service-db/agents/settings/Settings.cpp @@ -33,69 +33,75 @@ namespace Settings sys::Bus::SendUnicast(std::move(msg), dbAgentName, app.get()); } - sys::Message_t Settings::sendMsgAndWaitForResponse(std::shared_ptr<::Settings::Messages::SettingsMessage> &&msg) + void Settings::registerHandlers() { - auto ret = sys::Bus::SendUnicast(std::move(msg), dbAgentName, app.get(), dbWaitTimeMs); - if (ret.first == sys::ReturnCodes::Success) { - return ret.second; + using std::placeholders::_1; + using std::placeholders::_2; + app->connect(::Settings::Messages::VariableChanged(), + std::bind(&Settings::handleVariableChanged, this, _1, _2)); + app->connect(::Settings::Messages::CurrentProfileChanged(), + std::bind(&Settings::handleCurrentProfileChanged, this, _1, _2)); + app->connect(::Settings::Messages::CurrentModeChanged(), + std::bind(&Settings::handleCurrentModeChanged, this, _1, _2)); + app->connect(::Settings::Messages::ProfileListResponse(), + std::bind(&Settings::handleProfileListResponse, this, _1, _2)); + app->connect(::Settings::Messages::ModeListResponse(), + std::bind(&Settings::handleModeListResponse, this, _1, _2)); + } + auto Settings::handleVariableChanged(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t + { + LOG_DEBUG("handleVariableChanged"); + if (auto msg = dynamic_cast<::Settings::Messages::VariableChanged *>(req)) { + auto key = msg->getPath().variable; + auto val = msg->getValue(); + LOG_DEBUG("handleVariableChanged: (k=v): (%s=%s)", key.c_str(), val.value_or("").c_str()); + ValueCb::iterator it_cb = cbValues.find(key); + if (cbValues.end() != it_cb) { + it_cb->second(key, std::move(val)); + return std::make_shared(); + } } - return sys::Message_t{}; + return std::make_shared(); } - - void Settings::registerHandlers() + auto Settings::handleCurrentProfileChanged(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t { - handleValueChgMsg(); - handleProfileChgMsg(); - handleModeChgMsg(); - } - - void Settings::handleValueChgMsg() - { - LOG_DEBUG("handle handleValueChgMsg"); - app->connect(::Settings::Messages::VariableChanged(), [&](sys::DataMessage *req, sys::ResponseMessage *res) { - LOG_DEBUG("handleSettingsValueChgMsg"); - if (auto msg = dynamic_cast<::Settings::Messages::VariableChanged *>(req)) { - auto key = msg->getPath().variable; - auto val = msg->getValue(); - LOG_DEBUG("handleSettingsValueChgMsg: (k=v): (%s=%s)", key.c_str(), val.value_or("").c_str()); - ValueCb::iterator it_cb = cbValues.find(key); - if (cbValues.end() != it_cb) { - it_cb->second(key, std::move(val)); - return std::make_shared(); - } - } - return std::make_shared(); - }); + LOG_DEBUG("handleCurrentProfileChanged"); + if (auto msg = dynamic_cast<::Settings::Messages::CurrentProfileChanged *>(req)) { + auto profile = msg->getProfileName(); + LOG_DEBUG("handleCurrentProfileChanged: %s", profile.c_str()); + cbProfile(profile); + } + return std::make_shared(); } - - void Settings::handleProfileChgMsg() + auto Settings::handleCurrentModeChanged(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t { - LOG_DEBUG("handle handleProfileChgMsg"); - app->connect(::Settings::Messages::CurrentProfileChanged(), - [&](sys::DataMessage *req, [[maybe_unused]] sys::ResponseMessage *res) { - LOG_DEBUG("handleProfileChgMsg"); - if (auto msg = dynamic_cast<::Settings::Messages::CurrentProfileChanged *>(req)) { - auto profile = msg->getProfileName(); - LOG_DEBUG("handleGetProfilesMsg: %s", profile.c_str()); - cbProfile(profile); - } - return std::make_shared(); - }); + LOG_DEBUG("handleCurrentModeChanged"); + if (auto msg = dynamic_cast<::Settings::Messages::CurrentModeChanged *>(req)) { + auto mode = msg->getProfileName(); + LOG_DEBUG("handleCurrentModeChanged: %s", mode.c_str()); + cbMode(mode); + } + return std::make_shared(); } - - void Settings::handleModeChgMsg() + auto Settings::handleProfileListResponse(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t { - LOG_DEBUG("handle handleModeChgMsg"); - app->connect(::Settings::Messages::CurrentModeChanged(), - [&](sys::DataMessage *req, [[maybe_unused]] sys::ResponseMessage *res) { - LOG_DEBUG("handleModeChgMsg"); - if (auto msg = dynamic_cast<::Settings::Messages::CurrentModeChanged *>(req)) { - auto mode = msg->getProfileName(); - LOG_DEBUG("handleModeChgMsg: %s", mode.c_str()); - cbMode(mode); - } - return std::make_shared(); - }); + LOG_DEBUG("handleProfileListResponse"); + if (auto msg = dynamic_cast<::Settings::Messages::ProfileListResponse *>(req)) { + auto profiles = msg->getValue(); + LOG_DEBUG("handleProfileListResponse: %zu elements", profiles.size()); + cbAllProfiles(profiles); + } + return std::make_shared(); + } + auto Settings::handleModeListResponse(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t + { + LOG_DEBUG("handleModeListResponse"); + if (auto msg = dynamic_cast<::Settings::Messages::ModeListResponse *>(req)) { + auto modes = msg->getValue(); + LOG_DEBUG("handleModeListResponse: %zu elements", modes.size()); + cbAllModes(modes); + } + return std::make_shared(); } void Settings::registerValueChange(const std::string &variableName, ValueChangedCallback cb) @@ -129,27 +135,6 @@ namespace Settings sendMsg(std::move(msg)); } - std::optional Settings::getValue(const std::string &variableName) - { - EntryPath path; - path.variable = variableName; - path.service = app->GetName(); - auto msg = std::make_shared<::Settings::Messages::GetVariable>(path); - auto ret = sendMsgAndWaitForResponse(msg); - auto msgVar = dynamic_cast<::Settings::Messages::VariableResponse *>(ret.get()); - if (nullptr != msgVar) { - if (msgVar->getPath() == path.to_string()) { - return msgVar->getValue(); - } - else { - LOG_ERROR("Settings::getValue asked for variable:%s received variable:%s", - variableName.c_str(), - msgVar->getPath().c_str()); - } - } - return std::string{}; - } - void Settings::setValue(const std::string &variableName, const std::string &variableValue) { EntryPath path; @@ -159,24 +144,12 @@ namespace Settings sendMsg(std::move(msg)); } - Settings::ListOfProfiles Settings::getAllProfiles() + void Settings::getAllProfiles(OnAllProfilesRetrievedCallback cb) { - auto ret = sendMsgAndWaitForResponse(std::make_shared<::Settings::Messages::ListProfiles>()); - auto msgProfiles = dynamic_cast<::Settings::Messages::ProfileListResponse *>(ret.get()); - if (nullptr != msgProfiles) { - return msgProfiles->getValue(); + if (nullptr == cbAllProfiles) { + sendMsg(std::make_shared<::Settings::Messages::ListProfiles>()); } - return ListOfProfiles(); - } - - std::string Settings::getCurrentProfile() - { - auto ret = sendMsgAndWaitForResponse(std::make_shared<::Settings::Messages::GetCurrentProfile>()); - auto msgProf = dynamic_cast<::Settings::Messages::ProfileResponse *>(ret.get()); - if (nullptr != msgProf) { - return msgProf->getValue(); - } - return std::string{}; + cbAllProfiles = cb; } void Settings::setCurrentProfile(const std::string &profile) @@ -207,34 +180,27 @@ namespace Settings sendMsg(std::make_shared<::Settings::Messages::UnregisterOnProfileChange>()); } - Settings::ListOfModes Settings::getAllModes() + void Settings::getAllModes(OnAllModesRetrievedCallback cb) { - auto ret = sendMsgAndWaitForResponse(std::make_shared<::Settings::Messages::ListModes>()); - auto msgModes = dynamic_cast<::Settings::Messages::ModeListResponse *>(ret.get()); - if (nullptr != msgModes) { - return msgModes->getValue(); + if (nullptr == cbAllModes) { + sendMsg(std::make_shared<::Settings::Messages::ListModes>()); } - return ListOfModes(); + cbAllModes = cb; } - std::string Settings::getCurrentMode() + void Settings::setCurrentMode(const std::string &mode) { - auto ret = sendMsgAndWaitForResponse(std::make_shared<::Settings::Messages::GetCurrentMode>()); - auto msgMode = dynamic_cast<::Settings::Messages::ModeResponse *>(ret.get()); - if (nullptr != msgMode) { - return msgMode->getValue(); - } - return std::string{}; + sendMsg(std::make_shared<::Settings::Messages::SetCurrentMode>(mode)); } - void Settings::setCurrentMode(const std::string &mode) + void Settings::addMode(const std::string &mode) { - sendMsg(std::make_shared<::Settings::Messages::SetCurrentMode>(mode)); + sendMsg(std::make_shared<::Settings::Messages::AddMode>(mode)); } void Settings::registerModeChange(ModeChangedCallback cb) { - if (nullptr == cbMode) { + if (nullptr != cbMode) { LOG_DEBUG("ModeChange callback allready set overwriting"); } else { diff --git a/module-services/service-db/agents/settings/Settings.hpp b/module-services/service-db/agents/settings/Settings.hpp index e1162f9e5888260d948094265bf49eb5e1833252..251bd5cc9d1868e021701d2ab01cd6fec99ba216 100644 --- a/module-services/service-db/agents/settings/Settings.hpp +++ b/module-services/service-db/agents/settings/Settings.hpp @@ -18,6 +18,8 @@ namespace sys class Message; using Message_t = std::shared_ptr; + class DataMessage; + class ResponseMessage; }; // namespace sys namespace Settings @@ -35,23 +37,23 @@ namespace Settings using ModeChangedCallback = ProfileChangedCallback; using ListOfProfiles = std::list; using ListOfModes = ListOfProfiles; + using OnAllProfilesRetrievedCallback = std::function; + using OnAllModesRetrievedCallback = std::function; Settings(sys::Service *app, const std::string &dbAgentName = service::name::db); virtual ~Settings(); - std::optional getValue(const std::string &variableName); + void setValue(const std::string &variableName, const std::string &variableValue); void registerValueChange(const std::string &variableName, ValueChangedCallback cb); void unregisterValueChange(const std::string &variableName); - ListOfProfiles getAllProfiles(); - std::string getCurrentProfile(); + void getAllProfiles(OnAllProfilesRetrievedCallback cb); void setCurrentProfile(const std::string &profile); void addProfile(const std::string &profile); void registerProfileChange(ProfileChangedCallback); void unregisterProfileChange(); - ListOfModes getAllModes(); - std::string getCurrentMode(); + void getAllModes(OnAllModesRetrievedCallback cb); void setCurrentMode(const std::string &mode); void addMode(const std::string &mode); void registerModeChange(ModeChangedCallback); @@ -59,7 +61,6 @@ namespace Settings private: std::string dbAgentName; - constexpr static int16_t dbWaitTimeMs = 5000; std::shared_ptr app; std::string serviceName; @@ -69,12 +70,15 @@ namespace Settings using ValueCb = std::map; ValueCb cbValues; ModeChangedCallback cbMode; + OnAllModesRetrievedCallback cbAllModes; ProfileChangedCallback cbProfile; + OnAllProfilesRetrievedCallback cbAllProfiles; void sendMsg(std::shared_ptr<::Settings::Messages::SettingsMessage> &&msg); - sys::Message_t sendMsgAndWaitForResponse(std::shared_ptr<::Settings::Messages::SettingsMessage> &&msg); void registerHandlers(); - void handleValueChgMsg(); - void handleProfileChgMsg(); - void handleModeChgMsg(); + auto handleVariableChanged(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t; + auto handleCurrentProfileChanged(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t; + auto handleCurrentModeChanged(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t; + auto handleProfileListResponse(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t; + auto handleModeListResponse(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t; }; } // namespace Settings diff --git a/module-services/service-db/agents/settings/SettingsAgent.cpp b/module-services/service-db/agents/settings/SettingsAgent.cpp index af4705cccf8d564fb4c76982328c2924f785b60b..960aba1ce99ae18096e110ce962ab06cbe7a51eb 100644 --- a/module-services/service-db/agents/settings/SettingsAgent.cpp +++ b/module-services/service-db/agents/settings/SettingsAgent.cpp @@ -13,6 +13,17 @@ #include "Service/Service.hpp" // for Service #include "messages/SettingsMessages.hpp" // for SetVariable, GetVariable, VariableChanged, VariableResponse, EntryPath +#include + +namespace Settings +{ + namespace DbPaths + { + constexpr auto phone_mode = "system/phone_mode"; + constexpr auto phone_profile = "system/phone_profile"; + } // namespace DbPaths +}; // namespace Settings + SettingsAgent::SettingsAgent(sys::Service *parentService) : DatabaseAgent(parentService) { database = std::make_unique(getDbFilePath().c_str()); @@ -22,6 +33,16 @@ void SettingsAgent::initDb() { // LOG_DEBUG("sql:\n--\n%s\n--", getDbInitString().c_str()); database->execute(getDbInitString().c_str()); + auto notifications = database->query(Settings::Statements::getAllNotifications); + if (nullptr == notifications || 0 == notifications->getRowCount()) { + return; + } + do { + variableChangeRecipents[(*notifications)[0].getString()].insert((*notifications)[1].getString()); + /*what about mode/profile + modeChangeRecipents; + profileChangeRecipents;*/ + } while (notifications->nextRow()); } void SettingsAgent::deinitDb() @@ -35,10 +56,39 @@ void SettingsAgent::registerMessages() using std::placeholders::_1; using std::placeholders::_2; + // single variable parentService->connect(Settings::Messages::GetVariable(), std::bind(&SettingsAgent::handleGetVariable, this, _1, _2)); parentService->connect(Settings::Messages::SetVariable(), std::bind(&SettingsAgent::handleSetVariable, this, _1, _2)); + parentService->connect(Settings::Messages::RegisterOnVariableChange(), + std::bind(&SettingsAgent::handleRegisterOnVariableChange, this, _1, _2)); + parentService->connect(Settings::Messages::UnregisterOnVariableChange(), + std::bind(&SettingsAgent::handleUnregisterOnVariableChange, this, _1, _2)); + // profile + parentService->connect(Settings::Messages::RegisterOnProfileChange(), + std::bind(&SettingsAgent::handleRegisterProfileChange, this, _1, _2)); + parentService->connect(Settings::Messages::UnregisterOnProfileChange(), + std::bind(&SettingsAgent::handleUnregisterProfileChange, this, _1, _2)); + parentService->connect(Settings::Messages::SetCurrentProfile(), + std::bind(&SettingsAgent::handleSetCurrentProfile, this, _1, _2)); + parentService->connect(Settings::Messages::GetCurrentProfile(), + std::bind(&SettingsAgent::handleGetCurrentProfile, this, _1, _2)); + parentService->connect(Settings::Messages::AddProfile(), std::bind(&SettingsAgent::handleAddProfile, this, _1, _2)); + parentService->connect(Settings::Messages::ListProfiles(), + std::bind(&SettingsAgent::handleListProfiles, this, _1, _2)); + + // mode + parentService->connect(Settings::Messages::RegisterOnModeChange(), + std::bind(&SettingsAgent::handleRegisterOnModeChange, this, _1, _2)); + parentService->connect(Settings::Messages::UnregisterOnModeChange(), + std::bind(&SettingsAgent::handleUnregisterOnModeChange, this, _1, _2)); + parentService->connect(Settings::Messages::SetCurrentMode(), + std::bind(&SettingsAgent::handleSetCurrentMode, this, _1, _2)); + parentService->connect(Settings::Messages::GetCurrentMode(), + std::bind(&SettingsAgent::handleGetCurrentMode, this, _1, _2)); + parentService->connect(Settings::Messages::AddMode(), std::bind(&SettingsAgent::handleAddMode, this, _1, _2)); + parentService->connect(Settings::Messages::ListModes(), std::bind(&SettingsAgent::handleListModes, this, _1, _2)); } auto SettingsAgent::getDbInitString() -> const std::string @@ -60,17 +110,114 @@ auto SettingsAgent::getAgentName() -> const std::string return std::string("settingsAgent"); } -auto SettingsAgent::getValue(Settings::EntryPath path) -> std::optional +// dbSingleVar +auto SettingsAgent::dbGetValue(Settings::EntryPath path) -> std::optional +{ + // auto retQuery = database->query(Settings::Statements::getValue, path.to_string()); + auto retQuery = database->query(Settings::Statements::getValue, path.variable.c_str()); + if (nullptr == retQuery || 1 != retQuery->getRowCount()) { + return std::string{}; + } + return (*retQuery)[0].getString(); +} + +auto SettingsAgent::dbSetValue(Settings::EntryPath path, std::string value) -> bool +{ + /// insert or update + return database->execute(Settings::Statements::insertValue, path.variable.c_str(), value.c_str()); +} + +auto SettingsAgent::dbRegisterValueChange(Settings::EntryPath path) -> bool +{ + return database->execute(Settings::Statements::setNotification, path.variable.c_str(), path.service.c_str()); +} + +auto SettingsAgent::dbUnregisterValueChange(Settings::EntryPath path) -> bool +{ + return database->execute(Settings::Statements::clearNotificationdRow, path.variable.c_str()); +} + +// db Profile +auto SettingsAgent::dbRegisterOnProfileChange(const std::string &service) -> bool +{ + return database->execute(Settings::Statements::setNotification, Settings::DbPaths::phone_profile, service.c_str()); +} +auto SettingsAgent::dbUnregisterOnProfileChange(const std::string &service) -> bool +{ + return database->execute( + Settings::Statements::clearNotificationdRow, Settings::DbPaths::phone_profile, service.c_str()); +} +auto SettingsAgent::dbSetCurrentProfile(const std::string &profile) -> bool +{ + return database->execute(Settings::Statements::updateValue, profile.c_str(), Settings::DbPaths::phone_profile); +} +auto SettingsAgent::dbGetCurrentProfile() -> std::string +{ + auto qProfile = database->query(Settings::Statements::getValue, Settings::DbPaths::phone_profile); + if (nullptr == qProfile || 1 != qProfile->getRowCount()) { + return std::string{}; + } + return (*qProfile)[0].getString(); +} +auto SettingsAgent::dbGetAllProfiles() -> std::list +{ + auto qProfiles = database->query(Settings::Statements::getDictValue, Settings::DbPaths::phone_profile); + if (nullptr == qProfiles || 0 == qProfiles->getRowCount()) { + return std::list{}; + } + std::list profiles; + do { + profiles.push_back((*qProfiles)[0].getString()); + } while (qProfiles->nextRow()); + return profiles; +} +auto SettingsAgent::dbAddProfile(const std::string &profile) -> bool +{ + return database->execute(Settings::Statements::addDictValue, Settings::DbPaths::phone_profile, profile.c_str()); +} + +// dbMode +auto SettingsAgent::dbRegisterOnModeChange(const std::string &service) -> bool +{ + return database->execute(Settings::Statements::setNotification, Settings::DbPaths::phone_mode, service.c_str()); +} + +auto SettingsAgent::dbUnregisterOnModeChange(const std::string &service) -> bool { - // get value from db from specified path - return ""; + return database->execute( + Settings::Statements::clearNotificationdRow, Settings::DbPaths::phone_mode, service.c_str()); } -auto SettingsAgent::setValue(Settings::EntryPath path, std::string value) -> std::string +auto SettingsAgent::dbSetCurrentMode(const std::string &mode) -> bool { - // set value into db - // return old value - return ""; + return database->execute(Settings::Statements::updateValue, mode.c_str(), Settings::DbPaths::phone_mode); +} + +auto SettingsAgent::dbGetCurrentMode() -> std::string +{ + auto qMode = database->query(Settings::Statements::getValue, Settings::DbPaths::phone_mode); + if (nullptr == qMode || 1 != qMode->getRowCount()) { + return std::string{}; + } + return (*qMode)[0].getString(); +} + +auto SettingsAgent::dbGetAllModes() -> std::list +{ + auto qModes = database->query(Settings::Statements::getDictValue, Settings::DbPaths::phone_profile); + if (nullptr == qModes || 0 == qModes->getRowCount()) { + return std::list{}; + } + std::list modes; + do { + modes.push_back((*qModes)[0].getString()); + } while (qModes->nextRow()); + return modes; +} + +auto SettingsAgent::dbAddMode(const std::string &mode) -> bool +{ + return database->execute(Settings::Statements::addDictValue, Settings::DbPaths::phone_mode, mode.c_str()); } auto SettingsAgent::handleGetVariable(sys::DataMessage *req, sys::ResponseMessage * /*response*/) -> sys::Message_t @@ -78,7 +225,7 @@ auto SettingsAgent::handleGetVariable(sys::DataMessage *req, sys::ResponseMessag if (auto msg = dynamic_cast(req)) { auto path = msg->getPath(); - auto value = getValue(path); + auto value = dbGetValue(path); return std::make_shared(path, value); } @@ -91,10 +238,198 @@ auto SettingsAgent::handleSetVariable(sys::DataMessage *req, sys::ResponseMessag auto path = msg->getPath(); auto value = msg->getValue().value_or(""); - auto oldValue = setValue(path, msg->getValue().value_or("")); - - auto updateMsg = std::make_shared(path, value, oldValue); - sys::Bus::SendUnicast(std::move(updateMsg), "db-worker", parentService); + auto oldValue = dbGetValue(path); + if (oldValue.has_value() && oldValue.value() != value) { + dbSetValue(path, value); + // for (auto service : variableChangeRecipents[path.to_string()]) { + for (auto service : variableChangeRecipents[path.variable]) { + if (service != path.service) { + auto updateMsg = + std::make_shared(path, value, oldValue.value_or("")); + sys::Bus::SendUnicast(std::move(updateMsg), service, parentService); + } + } + } } return std::make_shared(); }; + +auto SettingsAgent::handleRegisterOnVariableChange(sys::DataMessage *req, sys::ResponseMessage * /*response*/) + -> sys::Message_t +{ + if (auto msg = dynamic_cast(req)) { + auto path = msg->getPath(); + if (dbRegisterValueChange(path)) { + auto it = variableChangeRecipents.find(path.to_string()); + if (variableChangeRecipents.end() == it) { + variableChangeRecipents[path.to_string()] = {path.service}; + auto currentValue = dbGetValue(path).value_or(""); + auto msgValue = std::make_shared<::Settings::Messages::VariableChanged>(path, currentValue, ""); + sys::Bus::SendUnicast(std::move(msgValue), msg->sender, parentService); + } + else { + it->second.insert(path.service); + } + } + } + return std::make_shared(); +} + +auto SettingsAgent::handleUnregisterOnVariableChange(sys::DataMessage *req, sys::ResponseMessage * /*response*/) + -> sys::Message_t +{ + if (auto msg = dynamic_cast(req)) { + auto path = msg->getPath(); + if (dbUnregisterValueChange(path)) { + auto it = variableChangeRecipents.find(path.to_string()); + if (variableChangeRecipents.end() != it) { + it->second.erase(path.service); + } + } + } + return std::make_shared(); +} + +// profile +auto SettingsAgent::handleRegisterProfileChange(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t +{ + if (auto msg = dynamic_cast(req)) { + if (dbRegisterOnProfileChange(msg->sender)) { + profileChangedRecipents.insert(msg->sender); + auto msgCurrentProfile = std::make_shared(dbGetCurrentProfile()); + sys::Bus::SendUnicast(std::move(msgCurrentProfile), msg->sender, parentService); + } + } + return std::make_shared(); +} +auto SettingsAgent::handleUnregisterProfileChange(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t +{ + if (auto msg = dynamic_cast(req)) { + if (dbUnregisterOnProfileChange(msg->sender)) { + profileChangedRecipents.erase(msg->sender); + } + } + return std::make_shared(); +} +auto SettingsAgent::handleSetCurrentProfile(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t +{ + if (auto msg = dynamic_cast(req)) { + auto profile = msg->getProfileName(); + if (dbSetCurrentProfile(profile)) { + for (auto service : profileChangedRecipents) { + if (service != msg->sender) { + auto msgProfileChanged = std::make_shared(profile); + sys::Bus::SendUnicast(std::move(msgProfileChanged), service, parentService); + } + } + } + } + return std::make_shared(); +} +auto SettingsAgent::handleGetCurrentProfile(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t +{ + if (nullptr != dynamic_cast(req)) { + auto service = profileChangedRecipents.find(req->sender); + if (profileChangedRecipents.end() != service) { + auto msgCurrentProfile = std::make_shared(dbGetCurrentProfile()); + sys::Bus::SendUnicast(std::move(msgCurrentProfile), *service, parentService); + } + } + return std::make_shared(); +} +auto SettingsAgent::handleAddProfile(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t +{ + if (auto msg = dynamic_cast(req)) { + if (dbAddProfile(msg->getProfileName())) { + auto allProfiles = dbGetAllProfiles(); + for (auto service : profileChangedRecipents) { + if (service != req->sender) { + auto msgAllProfiles = std::make_shared(allProfiles); + sys::Bus::SendUnicast(std::move(msgAllProfiles), service, parentService); + } + } + } + } + return std::make_shared(); +} +auto SettingsAgent::handleListProfiles(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t +{ + if (nullptr != dynamic_cast(req)) { + profileChangedRecipents.insert(req->sender); + auto msgAllProfiles = std::make_shared(dbGetAllProfiles()); + sys::Bus::SendUnicast(std::move(msgAllProfiles), req->sender, parentService); + } + return std::make_shared(); +} + +// mode +auto SettingsAgent::handleRegisterOnModeChange(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t +{ + if (auto msg = dynamic_cast(req)) { + if (dbRegisterOnModeChange(msg->sender)) { + modeChangeRecipents.insert(msg->sender); + auto msgMode = std::make_shared(dbGetCurrentMode()); + sys::Bus::SendUnicast(std::move(msgMode), msg->sender, parentService); + } + } + return std::make_shared(); +} +auto SettingsAgent::handleUnregisterOnModeChange(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t +{ + if (nullptr != dynamic_cast(req)) { + dbUnregisterOnModeChange(req->sender); + modeChangeRecipents.erase(req->sender); + } + return std::make_shared(); +} +auto SettingsAgent::handleSetCurrentMode(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t +{ + if (auto msg = dynamic_cast(req)) { + auto newMode = msg->getProfileName(); + if (dbGetCurrentMode() != newMode) { + if (dbSetCurrentMode(newMode)) { + for (auto service : modeChangeRecipents) { + if (service != msg->sender) { + auto msgModeChanged = std::make_shared(newMode); + sys::Bus::SendUnicast(std::move(msgModeChanged), service, parentService); + } + } + } + } + } + return std::make_shared(); +} +auto SettingsAgent::handleGetCurrentMode(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t +{ + if (nullptr != dynamic_cast(req)) { + if (modeChangeRecipents.end() != modeChangeRecipents.find(req->sender)) { + auto msgMode = std::make_shared(dbGetCurrentMode()); + sys::Bus::SendUnicast(std::move(msgMode), req->sender, parentService); + } + } + return std::make_shared(); +} +auto SettingsAgent::handleAddMode(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t +{ + if (auto msg = dynamic_cast(req)) { + if (dbAddMode(msg->getProfileName())) { + auto allModes = dbGetAllModes(); + for (auto service : modeChangeRecipents) { + if (service != msg->sender) { + auto msgAllModes = std::make_shared(allModes); + sys::Bus::SendUnicast(std::move(msgAllModes), service, parentService); + } + } + } + } + return std::make_shared(); +} +auto SettingsAgent::handleListModes(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t +{ + if (nullptr != dynamic_cast(req)) { + modeChangeRecipents.insert(req->sender); + auto msgAllModes = std::make_shared(dbGetAllModes()); + sys::Bus::SendUnicast(std::move(msgAllModes), req->sender, parentService); + } + return std::make_shared(); +} diff --git a/module-services/service-db/agents/settings/SettingsAgent.hpp b/module-services/service-db/agents/settings/SettingsAgent.hpp index c937355c7065a4df0b4c6976e637b18632c93700..5e2c6a81e7fa786ccaa324ed154b211c397b0030 100644 --- a/module-services/service-db/agents/settings/SettingsAgent.hpp +++ b/module-services/service-db/agents/settings/SettingsAgent.hpp @@ -9,6 +9,7 @@ #include "messages/SettingsMessages.hpp" #include "agents/DatabaseAgent.hpp" // for DatabaseAgent #include "Service/Message.hpp" // for DataMessage (ptr only), Message_t, ResponseMessage (ptr only) +#include namespace Settings { @@ -31,10 +32,54 @@ class SettingsAgent : public DatabaseAgent auto getAgentName() -> const std::string override; private: - auto getValue(Settings::EntryPath path) -> std::optional; - auto setValue(Settings::EntryPath path, std::string value) -> std::string; + using MapOfRecipentsToBeNotified = std::map>; + MapOfRecipentsToBeNotified variableChangeRecipents; + using SetOfRecipents = std::set; + SetOfRecipents profileChangedRecipents; + SetOfRecipents modeChangeRecipents; + // db operations + auto dbGetValue(Settings::EntryPath path) -> std::optional; + auto dbSetValue(Settings::EntryPath path, std::string value) -> bool; + auto dbRegisterValueChange(Settings::EntryPath path) -> bool; + auto dbUnregisterValueChange(Settings::EntryPath path) -> bool; + + auto dbRegisterOnProfileChange(const std::string &service) -> bool; + auto dbUnregisterOnProfileChange(const std::string &service) -> bool; + auto dbSetCurrentProfile(const std::string &profile) -> bool; + auto dbGetCurrentProfile() -> std::string; + auto dbGetAllProfiles() -> std::list; + auto dbAddProfile(const std::string &profile) -> bool; + + auto dbRegisterOnModeChange(const std::string &service) -> bool; + auto dbUnregisterOnModeChange(const std::string &service) -> bool; + auto dbSetCurrentMode(const std::string &mode) -> bool; + auto dbGetCurrentMode() -> std::string; + auto dbGetAllModes() -> std::list; + auto dbAddMode(const std::string &mode) -> bool; + auto getDbInitString() -> const std::string override; auto getDbFilePath() -> const std::string override; + + // msg handlers + // variable auto handleGetVariable(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t; auto handleSetVariable(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t; + auto handleRegisterOnVariableChange(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t; + auto handleUnregisterOnVariableChange(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t; + + // profile + auto handleRegisterProfileChange(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t; + auto handleUnregisterProfileChange(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t; + auto handleSetCurrentProfile(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t; + auto handleGetCurrentProfile(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t; + auto handleAddProfile(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t; + auto handleListProfiles(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t; + + // mode + auto handleRegisterOnModeChange(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t; + auto handleUnregisterOnModeChange(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t; + auto handleSetCurrentMode(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t; + auto handleGetCurrentMode(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t; + auto handleAddMode(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t; + auto handleListModes(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t; }; diff --git a/module-services/service-db/messages/SettingsMessages.hpp b/module-services/service-db/messages/SettingsMessages.hpp index 2fcff6d8ac4732e85220d3bf2385b72e9e4830d0..50be9ae3168209f4d8c384116b63984e16543e85 100644 --- a/module-services/service-db/messages/SettingsMessages.hpp +++ b/module-services/service-db/messages/SettingsMessages.hpp @@ -301,12 +301,11 @@ namespace Settings {} }; - class ListResponse : public sys::ResponseMessage + class ListResponse : public SettingsMessage { public: ListResponse() = default; - explicit ListResponse(std::list value, sys::ReturnCodes code = sys::ReturnCodes::Success) - : sys::ResponseMessage(code), value(std::move(value)) + explicit ListResponse(std::list value) : SettingsMessage(), value(std::move(value)) {} [[nodiscard]] auto getValue() const -> std::list diff --git a/module-services/service-db/test/CMakeLists.txt b/module-services/service-db/test/CMakeLists.txt index 11a448dd4db97b7bb76afb947993af70b522401f..56ceebbfe1f8bb4fda620bf2134326c9f7be9824 100644 --- a/module-services/service-db/test/CMakeLists.txt +++ b/module-services/service-db/test/CMakeLists.txt @@ -11,3 +11,4 @@ add_catch2_executable( module-services module-utils ) + diff --git a/module-services/service-db/test/test-service-db-settings-api.cpp b/module-services/service-db/test/test-service-db-settings-api.cpp index e7ee211dbdaf8a57f65189a184df1f49010d0363..5a1539cb09073b97d138885c46de67a42d5a8f9a 100644 --- a/module-services/service-db/test/test-service-db-settings-api.cpp +++ b/module-services/service-db/test/test-service-db-settings-api.cpp @@ -1,113 +1,137 @@ // Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md -#include // for AssertionHandler, SourceLineInfo, operator""_catch_sr, Section, StringRef, REQUIRE, SECTION, SectionInfo, TEST_CASE -#include // for Service -#include // for _Bind_helper<>::type, _Placeholder, bind, _1, _2 -#include // for operator!=, _Rb_tree_iterator, map<>::iterator, map<>::mapped_type, map -#include // for shared_ptr, allocator, make_shared, operator==, __shared_ptr_access -#include // for optional -#include // for string, operator==, basic_string - -#include "agents/settings/Settings.hpp" // for Settings -#include "messages/SettingsMessages.hpp" // for SetVariable, VariableResponse, GetVariable, EntryPath, VariableChanged -#include "Service/Common.hpp" // for ReturnCodes, ReturnCodes::Success, ServicePowerMode -#include "Service/Mailbox.hpp" // for Mailbox -#include "Service/Message.hpp" // for Message_t, ResponseMessage, DataMessage, Message - -namespace Settings +#include +#include "agents/settings/Settings.hpp" +#include "messages/SettingsMessages.hpp" +#include +#include +#include // for Message_t, ResponseMessage, DataMessage, Message + +#include +#include + +#include +#include + +#include + +#include "test-service-db-settings-testmsgs.hpp" +#include "test-service-db-settings-testservices.hpp" +#include "test-service-db-settings-testapps.hpp" + +struct vfs_initializer { - class MyService : public sys::Service + vfs_initializer() { - public: - MyService(const std::string &name) : sys::Service(name) - {} - using MapStr = std::map; - MapStr vars; - sys::Message_t handGetVar(sys::DataMessage *req, sys::ResponseMessage * /*response*/) - { - if (auto msg = dynamic_cast<::Settings::Messages::GetVariable *>(req)) { - - auto path = msg->getPath(); - if (vars.end() != vars.find(path.variable)) { - return std::make_shared<::Settings::Messages::VariableResponse>(path, vars[path.variable]); - } - - return std::make_shared<::Settings::Messages::VariableResponse>(path, ""); - } - return std::make_shared(); - }; - - sys::Message_t handSetVar(sys::DataMessage *req, sys::ResponseMessage * /*response*/) - { - if (auto msg = dynamic_cast<::Settings::Messages::SetVariable *>(req)) { - - auto path = msg->getPath(); - auto value = msg->getValue().value_or(""); - auto old_value = setVal(path, msg->getValue().value_or("")); - - auto update_msg = std::make_shared<::Settings::Messages::VariableChanged>(path, value, old_value); - } - return std::make_shared(); - }; - std::string setVal(::Settings::EntryPath path, std::string value) - { - // insert into ... - vars[path.variable] = value; - return value; - } - - sys::Message_t DataReceivedHandler(sys::DataMessage *msg, sys::ResponseMessage *resp) - { - return sys::Message_t(); - } - sys::ReturnCodes InitHandler() - { - using std::placeholders::_1; - using std::placeholders::_2; - - connect(::Settings::Messages::GetVariable(), std::bind(&MyService::handGetVar, this, _1, _2)); - connect(::Settings::Messages::SetVariable(), std::bind(&MyService::handSetVar, this, _1, _2)); - return sys::ReturnCodes::Success; - } - sys::ReturnCodes DeinitHandler() - { - return sys::ReturnCodes::Success; - } - sys::ReturnCodes SwitchPowerModeHandler(const sys::ServicePowerMode mode) - { - return sys::ReturnCodes::Success; - } - void ProcessMsgs() - { - isReady = true; - while (1) { - auto msg = mailbox.pop(0); - if (msg == nullptr) { - break; - } - auto ret = msg->Execute(this); - } - } - }; -}; // namespace Settings + vfs.Init(); + } +} vfs_init; + TEST_CASE("SettingsApi") { - SECTION("Create APP") + SECTION("variable/profile/mode register/set/get/unregister") { - Settings::MyService theApp("theApp"); - Settings::Settings setapi(&theApp); - } + std::shared_ptr manager = std::make_shared(5000); + std::shared_ptr varWritter; + std::shared_ptr varReader; + std::shared_ptr testVar; + std::shared_ptr profWritter; + std::shared_ptr profReader; + std::shared_ptr testProf; + std::shared_ptr testStart; + std::shared_ptr modeWritter; + std::shared_ptr modeReader; + std::shared_ptr testMode; - SECTION("set variable") - { - Settings::MyService theApp("theApp"); - theApp.InitHandler(); - Settings::Settings setapi(&theApp, "theApp"); - setapi.setValue("glosnosc", "5"); - theApp.ProcessMsgs(); - REQUIRE(1 == theApp.vars.size()); - REQUIRE(theApp.vars.end() != theApp.vars.find("glosnosc")); - REQUIRE("5" == theApp.vars["glosnosc"]); + manager->StartSystem([manager, + &varWritter, + &varReader, + &testVar, + &profWritter, + &profReader, + &testProf, + &modeWritter, + &modeReader, + &testMode, + &testStart]() { + // preliminary + testStart = std::make_shared(); + testStart->lock(); + std::cout << "start thr_id: " << std::this_thread::get_id() << std::endl << std::flush; + auto ret = sys::SystemManager::CreateService(std::make_shared(service::name::evt_manager), + manager.get()); + ret &= sys::SystemManager::CreateService(std::make_shared(), manager.get()); + + varWritter = std::make_shared("writterVar"); + varReader = std::make_shared("readerVar"); + + ret &= sys::SystemManager::CreateService(varWritter, manager.get()); + ret &= sys::SystemManager::CreateService(varReader, manager.get()); + + testVar = std::make_shared("appTest", varWritter, varReader, testStart); + ret &= sys::SystemManager::CreateService(testVar, manager.get()); + + profWritter = std::make_shared("writterProf"); + profReader = std::make_shared("readerProf"); + + ret &= sys::SystemManager::CreateService(profWritter, manager.get()); + ret &= sys::SystemManager::CreateService(profReader, manager.get()); + + testProf = + std::make_shared("appTestProfile", profWritter, profReader, testStart); + ret &= sys::SystemManager::CreateService(testProf, manager.get()); + + modeWritter = std::make_shared("writterMode"); + modeReader = std::make_shared("readerMode"); + + ret &= sys::SystemManager::CreateService(modeWritter, manager.get()); + ret &= sys::SystemManager::CreateService(modeReader, manager.get()); + + testMode = + std::make_shared("appTestMode", modeWritter, modeReader, testStart); + ret &= sys::SystemManager::CreateService(testMode, manager.get()); + + std::cout << "koniec start thr_id: " << std::this_thread::get_id() << std::endl << std::flush; + testStart->unlock(); + auto msgStart = std::make_shared(); + sys::Bus::SendUnicast(std::move(msgStart), "appTest", manager.get()); + + msgStart = std::make_shared(); + sys::Bus::SendUnicast(std::move(msgStart), "appTestProfile", manager.get()); + + msgStart = std::make_shared(); + sys::Bus::SendUnicast(std::move(msgStart), "appTestMode", manager.get()); + + return ret; + }); + + // start application + cpp_freertos::Thread::StartScheduler(); + + // check the results + std::cout << "testVar values:" << std::endl << std::flush; + for (auto s : testVar->v) + std::cout << s << std::endl << std::flush; + REQUIRE(testVar->v.size() == 3); + REQUIRE(testVar->v[1] == testVar->v[0] + "1"); + REQUIRE(testVar->v[2] == testVar->v[1] + "2"); + + // check the result + std::cout << "testProf values:" << std::endl << std::flush; + for (auto s : testProf->v) + std::cout << s << std::endl << std::flush; + REQUIRE(testProf->v[1] == testProf->v[0] + "1"); + REQUIRE(testProf->v[2] == testProf->v[0] + "12"); + REQUIRE(testProf->v[3] == "other"); + REQUIRE(testProf->v[4] == "other"); + + std::cout << "testMode values:" << std::endl << std::flush; + for (auto s : testMode->v) + std::cout << s << std::endl << std::flush; + REQUIRE(testMode->v[1] == testMode->v[0] + "1"); + REQUIRE(testMode->v[2] == testMode->v[0] + "12"); + REQUIRE(testMode->v[3] == "other"); + REQUIRE(testMode->v[4] == "other"); } } diff --git a/module-services/service-db/test/test-service-db-settings-testapps.hpp b/module-services/service-db/test/test-service-db-settings-testapps.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4a49820d78955d068d369972db0c52d5be690d55 --- /dev/null +++ b/module-services/service-db/test/test-service-db-settings-testapps.hpp @@ -0,0 +1,244 @@ +// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +namespace Settings +{ + class TestService : public sys::Service + { + public: + TestService(const std::string &name) : sys::Service(name) + {} + sys::ReturnCodes InitHandler() override + { + std::cout << "inithandler thr_id: " << std::this_thread::get_id() << std::endl << std::flush; + return sys::ReturnCodes::Success; + } + sys::ReturnCodes DeinitHandler() override + { + std::cout << "deinithandler thr_id: " << std::this_thread::get_id() << std::endl << std::flush; + return sys::ReturnCodes::Success; + } + sys::ReturnCodes SwitchPowerModeHandler(const sys::ServicePowerMode mode) override + { + return sys::ReturnCodes::Success; + } + sys::Message_t DataReceivedHandler(sys::DataMessage *req, sys::ResponseMessage *resp) override + { + return std::make_shared(); + }; + }; + /* @brief AppTest handles async communication between two services (setter and getter) + and simulates synchronous following flow: + 1. getter registers on value changes and gets the startup value of param "brightness" + 2. the setter app sets "brightness" to received in step 1 value + "1" + 3. check if the new value was received by getter + 4. unregister "brightness" on getter + 5. set "brightness" to value+"1"+"2" on setter + 6. wait 200ms and if getter does not provide value change finish + */ + class AppTest : public TestService + { + public: + enum class State : uint8_t + { + Unk, // init + Start, // got start, send register + Register, // got register cnf + RegisterStartVal, // got onchang (v), set (v+1) + RegisterSetVal, // got vcnf (v+1) && got onchange (v+1), send unregister + UnregisterWait, // + Unregister, + RegisterAllWait, + RegisterAll, + RegisterAllAdd, + RegisterAllAddWait, + Stop + }; + std::shared_ptr setter; + std::shared_ptr getter; + std::shared_ptr testStart; + State state; + std::string last_v; + std::vector v; + + AppTest(std::string name, + std::shared_ptr setter, + std::shared_ptr getter, + std::shared_ptr testStart) + : TestService(std::move(name)), setter(std::move(setter)), getter(std::move(getter)), + testStart(std::move(testStart)) + {} + sys::ReturnCodes InitHandler() override + { + state = State::Unk; + return sys::ReturnCodes::Success; + } + sys::ReturnCodes DeinitHandler() override + { + return sys::ReturnCodes::Success; + } + sys::Message_t DataReceivedHandler(sys::DataMessage *msg, sys::ResponseMessage *resp) override + { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + if (nullptr != dynamic_cast<::Settings::UTMsg::UTMsgStart *>(msg)) { + testStart->lock(); + testStart->unlock(); + if (state != State::Unk) { + sys::SystemManager::CloseSystem(this); + } + else { + state = State::Start; + auto msg = std::make_shared<::Settings::UTMsg::ReqRegValChg>("brightness", "none"); + sys::Bus::SendUnicast(std::move(msg), getter->GetName(), this); + } + } + else if (nullptr != dynamic_cast<::Settings::UTMsg::CnfRegValChg *>(msg)) { + if (state == State::Start) { + state = State::Register; + } + } + else if (auto m = dynamic_cast<::Settings::UTMsg::CnfValChg *>(msg)) { + if (state == State::Register) { + state = State::RegisterStartVal; + v.push_back(m->value); + auto msg = std::make_shared<::Settings::UTMsg::ReqSetVal>("brightness", v[0] + "1"); + sys::Bus::SendUnicast(std::move(msg), setter->GetName(), this); + } + else if (state == State::RegisterSetVal) { + if (m->value == v[0] + "1") { + v.push_back(m->value); + auto msg = std::make_shared<::Settings::UTMsg::ReqUnRegValChg>("brightness", "empty"); + sys::Bus::SendUnicast(std::move(msg), getter->GetName(), this); + state = State::UnregisterWait; + } + } + } + else if (nullptr != dynamic_cast<::Settings::UTMsg::CnfUnRegValChg *>(msg)) { + if (state == State::UnregisterWait) { + state = State::Unregister; + auto msg = std::make_shared<::Settings::UTMsg::ReqSetVal>("brightness", v.back() + "2"); + sys::Bus::SendUnicast(std::move(msg), setter->GetName(), this); + } + } + else if (auto m = dynamic_cast<::Settings::UTMsg::CnfReqSetVal *>(msg)) { + if (state == State::RegisterStartVal) { + state = State::RegisterSetVal; + } + else if (state == State::Unregister) { + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + v.push_back(m->value); + auto msg = std::make_shared<::Settings::UTMsg::UTMsgStop>(); + sys::Bus::SendUnicast(std::move(msg), GetName(), this); + } + } + else if (nullptr != dynamic_cast<::Settings::UTMsg::UTMsgStop *>(msg)) { + if (state == State::Unregister) { + sys::SystemManager::CloseSystem(this); + } + } + + return std::make_shared(); + } + }; + + class AppTestProfileMode : public AppTest + { + public: + AppTestProfileMode(const std::string &name, + std::shared_ptr setter, + std::shared_ptr getter, + std::shared_ptr testStart) + : AppTest(name, setter, getter, testStart) + {} + sys::Message_t DataReceivedHandler(sys::DataMessage *msg, sys::ResponseMessage *resp) override + { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + if (nullptr != dynamic_cast<::Settings::UTMsg::UTMsgStart *>(msg)) { + testStart->lock(); + testStart->unlock(); + if (state != State::Unk) { + sys::SystemManager::CloseSystem(this); + } + else { + state = State::Start; + auto msg = std::make_shared<::Settings::UTMsg::ReqRegProfileChg>(); + sys::Bus::SendUnicast(std::move(msg), getter->GetName(), this); + } + } + else if (nullptr != dynamic_cast<::Settings::UTMsg::CnfRegProfileChg *>(msg)) { + if (state == State::Start) { + state = State::Register; + } + } + else if (auto m = dynamic_cast<::Settings::UTMsg::ProfileChg *>(msg)) { + if (state == State::Register) { + state = State::RegisterStartVal; + v.push_back(m->name); + auto msg = std::make_shared<::Settings::UTMsg::ReqSetCurrentProfile>(m->name + "1"); + sys::Bus::SendUnicast(std::move(msg), setter->GetName(), this); + } + else if (state == State::RegisterSetVal) { + if (m->name == v[0] + "1") { + v.push_back(m->name); + auto msg = std::make_shared<::Settings::UTMsg::ReqUnRegProfileChg>(); + sys::Bus::SendUnicast(std::move(msg), getter->GetName(), this); + state = State::UnregisterWait; + } + } + } + else if (nullptr != dynamic_cast<::Settings::UTMsg::CnfUnRegProfileChg *>(msg)) { + if (state == State::UnregisterWait) { + state = State::Unregister; + auto msg = std::make_shared<::Settings::UTMsg::ReqSetCurrentProfile>(v.back() + "2"); + sys::Bus::SendUnicast(std::move(msg), setter->GetName(), this); + } + } + else if (auto m = dynamic_cast<::Settings::UTMsg::CnfSetCurrentProfile *>(msg)) { + if (state == State::RegisterStartVal) { + state = State::RegisterSetVal; + } + else if (state == State::Unregister) { + v.push_back(m->name); + auto msg = std::make_shared<::Settings::UTMsg::ReqGetAllProfiles>(); + sys::Bus::SendUnicast(std::move(msg), getter->GetName(), this); + } + } + else if (nullptr != dynamic_cast<::Settings::UTMsg::CnfGetAllProfiles *>(msg)) { + if (state == State::Unregister) { + state = State::RegisterAllWait; + } + } + else if (auto m = dynamic_cast<::Settings::UTMsg::ProfilesChg *>(msg)) { + if (state == State::RegisterAllWait) { + state = State::RegisterAll; + for (auto prof : m->profiles) { + v.push_back(prof); + } + auto msg = std::make_shared<::Settings::UTMsg::ReqAddProfile>("other"); + sys::Bus::SendUnicast(std::move(msg), setter->GetName(), this); + } + else if (state == State::RegisterAllAddWait) { + state = State::RegisterAllAdd; + for (auto prof : m->profiles) { + v.push_back(prof); + } + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + auto msg = std::make_shared<::Settings::UTMsg::UTMsgStop>(); + sys::Bus::SendUnicast(std::move(msg), GetName(), this); + } + } + else if (nullptr != dynamic_cast<::Settings::UTMsg::CnfAddProfile *>(msg)) { + if (state == State::RegisterAll) { + state = State::RegisterAllAddWait; + } + } + else if (nullptr != dynamic_cast<::Settings::UTMsg::UTMsgStop *>(msg)) { + if (state == State::RegisterAllAdd) { + sys::SystemManager::CloseSystem(this); + } + } + + return std::make_shared(); + } + }; +} // namespace Settings diff --git a/module-services/service-db/test/test-service-db-settings-testmsgs.hpp b/module-services/service-db/test/test-service-db-settings-testmsgs.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4e61b2fde33fe6c4bf4bb8fa4b48fcf4d633e11d --- /dev/null +++ b/module-services/service-db/test/test-service-db-settings-testmsgs.hpp @@ -0,0 +1,177 @@ +// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +namespace Settings +{ + namespace UTMsg + { + class SettingsUTMsg : public ::Settings::Messages::SettingsMessage + { + public: + explicit SettingsUTMsg(MessageType type = MessageType::Settings) + : ::Settings::Messages::SettingsMessage(type){}; + ~SettingsUTMsg() override = default; + }; + + class UTMsgReq : public SettingsUTMsg + { + public: + std::string name, value; + UTMsgReq() = default; + UTMsgReq(std::string name, std::string value) : name(std::move(name)), value(std::move(value)) + {} + }; + class UTMsgCnf : public SettingsUTMsg + { + public: + std::string name, value; + UTMsgCnf() = default; + UTMsgCnf(std::string name, std::string value) : name(std::move(name)), value(std::move(value)) + {} + }; + class UTMsgStart : public SettingsUTMsg + { + public: + UTMsgStart() = default; + }; + class UTMsgStop : public SettingsUTMsg + { + public: + UTMsgStop() = default; + }; + + class ReqRegValChg : public UTMsgReq + { + public: + ReqRegValChg(std::string name, std::string value) : UTMsgReq(std::move(name), std::move(value)) + {} + }; + class ReqUnRegValChg : public UTMsgReq + { + public: + ReqUnRegValChg(std::string name, std::string value) : UTMsgReq(std::move(name), std::move(value)) + {} + }; + class ReqSetVal : public UTMsgReq + { + public: + ReqSetVal(std::string name, std::string value) : UTMsgReq(std::move(name), std::move(value)) + {} + }; + class ReqGetVal : public UTMsgReq + { + public: + ReqGetVal(std::string name, std::string value) : UTMsgReq(std::move(name), std::move(value)) + {} + }; + class CnfRegValChg : public UTMsgCnf + { + public: + CnfRegValChg() = default; + CnfRegValChg(std::string name, std::string value) : UTMsgCnf(std::move(name), std::move(value)) + {} + }; + class CnfUnRegValChg : public UTMsgCnf + { + public: + CnfUnRegValChg() = default; + CnfUnRegValChg(std::string name, std::string value) : UTMsgCnf(std::move(name), std::move(value)) + {} + }; + class CnfReqSetVal : public UTMsgCnf + { + public: + CnfReqSetVal() = default; + CnfReqSetVal(std::string name, std::string value) : UTMsgCnf(std::move(name), std::move(value)) + {} + }; + class CnfReqGetVal : public UTMsgCnf + { + public: + CnfReqGetVal() = default; + CnfReqGetVal(std::string name, std::string value) : UTMsgCnf(std::move(name), std::move(value)) + {} + }; + class CnfValChg : public UTMsgCnf + { + public: + CnfValChg() = default; + CnfValChg(std::string name, std::string value) : UTMsgCnf(std::move(name), std::move(value)) + {} + }; + + class ReqRegProfileChg : public UTMsgReq + { + public: + ReqRegProfileChg() = default; + }; + class ReqUnRegProfileChg : public UTMsgReq + { + public: + ReqUnRegProfileChg() = default; + }; + class ReqSetCurrentProfile : public UTMsgReq + { + public: + ReqSetCurrentProfile(std::string profile) : UTMsgReq(std::move(profile), "") + {} + }; + class ReqGetAllProfiles : public UTMsgReq + { + public: + ReqGetAllProfiles() = default; + }; + class ReqAddProfile : public UTMsgReq + { + public: + ReqAddProfile(std::string profile) : UTMsgReq(std::move(profile), "") + {} + }; + class CnfRegProfileChg : public UTMsgCnf + { + public: + CnfRegProfileChg() = default; + }; + class CnfUnRegProfileChg : public UTMsgCnf + { + public: + CnfUnRegProfileChg() = default; + }; + class CnfSetCurrentProfile : public UTMsgCnf + { + public: + CnfSetCurrentProfile(std::string profile) : UTMsgCnf(std::move(profile), "") + {} + }; + class CnfGetAllProfiles : public UTMsgCnf + { + public: + CnfGetAllProfiles() = default; + }; + class CnfAddProfile : public UTMsgCnf + { + public: + CnfAddProfile(std::string profile) : UTMsgCnf(std::move(profile), "") + {} + }; + class CnfReqProfileChg : public UTMsgCnf + { + public: + CnfReqProfileChg(std::string profile) : UTMsgCnf(std::move(profile), "") + {} + }; + class ProfileChg : public UTMsgCnf + { + public: + ProfileChg(std::string profile) : UTMsgCnf(std::move(profile), "") + {} + }; + class ProfilesChg : public UTMsgCnf + { + public: + std::list profiles; + ProfilesChg(std::list profiles) : UTMsgCnf(), profiles(std::move(profiles)) + {} + }; + }; // namespace UTMsg +} // namespace Settings diff --git a/module-services/service-db/test/test-service-db-settings-testservices.hpp b/module-services/service-db/test/test-service-db-settings-testservices.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a93955889187e7a4a1137fee15e44d19e0bdb7c5 --- /dev/null +++ b/module-services/service-db/test/test-service-db-settings-testservices.hpp @@ -0,0 +1,184 @@ +// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +namespace Settings +{ + class MyService : public sys::Service + { + public: + MyService(const std::string &name) : sys::Service(name) + { + mySettings = std::make_shared<::Settings::Settings>(this); + } + std::shared_ptr<::Settings::Settings> mySettings; + std::vector> valChanged; + std::string whoRequestedNotifyOnChange; + void ValueChanged(const std::string &name, std::optional value) + { + valChanged.emplace_back(std::pair{name, value.value_or("")}); + } + void debug(const std::string &cmd, const std::string &k, const std::string &v) + { + std::cout << "[thr_id:" << std::this_thread::get_id() << ", thr_name:" << GetName() << "] " << cmd + << " [key, val] = (" << k << ", " << v << ")" << std::endl + << std::flush; + } + sys::Message_t DataReceivedHandler(sys::DataMessage *req, sys::ResponseMessage *resp) override + { + if (auto msg = dynamic_cast<::Settings::UTMsg::ReqRegValChg *>(req)) { + debug("ReqRegValChg", msg->name, msg->value); + whoRequestedNotifyOnChange = msg->sender; + mySettings->registerValueChange( + msg->name, ([this](const std::string &name, std::optional value) { + ValueChanged(name, value); + auto cnf = std::make_shared<::Settings::UTMsg::CnfValChg>(name, value.value_or("")); + sys::Bus::SendUnicast(std::move(cnf), whoRequestedNotifyOnChange, this); + })); + auto cnf = std::make_shared<::Settings::UTMsg::CnfRegValChg>(msg->name, msg->value); + sys::Bus::SendUnicast(std::move(cnf), whoRequestedNotifyOnChange, this); + } + else if (auto msg = dynamic_cast<::Settings::UTMsg::ReqUnRegValChg *>(req)) { + // unregister + debug("ReqUnRegValChg", msg->name, msg->value); + mySettings->unregisterValueChange(msg->name); + auto cnf = std::make_shared<::Settings::UTMsg::CnfUnRegValChg>(msg->name, msg->value); + sys::Bus::SendUnicast(std::move(cnf), msg->sender, this); + } + else if (auto msg = dynamic_cast<::Settings::UTMsg::ReqSetVal *>(req)) { + // set value + debug("ReqSetVal", msg->name, msg->value); + mySettings->setValue(msg->name, msg->value); + auto cnf = std::make_shared<::Settings::UTMsg::CnfReqSetVal>(msg->name, msg->value); + sys::Bus::SendUnicast(std::move(cnf), msg->sender, this); + } + else if (dynamic_cast<::Settings::UTMsg::ReqGetVal *>(msg)) { + debug("ReqGetValChg", msg->name, msg->value); + } + return std::make_shared(); + } + sys::ReturnCodes InitHandler() override + { + std::cout << "inithandler thr_id: " << std::this_thread::get_id() << std::endl << std::flush; + return sys::ReturnCodes::Success; + } + sys::ReturnCodes DeinitHandler() override + { + std::cout << "deinithandler thr_id: " << std::this_thread::get_id() << std::endl << std::flush; + return sys::ReturnCodes::Success; + } + sys::ReturnCodes SwitchPowerModeHandler(const sys::ServicePowerMode mode) override + { + return sys::ReturnCodes::Success; + } + }; + + class ServiceProfile : public MyService + { + public: + ServiceProfile(const std::string &name) : MyService(name) + {} + ::Settings::Settings::ListOfProfiles profiles; + std::string profile; + sys::Message_t DataReceivedHandler(sys::DataMessage *req, sys::ResponseMessage *resp) override + { + if (auto msg = dynamic_cast<::Settings::UTMsg::ReqRegProfileChg *>(req)) { + debug("ReqRegProfileChg", msg->name, msg->value); + whoRequestedNotifyOnChange = msg->sender; + mySettings->registerProfileChange(([this](const std::string &profile) { + this->profile = profile; + auto cnf = std::make_shared<::Settings::UTMsg::ProfileChg>(profile); + sys::Bus::SendUnicast(std::move(cnf), whoRequestedNotifyOnChange, this); + })); + auto cnf = std::make_shared<::Settings::UTMsg::CnfRegProfileChg>(); + sys::Bus::SendUnicast(std::move(cnf), whoRequestedNotifyOnChange, this); + } + else if (auto msg = dynamic_cast<::Settings::UTMsg::ReqUnRegProfileChg *>(req)) { + // unregister + debug("ReqUnRegProfileChg", msg->name, msg->value); + mySettings->unregisterProfileChange(); + auto cnf = std::make_shared<::Settings::UTMsg::CnfUnRegProfileChg>(); + sys::Bus::SendUnicast(std::move(cnf), msg->sender, this); + } + else if (auto msg = dynamic_cast<::Settings::UTMsg::ReqSetCurrentProfile *>(req)) { + // set value + debug("ReqSetCurrentProfile", msg->name, msg->value); + mySettings->setCurrentProfile(msg->name); + auto cnf = std::make_shared<::Settings::UTMsg::CnfSetCurrentProfile>(msg->name); + sys::Bus::SendUnicast(std::move(cnf), msg->sender, this); + } + else if (auto msg = dynamic_cast<::Settings::UTMsg::ReqGetAllProfiles *>(req)) { + debug("ReqGetAllProfiles", msg->name, msg->value); + mySettings->getAllProfiles(([this](const ::Settings::Settings::ListOfProfiles &profiles) { + this->profiles = profiles; + auto cnf = std::make_shared<::Settings::UTMsg::ProfilesChg>(profiles); + sys::Bus::SendUnicast(std::move(cnf), whoRequestedNotifyOnChange, this); + })); + auto cnf = std::make_shared<::Settings::UTMsg::CnfGetAllProfiles>(); + sys::Bus::SendUnicast(std::move(cnf), msg->sender, this); + } + else if (auto msg = dynamic_cast<::Settings::UTMsg::ReqAddProfile *>(req)) { + debug("ReqAddProfile", msg->name, msg->value); + mySettings->addProfile(msg->name); + auto cnf = std::make_shared<::Settings::UTMsg::CnfAddProfile>(msg->name); + sys::Bus::SendUnicast(std::move(cnf), msg->sender, this); + } + + return std::make_shared(); + } + }; + + class ServiceMode : public MyService + { + public: + ServiceMode(const std::string &name) : MyService(name) + {} + ::Settings::Settings::ListOfModes modes; + std::string mode; + sys::Message_t DataReceivedHandler(sys::DataMessage *req, sys::ResponseMessage *resp) override + { + if (auto msg = dynamic_cast<::Settings::UTMsg::ReqRegProfileChg *>(req)) { + debug("ReqRegProfileChg", msg->name, msg->value); + whoRequestedNotifyOnChange = msg->sender; + mySettings->registerModeChange(([this](const std::string &mode) { + this->mode = mode; + auto cnf = std::make_shared<::Settings::UTMsg::ProfileChg>(mode); + sys::Bus::SendUnicast(std::move(cnf), whoRequestedNotifyOnChange, this); + })); + auto cnf = std::make_shared<::Settings::UTMsg::CnfRegProfileChg>(); + sys::Bus::SendUnicast(std::move(cnf), whoRequestedNotifyOnChange, this); + } + else if (auto msg = dynamic_cast<::Settings::UTMsg::ReqUnRegProfileChg *>(req)) { + // unregister + debug("ReqUnRegProfileChg", msg->name, msg->value); + mySettings->unregisterModeChange(); + auto cnf = std::make_shared<::Settings::UTMsg::CnfUnRegProfileChg>(); + sys::Bus::SendUnicast(std::move(cnf), msg->sender, this); + } + else if (auto msg = dynamic_cast<::Settings::UTMsg::ReqSetCurrentProfile *>(req)) { + // set value + debug("ReqSetCurrentProfile", msg->name, msg->value); + mySettings->setCurrentMode(msg->name); + auto cnf = std::make_shared<::Settings::UTMsg::CnfSetCurrentProfile>(msg->name); + sys::Bus::SendUnicast(std::move(cnf), msg->sender, this); + } + else if (auto msg = dynamic_cast<::Settings::UTMsg::ReqGetAllProfiles *>(req)) { + debug("ReqGetAllProfiles", msg->name, msg->value); + mySettings->getAllModes(([this](const ::Settings::Settings::ListOfModes &modes) { + this->modes = modes; + auto cnf = std::make_shared<::Settings::UTMsg::ProfilesChg>(modes); + sys::Bus::SendUnicast(std::move(cnf), whoRequestedNotifyOnChange, this); + })); + auto cnf = std::make_shared<::Settings::UTMsg::CnfGetAllProfiles>(); + sys::Bus::SendUnicast(std::move(cnf), msg->sender, this); + } + else if (auto msg = dynamic_cast<::Settings::UTMsg::ReqAddProfile *>(req)) { + debug("ReqAddProfile", msg->name, msg->value); + mySettings->addMode(msg->name); + auto cnf = std::make_shared<::Settings::UTMsg::CnfAddProfile>(msg->name); + sys::Bus::SendUnicast(std::move(cnf), msg->sender, this); + } + + return std::make_shared(); + } + }; +} // namespace Settings diff --git a/module-services/service-db/workers/settings/settings_queries.hpp b/module-services/service-db/workers/settings/settings_queries.hpp index 28ed44e39f2df9a86289d02a314ed441d0230c4a..25f9211f336f14d042fe85a86c1a67c63227c75e 100644 --- a/module-services/service-db/workers/settings/settings_queries.hpp +++ b/module-services/service-db/workers/settings/settings_queries.hpp @@ -10,36 +10,49 @@ namespace Settings::Statements constexpr auto getValue = R"sql( SELECT value FROM settings_tab AS ST - WHERE ST.path = %q + WHERE ST.path = '%q' COLLATE NOCASE; )sql"; constexpr auto checkPathExists = R"sql( SELECT COUNT(value) AS PATH_EXISTS FROM settings_tab AS ST - WHERE ST.path = %q + WHERE ST.path = '%q' COLLATE NOCASE; )sql"; constexpr auto CheckValueExistsInDictionary = R"sql( SELECT COUNT(value) AS VALUE_EXISTS_IN_DICT FROM dictionary_tab AS DT - WHERE DT.path = %q - AND DT.value = %q + WHERE DT.path = '%q' + AND DT.value = '%q' COLLATE NOCASE; )sql"; + constexpr auto getDictValue = R"sql( + SELECT value + FROM dictionary_tab + WHERE path = '%q' + COLLATE NOCASE; + )sql"; + + // no duplicates in dictionary (PK = path + value) + constexpr auto addDictValue = R"sql( + INSERT OR IGNORE INTO dictionary_tab (path, value) + VALUES ( '%q', '%q') + )sql"; + constexpr auto checkSettingModified = R"sql( SELECT COUNT(value) AS DATA_CHANGED FROM settings_tab AS ST - WHERE ST.path = %q - AND ST.value != %q COLLATE NOCASE ; + WHERE ST.path = '%q' + AND ST.value != '%q' COLLATE NOCASE ; )sql"; constexpr auto insertValue = R"sql( INSERT OR REPLACE INTO settings_tab (path, value) VALUES - ( %q, %q ) ; + ( '%q', '%q' ) ; )sql"; constexpr auto updateValue = R"sql( - UPDATE settings_tab SET value = %q WHERE path = %q ; + UPDATE settings_tab SET value = '%q' WHERE path = '%q' ; )sql"; constexpr auto clearSettingsChangedTable = R"sql( @@ -48,7 +61,7 @@ namespace Settings::Statements constexpr auto clearSettingsChangedRow = R"sql( DELETE FROM settings_changed_tab - WHERE path = %q ; + WHERE path = '%q' ; )sql"; constexpr auto getSettingsChangeTable = R"sql( @@ -58,13 +71,13 @@ namespace Settings::Statements constexpr auto getSettingsChangeRow = R"sql( SELECT path, value FROM settings_changed_tab - WHERE path = %q + WHERE path = '%q' COLLATE NOCASE; )sql"; constexpr auto setNotification = R"sql( - INSERT OR REPLACE INTO notifications_tab (path, service) VALUES " - ( %q , %q ) ; + INSERT OR REPLACE INTO notifications_tab (path, service) VALUES + ( '%q' , '%q' ) ; )sql"; constexpr auto getAllNotifications = R"sql( @@ -78,7 +91,7 @@ namespace Settings::Statements constexpr auto clearNotificationdRow = R"sql( DELETE FROM notifications_tab - WHERE path = %q ; + WHERE path = '%q' AND service = '%q'; )sql"; } // namespace Settings::Statements diff --git a/test/mock-logs.cpp b/test/mock-logs.cpp index fbcf08b3752d5f58ab46fd684a3e07a747136b40..cc2f74e0e6fdeb3cfcdc0c90ec74e84d86f99ad5 100644 --- a/test/mock-logs.cpp +++ b/test/mock-logs.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md -#include +/*#include #include __attribute__((weak)) void log_Log( logger_level level, const char *file, int line, const char *function, const char *fmt, ...) @@ -9,4 +9,4 @@ __attribute__((weak)) void log_Log( va_list args; va_start(args, fmt); va_end(args); -} +}*/