chromium/base/fuchsia/test_log_listener_safe.h

// 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.

#ifndef BASE_FUCHSIA_TEST_LOG_LISTENER_SAFE_H_
#define BASE_FUCHSIA_TEST_LOG_LISTENER_SAFE_H_

#include <fidl/fuchsia.logger/cpp/fidl.h>
#include <lib/async/default.h>
#include <lib/fidl/cpp/binding.h>
#include <lib/zx/time.h>

#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <vector>

#include "base/containers/circular_deque.h"
#include "base/functional/callback.h"

namespace base {

// LogListenerSafe implementation that invokes a caller-supplied callback for
// each received message.
// Note that messages will be delivered in order of receipt from the system
// logger, starting with any recent messages that the logging service had
// cached, i.e. including messages that may pre-date this log-listener being
// created.
class TestLogListenerSafe final
    : public fidl::Server<fuchsia_logger::LogListenerSafe> {
 public:
  using OnLogMessageCallback =
      base::RepeatingCallback<void(const fuchsia_logger::LogMessage&)>;

  TestLogListenerSafe();
  ~TestLogListenerSafe() override;

  TestLogListenerSafe(const TestLogListenerSafe&) = delete;
  TestLogListenerSafe& operator=(const TestLogListenerSafe&) = delete;

  // Sets a callback to be invoked with every message received via Log().
  void set_on_log_message(OnLogMessageCallback callback);

 private:
  // LogListenerSafe implementation.
  void Log(LogRequest& request, LogCompleter::Sync& completer) override;
  void LogMany(LogManyRequest& request,
               LogManyCompleter::Sync& completer) override;
  void Done(DoneCompleter::Sync& completer) override;

  OnLogMessageCallback on_log_message_;
};

// Helper that manages a TestLogListenerSafe to simplify running the message
// loop until specific messages are received.
// Messages received prior to ListenToLog() being called will be silently
// ignored.
class SimpleTestLogListener {
 public:
  SimpleTestLogListener();
  ~SimpleTestLogListener();

  SimpleTestLogListener(const SimpleTestLogListener&) = delete;
  SimpleTestLogListener& operator=(const SimpleTestLogListener&) = delete;

  // Attaches this instance to receive data matching `options`, from `log`.
  void ListenToLog(const fidl::Client<fuchsia_logger::Log>& log,
                   std::unique_ptr<fuchsia_logger::LogFilterOptions> options);

  // Runs the message loop until a log message containing `expected_string` is
  // received, and returns it. Returns `std::nullopt` if `binding_` disconnects
  // without the `expected_string` having been logged.
  std::optional<fuchsia_logger::LogMessage> RunUntilMessageReceived(
      std::string_view expected_string);

 private:
  // Pushes `message` to the `logged_messages_` queue, or to `on_log_message_`.
  void PushLoggedMessage(const fuchsia_logger::LogMessage& message);

  // Used to ignore messages with timestamps prior to this listener's creation.
  zx::time ignore_before_;

  TestLogListenerSafe listener_;
  std::optional<fidl::ServerBinding<fuchsia_logger::LogListenerSafe>> binding_;

  base::circular_deque<fuchsia_logger::LogMessage> logged_messages_;
  TestLogListenerSafe::OnLogMessageCallback on_log_message_;
};

// Configures `listener` to listen for messages from the current process.
void ListenFilteredByCurrentProcessId(SimpleTestLogListener& listener);

}  // namespace base

#endif  // BASE_FUCHSIA_TEST_LOG_LISTENER_SAFE_H_