910e62b5创建于 1月15日历史提交
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <memory>
#include <string>
#include <utility>

#include "content/renderer/media/inspector_media_event_handler.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/web/web_media_inspector.h"

using ::testing::_;

namespace content {

class MockMediaInspectorContext : public blink::MediaInspectorContext {
 public:
  MockMediaInspectorContext() = default;
  virtual ~MockMediaInspectorContext() = default;

  void SetDomNodeIdForPlayer(const blink::WebString& player_id,
                             int dom_node_id) override {
    MockSetDomNodeIdForPlayer(dom_node_id);
  }

  blink::WebString CreatePlayer() override { return "TestPlayer"; }

  void DestroyPlayer(const blink::WebString& player_id) override {
    MockDestroyPlayer();
  }

  void NotifyPlayerEvents(blink::WebString id,
                          const blink::InspectorPlayerEvents& events) override {
    MockNotifyPlayerEvents(events);
  }

  void SetPlayerProperties(
      blink::WebString id,
      const blink::InspectorPlayerProperties& props) override {
    MockSetPlayerProperties(props);
  }

  void NotifyPlayerErrors(blink::WebString id,
                          const blink::InspectorPlayerErrors& errors) override {
    MockNotifyPlayerErrors(errors);
  }

  void NotifyPlayerMessages(
      blink::WebString id,
      const blink::InspectorPlayerMessages& messages) override {
    MockNotifyPlayerMessages(messages);
  }

  MOCK_METHOD1(MockNotifyPlayerEvents, void(blink::InspectorPlayerEvents));
  MOCK_METHOD1(MockSetPlayerProperties, void(blink::InspectorPlayerProperties));
  MOCK_METHOD1(MockNotifyPlayerErrors, void(blink::InspectorPlayerErrors));
  MOCK_METHOD1(MockNotifyPlayerMessages, void(blink::InspectorPlayerMessages));
  MOCK_METHOD0(MockDestroyPlayer, void());
  MOCK_METHOD0(MockIncrementActiveSessionCount, void());
  MOCK_METHOD0(MockDecrementActiveSessionCount, void());
  MOCK_METHOD1(MockSetDomNodeIdForPlayer, void(int));
};

class InspectorMediaEventHandlerTest : public testing::Test {
 public:
  InspectorMediaEventHandlerTest() {
    mock_context_ = std::make_unique<MockMediaInspectorContext>();
    handler_ =
        std::make_unique<InspectorMediaEventHandler>(mock_context_.get(), 123);
  }

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

 protected:
  std::unique_ptr<InspectorMediaEventHandler> handler_;
  std::unique_ptr<MockMediaInspectorContext> mock_context_;

  template <media::MediaLogEvent T>
  media::MediaLogRecord CreateEvent() {
    media::MediaLogRecord event;
    event.id = media::MediaPlayerLoggingID(0);
    event.type = media::MediaLogRecord::Type::kMediaEventTriggered;
    event.time = base::TimeTicks();
    event.params.Set("event", media::MediaLogEventTypeSupport<T>::TypeName());
    return event;
  }

  media::MediaLogRecord CreatePropChange(
      std::vector<std::pair<std::string, std::string>> props) {
    media::MediaLogRecord event;
    event.id = media::MediaPlayerLoggingID(0);
    event.type = media::MediaLogRecord::Type::kMediaPropertyChange;
    event.time = base::TimeTicks();
    for (auto p : props) {
      event.params.Set(std::get<0>(p), std::get<1>(p));
    }
    return event;
  }

  media::MediaLogRecord CreateMessage(std::string msg) {
    media::MediaLogRecord event;
    event.id = media::MediaPlayerLoggingID(0);
    event.type = media::MediaLogRecord::Type::kMessage;
    event.time = base::TimeTicks();
    event.params.Set("warning", msg);
    return event;
  }

