blob: adeb4d12a1147a6540cedf7ee022cd9a33c02154 [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 "lib/vfs/cpp/service.h"
#include <lib/fdio/vfs.h>
#include <lib/fidl/cpp/binding_set.h>
#include <fidl/examples/echo/cpp/fidl.h>
#include "fuchsia/io/cpp/fidl.h"
#include "lib/gtest/real_loop_fixture.h"
#include "lib/vfs/cpp/pseudo_dir.h"
class ServiceTest : public gtest::RealLoopFixture, public fidl::examples::echo::Echo {
void EchoString(fidl::StringPtr value, EchoStringCallback callback) override {
callback(answer_);
}
protected:
ServiceTest()
: answer_("my_fake_ans"),
service_name_("echo_service"),
second_loop_(&kAsyncLoopConfigNoAttachToThread) {
auto service =
std::make_unique<vfs::Service>(bindings_.GetHandler(this, second_loop_.dispatcher()));
dir_.Serve(fuchsia::io::OPEN_RIGHT_READABLE | fuchsia::io::OPEN_RIGHT_WRITABLE,
dir_ptr_.NewRequest().TakeChannel(), second_loop_.dispatcher());
dir_.AddEntry(service_name_, std::move(service));
second_loop_.StartThread("vfs test thread");
}
const std::string& answer() const { return answer_; }
const std::string& service_name() const { return service_name_; }
void AssertInvalidOpen(uint32_t flag, uint32_t mode, zx_status_t expected_status) {
SCOPED_TRACE("flag: " + std::to_string(flag) + ", mode: " + std::to_string(mode));
fuchsia::io::NodePtr node_ptr;
dir_ptr()->Open(flag | fuchsia::io::OPEN_FLAG_DESCRIBE, mode, service_name(),
node_ptr.NewRequest());
bool on_open_called = false;
node_ptr.events().OnOpen = [&](zx_status_t status,
std::unique_ptr<fuchsia::io::NodeInfo> unused) {
EXPECT_FALSE(on_open_called); // should be called only once
on_open_called = true;
EXPECT_EQ(expected_status, status);
};
RunLoopUntil([&]() { return on_open_called; }, zx::msec(1));
}
fuchsia::io::DirectoryPtr& dir_ptr() { return dir_ptr_; }
private:
std::string answer_;
std::string service_name_;
fidl::BindingSet<Echo> bindings_;
vfs::PseudoDir dir_;
fuchsia::io::DirectoryPtr dir_ptr_;
async::Loop second_loop_;
};
TEST_F(ServiceTest, CanOpenAsNodeReferenceAndTestGetAttr) {
fuchsia::io::NodeSyncPtr ptr;
dir_ptr()->Open(fuchsia::io::OPEN_FLAG_NODE_REFERENCE, 0, service_name(), ptr.NewRequest());
zx_status_t s;
fuchsia::io::NodeAttributes attr;
ptr->GetAttr(&s, &attr);
EXPECT_EQ(ZX_OK, s);
EXPECT_EQ(fuchsia::io::MODE_TYPE_SERVICE, attr.mode & fuchsia::io::MODE_TYPE_SERVICE);
}
TEST_F(ServiceTest, CanCloneNodeReference) {
fuchsia::io::NodeSyncPtr cloned_ptr;
{
fuchsia::io::NodeSyncPtr ptr;
dir_ptr()->Open(fuchsia::io::OPEN_FLAG_NODE_REFERENCE, 0, service_name(), ptr.NewRequest());
ptr->Clone(0, cloned_ptr.NewRequest());
}
zx_status_t s;
fuchsia::io::NodeAttributes attr;
cloned_ptr->GetAttr(&s, &attr);
EXPECT_EQ(ZX_OK, s);
EXPECT_EQ(fuchsia::io::MODE_TYPE_SERVICE, attr.mode & fuchsia::io::MODE_TYPE_SERVICE);
}
TEST_F(ServiceTest, TestDescribe) {
fuchsia::io::NodeSyncPtr ptr;
dir_ptr()->Open(fuchsia::io::OPEN_FLAG_NODE_REFERENCE, 0, service_name(), ptr.NewRequest());
fuchsia::io::NodeInfo info;
ptr->Describe(&info);
EXPECT_TRUE(info.is_service());
}
TEST_F(ServiceTest, CanOpenAsAService) {
uint32_t flags[] = {fuchsia::io::OPEN_RIGHT_READABLE, fuchsia::io::OPEN_RIGHT_WRITABLE,
fuchsia::io::OPEN_RIGHT_READABLE | fuchsia::io::OPEN_FLAG_NOT_DIRECTORY};
uint32_t modes[] = {0, fuchsia::io::MODE_TYPE_SERVICE, V_IRWXU, V_IRUSR, V_IWUSR, V_IXUSR};
for (uint32_t mode : modes) {
for (uint32_t flag : flags) {
SCOPED_TRACE("flag: " + std::to_string(flag) + ", mode: " + std::to_string(mode));
fidl::examples::echo::EchoSyncPtr ptr;
dir_ptr()->Open(flag, mode, service_name(),
fidl::InterfaceRequest<fuchsia::io::Node>(ptr.NewRequest().TakeChannel()));
fidl::StringPtr ans;
ptr->EchoString("hello", &ans);
EXPECT_EQ(answer(), ans);
}
}
}
TEST_F(ServiceTest, CannotOpenServiceWithInvalidFlags) {
uint32_t flags[] = {fuchsia::io::OPEN_FLAG_CREATE, fuchsia::io::OPEN_FLAG_CREATE_IF_ABSENT,
fuchsia::io::OPEN_FLAG_TRUNCATE, fuchsia::io::OPEN_FLAG_APPEND,
fuchsia::io::OPEN_FLAG_NO_REMOTE};
for (uint32_t flag : flags) {
AssertInvalidOpen(flag | fuchsia::io::OPEN_RIGHT_READABLE | fuchsia::io::OPEN_RIGHT_WRITABLE, 0,
ZX_ERR_NOT_SUPPORTED);
}
AssertInvalidOpen(fuchsia::io::OPEN_RIGHT_ADMIN, 0, ZX_ERR_ACCESS_DENIED);
AssertInvalidOpen(fuchsia::io::OPEN_RIGHT_READABLE | fuchsia::io::OPEN_FLAG_DIRECTORY, 0,
ZX_ERR_NOT_DIR);
}
TEST_F(ServiceTest, CannotOpenServiceWithInvalidMode) {
uint32_t modes[] = {fuchsia::io::MODE_TYPE_DIRECTORY, fuchsia::io::MODE_TYPE_BLOCK_DEVICE,
fuchsia::io::MODE_TYPE_FILE, fuchsia::io::MODE_TYPE_SOCKET};
for (uint32_t mode : modes) {
AssertInvalidOpen(fuchsia::io::OPEN_RIGHT_READABLE, mode, ZX_ERR_INVALID_ARGS);
}
}