Newer
Older
#include <boost/algorithm/string.hpp>
#include <nlohmann/json.hpp>
#include "mtx/events/collections.hpp"
#include "mtx/events/encrypted.hpp"
#include "mtx/requests.hpp"
#include "mtx/responses.hpp"
#include "mtxclient/http/client.hpp"
#include "test_helpers.hpp"
using namespace mtx::http;
using namespace mtx::events::collections;
using namespace mtx::requests;
TEST(ClientAPI, Register)
{
auto user = std::make_shared<Client>("localhost");
user->registration("alice", "secret", [](const mtx::responses::Register &, RequestErr err) {
ASSERT_TRUE(err);
EXPECT_EQ(mtx::errors::to_string(err->matrix_error.errcode), "M_USER_IN_USE");
});
auto username = utils::random_token(10, false);
// Synapse converts the username to lowercase.
boost::algorithm::to_lower(username);
user->registration(
username, "secret", [user, username](const mtx::responses::Register &, RequestErr err) {
if (!err || err->matrix_error.unauthorized.flows.size() == 0)
EXPECT_EQ(err->matrix_error.unauthorized.flows.size(), 1);
EXPECT_EQ(err->matrix_error.unauthorized.flows[0].stages[0], "m.login.dummy");
{err->matrix_error.unauthorized.session, mtx::user_interactive::auth::Dummy{}},
[username](const mtx::responses::Register &res, RequestErr err) {
const auto user_id = "@" + username + ":localhost";
check_error(err);
EXPECT_EQ(res.user_id.to_string(), user_id);
});
TEST(ClientAPI, LoginSuccess)
{
std::shared_ptr<Client> mtx_client = std::make_shared<Client>("localhost");
mtx_client->login("alice", "secret", [](const mtx::responses::Login &res, RequestErr err) {
mtx_client->login("bob", "secret", [](const mtx::responses::Login &res, RequestErr err) {
mtx_client->login("carl", "secret", [](const mtx::responses::Login &res, RequestErr err) {
validate_login("@carl:localhost", res);
});
mtx_client->close();
}
TEST(ClientAPI, LoginWrongPassword)
{
std::shared_ptr<Client> mtx_client = std::make_shared<Client>("localhost");
mtx_client->login(
"alice", "wrong_password", [](const mtx::responses::Login &res, RequestErr err) {
ASSERT_TRUE(err);
EXPECT_EQ(mtx::errors::to_string(err->matrix_error.errcode), "M_FORBIDDEN");
EXPECT_EQ(err->status_code, boost::beast::http::status::forbidden);
EXPECT_EQ(res.device_id, "");
EXPECT_EQ(res.access_token, "");
});
mtx_client->close();
}
TEST(ClientAPI, LoginWrongUsername)
{
std::shared_ptr<Client> mtx_client = std::make_shared<Client>("localhost");
mtx_client->login("john", "secret", [](const mtx::responses::Login &res, RequestErr err) {
ASSERT_TRUE(err);
EXPECT_EQ(mtx::errors::to_string(err->matrix_error.errcode), "M_FORBIDDEN");
EXPECT_EQ(err->status_code, boost::beast::http::status::forbidden);
EXPECT_EQ(res.device_id, "");
EXPECT_EQ(res.access_token, "");
});
mtx_client->close();
}
TEST(ClientAPI, LoginFlows)
{
std::shared_ptr<Client> mtx_client = std::make_shared<Client>("localhost");
mtx_client->get_login([](const mtx::responses::LoginFlows &res, RequestErr err) {
ASSERT_FALSE(err);
EXPECT_EQ(res.flows[0].type, mtx::user_interactive::auth_types::password);
});
mtx_client->close();
}
TEST(ClientAPI, SSORedirect)
{
std::shared_ptr<Client> mtx_client = std::make_shared<Client>("localhost");
EXPECT_EQ(mtx_client->login_sso_redirect("http://aaa:555/sso"),
"https://localhost:443/_matrix/client/r0/login/sso/"
"redirect?redirectUrl=http%3A%2F%2Faaa%3A555%2Fsso");
TEST(ClientAPI, EmptyUserAvatar)
{
auto alice = std::make_shared<Client>("localhost");
alice->login("alice", "secret", [alice](const mtx::responses::Login &res, RequestErr err) {
ASSERT_FALSE(err);
auto const alice_id = res.user_id;
alice->set_avatar_url("", [alice, alice_id](RequestErr err) {
ASSERT_FALSE(err);
auto done = false;
alice->get_profile(
alice_id.to_string(),
[&done](const mtx::responses::Profile &res, RequestErr err) {
ASSERT_FALSE(err);
ASSERT_TRUE(res.avatar_url.size() == 0);
done = true;
});
while (!done)
alice->get_avatar_url(
alice_id.to_string(),
[](const mtx::responses::AvatarUrl &res, RequestErr err) {
ASSERT_FALSE(err);
ASSERT_TRUE(res.avatar_url.size() == 0);
});
});
});
alice->close();
}
TEST(ClientAPI, RealUserAvatar)
{
auto alice = std::make_shared<Client>("localhost");
alice->login("alice", "secret", [alice](const mtx::responses::Login &res, RequestErr err) {
ASSERT_FALSE(err);
auto const alice_id = res.user_id;
auto const avatar_url = "mxc://matrix.org/wefh34uihSDRGhw34";
alice->set_avatar_url(avatar_url, [alice, alice_id, avatar_url](RequestErr err) {
ASSERT_FALSE(err);
auto done = false;
alice->get_profile(
[avatar_url, &done](const mtx::responses::Profile &res, RequestErr err) {
ASSERT_FALSE(err);
ASSERT_TRUE(res.avatar_url == avatar_url);
done = true;
});
while (!done)
alice->get_avatar_url(
[avatar_url](const mtx::responses::AvatarUrl &res, RequestErr err) {
ASSERT_FALSE(err);
ASSERT_TRUE(res.avatar_url == avatar_url);
});
});
});
alice->close();
}
TEST(ClientAPI, ChangeDisplayName)
{
std::shared_ptr<Client> mtx_client = std::make_shared<Client>("localhost");
mtx_client->login(
"alice", "secret", [mtx_client](const mtx::responses::Login &, RequestErr err) {
// Change the display name to Arthur Dent and verify its success through the lack
// of an error
mtx_client->set_displayname("Arthur Dent",
[](RequestErr err) { check_error(err); });
});
mtx_client->close();
}
TEST(ClientAPI, EmptyDisplayName)
{
std::shared_ptr<Client> mtx_client = std::make_shared<Client>("localhost");
mtx_client->login(
"alice", "secret", [mtx_client](const mtx::responses::Login &, RequestErr err) {
// Change the display name to an empty string and verify its success through the
// lack of an error
mtx_client->set_displayname("", [](RequestErr err) { check_error(err); });
});
mtx_client->close();
}
TEST(ClientAPI, CreateRoom)
{
std::shared_ptr<Client> mtx_client = std::make_shared<Client>("localhost");
mtx_client->login(
"alice", "secret", [mtx_client](const mtx::responses::Login &, RequestErr err) {
while (mtx_client->access_token().empty())
mtx::requests::CreateRoom req;
req.name = "Name";
req.topic = "Topic";
mtx_client->create_room(req, [](const mtx::responses::CreateRoom &res, RequestErr err) {
ASSERT_TRUE(res.room_id.localpart().size() > 10);
EXPECT_EQ(res.room_id.hostname(), "localhost");
});
mtx_client->close();
}
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
TEST(ClientAPI, TagRoom)
{
std::shared_ptr<Client> mtx_client = std::make_shared<Client>("localhost");
mtx_client->login(
"alice", "secret", [mtx_client](const mtx::responses::Login &, RequestErr err) {
check_error(err);
});
while (mtx_client->access_token().empty())
sleep();
mtx::requests::CreateRoom req;
req.name = "Name";
req.topic = "Topic";
mtx_client->create_room(
req, [mtx_client](const mtx::responses::CreateRoom &res, RequestErr err) {
auto room_id = res.room_id;
check_error(err);
mtx_client->put_tag(
room_id.to_string(), "u.Test", {0.5}, [mtx_client, room_id](RequestErr err) {
check_error(err);
mtx_client->get_tags(
room_id.to_string(),
[mtx_client, room_id](mtx::events::account_data::Tags tags,
RequestErr err) {
check_error(err);
EXPECT_EQ(tags.tags.at("u.Test").order, 0.5);
mtx_client->delete_tag(
room_id.to_string(),
"u.Test",
[mtx_client, room_id](RequestErr err) {
check_error(err);
mtx_client->get_tags(
room_id.to_string(),
[mtx_client,
room_id](mtx::events::account_data::Tags tags,
RequestErr err) {
check_error(err);
EXPECT_EQ(tags.tags.count("u.Test"), 0);
});
});
});
});
});
mtx_client->close();
}
TEST(ClientAPI, LogoutSuccess)
{
std::shared_ptr<Client> mtx_client = std::make_shared<Client>("localhost");
std::string token;
// Login and prove that login was successful by creating a room
mtx_client->login(
"alice", "secret", [&token](const mtx::responses::Login &res, RequestErr err) {
while (token.empty())
sleep();
mtx_client->set_access_token(token);
mtx::requests::CreateRoom req;
req.name = "Test1";
req.topic = "Topic1";
req, [](const mtx::responses::CreateRoom &, RequestErr err) { check_error(err); });
// Logout and prove that logout was successful and deleted the access_token_ for the client
mtx_client->logout([mtx_client, &token](const mtx::responses::Logout &, RequestErr err) {
while (token.size())
sleep();
// Verify that sending requests with this mtx_client fails after logout
mtx::requests::CreateRoom failReq;
failReq.name = "42";
failReq.topic = "LifeUniverseEverything";
mtx_client->create_room(failReq, [](const mtx::responses::CreateRoom &, RequestErr err) {
EXPECT_EQ(mtx::errors::to_string(err->matrix_error.errcode), "M_UNRECOGNIZED");
});
mtx_client->close();
}
TEST(ClientAPI, LogoutInvalidatesTokenOnServer)
{
std::shared_ptr<Client> mtx_client = std::make_shared<Client>("localhost");
std::string token;
// Login and prove that login was successful by creating a room
mtx_client->login(
"alice", "secret", [&token](const mtx::responses::Login &res, RequestErr err) {
while (token.empty())
sleep();
mtx_client->set_access_token(token);
mtx::requests::CreateRoom req;
req.name = "Test1";
req.topic = "Topic1";
req, [](const mtx::responses::CreateRoom &, RequestErr err) { check_error(err); });
// Logout and prove that logout was successful by verifying the old access_token_ is no
// longer valid
mtx_client->logout([mtx_client, &token](const mtx::responses::Logout &, RequestErr err) {
mtx_client->set_access_token(token);
token.clear();
});
while (token.size())
sleep();
// Verify that creating a room with the old access_token_ no longer succeeds after logout
mtx::requests::CreateRoom failReq;
failReq.name = "42";
failReq.topic = "LifeUniverseEverything";
mtx_client->create_room(failReq, [](const mtx::responses::CreateRoom &, RequestErr err) {
EXPECT_EQ(mtx::errors::to_string(err->matrix_error.errcode), "M_UNRECOGNIZED");
});
mtx_client->close();
}
TEST(ClientAPI, CreateRoomInvites)
{
auto alice = std::make_shared<Client>("localhost");
auto bob = std::make_shared<Client>("localhost");
auto carl = std::make_shared<Client>("localhost");
alice->login("alice", "secret", [alice](const mtx::responses::Login &, RequestErr err) {
bob->login("bob", "secret", [bob](const mtx::responses::Login &, RequestErr err) {
check_error(err);
});
carl->login("carl", "secret", [carl](const mtx::responses::Login &, RequestErr err) {
while (alice->access_token().empty() || bob->access_token().empty() ||
carl->access_token().empty())
mtx::requests::CreateRoom req;
req.name = "Name";
req.topic = "Topic";
req.invite = {"@bob:localhost", "@carl:localhost"};
alice->create_room(req, [bob, carl](const mtx::responses::CreateRoom &res, RequestErr err) {
auto room_id = res.room_id.to_string();
bob->join_room(room_id, [](const mtx::responses::RoomId &, RequestErr err) {
check_error(err);
});
carl->join_room(room_id, [](const mtx::responses::RoomId &, RequestErr err) {
check_error(err);
});
});
alice->close();
bob->close();
carl->close();
}
TEST(ClientAPI, JoinRoom)
{
auto alice = std::make_shared<Client>("localhost");
auto bob = std::make_shared<Client>("localhost");
alice->login("alice", "secret", [alice](const mtx::responses::Login &, RequestErr err) {
bob->login("bob", "secret", [bob](const mtx::responses::Login &, RequestErr err) {
check_error(err);
});
while (alice->access_token().empty() || bob->access_token().empty())
// Creating a random room alias.
// TODO: add a type for room aliases.
const auto alias = utils::random_token(20, false);
req.name = "Name";
req.topic = "Topic";
req.invite = {"@bob:localhost"};
req.room_alias_name = alias;
alice->create_room(
req, [bob, alias](const mtx::responses::CreateRoom &res, RequestErr err) {
check_error(err);
auto room_id = res.room_id.to_string();
bob->join_room(room_id, [](const mtx::responses::RoomId &, RequestErr err) {
check_error(err);
});
using namespace mtx::identifiers;
bob->join_room("!random_room_id:localhost",
[](const mtx::responses::RoomId &, RequestErr err) {
ASSERT_TRUE(err);
EXPECT_EQ(
mtx::errors::to_string(err->matrix_error.errcode),
"M_UNKNOWN");
});
// Join the room using an alias.
bob->join_room(
"#" + alias + ":localhost",
[](const mtx::responses::RoomId &, RequestErr err) { check_error(err); });
TEST(ClientAPI, LeaveRoom)
{
auto alice = std::make_shared<Client>("localhost");
auto bob = std::make_shared<Client>("localhost");
alice->login("alice", "secret", [alice](const mtx::responses::Login &, RequestErr err) {
bob->login("bob", "secret", [bob](const mtx::responses::Login &, RequestErr err) {
check_error(err);
});
while (alice->access_token().empty() || bob->access_token().empty())
mtx::requests::CreateRoom req;
req.name = "Name";
req.topic = "Topic";
req.invite = {"@bob:localhost"};
alice->create_room(req, [bob](const mtx::responses::CreateRoom &res, RequestErr err) {
bob->join_room(res.room_id.to_string(),
[room_id, bob](const mtx::responses::RoomId &, RequestErr err) {
check_error(err);
bob->leave_room(room_id.to_string(),
[](mtx::responses::Empty, RequestErr err) {
check_error(err);
});
});
// Trying to leave a non-existent room should fail.
bob->leave_room("!random_room_id:localhost", [](mtx::responses::Empty, RequestErr err) {
ASSERT_TRUE(err);
EXPECT_EQ(mtx::errors::to_string(err->matrix_error.errcode), "M_UNKNOWN");
EXPECT_EQ(err->matrix_error.error, "Not a known room");
});
alice->close();
bob->close();
}
TEST(ClientAPI, InviteRoom)
{
auto alice = std::make_shared<Client>("localhost");
auto bob = std::make_shared<Client>("localhost");
alice->login("alice", "secret", [alice](const mtx::responses::Login &, RequestErr err) {
bob->login("bob", "secret", [bob](const mtx::responses::Login &, RequestErr err) {
check_error(err);
});
while (alice->access_token().empty() || bob->access_token().empty())
mtx::requests::CreateRoom req;
req.name = "Name";
req.topic = "Topic";
req.invite = {};
alice->create_room(
req, [alice, bob](const mtx::responses::CreateRoom &res, RequestErr err) {
check_error(err);
auto room_id = res.room_id.to_string();
alice->invite_user(room_id,
"@bob:localhost",
[room_id, bob](const mtx::responses::Empty &, RequestErr err) {
check_error(err);
bob->join_room(
room_id,
[](const mtx::responses::RoomId &, RequestErr err) {
check_error(err);
});
});
});
alice->close();
bob->close();
}
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
TEST(ClientAPI, KickRoom)
{
auto alice = std::make_shared<Client>("localhost");
auto bob = std::make_shared<Client>("localhost");
alice->login("alice", "secret", [alice](const mtx::responses::Login &, RequestErr err) {
check_error(err);
});
bob->login("bob", "secret", [bob](const mtx::responses::Login &, RequestErr err) {
check_error(err);
});
while (alice->access_token().empty() || bob->access_token().empty())
sleep();
mtx::requests::CreateRoom req;
req.name = "Name";
req.topic = "Topic";
req.invite = {};
alice->create_room(
req, [alice, bob](const mtx::responses::CreateRoom &res, RequestErr err) {
check_error(err);
auto room_id = res.room_id.to_string();
alice->invite_user(
room_id,
"@bob:localhost",
[room_id, alice, bob](const mtx::responses::Empty &, RequestErr err) {
check_error(err);
bob->join_room(
room_id,
[alice, room_id](const mtx::responses::RoomId &, RequestErr err) {
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
check_error(err);
alice->kick_user(room_id,
"@bob:localhost",
[](const mtx::responses::Empty &,
RequestErr err) { check_error(err); });
});
});
});
alice->close();
bob->close();
}
TEST(ClientAPI, BanRoom)
{
auto alice = std::make_shared<Client>("localhost");
auto bob = std::make_shared<Client>("localhost");
alice->login("alice", "secret", [alice](const mtx::responses::Login &, RequestErr err) {
check_error(err);
});
bob->login("bob", "secret", [bob](const mtx::responses::Login &, RequestErr err) {
check_error(err);
});
while (alice->access_token().empty() || bob->access_token().empty())
sleep();
mtx::requests::CreateRoom req;
req.name = "Name";
req.topic = "Topic";
req.invite = {};
alice->create_room(
req, [alice, bob](const mtx::responses::CreateRoom &res, RequestErr err) {
check_error(err);
auto room_id = res.room_id.to_string();
alice->invite_user(
room_id,
"@bob:localhost",
[room_id, alice, bob](const mtx::responses::Empty &, RequestErr err) {
check_error(err);
bob->join_room(
room_id,
[alice, room_id](const mtx::responses::RoomId &, RequestErr err) {
check_error(err);
alice->ban_user(
room_id,
"@bob:localhost",
[alice, room_id](const mtx::responses::Empty &,
RequestErr err) {
check_error(err);
alice->unban_user(
room_id,
"@bob:localhost",
[](const mtx::responses::Empty &,
RequestErr err) { check_error(err); },
"You not bad anymore!");
},
"You bad!");
});
});
});
alice->close();
bob->close();
}
TEST(ClientAPI, InvalidInvite)
{
auto alice = std::make_shared<Client>("localhost");
auto bob = std::make_shared<Client>("localhost");
alice->login("alice", "secret", [alice](const mtx::responses::Login &, RequestErr err) {
bob->login("bob", "secret", [bob](const mtx::responses::Login &, RequestErr err) {
check_error(err);
});
while (alice->access_token().empty() || bob->access_token().empty())
mtx::requests::CreateRoom req;
req.name = "Name";
req.topic = "Topic";
req.invite = {};
alice->create_room(
req, [alice, bob](const mtx::responses::CreateRoom &res, RequestErr err) {
check_error(err);
auto room_id = res.room_id.to_string();
bob->invite_user(room_id,
"@carl:localhost",
[room_id, bob](const mtx::responses::Empty &, RequestErr err) {
ASSERT_TRUE(err);
EXPECT_EQ(
mtx::errors::to_string(err->matrix_error.errcode),
"M_FORBIDDEN");
});
});
alice->close();
bob->close();
}
TEST(ClientAPI, Sync)
{
std::shared_ptr<Client> mtx_client = std::make_shared<Client>("localhost");
mtx_client->login(
"alice", "secret", [mtx_client](const mtx::responses::Login &, RequestErr err) {
while (mtx_client->access_token().empty())
mtx::requests::CreateRoom req;
req.name = "Name";
req.topic = "Topic";
mtx_client->create_room(
req, [mtx_client](const mtx::responses::CreateRoom &, RequestErr err) {
check_error(err);
SyncOpts opts;
opts.timeout = 0;
mtx_client->sync(opts, [](const mtx::responses::Sync &res, RequestErr err) {
check_error(err);
ASSERT_TRUE(res.rooms.join.size() > 0);
ASSERT_TRUE(res.next_batch.size() > 0);
});
TEST(ClientAPI, Versions)
{
std::shared_ptr<Client> mtx_client = std::make_shared<Client>("localhost");
mtx_client->versions([](const mtx::responses::Versions &res, RequestErr err) {
EXPECT_EQ(res.versions.size(), 7);
EXPECT_EQ(res.versions.at(0), "r0.0.1");
EXPECT_EQ(res.versions.at(1), "r0.1.0");
EXPECT_EQ(res.versions.at(2), "r0.2.0");
EXPECT_EQ(res.versions.at(3), "r0.3.0");
EXPECT_EQ(res.versions.at(4), "r0.4.0");
EXPECT_EQ(res.versions.at(5), "r0.5.0");
EXPECT_EQ(res.versions.at(6), "r0.6.0");
TEST(ClientAPI, Typing)
{
auto alice = std::make_shared<Client>("localhost");
alice->login("alice", "secret", [](const mtx::responses::Login &, RequestErr err) {
check_error(err);
});
while (alice->access_token().empty())
mtx::requests::CreateRoom req;
alice->create_room(req, [alice](const mtx::responses::CreateRoom &res, RequestErr err) {
alice->start_typing(res.room_id.to_string(), 10000, [alice, res](RequestErr err) {
const auto room_id = res.room_id.to_string();
SyncOpts opts;
opts.timeout = 0;
alice->sync(opts,
[room_id, &can_continue](const mtx::responses::Sync &res,
RequestErr err) {
check_error(err);
auto room = res.rooms.join.at(room_id);
EXPECT_EQ(room.ephemeral.typing.size(), 1);
EXPECT_EQ(room.ephemeral.typing.front(),
"@alice:localhost");
});
while (!can_continue)
alice->stop_typing(
res.room_id.to_string(), [alice, room_id](RequestErr err) {
check_error(err);
SyncOpts opts;
opts.timeout = 0;
alice->sync(
opts,
[room_id](const mtx::responses::Sync &res, RequestErr err) {
check_error(err);
auto room = res.rooms.join.at(room_id);
EXPECT_EQ(room.ephemeral.typing.size(), 0);
});
});
});
});
alice->close();
}
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
TEST(ClientAPI, Presence)
{
auto alice = std::make_shared<Client>("localhost");
alice->login("alice", "secret", [](const mtx::responses::Login &, RequestErr err) {
check_error(err);
});
while (alice->access_token().empty())
sleep();
alice->put_presence_status(
mtx::presence::unavailable, "Is this thing on?", [alice](RequestErr err) {
check_error(err);
alice->presence_status(
alice->user_id().to_string(),
[alice](const mtx::events::presence::Presence &presence, RequestErr err) {
check_error(err);
EXPECT_EQ(presence.presence, mtx::presence::unavailable);
EXPECT_EQ(presence.status_msg, "Is this thing on?");
alice->put_presence_status(
mtx::presence::offline, std::nullopt, [alice](RequestErr err) {
check_error(err);
alice->presence_status(
alice->user_id().to_string(),
[alice](const mtx::events::presence::Presence &presence,
RequestErr err) {
check_error(err);
EXPECT_EQ(presence.presence,
mtx::presence::offline);
EXPECT_TRUE(presence.status_msg.empty());
});
});
});
});
alice->close();
}
TEST(ClientAPI, PresenceOverSync)
{
auto alice = std::make_shared<Client>("localhost");
auto bob = std::make_shared<Client>("localhost");
alice->login("alice", "secret", [](const mtx::responses::Login &, RequestErr err) {
check_error(err);
});
bob->login(
"bob", "secret", [](const mtx::responses::Login &, RequestErr err) { check_error(err); });
while (alice->access_token().empty() && bob->access_token().empty())
sleep();
mtx::requests::CreateRoom req;
req.invite = {"@bob:localhost"};
alice->create_room(
req, [alice, bob](const mtx::responses::CreateRoom &res, RequestErr err) {
check_error(err);
auto room_id = res.room_id.to_string();
bob->join_room(
room_id, [alice, bob, room_id](const mtx::responses::RoomId &, RequestErr err) {
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
check_error(err);
alice->put_presence_status(
mtx::presence::unavailable,
"Is this thing on?",
[alice, bob](RequestErr err) {
check_error(err);
SyncOpts opts;
opts.timeout = 10;
opts.set_presence = mtx::presence::online;
alice->sync(
opts,
[bob, opts](const mtx::responses::Sync &, RequestErr err) {
check_error(err);
bob->sync(
opts,
[bob](const mtx::responses::Sync &s,
RequestErr err) {
check_error(err);
ASSERT_GE(s.presence.size(), 1);
bool found = false;
for (const auto &p : s.presence) {
if (p.sender ==
"@alice:localhost") {
found = true;
EXPECT_EQ(
p.content.presence,
mtx::presence::online);
EXPECT_EQ(
p.content.status_msg,
"Is this thing "
"on?");
}
EXPECT_TRUE(found);
}
});
});
});
});
});
alice->close();
}
TEST(ClientAPI, SendMessages)
{
auto alice = std::make_shared<Client>("localhost");
auto bob = std::make_shared<Client>("localhost");
alice->login("alice", "secret", [alice](const mtx::responses::Login &, RequestErr err) {
bob->login("bob", "secret", [bob](const mtx::responses::Login &, RequestErr err) {
check_error(err);
});
while (alice->access_token().empty() || bob->access_token().empty())
mtx::requests::CreateRoom req;
req.invite = {"@bob:localhost"};
alice->create_room(
req, [alice, bob](const mtx::responses::CreateRoom &res, RequestErr err) {
check_error(err);
auto room_id = res.room_id.to_string();
room_id, [alice, bob, room_id](const mtx::responses::RoomId &, RequestErr err) {