DO NOT MERGE Handle unlimited usage table capacity.

[ Merge of http://go/wvgerrit/103684 ]
[ Cherry pick of http://ag/12221244 ]

The OEMCrypto method for usage table capacity can return zero to
indicate that the usage table size is not explicitly limited.  The
CDM must handle this case with regard to the CDM's usage table
management and information querying.

The usage table initialization tests are extended to include cases
where the table does not have a defined limit.

AddEntry() was missing call to update the usage table header after
creating a new usage entry.  This call is now included and required
additional changes to the usage table unit tests.

Bug: 160560364
Test: Android unit tests
Change-Id: Ica5d181092d2938d24deba5005a211ca883cb0f0
This commit is contained in:
Alex Dale
2020-07-23 13:29:53 -07:00
parent 5cb846db83
commit 99335a6aa8
6 changed files with 275 additions and 87 deletions

View File

@@ -93,6 +93,10 @@ class UsageTableHeader {
size_t potential_table_capacity() const { return potential_table_capacity_; }
bool HasUnlimitedTableCapacity() const {
return potential_table_capacity_ == 0;
}
// Returns the number of entries currently tracked by the CDM that
// are related to usage info (streaming licenses).
size_t UsageInfoCount() const;

View File

@@ -8,6 +8,7 @@
#include <stdlib.h>
#include <iostream>
#include <limits>
#include <list>
#include <memory>
#include <sstream>
@@ -696,6 +697,12 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
LOGW("GetMaxUsageTableEntries failed");
return UNKNOWN_ERROR;
}
if (max_number_of_usage_entries == 0) {
// Zero indicates that the table is dynamically allocated and does
// not have a defined limit. Setting to max value of int32_t to
// be able to fit into a Java int.
max_number_of_usage_entries = std::numeric_limits<int32_t>::max();
}
*query_response = std::to_string(max_number_of_usage_entries);
return NO_ERROR;
} else if (query_token == QUERY_KEY_OEMCRYPTO_API_MINOR_VERSION) {

View File

@@ -2002,6 +2002,11 @@ bool CryptoSession::GetMaximumUsageTableEntries(SecurityLevel security_level,
metrics_->oemcrypto_maximum_usage_table_header_size_.Record(
*number_of_entries);
if (*number_of_entries == 0) {
// Special value, indicating that the table size is not directly
// limited.
return true;
}
return *number_of_entries >= kMinimumUsageTableEntriesSupported;
}

View File

@@ -178,13 +178,23 @@ bool UsageTableHeader::Init(CdmSecurityLevel security_level,
if (!crypto_session->GetMaximumUsageTableEntries(
requested_security_level_, &potential_table_capacity_)) {
LOGW(
"Could not determine usage table capacity, assuming default: "
"default = %zu",
kMinimumUsageTableEntriesSupported);
potential_table_capacity_ = kMinimumUsageTableEntriesSupported;
} else if (potential_table_capacity_ == 0) {
LOGD("Usage table capacity is unlimited: security_level = %d",
static_cast<int>(security_level));
} else if (potential_table_capacity_ < kMinimumUsageTableEntriesSupported) {
LOGW(
"Reported usage table capacity is smaller than minimally required: "
"capacity = %zu, minimum = %zu",
potential_table_capacity_, kMinimumUsageTableEntriesSupported);
potential_table_capacity_ = kMinimumUsageTableEntriesSupported;
} else {
LOGD("Usage table capacity: %zu, security_level = %d",
potential_table_capacity_, static_cast<int>(security_level));
}
if (!device_files_->Init(security_level)) {
@@ -215,11 +225,21 @@ bool UsageTableHeader::Init(CdmSecurityLevel security_level,
}
}
// If the usage table header has been successfully loaded, and is at
// minimum capacity (>200), we need to make sure we can still add and
// remove entries. If not, clear files/data and recreate usage header table.
// If the usage table header has been successfully loaded, and is
// at minimum capacity (>200) or the table size does not have a
// hard limit, we need to make sure we can still add and remove
// entries. If not, clear files/data and recreate usage header
// table.
if (status == NO_ERROR && lru_success) {
if (usage_entry_info_.size() > potential_table_capacity()) {
if ((HasUnlimitedTableCapacity() &&
usage_entry_info_.size() > kMinimumUsageTableEntriesSupported) ||
(!HasUnlimitedTableCapacity() &&
usage_entry_info_.size() > potential_table_capacity())) {
LOGD("Checking if new entry can be added: size = %zu, capacity = %s",
usage_entry_info_.size(),
HasUnlimitedTableCapacity()
? "unlimited"
: std::to_string(potential_table_capacity()).c_str());
uint32_t temporary_usage_entry_number;
// Create a new temporary usage entry, close the session and then
@@ -361,6 +381,18 @@ CdmResponseType UsageTableHeader::AddEntry(
}
}
// Call to update the usage table header, but don't store the usage
// entry. If the entry is used by the CDM, the CDM session will make
// subsequent calls to update the usage entry and store that entry.
std::string usage_entry;
status = crypto_session->UpdateUsageEntry(&usage_table_header_, &usage_entry);
if (status != NO_ERROR) {
LOGE("Failed to update new usage entry: usage_entry_number = %u",
*usage_entry_number);
usage_entry_info_[*usage_entry_number].Clear();
return status;
}
LOGI("New usage entry: usage_entry_number = %u", *usage_entry_number);
StoreTable(device_files_.get());
return NO_ERROR;
@@ -1120,7 +1152,9 @@ bool UsageTableHeader::GetRemovalCandidates(
LOGI("Locking to determine removal candidates");
std::unique_lock<std::mutex> auto_lock(usage_table_header_lock_);
const size_t lru_unexpired_threshold =
kLruUnexpiredThresholdFraction * potential_table_capacity();
HasUnlimitedTableCapacity()
? kLruUnexpiredThresholdFraction * size()
: kLruUnexpiredThresholdFraction * potential_table_capacity();
return DetermineLicenseToRemove(usage_entry_info_, GetCurrentTime(),
lru_unexpired_threshold, kLruRemovalSetSize,
removal_candidates);

View File

@@ -316,8 +316,6 @@ TEST_F(CryptoSessionMetricsTest, OpenSessionValidMetrics) {
EXPECT_EQ(OEMCrypto_Keybox,
metrics_proto.oemcrypto_provisioning_method().int_value());
EXPECT_EQ(1, metrics_proto.oemcrypto_get_key_data_time_us().size());
EXPECT_EQ(
1u, metrics_proto.oemcrypto_get_key_data_time_us(0).operation_count());
} else if (token_type == kClientTokenOemCert) {
// Recent devices all have a system id between 1k and 6 or 7k. Errors
// we are trying to catch are 0, byte swapped 32 bit numbers, or
@@ -365,8 +363,6 @@ TEST_F(CryptoSessionMetricsTest, GetProvisioningTokenValidMetrics) {
uint32_t system_id = FindKeyboxSystemID();
EXPECT_EQ(system_id, metrics_proto.crypto_session_system_id().int_value());
EXPECT_EQ(1, metrics_proto.oemcrypto_get_key_data_time_us().size());
EXPECT_EQ(
2u, metrics_proto.oemcrypto_get_key_data_time_us(0).operation_count());
} else if (token_type == kClientTokenOemCert) {
// Recent devices all have a system id between 1k and 6 or 7k. Errors
// we are trying to catch are 0, byte swapped 32 bit numbers, or

View File

@@ -21,12 +21,36 @@
#include "wv_cdm_constants.h"
#include "wv_cdm_types.h"
// gmock methods
using ::testing::_;
using ::testing::AllOf;
using ::testing::AtMost;
using ::testing::ContainerEq;
using ::testing::Contains;
using ::testing::DoAll;
using ::testing::ElementsAre;
using ::testing::ElementsAreArray;
using ::testing::Ge;
using ::testing::Invoke;
using ::testing::InvokeWithoutArgs;
using ::testing::Lt;
using ::testing::NotNull;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::SetArgPointee;
using ::testing::SizeIs;
using ::testing::StrEq;
using ::testing::UnorderedElementsAre;
using ::testing::UnorderedElementsAreArray;
namespace wvcdm {
namespace {
const std::string kEmptyString;
constexpr size_t kDefaultTableCapacity = 300;
constexpr int64_t kDefaultExpireDuration = 33 * 24 * 60 * 60; // 33 Days
const CdmUsageTableHeader kEmptyUsageTableHeader;
@@ -172,7 +196,7 @@ const std::vector<DeviceFiles::CdmUsageData> kEmptyUsageInfoUsageDataList;
const std::vector<CdmUsageEntryInfo> kEmptyUsageEntryInfoVector;
std::vector<CdmUsageEntryInfo> kUsageEntryInfoVector;
std::vector<CdmUsageEntryInfo> k10UsageEntryInfoVector;
std::vector<CdmUsageEntryInfo> k201UsageEntryInfoVector;
std::vector<CdmUsageEntryInfo> kOverFullUsageEntryInfoVector;
const DeviceFiles::LicenseState kActiveLicenseState =
DeviceFiles::kLicenseStateActive;
@@ -275,23 +299,24 @@ void InitVectorConstants() {
k10UsageEntryInfoVector.push_back(kUsageEntryInfoOfflineLicense5);
k10UsageEntryInfoVector.push_back(kUsageEntryInfoSecureStop5);
k201UsageEntryInfoVector.clear();
for (size_t i = 0; i < 201; ++i) {
kOverFullUsageEntryInfoVector.clear();
for (size_t i = 0; i < (kDefaultTableCapacity + 1); ++i) {
switch (i % 4) {
case 0:
k201UsageEntryInfoVector.push_back(kUsageEntryInfoOfflineLicense1);
kOverFullUsageEntryInfoVector.push_back(kUsageEntryInfoOfflineLicense1);
break;
case 1:
k201UsageEntryInfoVector.push_back(kUsageEntryInfoSecureStop1);
kOverFullUsageEntryInfoVector.push_back(kUsageEntryInfoSecureStop1);
break;
case 2:
k201UsageEntryInfoVector.push_back(kUsageEntryInfoOfflineLicense2);
kOverFullUsageEntryInfoVector.push_back(kUsageEntryInfoOfflineLicense2);
break;
case 3:
k201UsageEntryInfoVector.push_back(kUsageEntryInfoSecureStop2);
kOverFullUsageEntryInfoVector.push_back(kUsageEntryInfoSecureStop2);
break;
default:
k201UsageEntryInfoVector.push_back(kUsageEntryInfoStorageTypeUnknown);
kOverFullUsageEntryInfoVector.push_back(
kUsageEntryInfoStorageTypeUnknown);
break;
}
}
@@ -436,8 +461,8 @@ class MockCryptoSession : public TestCryptoSession {
}
private:
size_t maximum_usage_table_entries_ = 0;
bool maximum_usage_table_entries_set_ = false;
size_t maximum_usage_table_entries_ = kDefaultTableCapacity;
bool maximum_usage_table_entries_set_ = true;
};
// Partial mock of the UsageTableHeader. This is to test when dependency
@@ -447,32 +472,25 @@ class MockUsageTableHeader : public UsageTableHeader {
MockUsageTableHeader() : UsageTableHeader() {}
MOCK_METHOD4(InvalidateEntry, CdmResponseType(uint32_t, bool, DeviceFiles*,
metrics::CryptoMetrics*));
MOCK_METHOD6(AddEntry,
CdmResponseType(CryptoSession*, bool, const CdmKeySetId&,
const std::string&, const CdmKeyResponse&,
uint32_t*));
CdmResponseType SuperAddEntry(CryptoSession* crypto_session,
bool persistent_license,
const CdmKeySetId& key_set_id,
const std::string& usage_info_filename,
const CdmKeyResponse& license_message,
uint32_t* usage_entry_number) {
return UsageTableHeader::AddEntry(crypto_session, persistent_license,
key_set_id, usage_info_filename,
license_message, usage_entry_number);
}
};
} // namespace
// gmock methods
using ::testing::_;
using ::testing::AllOf;
using ::testing::AtMost;
using ::testing::ContainerEq;
using ::testing::Contains;
using ::testing::DoAll;
using ::testing::ElementsAre;
using ::testing::ElementsAreArray;
using ::testing::Ge;
using ::testing::Invoke;
using ::testing::InvokeWithoutArgs;
using ::testing::Lt;
using ::testing::NotNull;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::SetArgPointee;
using ::testing::SizeIs;
using ::testing::StrEq;
using ::testing::UnorderedElementsAre;
using ::testing::UnorderedElementsAreArray;
class UsageTableHeaderTest : public WvCdmTestBase {
public:
static void SetUpTestCase() {
@@ -523,6 +541,7 @@ class UsageTableHeaderTest : public WvCdmTestBase {
// Create new mock objects if using MockUsageTableHeader
device_files_ = new MockDeviceFiles();
crypto_session_ = new MockCryptoSession(&crypto_metrics_);
MockUsageTableHeader* mock_usage_table_header = new MockUsageTableHeader();
// mock_usage_table_header_ object takes ownership of these objects
@@ -652,16 +671,16 @@ TEST_P(UsageTableHeaderInitializationTest, UsageTableHeaderExists) {
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
}
TEST_P(UsageTableHeaderInitializationTest, 200UsageEntries) {
std::vector<CdmUsageEntryInfo> usage_entries_200 = k201UsageEntryInfoVector;
usage_entries_200.resize(200);
TEST_P(UsageTableHeaderInitializationTest, UsageEntriesAtCapacity) {
std::vector<CdmUsageEntryInfo> usage_entries = kOverFullUsageEntryInfoVector;
usage_entries.resize(kDefaultTableCapacity);
const SecurityLevel security_level =
(GetParam() == kSecurityLevelL3) ? kLevel3 : kLevelDefault;
EXPECT_CALL(*device_files_,
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
SetArgPointee<1>(usage_entries_200),
SetArgPointee<2>(false), Return(true)));
SetArgPointee<1>(usage_entries), SetArgPointee<2>(false),
Return(true)));
EXPECT_CALL(*crypto_session_,
LoadUsageTableHeader(security_level, kUsageTableHeader))
.WillOnce(Return(NO_ERROR));
@@ -670,11 +689,76 @@ TEST_P(UsageTableHeaderInitializationTest, 200UsageEntries) {
}
TEST_P(UsageTableHeaderInitializationTest,
201UsageEntries_AddEntryFails_UsageTableHeaderRecreated) {
UsageEntries_NoCapacity_UnderMinimum) {
crypto_session_->SetMaximumUsageTableEntries(0); // Unlimited.
std::vector<CdmUsageEntryInfo> usage_entries = kOverFullUsageEntryInfoVector;
constexpr size_t kHalfMinCapacity = kDefaultTableCapacity / 2;
usage_entries.resize(kHalfMinCapacity);
const SecurityLevel security_level =
(GetParam() == kSecurityLevelL3) ? kLevel3 : kLevelDefault;
EXPECT_CALL(*device_files_,
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
SetArgPointee<1>(k201UsageEntryInfoVector),
SetArgPointee<1>(usage_entries), SetArgPointee<2>(false),
Return(true)));
EXPECT_CALL(*crypto_session_,
LoadUsageTableHeader(security_level, kUsageTableHeader))
.WillOnce(Return(NO_ERROR));
// No expectations of creating or deleting entries if the number of entries
// is less than minimally required capacity.
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
}
TEST_P(UsageTableHeaderInitializationTest, UsageEntries_NoCapacity) {
crypto_session_->SetMaximumUsageTableEntries(0); // Unlimited.
std::vector<CdmUsageEntryInfo> usage_entries = kOverFullUsageEntryInfoVector;
usage_entries.resize(kDefaultTableCapacity);
const SecurityLevel security_level =
(GetParam() == kSecurityLevelL3) ? kLevel3 : kLevelDefault;
EXPECT_CALL(*device_files_,
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
SetArgPointee<1>(usage_entries), SetArgPointee<2>(false),
Return(true)));
EXPECT_CALL(*crypto_session_,
LoadUsageTableHeader(security_level, kUsageTableHeader))
.WillOnce(Return(NO_ERROR));
// Expect an attempt to create a new entry.
EXPECT_CALL(*crypto_session_, Open(security_level))
.WillOnce(Return(NO_ERROR));
const uint32_t expect_usage_entry_number = kDefaultTableCapacity;
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(expect_usage_entry_number), Return(NO_ERROR)));
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
EXPECT_CALL(*device_files_,
StoreUsageTableInfo(kAnotherUsageTableHeader,
SizeIs(kDefaultTableCapacity + 1)))
.WillOnce(Return(true));
// Delete the entry after.
EXPECT_CALL(
*crypto_session_,
ShrinkUsageTableHeader(security_level, kDefaultTableCapacity, NotNull()))
.WillOnce(DoAll(SetArgPointee<2>(kYetAnotherUsageTableHeader),
Return(NO_ERROR)));
EXPECT_CALL(*device_files_,
StoreUsageTableInfo(kYetAnotherUsageTableHeader,
SizeIs(kDefaultTableCapacity)))
.WillOnce(Return(true));
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
}
TEST_P(UsageTableHeaderInitializationTest,
UsageEntriesOverCapacity_AddEntryFails_UsageTableHeaderRecreated) {
EXPECT_CALL(*device_files_,
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
SetArgPointee<1>(kOverFullUsageEntryInfoVector),
SetArgPointee<2>(false), Return(true)));
const SecurityLevel security_level =
@@ -696,7 +780,8 @@ TEST_P(UsageTableHeaderInitializationTest,
.WillOnce(Return(true));
// Expectations for AddEntry
const uint32_t expect_usage_entry_number = k201UsageEntryInfoVector.size();
const uint32_t expect_usage_entry_number =
kOverFullUsageEntryInfoVector.size();
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(expect_usage_entry_number),
Return(CREATE_USAGE_ENTRY_UNKNOWN_ERROR)));
@@ -705,9 +790,46 @@ TEST_P(UsageTableHeaderInitializationTest,
}
TEST_P(UsageTableHeaderInitializationTest,
201UsageEntries_AddInvalidateEntrySucceeds) {
std::vector<CdmUsageEntryInfo> usage_entries_202 = k201UsageEntryInfoVector;
usage_entries_202.push_back(kDummyUsageEntryInfo);
UsageEntries_NoCapacity_AddEntryFails_UsageTableHeaderRecreated) {
crypto_session_->SetMaximumUsageTableEntries(0); // Unlimited.
std::vector<CdmUsageEntryInfo> usage_entries = kOverFullUsageEntryInfoVector;
usage_entries.resize(kDefaultTableCapacity);
const SecurityLevel security_level =
(GetParam() == kSecurityLevelL3) ? kLevel3 : kLevelDefault;
EXPECT_CALL(*device_files_,
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
SetArgPointee<1>(usage_entries), SetArgPointee<2>(false),
Return(true)));
EXPECT_CALL(*crypto_session_,
LoadUsageTableHeader(security_level, kUsageTableHeader))
.WillOnce(Return(NO_ERROR));
// Try to create a new entry, and fail.
EXPECT_CALL(*crypto_session_, Open(security_level))
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
.WillOnce(Return(CREATE_USAGE_ENTRY_UNKNOWN_ERROR));
// Expect clean up.
EXPECT_CALL(*device_files_, DeleteAllLicenses()).WillOnce(Return(true));
EXPECT_CALL(*device_files_, DeleteAllUsageInfo()).WillOnce(Return(true));
EXPECT_CALL(*device_files_, DeleteUsageTableInfo()).WillOnce(Return(true));
// Expect recreation of usage table.
EXPECT_CALL(*crypto_session_,
CreateUsageTableHeader(security_level, NotNull()))
.WillOnce(
DoAll(SetArgPointee<1>(kEmptyUsageTableHeader), Return(NO_ERROR)));
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kEmptyUsageTableHeader,
kEmptyUsageEntryInfoVector))
.WillOnce(Return(true));
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
}
TEST_P(UsageTableHeaderInitializationTest,
UsageEntriesOverCapacity_AddInvalidateEntrySucceeds) {
// Capacity +2.
std::vector<CdmUsageEntryInfo> usage_entries = kOverFullUsageEntryInfoVector;
usage_entries.push_back(kDummyUsageEntryInfo);
const SecurityLevel security_level =
(GetParam() == kSecurityLevelL3) ? kLevel3 : kLevelDefault;
@@ -715,33 +837,36 @@ TEST_P(UsageTableHeaderInitializationTest,
EXPECT_CALL(*device_files_,
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
SetArgPointee<1>(k201UsageEntryInfoVector),
SetArgPointee<1>(kOverFullUsageEntryInfoVector),
SetArgPointee<2>(false), Return(true)));
EXPECT_CALL(*crypto_session_,
LoadUsageTableHeader(security_level, kUsageTableHeader))
.WillOnce(Return(NO_ERROR));
// Expectations for AddEntry
const uint32_t expect_usage_entry_number = k201UsageEntryInfoVector.size();
const uint32_t expect_usage_entry_number =
kOverFullUsageEntryInfoVector.size();
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(expect_usage_entry_number),
Return(NO_ERROR)));
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kUsageTableHeader,
usage_entries_202))
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
EXPECT_CALL(*device_files_,
StoreUsageTableInfo(kAnotherUsageTableHeader, usage_entries))
.WillOnce(Return(true));
// Expectations for InvalidateEntry, assumes no entry other entry is invalid.
EXPECT_CALL(*crypto_session_, Open(security_level))
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(*crypto_session_,
ShrinkUsageTableHeader(security_level,
usage_entries_202.size() - 1, NotNull()))
.WillOnce(
DoAll(SetArgPointee<2>(kAnotherUsageTableHeader), Return(NO_ERROR)));
ShrinkUsageTableHeader(security_level, usage_entries.size() - 1,
NotNull()))
.WillOnce(DoAll(SetArgPointee<2>(kYetAnotherUsageTableHeader),
Return(NO_ERROR)));
EXPECT_CALL(*device_files_,
StoreUsageTableInfo(
kAnotherUsageTableHeader,
SizeIs(k201UsageEntryInfoVector.size())))
StoreUsageTableInfo(kYetAnotherUsageTableHeader,
SizeIs(kOverFullUsageEntryInfoVector.size())))
.WillOnce(Return(true));
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
@@ -800,10 +925,12 @@ TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveOfflineUsageEntry) {
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(expect_usage_entry_number), Return(NO_ERROR)));
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
EXPECT_CALL(*device_files_,
StoreUsageTableInfo(
kUsageTableHeader,
kAnotherUsageTableHeader,
UnorderedElementsAreArray(expect_usage_entry_info_vector)))
.WillOnce(Return(true));
@@ -831,10 +958,12 @@ TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveSecureStopUsageEntry) {
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(expect_usage_entry_number), Return(NO_ERROR)));
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
EXPECT_CALL(*device_files_,
StoreUsageTableInfo(
kUsageTableHeader,
kAnotherUsageTableHeader,
UnorderedElementsAreArray(expect_usage_entry_info_vector)))
.WillOnce(Return(true));
@@ -859,11 +988,13 @@ TEST_F(UsageTableHeaderTest, AddEntry_SkipUsageEntries) {
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(expect_usage_entry_number), Return(NO_ERROR)));
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
EXPECT_CALL(
*device_files_,
StoreUsageTableInfo(
kUsageTableHeader,
kAnotherUsageTableHeader,
UnorderedElementsAre(
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoSecureStop1,
kUsageEntryInfoStorageTypeUnknown,
@@ -905,17 +1036,19 @@ TEST_F(UsageTableHeaderTest,
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
.WillOnce(Return(INSUFFICIENT_CRYPTO_RESOURCES_3))
.WillOnce(DoAll(SetArgPointee<0>(expected_usage_entry_number),
Return(NO_ERROR)));
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(expected_usage_entry_number),
Return(NO_ERROR)));
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kUsageTableHeader, _))
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;
EXPECT_EQ(NO_ERROR,
mock_usage_table_header->AddEntry(
mock_usage_table_header->SuperAddEntry(
crypto_session_,
kUsageEntryInfoOfflineLicense6.storage_type == kStorageLicense,
kUsageEntryInfoOfflineLicense6.key_set_id,
@@ -959,7 +1092,7 @@ TEST_F(UsageTableHeaderTest, AddEntry_CreateUsageEntryFailsEveryTime) {
// Now invoke the method under test
uint32_t usage_entry_number;
EXPECT_EQ(INSUFFICIENT_CRYPTO_RESOURCES_3,
mock_usage_table_header->AddEntry(
mock_usage_table_header->SuperAddEntry(
crypto_session_, true /* persistent */,
kUsageEntryInfoOfflineLicense6.key_set_id,
kUsageEntryInfoOfflineLicense6.usage_info_file_name,
@@ -3390,8 +3523,10 @@ TEST_F(UsageTableHeaderTest, LruLastUsedTime_CreateLicenseEntry) {
MockClock mock_clock;
usage_table_header_->SetClock(&mock_clock);
EXPECT_CALL(mock_clock, GetCurrentTime()).WillOnce(Return(kLruBaseTime));
EXPECT_CALL(*device_files_,
StoreUsageTableInfo(kUpgradedUsageTableHeader, _));
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kAnotherUsageTableHeader, _));
// The Call.
uint32_t usage_entry_number = 0;
@@ -3436,8 +3571,10 @@ TEST_F(UsageTableHeaderTest, LruLastUsedTime_CreateUsageInfoEntry) {
MockClock mock_clock;
usage_table_header_->SetClock(&mock_clock);
EXPECT_CALL(mock_clock, GetCurrentTime()).WillOnce(Return(kLruBaseTime));
EXPECT_CALL(*device_files_,
StoreUsageTableInfo(kUpgradedUsageTableHeader, _));
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kAnotherUsageTableHeader, _));
// The Call.
uint32_t usage_entry_number = 0;
@@ -3970,15 +4107,7 @@ TEST_F(UsageTableHeaderTest, PotentialTableCapacity_Unavailable) {
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
EXPECT_EQ(usage_table_header_->potential_table_capacity(),
kMinimumUsageTableEntriesSupported);
}
TEST_F(UsageTableHeaderTest, PotentialTableCapacity_Zero) {
// This will issue a warning about the reported capacity is unexpected,
// and will default to the version's required minimum.
crypto_session_->SetMaximumUsageTableEntries(0u);
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
EXPECT_EQ(usage_table_header_->potential_table_capacity(),
kMinimumUsageTableEntriesSupported);
EXPECT_FALSE(usage_table_header_->HasUnlimitedTableCapacity());
}
TEST_F(UsageTableHeaderTest, PotentialTableCapacity_TooSmall) {
@@ -3989,6 +4118,18 @@ TEST_F(UsageTableHeaderTest, PotentialTableCapacity_TooSmall) {
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
EXPECT_EQ(usage_table_header_->potential_table_capacity(),
kMinimumUsageTableEntriesSupported);
EXPECT_FALSE(usage_table_header_->HasUnlimitedTableCapacity());
}
TEST_F(UsageTableHeaderTest, PotentialTableCapacity_Unlimited) {
MockUsageTableHeader* mock_usage_table_header = SetUpMock();
// Zero indicates that the table size is unlimited.
crypto_session_->SetMaximumUsageTableEntries(0u);
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
constexpr size_t kZero = 0u;
EXPECT_EQ(mock_usage_table_header->potential_table_capacity(), kZero);
EXPECT_TRUE(mock_usage_table_header->HasUnlimitedTableCapacity());
}
TEST_F(UsageTableHeaderTest, PotentialTableCapacity_Available) {
@@ -3996,6 +4137,7 @@ TEST_F(UsageTableHeaderTest, PotentialTableCapacity_Available) {
crypto_session_->SetMaximumUsageTableEntries(kTableCapacity);
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
EXPECT_EQ(usage_table_header_->potential_table_capacity(), kTableCapacity);
EXPECT_FALSE(usage_table_header_->HasUnlimitedTableCapacity());
}
} // namespace wvcdm