chromium/fuchsia_web/webengine/browser/cast_streaming_browsertest.cc

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

#include <fuchsia/mem/cpp/fidl.h>

#include "base/fuchsia/mem_buffer_util.h"
#include "base/functional/callback_helpers.h"
#include "base/test/test_future.h"
#include "base/threading/platform_thread.h"
#include "components/cast/message_port/fuchsia/message_port_fuchsia.h"
#include "components/cast/message_port/platform_message_port.h"
#include "components/cast_streaming/test/cast_streaming_test_sender.h"
#include "content/public/test/browser_test.h"
#include "fuchsia_web/common/test/fit_adapter.h"
#include "fuchsia_web/common/test/frame_for_test.h"
#include "fuchsia_web/common/test/frame_test_util.h"
#include "fuchsia_web/common/test/test_navigation_listener.h"
#include "fuchsia_web/webengine/browser/context_impl.h"
#include "fuchsia_web/webengine/browser/frame_impl.h"
#include "fuchsia_web/webengine/test/test_data.h"
#include "fuchsia_web/webengine/test/web_engine_browser_test.h"
#include "media/base/media_util.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {

const char kCastStreamingReceiverPath[] = "/cast_streaming_receiver.html";

media::AudioDecoderConfig GetDefaultAudioConfig() {
  return media::AudioDecoderConfig(
      media::AudioCodec::kOpus, media::SampleFormat::kSampleFormatF32,
      media::ChannelLayout::CHANNEL_LAYOUT_STEREO,
      48000 /* samples_per_second */, media::EmptyExtraData(),
      media::EncryptionScheme::kUnencrypted);
}

media::VideoDecoderConfig GetDefaultVideoConfig() {
  const gfx::Size kVideoSize = {1920, 1080};
  const gfx::Rect kVideoRect(kVideoSize);

  return media::VideoDecoderConfig(
      media::VideoCodec::kVP8, media::VideoCodecProfile::VP8PROFILE_MIN,
      media::VideoDecoderConfig::AlphaMode::kIsOpaque, media::VideoColorSpace(),
      media::VideoTransformation(), kVideoSize, kVideoRect, kVideoSize,
      media::EmptyExtraData(), media::EncryptionScheme::kUnencrypted);
}

}  // namespace

// Base test fixture for Cast Streaming tests.
class CastStreamingBaseTest : public WebEngineBrowserTest {
 public:
  CastStreamingBaseTest() {
    set_test_server_root(base::FilePath(kTestServerRoot));
  }
  ~CastStreamingBaseTest() override = default;

  CastStreamingBaseTest(const CastStreamingBaseTest&) = delete;
  CastStreamingBaseTest& operator=(const CastStreamingBaseTest&) = delete;
};

// Test fixture for Cast Streaming tests with the Cast Streaming Receiver flag
// disabled.
class CastStreamingDisabledTest : public CastStreamingBaseTest {
 public:
  CastStreamingDisabledTest() = default;
  ~CastStreamingDisabledTest() override = default;
  CastStreamingDisabledTest(const CastStreamingDisabledTest&) = delete;
  CastStreamingDisabledTest& operator=(const CastStreamingDisabledTest&) =
      delete;

 protected:
  void SetUpCommandLine(base::CommandLine* command_line) override {
    content::BrowserTestBase::SetUpCommandLine(command_line);
    command_line->RemoveSwitch("enable-cast-streaming-receiver");
  }
};

// Test fixture for Cast Streaming tests with the Cast Streaming Receiver flag
// enabled.
class CastStreamingTest : public CastStreamingBaseTest {
 public:
  CastStreamingTest() = default;
  ~CastStreamingTest() override = default;
  CastStreamingTest(const CastStreamingTest&) = delete;
  CastStreamingTest& operator=(const CastStreamingTest&) = delete;

 protected:
  void SetUpCommandLine(base::CommandLine* command_line) override {
    content::BrowserTestBase::SetUpCommandLine(command_line);
    command_line->AppendSwitch("enable-cast-streaming-receiver");
  }
};

// Check that attempting to load the cast streaming media source URL when the
// command line switch is not set fails as expected.
IN_PROC_BROWSER_TEST_F(CastStreamingDisabledTest, LoadFailure) {
  ASSERT_TRUE(embedded_test_server()->Start());
  const GURL page_url(
      embedded_test_server()->GetURL(kCastStreamingReceiverPath));

  auto frame =
      FrameForTest::Create(context(), fuchsia::web::CreateFrameParams());
  EXPECT_TRUE(LoadUrlAndExpectResponse(frame.GetNavigationController(),
                                       fuchsia::web::LoadUrlParams(),
                                       page_url.spec()));
  frame.navigation_listener().RunUntilTitleEquals("error");
}

