chromium/content/test/fuzzer/controller_presentation_service_delegate_for_fuzzing.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 CONTENT_TEST_FUZZER_CONTROLLER_PRESENTATION_SERVICE_DELEGATE_FOR_FUZZING_H_
#define CONTENT_TEST_FUZZER_CONTROLLER_PRESENTATION_SERVICE_DELEGATE_FOR_FUZZING_H_

#include <map>
#include <memory>
#include <string>

#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/presentation_screen_availability_listener.h"
#include "content/public/browser/presentation_service_delegate.h"
#include "content/test/fuzzer/controller_presentation_service_delegate_for_fuzzing.pb.h"
#include "media/base/flinging_controller.h"
#include "third_party/blink/public/mojom/presentation/presentation.mojom.h"

// Fake for the `ControllerPresentationServiceDelegate` interface
//
// This fake is limited to do callback, observer and listener behaviours,
// according to a set of actions specified by a protobuf.
// So it is not suitable for tests. It is designed for a fuzzer.
//
// Usage: call the component as expected as the delegate interface.
// To run the callables provided, use `NextAction`,
// provide a protobuf of the `Action` message - there lists the possible calls.
// This will instruct the fake to run the callbacks accordingly.
//
// The callables are run on the UI thread, as the delegate interface is expected
// to be called on the UI thread.
// In the case of MojoLPM fuzzers, `NextAction` should be called on the fuzzer
// thread.
class ControllerPresentationServiceDelegateForFuzzing
    : public content::ControllerPresentationServiceDelegate {
 public:
  ControllerPresentationServiceDelegateForFuzzing();
  ~ControllerPresentationServiceDelegateForFuzzing() override;

  // Used to run one callable.
  // These are set by using this as implementation of the delegate interface.
  // The callable is specified by the `action`, as defined in assocciated proto.
  //
  // All calls must be run on the same sequence
  // (for MojoLPM fuzzers, it should be the fuzzer thread)
  void NextAction(
      const content::fuzzing::
          controller_presentation_service_delegate_for_fuzzing::proto::Action&
              action);

  // ControllerPresentationServiceDelegate implementation
  void AddObserver(int render_process_id,
                   int render_frame_id,
                   Observer* observer) override;

  void RemoveObserver(int render_process_id, int render_frame_id) override;

  void Reset(int render_process_id, int render_frame_id) override;

  bool AddScreenAvailabilityListener(
      int render_process_id,
      int render_frame_id,
      content::PresentationScreenAvailabilityListener* listener) override;

  void RemoveScreenAvailabilityListener(
      int render_process_id,
      int render_frame_id,
      content::PresentationScreenAvailabilityListener* listener) override;

  void SetDefaultPresentationUrls(
      const content::PresentationRequest& request,
      content::DefaultPresentationConnectionCallback callback) override;

  void StartPresentation(
      const content::PresentationRequest& request,
      content::PresentationConnectionCallback success_cb,
      content::PresentationConnectionErrorCallback error_cb) override;

  void ReconnectPresentation(
      const content::PresentationRequest& request,
      const std::string& presentation_id,
      content::PresentationConnectionCallback success_cb,
      content::PresentationConnectionErrorCallback error_cb) override;

  void CloseConnection(int render_process_id,
                       int render_frame_id,
                       const std::string& presentation_id) override;

  void Terminate(int render_process_id,
                 int render_frame_id,
                 const std::string& presentation_id) override;

  std::unique_ptr<media::FlingingController> GetFlingingController(
      int render_process_id,
      int render_frame_id,
      const std::string& presentation_id) override;

  void ListenForConnectionStateChange(
      int render_process_id,
      int render_frame_id,
      const blink::mojom::PresentationInfo& connection,
      const content::PresentationConnectionStateChangedCallback&
          state_changed_cb) override;

 private:
  using Action = content::fuzzing::
      controller_presentation_service_delegate_for_fuzzing::proto::Action;

  // Use to invoke the callbacks & registered callables
  // For each, we have two member functions, where the first calls the second.
  // The first is prefixed by `Handle`, which takes the raw protobuf datatype,
  // and is run on the same thread as `NextAction` (for MojoLPM: fuzzer thread).
  // The second is prefixed by `Call` which invokes the call with the converted
  // datatype, and is run on the UI thread.
  void HandleListenersGetAvailabilityUrl(
      const mojolpm::url::mojom::Url& proto_url);
  void CallListenersGetAvailabilityUrl(GURL url);

  void HandleListenersOnScreenAvailabilityChanged(
      const mojolpm::url::mojom::Url& proto_url,
      const mojolpm::blink::mojom::ScreenAvailability&
          proto_screen_availability);
  void CallListenersOnScreenAvailabilityChanged(
      GURL url,
      blink::mojom::ScreenAvailability screen_availability);

  void HandleSetDefaultPresentationUrls(
      const mojolpm::blink::mojom::PresentationConnectionResult& proto_result);
  void CallSetDefaultPresentationUrls(
      blink::mojom::PresentationConnectionResultPtr result_ptr);

  void HandleStartPresentationSuccess(
      const mojolpm::blink::mojom::PresentationConnectionResult& proto_result);
  void CallStartPresentationSuccess(
      blink::mojom::PresentationConnectionResultPtr result_ptr);

  void HandleStartPresentationError(
      const mojolpm::blink::mojom::PresentationError& proto_error);
  void CallStartPresentationError(blink::mojom::PresentationErrorPtr error_ptr);

  void HandleReconnectPresentationSuccess(
      const mojolpm::blink::mojom::PresentationConnectionResult& proto_result);
  void CallReconnectPresentationSuccess(
      blink::mojom::PresentationConnectionResultPtr result_ptr);

  void HandleReconnectPresentationError(
      const mojolpm::blink::mojom::PresentationError& proto_error);
  void CallReconnectPresentationError(
      blink::mojom::PresentationErrorPtr error_ptr);

  void HandleListenForConnectionStateChangeStateChanged(
      const mojolpm::blink::mojom::PresentationConnectionState&
          proto_connection_state);
  void CallListenForConnectionStateChangeStateChanged(
      blink::mojom::PresentationConnectionState connection_state);

  base::WeakPtr<ControllerPresentationServiceDelegateForFuzzing> GetWeakPtr() {
    return weak_factory_.GetWeakPtr();
  }

  // We store all callbacks as single callables; not queued nor out of order,
  // as this mimics the real delegate as closely as possible
  std::map<content::GlobalRenderFrameHostId,
           content::PresentationServiceDelegate::Observer*>
      observers_;

  std::map<GURL, content::PresentationScreenAvailabilityListener*> listeners_;

  content::DefaultPresentationConnectionCallback
      set_default_presentation_urls_callback_;

  content::PresentationConnectionCallback start_presentation_success_cb_;

  content::PresentationConnectionErrorCallback start_presentation_error_cb_;

  content::PresentationConnectionCallback reconnect_presentation_success_cb_;

  content::PresentationConnectionErrorCallback reconnect_presentation_error_cb_;

  content::PresentationConnectionStateChangedCallback
      listen_for_connection_state_change_state_changed_cb_;

  SEQUENCE_CHECKER(sequence_checker_);

  // `PostTask`ing the calls onto the UI thread is not guaranteed to outlive
  // `this`. So a weak pointer is necessary for those calls.
  base::WeakPtrFactory<ControllerPresentationServiceDelegateForFuzzing>
      weak_factory_{this};
};

#endif  // CONTENT_TEST_FUZZER_CONTROLLER_PRESENTATION_SERVICE_DELEGATE_FOR_FUZZING_H_