Merge "New usage entries are moved lower after creation." into sc-dev
This commit is contained in:
@@ -154,6 +154,46 @@ class UsageTableHeader {
|
||||
bool DetermineTableCapacity(CryptoSession* crypto_session);
|
||||
|
||||
// == Table operation methods ==
|
||||
// NOTE: The following "Table operation methods" require
|
||||
// |usage_table_header_lock_| to be taken before calling.
|
||||
|
||||
// Creates a new entry for the provided crypto session. If the
|
||||
// entry is created successfully in OEMCrypto, then a new entry
|
||||
// info is added to the table's vector of entry info.
|
||||
CdmResponseType CreateEntry(CryptoSession* const crypto_session,
|
||||
uint32_t* usage_entry_number);
|
||||
|
||||
// Attempts to relocate a newly created usage entry associated with
|
||||
// the provided |crypto_session| to the lowest unoccupied position in
|
||||
// the table.
|
||||
// |usage_entry_number| is treated as both an input and output.
|
||||
// Returns NO_ERROR so long as no internal operation fails,
|
||||
// regardless of whether the entry was moved or not.
|
||||
CdmResponseType RelocateNewEntry(CryptoSession* const crypto_session,
|
||||
uint32_t* usage_entry_number);
|
||||
|
||||
// Checks if the specified |usage_entry_number| is known to be
|
||||
// unoccupied (released).
|
||||
bool IsEntryUnoccupied(const uint32_t usage_entry_number) const;
|
||||
|
||||
// SetOfflineEntryInfo() and SetUsageInfoEntryInfo() populate the
|
||||
// entry meta-data with the required information based on the type
|
||||
// of entry.
|
||||
void SetOfflineEntryInfo(const uint32_t usage_entry_number,
|
||||
const std::string& key_set_id,
|
||||
const CdmKeyResponse& license_message);
|
||||
void SetUsageInfoEntryInfo(const uint32_t usage_entry_number,
|
||||
const std::string& key_set_id,
|
||||
const std::string& usage_info_file_name);
|
||||
|
||||
// Shrinks the table, removing all trailing unoccupied entries.
|
||||
// |usage_entry_info_| will be resized appropriately.
|
||||
// Caller must store the table after a successful call.
|
||||
CdmResponseType RefitTable(CryptoSession* const crypto_session);
|
||||
|
||||
virtual CdmResponseType InvalidateEntryInternal(
|
||||
uint32_t usage_entry_number, bool defrag_table, DeviceFiles* device_files,
|
||||
metrics::CryptoMetrics* metrics);
|
||||
|
||||
CdmResponseType MoveEntry(uint32_t from /* usage entry number */,
|
||||
const CdmUsageEntry& from_usage_entry,
|
||||
@@ -279,6 +319,7 @@ class UsageTableHeader {
|
||||
#if defined(UNIT_TEST)
|
||||
// Test related declarations
|
||||
friend class UsageTableHeaderTest;
|
||||
|
||||
FRIEND_TEST(UsageTableHeaderTest, Shrink_NoneOfTable);
|
||||
FRIEND_TEST(UsageTableHeaderTest, Shrink_PartOfTable);
|
||||
FRIEND_TEST(UsageTableHeaderTest, Shrink_AllOfTable);
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
namespace wvcdm {
|
||||
namespace {
|
||||
using TableLock = std::unique_lock<std::mutex>;
|
||||
|
||||
const std::string kEmptyString;
|
||||
const wvcdm::CdmKeySetId kDummyKeySetId = "DummyKsid";
|
||||
|
||||
@@ -252,75 +254,39 @@ CdmResponseType UsageTableHeader::AddEntry(
|
||||
CryptoSession* crypto_session, bool persistent_license,
|
||||
const CdmKeySetId& key_set_id, const std::string& usage_info_file_name,
|
||||
const CdmKeyResponse& license_message, uint32_t* usage_entry_number) {
|
||||
LOGD("oec_session_id = %u, type = %s, current_size = %zu",
|
||||
crypto_session->oec_session_id(),
|
||||
LOGD("key_set_id = %s, type = %s, current_size = %zu", IdToString(key_set_id),
|
||||
persistent_license ? "OfflineLicense" : "Streaming",
|
||||
usage_entry_info_.size());
|
||||
|
||||
metrics::CryptoMetrics* metrics = crypto_session->GetCryptoMetrics();
|
||||
if (metrics == nullptr) metrics = &alternate_crypto_metrics_;
|
||||
TableLock auto_lock(usage_table_header_lock_);
|
||||
|
||||
CdmResponseType status = crypto_session->CreateUsageEntry(usage_entry_number);
|
||||
|
||||
CdmResponseType status = CreateEntry(crypto_session, usage_entry_number);
|
||||
if (status == INSUFFICIENT_CRYPTO_RESOURCES) {
|
||||
LOGW("Usage table may be full, releasing oldest entry: size = %zu",
|
||||
usage_entry_info_.size());
|
||||
status = ReleaseOldestEntry(metrics);
|
||||
if (status == NO_ERROR) {
|
||||
status = crypto_session->CreateUsageEntry(usage_entry_number);
|
||||
status = CreateEntry(crypto_session, usage_entry_number);
|
||||
}
|
||||
}
|
||||
|
||||
if (status != NO_ERROR) return status;
|
||||
|
||||
LOGV("Locking to add entry");
|
||||
std::unique_lock<std::mutex> auto_lock(usage_table_header_lock_);
|
||||
if (*usage_entry_number < usage_entry_info_.size()) {
|
||||
LOGE(
|
||||
"New entry number is smaller than table size: "
|
||||
"entry_info_number = %u, table_size = %zu",
|
||||
*usage_entry_number, usage_entry_info_.size());
|
||||
return USAGE_INVALID_NEW_ENTRY;
|
||||
}
|
||||
status = RelocateNewEntry(crypto_session, usage_entry_number);
|
||||
if (status != NO_ERROR) return status;
|
||||
|
||||
if (*usage_entry_number > usage_entry_info_.size()) {
|
||||
LOGW(
|
||||
"New entry number is larger than table size, resizing: "
|
||||
"entry_info_number = %u, table_size = %zu",
|
||||
*usage_entry_number, usage_entry_info_.size());
|
||||
const size_t number_of_entries = usage_entry_info_.size();
|
||||
usage_entry_info_.resize(*usage_entry_number + 1);
|
||||
for (size_t i = number_of_entries; i < usage_entry_info_.size() - 1; ++i) {
|
||||
usage_entry_info_[i].Clear();
|
||||
}
|
||||
} else /* *usage_entry_number == usage_entry_info_.size() */ {
|
||||
usage_entry_info_.resize(*usage_entry_number + 1);
|
||||
}
|
||||
|
||||
usage_entry_info_[*usage_entry_number].storage_type =
|
||||
persistent_license ? kStorageLicense : kStorageUsageInfo;
|
||||
usage_entry_info_[*usage_entry_number].key_set_id = key_set_id;
|
||||
usage_entry_info_[*usage_entry_number].last_use_time = GetCurrentTime();
|
||||
if (!persistent_license) {
|
||||
usage_entry_info_[*usage_entry_number].usage_info_file_name =
|
||||
usage_info_file_name;
|
||||
usage_entry_info_[*usage_entry_number].offline_license_expiry_time = 0;
|
||||
if (persistent_license) {
|
||||
SetOfflineEntryInfo(*usage_entry_number, key_set_id, license_message);
|
||||
} else {
|
||||
// Need to determine the expire time for offline licenses.
|
||||
video_widevine::License license;
|
||||
if (license_message.size() > 0 &&
|
||||
ParseLicenseFromLicenseMessage(license_message, &license)) {
|
||||
const video_widevine::License::Policy& policy = license.policy();
|
||||
usage_entry_info_[*usage_entry_number].offline_license_expiry_time =
|
||||
license.license_start_time() + policy.rental_duration_seconds() +
|
||||
policy.playback_duration_seconds();
|
||||
} else {
|
||||
// If the license duration cannot be determined for any reason, it
|
||||
// is assumed to last at most 33 days.
|
||||
usage_entry_info_[*usage_entry_number].offline_license_expiry_time =
|
||||
usage_entry_info_[*usage_entry_number].last_use_time +
|
||||
kDefaultExpireDuration;
|
||||
}
|
||||
SetUsageInfoEntryInfo(*usage_entry_number, key_set_id,
|
||||
usage_info_file_name);
|
||||
}
|
||||
|
||||
status = RefitTable(crypto_session);
|
||||
if (status != NO_ERROR) {
|
||||
usage_entry_info_[*usage_entry_number].Clear();
|
||||
return status;
|
||||
}
|
||||
|
||||
// Call to update the usage table header, but don't store the usage
|
||||
@@ -334,8 +300,6 @@ CdmResponseType UsageTableHeader::AddEntry(
|
||||
usage_entry_info_[*usage_entry_number].Clear();
|
||||
return status;
|
||||
}
|
||||
|
||||
LOGI("usage_entry_number = %u", *usage_entry_number);
|
||||
StoreTable(device_files_.get());
|
||||
return NO_ERROR;
|
||||
}
|
||||
@@ -393,7 +357,14 @@ CdmResponseType UsageTableHeader::InvalidateEntry(
|
||||
uint32_t usage_entry_number, bool defrag_table, DeviceFiles* device_files,
|
||||
metrics::CryptoMetrics* metrics) {
|
||||
LOGD("usage_entry_number = %u", usage_entry_number);
|
||||
std::unique_lock<std::mutex> auto_lock(usage_table_header_lock_);
|
||||
TableLock auto_lock(usage_table_header_lock_);
|
||||
return InvalidateEntryInternal(usage_entry_number, defrag_table, device_files,
|
||||
metrics);
|
||||
}
|
||||
|
||||
CdmResponseType UsageTableHeader::InvalidateEntryInternal(
|
||||
uint32_t usage_entry_number, bool defrag_table, DeviceFiles* device_files,
|
||||
metrics::CryptoMetrics* metrics) {
|
||||
// OEMCrypto does not have any concept of "deleting" an entry.
|
||||
// Instead, the CDM marks the entry's meta data as invalid (storage
|
||||
// type unknown) and then performs a "defrag" of the OEMCrypto table.
|
||||
@@ -436,14 +407,12 @@ CdmResponseType UsageTableHeader::InvalidateEntry(
|
||||
|
||||
size_t UsageTableHeader::UsageInfoCount() const {
|
||||
LOGV("Locking to count usage info (streaming license) entries");
|
||||
std::unique_lock<std::mutex> auto_lock(usage_table_header_lock_);
|
||||
return std::count_if(usage_entry_info_.cbegin(), usage_entry_info_.cend(),
|
||||
EntryIsUsageInfo);
|
||||
}
|
||||
|
||||
size_t UsageTableHeader::OfflineEntryCount() const {
|
||||
LOGV("Locking to count offline license entries");
|
||||
std::unique_lock<std::mutex> auto_lock(usage_table_header_lock_);
|
||||
return std::count_if(usage_entry_info_.cbegin(), usage_entry_info_.cend(),
|
||||
EntryIsOfflineLicense);
|
||||
}
|
||||
@@ -547,6 +516,151 @@ bool UsageTableHeader::DetermineTableCapacity(CryptoSession* crypto_session) {
|
||||
return true;
|
||||
}
|
||||
|
||||
CdmResponseType UsageTableHeader::CreateEntry(
|
||||
CryptoSession* const crypto_session, uint32_t* usage_entry_number) {
|
||||
const CdmResponseType status =
|
||||
crypto_session->CreateUsageEntry(usage_entry_number);
|
||||
if (status != NO_ERROR) return status;
|
||||
// If the new entry number is smaller than expected, then the usage
|
||||
// table may be out of sync or OEMCrypto has been rolled back.
|
||||
// Not safe to continue.
|
||||
if (*usage_entry_number < usage_entry_info_.size()) {
|
||||
LOGE(
|
||||
"New entry number is smaller than table size: "
|
||||
"entry_info_number = %u, table_size = %zu",
|
||||
*usage_entry_number, usage_entry_info_.size());
|
||||
return USAGE_INVALID_NEW_ENTRY;
|
||||
}
|
||||
LOGI("usage_entry_number = %u", *usage_entry_number);
|
||||
const size_t previous_size = usage_entry_info_.size();
|
||||
usage_entry_info_.resize(*usage_entry_number + 1);
|
||||
if (*usage_entry_number > previous_size) {
|
||||
LOGW(
|
||||
"New entry number is larger than table size, resizing: "
|
||||
"entry_info_number = %u, table_size = %zu",
|
||||
*usage_entry_number, previous_size);
|
||||
for (size_t i = previous_size; i < usage_entry_info_.size() - 1; ++i) {
|
||||
usage_entry_info_[i].Clear();
|
||||
}
|
||||
}
|
||||
usage_entry_info_[*usage_entry_number].Clear();
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
CdmResponseType UsageTableHeader::RelocateNewEntry(
|
||||
CryptoSession* const crypto_session, uint32_t* usage_entry_number) {
|
||||
static constexpr uint32_t kMinimumEntryNumber = 0;
|
||||
const uint32_t initial_entry_number = *usage_entry_number;
|
||||
if (initial_entry_number == kMinimumEntryNumber) {
|
||||
// First entry in the table.
|
||||
return NO_ERROR;
|
||||
}
|
||||
uint32_t unoccupied_entry_number = initial_entry_number;
|
||||
for (uint32_t i = kMinimumEntryNumber; i < initial_entry_number; i++) {
|
||||
if (IsEntryUnoccupied(i)) {
|
||||
unoccupied_entry_number = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (unoccupied_entry_number == initial_entry_number) {
|
||||
// No open position.
|
||||
return NO_ERROR;
|
||||
}
|
||||
const CdmResponseType status =
|
||||
crypto_session->MoveUsageEntry(unoccupied_entry_number);
|
||||
if (status == MOVE_USAGE_ENTRY_DESTINATION_IN_USE) {
|
||||
// Not unexpected, there is a window of time between releasing the
|
||||
// entry and closing the OEMCrypto session.
|
||||
LOGD("Released entry still in use: index = %u", unoccupied_entry_number);
|
||||
return NO_ERROR;
|
||||
}
|
||||
if (status != NO_ERROR) return status;
|
||||
LOGI("Entry moved: from_index = %u, to_index = %u", initial_entry_number,
|
||||
unoccupied_entry_number);
|
||||
*usage_entry_number = unoccupied_entry_number;
|
||||
usage_entry_info_[unoccupied_entry_number] =
|
||||
std::move(usage_entry_info_[initial_entry_number]);
|
||||
usage_entry_info_[initial_entry_number].Clear();
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
bool UsageTableHeader::IsEntryUnoccupied(
|
||||
const uint32_t usage_entry_number) const {
|
||||
if (usage_entry_info_[usage_entry_number].storage_type !=
|
||||
kStorageTypeUnknown) {
|
||||
return false;
|
||||
}
|
||||
// TODO(sigquit): Check that entry is not in use by another session.
|
||||
// NOTE: The |storage_type| check will protect the integrity of the
|
||||
// entry. Attempting to use an entry index that is used by another
|
||||
// session is recoverable and will not affect any opened sessions.
|
||||
return true;
|
||||
}
|
||||
|
||||
void UsageTableHeader::SetOfflineEntryInfo(
|
||||
const uint32_t usage_entry_number, const std::string& key_set_id,
|
||||
const CdmKeyResponse& license_message) {
|
||||
CdmUsageEntryInfo& entry_info = usage_entry_info_[usage_entry_number];
|
||||
entry_info.Clear();
|
||||
entry_info.storage_type = kStorageLicense;
|
||||
entry_info.key_set_id = key_set_id;
|
||||
entry_info.last_use_time = GetCurrentTime();
|
||||
// Need to determine the expire time for offline licenses.
|
||||
video_widevine::License license;
|
||||
if (!license_message.empty() &&
|
||||
ParseLicenseFromLicenseMessage(license_message, &license)) {
|
||||
const video_widevine::License::Policy& policy = license.policy();
|
||||
entry_info.offline_license_expiry_time = license.license_start_time() +
|
||||
policy.rental_duration_seconds() +
|
||||
policy.playback_duration_seconds();
|
||||
} else {
|
||||
// If the license duration cannot be determined for any reason, it
|
||||
// is assumed to last at most 33 days.
|
||||
entry_info.offline_license_expiry_time =
|
||||
entry_info.last_use_time + kDefaultExpireDuration;
|
||||
}
|
||||
}
|
||||
|
||||
void UsageTableHeader::SetUsageInfoEntryInfo(
|
||||
const uint32_t usage_entry_number, const std::string& key_set_id,
|
||||
const std::string& usage_info_file_name) {
|
||||
CdmUsageEntryInfo& entry_info = usage_entry_info_[usage_entry_number];
|
||||
entry_info.Clear();
|
||||
entry_info.storage_type = kStorageUsageInfo;
|
||||
entry_info.key_set_id = key_set_id;
|
||||
entry_info.last_use_time = GetCurrentTime();
|
||||
entry_info.usage_info_file_name = usage_info_file_name;
|
||||
}
|
||||
|
||||
CdmResponseType UsageTableHeader::RefitTable(
|
||||
CryptoSession* const crypto_session) {
|
||||
// Remove all unoccupied entries at end of the table.
|
||||
uint32_t entries_to_remove = 0;
|
||||
for (uint32_t i = 0; i < usage_entry_info_.size(); i++) {
|
||||
const uint32_t usage_entry_number = usage_entry_info_.size() - i - 1;
|
||||
if (!IsEntryUnoccupied(usage_entry_number)) break;
|
||||
++entries_to_remove;
|
||||
}
|
||||
if (entries_to_remove == 0) return NO_ERROR;
|
||||
const uint32_t new_size = usage_entry_info_.size() - entries_to_remove;
|
||||
const CdmResponseType status = crypto_session->ShrinkUsageTableHeader(
|
||||
requested_security_level_, new_size, &usage_table_header_);
|
||||
if (status == SHRINK_USAGE_TABLE_HEADER_ENTRY_IN_USE) {
|
||||
// This error likely indicates that another session has released
|
||||
// its entry via a call to InvalidateEntry(), but has yet to close
|
||||
// its OEMCrypto session.
|
||||
// Safe to assume table state is not invalidated.
|
||||
LOGW("Unexpected entry in use: range = [%u, %zu]", new_size,
|
||||
usage_entry_info_.size() - 1);
|
||||
return NO_ERROR;
|
||||
}
|
||||
if (status != NO_ERROR) return status;
|
||||
LOGD("Table shrunk: old_size = %zu, new_size = %u", usage_entry_info_.size(),
|
||||
new_size);
|
||||
usage_entry_info_.resize(new_size);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
CdmResponseType UsageTableHeader::MoveEntry(
|
||||
uint32_t from_usage_entry_number, const CdmUsageEntry& from_usage_entry,
|
||||
uint32_t to_usage_entry_number, DeviceFiles* device_files,
|
||||
@@ -1035,8 +1149,8 @@ CdmResponseType UsageTableHeader::ReleaseOldestEntry(
|
||||
const CdmUsageEntryStorageType storage_type = usage_entry_info.storage_type;
|
||||
|
||||
const CdmResponseType status =
|
||||
InvalidateEntry(entry_number_to_delete, /* defrag_table = */ true,
|
||||
device_files_.get(), metrics);
|
||||
InvalidateEntryInternal(entry_number_to_delete, /* defrag_table = */ true,
|
||||
device_files_.get(), metrics);
|
||||
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("Failed to invalidate oldest entry: status = %d",
|
||||
@@ -1051,7 +1165,7 @@ CdmResponseType UsageTableHeader::ReleaseOldestEntry(
|
||||
|
||||
// Test only method.
|
||||
void UsageTableHeader::InvalidateEntryForTest(uint32_t usage_entry_number) {
|
||||
LOGV("usage_entry_number = %u", usage_entry_number);
|
||||
LOGD("usage_entry_number = %u", usage_entry_number);
|
||||
if (usage_entry_number >= usage_entry_info_.size()) {
|
||||
LOGE(
|
||||
"Requested usage entry number is larger than table size: "
|
||||
@@ -1188,8 +1302,6 @@ bool UsageTableHeader::LruUpgradeAllUsageEntries() {
|
||||
}
|
||||
|
||||
bool UsageTableHeader::GetRemovalCandidate(uint32_t* entry_to_remove) {
|
||||
LOGV("Locking to determine removal candidates");
|
||||
std::unique_lock<std::mutex> auto_lock(usage_table_header_lock_);
|
||||
const size_t lru_unexpired_threshold =
|
||||
HasUnlimitedTableCapacity()
|
||||
? kLruUnexpiredThresholdFraction * size()
|
||||
|
||||
@@ -202,8 +202,16 @@ const DeviceFiles::CdmUsageData kCdmUsageData3 = {
|
||||
const std::vector<DeviceFiles::CdmUsageData> kEmptyUsageInfoUsageDataList;
|
||||
|
||||
const std::vector<CdmUsageEntryInfo> kEmptyUsageEntryInfoVector;
|
||||
std::vector<CdmUsageEntryInfo> kUsageEntryInfoVector;
|
||||
std::vector<CdmUsageEntryInfo> k10UsageEntryInfoVector;
|
||||
const std::vector<CdmUsageEntryInfo> kUsageEntryInfoVector = {
|
||||
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoSecureStop1,
|
||||
kUsageEntryInfoStorageTypeUnknown};
|
||||
const std::vector<CdmUsageEntryInfo> k10UsageEntryInfoVector = {
|
||||
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoSecureStop1,
|
||||
kUsageEntryInfoOfflineLicense2, kUsageEntryInfoSecureStop2,
|
||||
kUsageEntryInfoOfflineLicense3, kUsageEntryInfoSecureStop3,
|
||||
kUsageEntryInfoOfflineLicense4, kUsageEntryInfoSecureStop4,
|
||||
kUsageEntryInfoOfflineLicense5, kUsageEntryInfoSecureStop5,
|
||||
};
|
||||
std::vector<CdmUsageEntryInfo> kOverFullUsageEntryInfoVector;
|
||||
|
||||
const CdmOfflineLicenseState kActiveLicenseState = kLicenseStateActive;
|
||||
@@ -289,23 +297,6 @@ std::vector<CdmUsageEntryInfo> kUpgradedUsageEntryInfoList;
|
||||
namespace {
|
||||
|
||||
void InitVectorConstants() {
|
||||
kUsageEntryInfoVector.clear();
|
||||
kUsageEntryInfoVector.push_back(kUsageEntryInfoOfflineLicense1);
|
||||
kUsageEntryInfoVector.push_back(kUsageEntryInfoSecureStop1);
|
||||
kUsageEntryInfoVector.push_back(kUsageEntryInfoStorageTypeUnknown);
|
||||
|
||||
k10UsageEntryInfoVector.clear();
|
||||
k10UsageEntryInfoVector.push_back(kUsageEntryInfoOfflineLicense1);
|
||||
k10UsageEntryInfoVector.push_back(kUsageEntryInfoSecureStop1);
|
||||
k10UsageEntryInfoVector.push_back(kUsageEntryInfoOfflineLicense2);
|
||||
k10UsageEntryInfoVector.push_back(kUsageEntryInfoSecureStop2);
|
||||
k10UsageEntryInfoVector.push_back(kUsageEntryInfoOfflineLicense3);
|
||||
k10UsageEntryInfoVector.push_back(kUsageEntryInfoSecureStop3);
|
||||
k10UsageEntryInfoVector.push_back(kUsageEntryInfoOfflineLicense4);
|
||||
k10UsageEntryInfoVector.push_back(kUsageEntryInfoSecureStop4);
|
||||
k10UsageEntryInfoVector.push_back(kUsageEntryInfoOfflineLicense5);
|
||||
k10UsageEntryInfoVector.push_back(kUsageEntryInfoSecureStop5);
|
||||
|
||||
kOverFullUsageEntryInfoVector.clear();
|
||||
for (size_t i = 0; i < (kDefaultTableCapacity + 1); ++i) {
|
||||
switch (i % 4) {
|
||||
@@ -479,8 +470,9 @@ class MockCryptoSession : public TestCryptoSession {
|
||||
class MockUsageTableHeader : public UsageTableHeader {
|
||||
public:
|
||||
MockUsageTableHeader() : UsageTableHeader() {}
|
||||
MOCK_METHOD4(InvalidateEntry, CdmResponseType(uint32_t, bool, DeviceFiles*,
|
||||
metrics::CryptoMetrics*));
|
||||
MOCK_METHOD4(InvalidateEntryInternal,
|
||||
CdmResponseType(uint32_t, bool, DeviceFiles*,
|
||||
metrics::CryptoMetrics*));
|
||||
MOCK_METHOD6(AddEntry, CdmResponseType(CryptoSession*, bool,
|
||||
const CdmKeySetId&, const std::string&,
|
||||
const CdmKeyResponse&, uint32_t*));
|
||||
@@ -1041,25 +1033,53 @@ TEST_F(UsageTableHeaderTest, AddEntry_UsageEntryTooSmall) {
|
||||
kEmptyString /* license */, &usage_entry_number));
|
||||
}
|
||||
|
||||
// Initial Test state:
|
||||
// 1. Table has a few entries, one of which is unoccupied.
|
||||
// 2. An entry-less session requires a new entry.
|
||||
//
|
||||
// Attempting to add an entry will result in:
|
||||
// a. A successful call to OEMCrypto to create an entry
|
||||
// at the end of the current table
|
||||
// b. Moving the new entry to the unoccupied entry index
|
||||
// c. Shrink table to remove the now empty entry slot created in (a)
|
||||
// d. Storing the new updated usage table
|
||||
//
|
||||
// Storage type Usage entries
|
||||
// at start at end
|
||||
// ============= ======== ======
|
||||
// Offline License 1 0 0
|
||||
// Secure Stop 1 1 1
|
||||
// Storage Type Unknown 2 Replaced
|
||||
// Offline License 2 DNE 2
|
||||
//
|
||||
// DNE = Does Not Exist
|
||||
//
|
||||
// # of usage entries 3 3
|
||||
TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveOfflineUsageEntry) {
|
||||
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
||||
const uint32_t expect_usage_entry_number = kUsageEntryInfoVector.size();
|
||||
const uint32_t initial_usage_entry_number = kUsageEntryInfoVector.size();
|
||||
const uint32_t final_usage_entry_number = kUsageEntryInfoVector.size() - 1;
|
||||
std::vector<CdmUsageEntryInfo> expect_usage_entry_info_vector =
|
||||
kUsageEntryInfoVector;
|
||||
expect_usage_entry_info_vector.resize(expect_usage_entry_number + 1);
|
||||
expect_usage_entry_info_vector[expect_usage_entry_number] =
|
||||
expect_usage_entry_info_vector[final_usage_entry_number] =
|
||||
kUsageEntryInfoOfflineLicense2;
|
||||
|
||||
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(initial_usage_entry_number),
|
||||
Return(NO_ERROR)));
|
||||
EXPECT_CALL(*crypto_session_, MoveUsageEntry(final_usage_entry_number))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
EXPECT_CALL(
|
||||
*crypto_session_,
|
||||
ShrinkUsageTableHeader(kLevelDefault,
|
||||
expect_usage_entry_info_vector.size(), NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<0>(expect_usage_entry_number), Return(NO_ERROR)));
|
||||
DoAll(SetArgPointee<2>(kAnotherUsageTableHeader), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kYetAnotherUsageTableHeader),
|
||||
Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_,
|
||||
StoreUsageTableInfo(
|
||||
kAnotherUsageTableHeader,
|
||||
UnorderedElementsAreArray(expect_usage_entry_info_vector)))
|
||||
StoreUsageTableInfo(kYetAnotherUsageTableHeader,
|
||||
expect_usage_entry_info_vector))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
uint32_t usage_entry_number = 0;
|
||||
@@ -1070,29 +1090,182 @@ TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveOfflineUsageEntry) {
|
||||
kUsageEntryInfoOfflineLicense2.key_set_id,
|
||||
kUsageEntryInfoOfflineLicense2.usage_info_file_name,
|
||||
kEmptyString /* license */, &usage_entry_number));
|
||||
EXPECT_EQ(expect_usage_entry_number, usage_entry_number);
|
||||
EXPECT_EQ(final_usage_entry_number, usage_entry_number);
|
||||
}
|
||||
|
||||
// Initial Test state:
|
||||
// 1. Table has a few entries, one of which is unoccupied.
|
||||
// 2. An entry-less session requires a new entry.
|
||||
//
|
||||
// Attempting to add an entry will result in:
|
||||
// a. A successful call to OEMCrypto to create an entry
|
||||
// at the end of the current table
|
||||
// b. Moving the new entry to the unoccupied entry index
|
||||
// c. Shrink table to remove the now empty entry slot created in (a)
|
||||
// d. Storing the new updated usage table
|
||||
//
|
||||
// Storage type Usage entries
|
||||
// at start at end
|
||||
// ============= ======== ======
|
||||
// Offline License 1 0 0
|
||||
// Secure Stop 1 1 1
|
||||
// Storage Type Unknown 2 Replaced
|
||||
// Secure Stop 2 DNE 2
|
||||
//
|
||||
// DNE = Does Not Exist
|
||||
//
|
||||
// # of usage entries 3 3
|
||||
TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveSecureStopUsageEntry) {
|
||||
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
||||
const uint32_t expect_usage_entry_number = kUsageEntryInfoVector.size();
|
||||
const uint32_t initial_usage_entry_number = kUsageEntryInfoVector.size();
|
||||
const uint32_t final_usage_entry_number = kUsageEntryInfoVector.size() - 1;
|
||||
std::vector<CdmUsageEntryInfo> expect_usage_entry_info_vector =
|
||||
kUsageEntryInfoVector;
|
||||
|
||||
expect_usage_entry_info_vector.resize(expect_usage_entry_number + 1);
|
||||
expect_usage_entry_info_vector[expect_usage_entry_number] =
|
||||
expect_usage_entry_info_vector[final_usage_entry_number] =
|
||||
kUsageEntryInfoSecureStop2;
|
||||
|
||||
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(initial_usage_entry_number),
|
||||
Return(NO_ERROR)));
|
||||
EXPECT_CALL(*crypto_session_, MoveUsageEntry(final_usage_entry_number))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
EXPECT_CALL(
|
||||
*crypto_session_,
|
||||
ShrinkUsageTableHeader(kLevelDefault,
|
||||
expect_usage_entry_info_vector.size(), NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<0>(expect_usage_entry_number), Return(NO_ERROR)));
|
||||
DoAll(SetArgPointee<2>(kAnotherUsageTableHeader), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kYetAnotherUsageTableHeader),
|
||||
Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_,
|
||||
StoreUsageTableInfo(kYetAnotherUsageTableHeader,
|
||||
expect_usage_entry_info_vector))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
uint32_t usage_entry_number = 0;
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
usage_table_header_->AddEntry(
|
||||
crypto_session_,
|
||||
kUsageEntryInfoSecureStop2.storage_type == kStorageLicense,
|
||||
kUsageEntryInfoSecureStop2.key_set_id,
|
||||
kUsageEntryInfoSecureStop2.usage_info_file_name,
|
||||
kEmptyString /* license */, &usage_entry_number));
|
||||
EXPECT_EQ(final_usage_entry_number, usage_entry_number);
|
||||
}
|
||||
|
||||
// Initial Test state:
|
||||
// 1. Table has a few entries, one of which is unoccupied.
|
||||
// 2. An entry-less session requires a new entry.
|
||||
//
|
||||
// Attempting to add an entry will result in:
|
||||
// a. An odd but successful call to OEMCrypto to create an entry
|
||||
// beyond the end of the current table
|
||||
// b. Empty entries will fill the gap between the original table
|
||||
// and the new entry
|
||||
// c. Move the new entry to the *lowest* unoccupied entry index
|
||||
// d. Shrink table to remove the now empty entry slot created in (a)
|
||||
// and the filler gap entries created in (b)
|
||||
// e. Storing the new updated usage table
|
||||
//
|
||||
// Storage type Usage entries
|
||||
// at start at end
|
||||
// ============= ======== ======
|
||||
// Offline License 1 0 0
|
||||
// Secure Stop 1 1 1
|
||||
// Storage Type Unknown 2 Replaced
|
||||
// Storage Type Unknown DNE Removed (never stored)
|
||||
// Storage Type Unknown DNE Removed (never stored)
|
||||
// Storage Type Unknown DNE Removed (never stored)
|
||||
// Secure Stop 2 DNE 2
|
||||
//
|
||||
// DNE = Does Not Exist
|
||||
//
|
||||
// # of usage entries 3 3
|
||||
TEST_F(UsageTableHeaderTest, AddEntry_SkipUsageEntries) {
|
||||
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
||||
const uint32_t next_usage_entry_number = kUsageEntryInfoVector.size();
|
||||
const size_t skip_usage_entries = 3;
|
||||
const uint32_t initial_usage_entry_number =
|
||||
next_usage_entry_number + skip_usage_entries;
|
||||
const uint32_t final_usage_entry_number = kUsageEntryInfoVector.size() - 1;
|
||||
std::vector<CdmUsageEntryInfo> expect_usage_entry_info_vector =
|
||||
kUsageEntryInfoVector;
|
||||
expect_usage_entry_info_vector[final_usage_entry_number] =
|
||||
kUsageEntryInfoSecureStop2;
|
||||
|
||||
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(initial_usage_entry_number),
|
||||
Return(NO_ERROR)));
|
||||
EXPECT_CALL(*crypto_session_, MoveUsageEntry(final_usage_entry_number))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
EXPECT_CALL(
|
||||
*crypto_session_,
|
||||
ShrinkUsageTableHeader(kLevelDefault,
|
||||
expect_usage_entry_info_vector.size(), NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<2>(kAnotherUsageTableHeader), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kYetAnotherUsageTableHeader),
|
||||
Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_,
|
||||
StoreUsageTableInfo(kYetAnotherUsageTableHeader,
|
||||
expect_usage_entry_info_vector))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
uint32_t usage_entry_number = 0;
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
usage_table_header_->AddEntry(
|
||||
crypto_session_,
|
||||
kUsageEntryInfoSecureStop2.storage_type == kStorageLicense,
|
||||
kUsageEntryInfoSecureStop2.key_set_id,
|
||||
kUsageEntryInfoSecureStop2.usage_info_file_name,
|
||||
kEmptyString /* license */, &usage_entry_number));
|
||||
EXPECT_EQ(final_usage_entry_number, usage_entry_number);
|
||||
}
|
||||
|
||||
// Initial Test state:
|
||||
// 1. Table has a few entries, one of which is unoccupied.
|
||||
// 2. An entry-less session requires a new entry.
|
||||
//
|
||||
// Attempting to add an entry will result in:
|
||||
// a. A successful call to OEMCrypto to create an entry
|
||||
// at the end of the current table
|
||||
// b. Cannot move the new entry to the unoccupied entry index
|
||||
// due to entry being in use (according to OEMCrypto)
|
||||
// c. Storing the new updated usage table
|
||||
//
|
||||
// Storage type Usage entries
|
||||
// at start at end
|
||||
// ============= ======== ======
|
||||
// Offline License 1 0 0
|
||||
// Secure Stop 1 1 1
|
||||
// Storage Type Unknown 2 2
|
||||
// Secure Stop 2 DNE 3
|
||||
//
|
||||
// DNE = Does Not Exist
|
||||
//
|
||||
// # of usage entries 3 4
|
||||
TEST_F(UsageTableHeaderTest, AddEntry_CannotMoveNewEntry) {
|
||||
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
||||
const uint32_t final_usage_entry_number = kUsageEntryInfoVector.size();
|
||||
const uint32_t attempted_usage_entry_number =
|
||||
kUsageEntryInfoVector.size() - 1;
|
||||
std::vector<CdmUsageEntryInfo> expect_usage_entry_info_vector =
|
||||
kUsageEntryInfoVector;
|
||||
expect_usage_entry_info_vector.push_back(kUsageEntryInfoSecureStop2);
|
||||
|
||||
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<0>(final_usage_entry_number), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*crypto_session_, MoveUsageEntry(attempted_usage_entry_number))
|
||||
.WillOnce(Return(MOVE_USAGE_ENTRY_DESTINATION_IN_USE));
|
||||
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_,
|
||||
StoreUsageTableInfo(
|
||||
kAnotherUsageTableHeader,
|
||||
UnorderedElementsAreArray(expect_usage_entry_info_vector)))
|
||||
StoreUsageTableInfo(kAnotherUsageTableHeader,
|
||||
expect_usage_entry_info_vector))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
uint32_t usage_entry_number = 0;
|
||||
@@ -1103,32 +1276,58 @@ TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveSecureStopUsageEntry) {
|
||||
kUsageEntryInfoSecureStop2.key_set_id,
|
||||
kUsageEntryInfoSecureStop2.usage_info_file_name,
|
||||
kEmptyString /* license */, &usage_entry_number));
|
||||
EXPECT_EQ(expect_usage_entry_number, usage_entry_number);
|
||||
EXPECT_EQ(final_usage_entry_number, usage_entry_number);
|
||||
}
|
||||
|
||||
TEST_F(UsageTableHeaderTest, AddEntry_SkipUsageEntries) {
|
||||
// Initial Test state:
|
||||
// 1. Table has a few entries, one of which is unoccupied.
|
||||
// 2. An entry-less session requires a new entry.
|
||||
//
|
||||
// Attempting to add an entry will result in:
|
||||
// a. A successful call to OEMCrypto to create an entry
|
||||
// at the end of the current table
|
||||
// b. Moving the new entry to the unoccupied entry index
|
||||
// c. Fail to shrink table due to occupied entry
|
||||
// d. Storing the new updated usage table
|
||||
//
|
||||
// Storage type Usage entries
|
||||
// at start at end
|
||||
// ============= ======== ======
|
||||
// Offline License 1 0 0
|
||||
// Secure Stop 1 1 1
|
||||
// Storage Type Unknown 2 Replaced
|
||||
// Secure Stop 2 DNE 2
|
||||
// Storage Type Unknown DNE 3 (created when new entry moved)
|
||||
//
|
||||
// DNE = Does Not Exist
|
||||
//
|
||||
// # of usage entries 3 4
|
||||
TEST_F(UsageTableHeaderTest, AddEntry_CannotShinkAfterMove) {
|
||||
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
||||
const uint32_t next_usage_entry_number = kUsageEntryInfoVector.size();
|
||||
size_t skip_usage_entries = 3;
|
||||
uint32_t expect_usage_entry_number =
|
||||
next_usage_entry_number + skip_usage_entries;
|
||||
const uint32_t initial_usage_entry_number = kUsageEntryInfoVector.size();
|
||||
const uint32_t final_usage_entry_number = kUsageEntryInfoVector.size() - 1;
|
||||
std::vector<CdmUsageEntryInfo> expect_usage_entry_info_vector =
|
||||
kUsageEntryInfoVector;
|
||||
expect_usage_entry_info_vector[final_usage_entry_number] =
|
||||
kUsageEntryInfoSecureStop2;
|
||||
expect_usage_entry_info_vector.push_back(kUsageEntryInfoStorageTypeUnknown);
|
||||
|
||||
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<0>(expect_usage_entry_number), Return(NO_ERROR)));
|
||||
.WillOnce(DoAll(SetArgPointee<0>(initial_usage_entry_number),
|
||||
Return(NO_ERROR)));
|
||||
EXPECT_CALL(*crypto_session_, MoveUsageEntry(final_usage_entry_number))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
EXPECT_CALL(
|
||||
*crypto_session_,
|
||||
ShrinkUsageTableHeader(
|
||||
kLevelDefault, expect_usage_entry_info_vector.size() - 1, NotNull()))
|
||||
.WillOnce(Return(SHRINK_USAGE_TABLE_HEADER_ENTRY_IN_USE));
|
||||
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
|
||||
EXPECT_CALL(
|
||||
*device_files_,
|
||||
StoreUsageTableInfo(
|
||||
kAnotherUsageTableHeader,
|
||||
UnorderedElementsAre(
|
||||
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoSecureStop1,
|
||||
kUsageEntryInfoStorageTypeUnknown,
|
||||
kUsageEntryInfoStorageTypeUnknown,
|
||||
kUsageEntryInfoStorageTypeUnknown,
|
||||
kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoSecureStop2)))
|
||||
EXPECT_CALL(*device_files_,
|
||||
StoreUsageTableInfo(kAnotherUsageTableHeader,
|
||||
expect_usage_entry_info_vector))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
uint32_t usage_entry_number = 0;
|
||||
@@ -1139,9 +1338,21 @@ TEST_F(UsageTableHeaderTest, AddEntry_SkipUsageEntries) {
|
||||
kUsageEntryInfoSecureStop2.key_set_id,
|
||||
kUsageEntryInfoSecureStop2.usage_info_file_name,
|
||||
kEmptyString /* license */, &usage_entry_number));
|
||||
EXPECT_EQ(expect_usage_entry_number, usage_entry_number);
|
||||
EXPECT_EQ(final_usage_entry_number, usage_entry_number);
|
||||
}
|
||||
|
||||
// Initial Test state:
|
||||
// 1. Table is full with entries
|
||||
// 2. An entry-less session requires a new entry.
|
||||
//
|
||||
// Attempting to add an entry will result in:
|
||||
// a. First call to OEMCrypto to create an entry fails due to
|
||||
// table being full
|
||||
// b. One of the existing entries will be removed, shrinking table
|
||||
// by one
|
||||
// c. Table will be stored
|
||||
// d. Second call to OEMCrypto to create an entry will succeed
|
||||
// e. Storing the new updated usage table
|
||||
TEST_F(UsageTableHeaderTest,
|
||||
AddEntry_CreateUsageEntryFailsOnce_SucceedsSecondTime) {
|
||||
// Initialize and setup
|
||||
@@ -1150,32 +1361,33 @@ TEST_F(UsageTableHeaderTest,
|
||||
std::vector<CdmUsageEntryInfo> usage_entry_info_vector_at_start =
|
||||
k10UsageEntryInfoVector;
|
||||
|
||||
uint32_t usage_entry_number_first_to_be_deleted; // randomly chosen
|
||||
std::vector<CdmUsageEntryInfo> final_usage_entries;
|
||||
uint32_t invalidated_entry = 0; // Randomly chosen by UsageTableHeader
|
||||
|
||||
const uint32_t expected_usage_entry_number =
|
||||
k10UsageEntryInfoVector.size() - 1;
|
||||
|
||||
// Setup expectations
|
||||
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
|
||||
// First call fails
|
||||
.WillOnce(Return(INSUFFICIENT_CRYPTO_RESOURCES))
|
||||
// Second call succeeds
|
||||
.WillOnce(DoAll(SetArgPointee<0>(expected_usage_entry_number),
|
||||
Return(NO_ERROR)));
|
||||
// Covers all other expectations.
|
||||
EXPECT_CALL(*mock_usage_table_header,
|
||||
InvalidateEntry(_, true, device_files_, NotNull()))
|
||||
.WillOnce(DoAll(SaveArg<0>(&usage_entry_number_first_to_be_deleted),
|
||||
InvalidateEntryInternal(_, true, device_files_, NotNull()))
|
||||
.WillOnce(DoAll(SaveArg<0>(&invalidated_entry),
|
||||
Invoke(this, &UsageTableHeaderTest::InvalidateEntry),
|
||||
Return(NO_ERROR)));
|
||||
|
||||
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
|
||||
.WillOnce(Return(INSUFFICIENT_CRYPTO_RESOURCES))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(expected_usage_entry_number),
|
||||
Return(NO_ERROR)));
|
||||
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
|
||||
|
||||
std::vector<CdmUsageEntryInfo> final_usage_entries;
|
||||
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kAnotherUsageTableHeader, _))
|
||||
.WillOnce(DoAll(SaveArg<1>(&final_usage_entries), Return(true)));
|
||||
|
||||
// Now invoke the method under test
|
||||
uint32_t usage_entry_number;
|
||||
uint32_t usage_entry_number = 0;
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
mock_usage_table_header->SuperAddEntry(
|
||||
crypto_session_,
|
||||
@@ -1187,17 +1399,15 @@ TEST_F(UsageTableHeaderTest,
|
||||
// Verify added/deleted usage entry number and entries
|
||||
EXPECT_EQ(expected_usage_entry_number, usage_entry_number);
|
||||
|
||||
EXPECT_LE(0u, usage_entry_number_first_to_be_deleted);
|
||||
EXPECT_LE(usage_entry_number_first_to_be_deleted,
|
||||
usage_entry_info_vector_at_start.size() - 1);
|
||||
EXPECT_LE(0u, invalidated_entry);
|
||||
EXPECT_LE(invalidated_entry, k10UsageEntryInfoVector.size() - 1);
|
||||
|
||||
std::vector<CdmUsageEntryInfo> expected_usage_entries =
|
||||
usage_entry_info_vector_at_start;
|
||||
expected_usage_entries[usage_entry_number_first_to_be_deleted] =
|
||||
expected_usage_entries[expected_usage_entries.size() - 1];
|
||||
expected_usage_entries.resize(expected_usage_entries.size() - 1);
|
||||
expected_usage_entries.push_back(kUsageEntryInfoOfflineLicense6);
|
||||
k10UsageEntryInfoVector;
|
||||
|
||||
expected_usage_entries[invalidated_entry] = expected_usage_entries.back();
|
||||
expected_usage_entries.pop_back();
|
||||
expected_usage_entries.push_back(kUsageEntryInfoOfflineLicense6);
|
||||
EXPECT_EQ(expected_usage_entries, final_usage_entries);
|
||||
}
|
||||
|
||||
@@ -1210,7 +1420,7 @@ TEST_F(UsageTableHeaderTest, AddEntry_CreateUsageEntryFailsEveryTime) {
|
||||
|
||||
// Setup expectations
|
||||
EXPECT_CALL(*mock_usage_table_header,
|
||||
InvalidateEntry(_, true, device_files_, NotNull()))
|
||||
InvalidateEntryInternal(_, true, device_files_, NotNull()))
|
||||
.WillOnce(DoAll(Invoke(this, &UsageTableHeaderTest::InvalidateEntry),
|
||||
Return(NO_ERROR)));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user