// Check that attempting to load the cast streaming media source URL when the
// command line switch is set properly succeeds.
IN_PROC_BROWSER_TEST_F(CastStreamingTest, LoadSuccess) {
  ASSERT_TRUE(embedded_test_server()->Start());
  const GURL page_url(
      embedded_test_server()->GetURL(kCastStreamingReceiverPath));
  fuchsia::mem::Buffer ignored_message_string =
      base::MemBufferFromString("hi", "test");

  std::unique_ptr<cast_api_bindings::MessagePort> sender_message_port;
  std::unique_ptr<cast_api_bindings::MessagePort> receiver_message_port;
  cast_api_bindings::CreatePlatformMessagePortPair(&sender_message_port,
                                                   &receiver_message_port);

  fidl::InterfaceRequest<::fuchsia::web::MessagePort> message_port_request =
      cast_api_bindings::MessagePortFuchsia::FromMessagePort(
          receiver_message_port.get())
          ->TakeServiceRequest();

  // Start the Sender
  cast_streaming::CastStreamingTestSender sender;
  sender.Start(std::move(sender_message_port), net::IPAddress::IPv6Localhost(),
               GetDefaultAudioConfig(), GetDefaultVideoConfig());

  // Create a Frame and set the Receiver MessagePort on it.
  auto frame =
      FrameForTest::Create(context(), fuchsia::web::CreateFrameParams());
  base::test::TestFuture<fuchsia::web::Frame_PostMessage_Result> post_result;
  frame->PostMessage(
      "cast-streaming:receiver",
      CreateWebMessageWithMessagePortRequest(std::move(message_port_request),
                                             std::move(ignored_message_string)),
      CallbackToFitFunction(post_result.GetCallback()));
  EXPECT_TRUE(LoadUrlAndExpectResponse(frame.GetNavigationController(),
                                       fuchsia::web::LoadUrlParams(),
                                       page_url.spec()));

  ASSERT_TRUE(sender.RunUntilActive());
  frame.navigation_listener().RunUntilTitleEquals("loadedmetadata");

  EXPECT_TRUE(post_result.Wait());
  EXPECT_NE(sender.audio_decoder_config(), std::nullopt);
  EXPECT_NE(sender.video_decoder_config(), std::nullopt);
}

// Check that attempting to start a video-only receiver properly disables audio.
IN_PROC_BROWSER_TEST_F(CastStreamingTest, VideoOnlyReceiver) {
  ASSERT_TRUE(embedded_test_server()->Start());
  const GURL kPageUrl(
      embedded_test_server()->GetURL(kCastStreamingReceiverPath));
  fuchsia::mem::Buffer ignored_message_string =
      base::MemBufferFromString("hi", "test");

  std::unique_ptr<cast_api_bindings::MessagePort> sender_message_port;
  std::unique_ptr<cast_api_bindings::MessagePort> receiver_message_port;
  cast_api_bindings::CreatePlatformMessagePortPair(&sender_message_port,
                                                   &receiver_message_port);

  fidl::InterfaceRequest<::fuchsia::web::MessagePort> message_port_request =
      cast_api_bindings::MessagePortFuchsia::FromMessagePort(
          receiver_message_port.get())
          ->TakeServiceRequest();

  // Start the Sender
  cast_streaming::CastStreamingTestSender sender;
  sender.Start(std::move(sender_message_port), net::IPAddress::IPv6Localhost(),
               GetDefaultAudioConfig(), GetDefaultVideoConfig());

  // Create a Frame and set the Receiver MessagePort on it.
  auto frame =
      FrameForTest::Create(context(), fuchsia::web::CreateFrameParams());
  base::test::TestFuture<fuchsia::web::Frame_PostMessage_Result> post_result;
  frame->PostMessage(
      "cast-streaming:video-only-receiver",
      CreateWebMessageWithMessagePortRequest(std::move(message_port_request),
                                             std::move(ignored_message_string)),
      CallbackToFitFunction(post_result.GetCallback()));

  EXPECT_TRUE(LoadUrlAndExpectResponse(frame.GetNavigationController(),
                                       fuchsia::web::LoadUrlParams(),
                                       kPageUrl.spec()));

  ASSERT_TRUE(sender.RunUntilActive());
  frame.navigation_listener().RunUntilTitleEquals("loadedmetadata");

  EXPECT_TRUE(post_result.Wait());
  EXPECT_EQ(sender.audio_decoder_config(), std::nullopt);
  EXPECT_NE(sender.video_decoder_config(), std::nullopt);
}