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