  media::MediaLogRecord CreateError(int errorcode) {
    media::MediaLogRecord error;
    error.id = media::MediaPlayerLoggingID(0);
    error.type = media::MediaLogRecord::Type::kMediaStatus;
    error.time = base::TimeTicks();
    error.params.Set(media::StatusConstants::kCodeKey, errorcode);
    error.params.Set(media::StatusConstants::kGroupKey,
                     media::PipelineStatus::Traits::Group());
    return error;
  }
};

bool operator==(const blink::InspectorPlayerProperty& lhs,
                const blink::InspectorPlayerProperty& rhs) {
  return lhs.name == rhs.name && lhs.value == rhs.value;
}

bool operator==(const blink::InspectorPlayerEvent& lhs,
                const blink::InspectorPlayerEvent& rhs) {
  return lhs.timestamp == rhs.timestamp && lhs.value == rhs.value;
}

bool operator==(const blink::InspectorPlayerMessage& lhs,
                const blink::InspectorPlayerMessage& rhs) {
  return lhs.level == rhs.level && lhs.message == rhs.message;
}

bool operator==(const blink::InspectorPlayerError& lhs,
                const blink::InspectorPlayerError& rhs) {
  return lhs.group == rhs.group && lhs.code == rhs.code;
}

MATCHER_P(PropertiesEqualTo, props, "") {
  if (props.size() != arg.size())
    return false;
  for (size_t i = 0; i < props.size(); i++)
    if (props[i] != arg[i])
      return false;
  return true;
}

MATCHER_P(EventsEqualTo, events, "") {
  if (events.size() != arg.size())
    return false;
  for (size_t i = 0; i < events.size(); i++)
    if (events[i] != arg[i])
      return false;
  return true;
}

MATCHER_P(MessagesEqualTo, messages, "") {
  if (messages.size() != arg.size())
    return false;
  for (size_t i = 0; i < messages.size(); i++)
    if (messages[i] != arg[i])
      return false;
  return true;
}

MATCHER_P(ErrorsEqualTo, errors, "") {
  if (errors.size() != arg.size())
    return false;
  for (size_t i = 0; i < errors.size(); i++)
    if (errors[i] != arg[i])
      return false;
  return true;
}

TEST_F(InspectorMediaEventHandlerTest, CallsSetDomNodeId) {
  EXPECT_CALL(*mock_context_, MockSetDomNodeIdForPlayer(123)).Times(1);
  handler_ =
      std::make_unique<InspectorMediaEventHandler>(mock_context_.get(), 123);
}

TEST_F(InspectorMediaEventHandlerTest, ConvertsProperties) {
  std::vector<media::MediaLogRecord> events = {
      CreatePropChange({{"test_key", "test_value"}})};

  blink::InspectorPlayerProperties expected;
  blink::InspectorPlayerProperty prop = {
      blink::WebString::FromUTF8("test_key"),
      blink::WebString::FromUTF8("test_value")};
  expected.emplace_back(prop);
  EXPECT_CALL(*mock_context_,
              MockSetPlayerProperties(PropertiesEqualTo(expected)))
      .Times(1);
  EXPECT_CALL(*mock_context_, MockNotifyPlayerEvents(_)).Times(0);

  handler_->SendQueuedMediaEvents(events);
}

TEST_F(InspectorMediaEventHandlerTest, SplitsDoubleProperties) {
  std::vector<media::MediaLogRecord> events = {
      CreatePropChange({{"test_key", "test_value"}, {"foo", "bar"}})};

  blink::InspectorPlayerProperties expected;
  blink::InspectorPlayerProperty prop_test = {
      blink::WebString::FromUTF8("test_key"),
      blink::WebString::FromUTF8("test_value")};
  blink::InspectorPlayerProperty prop_foo = {blink::WebString::FromUTF8("foo"),
                                             blink::WebString::FromUTF8("bar")};
  expected.emplace_back(prop_foo);
  expected.emplace_back(prop_test);
  EXPECT_CALL(*mock_context_,
              MockSetPlayerProperties(PropertiesEqualTo(expected)))
      .Times(1);
  EXPECT_CALL(*mock_context_, MockNotifyPlayerEvents(_)).Times(0);

  handler_->SendQueuedMediaEvents(events);
}

TEST_F(InspectorMediaEventHandlerTest, ConvertsMessageEvent) {
  std::vector<media::MediaLogRecord> events = {
      CreateMessage("Has Anyone Really Been Far Even as Decided to Use Even "
                    "Go Want to do Look More Like?")};

  blink::InspectorPlayerMessages expected;
  blink::InspectorPlayerMessage e = {
      blink::InspectorPlayerMessage::Level::kWarning,
      blink::WebString::FromUTF8("Has Anyone Really Been Far Even as Decided "
                                 "to Use Even Go Want to do Look More Like?")};
  expected.emplace_back(e);

  EXPECT_CALL(*mock_context_, MockSetPlayerProperties(_)).Times(0);
  EXPECT_CALL(*mock_context_,
              MockNotifyPlayerMessages(MessagesEqualTo(expected)))
      .Times(1);

  handler_->SendQueuedMediaEvents(events);
}

TEST_F(InspectorMediaEventHandlerTest, ConvertsEventsAndProperties) {
  std::vector<media::MediaLogRecord> events = {
      CreateMessage("100% medically accurate"),
      CreatePropChange(
          {{"free_puppies", "all_taken"}, {"illuminati", "confirmed"}})};

  blink::InspectorPlayerMessages expected_messages;
  blink::InspectorPlayerMessage e = {
      blink::InspectorPlayerMessage::Level::kWarning,
      blink::WebString::FromUTF8("100% medically accurate")};
  expected_messages.emplace_back(e);

  blink::InspectorPlayerProperties expected_properties;
  blink::InspectorPlayerProperty puppies = {
      blink::WebString::FromUTF8("free_puppies"),
      blink::WebString::FromUTF8("all_taken")};
  blink::InspectorPlayerProperty illumanati = {
      blink::WebString::FromUTF8("illuminati"),
      blink::WebString::FromUTF8("confirmed")};
  expected_properties.emplace_back(puppies);
  expected_properties.emplace_back(illumanati);

  EXPECT_CALL(*mock_context_,
              MockSetPlayerProperties(PropertiesEqualTo(expected_properties)))
      .Times(1);
  EXPECT_CALL(*mock_context_,
              MockNotifyPlayerMessages(MessagesEqualTo(expected_messages)))
      .Times(1);

  handler_->SendQueuedMediaEvents(events);
}

TEST_F(InspectorMediaEventHandlerTest, PassesPlayAndPauseEvents) {
  std::vector<media::MediaLogRecord> events = {
      CreateEvent<media::MediaLogEvent::kPlay>(),
      CreateEvent<media::MediaLogEvent::kPause>()};

  blink::InspectorPlayerEvents expected_events;
  blink::InspectorPlayerEvent play = {
      base::TimeTicks(), blink::WebString::FromUTF8("{\"event\":\"kPlay\"}")};
  blink::InspectorPlayerEvent pause = {
      base::TimeTicks(), blink::WebString::FromUTF8("{\"event\":\"kPause\"}")};
  expected_events.emplace_back(play);
  expected_events.emplace_back(pause);

  EXPECT_CALL(*mock_context_,
              MockNotifyPlayerEvents(EventsEqualTo(expected_events)))
      .Times(1);

  handler_->SendQueuedMediaEvents(events);
}

TEST_F(InspectorMediaEventHandlerTest, PassesErrorEvents) {
  std::vector<media::MediaLogRecord> errors = {
      CreateError(media::PIPELINE_ERROR_NETWORK),
      CreateError(media::PIPELINE_ERROR_EXTERNAL_RENDERER_FAILED)};

  blink::InspectorPlayerErrors expected_errors;
  blink::InspectorPlayerError first = {"PipelineStatus", 2, "", {}, {}, {}};
  blink::InspectorPlayerError second = {"PipelineStatus", 21, "", {}, {}, {}};
  expected_errors.emplace_back(first);
  expected_errors.emplace_back(second);

  EXPECT_CALL(*mock_context_,
              MockNotifyPlayerErrors(ErrorsEqualTo(expected_errors)))
      .Times(1);

  handler_->SendQueuedMediaEvents(errors);
}

}  // namespace content