~aleteoryx/muditaos

58068535d9c2faf95e27a3d30e196931aaa09957 — RobertPiet 5 years ago e4fcc83
[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
M module-services/service-db/ServiceDB.cpp => module-services/service-db/ServiceDB.cpp +0 -1
@@ 643,7 643,6 @@ sys::ReturnCodes ServiceDB::InitHandler()

sys::ReturnCodes ServiceDB::DeinitHandler()
{

    return sys::ReturnCodes::Success;
}


M module-services/service-db/agents/settings/Settings.cpp => module-services/service-db/agents/settings/Settings.cpp +74 -108
@@ 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<sys::ResponseMessage>();
            }
        }
        return sys::Message_t{};
        return std::make_shared<sys::ResponseMessage>();
    }

    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<sys::ResponseMessage>();
                }
            }
            return std::make_shared<sys::ResponseMessage>();
        });
        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<sys::ResponseMessage>();
    }

    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<sys::ResponseMessage>();
                     });
        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<sys::ResponseMessage>();
    }

    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<sys::ResponseMessage>();
                     });
        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<sys::ResponseMessage>();
    }
    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<sys::ResponseMessage>();
    }

    void Settings::registerValueChange(const std::string &variableName, ValueChangedCallback cb)


@@ 129,27 135,6 @@ namespace Settings
        sendMsg(std::move(msg));
    }

    std::optional<std::string> 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 {

M module-services/service-db/agents/settings/Settings.hpp => module-services/service-db/agents/settings/Settings.hpp +14 -10
@@ 18,6 18,8 @@ namespace sys
    class Message;

    using Message_t = std::shared_ptr<Message>;
    class DataMessage;
    class ResponseMessage;
}; // namespace sys

namespace Settings


@@ 35,23 37,23 @@ namespace Settings
        using ModeChangedCallback    = ProfileChangedCallback;
        using ListOfProfiles         = std::list<std::string>;
        using ListOfModes            = ListOfProfiles;
        using OnAllProfilesRetrievedCallback = std::function<void(const ListOfProfiles &)>;
        using OnAllModesRetrievedCallback    = std::function<void(const ListOfModes &)>;

        Settings(sys::Service *app, const std::string &dbAgentName = service::name::db);
        virtual ~Settings();
        std::optional<std::string> 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<sys::Service> app;
        std::string serviceName;


@@ 69,12 70,15 @@ namespace Settings
        using ValueCb = std::map<std::string, ValueChangedCallback>;
        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

M module-services/service-db/agents/settings/SettingsAgent.cpp => module-services/service-db/agents/settings/SettingsAgent.cpp +347 -12
@@ 13,6 13,17 @@
#include "Service/Service.hpp"           // for Service
#include "messages/SettingsMessages.hpp" // for SetVariable, GetVariable, VariableChanged, VariableResponse, EntryPath

