1 // Copyright 2020 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/fuchsia/test_log_listener_safe.h"
6
7 #include <lib/async/default.h>
8 #include <lib/fidl/cpp/box.h>
9 #include <lib/zx/clock.h>
10
11 #include "base/fuchsia/fuchsia_component_connect.h"
12 #include "base/fuchsia/fuchsia_logging.h"
13 #include "base/functional/callback_helpers.h"
14 #include "base/process/process.h"
15 #include "base/run_loop.h"
16 #include "base/strings/string_piece.h"
17 #include "base/test/bind.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "third_party/abseil-cpp/absl/types/optional.h"
20
21 namespace base {
22
23 TestLogListenerSafe::TestLogListenerSafe() = default;
24
25 TestLogListenerSafe::~TestLogListenerSafe() = default;
26
set_on_log_message(base::RepeatingCallback<void (const fuchsia_logger::LogMessage &)> callback)27 void TestLogListenerSafe::set_on_log_message(
28 base::RepeatingCallback<void(const fuchsia_logger::LogMessage&)> callback) {
29 on_log_message_ = std::move(callback);
30 }
31
Log(TestLogListenerSafe::LogRequest & request,TestLogListenerSafe::LogCompleter::Sync & completer)32 void TestLogListenerSafe::Log(
33 TestLogListenerSafe::LogRequest& request,
34 TestLogListenerSafe::LogCompleter::Sync& completer) {
35 if (on_log_message_)
36 on_log_message_.Run(request.log());
37 completer.Reply();
38 }
39
LogMany(TestLogListenerSafe::LogManyRequest & request,TestLogListenerSafe::LogManyCompleter::Sync & completer)40 void TestLogListenerSafe::LogMany(
41 TestLogListenerSafe::LogManyRequest& request,
42 TestLogListenerSafe::LogManyCompleter::Sync& completer) {
43 for (const auto& message : request.log()) {
44 on_log_message_.Run(message);
45 }
46 completer.Reply();
47 }
48
Done(TestLogListenerSafe::DoneCompleter::Sync & completer)49 void TestLogListenerSafe::Done(
50 TestLogListenerSafe::DoneCompleter::Sync& completer) {}
51
52 SimpleTestLogListener::SimpleTestLogListener() = default;
53 SimpleTestLogListener::~SimpleTestLogListener() = default;
54
ListenToLog(const fidl::Client<fuchsia_logger::Log> & log,std::unique_ptr<fuchsia_logger::LogFilterOptions> options)55 void SimpleTestLogListener::ListenToLog(
56 const fidl::Client<fuchsia_logger::Log>& log,
57 std::unique_ptr<fuchsia_logger::LogFilterOptions> options) {
58 auto listener_endpoints =
59 fidl::CreateEndpoints<fuchsia_logger::LogListenerSafe>();
60 ZX_CHECK(listener_endpoints.is_ok(), listener_endpoints.status_value())
61 << "Failed to create listener endpoints";
62 binding_.emplace(
63 async_get_default_dispatcher(), std::move(listener_endpoints->server),
64 &listener_, [](fidl::UnbindInfo info) {
65 ZX_LOG(ERROR, info.status()) << "LogListenerSafe disconnected";
66 });
67
68 ignore_before_ = zx::clock::get_monotonic();
69 listener_.set_on_log_message(base::BindRepeating(
70 &SimpleTestLogListener::PushLoggedMessage, base::Unretained(this)));
71 auto listen_safe_result =
72 log->ListenSafe({{.log_listener = std::move(listener_endpoints->client),
73 .options = std::move(options)}});
74 if (listen_safe_result.is_error()) {
75 ZX_DLOG(ERROR, listen_safe_result.error_value().status())
76 << "ListenSafe() failed";
77 }
78 }
79
80 absl::optional<fuchsia_logger::LogMessage>
RunUntilMessageReceived(base::StringPiece expected_string)81 SimpleTestLogListener::RunUntilMessageReceived(
82 base::StringPiece expected_string) {
83 while (!logged_messages_.empty()) {
84 fuchsia_logger::LogMessage message = logged_messages_.front();
85 logged_messages_.pop_front();
86 if (base::StringPiece(message.msg()).find(expected_string) !=
87 std::string::npos) {
88 return message;
89 }
90 }
91
92 absl::optional<fuchsia_logger::LogMessage> logged_message;
93 base::RunLoop loop;
94 on_log_message_ = base::BindLambdaForTesting(
95 [ignore_before = ignore_before_, &logged_message,
96 expected_string = std::string(expected_string),
97 quit_loop =
98 loop.QuitClosure()](const fuchsia_logger::LogMessage& message) {
99 if (zx::time(message.time()) < ignore_before) {
100 return;
101 }
102 if (message.msg().find(expected_string) == std::string::npos) {
103 return;
104 }
105 logged_message.emplace(message);
106 quit_loop.Run();
107 });
108
109 loop.Run();
110
111 on_log_message_ = NullCallback();
112
113 return logged_message;
114 }
115
PushLoggedMessage(const fuchsia_logger::LogMessage & message)116 void SimpleTestLogListener::PushLoggedMessage(
117 const fuchsia_logger::LogMessage& message) {
118 DVLOG(1) << "TestLogListener received: " << message.msg();
119 if (zx::time(message.time()) < ignore_before_) {
120 return;
121 }
122 if (on_log_message_) {
123 DCHECK(logged_messages_.empty());
124 on_log_message_.Run(message);
125 } else {
126 logged_messages_.push_back(std::move(message));
127 }
128 }
129
ListenFilteredByCurrentProcessId(SimpleTestLogListener & listener)130 void ListenFilteredByCurrentProcessId(SimpleTestLogListener& listener) {
131 // Connect the test LogListenerSafe to the Log.
132 auto log_client_end = fuchsia_component::Connect<fuchsia_logger::Log>();
133 ASSERT_TRUE(log_client_end.is_ok())
134 << FidlConnectionErrorMessage(log_client_end);
135 fidl::Client log_client(std::move(log_client_end.value()),
136 async_get_default_dispatcher());
137 listener.ListenToLog(
138 log_client,
139 std::make_unique<fuchsia_logger::LogFilterOptions>(
140 fuchsia_logger::LogFilterOptions{
141 {.filter_by_pid = true,
142 .pid = Process::Current().Pid(),
143 .min_severity = fuchsia_logger::LogLevelFilter::kInfo}}));
144 }
145
146 } // namespace base
147