From 9ab837c78a35ab85fc394c0ddd331646725d4123 Mon Sep 17 00:00:00 2001 From: Rahul Frias Date: Mon, 8 Mar 2021 10:22:00 -0800 Subject: [PATCH] Integration test for license duration with renewal This is a squash of several different CLs with chnages only affecting duration_use_case_test.cpp * Integration test for license duration with renewal [ Merge of http://go/wvgerrit/117263 ] Bug: 180067457 * Add test for infinite renewal [ Merge of http://go/wvgerrit/107743 ] This adds a test that verifies an infinite renewal is processed correctly. Bug: 162516965 Bug: 170355696 Bug: 169213621 Bug: 166728158 * Add more time to CdmUseCase_Streaming test [ Merge of http://go/wvgerrit/114146 and http://go/wvgerrit/114147 ] The duration tests CdmUseCase_Streaming.Case3 was flaky on the buildbot for platforms with a real clock because there was only room for 1 second of fudge at the end of playback -- i.e. the rental window ended at 35s, but the last playback was 34s. Bug: 175741647 * Set renewal server on command line for tests [ Merge of http://go/wvgerrit/110903 ] This CL adds the ability to set the renewal server on the command line, and adds some comments to the build scripts' README file to explain how to test a server rollout. Bug: 173031207 * Change duration test fudge from 1 to 2 [ Merge of http://go/wvgerrit/112143 ] Some duration tests are flakey. Let's see if this cleans them up enough. Bug: 175741647 * Correct some grammar [ Merged from http://go/wvgerrit/111824 and http://go/wvgerrit/112063 ] * Add license duration test [ Merge of http://go/wvgerrit/109143 ] This adds a license duration test that behaves the same as a rental duration test. We do not encourage content providers to do this, but it is reasonable that legacy licenses should work. Bug: 172099147 * Shorten duration tests [ Merge of http://go/wvgerrit/108664 ] This CL tweaks some of the times in the duration use case tests so that they take less time to run. These changes the CdmUseCase test time from six and half hours to 3 and a quarter. A 50% savings! Bug: 170746277 * Improve logging and edge cases in duration tests [ Merge of http://go/wvgerrit/108663 ] This cleans up some logging, and handles some edge cases on renewals when the renewal request round trip overlaps the cutoff time. Bug: 170746277 * Remove extra cutoff computations [ Merge of http://go/wvgerrit/106783 ] The duration tests originally tried to keep track of when the timer would have gone off if the test was allowed to continue. This proved impracticle, so the extra parameter has been removed. The tests still closely match the documented use cases. Bug: 169453960 * But not too lenient [ Merge of http://go/wvgerrit/107943 ] Previously, the duration tests were modified to allow playback to continue in some cases. See the documentation or code for a list of these cases. However, the tests had been modified to force playback to continue in these cases. This is not desired: in some cases, v15 devices can restrict playback as requested. This CL changes the tests so that playback restriction is allowed. In other words, we no longer force older devices to fail the test. Bug: 169255315 * Make some integration tests lenient [ Merge of http://go/wvgerrit/106843 ] This allows devices that have OEMCrypto version < v16 or do not support usage tables to continue playback for an offline license after the playback window has expired. Bug: 169582310 Test: duration_use_case_test.cpp * Add Renewal Use Case tests [ Merge of http://go/wvgerrit/105826 and http://go/wvgerrit/103784 ] This CL adds several integration tests that match the duration use cases with renewals. The test classes are designed for the core cdm, but the test cases match those found in oemcrypto/odk/test/odk_timer_test.cpp. Test: tests pass except for documented bugs. Bug: 161463952 Change-Id: Ib4775d48490cf150b89aeb2cc64e01a1428f0ab5 --- .../cdm/core/test/duration_use_case_test.cpp | 841 +++++++++++------- 1 file changed, 513 insertions(+), 328 deletions(-) diff --git a/libwvdrmengine/cdm/core/test/duration_use_case_test.cpp b/libwvdrmengine/cdm/core/test/duration_use_case_test.cpp index 53d57956..0fd4f519 100644 --- a/libwvdrmengine/cdm/core/test/duration_use_case_test.cpp +++ b/libwvdrmengine/cdm/core/test/duration_use_case_test.cpp @@ -6,6 +6,8 @@ // would, but in parallel, attempting to create as many collisions in the CDM // code as possible. +#include + #include #include #include @@ -45,7 +47,7 @@ const std::string kCencMimeType = "cenc"; // check. Similarly, when we verify that playback may continue until STOP, we // wait until STOP-kFudge and then check. License sign and load times are not // fudged because neither direction is more lenient than the other direction. -constexpr uint64_t kFudge = 1; +constexpr uint64_t kFudge = 2; // How long we allow for a full license round trip -- including time for // generating the request, sending the request to the server, processing the // request at the server, sending a response back. Since this is constant, we @@ -53,6 +55,9 @@ constexpr uint64_t kFudge = 1; // expire. This must be smaller than the renewal_recovery_duration for all of // our test cases below. constexpr uint64_t kRoundTripTime = 10; +// How long we use for a playback duration for many tests. This value should be +// short, but it should also be larger than our fudge value above. +constexpr uint64_t kPlayDuration = 4 + kFudge; // A renewal policy, whose values should match the policy on UAT and in // policies.dat with the same name. @@ -70,10 +75,13 @@ struct RenewalPolicy { uint64_t renewal_recovery_duration; }; -const RenewalPolicy kShortRenewal = {"CDM_LicenseWithRenewal_renewal", 25, 15}; -const RenewalPolicy kLongRenewal = {"CDM_LicenseWithRenewal_long_renewal", 40, - 15}; +const RenewalPolicy kShortRenewal = {"CDM_LicenseWithRenewal_renewal", 15, 10}; +const RenewalPolicy kLongRenewal = {"CDM_LicenseWithRenewal_long_renewal", 30, + 10}; const RenewalPolicy kLDLRenewal = {"CDM_LimitedDurationLicense_renewal", 0, 0}; +const RenewalPolicy kInfiniteRenewal = {"CDM_InfiniteRenewal_renewal", 0, 0}; +const RenewalPolicy kLicenseDurationWithRenewal = { + "CDM_LicenseDurationWithRenewal_renewal", 10, 0}; // Key ID in all duration tests. const KeyId kKeyId = "Duration_Key===="; @@ -156,7 +164,20 @@ class CdmDurationTest : public WvCdmTestBaseWithEngine, FetchLicense(); } - void TearDown() override { cdm_engine_.CloseSession(session_id_); } + void TearDown() override { + cdm_engine_.CloseSession(session_id_); + // Log the time used in this test suite. When this comment was written, + // these tests took over three hours. If we want to improve that, we need to + // track these times. + static uint64_t first_time = start_of_rental_clock_; + uint64_t delta = wvcdm::Clock().GetCurrentTime() - first_time; + uint64_t sec = delta % 60; + delta = delta / 60; + uint64_t min = delta % 60; + uint64_t hour = delta / 60; + LOGD("Time used in test suite so far: %" PRIu64 ":%02" PRIu64 ":%02" PRIu64, + hour, min, sec); + } // The end of the playback window. (using system clock) // This is not useful if the playback duration is 0, which means infinite. In @@ -186,7 +207,8 @@ class CdmDurationTest : public WvCdmTestBaseWithEngine, if (desired_rental_time >= rental_time) { TestSleep::Sleep(desired_rental_time - rental_time); } else { - LOGW("Test Clock skew sleeping from rental clock time %ld to %ld", + LOGW("Test Clock skew sleeping from rental clock time %" PRIu64 + " to %" PRIu64, rental_time, desired_rental_time); } cdm_engine_.OnTimerEvent(); @@ -233,13 +255,14 @@ class CdmDurationTest : public WvCdmTestBaseWithEngine, } // Append the content/policy id for the test to the URL. - std::string MakeUrl(const std::string& policy_id) { + std::string MakeUrl(const std::string& server_url, + const std::string& policy_id) { // For these tests, we want to specify the policy, but the UAT server only // allows us to set the content id as the video_id. So each policy is // matched to a single license with the same name. The local license // server, on the other hand, wants to see the policy id in the url. So we // have to guess which format to use based on the name of the server. - const std::string path = config_.license_server() + config_.client_auth(); + const std::string path = server_url + config_.client_auth(); std::string video_query; if (path.find("proxy.uat") != std::string::npos) { // This is uat or uat-nightly. Set the video_id. @@ -256,7 +279,7 @@ class CdmDurationTest : public WvCdmTestBaseWithEngine, void GetKeyResponse(const CdmKeyRequest& key_request) { // The content id matches the policy id used on UAT. - const std::string url = MakeUrl(content_id_); + const std::string url = MakeUrl(config_.license_server(), content_id_); UrlRequest url_request(url); ASSERT_TRUE(url_request.is_connected()); @@ -293,34 +316,27 @@ class CdmDurationTest : public WvCdmTestBaseWithEngine, } // Simulate loading or reloading a license, then verify that we are allowed - // playback from |start| to |stop|. If |cutoff| is not 0, then expect the - // timer to expire at that time. If |cutoff| is 0, expect the timer is not - // set. If you refer to the diagrams in "License Duration and Renewal", this - // tests a cyan bar with a green check mark. - // When nonzero |start|, |stop|, and |cutoff| are all system times. - void LoadAndAllowPlayback(uint64_t start, uint64_t stop, uint64_t cutoff) { + // playback from |start| to |stop|. If you refer to the diagrams in "License + // Duration and Renewal", this tests a cyan bar with a green check mark. Both + // |start| and |stop| are system times. + void LoadAndAllowPlayback(uint64_t start, uint64_t stop) { SleepUntil(start); LoadLicense(); - AllowPlayback(start, stop, cutoff); + AllowPlayback(start, stop); } - // Verify that we are allowed playback from |start| to |stop|. If |cutoff| is - // not 0, then expect the timer to expire at that time. If |cutoff| is 0, - // expect the timer is not set. If you refer to the diagrams in "License - // Duration and Renewal", this tests a cyan bar with a green check mark. - // When nonzero |start|, |stop|, and |cutoff| are all system times. - void AllowPlayback(uint64_t start, uint64_t stop, uint64_t cutoff) { + // Verify that we are allowed playback from |start| to |stop|. If you refer to + // the diagrams in "License Duration and Renewal", this tests a cyan bar with + // a green check mark. Both |start| and |stop| are all system times. + void AllowPlayback(uint64_t start, uint64_t stop) { ASSERT_LT(start, stop); - if (cutoff > 0) ASSERT_LE(stop, cutoff); - SleepUntil(start + kFudge); + SleepUntil(start); Decrypt(); const uint64_t mid = (start + stop) / 2; SleepUntil(mid); Decrypt(); SleepUntil(stop - kFudge); Decrypt(); - // TODO: Is there a way to verify that playback will be terminated at - // cutoff? } // Simulate loading or reloading a license, then attempt to play from |start| @@ -331,19 +347,18 @@ class CdmDurationTest : public WvCdmTestBaseWithEngine, void LoadAndTerminatePlayback(uint64_t start, uint64_t cutoff) { SleepUntil(start); LoadLicense(); - TerminatePlayback(start, cutoff, cutoff + kFudge); + TerminatePlayback(start, cutoff); } - // Attempt to play from |start| to |stop|. Verify that we are allowed playback - // from |start| to |cutoff|, but playback not allowed after |cutoff|. If you - // refer to the diagrams in "License Duration and Renewal", this tests a cyan - // bar with a black X. This assumes that |cutoff| is before |stop|. - // When nonzero |start|, |stop|, and |cutoff| are all system times. - void TerminatePlayback(uint64_t start, uint64_t cutoff, uint64_t stop) { + // Attempt to play from |start| to |cutoff|. Verify that we are allowed + // playback from |start| to |cutoff|, but playback not allowed after + // |cutoff|. If you refer to the diagrams in "License Duration and Renewal", + // this tests a cyan bar with a black X. This assumes that |cutoff| is before + // |stop|. Both |start| and |cutoff| are system times. + void TerminatePlayback(uint64_t start, uint64_t cutoff) { ASSERT_LT(start, cutoff); - ASSERT_LT(cutoff, stop); - AllowPlayback(start, cutoff, cutoff); - SleepUntil(stop + kFudge); + AllowPlayback(start, cutoff); + SleepUntil(cutoff + kFudge); FailDecrypt(); } @@ -363,34 +378,54 @@ class CdmDurationTest : public WvCdmTestBaseWithEngine, const std::vector input(buffer_size, 0); std::vector output(buffer_size, 0); const std::vector iv(KEY_IV_SIZE, 0); - Decrypt(session_id_, kKeyId, input, iv, &output, NO_ERROR); + const uint64_t now = CurrentRentalTime(); + EXPECT_EQ(NO_ERROR, Decrypt(session_id_, kKeyId, input, iv, &output)) + << "Failed to decrypt when rental clock = " << now + << ", and playback clock = " + << ((now < start_of_playback_) ? 0 : (now - start_of_playback_)); } void FailDecrypt() { - CdmResponseType expected_status = NEED_KEY; - // On low end devices, for some tests, we are lenient on playback - // termination. This means that low end devices are not required to fail - // playback. Tests that allow lenience are enumerated in the - // documentation. See the section in "License Duration and Renewal" on - // lenient tests. + bool allow_success = false; + // We will be lenient for some tests if it is a low end device without a + // usage table or if it is a pre-v16 devices. We are only leinient + // for an offline license. Being lenient means we allow playback, even + // though the policy requests playback cutoff. Tests that allow lenience + // are enumerated in the documentation. See the section in "License + // Duration and Renewal" on lenient tests. These tests call the function + // AllowLenience to signal this case. const bool low_end_device = (wvoec::global_features.api_version < wvoec::kCoreMessagesAPI || !wvoec::global_features.usage_table); if (allow_lenience_ && low_end_device && can_persist_) { - expected_status = NO_ERROR; - allow_lenience_ = false; // Only allow lenience once per test. + allow_success = true; } + allow_lenience_ = false; // Only allow lenience once per test. + constexpr size_t buffer_size = 500; const std::vector input(buffer_size, 0); std::vector output(buffer_size, 0); const std::vector iv(KEY_IV_SIZE, 0); - Decrypt(session_id_, kKeyId, input, iv, &output, expected_status); + const uint64_t now = CurrentRentalTime(); + CdmResponseType status = Decrypt(session_id_, kKeyId, input, iv, &output); + // We always allow failure. that's what we usually expect. + if (status == NEED_KEY) return; + // No other error code is allowed: either NO_ERROR or NEED_KEY. + ASSERT_EQ(NO_ERROR, status) + << "Failed to decrypt with unexpected error code when rental clock = " + << now << ", and playback clock = " + << (now < start_of_playback_ ? 0 : now - start_of_playback_); + // However, for those cases decided above, we also allow success. + EXPECT_TRUE(allow_success) + << "Device was unexpectedly lenient when rental clock = " << now + << ", and playback clock = " + << (now < start_of_playback_ ? 0 : now - start_of_playback_); } - void Decrypt(const CdmSessionId& session_id, const KeyId& key_id, - const std::vector& input, - const std::vector& iv, std::vector* output, - CdmResponseType expected_status) { + CdmResponseType Decrypt(const CdmSessionId& session_id, const KeyId& key_id, + const std::vector& input, + const std::vector& iv, + std::vector* output) { CdmDecryptionParametersV16 params(key_id); params.is_secure = false; CdmDecryptionSample sample(input.data(), output->data(), 0, input.size(), @@ -399,8 +434,7 @@ class CdmDurationTest : public WvCdmTestBaseWithEngine, sample.subsamples.push_back(subsample); params.samples.push_back(sample); - CdmResponseType status = cdm_engine_.DecryptV16(session_id, params); - ASSERT_EQ(expected_status, status); + return cdm_engine_.DecryptV16(session_id, params); } CdmSessionId session_id_; @@ -427,7 +461,7 @@ class CdmDurationTest : public WvCdmTestBaseWithEngine, /*****************************************************************************/ // Note on Use Case tests. The test classes below correspond to the use cases -// in the doucment "License Duration and Renewal.". Each diagram in that +// in the document "License Duration and Renewal". Each diagram in that // document has a test class below to verify the use case is supported. // // In the document, we use realistic rental times in hours or days. In these @@ -444,7 +478,7 @@ class CdmUseCase_Streaming : public CdmDurationTest { // Rental duration = 3 hours hard. (use 300 for readability) // Playback duration = 0 (unlimited) timer_limits_.soft_enforce_rental_duration = false; - timer_limits_.rental_duration_seconds = 35; + timer_limits_.rental_duration_seconds = 40; timer_limits_.total_playback_duration_seconds = 0; } }; @@ -452,8 +486,7 @@ class CdmUseCase_Streaming : public CdmDurationTest { // Playback within rental duration. TEST_P(CdmUseCase_Streaming, Case1) { // Allow playback within the rental window. - LoadAndAllowPlayback(start_of_playback_, EndOfRentalWindow(), - EndOfRentalWindow()); + LoadAndAllowPlayback(start_of_playback_, EndOfRentalWindow()); } // Playback exceeds rental duration. @@ -465,25 +498,26 @@ TEST_P(CdmUseCase_Streaming, Case2) { // Playback with stops/restarts within rental duration, last one exceeds rental // duration. TEST_P(CdmUseCase_Streaming, Case3) { - LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + 5, - EndOfRentalWindow()); + LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + kPlayDuration); UnloadLicense(); - LoadAndAllowPlayback(start_of_playback_ + 10, start_of_playback_ + 15, - EndOfRentalWindow()); + LoadAndAllowPlayback(start_of_playback_ + 2 * kPlayDuration, + start_of_playback_ + 3 * kPlayDuration); UnloadLicense(); - LoadAndTerminatePlayback(start_of_playback_ + 20, EndOfRentalWindow()); + LoadAndTerminatePlayback(start_of_playback_ + 4 * kPlayDuration, + EndOfRentalWindow()); } // Playback within rental duration, restart exceeds rental duration. TEST_P(CdmUseCase_Streaming, Case4) { - LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + 5, - EndOfRentalWindow()); + LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + kPlayDuration); UnloadLicense(); - ForbidPlayback(EndOfRentalWindow() + 5); + ForbidPlayback(EndOfRentalWindow() + kFudge); } // Initial playback exceeds rental duration. -TEST_P(CdmUseCase_Streaming, Case5) { ForbidPlayback(EndOfRentalWindow() + 5); } +TEST_P(CdmUseCase_Streaming, Case5) { + ForbidPlayback(EndOfRentalWindow() + kFudge); +} /*****************************************************************************/ // Streaming Quick Start. The user must start watching within 30 seconds, and @@ -500,7 +534,7 @@ class CdmUseCase_StreamingQuickStart : public CdmDurationTest { timer_limits_.soft_enforce_playback_duration = false; // A valid start of playback time. - start_of_playback_ = timer_limits_.rental_duration_seconds - 10; + start_of_playback_ = timer_limits_.rental_duration_seconds - kPlayDuration; } }; @@ -508,9 +542,9 @@ class CdmUseCase_StreamingQuickStart : public CdmDurationTest { TEST_P(CdmUseCase_StreamingQuickStart, Case1) { // As seen in the drawing, the playback window exceeds the rental window. EXPECT_LE(EndOfRentalWindow(), EndOfPlaybackWindow()); - // Allow playback within the playback window. - LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + 20, - EndOfPlaybackWindow()); + // Allow playback within the playback window, even if it is after the rental + // window. + LoadAndAllowPlayback(start_of_playback_, EndOfRentalWindow() + kFudge); } // Playback exceeds playback duration. @@ -520,91 +554,107 @@ TEST_P(CdmUseCase_StreamingQuickStart, Case2) { } // Playback with stops/restarts within playback duration, last one exceeds -// playback duration. +// playback duration. This also tests that playback may be restarted after the +// rental window has closed, as long as the playback window is still open. TEST_P(CdmUseCase_StreamingQuickStart, Case3) { - LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + 10, - EndOfPlaybackWindow()); + LoadAndAllowPlayback(start_of_playback_, + start_of_playback_ + 2 * kPlayDuration); UnloadLicense(); - LoadAndAllowPlayback(start_of_playback_ + 15, start_of_playback_ + 20, - EndOfPlaybackWindow()); + // Check that we can restart the playback after the rental window has stopped. + const uint64_t after_rental = EndOfRentalWindow() + kPlayDuration; + LoadAndAllowPlayback(after_rental, after_rental + kPlayDuration); UnloadLicense(); - LoadAndTerminatePlayback(start_of_playback_ + 25, EndOfPlaybackWindow()); + LoadAndTerminatePlayback(EndOfPlaybackWindow() - kPlayDuration, + EndOfPlaybackWindow()); } // Initial playback exceeds rental duration. TEST_P(CdmUseCase_StreamingQuickStart, Case4) { - ForbidPlayback(EndOfRentalWindow() + 10); + ForbidPlayback(EndOfRentalWindow() + kFudge); } +/*****************************************************************************/ +// Seven Day / Two Day. The user must start watching within 7 days. Once +// started, the user has two days to finish the video. This class sets up the +// times to match the diagrams in the document "License Duration and +// Renewal". There are four sets of classes below this separate out +// hard/soft for enforcement of rental and playback duration. +class CdmUseCase_SevenTwo : public CdmDurationTest { + public: + CdmUseCase_SevenTwo(const std::string& content_id) + : CdmDurationTest(content_id) { + // Rental Duration should be 7 days. In the diagram. + timer_limits_.rental_duration_seconds = seven_days_; + timer_limits_.total_playback_duration_seconds = two_days_; + } + + // Playback window is entirely contained in rental window. In diagram this is + // on day 3. + void StartDay3() { start_of_playback_ = day3_; } + + // Playback overlays end of rental window. In diagram, this is on day 6. + void StartDay6() { start_of_playback_ = day6_; } + static constexpr uint64_t seven_days_ = 100; + static constexpr uint64_t two_days_ = 50; + static constexpr uint64_t day3_ = 20; + static constexpr uint64_t day6_ = 70; +}; + /*****************************************************************************/ // Seven Day / Two Day. The user must start watching within 7 days. Once // started, the user has two days to finish the video. Playback is cutoff by the // smaller of the two time limits. The first four cases start on day // three. (See above for note on Use Case tests) -class CdmUseCase_SevenHardTwoHard_Start3 : public CdmDurationTest { +class CdmUseCase_SevenHardTwoHard : public CdmUseCase_SevenTwo { public: - CdmUseCase_SevenHardTwoHard_Start3() - : CdmDurationTest("CDM_SevenHardTwoHard") { - // Rental duration = 200, hard - // Playback duration = 100, hard - timer_limits_.rental_duration_seconds = 200; // 7 days. + CdmUseCase_SevenHardTwoHard() : CdmUseCase_SevenTwo("CDM_SevenHardTwoHard") { timer_limits_.soft_enforce_rental_duration = false; - timer_limits_.total_playback_duration_seconds = 100; // 2 days. timer_limits_.soft_enforce_playback_duration = false; - - start_of_playback_ = 50; // Start is less than rental - playback. } }; // Playback within playback and rental duration. -TEST_P(CdmUseCase_SevenHardTwoHard_Start3, Case1) { +TEST_P(CdmUseCase_SevenHardTwoHard, Case1) { + StartDay3(); // As seen in the drawing, the playback window is within the rental window. EXPECT_LT(EndOfPlaybackWindow(), EndOfRentalWindow()); // Allow playback within the rental window. - LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + 10, - EndOfPlaybackWindow()); + LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + kPlayDuration); } // Playback exceeds playback duration. -TEST_P(CdmUseCase_SevenHardTwoHard_Start3, Case2) { +TEST_P(CdmUseCase_SevenHardTwoHard, Case2) { + StartDay3(); // Allow playback within the playback window, but not beyond. LoadAndTerminatePlayback(start_of_playback_, EndOfPlaybackWindow()); } // Playback with stops/restarts within playback duration, last one exceeds // playback duration. -TEST_P(CdmUseCase_SevenHardTwoHard_Start3, Case3) { - LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + 10, - EndOfPlaybackWindow()); +TEST_P(CdmUseCase_SevenHardTwoHard, Case3) { + StartDay3(); + LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + kPlayDuration); UnloadLicense(); - LoadAndAllowPlayback(start_of_playback_ + 20, start_of_playback_ + 30, - EndOfPlaybackWindow()); + LoadAndAllowPlayback(start_of_playback_ + 2 * kPlayDuration, + start_of_playback_ + 3 * kPlayDuration); UnloadLicense(); AllowLenience(); - LoadAndTerminatePlayback(start_of_playback_ + 50, EndOfPlaybackWindow()); + LoadAndTerminatePlayback(start_of_playback_ + 4 * kPlayDuration, + EndOfPlaybackWindow()); } // Restart exceeds playback duration. -TEST_P(CdmUseCase_SevenHardTwoHard_Start3, Case4) { - LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + 50, - EndOfPlaybackWindow()); +TEST_P(CdmUseCase_SevenHardTwoHard, Case4) { + StartDay3(); + LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + kPlayDuration); UnloadLicense(); AllowLenience(); - ForbidPlayback(EndOfPlaybackWindow() + 10); + ForbidPlayback(EndOfPlaybackWindow() + kFudge); } -// The next four cases start on day six. -class CdmUseCase_SevenHardTwoHard_Start6 - : public CdmUseCase_SevenHardTwoHard_Start3 { - public: - CdmUseCase_SevenHardTwoHard_Start6() { - // Start is more than rental - playback = 200 - 100 - start_of_playback_ = 150; - } -}; - // Playback exceeds rental duration. -TEST_P(CdmUseCase_SevenHardTwoHard_Start6, Case5) { +TEST_P(CdmUseCase_SevenHardTwoHard, Case5) { + StartDay6(); // As seen in the drawing, the playback window is exceeds the rental window. EXPECT_GT(EndOfPlaybackWindow(), EndOfRentalWindow()); // Allow playback within the rental window. @@ -613,35 +663,38 @@ TEST_P(CdmUseCase_SevenHardTwoHard_Start6, Case5) { // Playback with stops/restarts within playback duration, last one is terminated // at the end of the rental duration. -TEST_P(CdmUseCase_SevenHardTwoHard_Start6, Case6) { - LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + 10, - EndOfRentalWindow()); +TEST_P(CdmUseCase_SevenHardTwoHard, Case6) { + StartDay6(); + LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + kPlayDuration); UnloadLicense(); - LoadAndAllowPlayback(start_of_playback_ + 20, start_of_playback_ + 30, - EndOfRentalWindow()); + LoadAndAllowPlayback(start_of_playback_ + 2 * kPlayDuration, + start_of_playback_ + 3 * kPlayDuration); UnloadLicense(); // Allow playback that starts within rental window, but terminate at end of // rental window. - LoadAndTerminatePlayback(start_of_playback_ + 40, EndOfRentalWindow()); + LoadAndTerminatePlayback(start_of_playback_ + 4 * kPlayDuration, + EndOfRentalWindow()); } // Playback within playback duration, restart exceeds rental duration. -TEST_P(CdmUseCase_SevenHardTwoHard_Start6, Case7) { - LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + 25, - EndOfRentalWindow()); +TEST_P(CdmUseCase_SevenHardTwoHard, Case7) { + StartDay6(); + LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + kPlayDuration); UnloadLicense(); // Restart does not work after end of playback window. - ForbidPlayback(EndOfRentalWindow() + 10); + ForbidPlayback(EndOfRentalWindow() + kPlayDuration); } // Playback exceeds rental and playback duration. -TEST_P(CdmUseCase_SevenHardTwoHard_Start6, Case8) { +TEST_P(CdmUseCase_SevenHardTwoHard, Case8) { + StartDay6(); LoadAndTerminatePlayback(start_of_playback_, EndOfRentalWindow()); } // First playback cannot exceed rental duration. -TEST_P(CdmUseCase_SevenHardTwoHard_Start6, Case9) { - ForbidPlayback(EndOfRentalWindow() + 10); +TEST_P(CdmUseCase_SevenHardTwoHard, Case9) { + StartDay6(); + ForbidPlayback(EndOfRentalWindow() + kFudge); } /*****************************************************************************/ @@ -649,73 +702,59 @@ TEST_P(CdmUseCase_SevenHardTwoHard_Start6, Case9) { // started, the user has two days to finish the video. Playback is cutoff by the // rental duration time limits. The first four cases start on day three. (See // above for note on Use Case tests) -class CdmUseCase_SevenHardTwoSoft_Start3 : public CdmDurationTest { +class CdmUseCase_SevenHardTwoSoft : public CdmUseCase_SevenTwo { public: - CdmUseCase_SevenHardTwoSoft_Start3() - : CdmDurationTest("CDM_SevenHardTwoSoft") { - // Rental duration = 200, hard - // Playback duration = 100, hard - timer_limits_.rental_duration_seconds = 200; + CdmUseCase_SevenHardTwoSoft() : CdmUseCase_SevenTwo("CDM_SevenHardTwoSoft") { timer_limits_.soft_enforce_rental_duration = false; - timer_limits_.total_playback_duration_seconds = 100; timer_limits_.soft_enforce_playback_duration = true; - - start_of_playback_ = 50; // Start is less than rental - playback. } }; // Playback within playback and rental duration. -TEST_P(CdmUseCase_SevenHardTwoSoft_Start3, Case1) { +TEST_P(CdmUseCase_SevenHardTwoSoft, Case1) { + StartDay3(); // As seen in the drawing, the playback window is within the rental window. EXPECT_LT(EndOfPlaybackWindow(), EndOfRentalWindow()); // Allow playback within the rental window. - LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + 10, - EndOfRentalWindow()); + LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + kPlayDuration); } // Playback exceeds playback duration. -TEST_P(CdmUseCase_SevenHardTwoSoft_Start3, Case2) { +TEST_P(CdmUseCase_SevenHardTwoSoft, Case2) { + StartDay3(); // Allow playback within the playback window, and a little after. // Timer expires at end of rental window. - LoadAndAllowPlayback(start_of_playback_, EndOfPlaybackWindow() + 15, - EndOfRentalWindow()); + LoadAndAllowPlayback(start_of_playback_, + EndOfPlaybackWindow() + kPlayDuration); } // Playback with stops/restarts within playback duration, last one exceeds // playback duration. -TEST_P(CdmUseCase_SevenHardTwoSoft_Start3, Case3) { - LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + 10, - EndOfRentalWindow()); +TEST_P(CdmUseCase_SevenHardTwoSoft, Case3) { + StartDay3(); + LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + kPlayDuration); UnloadLicense(); - LoadAndAllowPlayback(start_of_playback_ + 20, start_of_playback_ + 30, - EndOfRentalWindow()); + LoadAndAllowPlayback(start_of_playback_ + 2 * kPlayDuration, + start_of_playback_ + 3 * kPlayDuration); UnloadLicense(); - LoadAndAllowPlayback(start_of_playback_ + 50, EndOfPlaybackWindow() + 15, - EndOfRentalWindow()); + LoadAndAllowPlayback(start_of_playback_ + 4 * kPlayDuration, + EndOfPlaybackWindow() + kPlayDuration); } // Restart exceeds playback duration. -TEST_P(CdmUseCase_SevenHardTwoSoft_Start3, Case4) { - LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + 50, - EndOfRentalWindow()); +TEST_P(CdmUseCase_SevenHardTwoSoft, Case4) { + StartDay3(); + LoadAndAllowPlayback(start_of_playback_, + start_of_playback_ + 4 * kPlayDuration); UnloadLicense(); if (!can_persist_) return; // streaming license cannot restart. AllowLenience(); - ForbidPlayback(EndOfPlaybackWindow() + 10); + ForbidPlayback(EndOfPlaybackWindow() + kFudge); } -// The next four cases start on day six. -class CdmUseCase_SevenHardTwoSoft_Start6 - : public CdmUseCase_SevenHardTwoSoft_Start3 { - public: - CdmUseCase_SevenHardTwoSoft_Start6() { - // Start is more than rental - playback = 200 - 100 - start_of_playback_ = 150; - } -}; - // Playback exceeds rental duration. -TEST_P(CdmUseCase_SevenHardTwoSoft_Start6, Case5) { +TEST_P(CdmUseCase_SevenHardTwoSoft, Case5) { + StartDay6(); // As seen in the drawing, the playback window is exceeds the rental window. EXPECT_GT(EndOfPlaybackWindow(), EndOfRentalWindow()); // Allow playback within the rental window. @@ -724,33 +763,36 @@ TEST_P(CdmUseCase_SevenHardTwoSoft_Start6, Case5) { // Playback with stops/restarts within playback duration, last one exceeds // rental duration. -TEST_P(CdmUseCase_SevenHardTwoSoft_Start6, Case6) { - LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + 10, - EndOfRentalWindow()); +TEST_P(CdmUseCase_SevenHardTwoSoft, Case6) { + StartDay6(); + LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + kPlayDuration); UnloadLicense(); - LoadAndAllowPlayback(start_of_playback_ + 20, start_of_playback_ + 30, - EndOfRentalWindow()); + LoadAndAllowPlayback(start_of_playback_ + 2 * kPlayDuration, + start_of_playback_ + 3 * kPlayDuration); UnloadLicense(); - LoadAndTerminatePlayback(start_of_playback_ + 40, EndOfRentalWindow()); + LoadAndTerminatePlayback(start_of_playback_ + 4 * kPlayDuration, + EndOfRentalWindow()); } // Playback within playback duration, restart exceeds rental duration. -TEST_P(CdmUseCase_SevenHardTwoSoft_Start6, Case7) { - LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + 25, - EndOfRentalWindow()); +TEST_P(CdmUseCase_SevenHardTwoSoft, Case7) { + StartDay6(); + LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + kPlayDuration); UnloadLicense(); // Restart does not work after end of playback window. - ForbidPlayback(EndOfRentalWindow() + 10); + ForbidPlayback(EndOfRentalWindow() + kPlayDuration); } // Playback exceeds rental and playback duration. -TEST_P(CdmUseCase_SevenHardTwoSoft_Start6, Case8) { +TEST_P(CdmUseCase_SevenHardTwoSoft, Case8) { + StartDay6(); LoadAndTerminatePlayback(start_of_playback_, EndOfRentalWindow()); } // First playback cannot exceed rental duration. -TEST_P(CdmUseCase_SevenHardTwoSoft_Start6, Case9) { - ForbidPlayback(EndOfRentalWindow() + 10); +TEST_P(CdmUseCase_SevenHardTwoSoft, Case9) { + StartDay6(); + ForbidPlayback(EndOfRentalWindow() + kFudge); } /*****************************************************************************/ @@ -758,70 +800,57 @@ TEST_P(CdmUseCase_SevenHardTwoSoft_Start6, Case9) { // started, the user has two days to finish the video. Playback is cutoff by the // playback duration. The first four cases start on day three. (See above for // note on Use Case tests) -class CdmUseCase_SevenSoftTwoHard_Start3 : public CdmDurationTest { +class CdmUseCase_SevenSoftTwoHard : public CdmUseCase_SevenTwo { public: - CdmUseCase_SevenSoftTwoHard_Start3() - : CdmDurationTest("CDM_SevenSoftTwoHard") { - // Rental duration = 200, hard - // Playback duration = 100, hard - timer_limits_.rental_duration_seconds = 200; + CdmUseCase_SevenSoftTwoHard() : CdmUseCase_SevenTwo("CDM_SevenSoftTwoHard") { timer_limits_.soft_enforce_rental_duration = true; - timer_limits_.total_playback_duration_seconds = 100; timer_limits_.soft_enforce_playback_duration = false; - - start_of_playback_ = 50; // Start is less than rental - playback. } }; // Playback within playback and rental duration. -TEST_P(CdmUseCase_SevenSoftTwoHard_Start3, Case1) { +TEST_P(CdmUseCase_SevenSoftTwoHard, Case1) { + StartDay3(); // As seen in the drawing, the playback window is within the rental window. EXPECT_LT(EndOfPlaybackWindow(), EndOfRentalWindow()); // Allow playback within the rental window. - LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + 10, - EndOfPlaybackWindow()); + LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + kPlayDuration); } // Playback exceeds playback duration. -TEST_P(CdmUseCase_SevenSoftTwoHard_Start3, Case2) { +TEST_P(CdmUseCase_SevenSoftTwoHard, Case2) { + StartDay3(); // Allow playback within the playback window, but not beyond. LoadAndTerminatePlayback(start_of_playback_, EndOfPlaybackWindow()); } // Playback with stops/restarts within playback duration, last one exceeds // playback duration. -TEST_P(CdmUseCase_SevenSoftTwoHard_Start3, Case3) { - LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + 10, - EndOfPlaybackWindow()); +TEST_P(CdmUseCase_SevenSoftTwoHard, Case3) { + StartDay3(); + LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + kPlayDuration); UnloadLicense(); - LoadAndAllowPlayback(start_of_playback_ + 20, start_of_playback_ + 30, - EndOfPlaybackWindow()); + LoadAndAllowPlayback(start_of_playback_ + 2 * kPlayDuration, + start_of_playback_ + 3 * kPlayDuration); UnloadLicense(); AllowLenience(); - LoadAndTerminatePlayback(start_of_playback_ + 50, EndOfPlaybackWindow()); + LoadAndTerminatePlayback(start_of_playback_ + 4 * kPlayDuration, + EndOfPlaybackWindow()); } // Restart exceeds playback duration. -TEST_P(CdmUseCase_SevenSoftTwoHard_Start3, Case4) { - LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + 50, - EndOfPlaybackWindow()); +TEST_P(CdmUseCase_SevenSoftTwoHard, Case4) { + StartDay3(); + LoadAndAllowPlayback(start_of_playback_, + start_of_playback_ + 4 * kPlayDuration); UnloadLicense(); AllowLenience(); - ForbidPlayback(EndOfPlaybackWindow() + 10); + ForbidPlayback(EndOfPlaybackWindow() + kFudge); } -// The next four cases start on day six. -class CdmUseCase_SevenSoftTwoHard_Start6 - : public CdmUseCase_SevenSoftTwoHard_Start3 { - public: - CdmUseCase_SevenSoftTwoHard_Start6() { - // Start is more than rental - playback = 200 - 100 - start_of_playback_ = 150; - } -}; - // Playback exceeds rental duration. -TEST_P(CdmUseCase_SevenSoftTwoHard_Start6, Case5) { +TEST_P(CdmUseCase_SevenSoftTwoHard, Case5) { + StartDay6(); // As seen in the drawing, the playback window exceeds the rental window. EXPECT_GT(EndOfPlaybackWindow(), EndOfRentalWindow()); // Allow playback to continue beyond the rental window, but not beyond the @@ -831,34 +860,38 @@ TEST_P(CdmUseCase_SevenSoftTwoHard_Start6, Case5) { // Playback with stops/restarts within playback duration, last one exceeds // rental duration. -TEST_P(CdmUseCase_SevenSoftTwoHard_Start6, Case6) { - LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + 10, - EndOfPlaybackWindow()); +TEST_P(CdmUseCase_SevenSoftTwoHard, Case6) { + StartDay6(); + LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + kPlayDuration); UnloadLicense(); - LoadAndAllowPlayback(start_of_playback_ + 20, start_of_playback_ + 30, - EndOfPlaybackWindow()); + LoadAndAllowPlayback(start_of_playback_ + 2 * kPlayDuration, + start_of_playback_ + 3 * kPlayDuration); UnloadLicense(); AllowLenience(); - LoadAndTerminatePlayback(start_of_playback_ + 40, EndOfPlaybackWindow()); + LoadAndTerminatePlayback(start_of_playback_ + 4 * kPlayDuration, + EndOfPlaybackWindow()); } // Restart exceeds rental duration, playback exceeds playback duration. -TEST_P(CdmUseCase_SevenSoftTwoHard_Start6, Case7) { - LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + 25, - EndOfPlaybackWindow()); +TEST_P(CdmUseCase_SevenSoftTwoHard, Case7) { + StartDay6(); + LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + kPlayDuration); UnloadLicense(); AllowLenience(); - LoadAndTerminatePlayback(EndOfRentalWindow() + 10, EndOfPlaybackWindow()); + LoadAndTerminatePlayback(EndOfRentalWindow() + kPlayDuration, + EndOfPlaybackWindow()); } // Playback exceeds rental and playback duration. -TEST_P(CdmUseCase_SevenSoftTwoHard_Start6, Case8) { +TEST_P(CdmUseCase_SevenSoftTwoHard, Case8) { + StartDay6(); LoadAndTerminatePlayback(start_of_playback_, EndOfPlaybackWindow()); } // First playback cannot exceed rental duration. -TEST_P(CdmUseCase_SevenSoftTwoHard_Start6, Case9) { - ForbidPlayback(EndOfRentalWindow() + 10); +TEST_P(CdmUseCase_SevenSoftTwoHard, Case9) { + StartDay6(); + ForbidPlayback(EndOfRentalWindow() + kFudge); } /*****************************************************************************/ @@ -866,129 +899,120 @@ TEST_P(CdmUseCase_SevenSoftTwoHard_Start6, Case9) { // started, the user has two days to finish the video. Playback is not cutoff, // but restarts are not allowed after playback duration. The first four cases // start on day three. (See above for note on Use Case tests) -class CdmUseCase_SevenSoftTwoSoft_Start3 : public CdmDurationTest { +class CdmUseCase_SevenSoftTwoSoft : public CdmUseCase_SevenTwo { public: - CdmUseCase_SevenSoftTwoSoft_Start3() - : CdmDurationTest("CDM_SevenSoftTwoSoft") { - // Rental duration = 200, hard - // Playback duration = 100, hard - timer_limits_.rental_duration_seconds = 200; + CdmUseCase_SevenSoftTwoSoft() : CdmUseCase_SevenTwo("CDM_SevenSoftTwoSoft") { timer_limits_.soft_enforce_rental_duration = true; - timer_limits_.total_playback_duration_seconds = 100; timer_limits_.soft_enforce_playback_duration = true; - - start_of_playback_ = 50; // Start is less than rental - playback. } }; // Playback within playback and rental duration. -TEST_P(CdmUseCase_SevenSoftTwoSoft_Start3, Case1) { +TEST_P(CdmUseCase_SevenSoftTwoSoft, Case1) { + StartDay3(); // As seen in the drawing, the playback window is within the rental window. EXPECT_LT(EndOfPlaybackWindow(), EndOfRentalWindow()); // Allow playback within the rental window. - LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + 10, 0); + LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + kPlayDuration); } // Playback exceeds playback duration. -TEST_P(CdmUseCase_SevenSoftTwoSoft_Start3, Case2) { +TEST_P(CdmUseCase_SevenSoftTwoSoft, Case2) { + StartDay3(); // Allow playback within the playback window, and beyond. No timer limit. - LoadAndAllowPlayback(start_of_playback_, EndOfPlaybackWindow() + 10, 0); + LoadAndAllowPlayback(start_of_playback_, + EndOfPlaybackWindow() + kPlayDuration); } // Playback with stops/restarts within playback duration, last one exceeds // playback duration. -TEST_P(CdmUseCase_SevenSoftTwoSoft_Start3, Case3) { - LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + 10, 0); +TEST_P(CdmUseCase_SevenSoftTwoSoft, Case3) { + StartDay3(); + LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + kPlayDuration); UnloadLicense(); - LoadAndAllowPlayback(start_of_playback_ + 20, start_of_playback_ + 30, 0); + LoadAndAllowPlayback(start_of_playback_ + 2 * kPlayDuration, + start_of_playback_ + 3 * kPlayDuration); UnloadLicense(); - LoadAndAllowPlayback(start_of_playback_ + 50, EndOfPlaybackWindow() + 15, 0); + LoadAndAllowPlayback(start_of_playback_ + 4 * kPlayDuration, + EndOfPlaybackWindow() + kPlayDuration); } // Restart exceeds playback duration. -TEST_P(CdmUseCase_SevenSoftTwoSoft_Start3, Case4) { - LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + 50, 0); +TEST_P(CdmUseCase_SevenSoftTwoSoft, Case4) { + StartDay3(); + LoadAndAllowPlayback(start_of_playback_, + start_of_playback_ + 4 * kPlayDuration); UnloadLicense(); if (!can_persist_) return; // streaming license cannot restart. AllowLenience(); - ForbidPlayback(EndOfPlaybackWindow() + 10); + ForbidPlayback(EndOfPlaybackWindow() + kFudge); } -// The next four cases start on day six. -class CdmUseCase_SevenSoftTwoSoft_Start6 - : public CdmUseCase_SevenSoftTwoSoft_Start3 { - public: - CdmUseCase_SevenSoftTwoSoft_Start6() { - // Start is more than rental - playback = 200 - 100 - start_of_playback_ = 150; - } -}; - // Playback exceeds rental duration. -TEST_P(CdmUseCase_SevenSoftTwoSoft_Start6, Case5) { +TEST_P(CdmUseCase_SevenSoftTwoSoft, Case5) { + StartDay6(); // As seen in the drawing, the playback window exceeds the rental window. // We should be able to play a little bit after the rental window. - // We'll use 10 as "a little bit". - const uint64_t end_play = EndOfRentalWindow() + 10; + const uint64_t end_play = EndOfRentalWindow() + kPlayDuration; // For this case, we are playing after the end of the playback window, too. EXPECT_GT(EndOfPlaybackWindow(), end_play); // Allow playback past the rental window, but within the playback window. - LoadAndAllowPlayback(start_of_playback_, end_play, 0); + LoadAndAllowPlayback(start_of_playback_, end_play); } // Playback with stops/restarts within playback duration, last one exceeds // rental and playback duration. -TEST_P(CdmUseCase_SevenSoftTwoSoft_Start6, Case6) { - LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + 10, 0); +TEST_P(CdmUseCase_SevenSoftTwoSoft, Case6) { + StartDay6(); + LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + kPlayDuration); UnloadLicense(); - LoadAndAllowPlayback(start_of_playback_ + 20, start_of_playback_ + 30, 0); + LoadAndAllowPlayback(start_of_playback_ + 2 * kPlayDuration, + start_of_playback_ + 3 * kPlayDuration); UnloadLicense(); - LoadAndAllowPlayback(start_of_playback_ + 40, EndOfPlaybackWindow() + 10, 0); + LoadAndAllowPlayback(start_of_playback_ + 4 * kPlayDuration, + EndOfPlaybackWindow() + kPlayDuration); } // Playback with stops/restarts within playback duration, last one exceeds // playback duration. -TEST_P(CdmUseCase_SevenSoftTwoSoft_Start6, Case7) { - LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + 25, 0); +TEST_P(CdmUseCase_SevenSoftTwoSoft, Case7) { + StartDay6(); + LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + kPlayDuration); UnloadLicense(); // Allow playback to start after end of rental window, and continue after // playback window. - LoadAndAllowPlayback(EndOfRentalWindow() + 10, EndOfPlaybackWindow() + 10, 0); + LoadAndAllowPlayback(EndOfRentalWindow() + kPlayDuration, + EndOfPlaybackWindow() + kPlayDuration); UnloadLicense(); // But forbid restart after playback window. if (!can_persist_) return; // streaming license cannot restart. - ForbidPlayback(EndOfPlaybackWindow() + 20); + ForbidPlayback(EndOfPlaybackWindow() + 2 * kPlayDuration); } // Playback exceeds rental and playback duration. -TEST_P(CdmUseCase_SevenSoftTwoSoft_Start6, Case8) { - LoadAndAllowPlayback(start_of_playback_, EndOfPlaybackWindow() + 20, 0); +TEST_P(CdmUseCase_SevenSoftTwoSoft, Case8) { + StartDay6(); + LoadAndAllowPlayback(start_of_playback_, + EndOfPlaybackWindow() + 2 * kPlayDuration); } // First playback cannot exceed rental duration. -TEST_P(CdmUseCase_SevenSoftTwoSoft_Start6, Case9) { - ForbidPlayback(EndOfRentalWindow() + 10); +TEST_P(CdmUseCase_SevenSoftTwoSoft, Case9) { + StartDay6(); + ForbidPlayback(EndOfRentalWindow() + kFudge); } INSTANTIATE_TEST_CASE_P(Both, CdmUseCase_Streaming, ::testing::Values(false, true)); INSTANTIATE_TEST_CASE_P(Both, CdmUseCase_StreamingQuickStart, ::testing::Values(false, true)); -INSTANTIATE_TEST_CASE_P(Both, CdmUseCase_SevenHardTwoHard_Start3, +INSTANTIATE_TEST_CASE_P(Both, CdmUseCase_SevenHardTwoHard, ::testing::Values(false, true)); -INSTANTIATE_TEST_CASE_P(Both, CdmUseCase_SevenHardTwoHard_Start6, +INSTANTIATE_TEST_CASE_P(Both, CdmUseCase_SevenHardTwoSoft, ::testing::Values(false, true)); -INSTANTIATE_TEST_CASE_P(Both, CdmUseCase_SevenHardTwoSoft_Start3, +INSTANTIATE_TEST_CASE_P(Both, CdmUseCase_SevenSoftTwoHard, ::testing::Values(false, true)); -INSTANTIATE_TEST_CASE_P(Both, CdmUseCase_SevenHardTwoSoft_Start6, - ::testing::Values(false, true)); -INSTANTIATE_TEST_CASE_P(Both, CdmUseCase_SevenSoftTwoHard_Start3, - ::testing::Values(false, true)); -INSTANTIATE_TEST_CASE_P(Both, CdmUseCase_SevenSoftTwoHard_Start6, - ::testing::Values(false, true)); -INSTANTIATE_TEST_CASE_P(Both, CdmUseCase_SevenSoftTwoSoft_Start3, - ::testing::Values(false, true)); -INSTANTIATE_TEST_CASE_P(Both, CdmUseCase_SevenSoftTwoSoft_Start6, +INSTANTIATE_TEST_CASE_P(Both, CdmUseCase_SevenSoftTwoSoft, ::testing::Values(false, true)); class RenewalTest : public CdmDurationTest { @@ -1019,7 +1043,8 @@ class RenewalTest : public CdmDurationTest { const CdmResponseType result = cdm_engine_.GenerateRenewalRequest(session_id_, &request); ASSERT_EQ(KEY_MESSAGE, result); - const std::string url = MakeUrl(renewal_policy.policy_id); + const std::string url = + MakeUrl(config_.renewal_server(), renewal_policy.policy_id); renewal_in_flight_.reset(new UrlRequest(url)); ASSERT_TRUE(renewal_in_flight_->is_connected()); renewal_in_flight_->PostRequest(request.message); @@ -1064,9 +1089,9 @@ class RenewalTest : public CdmDurationTest { const RenewalPolicy& renewal_policy) { EXPECT_LE(start, load_time); EXPECT_LT(load_time, stop); - if (start < load_time) AllowPlayback(start, load_time, current_cutoff_); + if (start < load_time) AllowPlayback(start, load_time); LoadRenewal(load_time, renewal_policy); - AllowPlayback(load_time, stop, current_cutoff_); + AllowPlayback(load_time, stop); } // Verify that a renewal can be processed and attempt to play from |start| to @@ -1112,7 +1137,7 @@ class RenewalTest : public CdmDurationTest { // license is reloaded. LoadLicense(); ComputeCutoff(start, renewal_policy); - AllowPlayback(start, stop, current_cutoff_); + AllowPlayback(start, stop); } std::unique_ptr renewal_in_flight_; @@ -1127,9 +1152,9 @@ class CdmUseCase_LicenseWithRenewal : public RenewalTest { public: CdmUseCase_LicenseWithRenewal() : RenewalTest("CDM_LicenseWithRenewal") { timer_limits_.soft_enforce_rental_duration = false; - timer_limits_.rental_duration_seconds = 360u; - initial_policy_.renewal_delay = 25u; - initial_policy_.renewal_recovery_duration = 15u; + timer_limits_.rental_duration_seconds = 180u; + initial_policy_.renewal_delay = 15u; + initial_policy_.renewal_recovery_duration = 10u; timer_limits_.initial_renewal_duration_seconds = initial_policy_.renewal_delay + initial_policy_.renewal_recovery_duration; @@ -1144,7 +1169,7 @@ class CdmUseCase_LicenseWithRenewal : public RenewalTest { LoadLicense(); // Play until just before we expect a renewal to be generated. current_cutoff_ = next_renewal + initial_policy_.renewal_recovery_duration; - AllowPlayback(start_of_playback_, next_renewal, current_cutoff_); + AllowPlayback(start_of_playback_, next_renewal); } protected: @@ -1252,7 +1277,7 @@ TEST_P(CdmUseCase_LicenseWithRenewal, Case4) { TEST_P(CdmUseCase_LicenseWithRenewal, Case5) { uint64_t stop = 0; const uint64_t cutoff = EndOfRentalWindow(); - while (stop <= cutoff) { + while (stop < cutoff) { SleepUntilRenewalNeeded(); RequestRenewal(kShortRenewal); const uint64_t start = CurrentRentalTime(); @@ -1261,6 +1286,10 @@ TEST_P(CdmUseCase_LicenseWithRenewal, Case5) { if (stop >= cutoff) { RenewAndTerminate(start, load_time, cutoff, kShortRenewal); } else { + if (stop + kRoundTripTime >= cutoff) { + // If the next load time intersects the cutoff, back off a little. + stop -= kRoundTripTime; + } RenewAndContinue(start, load_time, stop, kShortRenewal); } } @@ -1280,7 +1309,7 @@ TEST_P(CdmUseCase_LicenseWithRenewal, Case6) { // Change renewal duration, and playing until the end of the rental window. uint64_t stop = 0; const uint64_t cutoff = EndOfRentalWindow(); - while (stop <= cutoff) { + while (stop < cutoff) { SleepUntilRenewalNeeded(); RequestRenewal(kLongRenewal); const uint64_t start = CurrentRentalTime(); @@ -1289,6 +1318,10 @@ TEST_P(CdmUseCase_LicenseWithRenewal, Case6) { if (stop >= cutoff) { RenewAndTerminate(start, load_time, cutoff, kLongRenewal); } else { + if (stop + kRoundTripTime >= cutoff) { + // If the next load time intersects the cutoff, back off a little. + stop -= kRoundTripTime; + } RenewAndContinue(start, load_time, stop, kLongRenewal); } } @@ -1305,15 +1338,6 @@ TEST_P(CdmUseCase_LicenseWithRenewal, Case7) { const uint64_t stop = load_time + kShortRenewal.renewal_delay; RenewAndContinue(start, load_time, stop, kShortRenewal); } - // Change renewal duration, and playing until the end of the rental window. - for (int i = 0; i < 2; i++) { - SleepUntilRenewalNeeded(); - RequestRenewal(kLongRenewal); - const uint64_t start = CurrentRentalTime(); - const uint64_t load_time = start + kRoundTripTime; - const uint64_t stop = load_time + kLongRenewal.renewal_delay; - RenewAndContinue(start, load_time, stop, kLongRenewal); - } // We attempt to continue playing beyond the renewal cutoff. SleepUntilRenewalNeeded(); RequestRenewal(kLongRenewal); @@ -1333,9 +1357,9 @@ class CdmUseCase_LicenseWithRenewalPlayback : public RenewalTest { CdmUseCase_LicenseWithRenewalPlayback() : RenewalTest("CDM_LicenseWithRenewal_playback") { timer_limits_.soft_enforce_rental_duration = false; - timer_limits_.total_playback_duration_seconds = 360u; - initial_policy_.renewal_delay = 25u; - initial_policy_.renewal_recovery_duration = 15u; + timer_limits_.total_playback_duration_seconds = 180u; + initial_policy_.renewal_delay = 15u; + initial_policy_.renewal_recovery_duration = 10u; timer_limits_.initial_renewal_duration_seconds = initial_policy_.renewal_delay + initial_policy_.renewal_recovery_duration; @@ -1349,7 +1373,7 @@ class CdmUseCase_LicenseWithRenewalPlayback : public RenewalTest { LoadLicense(); // Play until just before we expect a renewal to be generated. current_cutoff_ = next_renewal + initial_policy_.renewal_recovery_duration; - AllowPlayback(start_of_playback_, next_renewal, current_cutoff_); + AllowPlayback(start_of_playback_, next_renewal); } protected: @@ -1457,7 +1481,7 @@ TEST_P(CdmUseCase_LicenseWithRenewalPlayback, Case4) { TEST_P(CdmUseCase_LicenseWithRenewalPlayback, Case5) { uint64_t stop = 0; const uint64_t cutoff = EndOfPlaybackWindow(); - while (stop <= cutoff) { + while (stop < cutoff) { SleepUntilRenewalNeeded(); RequestRenewal(kShortRenewal); const uint64_t start = CurrentRentalTime(); @@ -1466,6 +1490,10 @@ TEST_P(CdmUseCase_LicenseWithRenewalPlayback, Case5) { if (stop >= cutoff) { RenewAndTerminate(start, load_time, cutoff, kShortRenewal); } else { + if (stop + kRoundTripTime >= cutoff) { + // If the next load time intersects the cutoff, back off a little. + stop -= kRoundTripTime; + } RenewAndContinue(start, load_time, stop, kShortRenewal); } } @@ -1485,7 +1513,7 @@ TEST_P(CdmUseCase_LicenseWithRenewalPlayback, Case6) { // Change renewal duration, and playing until the end of the rental window. uint64_t stop = 0; const uint64_t cutoff = EndOfPlaybackWindow(); - while (stop <= cutoff) { + while (stop < cutoff) { SleepUntilRenewalNeeded(); RequestRenewal(kLongRenewal); const uint64_t start = CurrentRentalTime(); @@ -1494,6 +1522,10 @@ TEST_P(CdmUseCase_LicenseWithRenewalPlayback, Case6) { if (stop >= cutoff) { RenewAndTerminate(start, load_time, cutoff, kLongRenewal); } else { + if (stop + kRoundTripTime >= cutoff) { + // If the next load time intersects the cutoff, back off a little. + stop -= kRoundTripTime; + } RenewAndContinue(start, load_time, stop, kLongRenewal); } } @@ -1510,15 +1542,6 @@ TEST_P(CdmUseCase_LicenseWithRenewalPlayback, Case7) { const uint64_t stop = load_time + kShortRenewal.renewal_delay; RenewAndContinue(start, load_time, stop, kShortRenewal); } - // Change renewal duration, and playing until the end of the rental window. - for (int i = 0; i < 2; i++) { - SleepUntilRenewalNeeded(); - RequestRenewal(kLongRenewal); - const uint64_t start = CurrentRentalTime(); - const uint64_t load_time = start + kRoundTripTime; - const uint64_t stop = load_time + kLongRenewal.renewal_delay; - RenewAndContinue(start, load_time, stop, kLongRenewal); - } // We attempt to continue playing beyond the renewal cutoff. SleepUntilRenewalNeeded(); RequestRenewal(kLongRenewal); @@ -1538,16 +1561,16 @@ class CdmUseCase_LimitedDurationLicense : public RenewalTest { CdmUseCase_LimitedDurationLicense() : RenewalTest("CDM_LimitedDurationLicense") { renewal_delay_ = 5u; - renewal_recovery_ = 55; + renewal_recovery_ = 15; // Pick a start of playback that is within the rental window, but so that // the initial renewal window is after rental window. - start_of_playback_ = 100; + start_of_playback_ = 10; timer_limits_.soft_enforce_rental_duration = true; - timer_limits_.rental_duration_seconds = 120; // 15 minutes. + timer_limits_.rental_duration_seconds = 15; // 15 minutes. timer_limits_.soft_enforce_playback_duration = false; - timer_limits_.total_playback_duration_seconds = 300; // --> 12 hours. + timer_limits_.total_playback_duration_seconds = 60; // --> 12 hours. timer_limits_.initial_renewal_duration_seconds = renewal_delay_ + renewal_recovery_; @@ -1563,14 +1586,16 @@ class CdmUseCase_LimitedDurationLicense : public RenewalTest { // Playback started within rental window and continues. TEST_P(CdmUseCase_LimitedDurationLicense, Case1) { // Allow playback within the initial renewal window. - LoadAndAllowPlayback(start_of_playback_, renewal_load_time_ - kRoundTripTime, - current_cutoff_); + LoadAndAllowPlayback(start_of_playback_, renewal_load_time_ - kRoundTripTime); SleepUntilRenewalNeeded(); RequestRenewal(kLDLRenewal); - // Continue playback for one hour (use 100 to condense test). - const uint64_t end_of_hour = renewal_load_time_ + 100; + // Continue playback until after renewal cutoff. + const uint64_t end_of_play = renewal_load_time_ + kPlayDuration; + const uint64_t cutoff = + start_of_playback_ + renewal_delay_ + renewal_recovery_; + ASSERT_GT(end_of_play, cutoff); const uint64_t start = CurrentRentalTime(); - RenewAndContinue(start, renewal_load_time_, end_of_hour, kLDLRenewal); + RenewAndContinue(start, renewal_load_time_, end_of_play, kLDLRenewal); } // Playback started after rental duration should fail. @@ -1591,8 +1616,7 @@ TEST_P(CdmUseCase_LimitedDurationLicense, Case3) { // continues. TEST_P(CdmUseCase_LimitedDurationLicense, Case4) { // Allow playback within the initial renewal window. - LoadAndAllowPlayback(start_of_playback_, renewal_load_time_ - kRoundTripTime, - current_cutoff_); + LoadAndAllowPlayback(start_of_playback_, renewal_load_time_ - kRoundTripTime); SleepUntilRenewalNeeded(); RequestRenewal(kLDLRenewal); const uint64_t start = CurrentRentalTime(); @@ -1603,25 +1627,179 @@ TEST_P(CdmUseCase_LimitedDurationLicense, Case4) { // Playback may be restarted. TEST_P(CdmUseCase_LimitedDurationLicense, Case5) { // Allow playback within the initial renewal window. - LoadAndAllowPlayback(start_of_playback_, renewal_load_time_ - kRoundTripTime, - current_cutoff_); + LoadAndAllowPlayback(start_of_playback_, renewal_load_time_ - kRoundTripTime); SleepUntilRenewalNeeded(); RequestRenewal(kLDLRenewal); // Continue playback for one hour (use 100 to condense test). - const uint64_t end_of_hour = renewal_load_time_ + 100; + const uint64_t end_of_play = renewal_load_time_ + kPlayDuration; const uint64_t start = CurrentRentalTime(); - RenewAndContinue(start, renewal_load_time_, end_of_hour, kLDLRenewal); + RenewAndContinue(start, renewal_load_time_, end_of_play, kLDLRenewal); UnloadLicense(); // Simulate reloading the license, and then reloading the renewal, and then // restarting playback. That is allowed, and playback shall be terminated at // the end of the original playback window. - const uint64_t reload_time = end_of_hour + 100; + const uint64_t reload_time = end_of_play + kPlayDuration; ReloadAndAllowPlayback(reload_time, EndOfPlaybackWindow(), kLDLRenewal); // But not beyond playback window. SleepUntil(EndOfPlaybackWindow() + 3 * kFudge); FailDecrypt(); } +/*****************************************************************************/ +// The unlimited streaming case has no limits on license use. This use case is +// not in the documentation because it is not recommended. +class CdmUseCase_UnlimitedStreaming : public CdmDurationTest { + public: + CdmUseCase_UnlimitedStreaming() : CdmDurationTest("CDM_UnlimitedStreaming") { + timer_limits_.rental_duration_seconds = 0; + timer_limits_.total_playback_duration_seconds = 0; + } +}; + +// Playback within rental duration. +TEST_P(CdmUseCase_UnlimitedStreaming, Case1) { + // Allow playback within the rental window. + LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + kPlayDuration); +} + +// Playback with stops/restarts within rental duration, last one exceeds rental +// duration. +TEST_P(CdmUseCase_UnlimitedStreaming, Case3) { + LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + kPlayDuration); + UnloadLicense(); + LoadAndAllowPlayback(start_of_playback_ + 2 * kPlayDuration, + start_of_playback_ + 3 * kPlayDuration); +} + +INSTANTIATE_TEST_CASE_P(Both, CdmUseCase_UnlimitedStreaming, + ::testing::Values(false, true)); + +/*****************************************************************************/ +// Some content providers set the license duration instead of the rental +// duration. The test behavior should be the same on the device. This use case +// is not in the documentation because it is not recommended. +class CdmUseCase_LicenseDuration : public CdmDurationTest { + public: + CdmUseCase_LicenseDuration() : CdmDurationTest("CDM_LicenseDuration") { + // Rental duration = 3 hours hard. (use 300 for readability) + // Playback duration = 0 (unlimited) + timer_limits_.soft_enforce_rental_duration = true; + timer_limits_.rental_duration_seconds = 40u; + timer_limits_.soft_enforce_playback_duration = false; + timer_limits_.total_playback_duration_seconds = 40u; + } +}; + +// Playback within rental duration. +TEST_P(CdmUseCase_LicenseDuration, Case1) { + // Allow playback within the playback window. + LoadAndAllowPlayback(start_of_playback_, EndOfPlaybackWindow()); +} + +// Playback exceeds rental duration. +TEST_P(CdmUseCase_LicenseDuration, Case2) { + // Allow playback within the playback window, but not beyond. + LoadAndTerminatePlayback(start_of_playback_, EndOfPlaybackWindow()); +} + +// Playback with stops/restarts within rental duration, last one exceeds +// playback duration. +TEST_P(CdmUseCase_LicenseDuration, Case3) { + LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + kPlayDuration); + UnloadLicense(); + LoadAndAllowPlayback(start_of_playback_ + 2 * kPlayDuration, + start_of_playback_ + 3 * kPlayDuration); + UnloadLicense(); + AllowLenience(); + LoadAndTerminatePlayback(start_of_playback_ + 4 * kPlayDuration, + EndOfPlaybackWindow()); +} + +// Playback within rental duration, restart exceeds playback duration. +TEST_P(CdmUseCase_LicenseDuration, Case4) { + LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + kPlayDuration); + UnloadLicense(); + ForbidPlayback(EndOfPlaybackWindow() + kFudge); +} + +// Initial playback exceeds rental duration. +TEST_P(CdmUseCase_LicenseDuration, Case5) { + ForbidPlayback(EndOfRentalWindow() + kFudge); +} + +// This use case is not documented because we don't recommend having a renewal +// with an infinite duration. However, some content providers use this policy, +// so we want to verify that we support it correctly. +class CdmUseCase_InfiniteRenewal : public RenewalTest { + public: + CdmUseCase_InfiniteRenewal() : RenewalTest("CDM_InfiniteRenewal") { + timer_limits_.soft_enforce_rental_duration = false; + timer_limits_.rental_duration_seconds = 50u; + timer_limits_.total_playback_duration_seconds = 0; + } +}; + +// The renewal interval is infinite. We never need to load the renewal. +TEST_P(CdmUseCase_InfiniteRenewal, NoRenewal) { + LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + kPlayDuration); + SleepUntil(EndOfRentalWindow() + kPlayDuration); + FailDecrypt(); +} + +// If we do load the renewal, the playback window still cuts off playback. +TEST_P(CdmUseCase_InfiniteRenewal, WithRenewal) { + LoadAndAllowPlayback(start_of_playback_, start_of_playback_ + kPlayDuration); + RequestRenewal(kInfiniteRenewal); + const uint64_t start = start_of_playback_ + 2 * kPlayDuration; + const uint64_t load_time = start + kRoundTripTime; + const uint64_t cutoff = EndOfRentalWindow(); + RenewAndTerminate(start, load_time, cutoff, kInfiniteRenewal); +} + +// If we load the renewal before playback starts, then the rental window still +// cuts off playback. +TEST_P(CdmUseCase_InfiniteRenewal, RenewBeforePlayback) { + LoadLicense(); + RequestRenewal(kInfiniteRenewal); + LoadRenewal(start_of_playback_, kInfiniteRenewal); + AllowPlayback(start_of_playback_, start_of_playback_ + 2 * kPlayDuration); + SleepUntil(EndOfRentalWindow() + kPlayDuration); + FailDecrypt(); +} + +// This use case is not documented because we don't recommend specifying the +// license duration instead of rental or playback duration. However, some +// content providers use this policy, so we want to verify that we support it +// correctly. +class CdmUseCase_LicenseDurationWithRenewal : public RenewalTest { + public: + CdmUseCase_LicenseDurationWithRenewal() + : RenewalTest("CDM_LicenseDurationWithRenewal") { + timer_limits_.soft_enforce_rental_duration = true; + timer_limits_.rental_duration_seconds = 30u; + timer_limits_.total_playback_duration_seconds = 0; + } +}; + +// If we do load the renewal, we may continue playback past original window. +TEST_P(CdmUseCase_LicenseDurationWithRenewal, WithRenewal) { + LoadAndAllowPlayback( + start_of_playback_, + start_of_playback_ + kLicenseDurationWithRenewal.renewal_delay); + // Play through four renewals, which should be past the rental window. + for (int i = 0; i < 4; i++) { + SleepUntilRenewalNeeded(); + RequestRenewal(kLicenseDurationWithRenewal); + const uint64_t start = CurrentRentalTime(); + const uint64_t load_time = start + kRoundTripTime; + const uint64_t stop = load_time + kLicenseDurationWithRenewal.renewal_delay; + RenewAndContinue(start, load_time, stop, kLicenseDurationWithRenewal); + } + // Expect that renewals did let us play past the rental window. + EXPECT_GT(CurrentRentalTime(), EndOfRentalWindow() + kPlayDuration); +} + +/***********************************************************************/ // All duration tests are parameterized by can_persist = true or false. INSTANTIATE_TEST_CASE_P(Both, CdmUseCase_LicenseWithRenewal, ::testing::Values(false, true)); @@ -1629,4 +1807,11 @@ INSTANTIATE_TEST_CASE_P(Both, CdmUseCase_LicenseWithRenewalPlayback, ::testing::Values(false, true)); INSTANTIATE_TEST_CASE_P(Both, CdmUseCase_LimitedDurationLicense, ::testing::Values(false, true)); +INSTANTIATE_TEST_CASE_P(Both, CdmUseCase_InfiniteRenewal, + ::testing::Values(false, true)); +INSTANTIATE_TEST_CASE_P(Both, CdmUseCase_LicenseDuration, + ::testing::Values(false, true)); +INSTANTIATE_TEST_CASE_P(Both, CdmUseCase_LicenseDurationWithRenewal, + ::testing::Values(false, true)); + } // namespace wvcdm