| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ui/display/manager/content_protection_key_manager.h" |
| |
| #include <memory> |
| #include <vector> |
| |
| #include "base/memory/raw_ptr.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/display/display_features.h" |
| #include "ui/display/manager/test/fake_display_snapshot.h" |
| #include "ui/display/manager/test/test_native_display_delegate.h" |
| #include "ui/display/types/display_constants.h" |
| |
| namespace display::test { |
| |
| namespace { |
| constexpr int64_t kDisplayId = 123; |
| const DisplayMode kDisplayMode({1366, 768}, false, 60.0f); |
| const std::string kFakeKey285 = |
| "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuv" |
| "wxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqr" |
| "stuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmn" |
| "opqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxy"; |
| |
| } // namespace |
| |
| class ContentProtectionKeyManagerTest : public testing::Test { |
| protected: |
| void SetProvisionedKeyRequest(bool use_valid_key) { |
| if (use_valid_key) { |
| key_manager_.set_provisioned_key_request(base::BindRepeating( |
| [](base::OnceCallback<void(const std::string&)> cb) { |
| std::move(cb).Run(kFakeKey285); |
| })); |
| } else { |
| key_manager_.set_provisioned_key_request(base::BindRepeating( |
| [](base::OnceCallback<void(const std::string&)> cb) { |
| std::move(cb).Run(""); |
| })); |
| } |
| } |
| |
| void SetKeyIfRequiredForDisplay(auto on_key_set) { |
| key_manager_.SetKeyIfRequired( |
| std::vector<raw_ptr<DisplaySnapshot, VectorExperimental>>{ |
| display_.get()}, |
| kDisplayId, std::move(on_key_set)); |
| } |
| |
| base::test::ScopedFeatureList scoped_feature_list_; |
| ContentProtectionKeyManager key_manager_; |
| std::unique_ptr<DisplaySnapshot> display_; |
| |
| ActionLogger log_; |
| TestNativeDisplayDelegate native_display_delegate_{&log_}; |
| |
| private: |
| void SetUp() override { |
| scoped_feature_list_.InitAndEnableFeature( |
| features::kRequireHdcpKeyProvisioning); |
| |
| key_manager_.set_native_display_delegate(&native_display_delegate_); |
| |
| display_ = FakeDisplaySnapshot::Builder() |
| .SetId(kDisplayId) |
| .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT) |
| .SetHasContentProtectionKey(true) |
| .SetCurrentMode(kDisplayMode.Clone()) |
| .Build(); |
| } |
| }; |
| |
| TEST_F(ContentProtectionKeyManagerTest, TestIfKeySetWhenServerKeyIsValid) { |
| SetProvisionedKeyRequest(true); |
| |
| auto on_key_set = base::BindOnce([](bool result) { EXPECT_TRUE(result); }); |
| |
| SetKeyIfRequiredForDisplay(std::move(on_key_set)); |
| |
| EXPECT_EQ(GetSetHdcpKeyPropAction(kDisplayId, true), |
| log_.GetActionsAndClear()); |
| } |
| |
| TEST_F(ContentProtectionKeyManagerTest, TestIfKeyNotSetWhenServerKeyIsEmpty) { |
| SetProvisionedKeyRequest(false); |
| |
| auto on_key_set = base::BindOnce([](bool result) { EXPECT_FALSE(result); }); |
| |
| SetKeyIfRequiredForDisplay(std::move(on_key_set)); |
| } |
| |
| TEST_F(ContentProtectionKeyManagerTest, TestIfKeyNotSetIfFeatureIsDisabled) { |
| scoped_feature_list_.Reset(); |
| |
| auto on_key_set = base::BindOnce([](bool result) { EXPECT_FALSE(result); }); |
| |
| SetKeyIfRequiredForDisplay(std::move(on_key_set)); |
| } |
| |
| TEST_F(ContentProtectionKeyManagerTest, TestIfKeyNotSetWhenDisplayIdMismatch) { |
| auto on_key_set = base::BindOnce([](bool result) { EXPECT_FALSE(result); }); |
| |
| key_manager_.SetKeyIfRequired( |
| std::vector<raw_ptr<DisplaySnapshot, VectorExperimental>>{display_.get()}, |
| kDisplayId + 1, std::move(on_key_set)); |
| } |
| |
| TEST_F(ContentProtectionKeyManagerTest, |
| TestIfKeySetWithMultipleDisplaysOneIsValid) { |
| auto other_display = FakeDisplaySnapshot::Builder() |
| .SetId(kDisplayId + 1) |
| .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT) |
| .SetHasContentProtectionKey(true) |
| .SetCurrentMode(kDisplayMode.Clone()) |
| .Build(); |
| |
| auto on_key_set = base::BindOnce([](bool result) { EXPECT_TRUE(result); }); |
| |
| SetProvisionedKeyRequest(true); |
| |
| auto displays = std::vector<raw_ptr<DisplaySnapshot, VectorExperimental>>{ |
| display_.get(), other_display.get()}; |
| key_manager_.SetKeyIfRequired(displays, kDisplayId, std::move(on_key_set)); |
| |
| EXPECT_EQ(GetSetHdcpKeyPropAction(kDisplayId, true), |
| log_.GetActionsAndClear()); |
| } |
| |
| TEST_F(ContentProtectionKeyManagerTest, TestIfKeyNotSetWhenDisplayIsEdp) { |
| display_ = FakeDisplaySnapshot::Builder() |
| .SetId(kDisplayId) |
| .SetType(DISPLAY_CONNECTION_TYPE_INTERNAL) |
| .SetHasContentProtectionKey(true) |
| .SetCurrentMode(kDisplayMode.Clone()) |
| .Build(); |
| |
| auto on_key_set = base::BindOnce([](bool result) { EXPECT_FALSE(result); }); |
| |
| SetKeyIfRequiredForDisplay(std::move(on_key_set)); |
| } |
| |
| TEST_F(ContentProtectionKeyManagerTest, |
| TestIfKeyNotSetWhenDisplayHasNoContentProtectionKeyProp) { |
| display_ = FakeDisplaySnapshot::Builder() |
| .SetId(kDisplayId) |
| .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT) |
| .SetHasContentProtectionKey(false) |
| .SetCurrentMode(kDisplayMode.Clone()) |
| .Build(); |
| |
| auto on_key_set = base::BindOnce([](bool result) { EXPECT_FALSE(result); }); |
| |
| SetKeyIfRequiredForDisplay(std::move(on_key_set)); |
| } |
| |
| TEST_F(ContentProtectionKeyManagerTest, TestThatKeyIsSetForMultipleDisplays) { |
| SetProvisionedKeyRequest(true); |
| |
| auto on_key_set = base::BindOnce([](bool result) { EXPECT_TRUE(result); }); |
| key_manager_.SetKeyIfRequired( |
| std::vector<raw_ptr<DisplaySnapshot, VectorExperimental>>{display_.get()}, |
| kDisplayId, std::move(on_key_set)); |
| |
| auto other_display = FakeDisplaySnapshot::Builder() |
| .SetId(kDisplayId + 1) |
| .SetType(DISPLAY_CONNECTION_TYPE_DISPLAYPORT) |
| .SetHasContentProtectionKey(true) |
| .SetCurrentMode(kDisplayMode.Clone()) |
| .Build(); |
| on_key_set = base::BindOnce([](bool result) { EXPECT_TRUE(result); }); |
| key_manager_.SetKeyIfRequired( |
| std::vector<raw_ptr<DisplaySnapshot, VectorExperimental>>{ |
| other_display.get()}, |
| kDisplayId + 1, std::move(on_key_set)); |
| |
| EXPECT_EQ(GetSetHdcpKeyPropAction(kDisplayId, true) + "," + |
| GetSetHdcpKeyPropAction(kDisplayId + 1, true), |
| log_.GetActionsAndClear()); |
| } |
| |
| TEST_F(ContentProtectionKeyManagerTest, |
| TestThatKeyIsFetchedOnlyOnceIfKeyValid) { |
| key_manager_.set_provisioned_key_request( |
| base::BindRepeating([](base::OnceCallback<void(const std::string&)> cb) { |
| static int fetch_key_call_count = 0; |
| |
| fetch_key_call_count++; |
| std::move(cb).Run(kFakeKey285); |
| |
| EXPECT_EQ(1, fetch_key_call_count); |
| })); |
| |
| auto on_key_set = base::BindOnce([](bool result) { EXPECT_TRUE(result); }); |
| |
| SetKeyIfRequiredForDisplay(std::move(on_key_set)); |
| |
| on_key_set = base::BindOnce([](bool result) { EXPECT_TRUE(true); }); |
| |
| key_manager_.SetKeyIfRequired( |
| std::vector<raw_ptr<DisplaySnapshot, VectorExperimental>>{display_.get()}, |
| kDisplayId + 1, std::move(on_key_set)); |
| } |
| |
| TEST_F(ContentProtectionKeyManagerTest, TestThatKeyIsFetchedAgainIfKeyInvalid) { |
| key_manager_.set_provisioned_key_request( |
| base::BindRepeating([](base::OnceCallback<void(const std::string&)> cb) { |
| static int fetch_key_call_count = 0; |
| |
| fetch_key_call_count++; |
| if (fetch_key_call_count == 1) { |
| std::move(cb).Run(""); |
| } else { |
| std::move(cb).Run(kFakeKey285); |
| |
| EXPECT_EQ(2, fetch_key_call_count); |
| } |
| })); |
| |
| auto on_key_set = base::BindOnce([](bool result) { EXPECT_FALSE(result); }); |
| |
| SetKeyIfRequiredForDisplay(std::move(on_key_set)); |
| |
| on_key_set = base::BindOnce([](bool result) { EXPECT_TRUE(true); }); |
| |
| key_manager_.SetKeyIfRequired( |
| std::vector<raw_ptr<DisplaySnapshot, VectorExperimental>>{display_.get()}, |
| kDisplayId + 1, std::move(on_key_set)); |
| } |
| |
| } // namespace display::test |