| // Copyright 2018 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 <fuchsia/logger/cpp/fidl.h> |
| #include <lib/fdio/directory.h> |
| #include <lib/fdio/fd.h> |
| #include <lib/fdio/fdio.h> |
| #include <lib/fidl/cpp/interface_ptr.h> |
| #include <lib/gtest/real_loop_fixture.h> |
| #include <lib/sys/cpp/component_context.h> |
| |
| #include <regex> |
| |
| #include <fidl/examples/echo/cpp/fidl.h> |
| #include <gmock/gmock.h> |
| #include <test/sysmgr/cpp/fidl.h> |
| |
| #include "gtest/gtest.h" |
| #include "src/sys/appmgr/appmgr.h" |
| |
| namespace sysmgr { |
| namespace test { |
| namespace { |
| |
| class SimpleLogCollector : public fuchsia::logger::LogListenerSafe { |
| public: |
| explicit SimpleLogCollector(fidl::InterfaceRequest<fuchsia::logger::LogListenerSafe> request, |
| async_dispatcher_t* dispatcher) |
| : binding_(this, std::move(request), dispatcher) { |
| binding_.set_error_handler([this](zx_status_t s) { |
| if (!done_) { |
| FAIL() << "Connection to simple collector closed early"; |
| } |
| }); |
| } |
| |
| virtual void Log(fuchsia::logger::LogMessage message, LogCallback received) override { |
| messages_.emplace_back(message.msg); |
| received(); |
| }; |
| |
| virtual void LogMany(std::vector<fuchsia::logger::LogMessage> messages, |
| LogManyCallback received) override { |
| for (auto& l : messages) { |
| Log(std::move(l), []() {}); |
| } |
| received(); |
| } |
| |
| virtual void Done() override { done_ = true; } |
| |
| bool done_; |
| fidl::Binding<fuchsia::logger::LogListenerSafe> binding_; |
| std::vector<std::string> messages_; |
| }; |
| |
| class TestSysmgr : public ::gtest::RealLoopFixture { |
| protected: |
| // Verifies that messages with the given tags match |expected_patterns|. |
| void VerifyLogs(const fuchsia::logger::LogPtr& log_ptr, std::vector<std::string> tags, |
| std::vector<std::string> expected_patterns) { |
| fidl::InterfaceHandle<fuchsia::logger::LogListenerSafe> listener_handle; |
| SimpleLogCollector collector(listener_handle.NewRequest(), dispatcher()); |
| auto filter_options = fuchsia::logger::LogFilterOptions::New(); |
| filter_options->tags = tags; |
| |
| // FIXME(45589) can't use DumpLogs without a fence |
| log_ptr->ListenSafe(std::move(listener_handle), std::move(filter_options)); |
| RunLoopUntil([&collector, &expected_patterns] { |
| return (collector.messages_.size() == expected_patterns.size()); |
| }); |
| |
| ASSERT_EQ(expected_patterns.size(), collector.messages_.size()); |
| auto expected = expected_patterns.begin(); |
| auto observed = collector.messages_.begin(); |
| while (expected != expected_patterns.end() || observed != collector.messages_.end()) { |
| ASSERT_THAT(*observed, ::testing::MatchesRegex(*expected)); |
| expected++; |
| observed++; |
| } |
| ASSERT_EQ(expected, expected_patterns.end()); |
| ASSERT_EQ(observed, collector.messages_.end()); |
| } |
| }; |
| |
| TEST_F(TestSysmgr, ServiceStartup) { |
| zx::channel h1, h2; |
| ASSERT_EQ(ZX_OK, zx::channel::create(0, &h1, &h2)); |
| |
| auto environment_services = sys::ComponentContext::Create()->svc(); |
| |
| // Make fidl.examples.echo.Echo from our own environment available in appmgr's |
| // root realm. |
| fuchsia::sys::ServiceListPtr root_realm_services(new fuchsia::sys::ServiceList); |
| root_realm_services->names = std::vector<std::string>{fidl::examples::echo::Echo::Name_}; |
| root_realm_services->host_directory = environment_services->CloneChannel().TakeChannel(); |
| |
| std::vector<std::string> sysmgr_args; |
| component::AppmgrArgs args{ |
| .pa_directory_request = h2.release(), |
| .root_realm_services = std::move(root_realm_services), |
| .environment_services = std::move(environment_services), |
| .sysmgr_url = "fuchsia-pkg://fuchsia.com/sysmgr_integration_tests#meta/sysmgr.cmx", |
| .sysmgr_args = std::move(sysmgr_args), |
| .run_virtual_console = false, |
| .retry_sysmgr_crash = false}; |
| component::Appmgr appmgr(dispatcher(), std::move(args)); |
| |
| // h1 is connected to h2, which is injected above as appmgr's |
| // PA_DIRECTORY_REQUEST handle. appmgr hosts a directory on that handle, which |
| // includes a svc/ subdirectory, which in turn connects to the first realm's |
| // services. That first realm is the sys realm created by sysmgr, so |
| // sysmgr_svc ends up being a directory with all services in the sys realm. |
| zx::channel svc_client, svc_server; |
| ASSERT_EQ(ZX_OK, zx::channel::create(0, &svc_client, &svc_server)); |
| ASSERT_EQ(ZX_OK, fdio_service_connect_at(h1.get(), "svc", svc_server.release())); |
| sys::ServiceDirectory sysmgr_svc(std::move(svc_client)); |
| |
| bool received_response = false; |
| std::string response; |
| ::test::sysmgr::InterfacePtr interface_ptr; |
| ASSERT_EQ(ZX_OK, sysmgr_svc.Connect(interface_ptr.NewRequest(dispatcher()))); |
| |
| fuchsia::logger::LogPtr log_ptr; |
| ASSERT_EQ(ZX_OK, sysmgr_svc.Connect(log_ptr.NewRequest(dispatcher()))); |
| |
| interface_ptr->Ping([&](fidl::StringPtr r) { |
| received_response = true; |
| response = r.value_or(""); |
| }); |
| RunLoopUntil([&] { return received_response; }); |
| EXPECT_EQ("test_sysmgr_service_startup", response); |
| |
| const std::string echo_msg = "test string for echo"; |
| received_response = false; |
| fidl::examples::echo::EchoPtr echo_ptr; |
| ASSERT_EQ(ZX_OK, sysmgr_svc.Connect(echo_ptr.NewRequest(dispatcher()))); |
| |
| echo_ptr->EchoString(echo_msg, [&](fidl::StringPtr r) { |
| received_response = true; |
| response = r.value_or(""); |
| }); |
| RunLoopUntil([&] { return received_response; }); |
| EXPECT_EQ(echo_msg, response); |
| |
| VerifyLogs(log_ptr, {"test_sysmgr_service"}, |
| { |
| "test_sysmgr_service.cc\\([0-9]{1,4}\\): Entering loop.", |
| "test_sysmgr_service.cc\\([0-9]{1,4}\\): Received ping.", |
| }); |
| VerifyLogs(log_ptr, {"appmgr"}, |
| {"\\[log_connector_impl.cc\\([0-9]{1,4}\\)\\] Successfully set up syslog"}); |
| } |
| |
| } // namespace |
| } // namespace test |
| } // namespace sysmgr |