M changelog.md => changelog.md +1 -0
@@ 11,6 11,7 @@
* Add Bluetooth virtual audio device.
* Add custom repeat window for the alarm application
* `[PowerManagement]` Add CPU frequency shift mechanism.
+* `[tests]` Extended the automated tests with new test cases: making a call, answering a call.
### Fixed
M module-db/Interface/SMSRecord.cpp => module-db/Interface/SMSRecord.cpp +25 -1
@@ 380,13 380,37 @@ std::unique_ptr<db::QueryResult> SMSRecordInterface::getByContactIDQuery(const s
std::unique_ptr<db::QueryResult> SMSRecordInterface::getByTextQuery(const std::shared_ptr<db::Query> &query)
{
const auto localQuery = static_cast<const db::query::SMSGetByText *>(query.get());
- auto smsVector = smsDB->sms.getByText(localQuery->text);
+ auto smsVector = getByText(localQuery->getText(), localQuery->getPhoneNumber());
auto recordVector = std::vector<SMSRecord>(smsVector.begin(), smsVector.end());
auto response = std::make_unique<db::query::SMSGetByTextResult>(recordVector);
response->setRequestQuery(query);
return response;
}
+
+std::vector<SMSRecord> SMSRecordInterface::getByText(const std::string &text,
+ const std::optional<utils::PhoneNumber::View> &phoneNumberFilter)
+{
+ if (phoneNumberFilter.has_value()) {
+ return getByTextAndPhoneNumber(text, phoneNumberFilter.value());
+ }
+ const auto &records = smsDB->sms.getByText(text);
+ return std::vector<SMSRecord>(records.begin(), records.end());
+}
+
+std::vector<SMSRecord> SMSRecordInterface::getByTextAndPhoneNumber(const std::string &text,
+ const utils::PhoneNumber::View &phoneNumber)
+{
+ ThreadRecordInterface threadsInterface{smsDB, contactsDB};
+ const auto &thread = threadsInterface.GetByNumber(phoneNumber);
+ if (!thread.isValid()) {
+ return {};
+ }
+
+ const auto &smsRecords = smsDB->sms.getByText(text, thread.ID);
+ return std::vector<SMSRecord>(smsRecords.begin(), smsRecords.end());
+}
+
std::unique_ptr<db::QueryResult> SMSRecordInterface::getCountQuery(const std::shared_ptr<db::Query> &query)
{
auto response = std::make_unique<db::query::SMSGetCountResult>(smsDB->sms.count());
M module-db/Interface/SMSRecord.hpp => module-db/Interface/SMSRecord.hpp +5 -0
@@ 77,6 77,11 @@ class SMSRecordInterface : public RecordInterface<SMSRecord, SMSRecordField>
SmsDB *smsDB = nullptr;
ContactsDB *contactsDB = nullptr;
+ std::vector<SMSRecord> getByText(const std::string &text,
+ const std::optional<utils::PhoneNumber::View> &phoneNumberFilter);
+ std::vector<SMSRecord> getByTextAndPhoneNumber(const std::string &text,
+ const utils::PhoneNumber::View &phoneNumber);
+
static void UpdateThreadSummary(ThreadRecord &threadToUpdate, const SMSRecord &rec);
std::unique_ptr<db::query::SMSSearchByTypeResult> runQueryImpl(const db::query::SMSSearchByType *query);
std::unique_ptr<db::QueryResult> getByIDQuery(const std::shared_ptr<db::Query> &query);
M module-db/Tables/SMSTable.cpp => module-db/Tables/SMSTable.cpp +24 -0
@@ 234,6 234,30 @@ std::vector<SMSTableRow> SMSTable::getByText(std::string text)
return ret;
}
+std::vector<SMSTableRow> SMSTable::getByText(std::string text, uint32_t threadId)
+{
+ auto retQuery =
+ db->query("SELECT *, INSTR(body,'%s') pos FROM sms WHERE pos > 0 AND thread_id=%u;", text.c_str(), threadId);
+ if ((retQuery == nullptr) || (retQuery->getRowCount() == 0)) {
+ return {};
+ }
+
+ std::vector<SMSTableRow> ret;
+ do {
+ ret.push_back(SMSTableRow{
+ (*retQuery)[0].getUInt32(), // ID
+ (*retQuery)[1].getUInt32(), // threadID
+ (*retQuery)[2].getUInt32(), // contactID
+ (*retQuery)[3].getUInt32(), // date
+ (*retQuery)[4].getUInt32(), // dateSent
+ (*retQuery)[5].getUInt32(), // errorCode
+ (*retQuery)[6].getString(), // body
+ static_cast<SMSType>((*retQuery)[7].getUInt32()), // type
+ });
+ } while (retQuery->nextRow());
+ return ret;
+}
+
std::vector<SMSTableRow> SMSTable::getLimitOffset(uint32_t offset, uint32_t limit)
{
auto retQuery = db->query("SELECT * from sms ORDER BY date DESC LIMIT %lu OFFSET %lu;", limit, offset);
M module-db/Tables/SMSTable.hpp => module-db/Tables/SMSTable.hpp +1 -0
@@ 49,6 49,7 @@ class SMSTable : public Table<SMSTableRow, SMSTableFields>
uint32_t countByFieldId(const char *field, uint32_t id) override final;
std::vector<SMSTableRow> getByContactId(uint32_t contactId);
std::vector<SMSTableRow> getByText(std::string text);
+ std::vector<SMSTableRow> getByText(std::string text, uint32_t threadId);
std::vector<SMSTableRow> getByThreadId(uint32_t threadId, uint32_t offset, uint32_t limit);
std::vector<SMSTableRow> getByThreadIdWithoutDraftWithEmptyInput(uint32_t threadId,
uint32_t offset,
M module-db/queries/messages/sms/QuerySMSGetByText.cpp => module-db/queries/messages/sms/QuerySMSGetByText.cpp +16 -0
@@ 8,6 8,21 @@ namespace db::query
SMSGetByText::SMSGetByText(std::string text) : Query(Query::Type::Read), text(std::move(text))
{}
+ void SMSGetByText::filterByPhoneNumber(const utils::PhoneNumber::View &number) noexcept
+ {
+ phoneNumber = number;
+ }
+
+ auto SMSGetByText::getPhoneNumber() const noexcept -> const std::optional<utils::PhoneNumber::View> &
+ {
+ return phoneNumber;
+ }
+
+ auto SMSGetByText::getText() const noexcept -> const std::string &
+ {
+ return text;
+ }
+
auto SMSGetByText::debugInfo() const -> std::string
{
return "SMSGetByText";
@@ 15,6 30,7 @@ namespace db::query
SMSGetByTextResult::SMSGetByTextResult(std::vector<SMSRecord> result) : result(std::move(result))
{}
+
auto SMSGetByTextResult::getResults() const -> std::vector<SMSRecord>
{
return result;
M module-db/queries/messages/sms/QuerySMSGetByText.hpp => module-db/queries/messages/sms/QuerySMSGetByText.hpp +9 -2
@@ 14,9 14,16 @@ namespace db::query
class SMSGetByText : public Query
{
public:
- SMSGetByText(std::string text);
- std::string text;
+ explicit SMSGetByText(std::string text);
+
+ void filterByPhoneNumber(const utils::PhoneNumber::View &number) noexcept;
+ [[nodiscard]] auto getPhoneNumber() const noexcept -> const std::optional<utils::PhoneNumber::View> &;
+ [[nodiscard]] auto getText() const noexcept -> const std::string &;
[[nodiscard]] auto debugInfo() const -> std::string override;
+
+ private:
+ std::string text;
+ std::optional<utils::PhoneNumber::View> phoneNumber;
};
class SMSGetByTextResult : public QueryResult
M module-services/service-db/ServiceDB.cpp => module-services/service-db/ServiceDB.cpp +1 -1
@@ 541,7 541,7 @@ sys::ReturnCodes ServiceDB::InitHandler()
smsDB = std::make_unique<SmsDB>((purefs::dir::getUserDiskPath() / "sms.db").c_str());
alarmsDB = std::make_unique<AlarmsDB>((purefs::dir::getUserDiskPath() / "alarms.db").c_str());
notesDB = std::make_unique<NotesDB>((purefs::dir::getUserDiskPath() / "notes.db").c_str());
- calllogDB = std::make_unique<CalllogDB>((purefs::dir::getUserDiskPath() / "callog.db").c_str());
+ calllogDB = std::make_unique<CalllogDB>((purefs::dir::getUserDiskPath() / "calllog.db").c_str());
countryCodesDB = std::make_unique<CountryCodesDB>("country-codes.db");
notificationsDB = std::make_unique<NotificationsDB>((purefs::dir::getUserDiskPath() / "notifications.db").c_str());
eventsDB = std::make_unique<EventsDB>((purefs::dir::getUserDiskPath() / "events.db").c_str());
M module-services/service-desktop/endpoints/messages/MessageHelper.cpp => module-services/service-desktop/endpoints/messages/MessageHelper.cpp +5 -0
@@ 198,6 198,11 @@ auto MessageHelper::requestSMS(Context &context) -> sys::ReturnCodes
else if (context.getBody()[json::messages::messageBody].string_value().empty() == false) {
auto query =
std::make_unique<db::query::SMSGetByText>(context.getBody()[json::messages::messageBody].string_value());
+ if (const auto filterByNumber = !context.getBody()[json::messages::phoneNumber].string_value().empty();
+ filterByNumber) {
+ utils::PhoneNumber number{context.getBody()[json::messages::phoneNumber].string_value()};
+ query->filterByPhoneNumber(number.getView());
+ }
auto listener = std::make_unique<db::EndpointListener>(
[=](db::QueryResult *result, Context context) {
M test/harness/utils.py => test/harness/utils.py +1 -1
@@ 10,7 10,7 @@ from harness.interface.defs import key_codes
# assuming that the harness is actually in the menu
application_keypath = {
- "phone": [
+ "calllog": [
"enter"
],
"contacts": [
A test/pytest/test_call_back.py => test/pytest/test_call_back.py +38 -0
@@ 0,0 1,38 @@
+# Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+# For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+import time
+import pytest
+
+from harness.interface.defs import key_codes
+
+
+def get_calllog_count(harness):
+ body = {"count": True}
+ return harness.endpoint_request("calllog", "get", body)["body"]["count"]
+
+
+@pytest.mark.rt1051
+@pytest.mark.usefixtures("phone_unlocked")
+def test_call(harness, call_duration):
+ count_before = get_calllog_count(harness)
+
+ # enter menu
+ harness.connection.send_key(key_codes["enter"])
+ harness.open_application("calllog")
+ if harness.connection.get_window_name() != "ApplicationCallLog":
+ time.sleep(2)
+ assert harness.connection.get_window_name() == "ApplicationCallLog"
+
+ # call
+ harness.connection.send_key(key_codes["fnLeft"])
+ time.sleep(call_duration)
+ # hang up
+ harness.connection.send_key(key_codes["fnRight"])
+ count_after = get_calllog_count(harness)
+
+ for _ in range(3):
+ harness.connection.send_key(key_codes["fnRight"])
+ time.sleep(1)
+
+ assert count_before + 1 == count_after
+ time.sleep(2) # needed to restore after call
A test/pytest/test_search_sms.py => test/pytest/test_search_sms.py +13 -0
@@ 0,0 1,13 @@
+# Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+# For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+import time
+import pytest
+
+from harness.interface.defs import key_codes
+
+@pytest.mark.rt1051
+@pytest.mark.usefixtures("phone_unlocked")
+def test_search_sms(harness, sms_text, phone_number):
+ body = {"messageBody": sms_text, "phoneNumber": str(phone_number)}
+ messages = harness.endpoint_request("messages", "get", body)["body"]
+ assert len(messages) != 0
M test/pytest/test_send_message.py => test/pytest/test_send_message.py +5 -5
@@ 6,15 6,15 @@ import pytest
from harness.interface.defs import key_codes
-def get_message_by_text(harness, message: str):
- body = {"messageBody": message}
+def get_message_by_text(harness, message: str, phone_number: str):
+ body = {"messageBody": message, "phoneNumber": phone_number}
return harness.endpoint_request("messages", "get", body)["body"]
@pytest.mark.rt1051
@pytest.mark.usefixtures("phone_unlocked")
def test_send_message(harness, phone_number, sms_text):
- messages = get_message_by_text(harness, sms_text.upper())
+ messages = get_message_by_text(harness, sms_text.upper(), str(phone_number))
# enter menu
harness.connection.send_key(key_codes["enter"])
@@ 35,11 35,11 @@ def test_send_message(harness, phone_number, sms_text):
harness.connection.send_key(key_codes["enter"])
# go back to main screen
- for i in range(3):
+ for _ in range(3):
harness.connection.send_key(key_codes["fnRight"])
time.sleep(2)
- new_messages = get_message_by_text(harness, sms_text.upper())
+ new_messages = get_message_by_text(harness, sms_text.upper(), str(phone_number))
diff = [i for i in messages + new_messages if i not in messages or i not in new_messages]
assert len(diff) == 1
R test/send_message.py => test/search_sms.py +9 -40
@@ 11,33 11,12 @@ from harness.interface.defs import key_codes, endpoint, method
from harness.interface.error import TestError, Error
-def send_message(harness, phone_number: str, message: str):
+def search_sms(harness, message: str, phone_number: str):
@harness.with_phone_unlocked
- def send(connection):
- # enter menu
- connection.send_key(key_codes["enter"])
- harness.open_application("messages")
- if harness.connection.get_window_name() != "ApplicationMessages":
- time.sleep(2)
- if harness.connection.get_window_name() != "ApplicationMessages":
- print("Application didn't switch, exiting...")
- exit(1)
-
- # create new message
- connection.send_key(key_codes["left"])
- # enter phone number
- harness.send_number(phone_number)
- # move down to message body
- connection.send_key(key_codes["down"])
- # write a message
- harness.send_text(message)
- # send
- connection.send_key(key_codes["enter"])
-
-
-def get_message_by_text(harness, message: str):
- body = {"messageBody": message}
- return harness.endpoint_request("messages", "get", body)["body"]
+ def do_it(connection):
+ body = {"messageBody": message, "phoneNumber": phone_number}
+ messages = harness.endpoint_request("messages", "get", body)["body"]
+ print(f'Found {len(messages)} messages')
def main():
@@ 45,10 24,9 @@ def main():
log.warning("Port name not passed, trying port name filename from simulator...")
try:
file = open("/tmp/purephone_pts_name", "r")
- except FileNotFoundError as err:
+ except FileNotFoundError:
raise TestError(Error.PORT_FILE_NOT_FOUND)
-
port_name = file.readline()
if port_name.isascii():
log.debug("found {} entry!".format(port_name))
@@ 59,19 37,10 @@ def main():
port_name = sys.argv[1]
harness = Harness(port_name)
- message = str(sys.argv[3])
- messages = get_message_by_text(harness, message.upper())
-
- send_message(harness, str(sys.argv[2]), message)
- time.sleep(2)
- new_messages = get_message_by_text(harness, message.upper())
+ message = str(sys.argv[2])
+ phone_number = str(sys.argv[3])
- diff = [i for i in messages + new_messages if i not in messages or i not in new_messages]
- if len(diff) != 1 or diff[0]["type"] != 0x08: # 0x08 - SMSType::OUTBOX
- log.error("sending error!")
- raise TestError(Error.TEST_FAILED)
- else:
- log.info("sending success!")
+ search_sms(harness, message, phone_number)
if __name__ == "__main__":