Commit 0d5d3189 authored by jrummell's avatar jrummell Committed by Commit bot

Test breaking the mojo connection to MojoCdm

Improve the testing on MojoCdm by adding a MockCdm. This allows for
testing that:
- resolving the promise works
- rejecting the promise works
- closing the connection before a call works
- closing the connection while executing the call works.

BUG=671362
TEST=new tests pass

Review-Url: https://codereview.chromium.org/2592913002
Cr-Commit-Position: refs/heads/master@{#442104}
parent 51b59b3a
......@@ -9,6 +9,7 @@
using ::testing::_;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::StrictMock;
MATCHER(NotEmpty, "") {
return !arg.empty();
......@@ -180,6 +181,118 @@ MockCdmSessionPromise::~MockCdmSessionPromise() {
MarkPromiseSettled();
}
MockCdm::MockCdm(const SessionMessageCB& session_message_cb,
const SessionClosedCB& session_closed_cb,
const SessionKeysChangeCB& session_keys_change_cb,
const SessionExpirationUpdateCB& session_expiration_update_cb)
: session_message_cb_(session_message_cb),
session_closed_cb_(session_closed_cb),
session_keys_change_cb_(session_keys_change_cb),
session_expiration_update_cb_(session_expiration_update_cb) {}
MockCdm::~MockCdm() {}
void MockCdm::SetServerCertificate(const std::vector<uint8_t>& certificate,
std::unique_ptr<SimpleCdmPromise> promise) {
OnSetServerCertificate(certificate, promise);
}
void MockCdm::CreateSessionAndGenerateRequest(
CdmSessionType session_type,
EmeInitDataType init_data_type,
const std::vector<uint8_t>& init_data,
std::unique_ptr<NewSessionCdmPromise> promise) {
OnCreateSessionAndGenerateRequest(session_type, init_data_type, init_data,
promise);
}
void MockCdm::LoadSession(CdmSessionType session_type,
const std::string& session_id,
std::unique_ptr<NewSessionCdmPromise> promise) {
OnLoadSession(session_type, session_id, promise);
}
void MockCdm::UpdateSession(const std::string& session_id,
const std::vector<uint8_t>& response,
std::unique_ptr<SimpleCdmPromise> promise) {
OnUpdateSession(session_id, response, promise);
}
void MockCdm::CloseSession(const std::string& session_id,
std::unique_ptr<SimpleCdmPromise> promise) {
OnCloseSession(session_id, promise);
}
void MockCdm::RemoveSession(const std::string& session_id,
std::unique_ptr<SimpleCdmPromise> promise) {
OnRemoveSession(session_id, promise);
}
void MockCdm::CallSessionMessageCB(
const std::string& session_id,
ContentDecryptionModule::MessageType message_type,
const std::vector<uint8_t>& message) {
session_message_cb_.Run(session_id, message_type, message);
}
void MockCdm::CallSessionClosedCB(const std::string& session_id) {
session_closed_cb_.Run(session_id);
}
void MockCdm::CallSessionKeysChangeCB(const std::string& session_id,
bool has_additional_usable_key,
CdmKeysInfo keys_info) {
session_keys_change_cb_.Run(session_id, has_additional_usable_key,
std::move(keys_info));
}
void MockCdm::CallSessionExpirationUpdateCB(const std::string& session_id,
base::Time new_expiry_time) {
session_expiration_update_cb_.Run(session_id, new_expiry_time);
}
MockCdmFactory::MockCdmFactory() {}
MockCdmFactory::~MockCdmFactory() {}
void MockCdmFactory::Create(
const std::string& key_system,
const GURL& security_origin,
const CdmConfig& cdm_config,
const SessionMessageCB& session_message_cb,
const SessionClosedCB& session_closed_cb,
const SessionKeysChangeCB& session_keys_change_cb,
const SessionExpirationUpdateCB& session_expiration_update_cb,
const CdmCreatedCB& cdm_created_cb) {
// If no key system specified, notify that Create() failed.
if (key_system.empty()) {
cdm_created_cb.Run(nullptr, "CDM creation failed");
return;
}
// Since there is a CDM, call |before_creation_cb_| first.
if (!before_creation_cb_.is_null())
before_creation_cb_.Run();
// Create and return a new MockCdm. Keep a pointer to the created CDM so
// that tests can access it. Calls to GetCdmContext() can be ignored.
scoped_refptr<MockCdm> cdm = new StrictMock<MockCdm>(
session_message_cb, session_closed_cb, session_keys_change_cb,
session_expiration_update_cb);
created_cdm_ = cdm.get();
EXPECT_CALL(*created_cdm_.get(), GetCdmContext());
cdm_created_cb.Run(std::move(cdm), "");
}
MockCdm* MockCdmFactory::GetCreatedCdm() {
return created_cdm_.get();
}
void MockCdmFactory::SetBeforeCreationCB(
const base::Closure& before_creation_cb) {
before_creation_cb_ = before_creation_cb;
}
MockStreamParser::MockStreamParser() {}
MockStreamParser::~MockStreamParser() {}
......
......@@ -15,9 +15,12 @@
#include "media/base/audio_decoder.h"
#include "media/base/audio_decoder_config.h"
#include "media/base/audio_renderer.h"
#include "media/base/cdm_config.h"
#include "media/base/cdm_context.h"
#include "media/base/cdm_factory.h"
#include "media/base/cdm_key_information.h"
#include "media/base/cdm_promise.h"
#include "media/base/cdm_promise_adapter.h"
#include "media/base/content_decryption_module.h"
#include "media/base/decoder_buffer.h"
#include "media/base/decryptor.h"
......@@ -446,6 +449,120 @@ class MockCdmSessionPromise : public NewSessionCdmPromise {
DISALLOW_COPY_AND_ASSIGN(MockCdmSessionPromise);
};
class MockCdm : public ContentDecryptionModule {
public:
MockCdm(const SessionMessageCB& session_message_cb,
const SessionClosedCB& session_closed_cb,
const SessionKeysChangeCB& session_keys_change_cb,
const SessionExpirationUpdateCB& session_expiration_update_cb);
// ContentDecryptionModule implementation.
// As move-only parameters aren't supported by mock methods, convert promises
// into IDs and pass them to On... methods.
void SetServerCertificate(const std::vector<uint8_t>& certificate,
std::unique_ptr<SimpleCdmPromise> promise) override;
MOCK_METHOD2(OnSetServerCertificate,
void(const std::vector<uint8_t>& certificate,
std::unique_ptr<SimpleCdmPromise>& promise));
void CreateSessionAndGenerateRequest(
CdmSessionType session_type,
EmeInitDataType init_data_type,
const std::vector<uint8_t>& init_data,
std::unique_ptr<NewSessionCdmPromise> promise) override;
MOCK_METHOD4(OnCreateSessionAndGenerateRequest,
void(CdmSessionType session_type,
EmeInitDataType init_data_type,
const std::vector<uint8_t>& init_data,
std::unique_ptr<NewSessionCdmPromise>& promise));
void LoadSession(CdmSessionType session_type,
const std::string& session_id,
std::unique_ptr<NewSessionCdmPromise> promise) override;
MOCK_METHOD3(OnLoadSession,
void(CdmSessionType session_type,
const std::string& session_id,
std::unique_ptr<NewSessionCdmPromise>& promise));
void UpdateSession(const std::string& session_id,
const std::vector<uint8_t>& response,
std::unique_ptr<SimpleCdmPromise> promise) override;
MOCK_METHOD3(OnUpdateSession,
void(const std::string& session_id,
const std::vector<uint8_t>& response,
std::unique_ptr<SimpleCdmPromise>& promise));
void CloseSession(const std::string& session_id,
std::unique_ptr<SimpleCdmPromise> promise) override;
MOCK_METHOD2(OnCloseSession,
void(const std::string& session_id,
std::unique_ptr<SimpleCdmPromise>& promise));
void RemoveSession(const std::string& session_id,
std::unique_ptr<SimpleCdmPromise> promise) override;
MOCK_METHOD2(OnRemoveSession,
void(const std::string& session_id,
std::unique_ptr<SimpleCdmPromise>& promise));
MOCK_METHOD0(GetCdmContext, CdmContext*());
void CallSessionMessageCB(const std::string& session_id,
ContentDecryptionModule::MessageType message_type,
const std::vector<uint8_t>& message);
void CallSessionClosedCB(const std::string& session_id);
void CallSessionKeysChangeCB(const std::string& session_id,
bool has_additional_usable_key,
CdmKeysInfo keys_info);
void CallSessionExpirationUpdateCB(const std::string& session_id,
base::Time new_expiry_time);
protected:
~MockCdm() override;
private:
// Callbacks.
SessionMessageCB session_message_cb_;
SessionClosedCB session_closed_cb_;
SessionKeysChangeCB session_keys_change_cb_;
SessionExpirationUpdateCB session_expiration_update_cb_;
DISALLOW_COPY_AND_ASSIGN(MockCdm);
};
class MockCdmFactory : public CdmFactory {
public:
MockCdmFactory();
~MockCdmFactory() override;
// CdmFactory implementation.
// This creates a StrictMock<MockCdm> when called. Although ownership of the
// created CDM is passed to |cdm_created_cb|, a copy is kept (and available
// using Cdm()). If |key_system| is empty, no CDM will be created.
void Create(const std::string& key_system,
const GURL& security_origin,
const CdmConfig& cdm_config,
const SessionMessageCB& session_message_cb,
const SessionClosedCB& session_closed_cb,
const SessionKeysChangeCB& session_keys_change_cb,
const SessionExpirationUpdateCB& session_expiration_update_cb,
const CdmCreatedCB& cdm_created_cb) override;
// Return a pointer to the created CDM.
MockCdm* GetCreatedCdm();
// Provide a callback to be called before the CDM is created and returned.
void SetBeforeCreationCB(const base::Closure& before_creation_cb);
private:
// Reference to the created CDM.
scoped_refptr<MockCdm> created_cdm_;
// Callback to be used before Create() successfully calls |cdm_created_cb|.
base::Closure before_creation_cb_;
DISALLOW_COPY_AND_ASSIGN(MockCdmFactory);
};
class MockStreamParser : public StreamParser {
public:
MockStreamParser();
......
......@@ -25,13 +25,6 @@
namespace media {
template <typename PromiseType>
static void RejectPromise(std::unique_ptr<PromiseType> promise,
mojom::CdmPromiseResultPtr result) {
promise->reject(result->exception, result->system_code,
result->error_message);
}
// static
void MojoCdm::Create(
const std::string& key_system,
......@@ -140,6 +133,9 @@ void MojoCdm::OnConnectionError(uint32_t custom_reason,
return;
}
// As communication with the remote CDM is broken, reject any outstanding
// promises and close all the existing sessions.
cdm_promise_adapter_.Clear();
cdm_session_tracker_.CloseRemainingSessions(session_closed_cb_);
}
......@@ -154,9 +150,10 @@ void MojoCdm::SetServerCertificate(const std::vector<uint8_t>& certificate,
return;
}
uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise));
remote_cdm_->SetServerCertificate(
certificate, base::Bind(&MojoCdm::OnSimpleCdmPromiseResult,
base::Unretained(this), base::Passed(&promise)));
base::Unretained(this), promise_id));
}
void MojoCdm::CreateSessionAndGenerateRequest(
......@@ -173,10 +170,11 @@ void MojoCdm::CreateSessionAndGenerateRequest(
return;
}
uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise));
remote_cdm_->CreateSessionAndGenerateRequest(
session_type, init_data_type, init_data,
base::Bind(&MojoCdm::OnNewSessionCdmPromiseResult, base::Unretained(this),
base::Passed(&promise)));
promise_id));
}
void MojoCdm::LoadSession(CdmSessionType session_type,
......@@ -191,10 +189,10 @@ void MojoCdm::LoadSession(CdmSessionType session_type,
return;
}
remote_cdm_->LoadSession(
session_type, session_id,
base::Bind(&MojoCdm::OnNewSessionCdmPromiseResult, base::Unretained(this),
base::Passed(&promise)));
uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise));
remote_cdm_->LoadSession(session_type, session_id,
base::Bind(&MojoCdm::OnNewSessionCdmPromiseResult,
base::Unretained(this), promise_id));
}
void MojoCdm::UpdateSession(const std::string& session_id,
......@@ -209,10 +207,10 @@ void MojoCdm::UpdateSession(const std::string& session_id,
return;
}
remote_cdm_->UpdateSession(
session_id, response,
base::Bind(&MojoCdm::OnSimpleCdmPromiseResult, base::Unretained(this),
base::Passed(&promise)));
uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise));
remote_cdm_->UpdateSession(session_id, response,
base::Bind(&MojoCdm::OnSimpleCdmPromiseResult,
base::Unretained(this), promise_id));
}
void MojoCdm::CloseSession(const std::string& session_id,
......@@ -226,9 +224,10 @@ void MojoCdm::CloseSession(const std::string& session_id,
return;
}
remote_cdm_->CloseSession(
session_id, base::Bind(&MojoCdm::OnSimpleCdmPromiseResult,
base::Unretained(this), base::Passed(&promise)));
uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise));
remote_cdm_->CloseSession(session_id,
base::Bind(&MojoCdm::OnSimpleCdmPromiseResult,
base::Unretained(this), promise_id));
}
void MojoCdm::RemoveSession(const std::string& session_id,
......@@ -242,9 +241,10 @@ void MojoCdm::RemoveSession(const std::string& session_id,
return;
}
remote_cdm_->RemoveSession(
session_id, base::Bind(&MojoCdm::OnSimpleCdmPromiseResult,
base::Unretained(this), base::Passed(&promise)));
uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise));
remote_cdm_->RemoveSession(session_id,
base::Bind(&MojoCdm::OnSimpleCdmPromiseResult,
base::Unretained(this), promise_id));
}
CdmContext* MojoCdm::GetCdmContext() {
......@@ -341,7 +341,9 @@ void MojoCdm::OnCdmInitialized(mojom::CdmPromiseResultPtr result,
DCHECK(pending_init_promise_);
if (!result->success) {
RejectPromise(std::move(pending_init_promise_), std::move(result));
pending_init_promise_->reject(result->exception, result->system_code,
result->error_message);
pending_init_promise_.reset();
return;
}
......@@ -366,24 +368,28 @@ void MojoCdm::OnKeyAdded() {
decryptor_->OnKeyAdded();
}
void MojoCdm::OnSimpleCdmPromiseResult(
std::unique_ptr<SimpleCdmPromise> promise,
void MojoCdm::OnSimpleCdmPromiseResult(uint32_t promise_id,
mojom::CdmPromiseResultPtr result) {
if (result->success)
promise->resolve();
else
RejectPromise(std::move(promise), std::move(result));
cdm_promise_adapter_.ResolvePromise(promise_id);
else {
cdm_promise_adapter_.RejectPromise(promise_id, result->exception,
result->system_code,
result->error_message);
}
}
void MojoCdm::OnNewSessionCdmPromiseResult(
std::unique_ptr<NewSessionCdmPromise> promise,
void MojoCdm::OnNewSessionCdmPromiseResult(uint32_t promise_id,
mojom::CdmPromiseResultPtr result,
const std::string& session_id) {
if (result->success) {
cdm_session_tracker_.AddSession(session_id);
promise->resolve(session_id);
} else
RejectPromise(std::move(promise), std::move(result));
cdm_promise_adapter_.ResolvePromise(promise_id, session_id);
} else {
cdm_promise_adapter_.RejectPromise(promise_id, result->exception,
result->system_code,
result->error_message);
}
}
} // namespace media
......@@ -17,6 +17,7 @@
#include "base/threading/thread_checker.h"
#include "media/base/cdm_context.h"
#include "media/base/cdm_initialized_promise.h"
#include "media/base/cdm_promise_adapter.h"
#include "media/base/cdm_session_tracker.h"
#include "media/base/content_decryption_module.h"
#include "media/mojo/interfaces/content_decryption_module.mojom.h"
......@@ -113,10 +114,9 @@ class MojoCdm : public ContentDecryptionModule,
void OnKeyAdded();
// Callbacks to handle CDM promises.
void OnSimpleCdmPromiseResult(std::unique_ptr<SimpleCdmPromise> promise,
void OnSimpleCdmPromiseResult(uint32_t promise_id,
mojom::CdmPromiseResultPtr result);
void OnNewSessionCdmPromiseResult(
std::unique_ptr<NewSessionCdmPromise> promise,
void OnNewSessionCdmPromiseResult(uint32_t promise_id,
mojom::CdmPromiseResultPtr result,
const std::string& session_id);
......@@ -157,6 +157,9 @@ class MojoCdm : public ContentDecryptionModule,
// Keep track of current sessions.
CdmSessionTracker cdm_session_tracker_;
// Keep track of outstanding promises.
CdmPromiseAdapter cdm_promise_adapter_;
// This must be the last member.
base::WeakPtrFactory<MojoCdm> weak_factory_;
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment