1 // Copyright 2020 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 "chromeos/components/cdm_factory_daemon/content_decryption_module_adapter.h"
6
7 #include <algorithm>
8
9 #include "base/logging.h"
10 #include "base/test/mock_callback.h"
11 #include "base/test/task_environment.h"
12 #include "media/base/decoder_buffer.h"
13 #include "media/base/mock_filters.h"
14 #include "testing/gmock/include/gmock/gmock.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 using DaemonCdm = chromeos::cdm::mojom::ContentDecryptionModule;
18 using testing::_;
19 using testing::IsNull;
20
21 namespace chromeos {
22
23 namespace {
24
25 constexpr char kFakeEmeInitData[] = "fake_init_data";
26 const std::vector<uint8_t> kFakeEncryptedData = {42, 22, 26, 13, 7, 16, 8, 2};
27 const std::vector<uint8_t> kFakeSideData = {36, 24, 36};
28 constexpr char kFakeKeyId[] = "fake_key_id";
29 constexpr char kFakeIv[] = "fake_iv_16_bytes";
30 constexpr char kFakeServiceCertificate[] = "fake_service_cert";
31 constexpr char kFakeSessionId1[] = "fakeSid1";
32 constexpr char kFakeSessionId2[] = "fakeSid2";
33 constexpr char kFakeSessionUpdate[] = "fake_session_update";
34
35 constexpr int64_t kFakeTimestampSec = 42;
36 constexpr int64_t kFakeDurationSec = 64;
37
38 template <size_t size>
ToVector(const char (& array)[size])39 std::vector<uint8_t> ToVector(const char (&array)[size]) {
40 return std::vector<uint8_t>(array, array + size - 1);
41 }
42
43 MATCHER_P(MatchesDecoderBuffer, buffer, "") {
44 DCHECK(arg);
45 return arg->MatchesForTesting(*buffer);
46 }
47
48 MATCHER_P(MatchesDecryptConfig, config, "") {
49 DCHECK(arg);
50 return arg.Equals(*config);
51 }
52
53 // Mock of the mojo implementation on the Chrome OS side.
54 class MockDaemonCdm : public cdm::mojom::ContentDecryptionModule {
55 public:
MockDaemonCdm(mojo::PendingAssociatedReceiver<ContentDecryptionModule> pending_receiver)56 MockDaemonCdm(mojo::PendingAssociatedReceiver<ContentDecryptionModule>
57 pending_receiver) {
58 receiver_.Bind(std::move(pending_receiver));
59 }
60 ~MockDaemonCdm() = default;
61
62 MOCK_METHOD(void,
63 SetServerCertificate,
64 (const std::vector<uint8_t>&, SetServerCertificateCallback));
65 MOCK_METHOD(void,
66 GetStatusForPolicy,
67 (media::HdcpVersion, GetStatusForPolicyCallback));
68 MOCK_METHOD(void,
69 CreateSessionAndGenerateRequest,
70 (media::CdmSessionType,
71 media::EmeInitDataType,
72 const std::vector<uint8_t>&,
73 CreateSessionAndGenerateRequestCallback));
74 MOCK_METHOD(void,
75 LoadSession,
76 (media::CdmSessionType, const std::string&, LoadSessionCallback));
77 MOCK_METHOD(void,
78 UpdateSession,
79 (const std::string&,
80 const std::vector<uint8_t>&,
81 UpdateSessionCallback));
82 MOCK_METHOD(void, CloseSession, (const std::string&, CloseSessionCallback));
83 MOCK_METHOD(void, RemoveSession, (const std::string&, RemoveSessionCallback));
84 MOCK_METHOD(void,
85 Decrypt,
86 (const std::vector<uint8_t>&,
87 cdm::mojom::DecryptConfigPtr,
88 DecryptCallback));
89 MOCK_METHOD(void,
90 GetHwKeyData,
91 (cdm::mojom::DecryptConfigPtr,
92 const std::vector<uint8_t>&,
93 GetHwKeyDataCallback callback));
94
95 private:
96 mojo::AssociatedReceiver<ContentDecryptionModule> receiver_{this};
97 };
98
CreatePromise(bool success)99 cdm::mojom::CdmPromiseResultPtr CreatePromise(bool success) {
100 cdm::mojom::CdmPromiseResultPtr promise = cdm::mojom::CdmPromiseResult::New();
101 promise->success = success;
102 if (!success) {
103 promise->error_message = "error";
104 }
105 return promise;
106 }
107
CreateDecoderBuffer(const std::vector<uint8_t> data)108 scoped_refptr<media::DecoderBuffer> CreateDecoderBuffer(
109 const std::vector<uint8_t> data) {
110 scoped_refptr<media::DecoderBuffer> buffer = media::DecoderBuffer::CopyFrom(
111 data.data(), data.size(), kFakeSideData.data(), kFakeSideData.size());
112 buffer->set_timestamp(base::TimeDelta::FromSeconds(kFakeTimestampSec));
113 buffer->set_duration(base::TimeDelta::FromSeconds(kFakeDurationSec));
114 return buffer;
115 }
116
CloneDecoderBuffer(scoped_refptr<media::DecoderBuffer> buffer_in)117 scoped_refptr<media::DecoderBuffer> CloneDecoderBuffer(
118 scoped_refptr<media::DecoderBuffer> buffer_in) {
119 scoped_refptr<media::DecoderBuffer> buffer_out =
120 media::DecoderBuffer::CopyFrom(buffer_in->data(), buffer_in->data_size(),
121 buffer_in->side_data(),
122 buffer_in->side_data_size());
123 buffer_out->set_timestamp(buffer_in->timestamp());
124 buffer_out->set_duration(buffer_in->duration());
125 if (buffer_in->decrypt_config())
126 buffer_out->set_decrypt_config(buffer_in->decrypt_config()->Clone());
127 buffer_out->set_is_key_frame(buffer_in->is_key_frame());
128 return buffer_out;
129 }
130
131 } // namespace
132
133 class ContentDecryptionModuleAdapterTest : public testing::Test {
134 protected:
ContentDecryptionModuleAdapterTest()135 ContentDecryptionModuleAdapterTest() {
136 mojo::AssociatedRemote<cdm::mojom::ContentDecryptionModule> daemon_cdm_mojo;
137 mock_daemon_cdm_ = std::make_unique<MockDaemonCdm>(
138 daemon_cdm_mojo.BindNewEndpointAndPassDedicatedReceiver());
139 cdm_adapter_ = base::WrapRefCounted<ContentDecryptionModuleAdapter>(
140 new ContentDecryptionModuleAdapter(
141 nullptr /* storage */, std::move(daemon_cdm_mojo),
142 mock_session_message_cb_.Get(), mock_session_closed_cb_.Get(),
143 mock_session_keys_change_cb_.Get(),
144 mock_session_expiration_update_cb_.Get()));
145 }
146
~ContentDecryptionModuleAdapterTest()147 ~ContentDecryptionModuleAdapterTest() override {
148 // Destroy the CdmAdapter first so it can invoke any session closed
149 // callbacks on destruction before we destroy the callback mockers.
150 cdm_adapter_.reset();
151 }
152
LoadSession()153 void LoadSession() {
154 EXPECT_CALL(*mock_daemon_cdm_,
155 LoadSession(media::CdmSessionType::kPersistentLicense,
156 kFakeSessionId1, _))
157 .WillOnce([](media::CdmSessionType session_type,
158 const std::string& session_id,
159 MockDaemonCdm::LoadSessionCallback callback) {
160 std::move(callback).Run(CreatePromise(true), kFakeSessionId2);
161 });
162 std::string session_id;
163 std::unique_ptr<media::MockCdmSessionPromise> promise =
164 std::make_unique<media::MockCdmSessionPromise>(true, &session_id);
165 cdm_adapter_->LoadSession(media::CdmSessionType::kPersistentLicense,
166 kFakeSessionId1, std::move(promise));
167 base::RunLoop().RunUntilIdle();
168 EXPECT_EQ(session_id, kFakeSessionId2);
169 }
170
171 scoped_refptr<ContentDecryptionModuleAdapter> cdm_adapter_;
172 std::unique_ptr<MockDaemonCdm> mock_daemon_cdm_;
173
174 base::MockCallback<media::SessionMessageCB> mock_session_message_cb_;
175 base::MockCallback<media::SessionClosedCB> mock_session_closed_cb_;
176 base::MockCallback<media::SessionKeysChangeCB> mock_session_keys_change_cb_;
177 base::MockCallback<media::SessionExpirationUpdateCB>
178 mock_session_expiration_update_cb_;
179
180 private:
181 base::test::TaskEnvironment task_environment_;
182 };
183
TEST_F(ContentDecryptionModuleAdapterTest,GetClientInterface)184 TEST_F(ContentDecryptionModuleAdapterTest, GetClientInterface) {
185 auto pending_remote = cdm_adapter_->GetClientInterface();
186 EXPECT_TRUE(pending_remote.is_valid());
187 // If we try to get it again, it should fail.
188 ASSERT_DEATH(cdm_adapter_->GetClientInterface(), "");
189 }
190
TEST_F(ContentDecryptionModuleAdapterTest,SetServerCertificate_Failure)191 TEST_F(ContentDecryptionModuleAdapterTest, SetServerCertificate_Failure) {
192 EXPECT_CALL(*mock_daemon_cdm_,
193 SetServerCertificate(ToVector(kFakeServiceCertificate), _))
194 .WillOnce([](const std::vector<uint8_t>& cert,
195 MockDaemonCdm::SetServerCertificateCallback callback) {
196 std::move(callback).Run(CreatePromise(false));
197 });
198 std::unique_ptr<media::MockCdmPromise> promise =
199 std::make_unique<media::MockCdmPromise>(false);
200 cdm_adapter_->SetServerCertificate(ToVector(kFakeServiceCertificate),
201 std::move(promise));
202 base::RunLoop().RunUntilIdle();
203 }
204
TEST_F(ContentDecryptionModuleAdapterTest,SetServerCertificate_Success)205 TEST_F(ContentDecryptionModuleAdapterTest, SetServerCertificate_Success) {
206 EXPECT_CALL(*mock_daemon_cdm_,
207 SetServerCertificate(ToVector(kFakeServiceCertificate), _))
208 .WillOnce([](const std::vector<uint8_t>& cert,
209 MockDaemonCdm::SetServerCertificateCallback callback) {
210 std::move(callback).Run(CreatePromise(true));
211 });
212 std::unique_ptr<media::MockCdmPromise> promise =
213 std::make_unique<media::MockCdmPromise>(true);
214 cdm_adapter_->SetServerCertificate(ToVector(kFakeServiceCertificate),
215 std::move(promise));
216 base::RunLoop().RunUntilIdle();
217 }
218
TEST_F(ContentDecryptionModuleAdapterTest,GetStatusForPolicy_Failure)219 TEST_F(ContentDecryptionModuleAdapterTest, GetStatusForPolicy_Failure) {
220 EXPECT_CALL(*mock_daemon_cdm_,
221 GetStatusForPolicy(media::HdcpVersion::kHdcpVersion1_4, _))
222 .WillOnce([](media::HdcpVersion hdcp_version,
223 MockDaemonCdm::GetStatusForPolicyCallback callback) {
224 std::move(callback).Run(
225 CreatePromise(false),
226 media::CdmKeyInformation::KeyStatus::OUTPUT_RESTRICTED);
227 });
228 media::CdmKeyInformation::KeyStatus key_status;
229 std::unique_ptr<media::MockCdmKeyStatusPromise> promise =
230 std::make_unique<media::MockCdmKeyStatusPromise>(false, &key_status);
231 cdm_adapter_->GetStatusForPolicy(media::HdcpVersion::kHdcpVersion1_4,
232 std::move(promise));
233 base::RunLoop().RunUntilIdle();
234 }
235
TEST_F(ContentDecryptionModuleAdapterTest,GetStatusForPolicy_SuccessRestricted)236 TEST_F(ContentDecryptionModuleAdapterTest,
237 GetStatusForPolicy_SuccessRestricted) {
238 EXPECT_CALL(*mock_daemon_cdm_,
239 GetStatusForPolicy(media::HdcpVersion::kHdcpVersion2_2, _))
240 .WillOnce([](media::HdcpVersion hdcp_version,
241 MockDaemonCdm::GetStatusForPolicyCallback callback) {
242 std::move(callback).Run(
243 CreatePromise(true),
244 media::CdmKeyInformation::KeyStatus::OUTPUT_RESTRICTED);
245 });
246 media::CdmKeyInformation::KeyStatus key_status;
247 std::unique_ptr<media::MockCdmKeyStatusPromise> promise =
248 std::make_unique<media::MockCdmKeyStatusPromise>(true, &key_status);
249 cdm_adapter_->GetStatusForPolicy(media::HdcpVersion::kHdcpVersion2_2,
250 std::move(promise));
251 base::RunLoop().RunUntilIdle();
252 EXPECT_EQ(key_status, media::CdmKeyInformation::KeyStatus::OUTPUT_RESTRICTED);
253 }
254
TEST_F(ContentDecryptionModuleAdapterTest,GetStatusForPolicy_SuccessUsable)255 TEST_F(ContentDecryptionModuleAdapterTest, GetStatusForPolicy_SuccessUsable) {
256 EXPECT_CALL(*mock_daemon_cdm_,
257 GetStatusForPolicy(media::HdcpVersion::kHdcpVersion2_0, _))
258 .WillOnce([](media::HdcpVersion hdcp_version,
259 MockDaemonCdm::GetStatusForPolicyCallback callback) {
260 std::move(callback).Run(CreatePromise(true),
261 media::CdmKeyInformation::KeyStatus::USABLE);
262 });
263 media::CdmKeyInformation::KeyStatus key_status;
264 std::unique_ptr<media::MockCdmKeyStatusPromise> promise =
265 std::make_unique<media::MockCdmKeyStatusPromise>(true, &key_status);
266 cdm_adapter_->GetStatusForPolicy(media::HdcpVersion::kHdcpVersion2_0,
267 std::move(promise));
268 base::RunLoop().RunUntilIdle();
269 EXPECT_EQ(key_status, media::CdmKeyInformation::KeyStatus::USABLE);
270 }
271
TEST_F(ContentDecryptionModuleAdapterTest,CreateSessionAndGenerateRequest_Failure)272 TEST_F(ContentDecryptionModuleAdapterTest,
273 CreateSessionAndGenerateRequest_Failure) {
274 EXPECT_CALL(*mock_daemon_cdm_,
275 CreateSessionAndGenerateRequest(media::CdmSessionType::kTemporary,
276 media::EmeInitDataType::CENC,
277 ToVector(kFakeEmeInitData), _))
278 .WillOnce(
279 [](media::CdmSessionType session_type,
280 media::EmeInitDataType init_type,
281 const std::vector<uint8_t>& init_data,
282 MockDaemonCdm::CreateSessionAndGenerateRequestCallback callback) {
283 std::move(callback).Run(CreatePromise(false), "");
284 });
285 std::string session_id;
286 std::unique_ptr<media::MockCdmSessionPromise> promise =
287 std::make_unique<media::MockCdmSessionPromise>(false, &session_id);
288 cdm_adapter_->CreateSessionAndGenerateRequest(
289 media::CdmSessionType::kTemporary, media::EmeInitDataType::CENC,
290 ToVector(kFakeEmeInitData), std::move(promise));
291 base::RunLoop().RunUntilIdle();
292 }
293
TEST_F(ContentDecryptionModuleAdapterTest,CreateSessionAndGenerateRequest_Success)294 TEST_F(ContentDecryptionModuleAdapterTest,
295 CreateSessionAndGenerateRequest_Success) {
296 EXPECT_CALL(*mock_daemon_cdm_,
297 CreateSessionAndGenerateRequest(media::CdmSessionType::kTemporary,
298 media::EmeInitDataType::CENC,
299 ToVector(kFakeEmeInitData), _))
300 .WillOnce(
301 [](media::CdmSessionType session_type,
302 media::EmeInitDataType init_type,
303 const std::vector<uint8_t>& init_data,
304 MockDaemonCdm::CreateSessionAndGenerateRequestCallback callback) {
305 std::move(callback).Run(CreatePromise(true), kFakeSessionId1);
306 });
307 std::string session_id;
308 std::unique_ptr<media::MockCdmSessionPromise> promise =
309 std::make_unique<media::MockCdmSessionPromise>(true, &session_id);
310 cdm_adapter_->CreateSessionAndGenerateRequest(
311 media::CdmSessionType::kTemporary, media::EmeInitDataType::CENC,
312 ToVector(kFakeEmeInitData), std::move(promise));
313 // We should also be getting a session closed callback for any open sessions.
314 EXPECT_CALL(mock_session_closed_cb_, Run(kFakeSessionId1));
315 base::RunLoop().RunUntilIdle();
316 EXPECT_EQ(session_id, kFakeSessionId1);
317 }
318
TEST_F(ContentDecryptionModuleAdapterTest,LoadSession_Failure)319 TEST_F(ContentDecryptionModuleAdapterTest, LoadSession_Failure) {
320 EXPECT_CALL(*mock_daemon_cdm_,
321 LoadSession(media::CdmSessionType::kPersistentLicense,
322 kFakeSessionId1, _))
323 .WillOnce([](media::CdmSessionType session_type,
324 const std::string& session_id,
325 MockDaemonCdm::LoadSessionCallback callback) {
326 std::move(callback).Run(CreatePromise(false), "");
327 });
328 std::string session_id;
329 std::unique_ptr<media::MockCdmSessionPromise> promise =
330 std::make_unique<media::MockCdmSessionPromise>(false, &session_id);
331 cdm_adapter_->LoadSession(media::CdmSessionType::kPersistentLicense,
332 kFakeSessionId1, std::move(promise));
333 base::RunLoop().RunUntilIdle();
334 }
335
TEST_F(ContentDecryptionModuleAdapterTest,LoadSession_Success)336 TEST_F(ContentDecryptionModuleAdapterTest, LoadSession_Success) {
337 LoadSession();
338 // We should also be getting a session closed callback for any open sessions.
339 EXPECT_CALL(mock_session_closed_cb_, Run(kFakeSessionId2));
340 }
341
TEST_F(ContentDecryptionModuleAdapterTest,UpdateSession_Failure)342 TEST_F(ContentDecryptionModuleAdapterTest, UpdateSession_Failure) {
343 EXPECT_CALL(*mock_daemon_cdm_,
344 UpdateSession(kFakeSessionId1, ToVector(kFakeSessionUpdate), _))
345 .WillOnce([](const std::string& session_id,
346 const std::vector<uint8_t>& response,
347 MockDaemonCdm::UpdateSessionCallback callback) {
348 std::move(callback).Run(CreatePromise(false));
349 });
350 std::unique_ptr<media::MockCdmPromise> promise =
351 std::make_unique<media::MockCdmPromise>(false);
352 cdm_adapter_->UpdateSession(kFakeSessionId1, ToVector(kFakeSessionUpdate),
353 std::move(promise));
354 base::RunLoop().RunUntilIdle();
355 }
356
TEST_F(ContentDecryptionModuleAdapterTest,UpdateSession_Success)357 TEST_F(ContentDecryptionModuleAdapterTest, UpdateSession_Success) {
358 EXPECT_CALL(*mock_daemon_cdm_,
359 UpdateSession(kFakeSessionId1, ToVector(kFakeSessionUpdate), _))
360 .WillOnce([](const std::string& session_id,
361 const std::vector<uint8_t>& response,
362 MockDaemonCdm::UpdateSessionCallback callback) {
363 std::move(callback).Run(CreatePromise(true));
364 });
365 std::unique_ptr<media::MockCdmPromise> promise =
366 std::make_unique<media::MockCdmPromise>(true);
367 cdm_adapter_->UpdateSession(kFakeSessionId1, ToVector(kFakeSessionUpdate),
368 std::move(promise));
369 base::RunLoop().RunUntilIdle();
370 }
371
TEST_F(ContentDecryptionModuleAdapterTest,CloseSession_Failure)372 TEST_F(ContentDecryptionModuleAdapterTest, CloseSession_Failure) {
373 EXPECT_CALL(*mock_daemon_cdm_, CloseSession(kFakeSessionId1, _))
374 .WillOnce([](const std::string& session_id,
375 MockDaemonCdm::CloseSessionCallback callback) {
376 std::move(callback).Run(CreatePromise(false));
377 });
378 std::unique_ptr<media::MockCdmPromise> promise =
379 std::make_unique<media::MockCdmPromise>(false);
380 cdm_adapter_->CloseSession(kFakeSessionId1, std::move(promise));
381 base::RunLoop().RunUntilIdle();
382 }
383
TEST_F(ContentDecryptionModuleAdapterTest,CloseSession_Success)384 TEST_F(ContentDecryptionModuleAdapterTest, CloseSession_Success) {
385 EXPECT_CALL(*mock_daemon_cdm_, CloseSession(kFakeSessionId1, _))
386 .WillOnce([](const std::string& session_id,
387 MockDaemonCdm::CloseSessionCallback callback) {
388 std::move(callback).Run(CreatePromise(true));
389 });
390 std::unique_ptr<media::MockCdmPromise> promise =
391 std::make_unique<media::MockCdmPromise>(true);
392 cdm_adapter_->CloseSession(kFakeSessionId1, std::move(promise));
393 base::RunLoop().RunUntilIdle();
394 }
395
TEST_F(ContentDecryptionModuleAdapterTest,RemoveSession_Failure)396 TEST_F(ContentDecryptionModuleAdapterTest, RemoveSession_Failure) {
397 EXPECT_CALL(*mock_daemon_cdm_, RemoveSession(kFakeSessionId1, _))
398 .WillOnce([](const std::string& session_id,
399 MockDaemonCdm::RemoveSessionCallback callback) {
400 std::move(callback).Run(CreatePromise(false));
401 });
402 std::unique_ptr<media::MockCdmPromise> promise =
403 std::make_unique<media::MockCdmPromise>(false);
404 cdm_adapter_->RemoveSession(kFakeSessionId1, std::move(promise));
405 base::RunLoop().RunUntilIdle();
406 }
407
TEST_F(ContentDecryptionModuleAdapterTest,RemoveSession_Success)408 TEST_F(ContentDecryptionModuleAdapterTest, RemoveSession_Success) {
409 EXPECT_CALL(*mock_daemon_cdm_, RemoveSession(kFakeSessionId1, _))
410 .WillOnce([](const std::string& session_id,
411 MockDaemonCdm::RemoveSessionCallback callback) {
412 std::move(callback).Run(CreatePromise(true));
413 });
414 std::unique_ptr<media::MockCdmPromise> promise =
415 std::make_unique<media::MockCdmPromise>(true);
416 cdm_adapter_->RemoveSession(kFakeSessionId1, std::move(promise));
417 base::RunLoop().RunUntilIdle();
418 }
419
TEST_F(ContentDecryptionModuleAdapterTest,OnSessionMessage)420 TEST_F(ContentDecryptionModuleAdapterTest, OnSessionMessage) {
421 EXPECT_CALL(mock_session_message_cb_,
422 Run(kFakeSessionId1, media::CdmMessageType::LICENSE_REQUEST,
423 ToVector(kFakeSessionUpdate)));
424 cdm_adapter_->OnSessionMessage(kFakeSessionId1,
425 media::CdmMessageType::LICENSE_REQUEST,
426 ToVector(kFakeSessionUpdate));
427 }
428
TEST_F(ContentDecryptionModuleAdapterTest,OnSessionClosed)429 TEST_F(ContentDecryptionModuleAdapterTest, OnSessionClosed) {
430 LoadSession();
431 EXPECT_CALL(mock_session_closed_cb_, Run(kFakeSessionId2));
432 cdm_adapter_->OnSessionClosed(kFakeSessionId2);
433 }
434
TEST_F(ContentDecryptionModuleAdapterTest,OnSessionKeysChange)435 TEST_F(ContentDecryptionModuleAdapterTest, OnSessionKeysChange) {
436 EXPECT_CALL(mock_session_keys_change_cb_, Run(kFakeSessionId1, true, _));
437 cdm_adapter_->OnSessionKeysChange(kFakeSessionId1, true, {});
438 }
439
TEST_F(ContentDecryptionModuleAdapterTest,OnSessionExpirationUpdate)440 TEST_F(ContentDecryptionModuleAdapterTest, OnSessionExpirationUpdate) {
441 constexpr double kFakeExpiration = 123456;
442 EXPECT_CALL(mock_session_expiration_update_cb_,
443 Run(kFakeSessionId2, base::Time::FromDoubleT(kFakeExpiration)));
444 cdm_adapter_->OnSessionExpirationUpdate(kFakeSessionId2, kFakeExpiration);
445 }
446
TEST_F(ContentDecryptionModuleAdapterTest,RegisterNewKeyCB)447 TEST_F(ContentDecryptionModuleAdapterTest, RegisterNewKeyCB) {
448 base::MockCallback<media::CdmContext::EventCB> event_cb_1;
449 base::MockCallback<media::CdmContext::EventCB> event_cb_2;
450 auto cb_registration_1 = cdm_adapter_->RegisterEventCB(event_cb_1.Get());
451 auto cb_registration_2 = cdm_adapter_->RegisterEventCB(event_cb_2.Get());
452
453 // All registered event callbacks should be invoked.
454 EXPECT_CALL(event_cb_1,
455 Run(media::CdmContext::Event::kHasAdditionalUsableKey));
456 EXPECT_CALL(event_cb_2,
457 Run(media::CdmContext::Event::kHasAdditionalUsableKey));
458 EXPECT_CALL(mock_session_keys_change_cb_, Run(kFakeSessionId1, true, _));
459 cdm_adapter_->OnSessionKeysChange(kFakeSessionId1, true, {});
460 base::RunLoop().RunUntilIdle();
461
462 // If no keys change, no registered event callbacks should be invoked.
463 EXPECT_CALL(event_cb_1, Run(_)).Times(0);
464 EXPECT_CALL(event_cb_2, Run(_)).Times(0);
465 EXPECT_CALL(mock_session_keys_change_cb_, Run(kFakeSessionId1, false, _));
466 cdm_adapter_->OnSessionKeysChange(kFakeSessionId1, false, {});
467 base::RunLoop().RunUntilIdle();
468 }
469
TEST_F(ContentDecryptionModuleAdapterTest,Decrypt_Unencrypted)470 TEST_F(ContentDecryptionModuleAdapterTest, Decrypt_Unencrypted) {
471 EXPECT_CALL(*mock_daemon_cdm_, Decrypt(_, _, _)).Times(0);
472 scoped_refptr<media::DecoderBuffer> encrypted_buffer =
473 CreateDecoderBuffer(kFakeEncryptedData);
474 encrypted_buffer->set_is_key_frame(true);
475 scoped_refptr<media::DecoderBuffer> decrypted_buffer =
476 CloneDecoderBuffer(encrypted_buffer);
477 base::MockCallback<media::Decryptor::DecryptCB> callback;
478 EXPECT_CALL(callback, Run(media::Decryptor::kSuccess,
479 MatchesDecoderBuffer(decrypted_buffer)));
480 cdm_adapter_->Decrypt(media::Decryptor::kVideo, encrypted_buffer,
481 callback.Get());
482 }
483
TEST_F(ContentDecryptionModuleAdapterTest,Decrypt_NoSubsamples)484 TEST_F(ContentDecryptionModuleAdapterTest, Decrypt_NoSubsamples) {
485 cdm::mojom::DecryptConfigPtr expected_decrypt_config =
486 cdm::mojom::DecryptConfig::New(
487 media::EncryptionScheme::kCbcs, kFakeKeyId, kFakeIv,
488 std::vector<cdm::mojom::SubsampleEntryPtr>(),
489 media::EncryptionPattern(6, 9));
490 EXPECT_CALL(*mock_daemon_cdm_,
491 Decrypt(kFakeEncryptedData,
492 MatchesDecryptConfig(&expected_decrypt_config), _))
493 .WillOnce([](const std::vector<uint8_t>& data,
494 cdm::mojom::DecryptConfigPtr decrypt_config,
495 MockDaemonCdm::DecryptCallback callback) {
496 // For decryption, just reverse the data.
497 std::vector<uint8_t> decrypted = data;
498 std::reverse(std::begin(decrypted), std::end(decrypted));
499 std::move(callback).Run(media::Decryptor::kSuccess,
500 std::move(decrypted));
501 });
502 std::vector<uint8_t> decrypted_data = kFakeEncryptedData;
503 std::reverse(std::begin(decrypted_data), std::end(decrypted_data));
504 scoped_refptr<media::DecoderBuffer> decrypted_buffer =
505 CreateDecoderBuffer(decrypted_data);
506 decrypted_buffer->set_is_key_frame(true);
507
508 base::MockCallback<media::Decryptor::DecryptCB> callback;
509 EXPECT_CALL(callback, Run(media::Decryptor::kSuccess,
510 MatchesDecoderBuffer(decrypted_buffer)));
511 scoped_refptr<media::DecoderBuffer> encrypted_buffer =
512 CreateDecoderBuffer(kFakeEncryptedData);
513 encrypted_buffer->set_is_key_frame(true);
514 encrypted_buffer->set_decrypt_config(media::DecryptConfig::CreateCbcsConfig(
515 kFakeKeyId, kFakeIv, {}, media::EncryptionPattern(6, 9)));
516 cdm_adapter_->Decrypt(media::Decryptor::kVideo, encrypted_buffer,
517 callback.Get());
518 base::RunLoop().RunUntilIdle();
519 }
520
TEST_F(ContentDecryptionModuleAdapterTest,Decrypt_Failure)521 TEST_F(ContentDecryptionModuleAdapterTest, Decrypt_Failure) {
522 EXPECT_CALL(*mock_daemon_cdm_, Decrypt(_, _, _))
523 .WillOnce([](const std::vector<uint8_t>& data,
524 cdm::mojom::DecryptConfigPtr decrypt_config,
525 MockDaemonCdm::DecryptCallback callback) {
526 std::move(callback).Run(media::Decryptor::kError, {});
527 });
528 base::MockCallback<media::Decryptor::DecryptCB> callback;
529 EXPECT_CALL(callback, Run(media::Decryptor::kError, IsNull()));
530 scoped_refptr<media::DecoderBuffer> encrypted_buffer =
531 CreateDecoderBuffer(kFakeEncryptedData);
532 encrypted_buffer->set_decrypt_config(media::DecryptConfig::CreateCbcsConfig(
533 kFakeKeyId, kFakeIv, {}, media::EncryptionPattern(6, 9)));
534 cdm_adapter_->Decrypt(media::Decryptor::kVideo, encrypted_buffer,
535 callback.Get());
536 base::RunLoop().RunUntilIdle();
537 }
538
TEST_F(ContentDecryptionModuleAdapterTest,Decrypt_NoKey)539 TEST_F(ContentDecryptionModuleAdapterTest, Decrypt_NoKey) {
540 EXPECT_CALL(*mock_daemon_cdm_, Decrypt(_, _, _))
541 .WillOnce([](const std::vector<uint8_t>& data,
542 cdm::mojom::DecryptConfigPtr decrypt_config,
543 MockDaemonCdm::DecryptCallback callback) {
544 std::move(callback).Run(media::Decryptor::kNoKey, {});
545 });
546 base::MockCallback<media::Decryptor::DecryptCB> callback;
547 EXPECT_CALL(callback, Run(media::Decryptor::kNoKey, IsNull()));
548 scoped_refptr<media::DecoderBuffer> encrypted_buffer =
549 CreateDecoderBuffer(kFakeEncryptedData);
550 encrypted_buffer->set_decrypt_config(media::DecryptConfig::CreateCbcsConfig(
551 kFakeKeyId, kFakeIv, {}, media::EncryptionPattern(6, 9)));
552 cdm_adapter_->Decrypt(media::Decryptor::kVideo, encrypted_buffer,
553 callback.Get());
554 base::RunLoop().RunUntilIdle();
555 }
556
TEST_F(ContentDecryptionModuleAdapterTest,Decrypt_MismatchedSubsamples)557 TEST_F(ContentDecryptionModuleAdapterTest, Decrypt_MismatchedSubsamples) {
558 EXPECT_CALL(*mock_daemon_cdm_, Decrypt(_, _, _)).Times(0);
559 base::MockCallback<media::Decryptor::DecryptCB> callback;
560 EXPECT_CALL(callback, Run(media::Decryptor::kError, IsNull()));
561 scoped_refptr<media::DecoderBuffer> encrypted_buffer =
562 CreateDecoderBuffer(kFakeEncryptedData);
563 encrypted_buffer->set_decrypt_config(media::DecryptConfig::CreateCencConfig(
564 kFakeKeyId, kFakeIv, {media::SubsampleEntry(1, 1)}));
565 cdm_adapter_->Decrypt(media::Decryptor::kVideo, encrypted_buffer,
566 callback.Get());
567 base::RunLoop().RunUntilIdle();
568 }
569
TEST_F(ContentDecryptionModuleAdapterTest,Decrypt_InvalidSizeReturned)570 TEST_F(ContentDecryptionModuleAdapterTest, Decrypt_InvalidSizeReturned) {
571 EXPECT_CALL(*mock_daemon_cdm_, Decrypt(_, _, _))
572 .WillOnce([](const std::vector<uint8_t>& data,
573 cdm::mojom::DecryptConfigPtr decrypt_config,
574 MockDaemonCdm::DecryptCallback callback) {
575 std::move(callback).Run(media::Decryptor::kSuccess, {1});
576 });
577 base::MockCallback<media::Decryptor::DecryptCB> callback;
578 EXPECT_CALL(callback, Run(media::Decryptor::kError, IsNull()));
579 scoped_refptr<media::DecoderBuffer> encrypted_buffer =
580 CreateDecoderBuffer(kFakeEncryptedData);
581 encrypted_buffer->set_decrypt_config(media::DecryptConfig::CreateCbcsConfig(
582 kFakeKeyId, kFakeIv, {}, media::EncryptionPattern(4, 4)));
583 cdm_adapter_->Decrypt(media::Decryptor::kVideo, encrypted_buffer,
584 callback.Get());
585 base::RunLoop().RunUntilIdle();
586 }
587
TEST_F(ContentDecryptionModuleAdapterTest,Decrypt_NoEncryptedSubsamples)588 TEST_F(ContentDecryptionModuleAdapterTest, Decrypt_NoEncryptedSubsamples) {
589 EXPECT_CALL(*mock_daemon_cdm_, Decrypt(_, _, _)).Times(0);
590 scoped_refptr<media::DecoderBuffer> encrypted_buffer =
591 CreateDecoderBuffer(kFakeEncryptedData);
592 encrypted_buffer->set_decrypt_config(media::DecryptConfig::CreateCencConfig(
593 kFakeKeyId, kFakeIv,
594 {media::SubsampleEntry(kFakeEncryptedData.size(), 0)}));
595 scoped_refptr<media::DecoderBuffer> decrypted_buffer =
596 CloneDecoderBuffer(encrypted_buffer);
597 decrypted_buffer->set_decrypt_config(nullptr);
598 base::MockCallback<media::Decryptor::DecryptCB> callback;
599 EXPECT_CALL(callback, Run(media::Decryptor::kSuccess,
600 MatchesDecoderBuffer(decrypted_buffer)));
601 cdm_adapter_->Decrypt(media::Decryptor::kVideo, encrypted_buffer,
602 callback.Get());
603 }
604
TEST_F(ContentDecryptionModuleAdapterTest,Decrypt_SubsampledCenc)605 TEST_F(ContentDecryptionModuleAdapterTest, Decrypt_SubsampledCenc) {
606 cdm::mojom::DecryptConfigPtr expected_decrypt_config =
607 cdm::mojom::DecryptConfig::New(
608 media::EncryptionScheme::kCenc, kFakeKeyId, kFakeIv,
609 std::vector<cdm::mojom::SubsampleEntryPtr>(), base::nullopt);
610 EXPECT_CALL(*mock_daemon_cdm_,
611 Decrypt(std::vector<uint8_t>(kFakeEncryptedData.begin() + 3,
612 kFakeEncryptedData.end()),
613 MatchesDecryptConfig(&expected_decrypt_config), _))
614 .WillOnce([](const std::vector<uint8_t>& data,
615 cdm::mojom::DecryptConfigPtr decrypt_config,
616 MockDaemonCdm::DecryptCallback callback) {
617 // For decryption, just reverse the data.
618 std::vector<uint8_t> decrypted = data;
619 std::reverse(std::begin(decrypted), std::end(decrypted));
620 std::move(callback).Run(media::Decryptor::kSuccess,
621 std::move(decrypted));
622 });
623 std::vector<uint8_t> decrypted_data = kFakeEncryptedData;
624 std::reverse(std::begin(decrypted_data) + 3, std::end(decrypted_data));
625 scoped_refptr<media::DecoderBuffer> decrypted_buffer =
626 CreateDecoderBuffer(decrypted_data);
627 decrypted_buffer->set_is_key_frame(true);
628 base::MockCallback<media::Decryptor::DecryptCB> callback;
629 EXPECT_CALL(callback, Run(media::Decryptor::kSuccess,
630 MatchesDecoderBuffer(decrypted_buffer)));
631 scoped_refptr<media::DecoderBuffer> encrypted_buffer =
632 CreateDecoderBuffer(kFakeEncryptedData);
633 encrypted_buffer->set_is_key_frame(true);
634 encrypted_buffer->set_decrypt_config(media::DecryptConfig::CreateCencConfig(
635 kFakeKeyId, kFakeIv, {media::SubsampleEntry(3, 5)}));
636 cdm_adapter_->Decrypt(media::Decryptor::kVideo, encrypted_buffer,
637 callback.Get());
638 base::RunLoop().RunUntilIdle();
639 }
640
TEST_F(ContentDecryptionModuleAdapterTest,Decrypt_SubsampledCbcs)641 TEST_F(ContentDecryptionModuleAdapterTest, Decrypt_SubsampledCbcs) {
642 cdm::mojom::DecryptConfigPtr expected_decrypt_config =
643 cdm::mojom::DecryptConfig::New(
644 media::EncryptionScheme::kCbcs, kFakeKeyId, kFakeIv,
645 std::vector<cdm::mojom::SubsampleEntryPtr>(), base::nullopt);
646 expected_decrypt_config->subsamples.emplace_back(
647 cdm::mojom::SubsampleEntry::New(1, 2));
648 expected_decrypt_config->subsamples.emplace_back(
649 cdm::mojom::SubsampleEntry::New(2, 3));
650 EXPECT_CALL(*mock_daemon_cdm_,
651 Decrypt(kFakeEncryptedData,
652 MatchesDecryptConfig(&expected_decrypt_config), _))
653 .WillOnce([](const std::vector<uint8_t>& data,
654 cdm::mojom::DecryptConfigPtr decrypt_config,
655 MockDaemonCdm::DecryptCallback callback) {
656 // For decryption, just reverse the data.
657 std::vector<uint8_t> decrypted = data;
658 std::reverse(std::begin(decrypted), std::end(decrypted));
659 std::move(callback).Run(media::Decryptor::kSuccess,
660 std::move(decrypted));
661 });
662 std::vector<uint8_t> decrypted_data = kFakeEncryptedData;
663 std::reverse(std::begin(decrypted_data), std::end(decrypted_data));
664 scoped_refptr<media::DecoderBuffer> decrypted_buffer =
665 CreateDecoderBuffer(decrypted_data);
666 decrypted_buffer->set_is_key_frame(true);
667 base::MockCallback<media::Decryptor::DecryptCB> callback;
668 EXPECT_CALL(callback, Run(media::Decryptor::kSuccess,
669 MatchesDecoderBuffer(decrypted_buffer)));
670 scoped_refptr<media::DecoderBuffer> encrypted_buffer =
671 CreateDecoderBuffer(kFakeEncryptedData);
672 encrypted_buffer->set_is_key_frame(true);
673 encrypted_buffer->set_decrypt_config(media::DecryptConfig::CreateCbcsConfig(
674 kFakeKeyId, kFakeIv,
675 {media::SubsampleEntry(1, 2), media::SubsampleEntry(2, 3)},
676 base::nullopt));
677 cdm_adapter_->Decrypt(media::Decryptor::kVideo, encrypted_buffer,
678 callback.Get());
679 base::RunLoop().RunUntilIdle();
680 }
681
TEST_F(ContentDecryptionModuleAdapterTest,Decrypt_CancelDecrypt)682 TEST_F(ContentDecryptionModuleAdapterTest, Decrypt_CancelDecrypt) {
683 EXPECT_CALL(*mock_daemon_cdm_, Decrypt(_, _, _))
684 .WillOnce([](const std::vector<uint8_t>& data,
685 cdm::mojom::DecryptConfigPtr decrypt_config,
686 MockDaemonCdm::DecryptCallback callback) {
687 std::move(callback).Run(media::Decryptor::kSuccess, data);
688 });
689 scoped_refptr<media::DecoderBuffer> buffer =
690 CreateDecoderBuffer(kFakeEncryptedData);
691 buffer->set_decrypt_config(media::DecryptConfig::CreateCbcsConfig(
692 kFakeKeyId, kFakeIv, {}, media::EncryptionPattern(6, 9)));
693 base::MockCallback<media::Decryptor::DecryptCB> callback;
694 EXPECT_CALL(callback, Run(media::Decryptor::kSuccess, IsNull())).Times(1);
695 cdm_adapter_->Decrypt(media::Decryptor::kAudio, buffer, callback.Get());
696 cdm_adapter_->CancelDecrypt(media::Decryptor::kAudio);
697 base::RunLoop().RunUntilIdle();
698 }
699
700 } // namespace chromeos
701