blob: a6ba6e2366b11189f16b4109adb389680035c65f [file] [log] [blame]
// Copyright 2017 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 <lib/async-loop/cpp/loop.h>
#include <lib/fdio/fd.h>
#include <lib/fdio/fdio.h>
#include <lib/fdio/directory.h>
#include <fs/synchronous-vfs.h>
#include <fs/pseudo-dir.h>
#include <fs/service.h>
#include <unittest/unittest.h>
#include <utility>
namespace {
bool test_service() {
BEGIN_TEST;
// set up a service which can only be bound once (to make it easy to
// simulate an error to test error reporting behavior from the connector)
zx::channel bound_channel;
auto svc = fbl::AdoptRef<fs::Service>(new fs::Service(
[&bound_channel](zx::channel channel) {
if (bound_channel)
return ZX_ERR_IO;
bound_channel = std::move(channel);
return ZX_OK;
}));
// open
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, svc->ValidateFlags(ZX_FS_RIGHT_READABLE));
EXPECT_EQ(ZX_OK, svc->Open(ZX_FS_RIGHT_READABLE, &redirect));
EXPECT_NULL(redirect);
// get attr
vnattr_t attr;
EXPECT_EQ(ZX_OK, svc->Getattr(&attr));
EXPECT_EQ(V_TYPE_FILE, attr.mode);
EXPECT_EQ(1, attr.nlink);
// make some channels we can use for testing
zx::channel c1, c2;
EXPECT_EQ(ZX_OK, zx::channel::create(0u, &c1, &c2));
zx_handle_t hc1 = c1.get();
// serve, the connector will return success the first time
fs::SynchronousVfs vfs;
EXPECT_EQ(ZX_OK, svc->Serve(&vfs, std::move(c1), ZX_FS_RIGHT_READABLE));
EXPECT_EQ(hc1, bound_channel.get());
// the connector will return failure because bound_channel is still valid
// we test that the error is propagated back up through Serve
EXPECT_EQ(ZX_ERR_IO, svc->Serve(&vfs, std::move(c2), ZX_FS_RIGHT_READABLE));
EXPECT_EQ(hc1, bound_channel.get());
END_TEST;
}
bool TestServeDirectory() {
BEGIN_TEST;
zx::channel client, server;
EXPECT_EQ(ZX_OK, zx::channel::create(0u, &client, &server));
// open client
zx::channel c1, c2;
EXPECT_EQ(ZX_OK, zx::channel::create(0u, &c1, &c2));
EXPECT_EQ(ZX_OK,
fdio_service_connect_at(client.get(), "abc", c2.release()));
// close client
// We test the semantic that a pending open is processed even if the client
// has been closed.
client.reset();
// serve
async::Loop loop(&kAsyncLoopConfigNoAttachToThread);
fs::SynchronousVfs vfs(loop.dispatcher());
auto directory = fbl::AdoptRef<fs::PseudoDir>(new fs::PseudoDir());
auto vnode = fbl::AdoptRef<fs::Service>(new fs::Service(
[&loop](zx::channel channel) {
loop.Shutdown();
return ZX_OK;
}));
directory->AddEntry("abc", vnode);
EXPECT_EQ(ZX_OK, vfs.ServeDirectory(directory, std::move(server)));
EXPECT_EQ(ZX_ERR_BAD_STATE, loop.RunUntilIdle());
END_TEST;
}
} // namespace
BEGIN_TEST_CASE(service_tests)
RUN_TEST(test_service)
RUN_TEST(TestServeDirectory)
END_TEST_CASE(service_tests)