~aleteoryx/muditaos

270d69edcc1e059aa992a45a7f1dc1533130c1fb — Mateusz Grzegorzek 4 years ago 24d11da
[EGD-5724] Add pagination for Templates

Add pagination for Templates
Fix bug in change message template response
M module-db/Interface/SMSTemplateRecord.cpp => module-db/Interface/SMSTemplateRecord.cpp +23 -5
@@ 92,6 92,9 @@ std::unique_ptr<db::QueryResult> SMSTemplateRecordInterface::runQuery(std::share
    else if (typeid(*query) == typeid(db::query::SMSTemplateGet)) {
        return getQuery(query);
    }
    else if (typeid(*query) == typeid(db::query::SMSTemplateGetWithTotalCount)) {
        return getQueryWithTotalCount(query);
    }
    else if (typeid(*query) == typeid(db::query::SMSTemplateGetForList)) {
        return getForListQuery(query);
    }


@@ 121,13 124,28 @@ std::unique_ptr<db::QueryResult> SMSTemplateRecordInterface::getByIDQuery(const 
    response->setRequestQuery(query);
    return response;
}
std::unique_ptr<db::QueryResult> SMSTemplateRecordInterface::getQuery(const std::shared_ptr<db::Query> &query)

auto SMSTemplateRecordInterface::getQueryRecords(const std::shared_ptr<db::Query> &query)
    -> std::vector<SMSTemplateRecord>
{
    const auto localQuery = static_cast<const db::query::SMSTemplateGet *>(query.get());
    auto dbResult         = smsDB->templates.getLimitOffset(localQuery->offset, localQuery->limit);

    auto recordVector = std::vector<SMSTemplateRecord>(dbResult.begin(), dbResult.end());
    auto response     = std::make_unique<db::query::SMSTemplateGetResult>(std::move(recordVector));
    return std::vector<SMSTemplateRecord>(dbResult.begin(), dbResult.end());
}

auto SMSTemplateRecordInterface::getQuery(const std::shared_ptr<db::Query> &query) -> std::unique_ptr<db::QueryResult>
{
    auto response = std::make_unique<db::query::SMSTemplateGetResult>(getQueryRecords(query));
    response->setRequestQuery(query);
    return response;
}

auto SMSTemplateRecordInterface::getQueryWithTotalCount(const std::shared_ptr<db::Query> &query)
    -> std::unique_ptr<db::QueryResult>
{
    auto response = std::make_unique<db::query::SMSTemplateGetResultWithTotalCount>(getQueryRecords(query),
                                                                                    smsDB->templates.count());
    response->setRequestQuery(query);
    return response;
}


@@ 169,9 187,9 @@ std::unique_ptr<db::QueryResult> SMSTemplateRecordInterface::removeQuery(const s
}
std::unique_ptr<db::QueryResult> SMSTemplateRecordInterface::updateQuery(const std::shared_ptr<db::Query> &query)
{
    const auto localQuery = static_cast<const db::query::SMSTemplateAdd *>(query.get());
    const auto localQuery = static_cast<const db::query::SMSTemplateUpdate *>(query.get());
    auto ret              = SMSTemplateRecordInterface::Update(localQuery->rec);
    auto response         = std::make_unique<db::query::SMSTemplateAddResult>(ret);
    auto response         = std::make_unique<db::query::SMSTemplateUpdateResult>(ret);
    response->setRequestQuery(query);
    return response;
}

M module-db/Interface/SMSTemplateRecord.hpp => module-db/Interface/SMSTemplateRecord.hpp +3 -1
@@ 49,7 49,9 @@ class SMSTemplateRecordInterface : public RecordInterface<SMSTemplateRecord, SMS
  private:
    SmsDB *smsDB = nullptr;
    std::unique_ptr<db::QueryResult> getByIDQuery(const std::shared_ptr<db::Query> &query);
    std::unique_ptr<db::QueryResult> getQuery(const std::shared_ptr<db::Query> &query);
    auto getQueryRecords(const std::shared_ptr<db::Query> &query) -> std::vector<SMSTemplateRecord>;
    auto getQuery(const std::shared_ptr<db::Query> &query) -> std::unique_ptr<db::QueryResult>;
    auto getQueryWithTotalCount(const std::shared_ptr<db::Query> &query) -> std::unique_ptr<db::QueryResult>;
    std::unique_ptr<db::QueryResult> getForListQuery(const std::shared_ptr<db::Query> &query);
    std::unique_ptr<db::QueryResult> getCountQuery(const std::shared_ptr<db::Query> &query);
    std::unique_ptr<db::QueryResult> addQuery(const std::shared_ptr<db::Query> &query);

M module-db/queries/messages/templates/QuerySMSTemplateGet.cpp => module-db/queries/messages/templates/QuerySMSTemplateGet.cpp +26 -2
@@ 6,8 6,8 @@

namespace db::query
{
    SMSTemplateGet::SMSTemplateGet(unsigned int offset, unsigned int limit)
        : Query(Query::Type::Read), offset(offset), limit(limit)
    SMSTemplateGet::SMSTemplateGet(unsigned int limit, unsigned int offset)
        : Query(Query::Type::Read), limit(limit), offset(offset)
    {}

    auto SMSTemplateGet::debugInfo() const -> std::string


@@ 15,6 15,15 @@ namespace db::query
        return "SMSTemplateGet";
    }

    SMSTemplateGetWithTotalCount::SMSTemplateGetWithTotalCount(std::size_t limit, std::size_t offset)
        : SMSTemplateGet(limit, offset)
    {}

    [[nodiscard]] auto SMSTemplateGetWithTotalCount::debugInfo() const -> std::string
    {
        return "SMSTemplateGetWithTotalCount";
    }

    SMSTemplateGetResult::SMSTemplateGetResult(std::vector<SMSTemplateRecord> result) : results(std::move(result))
    {}



@@ 27,4 36,19 @@ namespace db::query
    {
        return "SMSTemplateGetResults";
    }

    SMSTemplateGetResultWithTotalCount::SMSTemplateGetResultWithTotalCount(std::vector<SMSTemplateRecord> records,
                                                                           std::size_t totalTemplatesCount)
        : SMSTemplateGetResult(std::move(records)), totalTemplatesCount(totalTemplatesCount)
    {}

    auto SMSTemplateGetResultWithTotalCount::getTotalTemplatesCount() const noexcept -> std::size_t
    {
        return totalTemplatesCount;
    }

    [[nodiscard]] auto SMSTemplateGetResultWithTotalCount::debugInfo() const -> std::string
    {
        return "SMSTemplateGetResultWithTotalCount";
    }
} // namespace db::query

