1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "content/browser/media/cdm_registry_impl.h"
6 
7 #include <algorithm>
8 #include <string>
9 #include <vector>
10 
11 #include "base/base_paths.h"
12 #include "base/containers/flat_set.h"
13 #include "base/files/file_path.h"
14 #include "base/strings/string_split.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/token.h"
18 #include "base/version.h"
19 #include "content/public/common/cdm_info.h"
20 #include "media/base/video_codecs.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 
23 namespace content {
24 
25 namespace {
26 
27 using VideoCodec = media::VideoCodec;
28 using EncryptionScheme = media::EncryptionScheme;
29 using CdmSessionType = media::CdmSessionType;
30 
31 const char kTestCdmName[] = "Test CDM";
32 const char kAlternateCdmName[] = "Alternate CDM";
33 const base::Token kTestCdmGuid{1234, 5678};
34 const char kTestPath[] = "/aa/bb";
35 const char kVersion1[] = "1.1.1.1";
36 const char kVersion2[] = "1.1.1.2";
37 const char kTestKeySystem[] = "com.example.somesystem";
38 const char kTestFileSystemId[] = "file_system_id";
39 
40 // Helper function to compare a STL container to an initializer_list.
41 template <typename Container, typename T>
StlEquals(const Container a,std::initializer_list<T> b)42 bool StlEquals(const Container a, std::initializer_list<T> b) {
43   return a == Container(b);
44 }
45 
46 #define EXPECT_STL_EQ(a, ...)                 \
47   do {                                        \
48     EXPECT_TRUE(StlEquals(a, {__VA_ARGS__})); \
49   } while (false)
50 
51 #define EXPECT_VIDEO_CODECS(...) \
52   EXPECT_STL_EQ(cdm.capability.video_codecs, __VA_ARGS__)
53 
54 #define EXPECT_ENCRYPTION_SCHEMES(...) \
55   EXPECT_STL_EQ(cdm.capability.encryption_schemes, __VA_ARGS__)
56 
57 #define EXPECT_SESSION_TYPES(...) \
58   EXPECT_STL_EQ(cdm.capability.session_types, __VA_ARGS__)
59 
60 }  // namespace
61 
62 // For simplicity and to make failures easier to diagnose, this test uses
63 // std::string instead of base::FilePath and std::vector<std::string>.
64 class CdmRegistryImplTest : public testing::Test {
65  public:
CdmRegistryImplTest()66   CdmRegistryImplTest() {}
~CdmRegistryImplTest()67   ~CdmRegistryImplTest() override {}
68 
69  protected:
GetTestCdmInfo()70   CdmInfo GetTestCdmInfo() {
71     return CdmInfo(
72         kTestCdmName, kTestCdmGuid, base::Version(kVersion1),
73         base::FilePath::FromUTF8Unsafe(kTestPath), kTestFileSystemId,
74         CdmCapability(
75             {media::kCodecVP8, media::kCodecVP9}, {EncryptionScheme::kCenc},
76             {CdmSessionType::kTemporary, CdmSessionType::kPersistentLicense}),
77         kTestKeySystem, /*supports_sub_key_systems=*/true);
78   }
79 
Register(CdmInfo cdm_info)80   void Register(CdmInfo cdm_info) {
81     cdm_registry_.RegisterCdm(std::move(cdm_info));
82   }
83 
IsRegistered(const std::string & name,const std::string & version)84   bool IsRegistered(const std::string& name, const std::string& version) {
85     for (const auto& cdm : cdm_registry_.GetAllRegisteredCdms()) {
86       if (cdm.name == name && cdm.version.GetString() == version)
87         return true;
88     }
89     return false;
90   }
91 
GetVersions(const base::Token & guid)92   std::vector<std::string> GetVersions(const base::Token& guid) {
93     std::vector<std::string> versions;
94     for (const auto& cdm : cdm_registry_.GetAllRegisteredCdms()) {
95       if (cdm.guid == guid)
96         versions.push_back(cdm.version.GetString());
97     }
98     return versions;
99   }
100 
101  protected:
102   CdmRegistryImpl cdm_registry_;
103 };
104 
TEST_F(CdmRegistryImplTest,Register)105 TEST_F(CdmRegistryImplTest, Register) {
106   Register(GetTestCdmInfo());
107 
108   auto cdms = cdm_registry_.GetAllRegisteredCdms();
109   ASSERT_EQ(1u, cdms.size());
110   CdmInfo cdm = cdms[0];
111   EXPECT_EQ(kTestCdmName, cdm.name);
112   EXPECT_EQ(kVersion1, cdm.version.GetString());
113   EXPECT_EQ(kTestPath, cdm.path.MaybeAsASCII());
114   EXPECT_EQ(kTestFileSystemId, cdm.file_system_id);
115   EXPECT_VIDEO_CODECS(VideoCodec::kCodecVP8, VideoCodec::kCodecVP9);
116   EXPECT_ENCRYPTION_SCHEMES(EncryptionScheme::kCenc);
117   EXPECT_SESSION_TYPES(CdmSessionType::kTemporary,
118                        CdmSessionType::kPersistentLicense);
119   EXPECT_EQ(kTestKeySystem, cdm.supported_key_system);
120   EXPECT_TRUE(cdm.supports_sub_key_systems);
121 }
122 
TEST_F(CdmRegistryImplTest,ReRegister)123 TEST_F(CdmRegistryImplTest, ReRegister) {
124   auto cdm_info = GetTestCdmInfo();
125   Register(cdm_info);
126   EXPECT_TRUE(IsRegistered(kTestCdmName, kVersion1));
127 
128   // Now register same key system with different values.
129   cdm_info.supports_sub_key_systems = false;
130   Register(cdm_info);
131 
132   EXPECT_TRUE(IsRegistered(kTestCdmName, kVersion1));
133 }
134 
TEST_F(CdmRegistryImplTest,MultipleVersions)135 TEST_F(CdmRegistryImplTest, MultipleVersions) {
136   auto cdm_info = GetTestCdmInfo();
137   Register(cdm_info);
138   cdm_info.version = base::Version(kVersion2);
139   Register(cdm_info);
140 
141   EXPECT_TRUE(IsRegistered(kTestCdmName, kVersion1));
142   EXPECT_TRUE(IsRegistered(kTestCdmName, kVersion2));
143 }
144 
TEST_F(CdmRegistryImplTest,NewVersionInsertedLast)145 TEST_F(CdmRegistryImplTest, NewVersionInsertedLast) {
146   auto cdm_info = GetTestCdmInfo();
147   Register(cdm_info);
148   cdm_info.version = base::Version(kVersion2);
149   Register(cdm_info);
150 
151   const std::vector<std::string> versions = GetVersions(kTestCdmGuid);
152   EXPECT_EQ(2u, versions.size());
153   EXPECT_EQ(kVersion1, versions[0]);
154   EXPECT_EQ(kVersion2, versions[1]);
155 }
156 
TEST_F(CdmRegistryImplTest,DifferentNames)157 TEST_F(CdmRegistryImplTest, DifferentNames) {
158   auto cdm_info = GetTestCdmInfo();
159   Register(cdm_info);
160   cdm_info.name = kAlternateCdmName;
161   Register(cdm_info);
162 
163   EXPECT_TRUE(IsRegistered(kTestCdmName, kVersion1));
164   EXPECT_TRUE(IsRegistered(kAlternateCdmName, kVersion1));
165 }
166 
TEST_F(CdmRegistryImplTest,SupportedEncryptionSchemes)167 TEST_F(CdmRegistryImplTest, SupportedEncryptionSchemes) {
168   auto cdm_info = GetTestCdmInfo();
169   cdm_info.capability.encryption_schemes = {EncryptionScheme::kCenc,
170                                             EncryptionScheme::kCbcs};
171   Register(cdm_info);
172 
173   std::vector<CdmInfo> cdms = cdm_registry_.GetAllRegisteredCdms();
174   ASSERT_EQ(1u, cdms.size());
175   const CdmInfo& cdm = cdms[0];
176   EXPECT_ENCRYPTION_SCHEMES(EncryptionScheme::kCenc, EncryptionScheme::kCbcs);
177 }
178 
179 }  // namespace content
180