blob: 10126426d66c5c8cc5590da29750d563a0934a61 [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.
#include <fcntl.h>
#include <fuchsia/io/cpp/fidl.h>
#include <lib/fdio/directory.h>
#include <lib/fdio/fd.h>
#include <lib/vfs/cpp/composed_service_dir.h>
#include <lib/vfs/cpp/pseudo_dir.h>
#include <lib/vfs/cpp/service.h>
#include <zircon/status.h>
#include <memory>
#include <string>
#include <string_view>
#include <fbl/unique_fd.h>
#include "src/lib/testing/loop_fixture/real_loop_fixture.h"
namespace {
constexpr std::string_view kServices[]{"service_a", "service_b"};
constexpr std::string_view kFallbackServices[]{"service_b", "service_c"};
constexpr size_t kServiceConnections = 5;
constexpr size_t kFallbackServiceConnections = 2;
// Fixture sets up a composed service directory containing "service_a" and "service_b" which is
// backed by a fallback directory containing "service_b" and "service_c".
class ComposedServiceDirTest : public ::gtest::RealLoopFixture {
// vfs::ComposedServiceDir is deprecated. See https://fxbug.dev/309685624 for details.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
protected:
void SetUp() override {
root_ = std::make_unique<vfs::ComposedServiceDir>();
for (const auto service : kServices) {
root_->AddService(std::string(service),
std::make_unique<vfs::Service>(MakeService(service, /*fallback*/ false)));
}
fallback_dir_ = std::make_unique<vfs::PseudoDir>();
for (const auto service : kFallbackServices) {
fallback_dir_->AddEntry(std::string(service), std::make_unique<vfs::Service>(
MakeService(service, /*fallback*/ true)));
}
zx::channel fallback_client, fallback_server;
ASSERT_EQ(zx::channel::create(0, &fallback_client, &fallback_server), ZX_OK);
ASSERT_EQ(fallback_dir_->Serve(
fuchsia::io::OpenFlags::RIGHT_READABLE | fuchsia::io::OpenFlags::RIGHT_WRITABLE,
std::move(fallback_server)),
ZX_OK);
root_->set_fallback(fidl::InterfaceHandle<fuchsia::io::Directory>{std::move(fallback_client)});
zx::channel root_server;
ASSERT_EQ(zx::channel::create(0, &root_client_, &root_server), ZX_OK);
ASSERT_EQ(root_->Serve(
fuchsia::io::OpenFlags::RIGHT_READABLE | fuchsia::io::OpenFlags::RIGHT_WRITABLE,
std::move(root_server)),
ZX_OK);
}
const zx::channel& root_client() { return root_client_; }
auto& connection_attempts() { return connection_attempts_; }
auto& fallback_attempts() { return fallback_attempts_; }
private:
fit::function<void(zx::channel channel, async_dispatcher_t* dispatcher)> MakeService(
std::string_view name, bool fallback) {
return [this, name, fallback](zx::channel channel, async_dispatcher_t* dispatcher) {
if (fallback) {
fallback_attempts_[name]++;
} else {
connection_attempts_[name]++;
}
};
}
std::unique_ptr<vfs::ComposedServiceDir> root_;
std::unique_ptr<vfs::PseudoDir> fallback_dir_;
zx::channel root_client_;
std::map<std::string_view, size_t, std::less<>> connection_attempts_;
std::map<std::string_view, size_t, std::less<>> fallback_attempts_;
#pragma clang diagnostic pop
};
TEST_F(ComposedServiceDirTest, Connect) {
PerformBlockingWork([this] {
for (size_t i = 0; i < kServiceConnections; ++i) {
for (const auto& service : kServices) {
zx::channel client, server;
ASSERT_EQ(zx::channel::create(0, &client, &server), ZX_OK);
ASSERT_EQ(fdio_service_connect_at(root_client().get(), service.data(), server.release()),
ZX_OK);
}
}
for (size_t i = 0; i < kFallbackServiceConnections; ++i) {
for (const auto& service : kFallbackServices) {
zx::channel client, server;
ASSERT_EQ(zx::channel::create(0, &client, &server), ZX_OK);
ASSERT_EQ(fdio_service_connect_at(root_client().get(), service.data(), server.release()),
ZX_OK);
}
}
});
RunLoopUntilIdle();
// service_a is only in the root, service_b is in both, and service_c is only in the fallback.
EXPECT_EQ(connection_attempts()["service_a"], kServiceConnections);
EXPECT_EQ(connection_attempts()["service_b"], kServiceConnections + kFallbackServiceConnections);
EXPECT_EQ(connection_attempts()["service_c"], 0u);
EXPECT_EQ(fallback_attempts()["service_a"], 0u);
EXPECT_EQ(fallback_attempts()["service_b"], 0u);
EXPECT_EQ(fallback_attempts()["service_c"], kFallbackServiceConnections);
}
} // namespace