blob: 2a3204d7861254da842a7c74b4bf155c75272094 [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 <fidl/fuchsia.fs/cpp/common_types.h>
#include <fidl/fuchsia.io/cpp/wire.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/fdio/cpp/caller.h>
#include <lib/fdio/directory.h>
#include <lib/fidl/cpp/wire/channel.h>
#include <lib/fidl/cpp/wire/wire_messaging_declarations.h>
#include <lib/zx/result.h>
#include <unistd.h>
#include <zircon/errors.h>
#include <zircon/limits.h>
#include <zircon/types.h>
#include <cstdint>
#include <cstring>
#include <future>
#include <span>
#include <string_view>
#include <utility>
#include <fbl/unique_fd.h>
#include <zxtest/zxtest.h>
#include "src/storage/memfs/mounted_memfs.h"
namespace {
namespace fio = fuchsia_io;
TEST(FidlTests, TestFidlBasic) {
async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread);
ASSERT_OK(loop.StartThread());
zx::result memfs = MountedMemfs::Create(loop.dispatcher(), "/fidltmp");
ASSERT_OK(memfs);
fbl::unique_fd fd(open("/fidltmp", O_DIRECTORY | O_RDONLY));
ASSERT_GE(fd.get(), 0);
// Create a file
const char* filename = "file-a";
fd.reset(openat(fd.get(), filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR));
ASSERT_GE(fd.get(), 0);
const char* data = "hello";
ssize_t datalen = strlen(data);
ASSERT_EQ(write(fd.get(), data, datalen), datalen);
fd.reset();
auto [client, server] = fidl::Endpoints<fio::File>::Create();
ASSERT_OK(fdio_open3("/fidltmp/file-a", uint64_t{fio::wire::kPermReadable},
server.TakeChannel().release()));
{
const fidl::WireResult result = fidl::WireCall(client)->Query();
ASSERT_OK(result.status());
const fidl::WireResponse response = result.value();
const std::span data = response.protocol.get();
const std::string_view protocol{reinterpret_cast<const char*>(data.data()), data.size_bytes()};
ASSERT_EQ(protocol, std::string_view{fidl::DiscoverableProtocolName<fuchsia_io::File>});
}
const fidl::WireResult describe_result = fidl::WireCall(client)->Describe();
ASSERT_OK(describe_result.status());
ASSERT_FALSE(describe_result.value().has_observer());
ASSERT_OK(fidl::WireCall(client)->Close());
client.TakeChannel();
std::promise<zx_status_t> promise;
memfs.value()->Shutdown([&promise](zx_status_t status) { promise.set_value(status); });
ASSERT_EQ(promise.get_future().get(), ZX_OK);
loop.Shutdown();
}
TEST(FidlTests, TestFidlOpenReadOnly) {
async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread);
ASSERT_OK(loop.StartThread());
zx::result memfs = MountedMemfs::Create(loop.dispatcher(), "/fidltmp-ro");
ASSERT_OK(memfs);
fbl::unique_fd fd(open("/fidltmp-ro", O_DIRECTORY | O_RDONLY));
ASSERT_GE(fd.get(), 0);
// Create a file
const char* filename = "file-ro";
fd.reset(openat(fd.get(), filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR));
ASSERT_GE(fd.get(), 0);
fd.reset();
auto endpoints = fidl::Endpoints<fio::Node>::Create();
ASSERT_OK(fdio_open3("/fidltmp-ro/file-ro", static_cast<uint64_t>(fio::wire::kPermReadable),
endpoints.server.TakeChannel().release()));
auto result = fidl::WireCall(endpoints.client)->DeprecatedGetFlags();
ASSERT_OK(result.status());
ASSERT_OK(result->s);
ASSERT_EQ(result->flags, fio::wire::OpenFlags::kRightReadable);
endpoints.client.TakeChannel().reset();
std::promise<zx_status_t> promise;
memfs.value()->Shutdown([&promise](zx_status_t status) { promise.set_value(status); });
ASSERT_EQ(promise.get_future().get(), ZX_OK);
loop.Shutdown();
}
void QueryInfo(const char* path, fuchsia_io::wire::FilesystemInfo* info) {
fbl::unique_fd fd(open(path, O_RDONLY | O_DIRECTORY));
ASSERT_TRUE(fd);
fdio_cpp::FdioCaller caller(std::move(fd));
auto result = fidl::WireCall(caller.node())->QueryFilesystem();
ASSERT_OK(result.status());
ASSERT_OK(result->s);
ASSERT_NOT_NULL(result->info.get());
*info = *(result->info);
const char* kFsName = "memfs";
const char* name = reinterpret_cast<const char*>(info->name.data());
ASSERT_EQ(strncmp(name, kFsName, strlen(kFsName)), 0, "Unexpected filesystem mounted");
ASSERT_EQ(info->block_size, zx_system_get_page_size());
ASSERT_EQ(info->max_filename_size, NAME_MAX);
ASSERT_EQ(info->fs_type, fidl::ToUnderlying(fuchsia_fs::VfsType::kMemfs));
ASSERT_NE(info->fs_id, 0);
ASSERT_EQ(info->used_bytes % info->block_size, 0);
}
TEST(FidlTests, TestFidlQueryFilesystem) {
async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread);
ASSERT_OK(loop.StartThread());
zx::result memfs = MountedMemfs::Create(loop.dispatcher(), "/fidltmp-basic");
ASSERT_OK(memfs);
fbl::unique_fd fd(open("/fidltmp-basic", O_DIRECTORY | O_RDONLY));
ASSERT_GE(fd.get(), 0);
// Sanity checks
fuchsia_io::wire::FilesystemInfo info;
ASSERT_NO_FATAL_FAILURE(QueryInfo("/fidltmp-basic", &info));
// These values are nonsense, but they're the nonsense we expect memfs to generate.
ASSERT_EQ(info.total_bytes, UINT64_MAX);
ASSERT_EQ(info.used_bytes, 0);
std::promise<zx_status_t> promise;
memfs.value()->Shutdown([&promise](zx_status_t status) { promise.set_value(status); });
ASSERT_EQ(promise.get_future().get(), ZX_OK);
loop.Shutdown();
}
} // namespace