chromium/media/filters/hls_media_player_tag_recorder_unittest.cc

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/filters/hls_media_player_tag_recorder.h"

#include "base/test/gmock_callback_support.h"
#include "base/test/metrics/histogram_tester.h"
#include "media/filters/hls_network_access.h"
#include "media/filters/hls_test_helpers.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace media {
using ::base::test::RunOnceCallback;
using testing::_;
using testing::StrictMock;

const std::string kURL = "https://example.com/example.m3u8";

const std::string kEncryptedSimpleStream =
    "#EXTM3U\n"
    "#EXT-X-TARGETDURATION:2\n"
    "#EXT-X-MEDIA-SEQUENCE:0\n"
    "#EXT-X-PLAYLIST-TYPE:VOD\n"
    "#EXT-X-INDEPENDENT-SEGMENTS\n"
    "#EXT-X-KEY:METHOD=AES-128,URI=\"/"
    "enc.key\",IV=0xf4d52cf0dc02329c3ad6578744590658\n"
    "#EXTINF:1.600001,\n"
    "data00.ts\n"
    "#EXTINF:1.600002,\n"
    "data01.ts\n"
    "#EXTINF:1.600003,\n"
    "data02.ts\n"
    "#EXTINF:1.600004,\n"
    "data03.ts\n"
    "#EXTINF:1.600000,\n"
    "data04.ts\n"
    "#EXTINF:1.600000,\n"
    "data05.ts\n"
    "#EXTINF:1.600000,\n"
    "data06.ts\n"
    "#EXTINF:0.066667,\n"
    "data07.ts\n"
    "#EXT-X-ENDLIST\n";

const std::string kEncryptedSimpleStreamBadIV =
    "#EXTM3U\n"
    "#EXT-X-TARGETDURATION:2\n"
    "#EXT-X-MEDIA-SEQUENCE:0\n"
    "#EXT-X-PLAYLIST-TYPE:VOD\n"
    "#EXT-X-INDEPENDENT-SEGMENTS\n"
    "#EXT-X-KEY:METHOD=AES-128,URI=\"/"
    "enc.key\",IV=0xf4d52cf0dc02329c3ad578744590658\n"
    "#EXTINF:1.600001,\n"
    "data00.ts\n"
    "#EXTINF:1.600002,\n"
    "data01.ts\n"
    "#EXTINF:1.600003,\n"
    "data02.ts\n"
    "#EXTINF:1.600004,\n"
    "data03.ts\n"
    "#EXTINF:1.600000,\n"
    "data04.ts\n"
    "#EXTINF:1.600000,\n"
    "data05.ts\n"
    "#EXTINF:1.600000,\n"
    "data06.ts\n"
    "#EXTINF:0.066667,\n"
    "data07.ts\n"
    "#EXT-X-ENDLIST\n";

class HlsMediaPlayerTagRecorderTest : public testing::Test {
 public:
  HlsMediaPlayerTagRecorderTest() {
    auto network_access = std::make_unique<StrictMock<MockHlsNetworkAccess>>();
    network = network_access.get();
    recorder =
        std::make_unique<HlsMediaPlayerTagRecorder>(std::move(network_access));
  }

  ~HlsMediaPlayerTagRecorderTest() override { network = nullptr; }

  void BindManifest(std::string url,
                    std::string value,
                    bool taint_origin = false) {
    EXPECT_CALL(*network, ReadManifest(GURL(url), _))
        .Times(1)
        .WillOnce(RunOnceCallback<1>(
            StringHlsDataSourceStreamFactory::CreateStream(value, false)));
  }

 protected:
  raw_ptr<MockHlsNetworkAccess> network;
  std::unique_ptr<HlsMediaPlayerTagRecorder> recorder;
};

#define EXPECT_UMA(HT, NAME, VALUE)        \
  do {                                     \
    HT.ExpectUniqueSample(NAME, VALUE, 1); \
  } while (0)

#define EXPECT_NO_UMA(HT, NAME, VALUE)     \
  do {                                     \
    HT.ExpectUniqueSample(NAME, VALUE, 0); \
  } while (0)

TEST_F(HlsMediaPlayerTagRecorderTest, TestReadManifestParseBeforeOkSignal) {
  base::HistogramTester ht;
  BindManifest(kURL, kEncryptedSimpleStream);

  recorder->Start(GURL(kURL));

  EXPECT_NO_UMA(ht, "Media.HLS.PlaylistSegmentExtension", 0);
  EXPECT_NO_UMA(ht, "Media.HLS.AdvancedFeatureTags", 4);
  EXPECT_NO_UMA(ht, "Media.HLS.MultivariantPlaylist", 0);
  EXPECT_NO_UMA(ht, "Media.HLS.EncryptionMode", 1);

  recorder->AllowRecording();

  EXPECT_UMA(ht, "Media.HLS.PlaylistSegmentExtension", 0);
  EXPECT_UMA(ht, "Media.HLS.AdvancedFeatureTags", 4);
  EXPECT_UMA(ht, "Media.HLS.MultivariantPlaylist", 0);
  EXPECT_UMA(ht, "Media.HLS.EncryptionMode", 1);
}

TEST_F(HlsMediaPlayerTagRecorderTest, TestReadManifestParseAfterOkSignal) {
  base::HistogramTester ht;
  BindManifest(kURL, kEncryptedSimpleStream);

  recorder->AllowRecording();

  EXPECT_NO_UMA(ht, "Media.HLS.PlaylistSegmentExtension", 0);
  EXPECT_NO_UMA(ht, "Media.HLS.AdvancedFeatureTags", 4);
  EXPECT_NO_UMA(ht, "Media.HLS.MultivariantPlaylist", 0);
  EXPECT_NO_UMA(ht, "Media.HLS.EncryptionMode", 1);

  recorder->Start(GURL(kURL));

  EXPECT_UMA(ht, "Media.HLS.PlaylistSegmentExtension", 0);
  EXPECT_UMA(ht, "Media.HLS.AdvancedFeatureTags", 4);
  EXPECT_UMA(ht, "Media.HLS.MultivariantPlaylist", 0);
  EXPECT_UMA(ht, "Media.HLS.EncryptionMode", 1);
}

TEST_F(HlsMediaPlayerTagRecorderTest, TestInvalidManifest) {
  base::HistogramTester ht;
  BindManifest(kURL, kEncryptedSimpleStreamBadIV);
  recorder->AllowRecording();
  recorder->Start(GURL(kURL));
  EXPECT_UMA(ht, "Media.HLS.UnparsableManifest", 2);
}

#undef EXPECT_NO_UMA
#undef EXPECT_UMA

}  // namespace media