blob: 16f697d3a59ce4051f40b3a920cd6ded27fbc981 [file] [log] [blame]
// Copyright 2021 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 "src/modular/lib/session/session.h"
#include <lib/fdio/directory.h>
#include <lib/fdio/namespace.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/vfs/cpp/pseudo_dir.h>
#include <lib/vfs/cpp/service.h>
#include <zircon/status.h>
#include <gtest/gtest.h>
#include "src/lib/files/path.h"
#include "src/lib/fxl/strings/join_strings.h"
#include "src/lib/fxl/strings/split_string.h"
#include "src/lib/testing/loop_fixture/real_loop_fixture.h"
#include "src/modular/lib/pseudo_dir/pseudo_dir_server.h"
#include "src/modular/lib/session/session_constants.h"
class SessionTest : public gtest::RealLoopFixture {
public:
void SetUp() override { ASSERT_EQ(ZX_OK, fdio_ns_get_installed(&ns_)); }
void TearDown() override {
for (const auto& path : bound_ns_paths_) {
ASSERT_EQ(ZX_OK, fdio_ns_unbind(ns_, path.c_str()));
}
}
// Binds the |path| in the current process namespace to directory |handle|.
void BindNamespacePath(std::string path, zx::handle handle) {
ASSERT_EQ(ZX_OK, fdio_ns_bind(ns_, path.c_str(), handle.release()));
bound_ns_paths_.emplace_back(path);
}
// Serves a protocol at the given |path|.
template <typename Interface>
void ServeProtocolAt(std::string_view path, fidl::InterfaceRequestHandler<Interface> handler) {
// Split the path into two parts: a path to a directory, and the last segment,
// an entry in that directory.
auto path_split = fxl::SplitStringCopy(path, "/", fxl::WhiteSpaceHandling::kKeepWhitespace,
fxl::SplitResult::kSplitWantNonEmpty);
FX_CHECK(!path_split.empty());
auto entry_name = std::move(path_split.back());
path_split.pop_back();
auto namespace_path = files::JoinPath("/", fxl::JoinStrings(path_split, "/"));
auto new_protocol_server =
std::make_unique<modular::PseudoDirServer>(std::make_unique<vfs::PseudoDir>());
const auto& [it, inserted] =
protocol_servers_.try_emplace(namespace_path, std::move(new_protocol_server));
auto& protocol_server = it->second;
auto dir = protocol_server->pseudo_dir();
ASSERT_EQ(ZX_OK, dir->AddEntry(entry_name, std::make_unique<vfs::Service>(std::move(handler))));
if (inserted) {
BindNamespacePath(namespace_path, protocol_server->Serve().Unbind().TakeChannel());
}
}
private:
fdio_ns_t* ns_ = nullptr;
std::vector<std::string> bound_ns_paths_;
std::map<std::string, std::unique_ptr<modular::PseudoDirServer>> protocol_servers_;
};
// Tests that |ConnectToBasemgrDebug| can connect to |BasemgrDebug| served under the hub path
// that exists when basemgr is running as a v1 component.
TEST_F(SessionTest, ConnectToBasemgrDebugV1) {
static constexpr auto kTestBasemgrDebugPath = "/hub/c/basemgr.cmx/12345/out/debug/basemgr";
// Serve the |BasemgrDebug| service in the process namespace at the path |kTestBasemgrDebugPath|.
bool got_request{false};
fidl::InterfaceRequestHandler<fuchsia::modular::internal::BasemgrDebug> handler =
[&](fidl::InterfaceRequest<fuchsia::modular::internal::BasemgrDebug> request) {
got_request = true;
};
ServeProtocolAt<fuchsia::modular::internal::BasemgrDebug>(kTestBasemgrDebugPath,
std::move(handler));
// Connect to the |BasemgrDebug| service.
auto result = modular::session::ConnectToBasemgrDebug();
EXPECT_TRUE(result.is_ok());
// Ensure that the proxy returned is connected to the instance served above.
fuchsia::modular::internal::BasemgrDebugPtr basemgr_debug = result.take_value();
basemgr_debug->StartSessionWithRandomId();
RunLoopUntil([&]() { return got_request; });
EXPECT_TRUE(got_request);
}
// Tests that |ConnectToBasemgrDebug| can connect to |BasemgrDebug| served under
// the hub-v2 path that exists when basemgr is running as a v2 session.
TEST_F(SessionTest, ConnectToBasemgrDebugV2Session) {
static constexpr auto kTestBasemgrDebugPath =
"/hub-v2/children/core/children/session-manager/children/session:session/"
"exec/expose/fuchsia.modular.internal.BasemgrDebug";
// Serve the |BasemgrDebug| service in the process namespace at the path
// |kTestBasemgrDebugPath|.
bool got_request{false};
fidl::InterfaceRequestHandler<fuchsia::modular::internal::BasemgrDebug> handler =
[&](fidl::InterfaceRequest<fuchsia::modular::internal::BasemgrDebug> request) {
got_request = true;
};
ServeProtocolAt<fuchsia::modular::internal::BasemgrDebug>(kTestBasemgrDebugPath,
std::move(handler));
// Connect to the |BasemgrDebug| service.
auto result = modular::session::ConnectToBasemgrDebug();
EXPECT_TRUE(result.is_ok());
// Ensure that the proxy returned is connected to the instance served above.
fuchsia::modular::internal::BasemgrDebugPtr basemgr_debug = result.take_value();
basemgr_debug->StartSessionWithRandomId();
RunLoopUntil([&]() { return got_request; });
EXPECT_TRUE(got_request);
}