odk: core serialization structs & functions
odk directory copied from wvgerrit. branch oemcrypto-v16 commit 0c9a7dc Bug: 140758896 Test: odk_test Change-Id: I0c631f771b794468a63e4395f6b9c3b60a1dfd4f
This commit is contained in:
936
libwvdrmengine/oemcrypto/odk/test/odk_timer_test.cpp
Normal file
936
libwvdrmengine/oemcrypto/odk/test/odk_timer_test.cpp
Normal file
@@ -0,0 +1,936 @@
|
||||
/*
|
||||
* 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 description, 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
|
||||
Reference in New Issue
Block a user