blob: 4a27333f06d0acca3c8235ee75ccb9a11022222c [file] [log] [blame]
// Copyright 2019 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 <fuchsia/io/llcpp/fidl.h>
#include <fuchsia/io/llcpp/fidl_test_base.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/fdio/fd.h>
#include <lib/fdio/watcher.h>
#include <lib/fidl-async/cpp/bind.h>
#include <lib/zx/time.h>
#include <vector>
#include <fbl/unique_fd.h>
#include <zxtest/zxtest.h>
TEST(WatcherTest, WatchInvalidDirFD) {
ASSERT_STATUS(fdio_watch_directory(-1, nullptr, ZX_TIME_INFINITE, nullptr), ZX_ERR_INVALID_ARGS);
}
template <typename F>
class Server final : public fuchsia_io::testing::Directory_TestBase {
public:
explicit Server(F onWatch) : onWatch_(onWatch) {}
void NotImplemented_(const std::string& name, fidl::CompleterBase& completer) override {
ADD_FAILURE("%s should not be called", name.c_str());
completer.Close(ZX_ERR_NOT_SUPPORTED);
}
void Close(Interface::CloseCompleter::Sync& completer) override { completer.Reply(ZX_OK); }
void Describe(Interface::DescribeCompleter::Sync& completer) override {
fuchsia_io::wire::DirectoryObject directory;
completer.Reply(fuchsia_io::wire::NodeInfo::WithDirectory(
fidl::ObjectView<fuchsia_io::wire::DirectoryObject>::FromExternal(&directory)));
}
void Watch(uint32_t mask, uint32_t options, zx::channel watcher,
Interface::WatchCompleter::Sync& completer) override {
onWatch_(mask, options, std::move(watcher), completer);
}
private:
F onWatch_;
};
TEST(WatcherTest, Smoke) {
auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
ASSERT_OK(endpoints.status_value());
Server server([](uint32_t mask, uint32_t options, zx::channel watcher,
fidl::WireInterface<fuchsia_io::Directory>::WatchCompleter::Sync& completer) {
uint8_t bytes[fuchsia_io::wire::MAX_BUF];
auto it = std::begin(bytes);
{
constexpr char name[] = "unsupported";
*it++ = fuchsia_io::wire::WATCH_EVENT_IDLE + 1;
*it++ = sizeof(name);
it = std::copy(std::cbegin(name), std::cend(name), it);
}
{
constexpr char name[] = "valid";
*it++ = fuchsia_io::wire::WATCH_EVENT_ADDED;
*it++ = sizeof(name);
it = std::copy(std::cbegin(name), std::cend(name), it);
}
{
// Incomplete; event without name.
*it++ = fuchsia_io::wire::WATCH_EVENT_ADDED;
*it++ = 1;
}
completer.Reply(watcher.write(0, bytes, std::distance(std::begin(bytes), it), nullptr, 0));
});
async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread);
ASSERT_OK(fidl::BindSingleInFlightOnly(loop.dispatcher(), std::move(endpoints->server), &server));
ASSERT_OK(loop.StartThread("fake-directory-server"));
fbl::unique_fd directory;
ASSERT_OK(
fdio_fd_create(endpoints->client.channel().release(), directory.reset_and_get_address()));
std::vector<std::pair<int, std::string>> events;
ASSERT_STATUS(fdio_watch_directory(
directory.get(),
[](int dirfd, int event, const char* name, void* cookie) {
auto events_cookie = reinterpret_cast<decltype(events)*>(cookie);
events_cookie->emplace_back(event, std::string(name));
return ZX_OK;
},
zx::time::infinite().get(), &events),
ZX_ERR_PEER_CLOSED);
decltype(events) expected_events = {{WATCH_EVENT_ADD_FILE, "valid"}};
ASSERT_EQ(events, expected_events);
}