This commit contains the updated v16.1 documentation dated Nov 12th, as well has the headers and update ODK library. Unit tests and reference code is partially implemented, but not yet complete.
937 lines
43 KiB
C++
937 lines
43 KiB
C++
/*
|
|
* Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary
|
|
* source code may only be used and distributed under the Widevine Master
|
|
* License Agreement.
|
|
*/
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include "odk.h"
|
|
|
|
using ::testing::tuple;
|
|
using ::testing::Values;
|
|
using ::testing::WithParamInterface;
|
|
|
|
namespace {
|
|
constexpr uint64_t kTolerance = 1; // Allow 1 second of roundoff.
|
|
} // namespace
|
|
|
|
namespace odk_test {
|
|
struct ServerExpiry {
|
|
bool soft_rental;
|
|
bool soft_playback;
|
|
};
|
|
|
|
TEST(OdkTimerBasicTest, NullTest) {
|
|
// Assert that nullptr does not cause a core dump.
|
|
ODK_InitializeClockValues(nullptr, 0u);
|
|
ODK_ReloadClockValues(nullptr, 0u, 0u, 0u, kActive, 0u);
|
|
ODK_AttemptFirstPlayback(0u, nullptr, nullptr, nullptr);
|
|
ODK_UpdateLastPlaybackTime(0, nullptr, nullptr);
|
|
ASSERT_TRUE(true);
|
|
}
|
|
|
|
TEST(OdkTimerBasicTest, Init) {
|
|
// Verify that basic initialization sets all of the fields.
|
|
ODK_ClockValues clock_values;
|
|
uint64_t time = 42;
|
|
ODK_InitializeClockValues(&clock_values, time);
|
|
EXPECT_EQ(clock_values.time_of_license_signed, time);
|
|
EXPECT_EQ(clock_values.time_of_first_decrypt, 0);
|
|
EXPECT_EQ(clock_values.time_of_last_decrypt, 0);
|
|
EXPECT_EQ(clock_values.time_when_timer_expires, 0);
|
|
EXPECT_EQ(clock_values.timer_status, 0);
|
|
EXPECT_EQ(clock_values.status, kUnused);
|
|
}
|
|
|
|
TEST(OdkTimerBasicTest, Reload) {
|
|
// Verify that reloading clock values uses the same values
|
|
// for fields that can be saved, and sets others to 0.
|
|
ODK_ClockValues clock_values;
|
|
uint64_t time = 42u;
|
|
uint64_t lic_signed = 1u;
|
|
uint64_t first_decrypt = 2u;
|
|
uint64_t last_decrypt = 3u;
|
|
enum OEMCrypto_Usage_Entry_Status status = kInactiveUsed;
|
|
ODK_ReloadClockValues(&clock_values, lic_signed, first_decrypt, last_decrypt,
|
|
status, time);
|
|
EXPECT_EQ(clock_values.time_of_license_signed, lic_signed);
|
|
EXPECT_EQ(clock_values.time_of_first_decrypt, first_decrypt);
|
|
EXPECT_EQ(clock_values.time_of_last_decrypt, last_decrypt);
|
|
EXPECT_EQ(clock_values.time_when_timer_expires, 0u);
|
|
EXPECT_EQ(clock_values.timer_status, 0u);
|
|
EXPECT_EQ(clock_values.status, status);
|
|
}
|
|
|
|
// ************************************************************************
|
|
// Test that we can only start playback within the rental window. This
|
|
// simulates requesting a license at rental_clock_start_, and a rental window of
|
|
// 50-150s relative to license request, or 100-200s absolute.
|
|
class OdkTimerRentalWindow : public ::testing::Test {
|
|
public:
|
|
OdkTimerRentalWindow() {
|
|
rental_clock_start_ = 10000u;
|
|
rental_window_start_ = 50u;
|
|
rental_window_duration_ = 100u;
|
|
}
|
|
|
|
protected:
|
|
void SetUp() override {
|
|
::testing::Test::SetUp();
|
|
// Start rental clocks at rental_clock_start_.
|
|
ODK_InitializeClockValues(&clock_values_, rental_clock_start_);
|
|
// Simple license values:
|
|
timer_limits_.soft_expiry = false;
|
|
timer_limits_.earliest_playback_start_seconds = rental_window_start_;
|
|
timer_limits_.latest_playback_start_seconds =
|
|
rental_window_start_ + rental_window_duration_;
|
|
timer_limits_.initial_playback_duration_seconds = 0;
|
|
timer_limits_.renewal_playback_duration_seconds = 0;
|
|
timer_limits_.license_duration_seconds = 0;
|
|
}
|
|
|
|
// Simulate reloading a license in a new session. An offline license should
|
|
// have several of the clock_value's fields saved into the usage table. When
|
|
// it is reloaded those values should be reloaded. From these fields, the
|
|
// ODK function can tell if this is the first playback for the license, or
|
|
// just the first playback for this session. The key fields that should be
|
|
// saved are the status, and the times for license signed, and first and
|
|
// last playback times.
|
|
void ReloadClock(uint64_t system_time) {
|
|
ODK_ClockValues old_clock_values = clock_values_;
|
|
// First clear out the old clock values.
|
|
ODK_InitializeClockValues(&clock_values_, 0u);
|
|
ODK_ReloadClockValues(&clock_values_,
|
|
old_clock_values.time_of_license_signed,
|
|
old_clock_values.time_of_first_decrypt,
|
|
old_clock_values.time_of_last_decrypt,
|
|
old_clock_values.status, system_time);
|
|
}
|
|
|
|
uint64_t system_time(uint64_t rental_clock) {
|
|
return rental_clock_start_ + rental_clock;
|
|
}
|
|
|
|
ODK_TimerLimits timer_limits_;
|
|
ODK_ClockValues clock_values_;
|
|
|
|
// The rental clock starts when the request is signed.
|
|
uint64_t rental_clock_start_;
|
|
// start of rental window in seconds since rental clock start.
|
|
uint64_t rental_window_start_;
|
|
// The "width" of window.
|
|
uint64_t rental_window_duration_;
|
|
};
|
|
|
|
TEST_F(OdkTimerRentalWindow, EarlyTest) {
|
|
uint64_t timer_value = 0;
|
|
// An attempt to start playback before the timer starts is an error.
|
|
// We use the TIMER_EXPIRED error to mean both early or late.
|
|
const uint64_t bad_start_time =
|
|
system_time(timer_limits_.earliest_playback_start_seconds - 10);
|
|
EXPECT_EQ(ODK_TIMER_EXPIRED,
|
|
ODK_AttemptFirstPlayback(bad_start_time, &timer_limits_,
|
|
&clock_values_, &timer_value));
|
|
const uint64_t good_start_time =
|
|
system_time(timer_limits_.earliest_playback_start_seconds);
|
|
EXPECT_EQ(ODK_DISABLE_TIMER,
|
|
ODK_AttemptFirstPlayback(good_start_time, &timer_limits_,
|
|
&clock_values_, &timer_value));
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
EXPECT_EQ(good_start_time, clock_values_.time_of_first_decrypt);
|
|
EXPECT_EQ(good_start_time, clock_values_.time_of_last_decrypt);
|
|
EXPECT_EQ(0, clock_values_.time_when_timer_expires);
|
|
}
|
|
|
|
TEST_F(OdkTimerRentalWindow, NullTimer) {
|
|
// If OEMCrypto passes in a nullpointer, then the ODK should allow this.
|
|
uint64_t* timer_value_pointer = nullptr;
|
|
const uint64_t bad_start_time =
|
|
system_time(timer_limits_.earliest_playback_start_seconds - 10);
|
|
EXPECT_EQ(ODK_TIMER_EXPIRED,
|
|
ODK_AttemptFirstPlayback(bad_start_time, &timer_limits_,
|
|
&clock_values_, timer_value_pointer));
|
|
const uint64_t good_start_time =
|
|
system_time(timer_limits_.earliest_playback_start_seconds);
|
|
EXPECT_EQ(ODK_DISABLE_TIMER,
|
|
ODK_AttemptFirstPlayback(good_start_time, &timer_limits_,
|
|
&clock_values_, timer_value_pointer));
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
EXPECT_EQ(good_start_time, clock_values_.time_of_first_decrypt);
|
|
EXPECT_EQ(good_start_time, clock_values_.time_of_last_decrypt);
|
|
EXPECT_EQ(0, clock_values_.time_when_timer_expires);
|
|
}
|
|
|
|
// Verify that an attempt to start playback outside the rental window fails.
|
|
TEST_F(OdkTimerRentalWindow, LateTest) {
|
|
uint64_t timer_value = 0;
|
|
// An attempt to start playback before the timer starts is an error.
|
|
// We use the TIMER_EXPIRED error to mean both early or late.
|
|
const uint64_t start_time = system_time(201);
|
|
EXPECT_EQ(ODK_TIMER_EXPIRED,
|
|
ODK_AttemptFirstPlayback(start_time, &timer_limits_, &clock_values_,
|
|
&timer_value));
|
|
EXPECT_EQ(kUnused, clock_values_.status);
|
|
}
|
|
|
|
// ************************************************************************
|
|
// The Hard Rental use case is a strict time limit on playback.
|
|
class OdkTimerHardTest : public OdkTimerRentalWindow {
|
|
protected:
|
|
void SetUp() override {
|
|
OdkTimerRentalWindow::SetUp();
|
|
timer_limits_.soft_expiry = false; // Hard expiry.
|
|
// License duration is 200. The license starts when it was signed at 50,
|
|
// so the license is valid from 50-250. The rental window is 100-200 -- as
|
|
// inherited from the ODKRentalWindow class.
|
|
timer_limits_.license_duration_seconds = 200u;
|
|
}
|
|
};
|
|
|
|
TEST_F(OdkTimerHardTest, EarlyTest) {
|
|
uint64_t timer_value = 0;
|
|
// An attempt to start playback before the timer starts is an error.
|
|
// We use the TIMER_EXPIRED error to mean both early or late.
|
|
const uint64_t bad_start_time =
|
|
system_time(timer_limits_.earliest_playback_start_seconds - 10);
|
|
EXPECT_EQ(ODK_TIMER_EXPIRED,
|
|
ODK_AttemptFirstPlayback(bad_start_time, &timer_limits_,
|
|
&clock_values_, &timer_value));
|
|
EXPECT_EQ(kUnused, clock_values_.status);
|
|
// Starting playback within the window should work.
|
|
const uint64_t start_time =
|
|
system_time(timer_limits_.earliest_playback_start_seconds);
|
|
const uint64_t cutoff_time =
|
|
system_time(timer_limits_.license_duration_seconds);
|
|
// For a soft_expiry = false, we should set a timer.
|
|
EXPECT_EQ(ODK_SET_TIMER,
|
|
ODK_AttemptFirstPlayback(start_time, &timer_limits_, &clock_values_,
|
|
&timer_value));
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
EXPECT_EQ(start_time, clock_values_.time_of_last_decrypt);
|
|
EXPECT_NEAR(cutoff_time, clock_values_.time_when_timer_expires, kTolerance);
|
|
EXPECT_NEAR(cutoff_time - start_time, timer_value, kTolerance);
|
|
}
|
|
|
|
TEST_F(OdkTimerHardTest, NormalTest) {
|
|
uint64_t timer_value = 0;
|
|
// Starting playback within the window should work.
|
|
const uint64_t start_time =
|
|
system_time(timer_limits_.earliest_playback_start_seconds);
|
|
const uint64_t cutoff_time =
|
|
system_time(timer_limits_.license_duration_seconds);
|
|
// For a soft_expiry = false, we should set a timer.
|
|
EXPECT_EQ(ODK_SET_TIMER,
|
|
ODK_AttemptFirstPlayback(start_time, &timer_limits_, &clock_values_,
|
|
&timer_value));
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
EXPECT_EQ(start_time, clock_values_.time_of_last_decrypt);
|
|
EXPECT_NEAR(cutoff_time, clock_values_.time_when_timer_expires, kTolerance);
|
|
EXPECT_NEAR(cutoff_time - start_time, timer_value, kTolerance);
|
|
// Try to play before the cutoff time is valid.
|
|
const uint64_t valid_play_time = cutoff_time - 1;
|
|
// This play time is outside the rental window. We are allowed to continue
|
|
// playback after the rental window expires as long as the first decrypt is
|
|
// within the rental window.
|
|
EXPECT_LE(timer_limits_.latest_playback_start_seconds, valid_play_time);
|
|
EXPECT_EQ(OEMCrypto_SUCCESS,
|
|
ODK_UpdateLastPlaybackTime(valid_play_time, &timer_limits_,
|
|
&clock_values_));
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
// First decrypt should NOT change.
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
// Last decrypt should change.
|
|
EXPECT_EQ(valid_play_time, clock_values_.time_of_last_decrypt);
|
|
EXPECT_NEAR(cutoff_time, clock_values_.time_when_timer_expires, kTolerance);
|
|
// Try to play after the cutoff time is not valid.
|
|
const uint64_t late_play_time = cutoff_time + 1;
|
|
EXPECT_EQ(ODK_TIMER_EXPIRED,
|
|
ODK_UpdateLastPlaybackTime(late_play_time, &timer_limits_,
|
|
&clock_values_));
|
|
// First decrypt should NOT change.
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
// Last decrypt should NOT change because we were not allowed to decrypt.
|
|
EXPECT_EQ(valid_play_time, clock_values_.time_of_last_decrypt);
|
|
EXPECT_NEAR(cutoff_time, clock_values_.time_when_timer_expires, kTolerance);
|
|
}
|
|
|
|
// This verifies that the rental window only affects the first load for the
|
|
// license, not the first load for the session.
|
|
TEST_F(OdkTimerHardTest, Reload) {
|
|
uint64_t timer_value = 0;
|
|
// An attempt to start playback before the timer starts is an error.
|
|
// We use the TIMER_EXPIRED error to mean both early or late.
|
|
EXPECT_EQ(ODK_TIMER_EXPIRED,
|
|
ODK_AttemptFirstPlayback(75, &timer_limits_, &clock_values_,
|
|
&timer_value));
|
|
EXPECT_EQ(kUnused, clock_values_.status);
|
|
// Starting playback within the window should work.
|
|
const uint64_t start_time =
|
|
system_time(timer_limits_.earliest_playback_start_seconds);
|
|
const uint64_t cutoff_time =
|
|
system_time(timer_limits_.license_duration_seconds);
|
|
// For a soft_expiry = false, we should set a timer.
|
|
EXPECT_EQ(ODK_SET_TIMER,
|
|
ODK_AttemptFirstPlayback(start_time, &timer_limits_, &clock_values_,
|
|
&timer_value));
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
EXPECT_EQ(start_time, clock_values_.time_of_last_decrypt);
|
|
EXPECT_NEAR(cutoff_time, clock_values_.time_when_timer_expires, kTolerance);
|
|
EXPECT_NEAR(cutoff_time - start_time, timer_value, kTolerance);
|
|
|
|
// We can restart playback before the cutoff time.
|
|
const uint64_t valid_restart_time = cutoff_time - 10;
|
|
ReloadClock(valid_restart_time);
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
|
|
// This restart is outside the rental window. We are allowed to
|
|
// restart playback after the rental window expires as long as the first
|
|
// decrypt for the license is within the rental window.
|
|
EXPECT_LE(timer_limits_.latest_playback_start_seconds, valid_restart_time);
|
|
EXPECT_EQ(ODK_SET_TIMER,
|
|
ODK_AttemptFirstPlayback(valid_restart_time, &timer_limits_,
|
|
&clock_values_, &timer_value));
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
EXPECT_EQ(valid_restart_time, clock_values_.time_of_last_decrypt);
|
|
EXPECT_NEAR(cutoff_time, clock_values_.time_when_timer_expires, kTolerance);
|
|
EXPECT_NEAR(cutoff_time - valid_restart_time, timer_value, kTolerance);
|
|
|
|
// Try to play before the cutoff time is valid.
|
|
const uint64_t valid_play_time = cutoff_time - 1;
|
|
// This play time is outside the rental window. That means we are allowed
|
|
// to continue playback after the rental window expires as long as the first
|
|
// decrypt is within the rental window.
|
|
EXPECT_LE(timer_limits_.latest_playback_start_seconds, valid_play_time);
|
|
EXPECT_EQ(OEMCrypto_SUCCESS,
|
|
ODK_UpdateLastPlaybackTime(valid_play_time, &timer_limits_,
|
|
&clock_values_));
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
// First decrypt should NOT change.
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
// Last decrypt should change.
|
|
EXPECT_EQ(valid_play_time, clock_values_.time_of_last_decrypt);
|
|
EXPECT_NEAR(cutoff_time, clock_values_.time_when_timer_expires, kTolerance);
|
|
// Try to play after the cutoff time is not valid.
|
|
const uint64_t late_play_time = cutoff_time + 1;
|
|
EXPECT_EQ(ODK_TIMER_EXPIRED,
|
|
ODK_UpdateLastPlaybackTime(late_play_time, &timer_limits_,
|
|
&clock_values_));
|
|
// First decrypt should NOT change.
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
// Last decrypt should NOT change because we were not allowed to decrypt.
|
|
EXPECT_EQ(valid_play_time, clock_values_.time_of_last_decrypt);
|
|
EXPECT_NEAR(cutoff_time, clock_values_.time_when_timer_expires, kTolerance);
|
|
}
|
|
|
|
TEST_F(OdkTimerHardTest, ReloadLate) {
|
|
uint64_t timer_value = 0;
|
|
// Starting playback within the window should work.
|
|
const uint64_t start_time =
|
|
system_time(timer_limits_.earliest_playback_start_seconds);
|
|
const uint64_t cutoff_time =
|
|
system_time(timer_limits_.license_duration_seconds);
|
|
// For a soft_expiry = false, we should set a timer.
|
|
EXPECT_EQ(ODK_SET_TIMER,
|
|
ODK_AttemptFirstPlayback(start_time, &timer_limits_, &clock_values_,
|
|
&timer_value));
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
EXPECT_EQ(start_time, clock_values_.time_of_last_decrypt);
|
|
EXPECT_NEAR(cutoff_time, clock_values_.time_when_timer_expires, kTolerance);
|
|
EXPECT_NEAR(cutoff_time - start_time, timer_value, kTolerance);
|
|
|
|
// We can not restart playback after the cutoff time.
|
|
const uint64_t late_restart_time = cutoff_time + 10;
|
|
ReloadClock(late_restart_time);
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
EXPECT_EQ(ODK_TIMER_EXPIRED,
|
|
ODK_AttemptFirstPlayback(late_restart_time, &timer_limits_,
|
|
&clock_values_, &timer_value));
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
EXPECT_EQ(start_time, clock_values_.time_of_last_decrypt);
|
|
|
|
// Calling UpdateLastPlaybackTimer should not be done, but if it were done,
|
|
// it should also fail.
|
|
EXPECT_EQ(ODK_TIMER_EXPIRED,
|
|
ODK_UpdateLastPlaybackTime(late_restart_time, &timer_limits_,
|
|
&clock_values_));
|
|
// First decrypt should NOT change.
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
// Last decrypt should NOT change because we were not allowed to decrypt.
|
|
EXPECT_EQ(start_time, clock_values_.time_of_last_decrypt);
|
|
}
|
|
|
|
// ************************************************************************
|
|
// The Soft Rental use case is a strict time limit on playback.
|
|
class OdkTimerSoftTest : public OdkTimerRentalWindow {
|
|
protected:
|
|
void SetUp() override {
|
|
OdkTimerRentalWindow::SetUp();
|
|
timer_limits_.soft_expiry = true; // Soft expiry.
|
|
// License duration is 200. The license starts when it was signed at 50,
|
|
// so the license is valid from 50-250. The rental window is 100-200 -- as
|
|
// inherited from the ODKRentalWindow class.
|
|
timer_limits_.license_duration_seconds = 200u;
|
|
}
|
|
};
|
|
|
|
TEST_F(OdkTimerSoftTest, EarlyTest) {
|
|
uint64_t timer_value = 0;
|
|
// An attempt to start playback before the timer starts is an error.
|
|
// We use the TIMER_EXPIRED error to mean both early or late.
|
|
const uint64_t bad_start_time =
|
|
system_time(timer_limits_.earliest_playback_start_seconds - 10);
|
|
EXPECT_EQ(ODK_TIMER_EXPIRED,
|
|
ODK_AttemptFirstPlayback(bad_start_time, &timer_limits_,
|
|
&clock_values_, &timer_value));
|
|
// Starting playback within the window should work.
|
|
const uint64_t start_time =
|
|
system_time(timer_limits_.earliest_playback_start_seconds);
|
|
const uint64_t cutoff_time =
|
|
system_time(timer_limits_.license_duration_seconds);
|
|
// For a soft_expiry = true, we should not set a timer.
|
|
EXPECT_EQ(ODK_DISABLE_TIMER,
|
|
ODK_AttemptFirstPlayback(start_time, &timer_limits_, &clock_values_,
|
|
&timer_value));
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
EXPECT_EQ(start_time, clock_values_.time_of_last_decrypt);
|
|
EXPECT_EQ(0u, clock_values_.time_when_timer_expires);
|
|
}
|
|
|
|
TEST_F(OdkTimerSoftTest, NormalTest) {
|
|
uint64_t timer_value = 0;
|
|
const uint64_t start_time =
|
|
system_time(timer_limits_.earliest_playback_start_seconds);
|
|
const uint64_t cutoff_time =
|
|
system_time(timer_limits_.license_duration_seconds);
|
|
// For a soft_expiry = true, we should not set a timer.
|
|
EXPECT_EQ(ODK_DISABLE_TIMER,
|
|
ODK_AttemptFirstPlayback(start_time, &timer_limits_, &clock_values_,
|
|
&timer_value));
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
EXPECT_EQ(start_time, clock_values_.time_of_last_decrypt);
|
|
EXPECT_EQ(0u, clock_values_.time_when_timer_expires);
|
|
// Try to play before the cutoff time is valid.
|
|
const uint64_t valid_play_time = cutoff_time - 1;
|
|
// This play time is outside the rental window. We are allowed to continue
|
|
// playback after the rental window expires as long as the first decrypt is
|
|
// within the rental window.
|
|
EXPECT_LE(timer_limits_.latest_playback_start_seconds, valid_play_time);
|
|
EXPECT_EQ(OEMCrypto_SUCCESS,
|
|
ODK_UpdateLastPlaybackTime(valid_play_time, &timer_limits_,
|
|
&clock_values_));
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
// First decrypt should NOT change.
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
// Last decrypt should change.
|
|
EXPECT_EQ(valid_play_time, clock_values_.time_of_last_decrypt);
|
|
// Try to play after the cutoff time is still valid for soft expiry.
|
|
const uint64_t late_play_time = cutoff_time + 1;
|
|
EXPECT_EQ(OEMCrypto_SUCCESS,
|
|
ODK_UpdateLastPlaybackTime(late_play_time, &timer_limits_,
|
|
&clock_values_));
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
// First decrypt should NOT change.
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
// Last decrypt should NOT change because we were not allowed to decrypt.
|
|
EXPECT_EQ(late_play_time, clock_values_.time_of_last_decrypt);
|
|
}
|
|
|
|
// This verifies that the rental window only affects the first load for the
|
|
// license, not the first load for the session.
|
|
TEST_F(OdkTimerSoftTest, Reload) {
|
|
uint64_t timer_value = 0;
|
|
// Starting playback within the window should work.
|
|
const uint64_t start_time =
|
|
system_time(timer_limits_.earliest_playback_start_seconds);
|
|
const uint64_t cutoff_time =
|
|
system_time(timer_limits_.license_duration_seconds);
|
|
// For a soft_expiry = true, we should not set a timer.
|
|
EXPECT_EQ(ODK_DISABLE_TIMER,
|
|
ODK_AttemptFirstPlayback(start_time, &timer_limits_, &clock_values_,
|
|
&timer_value));
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
EXPECT_EQ(start_time, clock_values_.time_of_last_decrypt);
|
|
EXPECT_EQ(0, clock_values_.time_when_timer_expires);
|
|
|
|
// We can restart playback before the cutoff time.
|
|
const uint64_t valid_restart_time = cutoff_time - 10;
|
|
ReloadClock(valid_restart_time);
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
|
|
// This restart is outside the rental window. We are allowed to
|
|
// restart playback after the rental window expires as long as the first
|
|
// decrypt for the license is within the rental window.
|
|
EXPECT_LE(timer_limits_.latest_playback_start_seconds, valid_restart_time);
|
|
EXPECT_EQ(ODK_DISABLE_TIMER,
|
|
ODK_AttemptFirstPlayback(valid_restart_time, &timer_limits_,
|
|
&clock_values_, &timer_value));
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
EXPECT_EQ(valid_restart_time, clock_values_.time_of_last_decrypt);
|
|
EXPECT_EQ(0, clock_values_.time_when_timer_expires);
|
|
|
|
// Try to play before the cutoff time is valid.
|
|
const uint64_t valid_play_time = cutoff_time - 1;
|
|
// This play time is outside the rental window. That means we are allowed
|
|
// to continue playback after the rental window expires as long as the first
|
|
// decrypt is within the rental window.
|
|
EXPECT_LE(timer_limits_.latest_playback_start_seconds, valid_play_time);
|
|
EXPECT_EQ(OEMCrypto_SUCCESS,
|
|
ODK_UpdateLastPlaybackTime(valid_play_time, &timer_limits_,
|
|
&clock_values_));
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
// First decrypt should NOT change.
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
// Last decrypt should change.
|
|
EXPECT_EQ(valid_play_time, clock_values_.time_of_last_decrypt);
|
|
EXPECT_EQ(0u, clock_values_.time_when_timer_expires);
|
|
// Try to play after the cutoff time is still valid.
|
|
const uint64_t late_play_time = cutoff_time + 1;
|
|
EXPECT_EQ(OEMCrypto_SUCCESS,
|
|
ODK_UpdateLastPlaybackTime(late_play_time, &timer_limits_,
|
|
&clock_values_));
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
// First decrypt should NOT change.
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
// Last decrypt should change.
|
|
EXPECT_EQ(late_play_time, clock_values_.time_of_last_decrypt);
|
|
EXPECT_EQ(0u, clock_values_.time_when_timer_expires);
|
|
}
|
|
|
|
TEST_F(OdkTimerSoftTest, ReloadLate) {
|
|
uint64_t timer_value = 0;
|
|
// Starting playback within the window should work.
|
|
const uint64_t start_time =
|
|
system_time(timer_limits_.earliest_playback_start_seconds);
|
|
const uint64_t cutoff_time =
|
|
system_time(timer_limits_.license_duration_seconds);
|
|
// For a soft_expiry = true, we should not set a timer.
|
|
EXPECT_EQ(ODK_DISABLE_TIMER,
|
|
ODK_AttemptFirstPlayback(start_time, &timer_limits_, &clock_values_,
|
|
&timer_value));
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
EXPECT_EQ(start_time, clock_values_.time_of_last_decrypt);
|
|
EXPECT_EQ(0u, clock_values_.time_when_timer_expires);
|
|
|
|
// We can not restart playback after the cutoff time.
|
|
const uint64_t late_restart_time = cutoff_time + 10;
|
|
ReloadClock(late_restart_time);
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
EXPECT_EQ(ODK_TIMER_EXPIRED,
|
|
ODK_AttemptFirstPlayback(late_restart_time, &timer_limits_,
|
|
&clock_values_, &timer_value));
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
EXPECT_EQ(start_time, clock_values_.time_of_last_decrypt);
|
|
|
|
// Calling UpdateLastPlaybackTimer should not be done, but if it were done,
|
|
// it should also fail.
|
|
EXPECT_EQ(ODK_TIMER_EXPIRED,
|
|
ODK_UpdateLastPlaybackTime(late_restart_time, &timer_limits_,
|
|
&clock_values_));
|
|
// First decrypt should NOT change.
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
// Last decrypt should NOT change because we were not allowed to decrypt.
|
|
EXPECT_EQ(start_time, clock_values_.time_of_last_decrypt);
|
|
}
|
|
// ************************************************************************
|
|
|
|
// ************************************************************************
|
|
// From the server's point of view, there are two flags that decide soft or
|
|
// hard limits: the rental duration, and the playback duration. From
|
|
// OEMCrypto's point of view, there is only playback duration. A soft or hard
|
|
// rental duration is translated into different rental and license durations.
|
|
// The four test classes below all have a 700 rental window and a 200 playback
|
|
// duration. We'll use the server descritpion, and then set the OEMCrypto
|
|
// restraints in the test SetUp() function. Note, it's easier to use the word
|
|
// "day" but really the rental window is 700 seconds, not 7 days. These tests
|
|
// have some coverage overlap with the ones above, but it is better to have
|
|
// these all grouped together to make sure we cover all of the server team's
|
|
// needs.
|
|
// ************************************************************************
|
|
class Odk7DayTest : public OdkTimerRentalWindow,
|
|
public WithParamInterface<ServerExpiry> {
|
|
public:
|
|
Odk7DayTest() {
|
|
rental_window_duration_ = 700;
|
|
rental_window_start_ = 100u;
|
|
}
|
|
|
|
protected:
|
|
void SetUp() override {
|
|
OdkTimerRentalWindow::SetUp();
|
|
server_expiry_ = GetParam();
|
|
const uint64_t playback_duration = 200;
|
|
// Beginning of rental window. it is unusual to start it in the future,
|
|
// but it is a supported use case, so we'll test it here.
|
|
timer_limits_.earliest_playback_start_seconds = rental_window_start_;
|
|
// The rental window is 700 long.
|
|
timer_limits_.latest_playback_start_seconds =
|
|
timer_limits_.earliest_playback_start_seconds + rental_window_duration_;
|
|
// Playback duration is 200 starting from first playback.
|
|
timer_limits_.initial_playback_duration_seconds = playback_duration;
|
|
if (server_expiry_.soft_rental) {
|
|
// The license duration limits any restart. For soft rental window, the
|
|
// server will set this to the rental end + playback duration.
|
|
// License duration is in seconds since license signed.
|
|
timer_limits_.license_duration_seconds =
|
|
timer_limits_.latest_playback_start_seconds + playback_duration;
|
|
} else {
|
|
// The license duration limits any restart. For hard rental window, the
|
|
// server will set this to the rental end.
|
|
// License duration is in seconds since license signed.
|
|
timer_limits_.license_duration_seconds =
|
|
timer_limits_.latest_playback_start_seconds;
|
|
}
|
|
timer_limits_.soft_expiry = server_expiry_.soft_playback;
|
|
}
|
|
ServerExpiry server_expiry_;
|
|
};
|
|
|
|
TEST_P(Odk7DayTest, StartDay3) {
|
|
uint64_t timer_value = 0;
|
|
// Starting playback within the window should work.
|
|
const uint64_t three_days = 300u;
|
|
const uint64_t start_time = system_time(rental_window_start_ + three_days);
|
|
const uint64_t cutoff_time =
|
|
start_time + timer_limits_.initial_playback_duration_seconds;
|
|
if (server_expiry_.soft_playback) {
|
|
// If the playback expiry is soft, then the timer is disabled.
|
|
EXPECT_EQ(ODK_DISABLE_TIMER,
|
|
ODK_AttemptFirstPlayback(start_time, &timer_limits_,
|
|
&clock_values_, &timer_value));
|
|
} else {
|
|
// If the playback expiry is hard, then the timer should be set.
|
|
EXPECT_EQ(ODK_SET_TIMER,
|
|
ODK_AttemptFirstPlayback(start_time, &timer_limits_,
|
|
&clock_values_, &timer_value));
|
|
EXPECT_NEAR(cutoff_time, clock_values_.time_when_timer_expires, kTolerance);
|
|
EXPECT_NEAR(cutoff_time - start_time, timer_value, kTolerance);
|
|
}
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
EXPECT_EQ(start_time, clock_values_.time_of_last_decrypt);
|
|
// Try to play before the cutoff time is valid.
|
|
const uint64_t valid_play_time = cutoff_time - 50;
|
|
EXPECT_EQ(OEMCrypto_SUCCESS,
|
|
ODK_UpdateLastPlaybackTime(valid_play_time, &timer_limits_,
|
|
&clock_values_));
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
// First decrypt should NOT change.
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
// Last decrypt should change.
|
|
EXPECT_EQ(valid_play_time, clock_values_.time_of_last_decrypt);
|
|
if (!server_expiry_.soft_playback) {
|
|
EXPECT_NEAR(cutoff_time, clock_values_.time_when_timer_expires, kTolerance);
|
|
}
|
|
}
|
|
|
|
TEST_P(Odk7DayTest, StartDay3Reload) {
|
|
uint64_t timer_value = 0;
|
|
// Starting playback within the window should work.
|
|
const uint64_t three_days = 300u;
|
|
const uint64_t start_time = system_time(rental_window_start_ + three_days);
|
|
const uint64_t cutoff_time =
|
|
start_time + timer_limits_.initial_playback_duration_seconds;
|
|
EXPECT_NE(ODK_TIMER_EXPIRED,
|
|
ODK_AttemptFirstPlayback(start_time, &timer_limits_, &clock_values_,
|
|
&timer_value));
|
|
// -----------------------------------------------------------------------
|
|
// Try to reload and play before the cutoff time is valid.
|
|
uint64_t valid_restart_time = cutoff_time - 10;
|
|
ReloadClock(valid_restart_time);
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
if (server_expiry_.soft_playback) {
|
|
// If the playback expiry is soft, then the timer is disabled.
|
|
EXPECT_EQ(ODK_DISABLE_TIMER,
|
|
ODK_AttemptFirstPlayback(valid_restart_time, &timer_limits_,
|
|
&clock_values_, &timer_value));
|
|
} else {
|
|
// If the playback expiry is hard, then the timer should be set.
|
|
EXPECT_EQ(ODK_SET_TIMER,
|
|
ODK_AttemptFirstPlayback(valid_restart_time, &timer_limits_,
|
|
&clock_values_, &timer_value));
|
|
EXPECT_NEAR(cutoff_time, clock_values_.time_when_timer_expires, kTolerance);
|
|
EXPECT_NEAR(cutoff_time - valid_restart_time, timer_value, kTolerance);
|
|
}
|
|
|
|
// Try to play before the cutoff time is valid.
|
|
const uint64_t valid_play_time = cutoff_time - 1;
|
|
EXPECT_EQ(OEMCrypto_SUCCESS,
|
|
ODK_UpdateLastPlaybackTime(valid_play_time, &timer_limits_,
|
|
&clock_values_));
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
// First decrypt should NOT change.
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
// Last decrypt should change.
|
|
EXPECT_EQ(valid_play_time, clock_values_.time_of_last_decrypt);
|
|
if (!server_expiry_.soft_playback) {
|
|
EXPECT_NEAR(cutoff_time, clock_values_.time_when_timer_expires, kTolerance);
|
|
}
|
|
|
|
// Try to play after the cutoff time is valid for soft expiry, but not hard.
|
|
const uint64_t late_play_time = cutoff_time + 1;
|
|
if (server_expiry_.soft_playback) {
|
|
EXPECT_EQ(OEMCrypto_SUCCESS,
|
|
ODK_UpdateLastPlaybackTime(late_play_time, &timer_limits_,
|
|
&clock_values_));
|
|
// Last decrypt should change because we were allowed to decrypt.
|
|
EXPECT_EQ(late_play_time, clock_values_.time_of_last_decrypt);
|
|
} else {
|
|
EXPECT_EQ(ODK_TIMER_EXPIRED,
|
|
ODK_UpdateLastPlaybackTime(late_play_time, &timer_limits_,
|
|
&clock_values_));
|
|
// Last decrypt should NOT change because we were not allowed to decrypt.
|
|
EXPECT_EQ(valid_play_time, clock_values_.time_of_last_decrypt);
|
|
EXPECT_NEAR(cutoff_time, clock_values_.time_when_timer_expires, kTolerance);
|
|
}
|
|
// First decrypt should NOT change for either soft or hard.
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Try to reload after the cutoff time is not valid for soft or hard
|
|
// playback expiry.
|
|
const uint64_t late_restart_time = cutoff_time + 1;
|
|
ReloadClock(late_restart_time);
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
EXPECT_EQ(ODK_TIMER_EXPIRED,
|
|
ODK_AttemptFirstPlayback(late_restart_time, &timer_limits_,
|
|
&clock_values_, &timer_value));
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
|
|
// Calling UpdateLastPlaybackTimer should not be done, but if it were done,
|
|
// it should also fail.
|
|
EXPECT_EQ(ODK_TIMER_EXPIRED,
|
|
ODK_UpdateLastPlaybackTime(late_restart_time, &timer_limits_,
|
|
&clock_values_));
|
|
// First decrypt should NOT change.
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
// Last decrypt should not change.
|
|
if (server_expiry_.soft_playback) {
|
|
EXPECT_EQ(late_play_time, clock_values_.time_of_last_decrypt);
|
|
} else {
|
|
EXPECT_EQ(valid_play_time, clock_values_.time_of_last_decrypt);
|
|
}
|
|
}
|
|
|
|
TEST_P(Odk7DayTest, StartDay6Reload) {
|
|
uint64_t timer_value = 0;
|
|
// Starting playback within the window should work.
|
|
const uint64_t six_days = 600u;
|
|
const uint64_t start_time = system_time(rental_window_start_ + six_days);
|
|
const uint64_t cutoff_time =
|
|
server_expiry_.soft_rental
|
|
?
|
|
// If the rental expiry is soft, we can continue playing and
|
|
// reloading for the full playback duration.
|
|
start_time + timer_limits_.initial_playback_duration_seconds
|
|
// If the rental expiry is hard, we can reload only within the
|
|
// rental window.
|
|
: system_time(timer_limits_.latest_playback_start_seconds);
|
|
// Let's double check that math:
|
|
if (server_expiry_.soft_rental) {
|
|
// If that was not clear, the cutoff = 100 start of window + 600 start time
|
|
// + 200 playback duration...
|
|
EXPECT_EQ(system_time(900u), cutoff_time);
|
|
} else {
|
|
// ...and for hard rental, the cutoff = 100 start of window + 700 rental
|
|
// duration.
|
|
EXPECT_EQ(system_time(800u), cutoff_time);
|
|
}
|
|
|
|
if (server_expiry_.soft_playback) {
|
|
// If the playback expiry is soft, then the timer is disabled.
|
|
EXPECT_EQ(ODK_DISABLE_TIMER,
|
|
ODK_AttemptFirstPlayback(start_time, &timer_limits_,
|
|
&clock_values_, &timer_value));
|
|
} else {
|
|
// If the playback expiry is hard, then the timer should be set.
|
|
EXPECT_EQ(ODK_SET_TIMER,
|
|
ODK_AttemptFirstPlayback(start_time, &timer_limits_,
|
|
&clock_values_, &timer_value));
|
|
EXPECT_NEAR(cutoff_time, clock_values_.time_when_timer_expires, kTolerance);
|
|
EXPECT_NEAR(cutoff_time - start_time, timer_value, kTolerance);
|
|
}
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
EXPECT_EQ(start_time, clock_values_.time_of_last_decrypt);
|
|
// Try to play before the cutoff time is valid.
|
|
uint64_t valid_play_time = cutoff_time - 50;
|
|
EXPECT_EQ(OEMCrypto_SUCCESS,
|
|
ODK_UpdateLastPlaybackTime(valid_play_time, &timer_limits_,
|
|
&clock_values_));
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
// First decrypt should NOT change.
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
// Last decrypt should change.
|
|
EXPECT_EQ(valid_play_time, clock_values_.time_of_last_decrypt);
|
|
if (!server_expiry_.soft_playback) {
|
|
EXPECT_NEAR(cutoff_time, clock_values_.time_when_timer_expires, kTolerance);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Try to reload and play before the cutoff time is valid.
|
|
uint64_t valid_restart_time = cutoff_time - 10;
|
|
ReloadClock(valid_restart_time);
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
if (server_expiry_.soft_playback) {
|
|
// If the playback expiry is soft, then the timer is disabled.
|
|
EXPECT_EQ(ODK_DISABLE_TIMER,
|
|
ODK_AttemptFirstPlayback(valid_restart_time, &timer_limits_,
|
|
&clock_values_, &timer_value));
|
|
} else {
|
|
// If the playback expiry is hard, then the timer should be set.
|
|
EXPECT_EQ(ODK_SET_TIMER,
|
|
ODK_AttemptFirstPlayback(valid_restart_time, &timer_limits_,
|
|
&clock_values_, &timer_value));
|
|
EXPECT_NEAR(cutoff_time, clock_values_.time_when_timer_expires, kTolerance);
|
|
EXPECT_NEAR(cutoff_time - valid_restart_time, timer_value, kTolerance);
|
|
}
|
|
|
|
// Try to play before the cutoff time is valid.
|
|
valid_play_time = cutoff_time - 1;
|
|
EXPECT_EQ(OEMCrypto_SUCCESS,
|
|
ODK_UpdateLastPlaybackTime(valid_play_time, &timer_limits_,
|
|
&clock_values_));
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
// First decrypt should NOT change.
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
// Last decrypt should change.
|
|
EXPECT_EQ(valid_play_time, clock_values_.time_of_last_decrypt);
|
|
if (!server_expiry_.soft_playback) {
|
|
EXPECT_NEAR(cutoff_time, clock_values_.time_when_timer_expires, kTolerance);
|
|
}
|
|
|
|
// Try to play after the cutoff time is valid for soft expiry, but not hard.
|
|
const uint64_t late_play_time = cutoff_time + 1;
|
|
if (server_expiry_.soft_playback) {
|
|
EXPECT_EQ(OEMCrypto_SUCCESS,
|
|
ODK_UpdateLastPlaybackTime(late_play_time, &timer_limits_,
|
|
&clock_values_));
|
|
// Last decrypt should change because we were allowed to decrypt.
|
|
EXPECT_EQ(late_play_time, clock_values_.time_of_last_decrypt);
|
|
} else {
|
|
EXPECT_EQ(ODK_TIMER_EXPIRED,
|
|
ODK_UpdateLastPlaybackTime(late_play_time, &timer_limits_,
|
|
&clock_values_));
|
|
// Last decrypt should NOT change because we were not allowed to decrypt.
|
|
EXPECT_EQ(valid_play_time, clock_values_.time_of_last_decrypt);
|
|
EXPECT_NEAR(cutoff_time, clock_values_.time_when_timer_expires, kTolerance);
|
|
}
|
|
// First decrypt should NOT change for either soft or hard.
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Try to reload after the cutoff time is not valid for soft or hard
|
|
// playback expiry.
|
|
const uint64_t late_restart_time = cutoff_time + 2;
|
|
ReloadClock(late_restart_time);
|
|
EXPECT_EQ(kActive, clock_values_.status);
|
|
EXPECT_EQ(ODK_TIMER_EXPIRED,
|
|
ODK_AttemptFirstPlayback(late_restart_time, &timer_limits_,
|
|
&clock_values_, &timer_value));
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
|
|
// Calling UpdateLastPlaybackTimer should not be done, but if it were done,
|
|
// it should also fail.
|
|
EXPECT_EQ(ODK_TIMER_EXPIRED,
|
|
ODK_UpdateLastPlaybackTime(late_restart_time, &timer_limits_,
|
|
&clock_values_));
|
|
// First decrypt should NOT change.
|
|
EXPECT_EQ(start_time, clock_values_.time_of_first_decrypt);
|
|
// Last decrypt should not change.
|
|
if (server_expiry_.soft_playback) {
|
|
EXPECT_EQ(late_play_time, clock_values_.time_of_last_decrypt);
|
|
} else {
|
|
EXPECT_EQ(valid_play_time, clock_values_.time_of_last_decrypt);
|
|
}
|
|
}
|
|
|
|
// This test explicitly shows the difference between hard and soft rental
|
|
// expiry. This is not an OEMCrypto concept, but it is used on the serer, and
|
|
// this test verifies the logic is handled correctly when we translate it into
|
|
// OEMCrypto concepts.
|
|
TEST_P(Odk7DayTest, StartDay6ReloadDay7) {
|
|
uint64_t timer_value = 0;
|
|
// Starting playback within the window should work.
|
|
const uint64_t six_days = 600u;
|
|
const uint64_t seven_days = 700u;
|
|
const uint64_t start_time = system_time(rental_window_start_ + six_days);
|
|
EXPECT_NE(ODK_TIMER_EXPIRED,
|
|
ODK_AttemptFirstPlayback(start_time, &timer_limits_, &clock_values_,
|
|
&timer_value));
|
|
|
|
// Reload time is 1 second after end of rental window.
|
|
const uint64_t restart_time =
|
|
system_time(timer_limits_.latest_playback_start_seconds + 1);
|
|
ReloadClock(restart_time);
|
|
if (server_expiry_.soft_rental) {
|
|
if (server_expiry_.soft_playback) {
|
|
// If the playback expiry is soft, then the timer is disabled.
|
|
EXPECT_EQ(ODK_DISABLE_TIMER,
|
|
ODK_AttemptFirstPlayback(restart_time, &timer_limits_,
|
|
&clock_values_, &timer_value));
|
|
} else {
|
|
const uint64_t cutoff_time =
|
|
start_time + timer_limits_.initial_playback_duration_seconds;
|
|
// If the playback expiry is hard, then the timer should be set.
|
|
EXPECT_EQ(ODK_SET_TIMER,
|
|
ODK_AttemptFirstPlayback(restart_time, &timer_limits_,
|
|
&clock_values_, &timer_value));
|
|
EXPECT_NEAR(cutoff_time, clock_values_.time_when_timer_expires,
|
|
kTolerance);
|
|
EXPECT_NEAR(cutoff_time - restart_time, timer_value, kTolerance);
|
|
}
|
|
} else {
|
|
// For hard rental expiry, reloading after the rental window fails.
|
|
EXPECT_EQ(ODK_TIMER_EXPIRED,
|
|
ODK_AttemptFirstPlayback(restart_time, &timer_limits_,
|
|
&clock_values_, &timer_value));
|
|
}
|
|
}
|
|
|
|
TEST_P(Odk7DayTest, StartDay8) {
|
|
uint64_t timer_value = 0;
|
|
// Starting playback after the rental window should not work.
|
|
const uint64_t eight_days = 800u;
|
|
const uint64_t start_time = system_time(rental_window_start_ + eight_days);
|
|
EXPECT_EQ(ODK_TIMER_EXPIRED,
|
|
ODK_AttemptFirstPlayback(start_time, &timer_limits_, &clock_values_,
|
|
&timer_value));
|
|
EXPECT_EQ(kUnused, clock_values_.status);
|
|
EXPECT_EQ(0u, clock_values_.time_of_first_decrypt);
|
|
EXPECT_EQ(0u, clock_values_.time_of_last_decrypt);
|
|
// Calling UpdateLastPlaybackTimer should not be done, but if it were done,
|
|
// it should also fail.
|
|
EXPECT_EQ(ODK_TIMER_EXPIRED, ODK_UpdateLastPlaybackTime(
|
|
start_time, &timer_limits_, &clock_values_));
|
|
EXPECT_EQ(kUnused, clock_values_.status);
|
|
EXPECT_EQ(0u, clock_values_.time_of_first_decrypt);
|
|
EXPECT_EQ(0u, clock_values_.time_of_last_decrypt);
|
|
}
|
|
|
|
INSTANTIATE_TEST_CASE_P(OdkSoftHard, Odk7DayTest,
|
|
Values(ServerExpiry({true, true}),
|
|
ServerExpiry({true, false}),
|
|
ServerExpiry({false, true}),
|
|
ServerExpiry({false, false})));
|
|
|
|
// ************************************************************************
|
|
|
|
// ************************************************************************
|
|
// TODO(b/140765031): Cover all tests in Use Cases document.
|
|
// Limited Duration License
|
|
// 7 day with renewal.
|
|
// Streaming with renewal
|
|
// Persistent with renewal
|
|
|
|
} // namespace odk_test
|