| // Copyright 2020 The Fuchsia Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include <sys/time.h> | |
| #include <condition_variable> | |
| #include <memory> | |
| #include <mutex> | |
| #include <thread> | |
| #include <gtest/gtest.h> | |
| #include "src/developer/shell/mirror/client.h" | |
| #include "src/developer/shell/mirror/command_line_options.h" | |
| #include "src/developer/shell/mirror/server.h" | |
| #include "src/developer/shell/mirror/test_shared.h" | |
| namespace shell::mirror { | |
| class ClientServerTest : public ::testing::Test { | |
| public: | |
| ClientServerTest() {} | |
| }; | |
| class MessageLoopHolder { | |
| public: | |
| explicit MessageLoopHolder(std::unique_ptr<debug_ipc::PlatformMessageLoop> ptr) | |
| : ptr_(std::move(ptr)) {} | |
| ~MessageLoopHolder() { ptr_->Cleanup(); } | |
| debug_ipc::PlatformMessageLoop* operator->() { return ptr_.get(); } | |
| debug_ipc::PlatformMessageLoop* get() { return ptr_.get(); } | |
| private: | |
| std::unique_ptr<debug_ipc::PlatformMessageLoop> ptr_; | |
| }; | |
| TEST_F(ClientServerTest, RoundTrip) { | |
| const std::string kDataDir = "/client_server_test_tmp"; | |
| FileRepo repo(&kAsyncLoopConfigNoAttachToCurrentThread); | |
| repo.InitMemRepo(kDataDir); | |
| // Generate some fake files. | |
| std::vector<std::pair<std::string, std::string>> golden = { | |
| {kDataDir + "/z.txt", ""}, | |
| {kDataDir + "/a.txt", "Once upon a midnight dreary, while I pondered, weak and weary,"}, | |
| {kDataDir + "/b.txt", "Over many a quaint and curious volume of forgotten lore"}, | |
| {kDataDir + "/c.txt", "While I nodded, nearly napping, suddenly there came a tapping,"}, | |
| {kDataDir + "/d.txt", "As of some one gently rapping, rapping at my chamber door."}}; | |
| repo.WriteFiles(golden); | |
| CommandLineOptions options; | |
| options.port = 0; | |
| options.path = kDataDir; | |
| std::condition_variable cond_var; | |
| std::mutex mutex; | |
| uint16_t port; | |
| std::thread server_thread([&options, &cond_var, &port]() { | |
| SocketServer server; | |
| SocketServer::ConnectionConfig config; | |
| config.port = options.port; | |
| config.path = options.path; | |
| Err err = server.RunInLoop(config, FROM_HERE, [&cond_var, &server, &port]() { | |
| port = server.GetPort(); | |
| cond_var.notify_all(); | |
| }); | |
| ASSERT_TRUE(err.ok()) << err.msg; | |
| }); | |
| // Wait until the server has started. | |
| { | |
| std::unique_lock<std::mutex> l(mutex); | |
| cond_var.wait(l); | |
| } | |
| std::string host_and_port = "[::1]:" + std::to_string(port); | |
| // Initialize connection and load results. | |
| client::ClientConnection load_connection; | |
| Err err = load_connection.Init(host_and_port); | |
| ASSERT_TRUE(err.ok()) << err.msg; | |
| // Impossibly high timeout, because we're a test. | |
| struct timeval tv; | |
| tv.tv_sec = 10000; | |
| tv.tv_usec = 0; | |
| Files files; | |
| err = load_connection.Load(&files, &tv); | |
| ASSERT_TRUE(err.ok()) << err.msg; | |
| // Initialize connection and kill server. | |
| client::ClientConnection kill_connection; | |
| err = kill_connection.Init(host_and_port); | |
| ASSERT_TRUE(err.ok()) << err.msg; | |
| err = kill_connection.KillServer(); | |
| ASSERT_TRUE(err.ok()) << err.msg; | |
| server_thread.join(); | |
| // Make sure results are as expected. | |
| ASSERT_EQ(files.size(), golden.size()); | |
| for (const auto& file : files) { | |
| const auto& data = file.View(); | |
| const auto& name = file.Name(); | |
| bool found = false; | |
| for (size_t i = 0; i < golden.size(); i++) { | |
| if ((golden[i].first.substr(kDataDir.length() + 1) == name) && (golden[i].second == data)) { | |
| found = true; | |
| break; | |
| } | |
| } | |
| ASSERT_TRUE(found) << "Not found in expected: " << name << " with data \"" << data << "\""; | |
| } | |
| } | |
| } // namespace shell::mirror |