blob: 3181d4631ff4237698ea80f38609747ee267ed5a [file] [log] [blame]
// Copyright 2023 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.
// These tests verify basic functionality of `vfs::Service`. For more comprehensive tests, see
// //src/storage/lib/vfs/cpp and //src/storage/conformance.
#include <fcntl.h>
#include <fidl/fuchsia.io/cpp/fidl.h>
#include <fidl/test.placeholders/cpp/test_base.h>
#include <lib/fdio/directory.h>
#include <lib/fdio/fd.h>
#include <lib/vfs/cpp/pseudo_dir.h>
#include <lib/vfs/cpp/service.h>
#include <zircon/status.h>
#include <memory>
#include <fbl/unique_fd.h>
#include "src/lib/testing/loop_fixture/real_loop_fixture.h"
namespace {
// Sets up a service at root/instance that drops connections after a certain limit is reached.
class ServiceTest : public ::gtest::RealLoopFixture {
protected:
void SetUp() override {
root_ = std::make_unique<vfs::PseudoDir>();
auto [root_client, root_server] = fidl::Endpoints<fuchsia_io::Directory>::Create();
ASSERT_EQ(root_->Serve(fuchsia_io::kPermReadable, std::move(root_server)), ZX_OK);
root_client_ = std::move(root_client);
}
const fidl::ClientEnd<fuchsia_io::Directory>& root_client() { return root_client_; }
void AddService(std::unique_ptr<vfs::Service> service, std::string_view path) {
EXPECT_EQ(root_->AddEntry(std::string(path), std::move(service)), ZX_OK);
}
private:
std::unique_ptr<vfs::PseudoDir> root_;
std::vector<zx::channel> channels_;
fidl::ClientEnd<fuchsia_io::Directory> root_client_;
};
TEST_F(ServiceTest, Lambda) {
// Create a service with a callback that counts the number of times connection attempts are made.
size_t num_connections = 0;
auto service =
std::make_unique<vfs::Service>([&num_connections](zx::channel) { ++num_connections; });
AddService(std::move(service), "lambda");
// Connect to the service a few times and ensure the lambda was invoked the same amount of times.
constexpr size_t kConnectionAttempts = 5;
PerformBlockingWork([this] {
for (size_t i = 0; i < kConnectionAttempts; ++i) {
zx::channel client, server;
ASSERT_EQ(zx::channel::create(0, &client, &server), ZX_OK);
ASSERT_EQ(fdio_service_connect_at(root_client().channel().get(), "lambda", server.release()),
ZX_OK);
}
});
RunLoopUntilIdle();
ASSERT_EQ(num_connections, kConnectionAttempts);
}
class ExampleService : public fidl::testing::TestBase<test_placeholders::Echo> {
void EchoString(EchoStringRequest& request, EchoStringCompleter::Sync& completer) override {
completer.Reply(request.value());
}
void NotImplemented_(const std::string& name, ::fidl::CompleterBase& completer) override {
FAIL() << "Not implemented: " << name;
}
};
TEST_F(ServiceTest, ServiceSharedInstance) {
ExampleService instance;
instance.bind_handler(dispatcher());
auto service = std::make_unique<vfs::Service>(instance.bind_handler(dispatcher()));
AddService(std::move(service), "example");
}
TEST_F(ServiceTest, ServiceUniqueInstance) {
auto service =
std::make_unique<vfs::Service>([this](fidl::ServerEnd<test_placeholders::Echo> server_end) {
auto instance = std::make_unique<ExampleService>();
fidl::BindServer(dispatcher(), std::move(server_end), std::move(instance));
});
AddService(std::move(service), "example");
}
} // namespace