| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/fuchsia/test_log_listener_safe.h" |
| |
| #include <lib/async/default.h> |
| #include <lib/fidl/cpp/box.h> |
| #include <lib/zx/clock.h> |
| |
| #include "base/fuchsia/fuchsia_component_connect.h" |
| #include "base/fuchsia/fuchsia_logging.h" |
| #include "base/functional/callback_helpers.h" |
| #include "base/process/process.h" |
| #include "base/run_loop.h" |
| #include "base/strings/string_piece.h" |
| #include "base/test/bind.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| |
| namespace base { |
| |
| TestLogListenerSafe::TestLogListenerSafe() = default; |
| |
| TestLogListenerSafe::~TestLogListenerSafe() = default; |
| |
| void TestLogListenerSafe::set_on_log_message( |
| base::RepeatingCallback<void(const fuchsia_logger::LogMessage&)> callback) { |
| on_log_message_ = std::move(callback); |
| } |
| |
| void TestLogListenerSafe::Log( |
| TestLogListenerSafe::LogRequest& request, |
| TestLogListenerSafe::LogCompleter::Sync& completer) { |
| if (on_log_message_) |
| on_log_message_.Run(request.log()); |
| completer.Reply(); |
| } |
| |
| void TestLogListenerSafe::LogMany( |
| TestLogListenerSafe::LogManyRequest& request, |
| TestLogListenerSafe::LogManyCompleter::Sync& completer) { |
| for (const auto& message : request.log()) { |
| on_log_message_.Run(message); |
| } |
| completer.Reply(); |
| } |
| |
| void TestLogListenerSafe::Done( |
| TestLogListenerSafe::DoneCompleter::Sync& completer) {} |
| |
| SimpleTestLogListener::SimpleTestLogListener() = default; |
| SimpleTestLogListener::~SimpleTestLogListener() = default; |
| |
| void SimpleTestLogListener::ListenToLog( |
| const fidl::Client<fuchsia_logger::Log>& log, |
| std::unique_ptr<fuchsia_logger::LogFilterOptions> options) { |
| auto listener_endpoints = |
| fidl::CreateEndpoints<fuchsia_logger::LogListenerSafe>(); |
| ZX_CHECK(listener_endpoints.is_ok(), listener_endpoints.status_value()) |
| << "Failed to create listener endpoints"; |
| binding_.emplace( |
| async_get_default_dispatcher(), std::move(listener_endpoints->server), |
| &listener_, [](fidl::UnbindInfo info) { |
| ZX_LOG(ERROR, info.status()) << "LogListenerSafe disconnected"; |
| }); |
| |
| ignore_before_ = zx::clock::get_monotonic(); |
| listener_.set_on_log_message(base::BindRepeating( |
| &SimpleTestLogListener::PushLoggedMessage, base::Unretained(this))); |
| auto listen_safe_result = |
| log->ListenSafe({{.log_listener = std::move(listener_endpoints->client), |
| .options = std::move(options)}}); |
| if (listen_safe_result.is_error()) { |
| ZX_DLOG(ERROR, listen_safe_result.error_value().status()) |
| << "ListenSafe() failed"; |
| } |
| } |
| |
| absl::optional<fuchsia_logger::LogMessage> |
| SimpleTestLogListener::RunUntilMessageReceived( |
| base::StringPiece expected_string) { |
| while (!logged_messages_.empty()) { |
| fuchsia_logger::LogMessage message = logged_messages_.front(); |
| logged_messages_.pop_front(); |
| if (base::StringPiece(message.msg()).find(expected_string) != |
| std::string::npos) { |
| return message; |
| } |
| } |
| |
| absl::optional<fuchsia_logger::LogMessage> logged_message; |
| base::RunLoop loop; |
| on_log_message_ = base::BindLambdaForTesting( |
| [ignore_before = ignore_before_, &logged_message, |
| expected_string = std::string(expected_string), |
| quit_loop = |
| loop.QuitClosure()](const fuchsia_logger::LogMessage& message) { |
| if (zx::time(message.time()) < ignore_before) { |
| return; |
| } |
| if (message.msg().find(expected_string) == std::string::npos) { |
| return; |
| } |
| logged_message.emplace(message); |
| quit_loop.Run(); |
| }); |
| |
| loop.Run(); |
| |
| on_log_message_ = NullCallback(); |
| |
| return logged_message; |
| } |
| |
| void SimpleTestLogListener::PushLoggedMessage( |
| const fuchsia_logger::LogMessage& message) { |
| DVLOG(1) << "TestLogListener received: " << message.msg(); |
| if (zx::time(message.time()) < ignore_before_) { |
| return; |
| } |
| if (on_log_message_) { |
| DCHECK(logged_messages_.empty()); |
| on_log_message_.Run(message); |
| } else { |
| logged_messages_.push_back(std::move(message)); |
| } |
| } |
| |
| void ListenFilteredByCurrentProcessId(SimpleTestLogListener& listener) { |
| // Connect the test LogListenerSafe to the Log. |
| auto log_client_end = fuchsia_component::Connect<fuchsia_logger::Log>(); |
| ASSERT_TRUE(log_client_end.is_ok()) |
| << FidlConnectionErrorMessage(log_client_end); |
| fidl::Client log_client(std::move(log_client_end.value()), |
| async_get_default_dispatcher()); |
| listener.ListenToLog( |
| log_client, |
| std::make_unique<fuchsia_logger::LogFilterOptions>( |
| fuchsia_logger::LogFilterOptions{ |
| {.filter_by_pid = true, |
| .pid = Process::Current().Pid(), |
| .min_severity = fuchsia_logger::LogLevelFilter::kInfo}})); |
| } |
| |
| } // namespace base |