blob: b421b7131826b7aca504d120fc889daae8b36ec7 [file] [log] [blame]
// Copyright 2021 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 <fidl/fuchsia.device/cpp/wire.h>
#include <fidl/fuchsia.device/cpp/wire_test_base.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/fdio/directory.h>
#include <lib/fdio/fd.h>
#include <zircon/time.h>
#include <memory>
#include <fbl/ref_ptr.h>
#include <sdk/lib/device-watcher/cpp/device-watcher.h>
#include <zxtest/zxtest.h>
#include "src/lib/storage/vfs/cpp/managed_vfs.h"
#include "src/lib/storage/vfs/cpp/pseudo_dir.h"
#include "src/lib/storage/vfs/cpp/pseudo_file.h"
#include "src/lib/storage/vfs/cpp/service.h"
TEST(DeviceWatcherTest, Smoke) {
async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread);
auto file = fbl::MakeRefCounted<fs::UnbufferedPseudoFile>(
[](fbl::String* output) { return ZX_OK; }, [](std::string_view input) { return ZX_OK; });
auto third = fbl::MakeRefCounted<fs::PseudoDir>();
third->AddEntry("file", file);
auto second = fbl::MakeRefCounted<fs::PseudoDir>();
second->AddEntry("third", std::move(third));
auto first = fbl::MakeRefCounted<fs::PseudoDir>();
first->AddEntry("second", std::move(second));
first->AddEntry("file", file);
auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
ASSERT_EQ(ZX_OK, endpoints.status_value());
loop.StartThread();
fs::ManagedVfs vfs(loop.dispatcher());
vfs.ServeDirectory(first, std::move(endpoints->server));
fbl::unique_fd dir;
ASSERT_EQ(ZX_OK,
fdio_fd_create(endpoints->client.TakeChannel().release(), dir.reset_and_get_address()));
fbl::unique_fd out;
ASSERT_EQ(ZX_OK, device_watcher::WaitForFile(dir, "file", &out));
ASSERT_EQ(ZX_OK, device_watcher::RecursiveWaitForFile(dir, "second/third/file", &out));
ASSERT_EQ(ZX_OK, device_watcher::RecursiveWaitForFileReadOnly(dir, "second/third/file", &out));
sync_completion_t shutdown;
vfs.Shutdown([&shutdown](zx_status_t status) {
sync_completion_signal(&shutdown);
ASSERT_EQ(status, ZX_OK);
});
ASSERT_EQ(sync_completion_wait(&shutdown, zx::duration::infinite().get()), ZX_OK);
}
TEST(DeviceWatcherTest, OpenInNamespace) {
fbl::unique_fd f;
ASSERT_EQ(device_watcher::RecursiveWaitForFileReadOnly("/dev/sys/test", &f), ZX_OK);
ASSERT_EQ(device_watcher::RecursiveWaitForFile("/dev/sys/test", &f), ZX_OK);
ASSERT_EQ(device_watcher::RecursiveWaitForFile("/other-test/file", &f), ZX_ERR_NOT_SUPPORTED);
}
constexpr std::string_view kTopoPath = "/dev/test/device/out";
class ControllerImpl : public fidl::testing::WireTestBase<fuchsia_device::Controller>,
public fs::Service {
public:
explicit ControllerImpl(std::string_view topo_path, async_dispatcher_t* dispatcher)
: fs::Service([dispatcher, this](fidl::ServerEnd<fuchsia_device::Controller> server) {
fidl::BindServer(dispatcher, std::move(server), this);
return ZX_OK;
}),
topo_path_(topo_path) {}
void GetTopologicalPath(GetTopologicalPathRequestView request,
GetTopologicalPathCompleter::Sync& completer) override {
completer.ReplySuccess(fidl::StringView::FromExternal(topo_path_));
}
void NotImplemented_(const std::string& name, fidl::CompleterBase& completer) override {
FAIL("Unexpected call to ControllerImpl: %s", name.c_str());
}
private:
std::string topo_path_;
};
TEST(DeviceWatcherTest, WaitForDeviceTopologicalPath) {
async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread);
auto empty_file = fbl::MakeRefCounted<fs::UnbufferedPseudoFile>(
[](fbl::String* output) { return ZX_OK; }, [](std::string_view input) { return ZX_OK; });
auto controller1 =
fbl::MakeRefCounted<ControllerImpl>("/dev/test/not/the/one", loop.dispatcher());
auto controller2 = fbl::MakeRefCounted<ControllerImpl>(kTopoPath, loop.dispatcher());
auto first = fbl::MakeRefCounted<fs::PseudoDir>();
first->AddEntry("file", empty_file);
first->AddEntry("000", empty_file);
first->AddEntry("001", controller1);
first->AddEntry("002", controller2);
first->AddEntry("003", empty_file);
auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
ASSERT_EQ(ZX_OK, endpoints.status_value());
loop.StartThread();
fs::ManagedVfs vfs(loop.dispatcher());
vfs.ServeDirectory(first, std::move(endpoints->server));
fbl::unique_fd dir;
ASSERT_EQ(ZX_OK,
fdio_fd_create(endpoints->client.TakeChannel().release(), dir.reset_and_get_address()));
zx::status<zx::channel> status =
device_watcher::WaitForDeviceTopologicalPath(dir, std::string(kTopoPath).c_str());
ASSERT_TRUE(status.is_ok());
auto ctrl_client_end = fidl::ClientEnd<fuchsia_device::Controller>(std::move(status.value()));
fidl::WireResult result = fidl::WireCall(ctrl_client_end)->GetTopologicalPath();
ASSERT_EQ(kTopoPath, result->value()->path.get());
sync_completion_t shutdown;
vfs.Shutdown([&shutdown](zx_status_t status) {
sync_completion_signal(&shutdown);
ASSERT_EQ(status, ZX_OK);
});
ASSERT_EQ(sync_completion_wait(&shutdown, zx::duration::infinite().get()), ZX_OK);
}