| // Copyright 2020 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 <fidl/fuchsia.component.runner/cpp/wire_types.h> |
| #include <fidl/fuchsia.logger/cpp/wire.h> |
| #include <fuchsia/io/cpp/fidl.h> |
| #include <lib/async-loop/cpp/loop.h> |
| #include <lib/async-loop/default.h> |
| #include <lib/driver/component/cpp/tests/test_base.h> |
| #include <lib/driver/logging/cpp/logger.h> |
| #include <lib/fidl/cpp/binding.h> |
| |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include "src/lib/diagnostics/fake-log-sink/cpp/fake_log_sink.h" |
| |
| namespace { |
| |
| namespace fio = fuchsia::io; |
| namespace frunner = fuchsia_component_runner; |
| |
| using ::diagnostics::reader::LogsData; |
| using ::testing::ElementsAre; |
| |
| constexpr char kName[] = "my-name"; |
| constexpr char kMessage[] = "my-message"; |
| constexpr char kDriverTag[] = "driver"; |
| |
| void CheckLogReadable(fuchsia_logging::FakeLogSink& sink, |
| fuchsia_diagnostics_types::Severity severity) { |
| auto data = sink.ReadLogsData(); |
| ASSERT_TRUE(data); |
| const auto& metadata = data->metadata(); |
| EXPECT_EQ(metadata.severity, severity); |
| EXPECT_THAT(metadata.tags, ElementsAre(kDriverTag, kName)); |
| EXPECT_EQ(data->message(), kMessage); |
| } |
| |
| TEST(LoggerTest, CreateAndLog) { |
| async::Loop loop{&kAsyncLoopConfigNoAttachToCurrentThread}; |
| async::Loop ns_loop{&kAsyncLoopConfigNoAttachToCurrentThread}; |
| ns_loop.StartThread(); |
| |
| // Set up namespace. |
| auto svc = fidl::Endpoints<fuchsia_io::Directory>::Create(); |
| auto ns = fdf::testing::CreateNamespace(std::move(svc.client)); |
| ASSERT_TRUE(ns.is_ok()); |
| |
| std::optional<fuchsia_logging::FakeLogSink> log_sink; |
| |
| fdf::testing::Directory svc_directory; |
| svc_directory.SetOpenHandler([&log_sink](const std::string& path, auto object) { |
| EXPECT_EQ(path, fidl::DiscoverableProtocolName<fuchsia_logger::LogSink>); |
| ASSERT_FALSE(log_sink); |
| log_sink.emplace(FUCHSIA_LOG_INFO, |
| fidl::ServerEnd<fuchsia_logger::LogSink>(object.TakeChannel())); |
| }); |
| fidl::Binding<fio::Directory> svc_binding(&svc_directory); |
| |
| fdf::testing::Directory svc_directory2; |
| svc_directory2.SetOpenHandler([&ns_loop, &svc_binding](const std::string& path, auto object) { |
| EXPECT_EQ(path, "."); |
| svc_binding.Bind(object.TakeChannel(), ns_loop.dispatcher()); |
| }); |
| |
| fidl::Binding<fio::Directory> svc_binding2(&svc_directory2); |
| svc_binding2.Bind(svc.server.TakeChannel(), ns_loop.dispatcher()); |
| |
| auto logger = fdf::Logger::Create2(*ns, loop.dispatcher(), kName, FUCHSIA_LOG_INFO); |
| ASSERT_FALSE(logger->IsNoOp()); |
| loop.RunUntilIdle(); |
| |
| // Check initial state of logger. |
| ASSERT_TRUE(log_sink); |
| EXPECT_FALSE(log_sink->WaitForRecord(zx::time::infinite_past())); |
| |
| // Check state of logger after writing logs that were below |min_severity|. |
| FDF_LOGL(TRACE, *logger, kMessage); |
| EXPECT_FALSE(log_sink->WaitForRecord(zx::time::infinite_past())); |
| FDF_LOGL(DEBUG, *logger, kMessage); |
| EXPECT_FALSE(log_sink->WaitForRecord(zx::time::infinite_past())); |
| |
| // Check state of logger after writing logs. |
| FDF_LOGL(INFO, *logger, kMessage); |
| { |
| SCOPED_TRACE(""); |
| CheckLogReadable(*log_sink, fuchsia_diagnostics_types::Severity::kInfo); |
| } |
| FDF_LOGL(WARNING, *logger, kMessage); |
| { |
| SCOPED_TRACE(""); |
| CheckLogReadable(*log_sink, fuchsia_diagnostics_types::Severity::kWarn); |
| } |
| FDF_LOGL(ERROR, *logger, kMessage); |
| { |
| SCOPED_TRACE(""); |
| CheckLogReadable(*log_sink, fuchsia_diagnostics_types::Severity::kError); |
| } |
| } |
| |
| TEST(LoggerTest, CreateNoLogSink) { |
| async::Loop loop{&kAsyncLoopConfigNoAttachToCurrentThread}; |
| |
| // Setup namespace. |
| auto pkg = fidl::CreateEndpoints<fuchsia_io::Directory>(); |
| EXPECT_EQ(ZX_OK, pkg.status_value()); |
| auto svc = fidl::Endpoints<fuchsia_io::Directory>::Create(); |
| fidl::Arena arena; |
| fidl::VectorView<frunner::wire::ComponentNamespaceEntry> ns_entries(arena, 2); |
| ns_entries[0].Allocate(arena); |
| ns_entries[0].set_path(arena, "/pkg").set_directory(std::move(pkg->client)); |
| ns_entries[1].Allocate(arena); |
| ns_entries[1].set_path(arena, "/svc").set_directory(std::move(svc.client)); |
| auto ns = fdf::Namespace::Create(ns_entries); |
| ASSERT_TRUE(ns.is_ok()); |
| |
| svc.server.TakeChannel().reset(); |
| |
| // Setup logger. |
| auto logger = fdf::Logger::Create2(*ns, loop.dispatcher(), kName, FUCHSIA_LOG_INFO); |
| ASSERT_TRUE(logger->IsNoOp()); |
| } |
| |
| TEST(LoggerTest, SetSeverity) { |
| async::Loop loop{&kAsyncLoopConfigNoAttachToCurrentThread}; |
| async::Loop ns_loop{&kAsyncLoopConfigNoAttachToCurrentThread}; |
| ns_loop.StartThread(); |
| |
| // Setup namespace. |
| auto svc = fidl::Endpoints<fuchsia_io::Directory>::Create(); |
| auto ns = fdf::testing::CreateNamespace(std::move(svc.client)); |
| ASSERT_TRUE(ns.is_ok()); |
| |
| // Setup logger. |
| std::optional<fuchsia_logging::FakeLogSink> log_sink; |
| |
| fdf::testing::Directory svc_directory; |
| svc_directory.SetOpenHandler([&log_sink](const std::string& path, auto object) { |
| EXPECT_EQ(path, fidl::DiscoverableProtocolName<fuchsia_logger::LogSink>); |
| ASSERT_FALSE(log_sink); |
| log_sink.emplace(FUCHSIA_LOG_INFO, |
| fidl::ServerEnd<fuchsia_logger::LogSink>(object.TakeChannel())); |
| }); |
| fidl::Binding<fio::Directory> svc_binding(&svc_directory); |
| |
| fdf::testing::Directory svc_directory2; |
| svc_directory2.SetOpenHandler([&ns_loop, &svc_binding](const std::string& path, auto object) { |
| EXPECT_EQ(path, "."); |
| svc_binding.Bind(object.TakeChannel(), ns_loop.dispatcher()); |
| }); |
| fidl::Binding<fio::Directory> svc_binding2(&svc_directory2); |
| |
| svc_binding2.Bind(svc.server.TakeChannel(), ns_loop.dispatcher()); |
| |
| auto logger = fdf::Logger::Create2(*ns, loop.dispatcher(), kName, FUCHSIA_LOG_INFO); |
| ASSERT_FALSE(logger->IsNoOp()); |
| loop.RunUntilIdle(); |
| |
| // Check initial state of logger. |
| ASSERT_TRUE(log_sink); |
| EXPECT_FALSE(log_sink->WaitForRecord(zx::time::infinite_past())); |
| |
| // Check state of logger after writing logs that were above or equal to the default |
| // severity. |
| FDF_LOGL(INFO, *logger, kMessage); |
| { |
| SCOPED_TRACE(""); |
| CheckLogReadable(*log_sink, fuchsia_diagnostics_types::Severity::kInfo); |
| } |
| FDF_LOGL(WARNING, *logger, kMessage); |
| { |
| SCOPED_TRACE(""); |
| CheckLogReadable(*log_sink, fuchsia_diagnostics_types::Severity::kWarn); |
| } |
| |
| // Check severity after setting it. |
| log_sink->SetSeverity(FUCHSIA_LOG_WARNING); |
| |
| for (;;) { |
| loop.RunUntilIdle(); |
| |
| if (logger->GetSeverity() == FUCHSIA_LOG_WARNING) { |
| break; |
| } |
| |
| // Unfortunately, setting the severity involves two async loops on different threads: a FIDL |
| // message has to pass from the server and the client. It's not ideal, but the easiest way to |
| // test this is just to sleep and then test again. |
| usleep(1000); |
| } |
| |
| // Check state of logger after writing logs that were below min severity. |
| FDF_LOGL(INFO, *logger, kMessage); |
| EXPECT_FALSE(log_sink->WaitForRecord(zx::time::infinite_past())); |
| FDF_LOGL(WARNING, *logger, kMessage); |
| { |
| SCOPED_TRACE(""); |
| CheckLogReadable(*log_sink, fuchsia_diagnostics_types::Severity::kWarn); |
| } |
| } |
| |
| } // namespace |