blob: 79e7c4ce2b146299974c9408dfbbcea089f9e4da [file] [log] [blame]
// Copyright 2018 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 <fcntl.h>
#include <unistd.h>
#include "garnet/lib/debug_ipc/helper/fd_watcher.h"
#include "garnet/lib/debug_ipc/helper/platform_message_loop.h"
#include "gtest/gtest.h"
#if defined(__Fuchsia__)
#include <zx/socket.h>
#include "garnet/lib/debug_ipc/helper/socket_watcher.h"
#endif
namespace debug_ipc {
// This test either passes or hangs forever because the post didn't work.
// TODO(brettw) add a timeout when timers are supported in the message loop.
TEST(MessageLoop, PostQuit) {
PlatformMessageLoop loop;
loop.Init();
loop.PostTask(FROM_HERE, [loop_ptr = &loop]() { loop_ptr->QuitNow(); });
loop.Run();
loop.Cleanup();
}
TEST(MessageLoop, WatchPipeFD) {
// Make a pipe to talk about.
int pipefd[2] = {-1, -1};
ASSERT_EQ(0, pipe(pipefd));
ASSERT_NE(-1, pipefd[0]);
ASSERT_NE(-1, pipefd[1]);
int flags = fcntl(pipefd[0], F_GETFD);
flags |= O_NONBLOCK;
ASSERT_EQ(0, fcntl(pipefd[0], F_SETFD, flags));
flags = fcntl(pipefd[1], F_GETFD);
flags |= O_NONBLOCK;
ASSERT_EQ(0, fcntl(pipefd[1], F_SETFD, flags));
class ReadableWatcher : public FDWatcher {
public:
explicit ReadableWatcher(MessageLoop* loop) : loop_(loop) {}
void OnFDReadable(int fd) override { loop_->QuitNow(); }
private:
MessageLoop* loop_;
};
PlatformMessageLoop loop;
loop.Init();
// Scope everything to before MessageLoop::Cleanup().
{
ReadableWatcher watcher(&loop);
// Going to write to pipefd[0] -> read from pipefd[1].
MessageLoop::WatchHandle watch_handle =
loop.WatchFD(MessageLoop::WatchMode::kRead, pipefd[0], &watcher);
ASSERT_TRUE(watch_handle.watching());
// Enqueue a task that should cause pipefd[1] to become readable.
loop.PostTask(FROM_HERE,
[write_fd = pipefd[1]]() { write(write_fd, "Hello", 5); });
// This will quit on success because the OnFDReadable callback called
// QuitNow, or hang forever on failure.
// TODO(brettw) add a timeout when timers are supported in the message loop.
loop.Run();
}
loop.Cleanup();
}
#if defined(__Fuchsia__)
TEST(MessageLoop, ZirconSocket) {
zx::socket sender, receiver;
ASSERT_EQ(ZX_OK, zx::socket::create(ZX_SOCKET_STREAM, &sender, &receiver));
class ReadableWatcher : public SocketWatcher {
public:
explicit ReadableWatcher(MessageLoop* loop) : loop_(loop) {}
void OnSocketReadable(zx_handle_t socket_handle) override {
loop_->QuitNow();
}
private:
MessageLoop* loop_;
};
PlatformMessageLoop loop;
loop.Init();
// Scope everything to before MessageLoop::Cleanup().
{
ReadableWatcher watcher(&loop);
MessageLoop::WatchHandle watch_handle = loop.WatchSocket(
MessageLoop::WatchMode::kRead, receiver.get(), &watcher);
ASSERT_TRUE(watch_handle.watching());
// Enqueue a task that should cause receiver to become readable.
loop.PostTask(FROM_HERE,
[&sender]() { sender.write(0, "Hello", 5, nullptr); });
// This will quit on success because the OnSocketReadable callback called
// QuitNow, or hang forever on failure.
// TODO(brettw) add a timeout when timers are supported in the message loop.
loop.Run();
}
loop.Cleanup();
}
#endif
} // namespace debug_ipc