blob: 32026adfb1194cc211b42607adf2e2a70776cfb7 [file] [log] [blame]
// 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