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