diff --git a/libwvdrmengine/cdm/core/include/usage_table_header.h b/libwvdrmengine/cdm/core/include/usage_table_header.h index f38a96ef..fe541e89 100644 --- a/libwvdrmengine/cdm/core/include/usage_table_header.h +++ b/libwvdrmengine/cdm/core/include/usage_table_header.h @@ -70,6 +70,14 @@ class UsageTableHeader { DeviceFiles* handle, metrics::CryptoMetrics* metrics); + // Test only method. This method emulates the behavior of DeleteEntry + // without actually invoking OEMCrypto (through CryptoSession) + // or storage (through DeviceFiles). It modifies internal data structures + // when DeleteEntry is mocked. This allows one to test methods that are + // dependent on DeleteEntry without having to set expectations + // for the objects that DeleteEntry depends on. + void DeleteEntryForTest(uint32_t usage_entry_number); + private: CdmResponseType MoveEntry(uint32_t from /* usage entry number */, const CdmUsageEntry& from_usage_entry, @@ -118,6 +126,9 @@ class UsageTableHeader { metrics::CryptoMetrics alternate_crypto_metrics_; + // TODO(rfrias): Move to utility class + uint32_t GetRandomInRange(size_t upper_bound_inclusive); + // Test related declarations friend class UsageTableHeaderTest; diff --git a/libwvdrmengine/cdm/core/src/cdm_session.cpp b/libwvdrmengine/cdm/core/src/cdm_session.cpp index 55808aac..020b36ff 100644 --- a/libwvdrmengine/cdm/core/src/cdm_session.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_session.cpp @@ -56,7 +56,8 @@ CdmSession::CdmSession(FileSystem* file_system, CdmSession::~CdmSession() { if (usage_support_type_ == kUsageEntrySupport && has_provider_session_token() && - usage_table_header_ != NULL) { + usage_table_header_ != NULL && + !is_release_) { UpdateUsageEntryInformation(); } diff --git a/libwvdrmengine/cdm/core/src/usage_table_header.cpp b/libwvdrmengine/cdm/core/src/usage_table_header.cpp index 6e5076f1..19817a1f 100644 --- a/libwvdrmengine/cdm/core/src/usage_table_header.cpp +++ b/libwvdrmengine/cdm/core/src/usage_table_header.cpp @@ -74,9 +74,27 @@ bool UsageTableHeader::Init(CdmSecurityLevel security_level, if (status == NO_ERROR) { if (usage_entry_info_.size() > kMinUsageEntriesSupported) { uint32_t temporary_usage_entry_number; - CdmResponseType result = AddEntry(crypto_session, true, - kDummyKeySetId, kEmptyString, - &temporary_usage_entry_number); + + // Create a new temporary usage entry, close the session and then + // try to delete it. + CdmResponseType result = NO_ERROR; + { + // |local_crypto_session| points to an object whose scope is this + // method or a test object whose scope is the lifetime of this class + scoped_ptr scoped_crypto_session; + CryptoSession* local_crypto_session = test_crypto_session_.get(); + if (local_crypto_session == NULL) { + scoped_crypto_session.reset((new CryptoSession(metrics))); + local_crypto_session = scoped_crypto_session.get(); + } + + result = local_crypto_session->Open(requested_security_level_); + if (result == NO_ERROR) { + result = AddEntry(local_crypto_session, true, + kDummyKeySetId, kEmptyString, + &temporary_usage_entry_number); + } + } if (result == NO_ERROR) { result = DeleteEntry(temporary_usage_entry_number, file_handle_.get(), metrics); @@ -125,17 +143,20 @@ CdmResponseType UsageTableHeader::AddEntry( metrics::CryptoMetrics* metrics = crypto_session->GetCryptoMetrics(); if (metrics == NULL) metrics = &alternate_crypto_metrics_; - uint32_t retry_count = 0; - CdmResponseType status = NO_ERROR; - do { - { - AutoLock auto_lock(usage_table_header_lock_); - status = crypto_session->CreateUsageEntry(usage_entry_number); - } - if (status == INSUFFICIENT_CRYPTO_RESOURCES_3) - DeleteEntry(retry_count, file_handle_.get(), metrics); - } while (status == INSUFFICIENT_CRYPTO_RESOURCES_3 && - ++retry_count < kMaxCryptoRetries); + CdmResponseType status = crypto_session->CreateUsageEntry(usage_entry_number); + + // If usage entry creation fails due to insufficient resources, release a + // random entry and try again. + for (uint32_t retry_count = 0; + retry_count < kMaxCryptoRetries && + status == INSUFFICIENT_CRYPTO_RESOURCES_3; + ++retry_count) { + uint32_t entry_number_to_delete = + GetRandomInRange(usage_entry_info_.size()); + DeleteEntry(entry_number_to_delete, file_handle_.get(), metrics); + + status = crypto_session->CreateUsageEntry(usage_entry_number); + } if (status != NO_ERROR) return status; @@ -189,17 +210,22 @@ CdmResponseType UsageTableHeader::LoadEntry(CryptoSession* crypto_session, metrics::CryptoMetrics* metrics = crypto_session->GetCryptoMetrics(); if (metrics == NULL) metrics = &alternate_crypto_metrics_; - uint32_t retry_count = 0; - CdmResponseType status = NO_ERROR; - do { - { - AutoLock auto_lock(usage_table_header_lock_); + CdmResponseType status = + crypto_session->LoadUsageEntry(usage_entry_number, usage_entry); + + // If loading a usage entry fails due to insufficient resources, release a + // random entry and try again. + for (uint32_t retry_count = 0; + retry_count < kMaxCryptoRetries && + status == INSUFFICIENT_CRYPTO_RESOURCES_3; + ++retry_count) { + uint32_t entry_number_to_delete = + GetRandomInRange(usage_entry_info_.size()); + if (usage_entry_number != entry_number_to_delete) { + DeleteEntry(entry_number_to_delete, file_handle_.get(), metrics); status = crypto_session->LoadUsageEntry(usage_entry_number, usage_entry); } - if (status == INSUFFICIENT_CRYPTO_RESOURCES_3) - DeleteEntry(retry_count, file_handle_.get(), metrics); - } while (status == INSUFFICIENT_CRYPTO_RESOURCES_3 && - ++retry_count < kMaxCryptoRetries); + } return status; } @@ -676,6 +702,11 @@ bool UsageTableHeader::UpgradeUsageInfoFromUsageTable( return NO_ERROR; } +uint32_t UsageTableHeader::GetRandomInRange(size_t upper_bound_inclusive) { + if (upper_bound_inclusive == 0) return 0; + return rand() / (RAND_MAX / upper_bound_inclusive + 1); +} + // TODO(fredgc): remove when b/65730828 is addressed bool UsageTableHeader::CreateDummyOldUsageEntry(CryptoSession* crypto_session) { return crypto_session->CreateOldUsageEntry( @@ -688,4 +719,20 @@ bool UsageTableHeader::CreateDummyOldUsageEntry(CryptoSession* crypto_session) { kOldUsageEntryPoviderSessionToken); } +// Test only method. +void UsageTableHeader::DeleteEntryForTest(uint32_t usage_entry_number) { + LOGV("UsageTableHeader::DeleteEntryForTest: usage_entry_number: %d", + usage_entry_number); + if (usage_entry_number >= usage_entry_info_.size()) { + LOGE("UsageTableHeader::DeleteEntryForTest: usage entry number %d larger " + "than usage entry size %d", usage_entry_number, + usage_entry_info_.size()); + return; + } + // Move last entry into deleted location and shrink usage entries + usage_entry_info_[usage_entry_number] = + usage_entry_info_[usage_entry_info_.size() - 1]; + usage_entry_info_.resize(usage_entry_info_.size() - 1); +} + } // namespace wvcdm diff --git a/libwvdrmengine/cdm/core/test/usage_table_header_unittest.cpp b/libwvdrmengine/cdm/core/test/usage_table_header_unittest.cpp index ddd963fa..220bc798 100644 --- a/libwvdrmengine/cdm/core/test/usage_table_header_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/usage_table_header_unittest.cpp @@ -47,6 +47,18 @@ const CdmUsageEntryInfo kUsageEntryInfoOfflineLicense3 = { .storage_type = kStorageLicense, .key_set_id = "offline_key_set_3", .usage_info_file_name = ""}; +const CdmUsageEntryInfo kUsageEntryInfoOfflineLicense4 = { + .storage_type = kStorageLicense, + .key_set_id = "offline_key_set_4", + .usage_info_file_name = ""}; +const CdmUsageEntryInfo kUsageEntryInfoOfflineLicense5 = { + .storage_type = kStorageLicense, + .key_set_id = "offline_key_set_5", + .usage_info_file_name = ""}; +const CdmUsageEntryInfo kUsageEntryInfoOfflineLicense6 = { + .storage_type = kStorageLicense, + .key_set_id = "offline_key_set_6", + .usage_info_file_name = ""}; const CdmUsageEntryInfo kUsageEntryInfoSecureStop1 = { .storage_type = kStorageUsageInfo, .key_set_id = "secure_stop_key_set_1", @@ -59,6 +71,14 @@ const CdmUsageEntryInfo kUsageEntryInfoSecureStop3 = { .storage_type = kStorageUsageInfo, .key_set_id = "secure_stop_key_set_3", .usage_info_file_name = "usage_info_file_3"}; +const CdmUsageEntryInfo kUsageEntryInfoSecureStop4 = { + .storage_type = kStorageUsageInfo, + .key_set_id = "secure_stop_key_set_4", + .usage_info_file_name = "usage_info_file_4"}; +const CdmUsageEntryInfo kUsageEntryInfoSecureStop5 = { + .storage_type = kStorageUsageInfo, + .key_set_id = "secure_stop_key_set_5", + .usage_info_file_name = "usage_info_file_5"}; const CdmUsageEntryInfo kUsageEntryInfoStorageTypeUnknown = { .storage_type = kStorageTypeUnknown, .key_set_id = "", @@ -144,31 +164,36 @@ void InitVectorConstants() { 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); + k201UsageEntryInfoVector.clear(); - const CdmUsageEntryInfo* usage_entry_info = - &kUsageEntryInfoStorageTypeUnknown; for (size_t i = 0; i < 201; ++i) { switch (i % 4) { case 0: - usage_entry_info = &kUsageEntryInfoOfflineLicense1; + k201UsageEntryInfoVector.push_back(kUsageEntryInfoOfflineLicense1); break; case 1: - usage_entry_info = &kUsageEntryInfoSecureStop1; + k201UsageEntryInfoVector.push_back(kUsageEntryInfoSecureStop1); break; case 2: - usage_entry_info = &kUsageEntryInfoOfflineLicense2; + k201UsageEntryInfoVector.push_back(kUsageEntryInfoOfflineLicense2); break; case 3: - usage_entry_info = &kUsageEntryInfoSecureStop2; + k201UsageEntryInfoVector.push_back(kUsageEntryInfoSecureStop2); break; default: - usage_entry_info = &kUsageEntryInfoStorageTypeUnknown; + k201UsageEntryInfoVector.push_back(kUsageEntryInfoStorageTypeUnknown); break; } - if (i < 10) { - k10UsageEntryInfoVector.push_back(*usage_entry_info); - } - k201UsageEntryInfoVector.push_back(*usage_entry_info); } kUsageInfoFileList.clear(); @@ -242,13 +267,25 @@ class MockCryptoSession : public CryptoSession { CdmResponseType(uint32_t, CdmUsageTableHeader*)); }; +// Partial mock of the UsageTableHeader. This is to test when dependency +// exist on internal methods which would require complex expectations +class MockUsageTableHeader : public UsageTableHeader { + public: + MockUsageTableHeader() : UsageTableHeader() {} + MOCK_METHOD3(DeleteEntry, CdmResponseType(uint32_t, DeviceFiles*, + metrics::CryptoMetrics*)); +}; + } // namespace // gmock methods using ::testing::_; +using ::testing::AtMost; using ::testing::ElementsAreArray; +using ::testing::Invoke; using ::testing::NotNull; using ::testing::Return; +using ::testing::SaveArg; using ::testing::SetArgPointee; using ::testing::SizeIs; using ::testing::StrEq; @@ -261,6 +298,12 @@ class UsageTableHeaderTest : public ::testing::Test { InitVectorConstants(); } + // Useful when UsageTableHeader is mocked + void DeleteEntry(uint32_t usage_entry_number, DeviceFiles*, + metrics::CryptoMetrics*) { + usage_table_header_->DeleteEntryForTest(usage_entry_number); + } + protected: virtual void SetUp() { // UsageTableHeader will take ownership of the pointer @@ -273,6 +316,27 @@ class UsageTableHeaderTest : public ::testing::Test { usage_table_header_->SetCryptoSession(crypto_session_); } + // UsageTableHeaderTest maintains ownership of returned pointer + MockUsageTableHeader* SetUpMock() { + // Release non-mocked usage table header + if (usage_table_header_ != NULL) { + delete usage_table_header_; + usage_table_header_ = NULL; + } + + // 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 + mock_usage_table_header->SetDeviceFiles(device_files_); + mock_usage_table_header->SetCryptoSession(crypto_session_); + + usage_table_header_ = mock_usage_table_header; + return mock_usage_table_header; + } + virtual void TearDown() { if (usage_table_header_ != NULL) delete usage_table_header_; } @@ -286,7 +350,6 @@ class UsageTableHeaderTest : public ::testing::Test { Return(true))); EXPECT_CALL(*crypto_session_, LoadUsageTableHeader(usage_table_header)) .WillOnce(Return(NO_ERROR)); - EXPECT_TRUE(usage_table_header_->Init(security_level, crypto_session_)); } @@ -421,6 +484,11 @@ TEST_P(UsageTableHeaderInitializationTest, .WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader), SetArgPointee<1>(k201UsageEntryInfoVector), Return(true))); + + SecurityLevel security_level = + (GetParam() == kSecurityLevelL3) ? kLevel3 : kLevelDefault; + EXPECT_CALL(*crypto_session_, + Open(security_level)).WillOnce(Return(NO_ERROR)); EXPECT_CALL(*crypto_session_, LoadUsageTableHeader(kUsageTableHeader)) .WillOnce(Return(NO_ERROR)); EXPECT_CALL(*crypto_session_, CreateUsageTableHeader(NotNull())) @@ -458,6 +526,7 @@ TEST_P(UsageTableHeaderInitializationTest, DoAll(SetArgPointee<0>(kEmptyUsageTableHeader), Return(NO_ERROR))); 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_CALL(*device_files_, StoreUsageTableInfo(kEmptyUsageTableHeader, kEmptyUsageEntryInfoVector)) .WillOnce(Return(true)); @@ -475,7 +544,9 @@ TEST_P(UsageTableHeaderInitializationTest, SecurityLevel security_level = (GetParam() == kSecurityLevelL3) ? kLevel3 : kLevelDefault; EXPECT_CALL(*crypto_session_, - Open(security_level)).WillOnce(Return(NO_ERROR)); + Open(security_level)) + .Times(2) + .WillRepeatedly(Return(NO_ERROR)); EXPECT_CALL( *crypto_session_, ShrinkUsageTableHeader(usage_entries_202.size() - 1, NotNull())) @@ -510,7 +581,9 @@ TEST_P(UsageTableHeaderInitializationTest, (GetParam() == kSecurityLevelL3) ? kLevel3 : kLevelDefault; EXPECT_CALL(*crypto_session_, - Open(security_level)).WillOnce(Return(NO_ERROR)); + Open(security_level)) + .Times(2) + .WillRepeatedly(Return(NO_ERROR)); EXPECT_CALL( *crypto_session_, ShrinkUsageTableHeader(usage_entries_202.size() - 1, NotNull())) @@ -662,588 +735,176 @@ TEST_F(UsageTableHeaderTest, AddEntry_SkipUsageEntries) { TEST_F(UsageTableHeaderTest, AddEntry_CreateUsageEntryFailsOnce_SucceedsSecondTime) { + // Initialize and setup + MockUsageTableHeader* mock_usage_table_header = SetUpMock(); Init(kSecurityLevelL1, kUsageTableHeader, k10UsageEntryInfoVector); std::vector usage_entry_info_vector_at_start = k10UsageEntryInfoVector; - uint32_t usage_entry_number_to_be_deleted = 0; - CdmUsageEntryInfo usage_entry_to_be_deleted = - usage_entry_info_vector_at_start[usage_entry_number_to_be_deleted]; - uint32_t usage_entry_number_to_be_moved = - usage_entry_info_vector_at_start.size() - 1; - CdmUsageEntryInfo usage_entry_to_be_moved = - usage_entry_info_vector_at_start[usage_entry_number_to_be_moved]; + uint32_t usage_entry_number_first_to_be_deleted; // randomly choosen + std::vector final_usage_entries; - // The last entry is moved to the entry to be deleted (0) - std::vector usage_entry_info_vector_after_move = - usage_entry_info_vector_at_start; - usage_entry_info_vector_after_move[usage_entry_number_to_be_deleted] = - usage_entry_info_vector_at_start[usage_entry_number_to_be_moved]; + uint32_t expected_usage_entry_number = k10UsageEntryInfoVector.size() - 1; - // The entries are then shrunk by 1 - std::vector shrunk_usage_entry_info_vector = - usage_entry_info_vector_after_move; - shrunk_usage_entry_info_vector.resize( - shrunk_usage_entry_info_vector.size() - 1); + // Setup expectations + EXPECT_CALL(*mock_usage_table_header, + DeleteEntry(_, device_files_, NotNull())) + .WillOnce(DoAll(SaveArg<0>(&usage_entry_number_first_to_be_deleted), + Invoke(this, &UsageTableHeaderTest::DeleteEntry), + Return(NO_ERROR))); - // The new entry is then added to the end - uint32_t expect_usage_entry_number = k10UsageEntryInfoVector.size() - 1; - std::vector expect_usage_entry_info_vector = - shrunk_usage_entry_info_vector; - expect_usage_entry_info_vector.push_back(kUsageEntryInfoOfflineLicense3); - - // Expectations for AddEntry EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull())) .WillOnce(Return(INSUFFICIENT_CRYPTO_RESOURCES_3)) .WillOnce( - DoAll(SetArgPointee<0>(expect_usage_entry_number), Return(NO_ERROR))); + DoAll(SetArgPointee<0>(expected_usage_entry_number), + Return(NO_ERROR))); - EXPECT_CALL(*device_files_, - StoreUsageTableInfo( - kAnotherUsageTableHeader, - ElementsAreArray(expect_usage_entry_info_vector))) - .WillOnce(Return(true)); - - // Expectations for StoreEntry (DeleteEntry->MoveEntry) - EXPECT_CALL(*device_files_, - DeleteUsageInfo(usage_entry_to_be_moved.usage_info_file_name, - kProviderSessionToken)) - .WillOnce(Return(true)); - EXPECT_CALL(*device_files_, - StoreUsageInfo(kProviderSessionToken, kKeyRequest, kKeyResponse, - usage_entry_to_be_moved.usage_info_file_name, - usage_entry_to_be_moved.key_set_id, kAnotherUsageEntry, - usage_entry_number_to_be_deleted)) - .WillOnce(Return(true)); - - // Expectations for Shrink (DeleteEntry) - EXPECT_CALL( - *crypto_session_, - ShrinkUsageTableHeader(shrunk_usage_entry_info_vector.size(), NotNull())) - .WillOnce( - DoAll(SetArgPointee<1>(kAnotherUsageTableHeader), Return(NO_ERROR))); - EXPECT_CALL(*device_files_, - StoreUsageTableInfo( - kAnotherUsageTableHeader, - ElementsAreArray(shrunk_usage_entry_info_vector))) - .WillOnce(Return(true)); - - // Expectations for MoveEntry (DeleteEntry) - EXPECT_CALL(*crypto_session_, Open(kLevelDefault)) - .Times(2) - .WillRepeatedly(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, - LoadUsageEntry(usage_entry_number_to_be_moved, - kUsageEntry)) - .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, - MoveUsageEntry(usage_entry_number_to_be_deleted)) - .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull())) - .WillOnce(DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), - SetArgPointee<1>(kAnotherUsageEntry), Return(NO_ERROR))); - EXPECT_CALL(*device_files_, - StoreUsageTableInfo( - kAnotherUsageTableHeader, - ElementsAreArray(usage_entry_info_vector_after_move))) - .WillOnce(Return(true)); - - // Expectations for GetEntry (DeleteEntry) - EXPECT_CALL(*device_files_, - RetrieveUsageInfoByKeySetId( - usage_entry_to_be_moved.usage_info_file_name, - usage_entry_to_be_moved.key_set_id, NotNull(), NotNull(), - NotNull(), NotNull(), NotNull())) - .Times(2) - .WillRepeatedly(DoAll( - SetArgPointee<2>(kProviderSessionToken), - SetArgPointee<3>(kKeyRequest), SetArgPointee<4>(kKeyResponse), - SetArgPointee<5>(kUsageEntry), - SetArgPointee<6>(usage_entry_number_to_be_moved), Return(true))); + EXPECT_CALL(*device_files_, StoreUsageTableInfo(kUsageTableHeader, _)) + .WillOnce(DoAll(SaveArg<1>(&final_usage_entries), Return(true))); + // Now invoke the method under test uint32_t usage_entry_number; EXPECT_EQ(NO_ERROR, - usage_table_header_->AddEntry( + mock_usage_table_header->AddEntry( crypto_session_, - kUsageEntryInfoOfflineLicense3.storage_type == kStorageLicense, - kUsageEntryInfoOfflineLicense3.key_set_id, - kUsageEntryInfoOfflineLicense3.usage_info_file_name, + kUsageEntryInfoOfflineLicense6.storage_type == kStorageLicense, + kUsageEntryInfoOfflineLicense6.key_set_id, + kUsageEntryInfoOfflineLicense6.usage_info_file_name, &usage_entry_number)); - EXPECT_EQ(expect_usage_entry_number, usage_entry_number); + + // 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); + + std::vector 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); + + EXPECT_EQ(expected_usage_entries, final_usage_entries); } TEST_F(UsageTableHeaderTest, AddEntry_CreateUsageEntryFailsTwice_SucceedsThirdTime) { + // Initialize and setup + MockUsageTableHeader* mock_usage_table_header = SetUpMock(); Init(kSecurityLevelL1, kUsageTableHeader, k10UsageEntryInfoVector); - - // Initial usage entry info std::vector usage_entry_info_vector_at_start = k10UsageEntryInfoVector; - // usage entry info after first move - uint32_t usage_entry_number_first_to_be_deleted = 0; - uint32_t usage_entry_number_first_to_be_moved = - usage_entry_info_vector_at_start.size() - 1; + uint32_t usage_entry_number_first_to_be_deleted; // randomly choosen + uint32_t usage_entry_number_second_to_be_deleted; // randomly choosen + std::vector final_usage_entries; - // The last entry is moved to the first entry to be deleted - CdmUsageEntryInfo usage_entry_first_to_be_moved = - usage_entry_info_vector_at_start[usage_entry_number_first_to_be_moved]; - std::vector usage_entry_info_vector_after_first_move = - usage_entry_info_vector_at_start; - usage_entry_info_vector_after_first_move[ - usage_entry_number_first_to_be_deleted] = - usage_entry_first_to_be_moved; + uint32_t expected_usage_entry_number = k10UsageEntryInfoVector.size() - 2; - // The entries are then shrunk by 1 - std::vector usage_entry_info_vector_after_first_shrink = - usage_entry_info_vector_after_first_move; - usage_entry_info_vector_after_first_shrink.resize( - usage_entry_info_vector_after_first_shrink.size() - 1); + // Setup expectations + EXPECT_CALL(*mock_usage_table_header, + DeleteEntry(_, device_files_, NotNull())) + .WillOnce(DoAll(SaveArg<0>(&usage_entry_number_first_to_be_deleted), + Invoke(this, &UsageTableHeaderTest::DeleteEntry), + Return(NO_ERROR))) + .WillOnce(DoAll(SaveArg<0>(&usage_entry_number_second_to_be_deleted), + Invoke(this, &UsageTableHeaderTest::DeleteEntry), + Return(NO_ERROR))); - // usage entry info after second move - uint32_t usage_entry_number_second_to_be_deleted = 1; - uint32_t usage_entry_number_second_to_be_moved = - usage_entry_info_vector_after_first_shrink.size() - 1; - - // The last entry is moved to the second entry to be deleted - CdmUsageEntryInfo usage_entry_second_to_be_moved = - usage_entry_info_vector_after_first_shrink[ - usage_entry_number_second_to_be_moved]; - std::vector usage_entry_info_vector_after_second_move = - usage_entry_info_vector_after_first_shrink; - usage_entry_info_vector_after_second_move[ - usage_entry_number_second_to_be_deleted] = usage_entry_second_to_be_moved; - - // The entries are then shrunk by 1 - std::vector usage_entry_info_vector_after_second_shrink = - usage_entry_info_vector_after_second_move; - usage_entry_info_vector_after_second_shrink.resize( - usage_entry_info_vector_after_second_shrink.size() - 1); - - // The new entry is then added to the end - uint32_t expect_usage_entry_number = - usage_entry_info_vector_after_second_shrink.size(); - std::vector expect_usage_entry_info_vector = - usage_entry_info_vector_after_second_shrink; - expect_usage_entry_info_vector.push_back(kUsageEntryInfoOfflineLicense3); - - // Expectations for AddEntry EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull())) .WillOnce(Return(INSUFFICIENT_CRYPTO_RESOURCES_3)) .WillOnce(Return(INSUFFICIENT_CRYPTO_RESOURCES_3)) .WillOnce( - DoAll(SetArgPointee<0>(expect_usage_entry_number), Return(NO_ERROR))); - - EXPECT_CALL(*device_files_, - StoreUsageTableInfo( - kYetAnotherUsageTableHeader, - ElementsAreArray(expect_usage_entry_info_vector))) - .WillOnce(Return(true)); - - // Expectations for StoreEntry (DeleteEntry->MoveEntry) - EXPECT_CALL(*device_files_, - DeleteUsageInfo(usage_entry_first_to_be_moved.usage_info_file_name, - kProviderSessionToken)) - .WillOnce(Return(true)); - EXPECT_CALL(*device_files_, - StoreUsageInfo(kProviderSessionToken, kKeyRequest, kKeyResponse, - usage_entry_first_to_be_moved.usage_info_file_name, - usage_entry_first_to_be_moved.key_set_id, - kAnotherUsageEntry, - usage_entry_number_first_to_be_deleted)) - .WillOnce(Return(true)); - - EXPECT_TRUE(device_files_->StoreLicense( - usage_entry_second_to_be_moved.key_set_id, - kActiveLicenseState, kPsshData, kKeyRequest, kKeyResponse, - kKeyRenewalRequest, kKeyRenewalResponse, kReleaseServerUrl, - kPlaybackStartTime, kPlaybackStartTime + kPlaybackDuration, - kGracePeriodEndTime, kEmptyAppParameters, kYetAnotherUsageEntry, - usage_entry_number_second_to_be_moved)); - - DeviceFiles::LicenseState license_state = DeviceFiles::kLicenseStateUnknown; - CdmInitData pssh_data; - CdmKeyMessage key_request; - CdmKeyResponse key_response; - CdmKeyMessage key_renewal_request; - CdmKeyResponse key_renewal_response; - std::string release_server_url; - int64_t playback_start_time; - int64_t last_playback_time; - int64_t grace_period_end_time; - CdmAppParameterMap app_parameters; - CdmUsageEntry usage_entry; - uint32_t usage_entry_number = ~0; - - EXPECT_TRUE(device_files_->RetrieveLicense( - usage_entry_second_to_be_moved.key_set_id, &license_state, &pssh_data, - &key_request, &key_response, &key_renewal_request, &key_renewal_response, - &release_server_url, &playback_start_time, &last_playback_time, - &grace_period_end_time, &app_parameters, &usage_entry, - &usage_entry_number)); - EXPECT_EQ(kActiveLicenseState, license_state); - EXPECT_EQ(kPsshData, pssh_data); - EXPECT_EQ(kKeyRequest, key_request); - EXPECT_EQ(kKeyResponse, key_response); - EXPECT_EQ(kKeyRenewalRequest, key_renewal_request); - EXPECT_EQ(kKeyRenewalResponse, key_renewal_response); - EXPECT_EQ(kReleaseServerUrl, release_server_url); - EXPECT_EQ(kPlaybackStartTime, playback_start_time); - EXPECT_EQ(kPlaybackStartTime + kPlaybackDuration, last_playback_time); - EXPECT_EQ(kGracePeriodEndTime, grace_period_end_time); - EXPECT_EQ(kEmptyAppParameters.size(), app_parameters.size()); - EXPECT_EQ(kYetAnotherUsageEntry, usage_entry); - EXPECT_EQ(usage_entry_number_second_to_be_moved, usage_entry_number); - - // Expectations for Shrink (DeleteEntry) - EXPECT_CALL( - *crypto_session_, - ShrinkUsageTableHeader( - usage_entry_info_vector_after_first_shrink.size(), NotNull())) - .WillOnce( - DoAll(SetArgPointee<1>(kAnotherUsageTableHeader), Return(NO_ERROR))); - EXPECT_CALL( - *crypto_session_, - ShrinkUsageTableHeader( - usage_entry_info_vector_after_second_shrink.size(), NotNull())) - .WillOnce( - DoAll(SetArgPointee<1>(kYetAnotherUsageTableHeader), + DoAll(SetArgPointee<0>(expected_usage_entry_number), Return(NO_ERROR))); - EXPECT_CALL(*device_files_, - StoreUsageTableInfo( - kAnotherUsageTableHeader, - ElementsAreArray(usage_entry_info_vector_after_first_shrink))) - .WillOnce(Return(true)); - EXPECT_CALL(*device_files_, - StoreUsageTableInfo( - kYetAnotherUsageTableHeader, - ElementsAreArray( - usage_entry_info_vector_after_second_shrink))) - .WillOnce(Return(true)); - // Expectations for MoveEntry (DeleteEntry) - EXPECT_CALL(*crypto_session_, Open(kLevelDefault)) - .Times(4) - .WillRepeatedly(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, - LoadUsageEntry(usage_entry_number_first_to_be_moved, - kUsageEntry)) - .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, - LoadUsageEntry(usage_entry_number_second_to_be_moved, - kYetAnotherUsageEntry)) - .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, - MoveUsageEntry(usage_entry_number_first_to_be_deleted)) - .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, - MoveUsageEntry(usage_entry_number_second_to_be_deleted)) - .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull())) - .WillOnce(DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), - SetArgPointee<1>(kAnotherUsageEntry), Return(NO_ERROR))) - .WillOnce(DoAll(SetArgPointee<0>(kYetAnotherUsageTableHeader), - SetArgPointee<1>(kYetAnotherUsageEntry), - Return(NO_ERROR))); - EXPECT_CALL(*device_files_, - StoreUsageTableInfo( - kAnotherUsageTableHeader, - ElementsAreArray(usage_entry_info_vector_after_first_move))) - .WillOnce(Return(true)); - EXPECT_CALL(*device_files_, - StoreUsageTableInfo( - kYetAnotherUsageTableHeader, - ElementsAreArray(usage_entry_info_vector_after_second_move))) - .WillOnce(Return(true)); - - // Expectations for GetEntry (DeleteEntry) - EXPECT_CALL(*device_files_, - RetrieveUsageInfoByKeySetId( - usage_entry_first_to_be_moved.usage_info_file_name, - usage_entry_first_to_be_moved.key_set_id, NotNull(), NotNull(), - NotNull(), NotNull(), NotNull())) - .Times(2) - .WillRepeatedly(DoAll( - SetArgPointee<2>(kProviderSessionToken), - SetArgPointee<3>(kKeyRequest), SetArgPointee<4>(kKeyResponse), - SetArgPointee<5>(kUsageEntry), - SetArgPointee<6>(usage_entry_number_first_to_be_moved), - Return(true))); + EXPECT_CALL(*device_files_, StoreUsageTableInfo(kUsageTableHeader, _)) + .WillOnce(DoAll(SaveArg<1>(&final_usage_entries), Return(true))); + // Now invoke the method under test + uint32_t usage_entry_number; EXPECT_EQ(NO_ERROR, - usage_table_header_->AddEntry( + mock_usage_table_header->AddEntry( crypto_session_, - kUsageEntryInfoOfflineLicense3.storage_type == kStorageLicense, - kUsageEntryInfoOfflineLicense3.key_set_id, - kUsageEntryInfoOfflineLicense3.usage_info_file_name, + kUsageEntryInfoOfflineLicense6.storage_type == kStorageLicense, + kUsageEntryInfoOfflineLicense6.key_set_id, + kUsageEntryInfoOfflineLicense6.usage_info_file_name, &usage_entry_number)); - EXPECT_EQ(expect_usage_entry_number, usage_entry_number); + + // 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, usage_entry_number_second_to_be_deleted); + EXPECT_LE(usage_entry_number_second_to_be_deleted, + usage_entry_info_vector_at_start.size() - 1); + + std::vector 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[usage_entry_number_second_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); + + EXPECT_EQ(expected_usage_entries, final_usage_entries); } TEST_F(UsageTableHeaderTest, AddEntry_CreateUsageEntryFailsThrice) { + // Initialize and setup + MockUsageTableHeader* mock_usage_table_header = SetUpMock(); Init(kSecurityLevelL1, kUsageTableHeader, k10UsageEntryInfoVector); - - // Initial usage entry info std::vector usage_entry_info_vector_at_start = k10UsageEntryInfoVector; - // usage entry info after first move - uint32_t usage_entry_number_first_to_be_deleted = 0; - uint32_t usage_entry_number_first_to_be_moved = - usage_entry_info_vector_at_start.size() - 1; + uint32_t usage_entry_number_first_to_be_deleted; // randomly choosen + uint32_t usage_entry_number_second_to_be_deleted; // randomly choosen + uint32_t usage_entry_number_third_to_be_deleted; // randomly choosen + std::vector final_usage_entries; - // The last entry is moved to the first entry to be deleted - CdmUsageEntryInfo usage_entry_first_to_be_moved = - usage_entry_info_vector_at_start[usage_entry_number_first_to_be_moved]; - std::vector usage_entry_info_vector_after_first_move = - usage_entry_info_vector_at_start; - usage_entry_info_vector_after_first_move[ - usage_entry_number_first_to_be_deleted] = - usage_entry_first_to_be_moved; + // Setup expectations + EXPECT_CALL(*mock_usage_table_header, + DeleteEntry(_, device_files_, NotNull())) + .WillOnce(DoAll(SaveArg<0>(&usage_entry_number_first_to_be_deleted), + Invoke(this, &UsageTableHeaderTest::DeleteEntry), + Return(NO_ERROR))) + .WillOnce(DoAll(SaveArg<0>(&usage_entry_number_second_to_be_deleted), + Invoke(this, &UsageTableHeaderTest::DeleteEntry), + Return(NO_ERROR))) + .WillOnce(DoAll(SaveArg<0>(&usage_entry_number_third_to_be_deleted), + Invoke(this, &UsageTableHeaderTest::DeleteEntry), + Return(NO_ERROR))); - // The entries are then shrunk by 1 - std::vector usage_entry_info_vector_after_first_shrink = - usage_entry_info_vector_after_first_move; - usage_entry_info_vector_after_first_shrink.resize( - usage_entry_info_vector_after_first_shrink.size() - 1); - - // usage entry info after second move - uint32_t usage_entry_number_second_to_be_deleted = 1; - uint32_t usage_entry_number_second_to_be_moved = - usage_entry_info_vector_after_first_shrink.size() - 1; - - // The last entry is moved to the second entry to be deleted - CdmUsageEntryInfo usage_entry_second_to_be_moved = - usage_entry_info_vector_after_first_shrink[ - usage_entry_number_second_to_be_moved]; - std::vector usage_entry_info_vector_after_second_move = - usage_entry_info_vector_after_first_shrink; - usage_entry_info_vector_after_second_move[ - usage_entry_number_second_to_be_deleted] = usage_entry_second_to_be_moved; - - // The entries are then shrunk by 1 - std::vector usage_entry_info_vector_after_second_shrink = - usage_entry_info_vector_after_second_move; - usage_entry_info_vector_after_second_shrink.resize( - usage_entry_info_vector_after_second_shrink.size() - 1); - - // usage entry info after third move - uint32_t usage_entry_number_third_to_be_deleted = 2; - uint32_t usage_entry_number_third_to_be_moved = - usage_entry_info_vector_after_second_shrink.size() - 1; - - // The last entry is moved to the third entry to be deleted - CdmUsageEntryInfo usage_entry_third_to_be_moved = - usage_entry_info_vector_after_second_shrink[ - usage_entry_number_third_to_be_moved]; - std::vector usage_entry_info_vector_after_third_move = - usage_entry_info_vector_after_second_shrink; - usage_entry_info_vector_after_third_move[ - usage_entry_number_third_to_be_deleted] = usage_entry_third_to_be_moved; - - // The entries are then shrunk by 1 - std::vector usage_entry_info_vector_after_third_shrink = - usage_entry_info_vector_after_third_move; - usage_entry_info_vector_after_third_shrink.resize( - usage_entry_info_vector_after_third_shrink.size() - 1); - - // Expected results after the third failure - std::vector expect_usage_entry_info_vector = - usage_entry_info_vector_after_third_shrink; - - // Expectations for AddEntry EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull())) - .Times(3) + .Times(4) .WillRepeatedly(Return(INSUFFICIENT_CRYPTO_RESOURCES_3)); - // Expectations for StoreEntry (DeleteEntry->MoveEntry) - EXPECT_CALL(*device_files_, - DeleteUsageInfo(usage_entry_first_to_be_moved.usage_info_file_name, - kProviderSessionToken)) - .WillOnce(Return(true)); - EXPECT_CALL(*device_files_, - DeleteUsageInfo(usage_entry_third_to_be_moved.usage_info_file_name, - kProviderSessionToken)) - .WillOnce(Return(true)); - EXPECT_CALL(*device_files_, - StoreUsageInfo(kProviderSessionToken, kKeyRequest, kKeyResponse, - usage_entry_first_to_be_moved.usage_info_file_name, - usage_entry_first_to_be_moved.key_set_id, - kAnotherUsageEntry, - usage_entry_number_first_to_be_deleted)) - .WillOnce(Return(true)); - EXPECT_CALL(*device_files_, - StoreUsageInfo(kProviderSessionToken, kKeyRequest, kKeyResponse, - usage_entry_third_to_be_moved.usage_info_file_name, - usage_entry_third_to_be_moved.key_set_id, - kOneMoreUsageEntry, - usage_entry_number_third_to_be_deleted)) - .WillOnce(Return(true)); - - EXPECT_TRUE(device_files_->StoreLicense( - usage_entry_second_to_be_moved.key_set_id, - kActiveLicenseState, kPsshData, kKeyRequest, kKeyResponse, - kKeyRenewalRequest, kKeyRenewalResponse, kReleaseServerUrl, - kPlaybackStartTime, kPlaybackStartTime + kPlaybackDuration, - kGracePeriodEndTime, kEmptyAppParameters, kYetAnotherUsageEntry, - usage_entry_number_second_to_be_moved)); - - DeviceFiles::LicenseState license_state = DeviceFiles::kLicenseStateUnknown; - CdmInitData pssh_data; - CdmKeyMessage key_request; - CdmKeyResponse key_response; - CdmKeyMessage key_renewal_request; - CdmKeyResponse key_renewal_response; - std::string release_server_url; - int64_t playback_start_time; - int64_t last_playback_time; - int64_t grace_period_end_time; - CdmAppParameterMap app_parameters; - CdmUsageEntry usage_entry; - uint32_t usage_entry_number = ~0; - - EXPECT_TRUE(device_files_->RetrieveLicense( - usage_entry_second_to_be_moved.key_set_id, &license_state, &pssh_data, - &key_request, &key_response, &key_renewal_request, &key_renewal_response, - &release_server_url, &playback_start_time, &last_playback_time, - &grace_period_end_time, &app_parameters, &usage_entry, - &usage_entry_number)); - EXPECT_EQ(kActiveLicenseState, license_state); - EXPECT_EQ(kPsshData, pssh_data); - EXPECT_EQ(kKeyRequest, key_request); - EXPECT_EQ(kKeyResponse, key_response); - EXPECT_EQ(kKeyRenewalRequest, key_renewal_request); - EXPECT_EQ(kKeyRenewalResponse, key_renewal_response); - EXPECT_EQ(kReleaseServerUrl, release_server_url); - EXPECT_EQ(kPlaybackStartTime, playback_start_time); - EXPECT_EQ(kPlaybackStartTime + kPlaybackDuration, last_playback_time); - EXPECT_EQ(kGracePeriodEndTime, grace_period_end_time); - EXPECT_EQ(kEmptyAppParameters.size(), app_parameters.size()); - EXPECT_EQ(kYetAnotherUsageEntry, usage_entry); - EXPECT_EQ(usage_entry_number_second_to_be_moved, usage_entry_number); - - // Expectations for Shrink (DeleteEntry) - EXPECT_CALL( - *crypto_session_, - ShrinkUsageTableHeader( - usage_entry_info_vector_after_first_shrink.size(), NotNull())) - .WillOnce( - DoAll(SetArgPointee<1>(kAnotherUsageTableHeader), Return(NO_ERROR))); - EXPECT_CALL( - *crypto_session_, - ShrinkUsageTableHeader( - usage_entry_info_vector_after_second_shrink.size(), NotNull())) - .WillOnce( - DoAll(SetArgPointee<1>(kYetAnotherUsageTableHeader), - Return(NO_ERROR))); - EXPECT_CALL( - *crypto_session_, - ShrinkUsageTableHeader( - usage_entry_info_vector_after_third_shrink.size(), NotNull())) - .WillOnce( - DoAll(SetArgPointee<1>(kOneMoreUsageTableHeader), - Return(NO_ERROR))); - EXPECT_CALL(*device_files_, - StoreUsageTableInfo( - kAnotherUsageTableHeader, - ElementsAreArray(usage_entry_info_vector_after_first_shrink))) - .WillOnce(Return(true)); - EXPECT_CALL(*device_files_, - StoreUsageTableInfo( - kYetAnotherUsageTableHeader, - ElementsAreArray( - usage_entry_info_vector_after_second_shrink))) - .WillOnce(Return(true)); - EXPECT_CALL(*device_files_, - StoreUsageTableInfo( - kOneMoreUsageTableHeader, - ElementsAreArray( - usage_entry_info_vector_after_third_shrink))) - .WillOnce(Return(true)); - - // Expectations for MoveEntry (DeleteEntry) - EXPECT_CALL(*crypto_session_, Open(kLevelDefault)) - .Times(6) - .WillRepeatedly(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, - LoadUsageEntry(usage_entry_number_first_to_be_moved, - kUsageEntry)) - .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, - LoadUsageEntry(usage_entry_number_second_to_be_moved, - kYetAnotherUsageEntry)) - .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, - LoadUsageEntry(usage_entry_number_third_to_be_moved, - kOneMoreUsageEntry)) - .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, - MoveUsageEntry(usage_entry_number_first_to_be_deleted)) - .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, - MoveUsageEntry(usage_entry_number_second_to_be_deleted)) - .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, - MoveUsageEntry(usage_entry_number_third_to_be_deleted)) - .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull())) - .WillOnce(DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), - SetArgPointee<1>(kAnotherUsageEntry), Return(NO_ERROR))) - .WillOnce(DoAll(SetArgPointee<0>(kYetAnotherUsageTableHeader), - SetArgPointee<1>(kYetAnotherUsageEntry), - Return(NO_ERROR))) - .WillOnce(DoAll(SetArgPointee<0>(kOneMoreUsageTableHeader), - SetArgPointee<1>(kOneMoreUsageEntry), - Return(NO_ERROR))); - EXPECT_CALL(*device_files_, - StoreUsageTableInfo( - kAnotherUsageTableHeader, - ElementsAreArray(usage_entry_info_vector_after_first_move))) - .WillOnce(Return(true)); - EXPECT_CALL(*device_files_, - StoreUsageTableInfo( - kYetAnotherUsageTableHeader, - ElementsAreArray(usage_entry_info_vector_after_second_move))) - .WillOnce(Return(true)); - EXPECT_CALL(*device_files_, - StoreUsageTableInfo( - kOneMoreUsageTableHeader, - ElementsAreArray(usage_entry_info_vector_after_third_move))) - .WillOnce(Return(true)); - - // Expectations for GetEntry (DeleteEntry) - EXPECT_CALL(*device_files_, - RetrieveUsageInfoByKeySetId( - usage_entry_first_to_be_moved.usage_info_file_name, - usage_entry_first_to_be_moved.key_set_id, NotNull(), NotNull(), - NotNull(), NotNull(), NotNull())) - .Times(2) - .WillRepeatedly(DoAll( - SetArgPointee<2>(kProviderSessionToken), - SetArgPointee<3>(kKeyRequest), SetArgPointee<4>(kKeyResponse), - SetArgPointee<5>(kUsageEntry), - SetArgPointee<6>(usage_entry_number_first_to_be_moved), - Return(true))); - EXPECT_CALL(*device_files_, - RetrieveUsageInfoByKeySetId( - usage_entry_third_to_be_moved.usage_info_file_name, - usage_entry_third_to_be_moved.key_set_id, NotNull(), NotNull(), - NotNull(), NotNull(), NotNull())) - .Times(2) - .WillRepeatedly(DoAll( - SetArgPointee<2>(kProviderSessionToken), - SetArgPointee<3>(kKeyRequest), SetArgPointee<4>(kKeyResponse), - SetArgPointee<5>(kOneMoreUsageEntry), - SetArgPointee<6>(usage_entry_number_third_to_be_moved), - Return(true))); - + // Now invoke the method under test + uint32_t usage_entry_number; EXPECT_EQ(INSUFFICIENT_CRYPTO_RESOURCES_3, - usage_table_header_->AddEntry( + mock_usage_table_header->AddEntry( crypto_session_, - kUsageEntryInfoOfflineLicense3.storage_type == kStorageLicense, - kUsageEntryInfoOfflineLicense3.key_set_id, - kUsageEntryInfoOfflineLicense3.usage_info_file_name, + kUsageEntryInfoOfflineLicense6.storage_type == kStorageLicense, + kUsageEntryInfoOfflineLicense6.key_set_id, + kUsageEntryInfoOfflineLicense6.usage_info_file_name, &usage_entry_number)); + + // Verify deleted usage entry number and entries + 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, usage_entry_number_second_to_be_deleted); + EXPECT_LE(usage_entry_number_second_to_be_deleted, + usage_entry_info_vector_at_start.size() - 1); + EXPECT_LE(0u, usage_entry_number_third_to_be_deleted); + EXPECT_LE(usage_entry_number_third_to_be_deleted, + usage_entry_info_vector_at_start.size() - 1); } TEST_F(UsageTableHeaderTest, LoadEntry_InvalidEntryNumber) { @@ -1309,565 +970,94 @@ TEST_F(UsageTableHeaderTest, UpdateEntry) { TEST_F(UsageTableHeaderTest, LoadEntry_LoadUsageEntryFailsOnce_SucceedsSecondTime) { + // Initialize and setup + MockUsageTableHeader* mock_usage_table_header = SetUpMock(); Init(kSecurityLevelL1, kUsageTableHeader, k10UsageEntryInfoVector); - std::vector usage_entry_info_vector_at_start = - k10UsageEntryInfoVector; - uint32_t usage_entry_number_to_load = 5; + uint32_t usage_entry_number_to_load = rand() / + (RAND_MAX / k10UsageEntryInfoVector.size() + 1); + CdmUsageEntry usage_entry_to_load = kUsageEntry; - uint32_t usage_entry_number_to_be_deleted = 0; - CdmUsageEntryInfo usage_entry_to_be_deleted = - usage_entry_info_vector_at_start[usage_entry_number_to_be_deleted]; - uint32_t usage_entry_number_to_be_moved = - usage_entry_info_vector_at_start.size() - 1; - CdmUsageEntryInfo usage_entry_to_be_moved = - usage_entry_info_vector_at_start[usage_entry_number_to_be_moved]; + // Setup expectations + EXPECT_CALL(*mock_usage_table_header, + DeleteEntry(_, device_files_, NotNull())) + .Times(AtMost(1)) + .WillRepeatedly( + DoAll(Invoke(this, &UsageTableHeaderTest::DeleteEntry), + Return(NO_ERROR))); - // The last entry is moved to the entry to be deleted (0) - std::vector usage_entry_info_vector_after_move = - usage_entry_info_vector_at_start; - usage_entry_info_vector_after_move[usage_entry_number_to_be_deleted] = - usage_entry_info_vector_at_start[usage_entry_number_to_be_moved]; - - // The entries are then shrunk by 1 - std::vector shrunk_usage_entry_info_vector = - usage_entry_info_vector_after_move; - shrunk_usage_entry_info_vector.resize( - shrunk_usage_entry_info_vector.size() - 1); - - // Expectations for LoadEntry - std::vector expect_usage_entry_info_vector = - shrunk_usage_entry_info_vector; - - EXPECT_CALL(*crypto_session_, LoadUsageEntry(usage_entry_number_to_load, - kAndAnotherUsageEntry)) + EXPECT_CALL(*crypto_session_, + LoadUsageEntry(usage_entry_number_to_load, usage_entry_to_load)) .WillOnce(Return(INSUFFICIENT_CRYPTO_RESOURCES_3)) .WillOnce(Return(NO_ERROR)); - // Expectations for StoreEntry (DeleteEntry->MoveEntry) - EXPECT_CALL(*device_files_, - DeleteUsageInfo(usage_entry_to_be_moved.usage_info_file_name, - kProviderSessionToken)) - .WillOnce(Return(true)); - EXPECT_CALL(*device_files_, - StoreUsageInfo(kProviderSessionToken, kKeyRequest, kKeyResponse, - usage_entry_to_be_moved.usage_info_file_name, - usage_entry_to_be_moved.key_set_id, kAnotherUsageEntry, - usage_entry_number_to_be_deleted)) - .WillOnce(Return(true)); - - // Expectations for Shrink (DeleteEntry) - EXPECT_CALL( - *crypto_session_, - ShrinkUsageTableHeader(shrunk_usage_entry_info_vector.size(), NotNull())) - .WillOnce( - DoAll(SetArgPointee<1>(kAnotherUsageTableHeader), Return(NO_ERROR))); - EXPECT_CALL(*device_files_, - StoreUsageTableInfo( - kAnotherUsageTableHeader, - ElementsAreArray(shrunk_usage_entry_info_vector))) - .WillOnce(Return(true)); - - // Expectations for MoveEntry (DeleteEntry) - EXPECT_CALL(*crypto_session_, Open(kLevelDefault)) - .Times(2) - .WillRepeatedly(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, - LoadUsageEntry(usage_entry_number_to_be_moved, - kUsageEntry)) - .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, - MoveUsageEntry(usage_entry_number_to_be_deleted)) - .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull())) - .WillOnce(DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), - SetArgPointee<1>(kAnotherUsageEntry), Return(NO_ERROR))); - EXPECT_CALL(*device_files_, - StoreUsageTableInfo( - kAnotherUsageTableHeader, - ElementsAreArray(usage_entry_info_vector_after_move))) - .WillOnce(Return(true)); - - // Expectations for GetEntry (DeleteEntry) - EXPECT_CALL(*device_files_, - RetrieveUsageInfoByKeySetId( - usage_entry_to_be_moved.usage_info_file_name, - usage_entry_to_be_moved.key_set_id, NotNull(), NotNull(), - NotNull(), NotNull(), NotNull())) - .Times(2) - .WillRepeatedly(DoAll( - SetArgPointee<2>(kProviderSessionToken), - SetArgPointee<3>(kKeyRequest), SetArgPointee<4>(kKeyResponse), - SetArgPointee<5>(kUsageEntry), - SetArgPointee<6>(usage_entry_number_to_be_moved), Return(true))); - + // Now invoke the method under test EXPECT_EQ(NO_ERROR, - usage_table_header_->LoadEntry( + mock_usage_table_header->LoadEntry( crypto_session_, - kAndAnotherUsageEntry, + usage_entry_to_load, usage_entry_number_to_load)); } TEST_F(UsageTableHeaderTest, LoadEntry_LoadUsageEntryFailsTwice_SucceedsThirdTime) { + // Initialize and setup + MockUsageTableHeader* mock_usage_table_header = SetUpMock(); Init(kSecurityLevelL1, kUsageTableHeader, k10UsageEntryInfoVector); - // Initial usage entry info - std::vector usage_entry_info_vector_at_start = - k10UsageEntryInfoVector; + uint32_t usage_entry_number_to_load = rand() / + (RAND_MAX / k10UsageEntryInfoVector.size() + 1); + CdmUsageEntry usage_entry_to_load = kUsageEntry; - uint32_t usage_entry_number_to_load = 5; - - // usage entry info after first move - uint32_t usage_entry_number_first_to_be_deleted = 0; - uint32_t usage_entry_number_first_to_be_moved = - usage_entry_info_vector_at_start.size() - 1; - - // The last entry is moved to the first entry to be deleted - CdmUsageEntryInfo usage_entry_first_to_be_moved = - usage_entry_info_vector_at_start[usage_entry_number_first_to_be_moved]; - std::vector usage_entry_info_vector_after_first_move = - usage_entry_info_vector_at_start; - usage_entry_info_vector_after_first_move[ - usage_entry_number_first_to_be_deleted] = - usage_entry_first_to_be_moved; - - // The entries are then shrunk by 1 - std::vector usage_entry_info_vector_after_first_shrink = - usage_entry_info_vector_after_first_move; - usage_entry_info_vector_after_first_shrink.resize( - usage_entry_info_vector_after_first_shrink.size() - 1); - - // usage entry info after second move - uint32_t usage_entry_number_second_to_be_deleted = 1; - uint32_t usage_entry_number_second_to_be_moved = - usage_entry_info_vector_after_first_shrink.size() - 1; - - // The last entry is moved to the second entry to be deleted - CdmUsageEntryInfo usage_entry_second_to_be_moved = - usage_entry_info_vector_after_first_shrink[ - usage_entry_number_second_to_be_moved]; - std::vector usage_entry_info_vector_after_second_move = - usage_entry_info_vector_after_first_shrink; - usage_entry_info_vector_after_second_move[ - usage_entry_number_second_to_be_deleted] = usage_entry_second_to_be_moved; - - // The entries are then shrunk by 1 - std::vector usage_entry_info_vector_after_second_shrink = - usage_entry_info_vector_after_second_move; - usage_entry_info_vector_after_second_shrink.resize( - usage_entry_info_vector_after_second_shrink.size() - 1); - - // Expectations for LoadEntry - std::vector expect_usage_entry_info_vector = - usage_entry_info_vector_after_second_shrink; - - EXPECT_CALL(*crypto_session_, LoadUsageEntry(usage_entry_number_to_load, - kAndAnotherUsageEntry)) - .WillOnce(Return(INSUFFICIENT_CRYPTO_RESOURCES_3)) - .WillOnce(Return(INSUFFICIENT_CRYPTO_RESOURCES_3)) - .WillOnce(Return(NO_ERROR)); - - // Expectations for StoreEntry (DeleteEntry->MoveEntry) - EXPECT_CALL(*device_files_, - DeleteUsageInfo(usage_entry_first_to_be_moved.usage_info_file_name, - kProviderSessionToken)) - .WillOnce(Return(true)); - EXPECT_CALL(*device_files_, - StoreUsageInfo(kProviderSessionToken, kKeyRequest, kKeyResponse, - usage_entry_first_to_be_moved.usage_info_file_name, - usage_entry_first_to_be_moved.key_set_id, - kAnotherUsageEntry, - usage_entry_number_first_to_be_deleted)) - .WillOnce(Return(true)); - - EXPECT_TRUE(device_files_->StoreLicense( - usage_entry_second_to_be_moved.key_set_id, - kActiveLicenseState, kPsshData, kKeyRequest, kKeyResponse, - kKeyRenewalRequest, kKeyRenewalResponse, kReleaseServerUrl, - kPlaybackStartTime, kPlaybackStartTime + kPlaybackDuration, - kGracePeriodEndTime, kEmptyAppParameters, kYetAnotherUsageEntry, - usage_entry_number_second_to_be_moved)); - - DeviceFiles::LicenseState license_state = DeviceFiles::kLicenseStateUnknown; - CdmInitData pssh_data; - CdmKeyMessage key_request; - CdmKeyResponse key_response; - CdmKeyMessage key_renewal_request; - CdmKeyResponse key_renewal_response; - std::string release_server_url; - int64_t playback_start_time; - int64_t last_playback_time; - int64_t grace_period_end_time; - CdmAppParameterMap app_parameters; - CdmUsageEntry usage_entry; - uint32_t usage_entry_number = ~0; - - EXPECT_TRUE(device_files_->RetrieveLicense( - usage_entry_second_to_be_moved.key_set_id, &license_state, &pssh_data, - &key_request, &key_response, &key_renewal_request, &key_renewal_response, - &release_server_url, &playback_start_time, &last_playback_time, - &grace_period_end_time, &app_parameters, &usage_entry, - &usage_entry_number)); - EXPECT_EQ(kActiveLicenseState, license_state); - EXPECT_EQ(kPsshData, pssh_data); - EXPECT_EQ(kKeyRequest, key_request); - EXPECT_EQ(kKeyResponse, key_response); - EXPECT_EQ(kKeyRenewalRequest, key_renewal_request); - EXPECT_EQ(kKeyRenewalResponse, key_renewal_response); - EXPECT_EQ(kReleaseServerUrl, release_server_url); - EXPECT_EQ(kPlaybackStartTime, playback_start_time); - EXPECT_EQ(kPlaybackStartTime + kPlaybackDuration, last_playback_time); - EXPECT_EQ(kGracePeriodEndTime, grace_period_end_time); - EXPECT_EQ(kEmptyAppParameters.size(), app_parameters.size()); - EXPECT_EQ(kYetAnotherUsageEntry, usage_entry); - EXPECT_EQ(usage_entry_number_second_to_be_moved, usage_entry_number); - - // Expectations for Shrink (DeleteEntry) - EXPECT_CALL( - *crypto_session_, - ShrinkUsageTableHeader( - usage_entry_info_vector_after_first_shrink.size(), NotNull())) - .WillOnce( - DoAll(SetArgPointee<1>(kAnotherUsageTableHeader), Return(NO_ERROR))); - EXPECT_CALL( - *crypto_session_, - ShrinkUsageTableHeader( - usage_entry_info_vector_after_second_shrink.size(), NotNull())) - .WillOnce( - DoAll(SetArgPointee<1>(kYetAnotherUsageTableHeader), + // Setup expectations + EXPECT_CALL(*mock_usage_table_header, + DeleteEntry(_, device_files_, NotNull())) + .Times(AtMost(2)) + .WillRepeatedly( + DoAll(Invoke(this, &UsageTableHeaderTest::DeleteEntry), Return(NO_ERROR))); - EXPECT_CALL(*device_files_, - StoreUsageTableInfo( - kAnotherUsageTableHeader, - ElementsAreArray(usage_entry_info_vector_after_first_shrink))) - .WillOnce(Return(true)); - EXPECT_CALL(*device_files_, - StoreUsageTableInfo( - kYetAnotherUsageTableHeader, - ElementsAreArray( - usage_entry_info_vector_after_second_shrink))) - .WillOnce(Return(true)); - // Expectations for MoveEntry (DeleteEntry) - EXPECT_CALL(*crypto_session_, Open(kLevelDefault)) - .Times(4) - .WillRepeatedly(Return(NO_ERROR)); EXPECT_CALL(*crypto_session_, - LoadUsageEntry(usage_entry_number_first_to_be_moved, - kUsageEntry)) + LoadUsageEntry(usage_entry_number_to_load, usage_entry_to_load)) + .WillOnce(Return(INSUFFICIENT_CRYPTO_RESOURCES_3)) + .WillOnce(Return(INSUFFICIENT_CRYPTO_RESOURCES_3)) .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, - LoadUsageEntry(usage_entry_number_second_to_be_moved, - kYetAnotherUsageEntry)) - .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, - MoveUsageEntry(usage_entry_number_first_to_be_deleted)) - .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, - MoveUsageEntry(usage_entry_number_second_to_be_deleted)) - .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull())) - .WillOnce(DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), - SetArgPointee<1>(kAnotherUsageEntry), Return(NO_ERROR))) - .WillOnce(DoAll(SetArgPointee<0>(kYetAnotherUsageTableHeader), - SetArgPointee<1>(kYetAnotherUsageEntry), - Return(NO_ERROR))); - EXPECT_CALL(*device_files_, - StoreUsageTableInfo( - kAnotherUsageTableHeader, - ElementsAreArray(usage_entry_info_vector_after_first_move))) - .WillOnce(Return(true)); - EXPECT_CALL(*device_files_, - StoreUsageTableInfo( - kYetAnotherUsageTableHeader, - ElementsAreArray(usage_entry_info_vector_after_second_move))) - .WillOnce(Return(true)); - - // Expectations for GetEntry (DeleteEntry) - EXPECT_CALL(*device_files_, - RetrieveUsageInfoByKeySetId( - usage_entry_first_to_be_moved.usage_info_file_name, - usage_entry_first_to_be_moved.key_set_id, NotNull(), NotNull(), - NotNull(), NotNull(), NotNull())) - .Times(2) - .WillRepeatedly(DoAll( - SetArgPointee<2>(kProviderSessionToken), - SetArgPointee<3>(kKeyRequest), SetArgPointee<4>(kKeyResponse), - SetArgPointee<5>(kUsageEntry), - SetArgPointee<6>(usage_entry_number_first_to_be_moved), - Return(true))); + // Now invoke the method under test EXPECT_EQ(NO_ERROR, - usage_table_header_->LoadEntry( + mock_usage_table_header->LoadEntry( crypto_session_, - kAndAnotherUsageEntry, + usage_entry_to_load, usage_entry_number_to_load)); } TEST_F(UsageTableHeaderTest, LoadEntry_LoadUsageEntryFailsThrice) { + // Initialize and setup + MockUsageTableHeader* mock_usage_table_header = SetUpMock(); Init(kSecurityLevelL1, kUsageTableHeader, k10UsageEntryInfoVector); - // Initial usage entry info - std::vector usage_entry_info_vector_at_start = - k10UsageEntryInfoVector; + uint32_t usage_entry_number_to_load = rand() / + (RAND_MAX / k10UsageEntryInfoVector.size() + 1); + CdmUsageEntry usage_entry_to_load = kUsageEntry; - uint32_t usage_entry_number_to_load = 5; + // Setup expectations + EXPECT_CALL(*mock_usage_table_header, + DeleteEntry(_, device_files_, NotNull())) + .Times(AtMost(3)) + .WillRepeatedly( + DoAll(Invoke(this, &UsageTableHeaderTest::DeleteEntry), + Return(NO_ERROR))); - // usage entry info after first move - uint32_t usage_entry_number_first_to_be_deleted = 0; - uint32_t usage_entry_number_first_to_be_moved = - usage_entry_info_vector_at_start.size() - 1; - - // The last entry is moved to the first entry to be deleted - CdmUsageEntryInfo usage_entry_first_to_be_moved = - usage_entry_info_vector_at_start[usage_entry_number_first_to_be_moved]; - std::vector usage_entry_info_vector_after_first_move = - usage_entry_info_vector_at_start; - usage_entry_info_vector_after_first_move[ - usage_entry_number_first_to_be_deleted] = - usage_entry_first_to_be_moved; - - // The entries are then shrunk by 1 - std::vector usage_entry_info_vector_after_first_shrink = - usage_entry_info_vector_after_first_move; - usage_entry_info_vector_after_first_shrink.resize( - usage_entry_info_vector_after_first_shrink.size() - 1); - - // usage entry info after second move - uint32_t usage_entry_number_second_to_be_deleted = 1; - uint32_t usage_entry_number_second_to_be_moved = - usage_entry_info_vector_after_first_shrink.size() - 1; - - // The last entry is moved to the second entry to be deleted - CdmUsageEntryInfo usage_entry_second_to_be_moved = - usage_entry_info_vector_after_first_shrink[ - usage_entry_number_second_to_be_moved]; - std::vector usage_entry_info_vector_after_second_move = - usage_entry_info_vector_after_first_shrink; - usage_entry_info_vector_after_second_move[ - usage_entry_number_second_to_be_deleted] = usage_entry_second_to_be_moved; - - // The entries are then shrunk by 1 - std::vector usage_entry_info_vector_after_second_shrink = - usage_entry_info_vector_after_second_move; - usage_entry_info_vector_after_second_shrink.resize( - usage_entry_info_vector_after_second_shrink.size() - 1); - - // usage entry info after third move - uint32_t usage_entry_number_third_to_be_deleted = 2; - uint32_t usage_entry_number_third_to_be_moved = - usage_entry_info_vector_after_second_shrink.size() - 1; - - // The last entry is moved to the third entry to be deleted - CdmUsageEntryInfo usage_entry_third_to_be_moved = - usage_entry_info_vector_after_second_shrink[ - usage_entry_number_third_to_be_moved]; - std::vector usage_entry_info_vector_after_third_move = - usage_entry_info_vector_after_second_shrink; - usage_entry_info_vector_after_third_move[ - usage_entry_number_third_to_be_deleted] = usage_entry_third_to_be_moved; - - // The entries are then shrunk by 1 - std::vector usage_entry_info_vector_after_third_shrink = - usage_entry_info_vector_after_third_move; - usage_entry_info_vector_after_third_shrink.resize( - usage_entry_info_vector_after_third_shrink.size() - 1); - - // Expectations for LoadEntry - std::vector expect_usage_entry_info_vector = - usage_entry_info_vector_after_third_shrink; - - EXPECT_CALL(*crypto_session_, LoadUsageEntry(usage_entry_number_to_load, - kAndAnotherUsageEntry)) - .Times(3) + EXPECT_CALL(*crypto_session_, + LoadUsageEntry(usage_entry_number_to_load, usage_entry_to_load)) + .Times(AtMost(4)) .WillRepeatedly(Return(INSUFFICIENT_CRYPTO_RESOURCES_3)); - // Expectations for StoreEntry (DeleteEntry->MoveEntry) - EXPECT_CALL(*device_files_, - DeleteUsageInfo(usage_entry_first_to_be_moved.usage_info_file_name, - kProviderSessionToken)) - .WillOnce(Return(true)); - EXPECT_CALL(*device_files_, - DeleteUsageInfo(usage_entry_third_to_be_moved.usage_info_file_name, - kProviderSessionToken)) - .WillOnce(Return(true)); - EXPECT_CALL(*device_files_, - StoreUsageInfo(kProviderSessionToken, kKeyRequest, kKeyResponse, - usage_entry_first_to_be_moved.usage_info_file_name, - usage_entry_first_to_be_moved.key_set_id, - kAnotherUsageEntry, - usage_entry_number_first_to_be_deleted)) - .WillOnce(Return(true)); - EXPECT_CALL(*device_files_, - StoreUsageInfo(kProviderSessionToken, kKeyRequest, kKeyResponse, - usage_entry_third_to_be_moved.usage_info_file_name, - usage_entry_third_to_be_moved.key_set_id, - kOneMoreUsageEntry, - usage_entry_number_third_to_be_deleted)) - .WillOnce(Return(true)); - - EXPECT_TRUE(device_files_->StoreLicense( - usage_entry_second_to_be_moved.key_set_id, - kActiveLicenseState, kPsshData, kKeyRequest, kKeyResponse, - kKeyRenewalRequest, kKeyRenewalResponse, kReleaseServerUrl, - kPlaybackStartTime, kPlaybackStartTime + kPlaybackDuration, - kGracePeriodEndTime, kEmptyAppParameters, kYetAnotherUsageEntry, - usage_entry_number_second_to_be_moved)); - - DeviceFiles::LicenseState license_state = DeviceFiles::kLicenseStateUnknown; - CdmInitData pssh_data; - CdmKeyMessage key_request; - CdmKeyResponse key_response; - CdmKeyMessage key_renewal_request; - CdmKeyResponse key_renewal_response; - std::string release_server_url; - int64_t playback_start_time; - int64_t last_playback_time; - int64_t grace_period_end_time; - CdmAppParameterMap app_parameters; - CdmUsageEntry usage_entry; - uint32_t usage_entry_number = ~0; - - EXPECT_TRUE(device_files_->RetrieveLicense( - usage_entry_second_to_be_moved.key_set_id, &license_state, &pssh_data, - &key_request, &key_response, &key_renewal_request, &key_renewal_response, - &release_server_url, &playback_start_time, &last_playback_time, - &grace_period_end_time, &app_parameters, &usage_entry, - &usage_entry_number)); - EXPECT_EQ(kActiveLicenseState, license_state); - EXPECT_EQ(kPsshData, pssh_data); - EXPECT_EQ(kKeyRequest, key_request); - EXPECT_EQ(kKeyResponse, key_response); - EXPECT_EQ(kKeyRenewalRequest, key_renewal_request); - EXPECT_EQ(kKeyRenewalResponse, key_renewal_response); - EXPECT_EQ(kReleaseServerUrl, release_server_url); - EXPECT_EQ(kPlaybackStartTime, playback_start_time); - EXPECT_EQ(kPlaybackStartTime + kPlaybackDuration, last_playback_time); - EXPECT_EQ(kGracePeriodEndTime, grace_period_end_time); - EXPECT_EQ(kEmptyAppParameters.size(), app_parameters.size()); - EXPECT_EQ(kYetAnotherUsageEntry, usage_entry); - EXPECT_EQ(usage_entry_number_second_to_be_moved, usage_entry_number); - - // Expectations for Shrink (DeleteEntry) - EXPECT_CALL( - *crypto_session_, - ShrinkUsageTableHeader( - usage_entry_info_vector_after_first_shrink.size(), NotNull())) - .WillOnce( - DoAll(SetArgPointee<1>(kAnotherUsageTableHeader), Return(NO_ERROR))); - EXPECT_CALL( - *crypto_session_, - ShrinkUsageTableHeader( - usage_entry_info_vector_after_second_shrink.size(), NotNull())) - .WillOnce( - DoAll(SetArgPointee<1>(kYetAnotherUsageTableHeader), - Return(NO_ERROR))); - EXPECT_CALL( - *crypto_session_, - ShrinkUsageTableHeader( - usage_entry_info_vector_after_third_shrink.size(), NotNull())) - .WillOnce( - DoAll(SetArgPointee<1>(kOneMoreUsageTableHeader), - Return(NO_ERROR))); - EXPECT_CALL(*device_files_, - StoreUsageTableInfo( - kAnotherUsageTableHeader, - ElementsAreArray(usage_entry_info_vector_after_first_shrink))) - .WillOnce(Return(true)); - EXPECT_CALL(*device_files_, - StoreUsageTableInfo( - kYetAnotherUsageTableHeader, - ElementsAreArray( - usage_entry_info_vector_after_second_shrink))) - .WillOnce(Return(true)); - EXPECT_CALL(*device_files_, - StoreUsageTableInfo( - kOneMoreUsageTableHeader, - ElementsAreArray( - usage_entry_info_vector_after_third_shrink))) - .WillOnce(Return(true)); - - // Expectations for MoveEntry (DeleteEntry) - EXPECT_CALL(*crypto_session_, Open(kLevelDefault)) - .Times(6) - .WillRepeatedly(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, - LoadUsageEntry(usage_entry_number_first_to_be_moved, - kUsageEntry)) - .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, - LoadUsageEntry(usage_entry_number_second_to_be_moved, - kYetAnotherUsageEntry)) - .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, - LoadUsageEntry(usage_entry_number_third_to_be_moved, - kOneMoreUsageEntry)) - .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, - MoveUsageEntry(usage_entry_number_first_to_be_deleted)) - .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, - MoveUsageEntry(usage_entry_number_second_to_be_deleted)) - .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, - MoveUsageEntry(usage_entry_number_third_to_be_deleted)) - .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull())) - .WillOnce(DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), - SetArgPointee<1>(kAnotherUsageEntry), Return(NO_ERROR))) - .WillOnce(DoAll(SetArgPointee<0>(kYetAnotherUsageTableHeader), - SetArgPointee<1>(kYetAnotherUsageEntry), - Return(NO_ERROR))) - .WillOnce(DoAll(SetArgPointee<0>(kOneMoreUsageTableHeader), - SetArgPointee<1>(kOneMoreUsageEntry), - Return(NO_ERROR))); - EXPECT_CALL(*device_files_, - StoreUsageTableInfo( - kAnotherUsageTableHeader, - ElementsAreArray(usage_entry_info_vector_after_first_move))) - .WillOnce(Return(true)); - EXPECT_CALL(*device_files_, - StoreUsageTableInfo( - kYetAnotherUsageTableHeader, - ElementsAreArray(usage_entry_info_vector_after_second_move))) - .WillOnce(Return(true)); - EXPECT_CALL(*device_files_, - StoreUsageTableInfo( - kOneMoreUsageTableHeader, - ElementsAreArray(usage_entry_info_vector_after_third_move))) - .WillOnce(Return(true)); - - // Expectations for GetEntry (DeleteEntry) - EXPECT_CALL(*device_files_, - RetrieveUsageInfoByKeySetId( - usage_entry_first_to_be_moved.usage_info_file_name, - usage_entry_first_to_be_moved.key_set_id, NotNull(), NotNull(), - NotNull(), NotNull(), NotNull())) - .Times(2) - .WillRepeatedly(DoAll( - SetArgPointee<2>(kProviderSessionToken), - SetArgPointee<3>(kKeyRequest), SetArgPointee<4>(kKeyResponse), - SetArgPointee<5>(kUsageEntry), - SetArgPointee<6>(usage_entry_number_first_to_be_moved), - Return(true))); - EXPECT_CALL(*device_files_, - RetrieveUsageInfoByKeySetId( - usage_entry_third_to_be_moved.usage_info_file_name, - usage_entry_third_to_be_moved.key_set_id, NotNull(), NotNull(), - NotNull(), NotNull(), NotNull())) - .Times(2) - .WillRepeatedly(DoAll( - SetArgPointee<2>(kProviderSessionToken), - SetArgPointee<3>(kKeyRequest), SetArgPointee<4>(kKeyResponse), - SetArgPointee<5>(kOneMoreUsageEntry), - SetArgPointee<6>(usage_entry_number_third_to_be_moved), - Return(true))); - + // Now invoke the method under test EXPECT_EQ(INSUFFICIENT_CRYPTO_RESOURCES_3, - usage_table_header_->LoadEntry( + mock_usage_table_header->LoadEntry( crypto_session_, - kAndAnotherUsageEntry, + usage_entry_to_load, usage_entry_number_to_load)); } @@ -3104,6 +2294,7 @@ TEST_F(UsageTableHeaderTest, StaleHeader) { DoAll(SetArgPointee<0>(kEmptyUsageTableHeader), Return(NO_ERROR))); 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_CALL(*device_files_, StoreUsageTableInfo(kEmptyUsageTableHeader, kEmptyUsageEntryInfoVector)) .WillOnce(Return(true)); diff --git a/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp b/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp index d2c7f1ca..3176aa06 100644 --- a/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp +++ b/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp @@ -1603,41 +1603,53 @@ TEST_F(WvCdmExtendedDurationTest, MaxUsageEntryOfflineRecoveryTest) { std::string key_id; std::string client_auth; GetOfflineConfiguration(&key_id, &client_auth); + std::vector key_set_ids; // Download large number of offline licenses. If OEMCrypto returns // OEMCrypto_ERROR_INSUFFICIENT_RESOURCES when usage table is at capacity, - // licenses will be deleted internally to make space and we might + // licenses will be deleted internally to make space and we will // not encounter an error. - CdmResponseType response = NO_ERROR; for (size_t i = 0; i < 2000; ++i) { decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL, &session_id_); - GenerateKeyRequest(key_id, kLicenseTypeOffline, &response); - if (response != KEY_MESSAGE) { - decryptor_.CloseSession(session_id_); - break; - } - VerifyKeyRequestResponse(kUatLicenseServer, client_auth, false, &response); - if (response != KEY_ADDED) { - decryptor_.CloseSession(session_id_); - break; - } - EXPECT_EQ(KEY_ADDED, response); + GenerateKeyRequest(kOfflineClip2PstInitData, kLicenseTypeOffline); + VerifyKeyRequestResponse(g_license_server, client_auth, false); + + key_set_ids.push_back(key_set_id_); + decryptor_.CloseSession(session_id_); } - // If we encountered an error, verify that on UsageTableHeader creation - // the usage entries will be deleted and that we can add new ones. - if (response != KEY_ADDED && response != KEY_MESSAGE) { - Provision(); - for (size_t i = 0; i < 10; ++i) { - decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL, - &session_id_); - GenerateKeyRequest(key_id, kLicenseTypeOffline); - VerifyKeyRequestResponse(kUatLicenseServer, client_auth, false); - decryptor_.CloseSession(session_id_); + uint32_t number_of_valid_offline_sessions = 0; + for (size_t i = 0; i < key_set_ids.size(); ++i) { + session_id_.clear(); + decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL, + &session_id_); + CdmResponseType result = decryptor_.RestoreKey(session_id_, key_set_ids[i]); + + if (result == KEY_ADDED) { + ++number_of_valid_offline_sessions; + + // Decrypt data + SubSampleInfo* data = &kEncryptedOfflineClip2SubSample; + std::vector decrypt_buffer(data->encrypt_data.size()); + CdmDecryptionParameters decryption_parameters( + &data->key_id, &data->encrypt_data.front(), + data->encrypt_data.size(), &data->iv, + data->block_offset, &decrypt_buffer[0]); + decryption_parameters.is_encrypted = data->is_encrypted; + decryption_parameters.is_secure = data->is_secure; + decryption_parameters.subsample_flags = data->subsample_flags; + EXPECT_EQ(NO_ERROR, + decryptor_.Decrypt(session_id_, data->validate_key_id, + decryption_parameters)); + + EXPECT_EQ(data->decrypt_data, decrypt_buffer); } + decryptor_.CloseSession(session_id_); } + + EXPECT_GE(number_of_valid_offline_sessions, 200u); } } // namespace wvcdm