blob: df6fdb086ae7632916ca2ad7f7202464c313c105 [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 <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <fuchsia/io/llcpp/fidl.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 <lib/fdio/fdio.h>
#include <lib/memfs/cpp/vnode.h>
#include <lib/memfs/memfs.h>
#include <lib/zx/channel.h>
#include <lib/zx/vmo.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <threads.h>
#include <unistd.h>
#include <zircon/processargs.h>
#include <zircon/syscalls.h>
#include <fbl/unique_fd.h>
#include <unittest/unittest.h>
namespace {
namespace fio = ::llcpp::fuchsia::io;
bool test_vmofile_basic() {
BEGIN_TEST;
async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread);
ASSERT_EQ(loop.StartThread(), ZX_OK);
async_dispatcher_t* dispatcher = loop.dispatcher();
zx::channel client, server;
ASSERT_EQ(zx::channel::create(0, &client, &server), ZX_OK);
std::unique_ptr<memfs::Vfs> vfs;
fbl::RefPtr<memfs::VnodeDir> root;
ASSERT_EQ(memfs::Vfs::Create("<tmp>", 1000, &vfs, &root), ZX_OK);
vfs->SetDispatcher(dispatcher);
zx::vmo backing_vmo;
ASSERT_EQ(zx::vmo::create(64, 0, &backing_vmo), ZX_OK);
ASSERT_EQ(backing_vmo.write("hello, world!", 0, 13), ZX_OK);
ASSERT_EQ(vfs->CreateFromVmo(root.get(), "greeting", backing_vmo.get(), 0, 13), ZX_OK);
ASSERT_EQ(vfs->ServeDirectory(std::move(root), std::move(server)), ZX_OK);
zx::channel h, request;
ASSERT_EQ(zx::channel::create(0, &h, &request), ZX_OK);
auto open_result =
fio::Directory::Call::Open(zx::unowned_channel(client), fio::OPEN_RIGHT_READABLE, 0,
fidl::StringView("greeting"), std::move(request));
ASSERT_EQ(open_result.status(), ZX_OK);
auto get_result = fio::File::Call::GetBuffer(zx::unowned_channel(h), fio::VMO_FLAG_READ);
ASSERT_EQ(get_result.status(), ZX_OK);
ASSERT_EQ(get_result.Unwrap()->s, ZX_OK);
llcpp::fuchsia::mem::Buffer* buffer = get_result.Unwrap()->buffer;
ASSERT_TRUE(buffer->vmo.is_valid());
ASSERT_EQ(buffer->size, 13);
auto describe_result = fio::File::Call::Describe(zx::unowned_channel(h));
ASSERT_EQ(describe_result.status(), ZX_OK);
fio::NodeInfo* info = &describe_result.Unwrap()->info;
ASSERT_TRUE(info->is_vmofile());
ASSERT_EQ(info->vmofile().offset, 0u);
ASSERT_EQ(info->vmofile().length, 13u);
auto seek_result = fio::File::Call::Seek(zx::unowned_channel(h), 7u, fio::SeekOrigin::START);
ASSERT_EQ(seek_result.status(), ZX_OK);
ASSERT_EQ(seek_result.Unwrap()->s, ZX_OK);
ASSERT_EQ(seek_result.Unwrap()->offset, 7u);
describe_result = fio::File::Call::Describe(zx::unowned_channel(h));
ASSERT_EQ(describe_result.status(), ZX_OK);
info = &describe_result.Unwrap()->info;
ASSERT_TRUE(info->is_vmofile());
ASSERT_EQ(info->vmofile().offset, 0u);
ASSERT_EQ(info->vmofile().length, 13u);
h.reset();
sync_completion_t completion;
vfs->Shutdown([&completion](zx_status_t status) {
EXPECT_EQ(status, ZX_OK);
sync_completion_signal(&completion);
});
// The following sequence of events must occur to terminate cleanly:
// 1) Invoke "vfs.Shutdown", passing a closure.
// 2) Wait for the closure to be invoked, and for |completion| to be signalled. This implies
// that Shutdown no longer relies on the dispatch loop, nor will it attempt to continue
// accessing |completion|.
// 3) Shutdown the dispatch loop.
//
// If the dispatch loop is terminated too before the vfs shutdown task completes, it may see
// "ZX_ERR_CANCELED" posted to the "vfs.Shutdown" closure instead.
sync_completion_wait(&completion, zx::sec(5).get());
loop.Shutdown();
END_TEST;
}
} // namespace
BEGIN_TEST_CASE(vmofile_tests)
RUN_TEST(test_vmofile_basic)
END_TEST_CASE(vmofile_tests)