From e1ec72eab6d00b3ba38e5932bc88920f103b6e4a Mon Sep 17 00:00:00 2001 From: aunsane Date: Fri, 27 Apr 2018 21:33:17 +0300 Subject: Telegram: initial commit - tdlib moved to telegram dir --- protocols/Telegram/tdlib/td/test/tdclient.cpp | 837 ++++++++++++++++++++++++++ 1 file changed, 837 insertions(+) create mode 100644 protocols/Telegram/tdlib/td/test/tdclient.cpp (limited to 'protocols/Telegram/tdlib/td/test/tdclient.cpp') diff --git a/protocols/Telegram/tdlib/td/test/tdclient.cpp b/protocols/Telegram/tdlib/td/test/tdclient.cpp new file mode 100644 index 0000000000..7cef0fcbc0 --- /dev/null +++ b/protocols/Telegram/tdlib/td/test/tdclient.cpp @@ -0,0 +1,837 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#include "data.h" + +#include "td/actor/PromiseFuture.h" + +#include "td/telegram/ClientActor.h" + +#include "td/telegram/td_api.h" + +#include "td/utils/base64.h" +#include "td/utils/BufferedFd.h" +#include "td/utils/filesystem.h" +#include "td/utils/format.h" +#include "td/utils/logging.h" +#include "td/utils/misc.h" +#include "td/utils/port/FileFd.h" +#include "td/utils/port/path.h" +#include "td/utils/Random.h" +#include "td/utils/Slice.h" +#include "td/utils/Status.h" +#include "td/utils/tests.h" + +#include +#include +#include +#include +#include + +REGISTER_TESTS(tdclient); + +namespace td { + +template +static void check_td_error(T &result) { + CHECK(result->get_id() != td_api::error::ID) << to_string(result); +} + +static void rmrf(CSlice path) { + td::walk_path(path, [](CSlice path, bool is_dir) { + if (is_dir) { + td::rmdir(path).ignore(); + } else { + td::unlink(path).ignore(); + } + }); +} + +class TestClient : public Actor { + public: + explicit TestClient(string name) : name_(std::move(name)) { + } + struct Update { + uint64 id; + tl_object_ptr object; + Update(uint64 id, tl_object_ptr object) : id(id), object(std::move(object)) { + } + }; + class Listener { + public: + Listener() = default; + Listener(const Listener &) = delete; + Listener &operator=(const Listener &) = delete; + Listener(Listener &&) = delete; + Listener &operator=(Listener &&) = delete; + virtual ~Listener() = default; + virtual void start_listen(TestClient *client) { + } + virtual void stop_listen() { + } + virtual void on_update(std::shared_ptr update) = 0; + }; + void close(Promise<> close_promise) { + close_promise_ = std::move(close_promise); + td_.reset(); + } + + unique_ptr make_td_callback() { + class TdCallbackImpl : public TdCallback { + public: + explicit TdCallbackImpl(ActorId client) : client_(client) { + } + void on_result(uint64 id, tl_object_ptr result) override { + send_closure(client_, &TestClient::on_result, id, std::move(result)); + } + void on_error(uint64 id, tl_object_ptr error) override { + send_closure(client_, &TestClient::on_error, id, std::move(error)); + } + void on_closed() override { + send_closure(client_, &TestClient::on_closed); + } + + private: + ActorId client_; + }; + return make_unique(actor_id(this)); + } + + void add_listener(std::unique_ptr listener) { + auto *ptr = listener.get(); + listeners_.push_back(std::move(listener)); + ptr->start_listen(this); + } + void remove_listener(Listener *listener) { + pending_remove_.push_back(listener); + } + void do_pending_remove_listeners() { + for (auto listener : pending_remove_) { + do_remove_listener(listener); + } + pending_remove_.clear(); + } + void do_remove_listener(Listener *listener) { + for (size_t i = 0; i < listeners_.size(); i++) { + if (listeners_[i].get() == listener) { + listener->stop_listen(); + listeners_.erase(listeners_.begin() + i); + break; + } + } + } + + void on_result(uint64 id, tl_object_ptr result) { + on_update(std::make_shared(id, std::move(result))); + } + void on_error(uint64 id, tl_object_ptr error) { + on_update(std::make_shared(id, std::move(error))); + } + void on_update(std::shared_ptr update) { + for (auto &listener : listeners_) { + listener->on_update(update); + } + do_pending_remove_listeners(); + } + + void on_closed() { + stop(); + } + + void start_up() override { + rmrf(name_); + set_context(std::make_shared()); + set_tag(name_); + LOG(INFO) << "START UP!"; + + td_ = create_actor("Td-proxy", make_td_callback()); + } + + ActorOwn td_; + + string name_; + + private: + std::vector> listeners_; + std::vector pending_remove_; + + Promise<> close_promise_; +}; + +class Task : public TestClient::Listener { + public: + void on_update(std::shared_ptr update) override { + auto it = sent_queries_.find(update->id); + if (it != sent_queries_.end()) { + it->second(std::move(update->object)); + sent_queries_.erase(it); + } + process_update(update); + } + void start_listen(TestClient *client) override { + client_ = client; + start_up(); + } + virtual void process_update(std::shared_ptr update) { + } + + template + void send_query(tl_object_ptr function, F callback) { + auto id = current_query_id_++; + sent_queries_[id] = std::forward(callback); + send_closure(client_->td_, &ClientActor::request, id, std::move(function)); + } + + protected: + std::map)>> sent_queries_; + TestClient *client_; + uint64 current_query_id_ = 1; + + virtual void start_up() { + } + void stop() { + client_->remove_listener(this); + } +}; + +class DoAuthentication : public Task { + public: + DoAuthentication(string name, string phone, string code, Promise<> promise) + : name_(std::move(name)), phone_(std::move(phone)), code_(std::move(code)), promise_(std::move(promise)) { + } + void start_up() override { + send_query(make_tl_object(), + [this](auto res) { this->process_authorization_state(std::move(res)); }); + } + void process_authorization_state(tl_object_ptr authorization_state) { + start_flag_ = true; + tl_object_ptr function; + switch (authorization_state->get_id()) { + case td_api::authorizationStateWaitEncryptionKey::ID: + function = make_tl_object(); + break; + case td_api::authorizationStateWaitPhoneNumber::ID: + function = make_tl_object(phone_, false, true); + break; + case td_api::authorizationStateWaitCode::ID: + function = make_tl_object(code_, name_, ""); + break; + case td_api::authorizationStateWaitTdlibParameters::ID: { + auto parameters = td_api::make_object(); + parameters->use_test_dc_ = true; + parameters->database_directory_ = name_ + TD_DIR_SLASH; + parameters->use_message_database_ = true; + parameters->use_secret_chats_ = true; + parameters->api_id_ = 94575; + parameters->api_hash_ = "a3406de8d171bb422bb6ddf3bbd800e2"; + parameters->system_language_code_ = "en"; + parameters->device_model_ = "Desktop"; + parameters->system_version_ = "Unknown"; + parameters->application_version_ = "tdclient-test"; + parameters->ignore_file_names_ = false; + parameters->enable_storage_optimizer_ = true; + function = td_api::make_object(std::move(parameters)); + break; + } + case td_api::authorizationStateReady::ID: + on_authorization_ready(); + return; + default: + CHECK(false) << "Unexpected authorization state " << to_string(authorization_state); + } + send_query(std::move(function), [this](auto res) { CHECK(res->get_id() == td_api::ok::ID) << to_string(res); }); + } + void on_authorization_ready() { + LOG(INFO) << "GOT AUTHORIZED"; + stop(); + } + + private: + string name_; + string phone_; + string code_; + Promise<> promise_; + bool start_flag_{false}; + void process_update(std::shared_ptr update) override { + if (!start_flag_) { + return; + } + if (!update->object) { + return; + } + if (update->object->get_id() == td_api::updateAuthorizationState::ID) { + auto o = std::move(update->object); + process_authorization_state(std::move(static_cast(*o).authorization_state_)); + } + } +}; + +class SetUsername : public Task { + public: + SetUsername(string username, Promise<> promise) : username_(std::move(username)), promise_(std::move(promise)) { + } + + private: + string username_; + Promise<> promise_; + int32 self_id_; + string tag_; + + void start_up() override { + send_query(make_tl_object(), [this](auto res) { this->process_me_user(std::move(res)); }); + } + + void process_me_user(tl_object_ptr res) { + CHECK(res->get_id() == td_api::user::ID); + auto user = move_tl_object_as(res); + self_id_ = user->id_; + if (user->username_ != username_) { + LOG(INFO) << "SET USERNAME: " << username_; + send_query(make_tl_object(username_), [this](auto res) { + CHECK(res->get_id() == td_api::ok::ID); + this->send_self_message(); + }); + } else { + send_self_message(); + } + } + void send_self_message() { + tag_ = PSTRING() << format::as_hex(Random::secure_int64()); + + send_query(make_tl_object(self_id_, false), [this](auto res) { + CHECK(res->get_id() == td_api::chat::ID); + auto chat = move_tl_object_as(res); + this->send_query( + make_tl_object( + chat->id_, 0, false, false, nullptr, + make_tl_object( + make_tl_object(PSTRING() << tag_ << " INIT", Auto()), false, false)), + [](auto res) {}); + }); + } + + void process_update(std::shared_ptr update) override { + if (!update->object) { + return; + } + if (update->object->get_id() == td_api::updateMessageSendSucceeded::ID) { + auto updateNewMessage = move_tl_object_as(update->object); + auto &message = updateNewMessage->message_; + if (message->content_->get_id() == td_api::messageText::ID) { + auto messageText = move_tl_object_as(message->content_); + auto text = messageText->text_->text_; + if (text.substr(0, tag_.size()) == tag_) { + LOG(INFO) << "GOT SELF MESSAGE"; + return stop(); + } + } + } + } +}; + +class CheckTestA : public Task { + public: + CheckTestA(string tag, Promise<> promise) : tag_(std::move(tag)), promise_(std::move(promise)) { + } + + private: + string tag_; + Promise<> promise_; + string previous_text_; + int cnt_ = 20; + void process_update(std::shared_ptr update) override { + if (update->object->get_id() == td_api::updateNewMessage::ID) { + auto updateNewMessage = move_tl_object_as(update->object); + auto &message = updateNewMessage->message_; + if (message->content_->get_id() == td_api::messageText::ID) { + auto messageText = move_tl_object_as(message->content_); + auto text = messageText->text_->text_; + if (text.substr(0, tag_.size()) == tag_) { + CHECK(text > previous_text_) << tag("now", text) << tag("previous", previous_text_); + previous_text_ = text; + cnt_--; + LOG(INFO) << "GOT " << tag("text", text) << tag("left", cnt_); + if (cnt_ == 0) { + return stop(); + } + } + } + } + } +}; + +class TestA : public Task { + public: + TestA(string tag, string username) : tag_(std::move(tag)), username_(std::move(username)) { + } + void start_up() override { + send_query(make_tl_object(username_), [this](auto res) { + CHECK(res->get_id() == td_api::chat::ID); + auto chat = move_tl_object_as(res); + for (int i = 0; i < 20; i++) { + this->send_query(make_tl_object( + chat->id_, 0, false, false, nullptr, + make_tl_object( + make_tl_object(PSTRING() << tag_ << " " << (1000 + i), Auto()), + false, false)), + [&](auto res) { this->stop(); }); + } + }); + } + + private: + string tag_; + string username_; +}; + +class TestSecretChat : public Task { + public: + TestSecretChat(string tag, string username) : tag_(std::move(tag)), username_(std::move(username)) { + } + + void start_up() override { + auto f = [this](auto res) { + CHECK(res->get_id() == td_api::chat::ID); + auto chat = move_tl_object_as(res); + this->chat_id_ = chat->id_; + this->secret_chat_id_ = move_tl_object_as(chat->type_)->secret_chat_id_; + }; + send_query(make_tl_object(username_), [this, f = std::move(f)](auto res) mutable { + CHECK(res->get_id() == td_api::chat::ID); + auto chat = move_tl_object_as(res); + CHECK(chat->type_->get_id() == td_api::chatTypePrivate::ID); + auto info = move_tl_object_as(chat->type_); + this->send_query(make_tl_object(info->user_id_), std::move(f)); + }); + } + + void process_update(std::shared_ptr update) override { + if (!update->object) { + return; + } + if (update->object->get_id() == td_api::updateSecretChat::ID) { + auto update_secret_chat = move_tl_object_as(update->object); + if (update_secret_chat->secret_chat_->id_ != secret_chat_id_ || + update_secret_chat->secret_chat_->state_->get_id() != td_api::secretChatStateReady::ID) { + return; + } + LOG(INFO) << "SEND ENCRYPTED MESSAGES"; + for (int i = 0; i < 20; i++) { + send_query(make_tl_object( + chat_id_, 0, false, false, nullptr, + make_tl_object( + make_tl_object(PSTRING() << tag_ << " " << (1000 + i), Auto()), false, + false)), + [](auto res) {}); + } + } + } + + private: + string tag_; + string username_; + int64 secret_chat_id_ = 0; + int64 chat_id_ = 0; +}; + +class TestFileGenerated : public Task { + public: + TestFileGenerated(string tag, string username) : tag_(std::move(tag)), username_(std::move(username)) { + } + + void start_up() override { + } + + void process_update(std::shared_ptr update) override { + if (!update->object) { + return; + } + if (update->object->get_id() == td_api::updateNewMessage::ID) { + auto updateNewMessage = move_tl_object_as(update->object); + auto &message = updateNewMessage->message_; + chat_id_ = message->chat_id_; + if (message->content_->get_id() == td_api::messageText::ID) { + auto messageText = move_tl_object_as(message->content_); + auto text = messageText->text_->text_; + if (text.substr(0, tag_.size()) == tag_) { + if (text.substr(tag_.size() + 1) == "ONE_FILE") { + return one_file(); + } + } + } + } else if (update->object->get_id() == td_api::updateFileGenerationStart::ID) { + auto info = move_tl_object_as(update->object); + generate_file(info->generation_id_, info->original_path_, info->destination_path_, info->conversion_); + } else if (update->object->get_id() == td_api::updateFile::ID) { + auto file = move_tl_object_as(update->object); + LOG(INFO) << to_string(file); + } + } + void one_file() { + LOG(ERROR) << "Start ONE_FILE test"; + string file_path = string("test_documents") + TD_DIR_SLASH + "a.txt"; + mkpath(file_path).ensure(); + auto raw_file = + FileFd::open(file_path, FileFd::Flags::Create | FileFd::Flags::Truncate | FileFd::Flags::Write).move_as_ok(); + auto file = BufferedFd(std::move(raw_file)); + for (int i = 1; i < 100000; i++) { + file.write(PSLICE() << i << "\n").ensure(); + } + file.flush_write().ensure(); // important + file.close(); + this->send_query(make_tl_object( + chat_id_, 0, false, false, nullptr, + make_tl_object( + make_tl_object(file_path, "square", 0), + make_tl_object( + make_tl_object(file_path, "thumbnail", 0), 0, 0), + make_tl_object(tag_, Auto()))), + [](auto res) { check_td_error(res); }); + + this->send_query( + make_tl_object(chat_id_, 0, false, false, nullptr, + make_tl_object( + make_tl_object(file_path, "square", 0), + nullptr, make_tl_object(tag_, Auto()))), + [](auto res) { check_td_error(res); }); + } + + friend class GenerateFile; + class GenerateFile : public Actor { + public: + GenerateFile(Task *parent, int64 id, string original_path, string destination_path, string conversion) + : parent_(parent) + , id_(id) + , original_path_(std::move(original_path)) + , destination_path_(std::move(destination_path)) + , conversion_(std::move(conversion)) { + } + + private: + Task *parent_; + int64 id_; + string original_path_; + string destination_path_; + string conversion_; + + FILE *from = nullptr; + FILE *to = nullptr; + + void start_up() override { + from = std::fopen(original_path_.c_str(), "rb"); + CHECK(from); + to = std::fopen(destination_path_.c_str(), "wb"); + CHECK(to); + yield(); + } + void loop() override { + int cnt = 0; + while (true) { + uint32 x; + auto r = std::fscanf(from, "%u", &x); + if (r != 1) { + return stop(); + } + std::fprintf(to, "%u\n", x * x); + if (++cnt >= 10000) { + break; + } + } + auto ready = std::ftell(to); + LOG(ERROR) << "READY: " << ready; + parent_->send_query(make_tl_object( + id_, 1039823 /*yeah, exact size of this file*/, narrow_cast(ready)), + [](auto result) { check_td_error(result); }); + set_timeout_in(0.02); + } + void tear_down() override { + std::fclose(from); + std::fclose(to); + parent_->send_query(make_tl_object(id_, nullptr), + [](auto result) { check_td_error(result); }); + } + }; + void generate_file(int64 id, string original_path, string destination_path, string conversion) { + LOG(ERROR) << "Generate file " << tag("id", id) << tag("original_path", original_path) + << tag("destination_path", destination_path) << tag("conversion", conversion); + if (conversion == "square") { + create_actor("GenerateFile", this, id, original_path, destination_path, conversion).release(); + } else if (conversion == "thumbnail") { + write_file(destination_path, base64url_decode(Slice(thumbnail, thumbnail_size)).ok()).ensure(); + this->send_query(make_tl_object(id, nullptr), + [](auto result) { check_td_error(result); }); + } else { + LOG(FATAL) << "unknown " << tag("conversion", conversion); + } + } + + private: + string tag_; + string username_; + int64 chat_id_ = 0; +}; + +class CheckTestC : public Task { + public: + CheckTestC(string username, string tag, Promise<> promise) + : username_(std::move(username)), tag_(std::move(tag)), promise_(std::move(promise)) { + } + + void start_up() override { + send_query(make_tl_object(username_), [this](auto res) { + CHECK(res->get_id() == td_api::chat::ID); + auto chat = move_tl_object_as(res); + chat_id_ = chat->id_; + this->one_file(); + }); + } + + private: + string username_; + string tag_; + Promise<> promise_; + int64 chat_id_; + + void one_file() { + this->send_query( + make_tl_object( + chat_id_, 0, false, false, nullptr, + make_tl_object( + make_tl_object(PSTRING() << tag_ << " ONE_FILE", Auto()), false, false)), + [](auto res) { check_td_error(res); }); + } + + void process_update(std::shared_ptr update) override { + if (!update->object) { + return; + } + if (update->object->get_id() == td_api::updateNewMessage::ID) { + auto updateNewMessage = move_tl_object_as(update->object); + auto &message = updateNewMessage->message_; + if (message->content_->get_id() == td_api::messageDocument::ID) { + auto messageDocument = move_tl_object_as(message->content_); + auto text = messageDocument->caption_->text_; + if (text.substr(0, tag_.size()) == tag_) { + file_id_to_check_ = messageDocument->document_->document_->id_; + LOG(ERROR) << "GOT FILE " << to_string(messageDocument->document_->document_); + this->send_query(make_tl_object(file_id_to_check_, 1), + [](auto res) { check_td_error(res); }); + } + } + } else if (update->object->get_id() == td_api::updateFile::ID) { + auto updateFile = move_tl_object_as(update->object); + if (updateFile->file_->id_ == file_id_to_check_ && (updateFile->file_->local_->is_downloading_completed_)) { + check_file(updateFile->file_->local_->path_); + } + } + } + + void check_file(CSlice path) { + FILE *from = std::fopen(path.c_str(), "rb"); + CHECK(from); + uint32 x; + uint32 y = 1; + while (std::fscanf(from, "%u", &x) == 1) { + CHECK(x == y * y); + y++; + } + std::fclose(from); + stop(); + } + int32 file_id_to_check_ = 0; +}; + +class LoginTestActor : public Actor { + public: + explicit LoginTestActor(Status *status) : status_(status) { + *status_ = Status::OK(); + } + + private: + Status *status_; + ActorOwn alice_; + ActorOwn bob_; + + string alice_phone_ = "9996636437"; + string bob_phone_ = "9996636438"; + string alice_username_ = "alice_" + alice_phone_; + string bob_username_ = "bob_" + bob_phone_; + + string stage_name_; + + void begin_stage(string stage_name, double timeout) { + LOG(WARNING) << "Begin stage '" << stage_name << "'"; + stage_name_ = std::move(stage_name); + set_timeout_in(timeout); + } + + void start_up() override { + begin_stage("Logging in", 160); + alice_ = create_actor("AliceClient", "alice"); + bob_ = create_actor("BobClient", "bob"); + + send_closure(alice_, &TestClient::add_listener, + std::make_unique( + "alice", alice_phone_, "33333", + PromiseCreator::event(self_closure(this, &LoginTestActor::start_up_fence_dec)))); + + send_closure(bob_, &TestClient::add_listener, + std::make_unique( + "bob", bob_phone_, "33333", + PromiseCreator::event(self_closure(this, &LoginTestActor::start_up_fence_dec)))); + } + + int start_up_fence_ = 3; + void start_up_fence_dec() { + --start_up_fence_; + if (start_up_fence_ == 0) { + init(); + } else if (start_up_fence_ == 1) { + return init(); + class WaitActor : public Actor { + public: + WaitActor(double timeout, Promise<> promise) : timeout_(timeout), promise_(std::move(promise)) { + } + void start_up() override { + set_timeout_in(timeout_); + } + void timeout_expired() override { + stop(); + } + + private: + double timeout_; + Promise<> promise_; + }; + create_actor("WaitActor", 2, + PromiseCreator::event(self_closure(this, &LoginTestActor::start_up_fence_dec))) + .release(); + } + } + + void init() { + send_closure(alice_, &TestClient::add_listener, + std::make_unique( + alice_username_, PromiseCreator::event(self_closure(this, &LoginTestActor::init_fence_dec)))); + send_closure(bob_, &TestClient::add_listener, + std::make_unique( + bob_username_, PromiseCreator::event(self_closure(this, &LoginTestActor::init_fence_dec)))); + } + + int init_fence_ = 2; + void init_fence_dec() { + if (--init_fence_ == 0) { + test_a(); + } + } + + int32 test_a_fence_ = 2; + void test_a_fence() { + if (--test_a_fence_ == 0) { + test_b(); + } + } + + void test_a() { + begin_stage("Ready to create chats", 80); + string alice_tag = PSTRING() << format::as_hex(Random::secure_int64()); + string bob_tag = PSTRING() << format::as_hex(Random::secure_int64()); + + send_closure(bob_, &TestClient::add_listener, + std::make_unique( + alice_tag, PromiseCreator::event(self_closure(this, &LoginTestActor::test_a_fence)))); + send_closure(alice_, &TestClient::add_listener, + std::make_unique( + bob_tag, PromiseCreator::event(self_closure(this, &LoginTestActor::test_a_fence)))); + + send_closure(alice_, &TestClient::add_listener, std::make_unique(alice_tag, bob_username_)); + send_closure(bob_, &TestClient::add_listener, std::make_unique(bob_tag, alice_username_)); + // send_closure(alice_, &TestClient::add_listener, std::make_unique(bob_username_)); + } + + void timeout_expired() override { + LOG(FATAL) << "Timeout expired in stage '" << stage_name_ << "'"; + } + + int32 test_b_fence_ = 1; + void test_b_fence() { + if (--test_b_fence_ == 0) { + test_c(); + } + } + + int32 test_c_fence_ = 1; + void test_c_fence() { + if (--test_c_fence_ == 0) { + finish(); + } + } + + void test_b() { + begin_stage("Create secret chat", 40); + string tag = PSTRING() << format::as_hex(Random::secure_int64()); + + send_closure( + bob_, &TestClient::add_listener, + std::make_unique(tag, PromiseCreator::event(self_closure(this, &LoginTestActor::test_b_fence)))); + send_closure(alice_, &TestClient::add_listener, std::make_unique(tag, bob_username_)); + } + + void test_c() { + begin_stage("Send generated file", 240); + string tag = PSTRING() << format::as_hex(Random::secure_int64()); + + send_closure(bob_, &TestClient::add_listener, + std::make_unique( + alice_username_, tag, PromiseCreator::event(self_closure(this, &LoginTestActor::test_c_fence)))); + send_closure(alice_, &TestClient::add_listener, std::make_unique(tag, bob_username_)); + } + + int32 finish_fence_ = 2; + void finish_fence() { + finish_fence_--; + if (finish_fence_ == 0) { + Scheduler::instance()->finish(); + stop(); + } + } + void finish() { + send_closure(alice_, &TestClient::close, PromiseCreator::event(self_closure(this, &LoginTestActor::finish_fence))); + send_closure(bob_, &TestClient::close, PromiseCreator::event(self_closure(this, &LoginTestActor::finish_fence))); + } +}; + +class Tdclient_login : public td::Test { + public: + using Test::Test; + bool step() final { + if (!is_inited_) { + SET_VERBOSITY_LEVEL(VERBOSITY_NAME(DEBUG) + 2); + sched_.init(4); + sched_.create_actor_unsafe(0, "LoginTestActor", &result_).release(); + sched_.start(); + is_inited_ = true; + } + + bool ret = sched_.run_main(10); + if (ret) { + return true; + } + sched_.finish(); + if (result_.is_error()) { + LOG(ERROR) << result_; + } + ASSERT_TRUE(result_.is_ok()); + return false; + } + + private: + bool is_inited_ = false; + ConcurrentScheduler sched_; + Status result_; +}; +Tdclient_login Tdclient_login("Tdclient_login"); +}; // namespace td -- cgit v1.2.3