cdm_adapter_unittest.cc 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. // Copyright 2015 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. #include "media/cdm/cdm_adapter.h"
  5. #include <stdint.h>
  6. #include <memory>
  7. #include "base/bind.h"
  8. #include "base/check.h"
  9. #include "base/command_line.h"
  10. #include "base/memory/raw_ptr.h"
  11. #include "base/run_loop.h"
  12. #include "base/strings/string_number_conversions.h"
  13. #include "base/test/task_environment.h"
  14. #include "media/base/cdm_callback_promise.h"
  15. #include "media/base/cdm_key_information.h"
  16. #include "media/base/content_decryption_module.h"
  17. #include "media/base/media_switches.h"
  18. #include "media/base/mock_filters.h"
  19. #include "media/cdm/api/content_decryption_module.h"
  20. #include "media/cdm/cdm_module.h"
  21. #include "media/cdm/external_clear_key_test_helper.h"
  22. #include "media/cdm/library_cdm/cdm_host_proxy.h"
  23. #include "media/cdm/library_cdm/mock_library_cdm.h"
  24. #include "media/cdm/mock_helpers.h"
  25. #include "media/cdm/simple_cdm_allocator.h"
  26. #include "media/media_buildflags.h"
  27. #include "testing/gmock/include/gmock/gmock.h"
  28. #include "testing/gtest/include/gtest/gtest.h"
  29. using ::testing::Invoke;
  30. using ::testing::IsNull;
  31. using ::testing::NotNull;
  32. using ::testing::Return;
  33. using ::testing::Values;
  34. using ::testing::SaveArg;
  35. using ::testing::StrictMock;
  36. using ::testing::_;
  37. MATCHER(IsNotEmpty, "") {
  38. return !arg.empty();
  39. }
  40. MATCHER(IsNullTime, "") {
  41. return arg.is_null();
  42. }
  43. MATCHER(IsNullPlatformChallengeResponse, "") {
  44. // Only check the |signed_data| for simplicity.
  45. return !arg.signed_data;
  46. }
  47. // TODO(jrummell): These tests are a subset of those in aes_decryptor_unittest.
  48. // Refactor aes_decryptor_unittest.cc to handle AesDecryptor directly and
  49. // via CdmAdapter once CdmAdapter supports decrypting functionality. There
  50. // will also be tests that only CdmAdapter supports, like file IO, which
  51. // will need to be handled separately.
  52. namespace media {
  53. namespace {
  54. // Random key ID used to create a session.
  55. const uint8_t kKeyId[] = {
  56. // base64 equivalent is AQIDBAUGBwgJCgsMDQ4PEA
  57. 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
  58. 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
  59. };
  60. const char kKeyIdAsJWK[] = "{\"kids\": [\"AQIDBAUGBwgJCgsMDQ4PEA\"]}";
  61. const uint8_t kKeyIdAsPssh[] = {
  62. 0x00, 0x00, 0x00, 0x34, // size = 52
  63. 'p', 's', 's', 'h', // 'pssh'
  64. 0x01, // version = 1
  65. 0x00, 0x00, 0x00, // flags
  66. 0x10, 0x77, 0xEF, 0xEC, 0xC0, 0xB2, 0x4D, 0x02, // Common SystemID
  67. 0xAC, 0xE3, 0x3C, 0x1E, 0x52, 0xE2, 0xFB, 0x4B,
  68. 0x00, 0x00, 0x00, 0x01, // key count
  69. 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // key
  70. 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
  71. 0x00, 0x00, 0x00, 0x00, // datasize
  72. };
  73. // Key is 0x0405060708090a0b0c0d0e0f10111213,
  74. // base64 equivalent is BAUGBwgJCgsMDQ4PEBESEw.
  75. const char kKeyAsJWK[] =
  76. "{"
  77. " \"keys\": ["
  78. " {"
  79. " \"kty\": \"oct\","
  80. " \"alg\": \"A128KW\","
  81. " \"kid\": \"AQIDBAUGBwgJCgsMDQ4PEA\","
  82. " \"k\": \"BAUGBwgJCgsMDQ4PEBESEw\""
  83. " }"
  84. " ],"
  85. " \"type\": \"temporary\""
  86. "}";
  87. class MockFileIOClient : public cdm::FileIOClient {
  88. public:
  89. MockFileIOClient() = default;
  90. ~MockFileIOClient() override = default;
  91. MOCK_METHOD1(OnOpenComplete, void(Status));
  92. MOCK_METHOD3(OnReadComplete, void(Status, const uint8_t*, uint32_t));
  93. MOCK_METHOD1(OnWriteComplete, void(Status));
  94. };
  95. } // namespace
  96. // Tests CdmAdapter with the following parameter:
  97. // - int: CDM interface version to test.
  98. class CdmAdapterTestBase : public testing::Test,
  99. public testing::WithParamInterface<int> {
  100. public:
  101. enum ExpectedResult { SUCCESS, FAILURE };
  102. CdmAdapterTestBase() {
  103. base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
  104. switches::kOverrideEnabledCdmInterfaceVersion,
  105. base::NumberToString(GetCdmInterfaceVersion()));
  106. }
  107. CdmAdapterTestBase(const CdmAdapterTestBase&) = delete;
  108. CdmAdapterTestBase& operator=(const CdmAdapterTestBase&) = delete;
  109. ~CdmAdapterTestBase() override { CdmModule::ResetInstanceForTesting(); }
  110. protected:
  111. virtual CdmConfig GetCdmConfig() = 0;
  112. virtual CdmAdapter::CreateCdmFunc GetCreateCdmFunc() = 0;
  113. int GetCdmInterfaceVersion() { return GetParam(); }
  114. // Initializes the adapter. |expected_result| tests that the call succeeds
  115. // or generates an error.
  116. void InitializeWithCdmConfigAndExpect(const CdmConfig& cdm_config,
  117. ExpectedResult expected_result) {
  118. std::unique_ptr<CdmAllocator> allocator(new SimpleCdmAllocator());
  119. std::unique_ptr<StrictMock<MockCdmAuxiliaryHelper>> cdm_helper(
  120. new StrictMock<MockCdmAuxiliaryHelper>(std::move(allocator)));
  121. cdm_helper_ = cdm_helper.get();
  122. CdmAdapter::Create(
  123. cdm_config, GetCreateCdmFunc(), std::move(cdm_helper),
  124. base::BindRepeating(&MockCdmClient::OnSessionMessage,
  125. base::Unretained(&cdm_client_)),
  126. base::BindRepeating(&MockCdmClient::OnSessionClosed,
  127. base::Unretained(&cdm_client_)),
  128. base::BindRepeating(&MockCdmClient::OnSessionKeysChange,
  129. base::Unretained(&cdm_client_)),
  130. base::BindRepeating(&MockCdmClient::OnSessionExpirationUpdate,
  131. base::Unretained(&cdm_client_)),
  132. base::BindOnce(&CdmAdapterTestBase::OnCdmCreated,
  133. base::Unretained(this), expected_result));
  134. RunUntilIdle();
  135. ASSERT_EQ(expected_result == SUCCESS, !!cdm_);
  136. }
  137. void InitializeAndExpect(ExpectedResult expected_result) {
  138. // Default CdmConfig is sufficient for most tests.
  139. InitializeWithCdmConfigAndExpect(GetCdmConfig(), expected_result);
  140. }
  141. void OnCdmCreated(ExpectedResult expected_result,
  142. const scoped_refptr<ContentDecryptionModule>& cdm,
  143. const std::string& error_message) {
  144. if (cdm) {
  145. ASSERT_EQ(expected_result, SUCCESS)
  146. << "CDM creation succeeded unexpectedly.";
  147. CdmAdapter* cdm_adapter = static_cast<CdmAdapter*>(cdm.get());
  148. ASSERT_EQ(GetCdmInterfaceVersion(), cdm_adapter->GetInterfaceVersion());
  149. cdm_ = cdm;
  150. } else {
  151. ASSERT_EQ(expected_result, FAILURE) << error_message;
  152. }
  153. }
  154. void RunUntilIdle() { task_environment_.RunUntilIdle(); }
  155. StrictMock<MockCdmClient> cdm_client_;
  156. raw_ptr<StrictMock<MockCdmAuxiliaryHelper>> cdm_helper_ = nullptr;
  157. // Keep track of the loaded CDM.
  158. scoped_refptr<ContentDecryptionModule> cdm_;
  159. base::test::SingleThreadTaskEnvironment task_environment_;
  160. };
  161. class CdmAdapterTestWithClearKeyCdm : public CdmAdapterTestBase {
  162. public:
  163. ~CdmAdapterTestWithClearKeyCdm() {
  164. // Clear |cdm_| before we destroy |helper_|.
  165. cdm_ = nullptr;
  166. RunUntilIdle();
  167. }
  168. void SetUp() override {
  169. CdmAdapterTestBase::SetUp();
  170. #if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION)
  171. CdmModule::GetInstance()->Initialize(helper_.LibraryPath(), {});
  172. #else
  173. CdmModule::GetInstance()->Initialize(helper_.LibraryPath());
  174. #endif // BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION)
  175. }
  176. // CdmAdapterTestBase implementation.
  177. CdmConfig GetCdmConfig() override { return helper_.CdmConfig(); }
  178. CdmAdapter::CreateCdmFunc GetCreateCdmFunc() override {
  179. return CdmModule::GetInstance()->GetCreateCdmFunc();
  180. }
  181. protected:
  182. // Creates a new session using |key_id|. |session_id_| will be set
  183. // when the promise is resolved. |expected_result| tests that
  184. // CreateSessionAndGenerateRequest() succeeds or generates an error.
  185. void CreateSessionAndExpect(EmeInitDataType data_type,
  186. const std::vector<uint8_t>& key_id,
  187. ExpectedResult expected_result) {
  188. DCHECK(!key_id.empty());
  189. if (expected_result == SUCCESS) {
  190. EXPECT_CALL(cdm_client_, OnSessionMessage(IsNotEmpty(), _, _));
  191. }
  192. cdm_->CreateSessionAndGenerateRequest(
  193. CdmSessionType::kTemporary, data_type, key_id,
  194. CreateSessionPromise(expected_result));
  195. RunUntilIdle();
  196. }
  197. // Loads the session specified by |session_id|. |expected_result| tests
  198. // that LoadSession() succeeds or generates an error.
  199. void LoadSessionAndExpect(const std::string& session_id,
  200. ExpectedResult expected_result) {
  201. DCHECK(!session_id.empty());
  202. ASSERT_EQ(expected_result, FAILURE) << "LoadSession not supported.";
  203. cdm_->LoadSession(CdmSessionType::kTemporary, session_id,
  204. CreateSessionPromise(expected_result));
  205. RunUntilIdle();
  206. }
  207. // Updates the session specified by |session_id| with |key|. |expected_result|
  208. // tests that the update succeeds or generates an error. |new_key_expected|
  209. // is the expected parameter when the SessionKeysChange event happens.
  210. void UpdateSessionAndExpect(std::string session_id,
  211. const std::string& key,
  212. ExpectedResult expected_result,
  213. bool new_key_expected) {
  214. DCHECK(!key.empty());
  215. if (expected_result == SUCCESS) {
  216. EXPECT_CALL(cdm_client_,
  217. OnSessionKeysChangeCalled(session_id, new_key_expected));
  218. EXPECT_CALL(cdm_client_,
  219. OnSessionExpirationUpdate(session_id, IsNullTime()));
  220. } else {
  221. EXPECT_CALL(cdm_client_, OnSessionKeysChangeCalled(_, _)).Times(0);
  222. EXPECT_CALL(cdm_client_, OnSessionExpirationUpdate(_, _)).Times(0);
  223. }
  224. cdm_->UpdateSession(session_id,
  225. std::vector<uint8_t>(key.begin(), key.end()),
  226. CreatePromise(expected_result));
  227. RunUntilIdle();
  228. }
  229. std::string SessionId() { return session_id_; }
  230. private:
  231. // Methods used for promise resolved/rejected.
  232. MOCK_METHOD0(OnResolve, void());
  233. MOCK_METHOD1(OnResolveWithSession, void(const std::string& session_id));
  234. MOCK_METHOD3(OnReject,
  235. void(CdmPromise::Exception exception_code,
  236. uint32_t system_code,
  237. const std::string& error_message));
  238. // Create a promise. |expected_result| is used to indicate how the promise
  239. // should be fulfilled.
  240. std::unique_ptr<SimpleCdmPromise> CreatePromise(
  241. ExpectedResult expected_result) {
  242. if (expected_result == SUCCESS) {
  243. EXPECT_CALL(*this, OnResolve());
  244. } else {
  245. EXPECT_CALL(*this, OnReject(_, _, IsNotEmpty()));
  246. }
  247. std::unique_ptr<SimpleCdmPromise> promise(new CdmCallbackPromise<>(
  248. base::BindOnce(&CdmAdapterTestWithClearKeyCdm::OnResolve,
  249. base::Unretained(this)),
  250. base::BindOnce(&CdmAdapterTestWithClearKeyCdm::OnReject,
  251. base::Unretained(this))));
  252. return promise;
  253. }
  254. // Create a promise to be used when a new session is created.
  255. // |expected_result| is used to indicate how the promise should be fulfilled.
  256. std::unique_ptr<NewSessionCdmPromise> CreateSessionPromise(
  257. ExpectedResult expected_result) {
  258. if (expected_result == SUCCESS) {
  259. EXPECT_CALL(*this, OnResolveWithSession(_))
  260. .WillOnce(SaveArg<0>(&session_id_));
  261. } else {
  262. EXPECT_CALL(*this, OnReject(_, _, IsNotEmpty()));
  263. }
  264. std::unique_ptr<NewSessionCdmPromise> promise(
  265. new CdmCallbackPromise<std::string>(
  266. base::BindOnce(&CdmAdapterTestWithClearKeyCdm::OnResolveWithSession,
  267. base::Unretained(this)),
  268. base::BindOnce(&CdmAdapterTestWithClearKeyCdm::OnReject,
  269. base::Unretained(this))));
  270. return promise;
  271. }
  272. // Helper class to load/unload Clear Key CDM Library.
  273. // TODO(xhwang): CdmModule does CDM loading/unloading by itself. So it seems
  274. // we don't need to use ExternalClearKeyTestHelper. Simplify this if possible.
  275. ExternalClearKeyTestHelper helper_;
  276. // |session_id_| is the latest result of calling CreateSession().
  277. std::string session_id_;
  278. };
  279. class CdmAdapterTestWithMockCdm : public CdmAdapterTestBase {
  280. public:
  281. ~CdmAdapterTestWithMockCdm() override {
  282. // Makes sure Destroy() is called on CdmAdapter destruction.
  283. EXPECT_CALL(*mock_library_cdm_, DestroyCalled());
  284. cdm_ = nullptr;
  285. RunUntilIdle();
  286. }
  287. // CdmAdapterTestBase implementation.
  288. CdmConfig GetCdmConfig() override {
  289. return {"x-com.mock", false, false, false};
  290. }
  291. CdmAdapter::CreateCdmFunc GetCreateCdmFunc() override {
  292. return CreateMockLibraryCdm;
  293. }
  294. protected:
  295. void InitializeWithCdmConfig(const CdmConfig& cdm_config) {
  296. // TODO(xhwang): Add tests for failure cases.
  297. InitializeWithCdmConfigAndExpect(cdm_config, SUCCESS);
  298. mock_library_cdm_ = MockLibraryCdm::GetInstance();
  299. ASSERT_TRUE(mock_library_cdm_);
  300. cdm_host_proxy_ = mock_library_cdm_->GetCdmHostProxy();
  301. ASSERT_TRUE(cdm_host_proxy_);
  302. }
  303. raw_ptr<MockLibraryCdm> mock_library_cdm_ = nullptr;
  304. raw_ptr<CdmHostProxy> cdm_host_proxy_ = nullptr;
  305. };
  306. // Instantiate test cases
  307. INSTANTIATE_TEST_SUITE_P(CDM_10, CdmAdapterTestWithClearKeyCdm, Values(10));
  308. INSTANTIATE_TEST_SUITE_P(CDM_11, CdmAdapterTestWithClearKeyCdm, Values(11));
  309. INSTANTIATE_TEST_SUITE_P(CDM_10, CdmAdapterTestWithMockCdm, Values(10));
  310. INSTANTIATE_TEST_SUITE_P(CDM_11, CdmAdapterTestWithMockCdm, Values(11));
  311. // CdmAdapterTestWithClearKeyCdm Tests
  312. TEST_P(CdmAdapterTestWithClearKeyCdm, Initialize) {
  313. InitializeAndExpect(SUCCESS);
  314. }
  315. // TODO(xhwang): This belongs to CdmModuleTest.
  316. TEST_P(CdmAdapterTestWithClearKeyCdm, BadLibraryPath) {
  317. CdmModule::ResetInstanceForTesting();
  318. #if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION)
  319. CdmModule::GetInstance()->Initialize(
  320. base::FilePath(FILE_PATH_LITERAL("no_library_here")), {});
  321. #else
  322. CdmModule::GetInstance()->Initialize(
  323. base::FilePath(FILE_PATH_LITERAL("no_library_here")));
  324. #endif // BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION)
  325. ASSERT_FALSE(GetCreateCdmFunc());
  326. }
  327. TEST_P(CdmAdapterTestWithClearKeyCdm, CreateWebmSession) {
  328. InitializeAndExpect(SUCCESS);
  329. std::vector<uint8_t> key_id(kKeyId, kKeyId + std::size(kKeyId));
  330. CreateSessionAndExpect(EmeInitDataType::WEBM, key_id, SUCCESS);
  331. }
  332. TEST_P(CdmAdapterTestWithClearKeyCdm, CreateKeyIdsSession) {
  333. InitializeAndExpect(SUCCESS);
  334. // Don't include the trailing /0 from the string in the data passed in.
  335. std::vector<uint8_t> key_id(kKeyIdAsJWK,
  336. kKeyIdAsJWK + std::size(kKeyIdAsJWK) - 1);
  337. CreateSessionAndExpect(EmeInitDataType::KEYIDS, key_id, SUCCESS);
  338. }
  339. TEST_P(CdmAdapterTestWithClearKeyCdm, CreateCencSession) {
  340. InitializeAndExpect(SUCCESS);
  341. std::vector<uint8_t> key_id(kKeyIdAsPssh,
  342. kKeyIdAsPssh + std::size(kKeyIdAsPssh));
  343. CreateSessionAndExpect(EmeInitDataType::CENC, key_id, SUCCESS);
  344. }
  345. TEST_P(CdmAdapterTestWithClearKeyCdm, CreateSessionWithBadData) {
  346. InitializeAndExpect(SUCCESS);
  347. // Use |kKeyId| but specify KEYIDS format.
  348. std::vector<uint8_t> key_id(kKeyId, kKeyId + std::size(kKeyId));
  349. CreateSessionAndExpect(EmeInitDataType::KEYIDS, key_id, FAILURE);
  350. }
  351. TEST_P(CdmAdapterTestWithClearKeyCdm, LoadSession) {
  352. InitializeAndExpect(SUCCESS);
  353. // LoadSession() is not supported by AesDecryptor.
  354. std::vector<uint8_t> key_id(kKeyId, kKeyId + std::size(kKeyId));
  355. CreateSessionAndExpect(EmeInitDataType::KEYIDS, key_id, FAILURE);
  356. }
  357. TEST_P(CdmAdapterTestWithClearKeyCdm, UpdateSession) {
  358. InitializeAndExpect(SUCCESS);
  359. std::vector<uint8_t> key_id(kKeyId, kKeyId + std::size(kKeyId));
  360. CreateSessionAndExpect(EmeInitDataType::WEBM, key_id, SUCCESS);
  361. UpdateSessionAndExpect(SessionId(), kKeyAsJWK, SUCCESS, true);
  362. }
  363. TEST_P(CdmAdapterTestWithClearKeyCdm, UpdateSessionWithBadData) {
  364. InitializeAndExpect(SUCCESS);
  365. std::vector<uint8_t> key_id(kKeyId, kKeyId + std::size(kKeyId));
  366. CreateSessionAndExpect(EmeInitDataType::WEBM, key_id, SUCCESS);
  367. UpdateSessionAndExpect(SessionId(), "random data", FAILURE, true);
  368. }
  369. // CdmAdapterTestWithMockCdm Tests
  370. // ChallengePlatform() will ask the helper to send platform challenge.
  371. TEST_P(CdmAdapterTestWithMockCdm, ChallengePlatform) {
  372. CdmConfig cdm_config = GetCdmConfig();
  373. cdm_config.allow_distinctive_identifier = true;
  374. InitializeWithCdmConfig(cdm_config);
  375. std::string service_id = "service_id";
  376. std::string challenge = "challenge";
  377. EXPECT_CALL(*cdm_helper_, ChallengePlatformCalled(service_id, challenge))
  378. .WillOnce(Return(true));
  379. EXPECT_CALL(*mock_library_cdm_, OnPlatformChallengeResponse(_));
  380. cdm_host_proxy_->SendPlatformChallenge(service_id.data(), service_id.size(),
  381. challenge.data(), challenge.size());
  382. RunUntilIdle();
  383. }
  384. // ChallengePlatform() will always fail if |allow_distinctive_identifier| is
  385. // false.
  386. TEST_P(CdmAdapterTestWithMockCdm,
  387. ChallengePlatform_DistinctiveIdentifierNotAllowed) {
  388. CdmConfig cdm_config = GetCdmConfig();
  389. cdm_config.allow_distinctive_identifier = false;
  390. InitializeWithCdmConfig(cdm_config);
  391. EXPECT_CALL(*mock_library_cdm_,
  392. OnPlatformChallengeResponse(IsNullPlatformChallengeResponse()));
  393. std::string service_id = "service_id";
  394. std::string challenge = "challenge";
  395. cdm_host_proxy_->SendPlatformChallenge(service_id.data(), service_id.size(),
  396. challenge.data(), challenge.size());
  397. RunUntilIdle();
  398. }
  399. // CreateFileIO() will ask helper to create FileIO.
  400. TEST_P(CdmAdapterTestWithMockCdm, CreateFileIO) {
  401. CdmConfig cdm_config = GetCdmConfig();
  402. cdm_config.allow_persistent_state = true;
  403. InitializeWithCdmConfig(cdm_config);
  404. MockFileIOClient file_io_client;
  405. EXPECT_CALL(*cdm_helper_, CreateCdmFileIO(_));
  406. cdm_host_proxy_->CreateFileIO(&file_io_client);
  407. RunUntilIdle();
  408. }
  409. // CreateFileIO() will always fail if |allow_persistent_state| is false.
  410. TEST_P(CdmAdapterTestWithMockCdm, CreateFileIO_PersistentStateNotAllowed) {
  411. CdmConfig cdm_config = GetCdmConfig();
  412. InitializeWithCdmConfig(cdm_config);
  413. // When |allow_persistent_state| is false, should return null immediately
  414. // without asking helper to create FileIO.
  415. MockFileIOClient file_io_client;
  416. ASSERT_FALSE(cdm_host_proxy_->CreateFileIO(&file_io_client));
  417. RunUntilIdle();
  418. }
  419. // RequestStorageId() with version 0 (latest) is supported.
  420. TEST_P(CdmAdapterTestWithMockCdm, RequestStorageId_Version_0) {
  421. CdmConfig cdm_config = GetCdmConfig();
  422. cdm_config.allow_persistent_state = true;
  423. InitializeWithCdmConfig(cdm_config);
  424. std::vector<uint8_t> storage_id = {1, 2, 3};
  425. EXPECT_CALL(*cdm_helper_, GetStorageIdCalled(0)).WillOnce(Return(storage_id));
  426. EXPECT_CALL(*mock_library_cdm_, OnStorageId(0, NotNull(), 3));
  427. cdm_host_proxy_->RequestStorageId(0);
  428. RunUntilIdle();
  429. }
  430. // RequestStorageId() with version 1 is supported.
  431. TEST_P(CdmAdapterTestWithMockCdm, RequestStorageId_Version_1) {
  432. CdmConfig cdm_config = GetCdmConfig();
  433. cdm_config.allow_persistent_state = true;
  434. InitializeWithCdmConfig(cdm_config);
  435. std::vector<uint8_t> storage_id = {1, 2, 3};
  436. EXPECT_CALL(*cdm_helper_, GetStorageIdCalled(1)).WillOnce(Return(storage_id));
  437. EXPECT_CALL(*mock_library_cdm_, OnStorageId(1, NotNull(), 3));
  438. cdm_host_proxy_->RequestStorageId(1);
  439. RunUntilIdle();
  440. }
  441. // RequestStorageId() with version 2 is not supported.
  442. TEST_P(CdmAdapterTestWithMockCdm, RequestStorageId_Version_2) {
  443. CdmConfig cdm_config = GetCdmConfig();
  444. cdm_config.allow_persistent_state = true;
  445. InitializeWithCdmConfig(cdm_config);
  446. EXPECT_CALL(*mock_library_cdm_, OnStorageId(2, IsNull(), 0));
  447. cdm_host_proxy_->RequestStorageId(2);
  448. RunUntilIdle();
  449. }
  450. // RequestStorageId() will always fail if |allow_persistent_state| is false.
  451. TEST_P(CdmAdapterTestWithMockCdm, RequestStorageId_PersistentStateNotAllowed) {
  452. CdmConfig cdm_config = GetCdmConfig();
  453. InitializeWithCdmConfig(cdm_config);
  454. EXPECT_CALL(*mock_library_cdm_, OnStorageId(1, IsNull(), 0));
  455. cdm_host_proxy_->RequestStorageId(1);
  456. RunUntilIdle();
  457. }
  458. TEST_P(CdmAdapterTestWithMockCdm, GetDecryptor) {
  459. CdmConfig cdm_config = GetCdmConfig();
  460. InitializeWithCdmConfig(cdm_config);
  461. auto* cdm_context = cdm_->GetCdmContext();
  462. ASSERT_TRUE(cdm_context);
  463. EXPECT_TRUE(cdm_context->GetDecryptor());
  464. }
  465. } // namespace media