M module-db/queries/messages/templates/QuerySMSTemplateGet.hpp => module-db/queries/messages/templates/QuerySMSTemplateGet.hpp +20 -2
@@ 14,13 14,20 @@ namespace db::query
    class SMSTemplateGet : public Query
    {
      public:
        unsigned int offset;
        unsigned int limit;
        SMSTemplateGet(unsigned int offset, unsigned int limit);
        unsigned int offset;
        SMSTemplateGet(unsigned int limit, unsigned int offset);

        [[nodiscard]] auto debugInfo() const -> std::string override;
    };

    class SMSTemplateGetWithTotalCount : public SMSTemplateGet
    {
      public:
        SMSTemplateGetWithTotalCount(std::size_t limit, std::size_t offset);
        [[nodiscard]] auto debugInfo() const -> std::string override;
    };

    class SMSTemplateGetResult : public QueryResult
    {
        std::vector<SMSTemplateRecord> results;


@@ 31,4 38,15 @@ namespace db::query
        [[nodiscard]] auto debugInfo() const -> std::string override;
    };

    class SMSTemplateGetResultWithTotalCount : public SMSTemplateGetResult
    {
      public:
        SMSTemplateGetResultWithTotalCount(std::vector<SMSTemplateRecord> records, std::size_t totalTemplatesCount);
        [[nodiscard]] auto debugInfo() const -> std::string override;
        [[nodiscard]] auto getTotalTemplatesCount() const noexcept -> std::size_t;

      private:
        std::size_t totalTemplatesCount;
    };

}; // namespace db::query

