|  | // 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] |