blob: 696316e0283d901792658dae484e3f2499e563b4 [file] [log] [blame]
// Copyright 2022 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.
// [START example]
#include <fuchsia/component/cpp/fidl.h>
#include <fuchsia/component/sandbox/cpp/fidl.h>
#include <fuchsia/examples/cpp/fidl.h>
#include <fuchsia/testing/harness/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/component/incoming/cpp/protocol.h>
#include <lib/fdio/directory.h>
#include <lib/fdio/namespace.h>
#include <lib/sys/cpp/component_context.h>
#include <lib/syslog/cpp/macros.h>
#include <atomic>
#include <string>
#include <test/example/cpp/fidl.h>
#include <zxtest/zxtest.h>
class FuchsiaExamplesTest : public zxtest::Test {
public:
~FuchsiaExamplesTest() override = default;
};
// TODO(https://fxbug.dev/330610053): Once a C++ realm_proxy library is available, use
// that instead of this custom boilerplate
class InstalledNamespace {
public:
InstalledNamespace(std::string prefix, zx::channel realm_factory)
: prefix_(std::move(prefix)), realm_factory_(std::move(realm_factory)) {}
~InstalledNamespace() {
fdio_ns_t* ns;
EXPECT_EQ(fdio_ns_get_installed(&ns), ZX_OK);
EXPECT_EQ(fdio_ns_unbind(ns, prefix_.c_str()), ZX_OK);
}
template <typename Interface>
zx_status_t Connect(fidl::InterfaceRequest<Interface> request,
const std::string& interface_name = Interface::Name_) const {
return Connect(interface_name, request.TakeChannel());
}
zx_status_t Connect(const std::string& interface_name, zx::channel request) const {
const std::string path = prefix_ + "/" + interface_name;
return fdio_service_connect(path.c_str(), request.release());
}
static InstalledNamespace Create(sys::ComponentContext* context);
const std::string& prefix() const { return prefix_; }
private:
std::string prefix_;
/// This is not used, but it keeps the RealmFactory connection alive.
///
/// The RealmFactory server may use this connection to pin the lifetime of the realm created
/// for the test.
zx::channel realm_factory_;
};
namespace {
std::atomic_int32_t namespace_ctr{1};
} // namespace
template <typename Interface>
InstalledNamespace ExtendNamespace(
sys::ComponentContext* context, fidl::InterfaceHandle<Interface> realm_factory,
fidl::InterfaceHandle<::fuchsia::component::sandbox::Dictionary> dictionary) {
std::string prefix = std::string("/dict-") + std::to_string(namespace_ctr++);
fuchsia::component::NamespaceSyncPtr namespace_proxy;
EXPECT_OK(context->svc()->Connect(namespace_proxy.NewRequest()));
std::vector<fuchsia::component::NamespaceInputEntry> entries;
entries.emplace_back(fuchsia::component::NamespaceInputEntry{
.path = prefix,
.dictionary = std::move(dictionary),
});
fuchsia::component::Namespace_Create_Result result;
EXPECT_OK(namespace_proxy->Create(std::move(entries), &result));
EXPECT_TRUE(!result.is_err());
std::vector<fuchsia::component::NamespaceEntry> namespace_entries =
std::move(result.response().entries);
EXPECT_EQ(namespace_entries.size(), 1);
auto& entry = namespace_entries[0];
EXPECT_TRUE(entry.has_path() && entry.has_directory());
EXPECT_EQ(entry.path(), prefix);
fdio_ns_t* ns;
EXPECT_OK(fdio_ns_get_installed(&ns));
zx_handle_t dir_handle = entry.mutable_directory()->TakeChannel().release();
EXPECT_OK(fdio_ns_bind(ns, prefix.c_str(), dir_handle));
return InstalledNamespace(std::move(prefix), realm_factory.TakeChannel());
}
TEST(FuchsiaExamplesTest, Echo) {
async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
test::example::RealmFactorySyncPtr realm_factory;
auto context = sys::ComponentContext::Create();
EXPECT_OK(context->svc()->Connect(realm_factory.NewRequest()));
fuchsia::component::sandbox::DictionarySyncPtr dictionary;
test::example::RealmFactory_CreateRealm_Result result;
test::example::RealmOptions options;
EXPECT_OK(realm_factory->CreateRealm(std::move(options), dictionary.NewRequest(), &result));
auto test_ns = ExtendNamespace(context.get(), realm_factory.Unbind(), dictionary.Unbind());
fuchsia::examples::EchoSyncPtr echo;
EXPECT_OK(test_ns.Connect(echo.NewRequest()));
std::string response;
EXPECT_OK(echo->EchoString("hello", &response));
EXPECT_STREQ(response.c_str(), "hello");
}
// [END example]