M module-services/service-desktop/endpoints/messages/MessageHelper.cpp => module-services/service-desktop/endpoints/messages/MessageHelper.cpp +37 -31
@@ 214,6 214,7 @@ namespace parserFSM
        }
        return sys::ReturnCodes::Success;
    }

    auto MessageHelper::updateTemplate(Context &context) -> sys::ReturnCodes
    {
        if (!context.getBody()[json::messages::templateID].is_number()) {


@@ 584,9 585,9 @@ namespace parserFSM
        auto listener = std::make_unique<db::EndpointListener>(
            [=](db::QueryResult *result, Context context) {
                if (auto smsResult = dynamic_cast<db::query::SMSTemplateGetCountResult *>(result)) {
                    auto id = smsResult->getResults();
                    auto count = smsResult->getResults();

                    context.setResponseBody(json11::Json::object{{json::messages::count, static_cast<int>(id)}});
                    context.setResponseBody(json11::Json::object{{json::messages::count, static_cast<int>(count)}});
                    MessageHandler::putToSendQueue(context.createSimpleResponse());
                    return true;
                }


@@ 625,38 626,43 @@ namespace parserFSM

    auto MessageHelper::getMessagesTemplates(Context &context) -> sys::ReturnCodes
    {
        auto query = std::make_unique<db::query::SMSTemplateGet>(
            context.getBody()[json::messages::offset].int_value(),
            context.getBody()[json::messages::limit].is_number() ? context.getBody()[json::messages::limit].int_value()
                                                                 : defaultLimit);
        auto listener = std::make_unique<db::EndpointListener>(
            [=](db::QueryResult *result, Context context) {
                if (auto smsTemplateResult = dynamic_cast<db::query::SMSTemplateGetResult *>(result)) {
        try {
            auto &ctx                = dynamic_cast<PagedContext &>(context);
            const std::size_t limit  = ctx.getBody()[json::messages::limit].int_value();
            const std::size_t offset = ctx.getBody()[json::messages::offset].int_value();
            ctx.setRequestedLimit(limit);
            ctx.setRequestedOffset(offset);
            auto query =
                std::make_unique<db::query::SMSTemplateGetWithTotalCount>(std::min(ctx.getPageSize(), limit), offset);
            auto listener = std::make_unique<db::EndpointListenerWithPages>(
                [=](db::QueryResult *result, PagedContext &context) {
                    if (auto smsTemplateResult =
                            dynamic_cast<db::query::SMSTemplateGetResultWithTotalCount *>(result)) {
                        json11::Json::array smsTemplateArray;
                        const auto &results = smsTemplateResult->getResults();
                        smsTemplateArray.reserve(results.size());
                        for (const auto &record : results) {
                            smsTemplateArray.emplace_back(toJson(record));
                        }

                    json11::Json::array smsTemplateArray;
                    for (const auto &record : smsTemplateResult->getResults()) {
                        smsTemplateArray.emplace_back(toJson(record));
                        context.setResponseBody(std::move(smsTemplateArray));
                        context.setTotalCount(smsTemplateResult->getTotalTemplatesCount());
                        MessageHandler::putToSendQueue(context.createSimpleResponse());
                        return true;
                    }
                    else {
                        return false;
                    }
                },
                ctx);

                    auto responseBody = json11::Json::object{
                        {json::messages::totalCount, 0},
                        {json::messages::nextPage,
                         json11::Json::object{{json::messages::offset, 0}, {json::messages::limit, 0}}},
                        {json::messages::entries, smsTemplateArray},
                    };

                    context.setResponseBody(responseBody);
                    MessageHandler::putToSendQueue(context.createSimpleResponse());
                    return true;
                }
                else {
                    return false;
                }
            },
            context);

        query->setQueryListener(std::move(listener));
        DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::SMSTemplate, std::move(query));
            query->setQueryListener(std::move(listener));
            DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::SMSTemplate, std::move(query));
        }
        catch (const std::bad_cast &e) {
            LOG_ERROR("%s", e.what());
            return sys::ReturnCodes::Failure;
        }
        return sys::ReturnCodes::Success;
    }
} // namespace parserFSM

M test/pytest/service-desktop/test_templates.py => test/pytest/service-desktop/test_templates.py +158 -69
@@ 4,76 4,165 @@ import pytest
from harness.interface.defs import status


@pytest.mark.service_desktop_test
@pytest.mark.usefixtures("usb_unlocked")
def test_templates(harness):
    # getting the templates count
    body = {"category": "template", "count": True}
    ret = harness.endpoint_request("messages", "get", body)
    assert ret["status"] == status["OK"]
    count = ret["body"]["count"]

    if count == 0:
        body = {"category": "template", "templateBody": "first template"}
        ret = harness.endpoint_request("messages", "post", body)
class TemplatesTester:
    def __init__(self, harness):
        self.harness = harness
        self.template_body = "TEST TEMPLATE BODY"
        self.templates_page_size = 4

    def __get_count(self):
        body = {"category": "template", "count": True}
        ret = self.harness.endpoint_request("messages", "get", body)
        assert ret["status"] == status["OK"]
        return ret["body"]["count"]

    def __add_template(self):
        body = {"category": "template", "templateBody": self.template_body}
        ret = self.harness.endpoint_request("messages", "post", body)
        assert ret["status"] == status["OK"]
        return ret

    def __get_templates(self, limit, offset):
        body = {"category": "template", "limit": limit, "offset": offset}
        return self.harness.endpoint_request("messages", "get", body)

    def __remove_template(self, template_id):
        body = {"category": "template", "templateID": template_id}
        ret = self.harness.endpoint_request("messages", "del", body)
        assert ret["status"] == status["OK"]

    def __get_all_templates(self):
        body = {"category": "template", "count": True}
        ret = harness.endpoint_request("messages", "get", body)
        ret = self.harness.endpoint_request("messages", "get", body)

        assert ret["status"] == status["OK"]

        total_count = ret["body"]["count"]
        offset = 0

        templates = []

        while True:
            ret = self.__get_templates(total_count, offset)
            templates += ret["body"]["entries"]

            assert ret["status"] == status["OK"]
            assert ret["body"]["totalCount"] == total_count

            if "nextPage" in ret["body"]:

                assert "limit" in ret["body"]["nextPage"]

                assert "offset" in ret["body"]["nextPage"]
                offset = ret["body"]["nextPage"]["offset"]

            else:
                break

        return templates

    def __remove_added_templates(self, templates):
        for template in templates:
            if template["templateBody"] == self.template_body:
                self.__remove_template(template["templateID"])

    def test_getting_template_by_id(self):
        template_id = 1
        body = {"category": "template", "templateID": template_id}
        ret = self.harness.endpoint_request("messages", "get", body)

        assert ret["status"] == status["OK"]
        count = ret["body"]["count"]
        assert count

    # getting all templates
    body = {"category": "template", "limit": count}
    ret = harness.endpoint_request("messages", "get", body)
    assert ret["status"] == status["OK"]
    assert len(ret["body"]["entries"]) == count

    # getting a number of templates
    number_of_requested_templates = 3
    body = {"category": "template", "limit": number_of_requested_templates, "offset": 0}
    ret = harness.endpoint_request("messages", "get", body)
    assert ret["status"] == status["OK"]

    templates = ret["body"]["entries"]  # getting entries
    templates_count = len(templates)
    assert templates_count == number_of_requested_templates

    # getting template by ID
    body = {"category": "template", "templateID": 1}
    ret = harness.endpoint_request("messages", "get", body)
    assert ret["status"] == status["OK"]

    # adding new template
    body = {"category": "template", "templateBody": "test template"}
    ret = harness.endpoint_request("messages", "post", body)
    assert ret["status"] == status["OK"]

    # getting the templates count again
    body = {"category": "template", "count": True}
    ret = harness.endpoint_request("messages", "get", body)
    assert ret["status"] == status["OK"]
    assert ret["body"]["count"] == count + 1

    # getting template to remove
    body = {"category": "template", "limit": count + 1}
    ret = harness.endpoint_request("messages", "get", body)
    assert ret["status"] == status["OK"]

    templateid = 0
    for template in ret["body"]["entries"]:
        if template["templateBody"] == "test template":
            templateid = template["templateID"]
            break

    # removing template
    body = {"category": "template", "templateID": templateid}
    ret = harness.endpoint_request("messages", "del", body)
    assert ret["status"] == status["OK"]

    # getting the templates count again
    body = {"category": "template", "count": True}
    ret = harness.endpoint_request("messages", "get", body)
    assert ret["status"] == status["OK"]
    assert ret["body"]["count"] == count
        assert ret["body"]["templateID"] == template_id

    def test_getting_templates_without_pagination(self):
        count = self.__get_count()

        number_of_requested_templates = self.templates_page_size - 1
        ret = self.__get_templates(number_of_requested_templates, 0)

        assert ret["status"] == status["OK"]
        assert ret["body"]["totalCount"] == count
        assert len(ret["body"]["entries"]) == number_of_requested_templates

    def test_changing_template_body(self):
        test_passed = False
        initial_count = self.__get_count()

        self.__add_template()

        templates = self.__get_all_templates()

        for template in templates:

            if template["templateBody"] == self.template_body:

                # Change template
                new_template_body = "NEW TEMPLATE BODY TEST"
                body = {"category": "template", "templateID": template["templateID"], "templateBody": new_template_body}
                ret = self.harness.endpoint_request("messages", "put", body)
                assert ret["status"] == status["OK"]

                # and then remove it to clean env
                self.__remove_template(template["templateID"])
                test_passed = True
                break

        # templates count at the end of the test should match initial templates count
        total_count = self.__get_count()
        assert total_count == initial_count
        assert test_passed == True

    def test_getting_templates_with_pagination(self):
        initial_count = self.__get_count()

        self.__add_template()

        total_count = self.__get_count()
        assert total_count == initial_count + 1

        # adding new templates to make the total count be above templates page size
        expected_templates_count = self.templates_page_size * 3 + 1
        num_of_templates_to_insert = expected_templates_count - total_count

        while 0 < num_of_templates_to_insert:
            self.__add_template()
            num_of_templates_to_insert -= 1

        total_count = self.__get_count()
        assert total_count == expected_templates_count

        templates = self.__get_all_templates()

        self.__remove_added_templates(templates)

        # templates count at the end of the test should match initial templates count
        total_count = self.__get_count()
        assert total_count == initial_count


@pytest.mark.service_desktop_test
@pytest.mark.usefixtures("usb_unlocked")
def test_get_template_by_id(harness):
    templates_tester = TemplatesTester(harness)
    templates_tester.test_getting_template_by_id()


@pytest.mark.service_desktop_test
@pytest.mark.usefixtures("usb_unlocked")
def test_get_templates_without_paggination(harness):
    templates_tester = TemplatesTester(harness)
    templates_tester.test_getting_templates_without_pagination()


@pytest.mark.service_desktop_test
@pytest.mark.usefixtures("usb_unlocked")
def test_change_template(harness):
    templates_tester = TemplatesTester(harness)
    templates_tester.test_changing_template_body()


@pytest.mark.service_desktop_test
@pytest.mark.usefixtures("usb_unlocked")
def test_get_templates_with_pagination(harness):
    templates_tester = TemplatesTester(harness)
    templates_tester.test_getting_templates_with_pagination()