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