#include <module-services/service-db/workers/settings/settings_queries.hpp>

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<Database>(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<std::string>
// dbSingleVar
auto SettingsAgent::dbGetValue(Settings::EntryPath path) -> std::optional<std::string>
{
    // 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<std::string>
{
    auto qProfiles = database->query(Settings::Statements::getDictValue, Settings::DbPaths::phone_profile);
    if (nullptr == qProfiles || 0 == qProfiles->getRowCount()) {
        return std::list<std::string>{};
    }
    std::list<std::string> 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<std::string>
{
    auto qModes = database->query(Settings::Statements::getDictValue, Settings::DbPaths::phone_profile);
    if (nullptr == qModes || 0 == qModes->getRowCount()) {
        return std::list<std::string>{};
    }
    std::list<std::string> 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<Settings::Messages::GetVariable *>(req)) {

        auto path  = msg->getPath();
        auto value = getValue(path);
        auto value = dbGetValue(path);

        return std::make_shared<Settings::Messages::VariableResponse>(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<Settings::Messages::VariableChanged>(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<Settings::Messages::VariableChanged>(path, value, oldValue.value_or(""));
                    sys::Bus::SendUnicast(std::move(updateMsg), service, parentService);
                }
            }
        }
    }
    return std::make_shared<sys::ResponseMessage>();
};

auto SettingsAgent::handleRegisterOnVariableChange(sys::DataMessage *req, sys::ResponseMessage * /*response*/)
    -> sys::Message_t
{
    if (auto msg = dynamic_cast<Settings::Messages::RegisterOnVariableChange *>(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<sys::ResponseMessage>();
}

auto SettingsAgent::handleUnregisterOnVariableChange(sys::DataMessage *req, sys::ResponseMessage * /*response*/)
    -> sys::Message_t
{
    if (auto msg = dynamic_cast<Settings::Messages::UnregisterOnVariableChange *>(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<sys::ResponseMessage>();
}

// profile
auto SettingsAgent::handleRegisterProfileChange(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t
{
    if (auto msg = dynamic_cast<Settings::Messages::RegisterOnProfileChange *>(req)) {
        if (dbRegisterOnProfileChange(msg->sender)) {
            profileChangedRecipents.insert(msg->sender);
            auto msgCurrentProfile = std::make_shared<Settings::Messages::CurrentProfileChanged>(dbGetCurrentProfile());
            sys::Bus::SendUnicast(std::move(msgCurrentProfile), msg->sender, parentService);
        }
    }
    return std::make_shared<sys::ResponseMessage>();
}
auto SettingsAgent::handleUnregisterProfileChange(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t
{
    if (auto msg = dynamic_cast<Settings::Messages::UnregisterOnProfileChange *>(req)) {
        if (dbUnregisterOnProfileChange(msg->sender)) {
            profileChangedRecipents.erase(msg->sender);
        }
    }
    return std::make_shared<sys::ResponseMessage>();
}
auto SettingsAgent::handleSetCurrentProfile(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t
{
    if (auto msg = dynamic_cast<Settings::Messages::SetCurrentProfile *>(req)) {
        auto profile = msg->getProfileName();
        if (dbSetCurrentProfile(profile)) {
            for (auto service : profileChangedRecipents) {
                if (service != msg->sender) {
                    auto msgProfileChanged = std::make_shared<Settings::Messages::CurrentProfileChanged>(profile);
                    sys::Bus::SendUnicast(std::move(msgProfileChanged), service, parentService);
                }
            }
        }
    }
    return std::make_shared<sys::ResponseMessage>();
}
auto SettingsAgent::handleGetCurrentProfile(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t
{
    if (nullptr != dynamic_cast<Settings::Messages::GetCurrentProfile *>(req)) {
        auto service = profileChangedRecipents.find(req->sender);
        if (profileChangedRecipents.end() != service) {
            auto msgCurrentProfile = std::make_shared<Settings::Messages::CurrentProfileChanged>(dbGetCurrentProfile());
            sys::Bus::SendUnicast(std::move(msgCurrentProfile), *service, parentService);
        }
    }
    return std::make_shared<sys::ResponseMessage>();
}
auto SettingsAgent::handleAddProfile(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t
{
    if (auto msg = dynamic_cast<Settings::Messages::AddProfile *>(req)) {
        if (dbAddProfile(msg->getProfileName())) {
            auto allProfiles = dbGetAllProfiles();
            for (auto service : profileChangedRecipents) {
                if (service != req->sender) {
                    auto msgAllProfiles = std::make_shared<Settings::Messages::ProfileListResponse>(allProfiles);
                    sys::Bus::SendUnicast(std::move(msgAllProfiles), service, parentService);
                }
            }
        }
    }
    return std::make_shared<sys::ResponseMessage>();
}
auto SettingsAgent::handleListProfiles(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t
{
    if (nullptr != dynamic_cast<Settings::Messages::ListProfiles *>(req)) {
        profileChangedRecipents.insert(req->sender);
        auto msgAllProfiles = std::make_shared<Settings::Messages::ProfileListResponse>(dbGetAllProfiles());
        sys::Bus::SendUnicast(std::move(msgAllProfiles), req->sender, parentService);
    }
    return std::make_shared<sys::ResponseMessage>();
}

// mode
auto SettingsAgent::handleRegisterOnModeChange(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t
{
    if (auto msg = dynamic_cast<Settings::Messages::RegisterOnModeChange *>(req)) {
        if (dbRegisterOnModeChange(msg->sender)) {
            modeChangeRecipents.insert(msg->sender);
            auto msgMode = std::make_shared<Settings::Messages::CurrentModeChanged>(dbGetCurrentMode());
            sys::Bus::SendUnicast(std::move(msgMode), msg->sender, parentService);
        }
    }
    return std::make_shared<sys::ResponseMessage>();
}
auto SettingsAgent::handleUnregisterOnModeChange(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t
{
    if (nullptr != dynamic_cast<Settings::Messages::UnregisterOnModeChange *>(req)) {
        dbUnregisterOnModeChange(req->sender);
        modeChangeRecipents.erase(req->sender);
    }
    return std::make_shared<sys::ResponseMessage>();
}
auto SettingsAgent::handleSetCurrentMode(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t
{
    if (auto msg = dynamic_cast<Settings::Messages::SetCurrentMode *>(req)) {
        auto newMode = msg->getProfileName();
        if (dbGetCurrentMode() != newMode) {
            if (dbSetCurrentMode(newMode)) {
                for (auto service : modeChangeRecipents) {
                    if (service != msg->sender) {
                        auto msgModeChanged = std::make_shared<Settings::Messages::CurrentModeChanged>(newMode);
                        sys::Bus::SendUnicast(std::move(msgModeChanged), service, parentService);
                    }
                }
            }
        }
    }
    return std::make_shared<sys::ResponseMessage>();
}
auto SettingsAgent::handleGetCurrentMode(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t
{
    if (nullptr != dynamic_cast<Settings::Messages::GetCurrentMode *>(req)) {
        if (modeChangeRecipents.end() != modeChangeRecipents.find(req->sender)) {
            auto msgMode = std::make_shared<Settings::Messages::CurrentModeChanged>(dbGetCurrentMode());
            sys::Bus::SendUnicast(std::move(msgMode), req->sender, parentService);
        }
    }
    return std::make_shared<sys::ResponseMessage>();
}
auto SettingsAgent::handleAddMode(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t
{
    if (auto msg = dynamic_cast<Settings::Messages::AddMode *>(req)) {
        if (dbAddMode(msg->getProfileName())) {
            auto allModes = dbGetAllModes();
            for (auto service : modeChangeRecipents) {
                if (service != msg->sender) {
                    auto msgAllModes = std::make_shared<Settings::Messages::ModeListResponse>(allModes);
                    sys::Bus::SendUnicast(std::move(msgAllModes), service, parentService);
                }
            }
        }
    }
    return std::make_shared<sys::ResponseMessage>();
}
auto SettingsAgent::handleListModes(sys::DataMessage *req, sys::ResponseMessage *) -> sys::Message_t
{
    if (nullptr != dynamic_cast<Settings::Messages::ListModes *>(req)) {
        modeChangeRecipents.insert(req->sender);
        auto msgAllModes = std::make_shared<Settings::Messages::ModeListResponse>(dbGetAllModes());
        sys::Bus::SendUnicast(std::move(msgAllModes), req->sender, parentService);
    }
    return std::make_shared<sys::ResponseMessage>();
}

M module-services/service-db/agents/settings/SettingsAgent.hpp => module-services/service-db/agents/settings/SettingsAgent.hpp +47 -2
@@ 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 <map>

namespace Settings
{


@@ 31,10 32,54 @@ class SettingsAgent : public DatabaseAgent
    auto getAgentName() -> const std::string override;

  private:
    auto getValue(Settings::EntryPath path) -> std::optional<std::string>;
    auto setValue(Settings::EntryPath path, std::string value) -> std::string;
    using MapOfRecipentsToBeNotified = std::map<std::string, std::set<std::string>>;
    MapOfRecipentsToBeNotified variableChangeRecipents;
    using SetOfRecipents = std::set<std::string>;
    SetOfRecipents profileChangedRecipents;
    SetOfRecipents modeChangeRecipents;
    // db operations
    auto dbGetValue(Settings::EntryPath path) -> std::optional<std::string>;
    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<std::string>;
    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<std::string>;
    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;
};

M module-services/service-db/messages/SettingsMessages.hpp => module-services/service-db/messages/SettingsMessages.hpp +2 -3
@@ 301,12 301,11 @@ namespace Settings
            {}
        };

        class ListResponse : public sys::ResponseMessage
        class ListResponse : public SettingsMessage
        {
          public:
            ListResponse() = default;
            explicit ListResponse(std::list<std::string> value, sys::ReturnCodes code = sys::ReturnCodes::Success)
                : sys::ResponseMessage(code), value(std::move(value))
            explicit ListResponse(std::list<std::string> value) : SettingsMessage(), value(std::move(value))
            {}

            [[nodiscard]] auto getValue() const -> std::list<std::string>

M module-services/service-db/test/CMakeLists.txt => module-services/service-db/test/CMakeLists.txt +1 -0
@@ 11,3 11,4 @@ add_catch2_executable(
                module-services
                module-utils
)


M module-services/service-db/test/test-service-db-settings-api.cpp => module-services/service-db/test/test-service-db-settings-api.cpp +126 -102
@@ 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 <catch2/catch.hpp> // for AssertionHandler, SourceLineInfo, operator""_catch_sr, Section, StringRef, REQUIRE, SECTION, SectionInfo, TEST_CASE
#include <Service/Service.hpp> // for Service
#include <functional>          // for _Bind_helper<>::type, _Placeholder, bind, _1, _2
#include <map>                 // for operator!=, _Rb_tree_iterator, map<>::iterator, map<>::mapped_type, map
#include <memory>              // for shared_ptr, allocator, make_shared, operator==, __shared_ptr_access
#include <optional>            // for optional
#include <string>              // 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 <catch2/catch.hpp>
#include "agents/settings/Settings.hpp"
#include "messages/SettingsMessages.hpp"
#include <Service/Service.hpp>
#include <functional>
#include <thread> // for Message_t, ResponseMessage, DataMessage, Message

#include <module-services/service-db/ServiceDB.hpp>
#include <module-sys/SystemManager/SystemManager.hpp>

#include <module-services/service-evtmgr/EventManager.hpp>
#include <module-services/service-evtmgr/Constants.hpp>

#include <module-services/service-fota/api/FotaServiceAPI.cpp>

#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<std::string, std::string>;
        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::ResponseMessage>();
        };

        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<sys::ResponseMessage>();
        };
        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<sys::SystemManager> manager = std::make_shared<sys::SystemManager>(5000);
        std::shared_ptr<Settings::MyService> varWritter;
        std::shared_ptr<Settings::MyService> varReader;
        std::shared_ptr<Settings::AppTest> testVar;
        std::shared_ptr<Settings::ServiceProfile> profWritter;
        std::shared_ptr<Settings::ServiceProfile> profReader;
        std::shared_ptr<Settings::AppTestProfileMode> testProf;
        std::shared_ptr<std::mutex> testStart;
        std::shared_ptr<Settings::ServiceMode> modeWritter;
        std::shared_ptr<Settings::ServiceMode> modeReader;
        std::shared_ptr<Settings::AppTestProfileMode> 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<std::mutex>();
            testStart->lock();
            std::cout << "start thr_id: " << std::this_thread::get_id() << std::endl << std::flush;
            auto ret = sys::SystemManager::CreateService(std::make_shared<EventManager>(service::name::evt_manager),
                                                         manager.get());
            ret &= sys::SystemManager::CreateService(std::make_shared<ServiceDB>(), manager.get());

            varWritter = std::make_shared<Settings::MyService>("writterVar");
            varReader  = std::make_shared<Settings::MyService>("readerVar");

            ret &= sys::SystemManager::CreateService(varWritter, manager.get());
            ret &= sys::SystemManager::CreateService(varReader, manager.get());

            testVar = std::make_shared<Settings::AppTest>("appTest", varWritter, varReader, testStart);
            ret &= sys::SystemManager::CreateService(testVar, manager.get());

            profWritter = std::make_shared<Settings::ServiceProfile>("writterProf");
            profReader  = std::make_shared<Settings::ServiceProfile>("readerProf");

            ret &= sys::SystemManager::CreateService(profWritter, manager.get());
            ret &= sys::SystemManager::CreateService(profReader, manager.get());

            testProf =
                std::make_shared<Settings::AppTestProfileMode>("appTestProfile", profWritter, profReader, testStart);
            ret &= sys::SystemManager::CreateService(testProf, manager.get());

            modeWritter = std::make_shared<Settings::ServiceMode>("writterMode");
            modeReader  = std::make_shared<Settings::ServiceMode>("readerMode");

            ret &= sys::SystemManager::CreateService(modeWritter, manager.get());
            ret &= sys::SystemManager::CreateService(modeReader, manager.get());

            testMode =
                std::make_shared<Settings::AppTestProfileMode>("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<Settings::UTMsg::UTMsgStart>();
            sys::Bus::SendUnicast(std::move(msgStart), "appTest", manager.get());

            msgStart = std::make_shared<Settings::UTMsg::UTMsgStart>();
            sys::Bus::SendUnicast(std::move(msgStart), "appTestProfile", manager.get());

            msgStart = std::make_shared<Settings::UTMsg::UTMsgStart>();
            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");
    }
}

A module-services/service-db/test/test-service-db-settings-testapps.hpp => module-services/service-db/test/test-service-db-settings-testapps.hpp +244 -0
@@ 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<sys::ResponseMessage>();
        };
    };
    /* @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<MyService> setter;
        std::shared_ptr<MyService> getter;
        std::shared_ptr<std::mutex> testStart;
        State state;
        std::string last_v;
        std::vector<std::string> v;

        AppTest(std::string name,
                std::shared_ptr<MyService> setter,
                std::shared_ptr<MyService> getter,
                std::shared_ptr<std::mutex> 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<sys::ResponseMessage>();
        }
    };

    class AppTestProfileMode : public AppTest
    {
      public:
        AppTestProfileMode(const std::string &name,
                           std::shared_ptr<MyService> setter,
                           std::shared_ptr<MyService> getter,
                           std::shared_ptr<std::mutex> 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<sys::ResponseMessage>();
        }
    };
} // namespace Settings

A module-services/service-db/test/test-service-db-settings-testmsgs.hpp => module-services/service-db/test/test-service-db-settings-testmsgs.hpp +177 -0
@@ 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<std::string> profiles;
            ProfilesChg(std::list<std::string> profiles) : UTMsgCnf(), profiles(std::move(profiles))
            {}
        };
    }; // namespace UTMsg
} // namespace Settings

A module-services/service-db/test/test-service-db-settings-testservices.hpp => module-services/service-db/test/test-service-db-settings-testservices.hpp +184 -0
@@ 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<std::pair<std::string, std::string>> valChanged;
        std::string whoRequestedNotifyOnChange;
        void ValueChanged(const std::string &name, std::optional<std::string> value)
        {
            valChanged.emplace_back(std::pair<std::string, std::string>{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<std::string> 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::ResponseMessage>();
        }
        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<sys::ResponseMessage>();
        }
    };

    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<sys::ResponseMessage>();
        }
    };
} // namespace Settings

M module-services/service-db/workers/settings/settings_queries.hpp => module-services/service-db/workers/settings/settings_queries.hpp +26 -13
@@ 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

M test/mock-logs.cpp => test/mock-logs.cpp +2 -2
@@ 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 <log/log.hpp>
/*#include <log/log.hpp>
#include <cstdarg>
__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);
}
}*/