Commit 2640f0a9 authored by Henrique Grandinetti's avatar Henrique Grandinetti Committed by Commit Bot

Implement TimeLimitProcessor.

Bug: 823536
Change-Id: If7441ec8bff5fc95af03eb07955ee94b21f46208
Reviewed-on: https://chromium-review.googlesource.com/1095375
Commit-Queue: Henrique Grandinetti <hgrandinetti@google.com>
Reviewed-by: default avatarAlexander Alekseev <alemate@chromium.org>
Reviewed-by: default avatarJacob Dufault <jdufault@chromium.org>
Cr-Commit-Position: refs/heads/master@{#568246}
parent c9829db7
...@@ -7,15 +7,19 @@ ...@@ -7,15 +7,19 @@
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
namespace chromeos { namespace chromeos {
namespace usage_time_limit {
namespace internal { namespace internal {
namespace { namespace {
constexpr char kOverride[] = "overrides";
constexpr char kOverrideAction[] = "action"; constexpr char kOverrideAction[] = "action";
constexpr char kOverrideActionCreatedAt[] = "created_at_millis"; constexpr char kOverrideActionCreatedAt[] = "created_at_millis";
constexpr char kOverrideActionDurationMins[] = "duration_mins"; constexpr char kOverrideActionDurationMins[] = "duration_mins";
constexpr char kOverrideActionLock[] = "LOCK"; constexpr char kOverrideActionLock[] = "LOCK";
constexpr char kOverrideActionSpecificData[] = "action_specific_data"; constexpr char kOverrideActionSpecificData[] = "action_specific_data";
constexpr char kTimeLimitLastUpdatedAt[] = "last_updated_millis"; constexpr char kTimeLimitLastUpdatedAt[] = "last_updated_millis";
constexpr char kTimeWindowLimit[] = "time_window_limit";
constexpr char kTimeUsageLimit[] = "time_usage_limit";
constexpr char kUsageLimitResetAt[] = "reset_at"; constexpr char kUsageLimitResetAt[] = "reset_at";
constexpr char kUsageLimitUsageQuota[] = "usage_quota_mins"; constexpr char kUsageLimitUsageQuota[] = "usage_quota_mins";
constexpr char kWindowLimitEntries[] = "entries"; constexpr char kWindowLimitEntries[] = "entries";
...@@ -28,6 +32,612 @@ constexpr const char* kTimeLimitWeekdays[] = { ...@@ -28,6 +32,612 @@ constexpr const char* kTimeLimitWeekdays[] = {
"sunday", "monday", "tuesday", "wednesday", "sunday", "monday", "tuesday", "wednesday",
"thursday", "friday", "saturday"}; "thursday", "friday", "saturday"};
// Whether a timestamp is inside a window.
bool ContainsTime(base::Time start, base::Time end, base::Time now) {
return now >= start && now < end;
}
// Returns true when a < b. When b is null, this returns false.
bool IsBefore(base::Time a, base::Time b) {
return b.is_null() || a < b;
}
// The UTC midnight for a timestamp.
base::Time UTCMidnight(base::Time time) {
base::Time::Exploded exploded;
time.UTCExplode(&exploded);
exploded.hour = 0;
exploded.minute = 0;
exploded.second = 0;
exploded.millisecond = 0;
base::Time out_time;
if (base::Time::FromUTCExploded(exploded, &out_time))
return out_time;
return time;
}
// Helper class to process the UsageTimeLimit policy.
class UsageTimeLimitProcessor {
public:
UsageTimeLimitProcessor(
base::Optional<internal::TimeWindowLimit> time_window_limit,
base::Optional<internal::TimeUsageLimit> time_usage_limit,
base::Optional<internal::Override> override,
const base::TimeDelta& used_time,
const base::Time& usage_timestamp,
const base::Time& current_time,
const base::Optional<State>& previous_state);
~UsageTimeLimitProcessor() = default;
// Current user's session state.
State GetState();
// Expected time when the user's usage quota should be reseted.
base::Time GetExpectedResetTime();
private:
// Get the active time window limit.
base::Optional<internal::TimeWindowLimitEntry> GetActiveTimeWindowLimit();
// Get the active time usage limit.
base::Optional<internal::TimeUsageLimitEntry> GetActiveTimeUsageLimit();
// Get the enabled time usage limit.
base::Optional<internal::TimeUsageLimitEntry> GetEnabledTimeUsageLimit();
// Returns the duration of all the consuctive time window limit starting at
// the given weekday.
base::TimeDelta GetConsecutiveTimeWindowLimitDuration(
internal::Weekday weekday);
// Whether there is a valid override.
bool HasActiveOverride();
// Whether the user's session should be locked.
bool IsLocked();
// Which policy is currently active.
ActivePolicies GetActivePolicy();
// Expected time when the state will change.
base::Time GetNextStateChangeTime(ActivePolicies* out_next_active);
// Whether the time window limit defined in the given weekday is overridden.
bool IsWindowLimitOverridden(internal::Weekday weekday);
// Whether the time usage limit defined in the given weekday is overridden.
bool IsUsageLimitOverridden(internal::Weekday weekday);
// When the lock override should reset.
base::TimeDelta LockOverrideResetTime();
// When the usage limit should reset the usage quota.
base::TimeDelta UsageLimitResetTime();
// Checks if the time window limit entry for the current weekday is active.
bool IsTodayTimeWindowLimitActive();
// Converts the policy time, which is a delta from midnight, to a timestamp.
// Since this is done based on the current time, a shift in days param is
// available.
base::Time ConvertPolicyTime(base::TimeDelta policy_time, int shift_in_days);
// The policy time window limit object.
base::Optional<internal::TimeWindowLimit> time_window_limit;
// The policy time usage limit object.
base::Optional<internal::TimeUsageLimit> time_usage_limit;
// The policy override object.
base::Optional<internal::Override> override;
// How long the user has used the device.
const base::TimeDelta used_time;
// When the used_time data was collected.
const base::Time usage_timestamp;
// The current time, not necessarily equal to usage_timestamp.
const base::Time current_time;
// Current weekday, extracted from current time.
internal::Weekday current_weekday;
// The previous state calculated by this class.
const base::Optional<State>& previous_state;
// The active time window limit. If this is set, it means that the user
// session should be locked, in other words, there is a time window limit set
// for the current day, the current time is inside that window and no unlock
// override is preventing it to be locked.
base::Optional<internal::TimeWindowLimitEntry> active_time_window_limit;
// The active time usage limit. If this is set, it means that the user session
// should be locked, in other words, there is a time usage limit set for the
// current day, the user has used all their usage quota and no unlock override
// is preventing it to be locked.
base::Optional<internal::TimeUsageLimitEntry> active_time_usage_limit;
// If this is set, it means that there is a time usage limit set for today,
// but it is not necessarily active. It could be inactive either because the
// user haven't used all their quota or because there is an unlock override
// active.
base::Optional<internal::TimeUsageLimitEntry> enabled_time_usage_limit;
// Whether there is a window limit overridden.
bool overridden_window_limit = false;
// Whether there is a usage limit overridden.
bool overridden_usage_limit = false;
};
UsageTimeLimitProcessor::UsageTimeLimitProcessor(
base::Optional<internal::TimeWindowLimit> time_window_limit,
base::Optional<internal::TimeUsageLimit> time_usage_limit,
base::Optional<internal::Override> override,
const base::TimeDelta& used_time,
const base::Time& usage_timestamp,
const base::Time& current_time,
const base::Optional<State>& previous_state)
: time_window_limit(std::move(time_window_limit)),
time_usage_limit(std::move(time_usage_limit)),
override(std::move(override)),
used_time(used_time),
usage_timestamp(usage_timestamp),
current_time(current_time),
current_weekday(internal::GetWeekday(current_time)),
previous_state(previous_state),
enabled_time_usage_limit(GetEnabledTimeUsageLimit()) {
// This will also set overridden_window_limit to true if applicable.
active_time_window_limit = GetActiveTimeWindowLimit();
// This will also sets overridden_usage_limit to true if applicable.
active_time_usage_limit = GetActiveTimeUsageLimit();
}
base::Time UsageTimeLimitProcessor::GetExpectedResetTime() {
base::TimeDelta delta_from_midnight =
current_time - UTCMidnight(current_time);
int shift_in_days = 1;
if (delta_from_midnight < UsageLimitResetTime())
shift_in_days = 0;
return ConvertPolicyTime(UsageLimitResetTime(), shift_in_days);
}
State UsageTimeLimitProcessor::GetState() {
State state;
state.is_locked = IsLocked();
state.active_policy = GetActivePolicy();
// Time usage limit is enabled if there is an entry for the current day and it
// is not overridden.
if (enabled_time_usage_limit || active_time_usage_limit) {
state.is_time_usage_limit_enabled = true;
state.remaining_usage =
std::max(enabled_time_usage_limit->usage_quota - used_time,
base::TimeDelta::FromMinutes(0));
}
const base::TimeDelta delta_zero = base::TimeDelta::FromMinutes(0);
// Time usage limit started when the usage quota ends.
if ((previous_state && previous_state->remaining_usage > delta_zero &&
state.remaining_usage <= delta_zero) ||
(!previous_state && state.remaining_usage <= delta_zero)) {
state.time_usage_limit_started = usage_timestamp;
} else if (previous_state && previous_state->remaining_usage <= delta_zero) {
state.time_usage_limit_started = previous_state->time_usage_limit_started;
}
state.next_state_change_time =
GetNextStateChangeTime(&state.next_state_active_policy);
if (!previous_state) {
return state;
}
if (previous_state->is_locked == state.is_locked &&
previous_state->active_policy == state.active_policy) {
state.last_state_changed = previous_state->last_state_changed;
return state;
}
state.last_state_changed = current_time;
return state;
}
base::TimeDelta UsageTimeLimitProcessor::GetConsecutiveTimeWindowLimitDuration(
internal::Weekday weekday) {
base::TimeDelta duration = base::TimeDelta::FromMinutes(0);
base::Optional<internal::TimeWindowLimitEntry> current_day_entry =
time_window_limit->entries[weekday];
if (!time_window_limit || !current_day_entry)
return duration;
// Iterate throught entries as long as they are consecutive, or overlap.
base::TimeDelta last_entry_end = current_day_entry->starts_at;
for (int i = 0; i < static_cast<int>(internal::Weekday::kCount); i++) {
base::Optional<internal::TimeWindowLimitEntry> window_limit_entry =
time_window_limit->entries[internal::WeekdayShift(weekday, i)];
// It is not consecutive.
if (!window_limit_entry || window_limit_entry->starts_at > last_entry_end)
break;
if (window_limit_entry->IsOvernight()) {
duration += base::TimeDelta(base::TimeDelta::FromHours(24) -
window_limit_entry->starts_at) +
base::TimeDelta(window_limit_entry->ends_at);
} else {
duration += base::TimeDelta(window_limit_entry->ends_at -
window_limit_entry->starts_at);
// This entry is not overnight, so the next one cannot be a consecutive
// window.
break;
}
}
return duration;
}
bool UsageTimeLimitProcessor::IsWindowLimitOverridden(
internal::Weekday weekday) {
if (!time_window_limit || !override ||
override->action == internal::Override::Action::kLock) {
return false;
}
base::Optional<internal::TimeWindowLimitEntry> window_limit_entry =
time_window_limit->entries[weekday];
// If the time window limit has been updated since the override, it doesn't
// take effect.
if (!window_limit_entry ||
window_limit_entry->last_updated > override->created_at)
return false;
int days_behind = 0;
for (int i = 0; i < static_cast<int>(internal::Weekday::kCount); i++) {
if (internal::WeekdayShift(weekday, i) == current_weekday) {
days_behind = i;
break;
}
}
base::Time window_limit_start =
ConvertPolicyTime(window_limit_entry->starts_at, -days_behind);
base::Time window_limit_end =
window_limit_start + GetConsecutiveTimeWindowLimitDuration(weekday);
return ContainsTime(window_limit_start, window_limit_end,
override->created_at);
}
bool UsageTimeLimitProcessor::IsUsageLimitOverridden(
internal::Weekday weekday) {
if (!override || override->action == internal::Override::Action::kLock)
return false;
if (!time_usage_limit || !previous_state)
return false;
base::Optional<internal::TimeUsageLimitEntry> usage_limit_entry =
time_usage_limit->entries[weekday];
// If the time usage limit has been updated since the override, it doesn't
// take effect.
if (!usage_limit_entry ||
usage_limit_entry->last_updated > override->created_at)
return false;
bool usage_limit_enforced_previously =
previous_state->is_time_usage_limit_enabled &&
previous_state->remaining_usage <= base::TimeDelta::FromMinutes(0);
bool override_created_after_usage_limit_start =
override->created_at > previous_state->time_usage_limit_started;
return usage_limit_enforced_previously &&
override_created_after_usage_limit_start;
}
base::Optional<internal::TimeWindowLimitEntry>
UsageTimeLimitProcessor::GetActiveTimeWindowLimit() {
if (!time_window_limit)
return base::nullopt;
internal::Weekday previous_weekday =
internal::WeekdayShift(current_weekday, -1);
base::Optional<internal::TimeWindowLimitEntry> previous_day_entry =
time_window_limit->entries[previous_weekday];
// Active time window limit that started on the previous day.
base::Optional<internal::TimeWindowLimitEntry> previous_day_active_entry;
if (previous_day_entry && previous_day_entry->IsOvernight()) {
base::Time limit_start =
ConvertPolicyTime(previous_day_entry->starts_at, -1);
base::Time limit_end = ConvertPolicyTime(previous_day_entry->ends_at, 0);
if (ContainsTime(limit_start, limit_end, current_time)) {
if (IsWindowLimitOverridden(previous_weekday)) {
overridden_window_limit = true;
} else {
previous_day_active_entry = previous_day_entry;
}
}
}
base::Optional<internal::TimeWindowLimitEntry> current_day_entry =
time_window_limit->entries[current_weekday];
// Active time window limit that started today.
base::Optional<internal::TimeWindowLimitEntry> current_day_active_entry;
if (current_day_entry) {
base::Time limit_start = ConvertPolicyTime(current_day_entry->starts_at, 0);
base::Time limit_end = ConvertPolicyTime(
current_day_entry->ends_at, current_day_entry->IsOvernight() ? 1 : 0);
if (ContainsTime(limit_start, limit_end, current_time)) {
if (IsWindowLimitOverridden(current_weekday)) {
overridden_window_limit = true;
} else {
current_day_active_entry = current_day_entry;
}
}
}
if (current_day_active_entry && previous_day_active_entry) {
// If two windows overlap and are active now we must return the one that
// ends later.
if (current_day_active_entry->IsOvernight() ||
current_day_active_entry->ends_at >
previous_day_active_entry->ends_at) {
return current_day_active_entry;
}
return previous_day_active_entry;
}
if (current_day_active_entry)
return current_day_active_entry;
return previous_day_active_entry;
}
base::Optional<internal::TimeUsageLimitEntry>
UsageTimeLimitProcessor::GetEnabledTimeUsageLimit() {
if (!time_usage_limit)
return base::nullopt;
internal::Weekday current_usage_limit_day =
current_time > ConvertPolicyTime(UsageLimitResetTime(), 0)
? current_weekday
: internal::WeekdayShift(current_weekday, -1);
return time_usage_limit->entries[current_usage_limit_day];
}
base::Optional<internal::TimeUsageLimitEntry>
UsageTimeLimitProcessor::GetActiveTimeUsageLimit() {
if (!time_usage_limit)
return base::nullopt;
internal::Weekday current_usage_limit_day =
current_time > ConvertPolicyTime(UsageLimitResetTime(), 0)
? current_weekday
: internal::WeekdayShift(current_weekday, -1);
base::Optional<internal::TimeUsageLimitEntry> current_usage_limit =
GetEnabledTimeUsageLimit();
if (IsUsageLimitOverridden(current_usage_limit_day))
return base::nullopt;
if (current_usage_limit && used_time >= current_usage_limit->usage_quota)
return current_usage_limit;
return base::nullopt;
}
bool UsageTimeLimitProcessor::HasActiveOverride() {
if (!override)
return false;
if (overridden_window_limit || overridden_usage_limit)
return true;
if (!overridden_usage_limit && !overridden_window_limit &&
override->action == internal::Override::Action::kLock)
return true;
return false;
}
bool UsageTimeLimitProcessor::IsLocked() {
return active_time_usage_limit || active_time_window_limit ||
(HasActiveOverride() &&
override->action == internal::Override::Action::kLock);
}
ActivePolicies UsageTimeLimitProcessor::GetActivePolicy() {
if (active_time_window_limit)
return ActivePolicies::kFixedLimit;
if (active_time_usage_limit)
return ActivePolicies::kUsageLimit;
if (HasActiveOverride())
return ActivePolicies::kOverride;
return ActivePolicies::kNoActivePolicy;
}
base::Time UsageTimeLimitProcessor::GetNextStateChangeTime(
ActivePolicies* out_next_active) {
base::Time next_change;
*out_next_active = ActivePolicies::kNoActivePolicy;
// Time when the time_window_limit ends. Only available if there is an
// active time window limit.
base::Time active_time_window_limit_ends;
if (active_time_window_limit) {
base::TimeDelta window_limit_duration =
IsTodayTimeWindowLimitActive()
? GetConsecutiveTimeWindowLimitDuration(current_weekday)
: GetConsecutiveTimeWindowLimitDuration(
internal::WeekdayShift(current_weekday, -1));
active_time_window_limit_ends =
ConvertPolicyTime(active_time_window_limit->starts_at,
IsTodayTimeWindowLimitActive() ? 0 : -1) +
window_limit_duration;
}
// Next time when the usage quota will be reset.
base::Time next_usage_quota_reset;
bool has_reset_today =
current_time - UTCMidnight(current_time) >= UsageLimitResetTime();
next_usage_quota_reset =
ConvertPolicyTime(UsageLimitResetTime(), has_reset_today ? 1 : 0);
// Check when next time window limit starts.
if (time_window_limit) {
internal::Weekday start_day = current_weekday;
if (IsTodayTimeWindowLimitActive())
start_day = internal::WeekdayShift(start_day, 1);
// Search a time window limit in the next following days.
for (int i = 0; i < static_cast<int>(internal::Weekday::kCount); i++) {
base::Optional<internal::TimeWindowLimitEntry> entry =
time_window_limit.value()
.entries[internal::WeekdayShift(start_day, i)];
if (entry) {
int shift = start_day == current_weekday ? 0 : 1;
base::Time start_time = ConvertPolicyTime(entry->starts_at, i + shift);
if (IsBefore(start_time, next_change)) {
next_change = start_time;
*out_next_active = ActivePolicies::kFixedLimit;
}
break;
}
}
}
// Minimum time when the time usage quota could end. Not calculated when
// time usage limit has already finished. If there is no active time usage
// limit on the current day, we search on the following days.
if (time_usage_limit && !active_time_usage_limit && !overridden_usage_limit &&
!active_time_window_limit) {
// If there is an active time usage, we just look when it would lock the
// session if the user don't stop using it.
if (enabled_time_usage_limit) {
base::Time quota_ends =
current_time + (enabled_time_usage_limit->usage_quota - used_time);
if (IsBefore(quota_ends, next_change)) {
next_change = quota_ends;
*out_next_active = ActivePolicies::kUsageLimit;
}
} else {
// Look for the next time usage, and calculate when the minimum time it
// could end.
for (int i = 0; i < static_cast<int>(internal::Weekday::kCount); i++) {
base::Optional<internal::TimeUsageLimitEntry> usage_limit_entry =
time_usage_limit
->entries[internal::WeekdayShift(current_weekday, i)];
if (usage_limit_entry) {
base::Time quota_ends = ConvertPolicyTime(UsageLimitResetTime(), i) +
usage_limit_entry->usage_quota;
if (IsBefore(quota_ends, next_change)) {
next_change = quota_ends;
*out_next_active = ActivePolicies::kUsageLimit;
}
break;
}
}
}
}
// When the current active time window limit ends.
if (active_time_window_limit) {
if (IsBefore(active_time_window_limit_ends, next_change)) {
next_change = active_time_window_limit_ends;
if (active_time_usage_limit &&
used_time >= active_time_usage_limit->usage_quota &&
active_time_window_limit_ends < next_usage_quota_reset) {
*out_next_active = ActivePolicies::kUsageLimit;
} else {
*out_next_active = ActivePolicies::kNoActivePolicy;
}
}
}
// When the usage quota resets. Only calculated if there is an enforced time
// usage limit, and when it ends no other policy would be active.
if (active_time_usage_limit &&
(!active_time_window_limit ||
active_time_window_limit->ends_at < UsageLimitResetTime())) {
if (IsBefore(next_usage_quota_reset, next_change)) {
next_change = next_usage_quota_reset;
*out_next_active = ActivePolicies::kNoActivePolicy;
}
}
// When a lock override will become inactive. Lock overrides are disabled at
// the same time as time usage limit resets.
if (HasActiveOverride() &&
override->action == internal::Override::Action::kLock) {
// Whether this lock override was created after today's reset.
bool lock_after_reset = override->created_at >
UTCMidnight(current_time) + LockOverrideResetTime();
base::Time lock_end =
ConvertPolicyTime(LockOverrideResetTime(), lock_after_reset ? 1 : 0);
if (IsBefore(lock_end, next_change)) {
next_change = lock_end;
if (active_time_window_limit &&
active_time_window_limit_ends > next_usage_quota_reset) {
*out_next_active = ActivePolicies::kFixedLimit;
} else {
*out_next_active = ActivePolicies::kNoActivePolicy;
}
}
}
return next_change;
}
bool UsageTimeLimitProcessor::IsTodayTimeWindowLimitActive() {
if (!time_window_limit)
return false;
base::Optional<internal::TimeWindowLimitEntry> today_window_limit =
time_window_limit->entries[current_weekday];
base::Optional<internal::TimeWindowLimitEntry> yesterday_window_limit =
time_window_limit.value()
.entries[internal::WeekdayShift(current_weekday, -1)];
if ((active_time_window_limit || overridden_window_limit) &&
(!yesterday_window_limit ||
yesterday_window_limit->ends_at < today_window_limit->ends_at)) {
return true;
}
return false;
}
base::TimeDelta UsageTimeLimitProcessor::UsageLimitResetTime() {
if (time_usage_limit)
return time_usage_limit->resets_at;
return base::TimeDelta::FromMinutes(0);
}
base::TimeDelta UsageTimeLimitProcessor::LockOverrideResetTime() {
// The default behavior is to stop enforcing the lock override at the same
// time as the time usage limit resets.
return UsageLimitResetTime();
}
base::Time UsageTimeLimitProcessor::ConvertPolicyTime(
base::TimeDelta policy_time,
int shift_in_days) {
return UTCMidnight(current_time) + base::TimeDelta::FromDays(shift_in_days) +
policy_time;
}
} // namespace } // namespace
// Transforms the time dictionary sent on the UsageTimeLimit policy to a // Transforms the time dictionary sent on the UsageTimeLimit policy to a
...@@ -53,11 +663,6 @@ Weekday GetWeekday(std::string weekday) { ...@@ -53,11 +663,6 @@ Weekday GetWeekday(std::string weekday) {
TimeWindowLimitEntry::TimeWindowLimitEntry() = default; TimeWindowLimitEntry::TimeWindowLimitEntry() = default;
TimeWindowLimitEntry::TimeWindowLimitEntry(TimeWindowLimitEntry&&) = default;
TimeWindowLimitEntry& TimeWindowLimitEntry::operator=(TimeWindowLimitEntry&&) =
default;
bool TimeWindowLimitEntry::IsOvernight() const { bool TimeWindowLimitEntry::IsOvernight() const {
return ends_at < starts_at; return ends_at < starts_at;
} }
...@@ -97,7 +702,7 @@ TimeWindowLimit::TimeWindowLimit(const base::Value& window_limit_dict) { ...@@ -97,7 +702,7 @@ TimeWindowLimit::TimeWindowLimit(const base::Value& window_limit_dict) {
// We only support one time_limit_window per day. If more than one is sent // We only support one time_limit_window per day. If more than one is sent
// we only use the latest updated. // we only use the latest updated.
if (!entries[weekday] || if (!entries[weekday] ||
entries[weekday].value().last_updated < entry.last_updated) { entries[weekday]->last_updated < entry.last_updated) {
entries[weekday] = std::move(entry); entries[weekday] = std::move(entry);
} }
} }
...@@ -111,18 +716,13 @@ TimeWindowLimit& TimeWindowLimit::operator=(TimeWindowLimit&&) = default; ...@@ -111,18 +716,13 @@ TimeWindowLimit& TimeWindowLimit::operator=(TimeWindowLimit&&) = default;
TimeUsageLimitEntry::TimeUsageLimitEntry() = default; TimeUsageLimitEntry::TimeUsageLimitEntry() = default;
TimeUsageLimitEntry::TimeUsageLimitEntry(TimeUsageLimitEntry&&) = default;
TimeUsageLimitEntry& TimeUsageLimitEntry::operator=(TimeUsageLimitEntry&&) =
default;
TimeUsageLimit::TimeUsageLimit(const base::Value& usage_limit_dict) TimeUsageLimit::TimeUsageLimit(const base::Value& usage_limit_dict)
// Default reset time is midnight. // Default reset time is midnight.
: reset_at(base::TimeDelta::FromMinutes(0)) { : resets_at(base::TimeDelta::FromMinutes(0)) {
const base::Value* reset_at_value = const base::Value* resets_at_value =
usage_limit_dict.FindKey(kUsageLimitResetAt); usage_limit_dict.FindKey(kUsageLimitResetAt);
if (reset_at_value) { if (resets_at_value) {
reset_at = ValueToTimeDelta(reset_at_value); resets_at = ValueToTimeDelta(resets_at_value);
} }
for (const std::string& weekday_key : kTimeLimitWeekdays) { for (const std::string& weekday_key : kTimeLimitWeekdays) {
...@@ -194,28 +794,68 @@ Weekday GetWeekday(base::Time time) { ...@@ -194,28 +794,68 @@ Weekday GetWeekday(base::Time time) {
} }
Weekday WeekdayShift(Weekday current_day, int shift) { Weekday WeekdayShift(Weekday current_day, int shift) {
return static_cast<Weekday>(static_cast<int>(current_day) + return static_cast<Weekday>((static_cast<int>(current_day) + shift) %
shift % static_cast<int>(Weekday::kCount)); static_cast<int>(Weekday::kCount));
} }
} // namespace internal } // namespace internal
namespace usage_time_limit { base::Optional<internal::TimeWindowLimit> TimeWindowLimitFromPolicy(
const std::unique_ptr<base::DictionaryValue>& time_limit) {
base::Value* time_window_limit_value =
time_limit->FindKey(internal::kTimeWindowLimit);
if (!time_window_limit_value)
return base::nullopt;
return internal::TimeWindowLimit(*time_window_limit_value);
}
base::Optional<internal::TimeUsageLimit> TimeUsageLimitFromPolicy(
const std::unique_ptr<base::DictionaryValue>& time_limit) {
base::Value* time_usage_limit_value =
time_limit->FindKey(internal::kTimeUsageLimit);
if (!time_usage_limit_value)
return base::nullopt;
return internal::TimeUsageLimit(*time_usage_limit_value);
}
base::Optional<internal::Override> OverrideFromPolicy(
const std::unique_ptr<base::DictionaryValue>& time_limit) {
base::Value* override_value = time_limit->FindKey(internal::kOverride);
if (!override_value)
return base::nullopt;
return internal::Override(*override_value);
}
State GetState(const std::unique_ptr<base::DictionaryValue>& time_limit, State GetState(const std::unique_ptr<base::DictionaryValue>& time_limit,
const base::TimeDelta& used_time, const base::TimeDelta& used_time,
const base::Time& usage_timestamp, const base::Time& usage_timestamp,
const base::Time& current_time, const base::Time& current_time,
const base::Optional<State>& previous_state) { const base::Optional<State>& previous_state) {
// TODO: Implement method. base::Optional<internal::TimeWindowLimit> time_window_limit =
return State(); TimeWindowLimitFromPolicy(time_limit);
base::Optional<internal::TimeUsageLimit> time_usage_limit =
TimeUsageLimitFromPolicy(time_limit);
base::Optional<internal::Override> override = OverrideFromPolicy(time_limit);
return internal::UsageTimeLimitProcessor(
std::move(time_window_limit), std::move(time_usage_limit),
std::move(override), used_time, current_time, current_time,
previous_state)
.GetState();
} }
base::Time GetExpectedResetTime( base::Time GetExpectedResetTime(
const std::unique_ptr<base::DictionaryValue>& time_limit, const std::unique_ptr<base::DictionaryValue>& time_limit,
base::Time current_time) { const base::Time current_time) {
// TODO: Implement this method. base::Optional<internal::TimeWindowLimit> time_window_limit =
return base::Time(); TimeWindowLimitFromPolicy(time_limit);
base::Optional<internal::TimeUsageLimit> time_usage_limit =
TimeUsageLimitFromPolicy(time_limit);
base::Optional<internal::Override> override = OverrideFromPolicy(time_limit);
return internal::UsageTimeLimitProcessor(
std::move(time_window_limit), std::move(time_usage_limit),
std::move(override), base::TimeDelta::FromMinutes(0), base::Time(),
current_time, base::nullopt)
.GetExpectedResetTime();
} }
} // namespace usage_time_limit } // namespace usage_time_limit
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "base/values.h" #include "base/values.h"
namespace chromeos { namespace chromeos {
namespace usage_time_limit {
namespace internal { namespace internal {
enum class Weekday { enum class Weekday {
...@@ -27,11 +28,8 @@ enum class Weekday { ...@@ -27,11 +28,8 @@ enum class Weekday {
kCount, kCount,
}; };
class TimeWindowLimitEntry { struct TimeWindowLimitEntry {
public:
TimeWindowLimitEntry(); TimeWindowLimitEntry();
TimeWindowLimitEntry(TimeWindowLimitEntry&&);
TimeWindowLimitEntry& operator=(TimeWindowLimitEntry&&);
bool IsOvernight() const; bool IsOvernight() const;
...@@ -41,9 +39,6 @@ class TimeWindowLimitEntry { ...@@ -41,9 +39,6 @@ class TimeWindowLimitEntry {
base::TimeDelta ends_at; base::TimeDelta ends_at;
// Last time this entry was updated. // Last time this entry was updated.
base::Time last_updated; base::Time last_updated;
private:
DISALLOW_COPY_AND_ASSIGN(TimeWindowLimitEntry);
}; };
class TimeWindowLimit { class TimeWindowLimit {
...@@ -59,17 +54,11 @@ class TimeWindowLimit { ...@@ -59,17 +54,11 @@ class TimeWindowLimit {
DISALLOW_COPY_AND_ASSIGN(TimeWindowLimit); DISALLOW_COPY_AND_ASSIGN(TimeWindowLimit);
}; };
class TimeUsageLimitEntry { struct TimeUsageLimitEntry {
public:
TimeUsageLimitEntry(); TimeUsageLimitEntry();
TimeUsageLimitEntry(TimeUsageLimitEntry&&);
TimeUsageLimitEntry& operator=(TimeUsageLimitEntry&&);
base::TimeDelta usage_quota; base::TimeDelta usage_quota;
base::Time last_updated; base::Time last_updated;
private:
DISALLOW_COPY_AND_ASSIGN(TimeUsageLimitEntry);
}; };
class TimeUsageLimit { class TimeUsageLimit {
...@@ -80,7 +69,7 @@ class TimeUsageLimit { ...@@ -80,7 +69,7 @@ class TimeUsageLimit {
TimeUsageLimit& operator=(TimeUsageLimit&&); TimeUsageLimit& operator=(TimeUsageLimit&&);
std::unordered_map<Weekday, base::Optional<TimeUsageLimitEntry>> entries; std::unordered_map<Weekday, base::Optional<TimeUsageLimitEntry>> entries;
base::TimeDelta reset_at; base::TimeDelta resets_at;
private: private:
DISALLOW_COPY_AND_ASSIGN(TimeUsageLimit); DISALLOW_COPY_AND_ASSIGN(TimeUsageLimit);
...@@ -111,8 +100,6 @@ Weekday WeekdayShift(Weekday current_day, int shift); ...@@ -111,8 +100,6 @@ Weekday WeekdayShift(Weekday current_day, int shift);
} // namespace internal } // namespace internal
namespace usage_time_limit {
enum class ActivePolicies { enum class ActivePolicies {
kNoActivePolicy, kNoActivePolicy,
kOverride, kOverride,
...@@ -122,7 +109,7 @@ enum class ActivePolicies { ...@@ -122,7 +109,7 @@ enum class ActivePolicies {
struct State { struct State {
// Whether the device is currently locked. // Whether the device is currently locked.
bool is_locked; bool is_locked = false;
// Which policy is responsible for the current state. // Which policy is responsible for the current state.
// If it is locked, one of [ override, fixed_limit, usage_limit ] // If it is locked, one of [ override, fixed_limit, usage_limit ]
...@@ -130,12 +117,18 @@ struct State { ...@@ -130,12 +117,18 @@ struct State {
ActivePolicies active_policy; ActivePolicies active_policy;
// Whether time_usage_limit is currently active. // Whether time_usage_limit is currently active.
bool is_time_usage_limit_enabled; bool is_time_usage_limit_enabled = false;
// Remaining screen usage quota. Only available if // Remaining screen usage quota. Only available if
// is_time_limit_enabled = true // is_time_limit_enabled = true
base::TimeDelta remaining_usage; base::TimeDelta remaining_usage;
// When the time usage limit started being enforced. Only available when
// is_time_usage_limit_enabled = true and remaining_usage is 0, which means
// that the time usage limit is enforced, and therefore should have a start
// time.
base::Time time_usage_limit_started;
// Next epoch time that time limit state could change. This could be the // Next epoch time that time limit state could change. This could be the
// start time of the next fixed window limit, the end time of the current // start time of the next fixed window limit, the end time of the current
// fixed limit, the earliest time a usage limit could be reached, or the // fixed limit, the earliest time a usage limit could be reached, or the
...@@ -146,7 +139,7 @@ struct State { ...@@ -146,7 +139,7 @@ struct State {
ActivePolicies next_state_active_policy; ActivePolicies next_state_active_policy;
// Last time the state changed. // Last time the state changed.
base::Time last_state_changed; base::Time last_state_changed = base::Time();
}; };
// Returns the current state of the user session with the given usage time limit // Returns the current state of the user session with the given usage time limit
...@@ -165,4 +158,4 @@ base::Time GetExpectedResetTime( ...@@ -165,4 +158,4 @@ base::Time GetExpectedResetTime(
} // namespace usage_time_limit } // namespace usage_time_limit
} // namespace chromeos } // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_USAGE_TIME_LIMIT_PROCESSOR_H_ #endif // CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_USAGE_TIME_LIMIT_PROCESSOR_H_
\ No newline at end of file
...@@ -10,55 +10,74 @@ ...@@ -10,55 +10,74 @@
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace chromeos { namespace chromeos {
namespace internal { namespace usage_time_limit {
class UsageTimeLimitProcessorTest : public testing::Test { using UsageTimeLimitProcessorTest = testing::Test;
public:
UsageTimeLimitProcessorTest() {}
~UsageTimeLimitProcessorTest() override = default;
base::Value CreateTime(int hour, int minute) { base::Value CreateTime(int hour, int minute) {
base::Value time(base::Value::Type::DICTIONARY); base::Value time(base::Value::Type::DICTIONARY);
time.SetKey("hour", base::Value(hour)); time.SetKey("hour", base::Value(hour));
time.SetKey("minute", base::Value(minute)); time.SetKey("minute", base::Value(minute));
return time; return time;
} }
base::Value CreateTimeWindow(base::Value day, base::Value CreateTimeWindow(base::Value day,
base::Value start, base::Value start,
base::Value end, base::Value end,
base::Value last_updated) { base::Value last_updated) {
base::Value time_window(base::Value::Type::DICTIONARY); base::Value time_window(base::Value::Type::DICTIONARY);
time_window.SetKey("effective_day", std::move(day)); time_window.SetKey("effective_day", std::move(day));
time_window.SetKey("starts_at", std::move(start)); time_window.SetKey("starts_at", std::move(start));
time_window.SetKey("ends_at", std::move(end)); time_window.SetKey("ends_at", std::move(end));
time_window.SetKey("last_updated_millis", std::move(last_updated)); time_window.SetKey("last_updated_millis", std::move(last_updated));
return time_window; return time_window;
} }
base::Value CreateTimeUsage(base::Value usage_quota, base::Value CreateTimeUsage(base::Value usage_quota, base::Value last_updated) {
base::Value last_updated) { base::Value time_usage(base::Value::Type::DICTIONARY);
base::Value time_usage(base::Value::Type::DICTIONARY); time_usage.SetKey("usage_quota_mins", std::move(usage_quota));
time_usage.SetKey("usage_quota_mins", std::move(usage_quota)); time_usage.SetKey("last_updated_millis", std::move(last_updated));
time_usage.SetKey("last_updated_millis", std::move(last_updated)); return time_usage;
return time_usage; }
base::Time TimeFromString(const char* time_string) {
base::Time time;
if (!base::Time::FromUTCString(time_string, &time)) {
LOG(ERROR) << "Wrong time string format.";
} }
return time;
}
std::string CreatePolicyTimestamp(const char* time_string) {
base::Time time = TimeFromString(time_string);
return std::to_string(
base::TimeDelta(time - base::Time::UnixEpoch()).InMilliseconds());
}
std::string CreatePolicyTimestamp(const char* time_string) { void AssertEqState(State expected, State actual) {
base::Time time; ASSERT_EQ(expected.is_locked, actual.is_locked);
if (!base::Time::FromUTCString(time_string, &time)) { ASSERT_EQ(expected.active_policy, actual.active_policy);
LOG(ERROR) << "Wrong time string format."; ASSERT_EQ(expected.is_time_usage_limit_enabled,
actual.is_time_usage_limit_enabled);
if (actual.is_time_usage_limit_enabled) {
ASSERT_EQ(expected.remaining_usage, actual.remaining_usage);
if (actual.remaining_usage <= base::TimeDelta::FromMinutes(0)) {
ASSERT_EQ(expected.time_usage_limit_started,
actual.time_usage_limit_started);
} }
return std::to_string(
base::TimeDelta(time - base::Time::UnixEpoch()).InMilliseconds());
} }
};
// Validates that a well formed dictionary containing the time_window_limit ASSERT_EQ(expected.next_state_change_time, actual.next_state_change_time);
// information from the UsageTimeLimit policy is converted to its intermediate ASSERT_EQ(expected.next_state_active_policy, actual.next_state_active_policy);
// representation correctly. ASSERT_EQ(expected.last_state_changed, actual.last_state_changed);
TEST_F(UsageTimeLimitProcessorTest, TimeLimitWindowValid) { }
// Create dictionary containing the policy information.
namespace internal {
using UsageTimeLimitProcessorInternalTest = testing::Test;
TEST_F(UsageTimeLimitProcessorInternalTest, TimeLimitWindowValid) {
std::string last_updated_millis = std::string last_updated_millis =
CreatePolicyTimestamp("1 Jan 1970 00:00:00"); CreatePolicyTimestamp("1 Jan 1970 00:00:00");
base::Value monday_time_limit = base::Value monday_time_limit =
...@@ -111,7 +130,7 @@ TEST_F(UsageTimeLimitProcessorTest, TimeLimitWindowValid) { ...@@ -111,7 +130,7 @@ TEST_F(UsageTimeLimitProcessorTest, TimeLimitWindowValid) {
// Validates that a well formed dictionary containing the time_usage_limit // Validates that a well formed dictionary containing the time_usage_limit
// information from the UsageTimeLimit policy is converted to its intermediate // information from the UsageTimeLimit policy is converted to its intermediate
// representation correctly. // representation correctly.
TEST_F(UsageTimeLimitProcessorTest, TimeUsageWindowValid) { TEST_F(UsageTimeLimitProcessorInternalTest, TimeUsageWindowValid) {
// Create dictionary containing the policy information. // Create dictionary containing the policy information.
std::string last_updated_millis_one = std::string last_updated_millis_one =
CreatePolicyTimestamp("1 Jan 2018 10:00:00"); CreatePolicyTimestamp("1 Jan 2018 10:00:00");
...@@ -130,7 +149,7 @@ TEST_F(UsageTimeLimitProcessorTest, TimeUsageWindowValid) { ...@@ -130,7 +149,7 @@ TEST_F(UsageTimeLimitProcessorTest, TimeUsageWindowValid) {
// Call tested functions. // Call tested functions.
TimeUsageLimit usage_limit_struct(time_usage_limit); TimeUsageLimit usage_limit_struct(time_usage_limit);
ASSERT_EQ(usage_limit_struct.reset_at.InMinutes(), 8 * 60); ASSERT_EQ(usage_limit_struct.resets_at.InMinutes(), 8 * 60);
ASSERT_EQ(usage_limit_struct.entries[Weekday::kTuesday] ASSERT_EQ(usage_limit_struct.entries[Weekday::kTuesday]
.value() .value()
...@@ -157,7 +176,7 @@ TEST_F(UsageTimeLimitProcessorTest, TimeUsageWindowValid) { ...@@ -157,7 +176,7 @@ TEST_F(UsageTimeLimitProcessorTest, TimeUsageWindowValid) {
// Validates that a well formed dictionary containing the override information // Validates that a well formed dictionary containing the override information
// from the UsageTimeLimit policy is converted to its intermediate // from the UsageTimeLimit policy is converted to its intermediate
// representation correctly. // representation correctly.
TEST_F(UsageTimeLimitProcessorTest, OverrideValid) { TEST_F(UsageTimeLimitProcessorInternalTest, OverrideValid) {
// Create policy information. // Create policy information.
std::string created_at_millis = CreatePolicyTimestamp("1 Jan 2018 10:00:00"); std::string created_at_millis = CreatePolicyTimestamp("1 Jan 2018 10:00:00");
base::Value override = base::Value(base::Value::Type::DICTIONARY); base::Value override = base::Value(base::Value::Type::DICTIONARY);
...@@ -174,4 +193,514 @@ TEST_F(UsageTimeLimitProcessorTest, OverrideValid) { ...@@ -174,4 +193,514 @@ TEST_F(UsageTimeLimitProcessorTest, OverrideValid) {
} }
} // namespace internal } // namespace internal
// Tests the GetState for a policy that only have the time window limit set. It
// is checked that the state is correct before, during and after the policy is
// enforced.
TEST_F(UsageTimeLimitProcessorTest, GetStateOnlyTimeWindowLimitSet) {
// Set up policy.
std::string last_updated_millis = CreatePolicyTimestamp("1 Jan 2018 10:00");
base::Value monday_time_limit =
CreateTimeWindow(base::Value("MONDAY"), CreateTime(21, 0),
CreateTime(7, 30), base::Value(last_updated_millis));
base::Value friday_time_limit =
CreateTimeWindow(base::Value("FRIDAY"), CreateTime(21, 0),
CreateTime(7, 30), base::Value(last_updated_millis));
base::Value window_limit_entries(base::Value::Type::LIST);
window_limit_entries.GetList().push_back(std::move(monday_time_limit));
window_limit_entries.GetList().push_back(std::move(friday_time_limit));
base::Value time_window_limit(base::Value::Type::DICTIONARY);
time_window_limit.SetKey("entries", std::move(window_limit_entries));
std::unique_ptr<base::Value> time_limit =
std::make_unique<base::Value>(base::Value::Type::DICTIONARY);
time_limit->SetKey("time_window_limit", std::move(time_window_limit));
std::unique_ptr<base::DictionaryValue> time_limit_dictionary =
base::DictionaryValue::From(std::move(time_limit));
base::Time monday_time_window_limit_start =
TimeFromString("Mon, 1 Jan 2018 21:00");
base::Time monday_time_window_limit_end =
TimeFromString("Tue, 2 Jan 2018 7:30");
base::Time friday_time_window_limit_start =
TimeFromString("Fri, 5 Jan 2018 21:00");
// Check state before Monday time window limit.
base::Time time_one = TimeFromString("Mon, 1 Jan 2018 20:00");
State state_one =
GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(0), time_one,
time_one, base::nullopt);
State expected_state_one;
expected_state_one.is_locked = false;
expected_state_one.active_policy = ActivePolicies::kNoActivePolicy;
expected_state_one.is_time_usage_limit_enabled = false;
expected_state_one.next_state_change_time = monday_time_window_limit_start;
expected_state_one.next_state_active_policy = ActivePolicies::kFixedLimit;
expected_state_one.last_state_changed = base::Time();
AssertEqState(expected_state_one, state_one);
// Check state during the Monday time window limit.
base::Time time_two = TimeFromString("Mon, 1 Jan 2018 22:00");
State state_two =
GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(0), time_two,
time_two, state_one);
State expected_state_two;
expected_state_two.is_locked = true;
expected_state_two.active_policy = ActivePolicies::kFixedLimit;
expected_state_two.is_time_usage_limit_enabled = false;
expected_state_two.next_state_change_time = monday_time_window_limit_end;
expected_state_two.next_state_active_policy = ActivePolicies::kNoActivePolicy;
expected_state_two.last_state_changed = time_two;
AssertEqState(expected_state_two, state_two);
// Check state after the Monday time window limit.
base::Time time_three = TimeFromString("Tue, 2 Jan 2018 9:00");
State state_three =
GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(0),
time_three, time_three, state_two);
State expected_state_three;
expected_state_three.is_locked = false;
expected_state_three.active_policy = ActivePolicies::kNoActivePolicy;
expected_state_three.is_time_usage_limit_enabled = false;
expected_state_three.next_state_change_time = friday_time_window_limit_start;
expected_state_three.next_state_active_policy = ActivePolicies::kFixedLimit;
expected_state_three.last_state_changed = time_three;
AssertEqState(expected_state_three, state_three);
}
// Tests the GetState for a policy that only have the time usage limit set. It
// is checked that the state is correct before and during the policy is
// enforced.
TEST_F(UsageTimeLimitProcessorTest, GetStateOnlyTimeUsageLimitSet) {
// Set up policy.
std::string last_updated = CreatePolicyTimestamp("1 Jan 2018 8:00");
base::Value tuesday_time_usage =
CreateTimeUsage(base::Value(120), base::Value(last_updated));
base::Value thursday_time_usage =
CreateTimeUsage(base::Value(80), base::Value(last_updated));
base::Value time_usage_limit = base::Value(base::Value::Type::DICTIONARY);
time_usage_limit.SetKey("tuesday", std::move(tuesday_time_usage));
time_usage_limit.SetKey("thursday", std::move(thursday_time_usage));
time_usage_limit.SetKey("reset_at", CreateTime(8, 0));
std::unique_ptr<base::Value> time_limit =
std::make_unique<base::Value>(base::Value::Type::DICTIONARY);
time_limit->SetKey("time_usage_limit", std::move(time_usage_limit));
std::unique_ptr<base::DictionaryValue> time_limit_dictionary =
base::DictionaryValue::From(std::move(time_limit));
// Check state before time usage limit is enforced.
base::Time time_one = TimeFromString("Mon, 1 Jan 2018 20:00");
State state_one =
GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(120),
time_one, time_one, base::nullopt);
State expected_state_one;
expected_state_one.is_locked = false;
expected_state_one.active_policy = ActivePolicies::kNoActivePolicy;
expected_state_one.is_time_usage_limit_enabled = false;
// Next state is the minimum time when the time usage limit could be enforced.
expected_state_one.next_state_change_time =
TimeFromString("Tue, 2 Jan 2018 10:00");
expected_state_one.next_state_active_policy = ActivePolicies::kUsageLimit;
expected_state_one.last_state_changed = base::Time();
AssertEqState(expected_state_one, state_one);
// Check state before time usage limit is enforced.
base::Time time_two = TimeFromString("Tue, 2 Jan 2018 12:00");
State state_two =
GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(60),
time_two, time_two, state_one);
State expected_state_two;
expected_state_two.is_locked = false;
expected_state_two.active_policy = ActivePolicies::kNoActivePolicy;
expected_state_two.is_time_usage_limit_enabled = true;
expected_state_two.remaining_usage = base::TimeDelta::FromMinutes(60);
expected_state_two.next_state_change_time =
time_two + base::TimeDelta::FromMinutes(60);
expected_state_two.next_state_active_policy = ActivePolicies::kUsageLimit;
expected_state_two.last_state_changed = base::Time();
AssertEqState(expected_state_two, state_two);
// Check state when the time usage limit should be enforced.
base::Time time_three = TimeFromString("Tue, 2 Jan 2018 21:00");
State state_three =
GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(120),
time_three, time_three, state_two);
base::Time wednesday_reset_time = TimeFromString("Wed, 3 Jan 2018 8:00");
State expected_state_three;
expected_state_three.is_locked = true;
expected_state_three.active_policy = ActivePolicies::kUsageLimit;
expected_state_three.is_time_usage_limit_enabled = true;
expected_state_three.remaining_usage = base::TimeDelta::FromMinutes(0);
expected_state_three.time_usage_limit_started = time_three;
expected_state_three.next_state_change_time = wednesday_reset_time;
expected_state_three.next_state_active_policy =
ActivePolicies::kNoActivePolicy;
expected_state_three.last_state_changed = time_three;
AssertEqState(expected_state_three, state_three);
}
// Test GetState with both time window limit and time usage limit defined.
TEST_F(UsageTimeLimitProcessorTest, GetStateWithTimeUsageAndWindowLimitActive) {
// Setup time window limit.
std::string last_updated = CreatePolicyTimestamp("1 Jan 2018 8:00");
base::Value monday_time_limit =
CreateTimeWindow(base::Value("MONDAY"), CreateTime(21, 0),
CreateTime(8, 30), base::Value(last_updated));
base::Value friday_time_limit =
CreateTimeWindow(base::Value("FRIDAY"), CreateTime(21, 0),
CreateTime(8, 30), base::Value(last_updated));
base::Value window_limit_entries(base::Value::Type::LIST);
window_limit_entries.GetList().push_back(std::move(monday_time_limit));
window_limit_entries.GetList().push_back(std::move(friday_time_limit));
base::Value time_window_limit(base::Value::Type::DICTIONARY);
time_window_limit.SetKey("entries", std::move(window_limit_entries));
// Setup time usage limit.
base::Value monday_time_usage =
CreateTimeUsage(base::Value(120), base::Value(last_updated));
base::Value thursday_time_usage =
CreateTimeUsage(base::Value(80), base::Value(last_updated));
base::Value time_usage_limit = base::Value(base::Value::Type::DICTIONARY);
time_usage_limit.SetKey("monday", std::move(monday_time_usage));
time_usage_limit.SetKey("reset_at", CreateTime(8, 0));
// Setup policy.
std::unique_ptr<base::Value> time_limit =
std::make_unique<base::Value>(base::Value::Type::DICTIONARY);
time_limit->SetKey("time_window_limit", std::move(time_window_limit));
time_limit->SetKey("time_usage_limit", std::move(time_usage_limit));
std::unique_ptr<base::DictionaryValue> time_limit_dictionary =
base::DictionaryValue::From(std::move(time_limit));
// Check state before any policy is enforced.
base::Time time_one = TimeFromString("Mon, 1 Jan 2018 14:00");
State state_one =
GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(80),
time_one, time_one, base::nullopt);
State expected_state_one;
expected_state_one.is_locked = false;
expected_state_one.active_policy = ActivePolicies::kNoActivePolicy;
expected_state_one.is_time_usage_limit_enabled = true;
expected_state_one.remaining_usage = base::TimeDelta::FromMinutes(40);
expected_state_one.next_state_change_time =
time_one + base::TimeDelta::FromMinutes(40);
expected_state_one.next_state_active_policy = ActivePolicies::kUsageLimit;
expected_state_one.last_state_changed = base::Time();
AssertEqState(expected_state_one, state_one);
// Check state during time usage limit.
base::Time time_two = TimeFromString("Mon, 1 Jan 2018 16:00");
State state_two =
GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(121),
time_two, time_two, state_one);
base::Time monday_time_window_limit_start =
TimeFromString("Mon, 1 Jan 2018 21:00");
State expected_state_two;
expected_state_two.is_locked = true;
expected_state_two.active_policy = ActivePolicies::kUsageLimit;
expected_state_two.is_time_usage_limit_enabled = true;
expected_state_two.remaining_usage = base::TimeDelta::FromMinutes(0);
expected_state_two.time_usage_limit_started = time_two;
expected_state_two.next_state_change_time = monday_time_window_limit_start;
expected_state_two.next_state_active_policy = ActivePolicies::kFixedLimit;
expected_state_two.last_state_changed = time_two;
AssertEqState(expected_state_two, state_two);
// Check state during time window limit and time usage limit enforced.
base::Time time_three = TimeFromString("Mon, 1 Jan 2018 21:00");
State state_three =
GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(120),
time_three, time_three, state_two);
State expected_state_three;
expected_state_three.is_locked = true;
expected_state_three.active_policy = ActivePolicies::kFixedLimit;
expected_state_three.is_time_usage_limit_enabled = true;
expected_state_three.remaining_usage = base::TimeDelta::FromMinutes(0);
expected_state_three.time_usage_limit_started = time_two;
expected_state_three.next_state_change_time =
TimeFromString("e, 2 Jan 2018 8:30");
expected_state_three.next_state_active_policy =
ActivePolicies::kNoActivePolicy;
expected_state_three.last_state_changed = time_three;
AssertEqState(expected_state_three, state_three);
// Check state after time usage limit reset and window limit end.
base::Time time_four = TimeFromString("Fri, 5 Jan 2018 8:30");
State state_four =
GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(120),
time_four, time_four, state_three);
State expected_state_four;
expected_state_four.is_locked = false;
expected_state_four.active_policy = ActivePolicies::kNoActivePolicy;
expected_state_four.is_time_usage_limit_enabled = false;
expected_state_four.next_state_change_time =
TimeFromString("Fri, 5 Jan 2018 21:00");
expected_state_four.next_state_active_policy = ActivePolicies::kFixedLimit;
expected_state_four.last_state_changed = time_four;
AssertEqState(expected_state_four, state_four);
}
// Check GetState when a lock override is active.
TEST_F(UsageTimeLimitProcessorTest, GetStateWithOverrideLock) {
std::string created_at = CreatePolicyTimestamp("1 Jan 2018 15:00");
base::Value override = base::Value(base::Value::Type::DICTIONARY);
override.SetKey("action", base::Value("LOCK"));
override.SetKey("created_at_millis", base::Value(created_at));
std::unique_ptr<base::Value> time_limit =
std::make_unique<base::Value>(base::Value::Type::DICTIONARY);
time_limit->SetKey("overrides", std::move(override));
std::unique_ptr<base::DictionaryValue> time_limit_dictionary =
base::DictionaryValue::From(std::move(time_limit));
base::Time time_one = TimeFromString("Mon, 1 Jan 2018 15:05");
State state_one =
GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(0), time_one,
time_one, base::nullopt);
// Check that the device is locked until next morning.
State expected_state_one;
expected_state_one.is_locked = true;
expected_state_one.active_policy = ActivePolicies::kOverride;
expected_state_one.is_time_usage_limit_enabled = false;
expected_state_one.next_state_change_time =
TimeFromString("Tue, 2 Jan 2018 0:00");
expected_state_one.next_state_active_policy = ActivePolicies::kNoActivePolicy;
expected_state_one.last_state_changed = base::Time();
AssertEqState(expected_state_one, state_one);
}
// Test GetState when a overridden time window limit has been updated, so the
// override should not be aplicable anymore.
TEST_F(UsageTimeLimitProcessorTest, GetStateUpdateUnlockedTimeWindowLimit) {
// Setup time window limit.
std::string last_updated = CreatePolicyTimestamp("Mon, 1 Jan 2018 8:00");
base::Value monday_time_limit =
CreateTimeWindow(base::Value("MONDAY"), CreateTime(18, 0),
CreateTime(7, 30), base::Value(last_updated));
base::Value window_limit_entries(base::Value::Type::LIST);
window_limit_entries.GetList().push_back(std::move(monday_time_limit));
base::Value time_window_limit(base::Value::Type::DICTIONARY);
time_window_limit.SetKey("entries", std::move(window_limit_entries));
// Setup override.
std::string created_at = CreatePolicyTimestamp("Mon, 1 Jan 2018 18:30");
base::Value override = base::Value(base::Value::Type::DICTIONARY);
override.SetKey("action", base::Value("UNLOCK"));
override.SetKey("created_at_millis", base::Value(created_at));
std::unique_ptr<base::Value> time_limit =
std::make_unique<base::Value>(base::Value::Type::DICTIONARY);
time_limit->SetKey("time_window_limit", std::move(time_window_limit));
time_limit->SetKey("overrides", std::move(override));
std::unique_ptr<base::DictionaryValue> time_limit_dictionary =
base::DictionaryValue::From(std::move(time_limit));
// Check that the override is invalidating the time window limit.
base::Time time_one = TimeFromString("Mon, 1 Jan 2018 18:35");
State state_one =
GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(120),
time_one, time_one, base::nullopt);
State expected_state_one;
expected_state_one.is_locked = false;
expected_state_one.active_policy = ActivePolicies::kOverride;
expected_state_one.is_time_usage_limit_enabled = false;
expected_state_one.next_state_change_time =
TimeFromString("Mon, 8 Jan 2018 18:00");
expected_state_one.next_state_active_policy = ActivePolicies::kFixedLimit;
expected_state_one.last_state_changed = base::Time();
AssertEqState(expected_state_one, state_one);
// Change time window limit
std::string last_updated_two = CreatePolicyTimestamp("Mon, 1 Jan 2018 19:00");
base::Value monday_time_limit_two =
CreateTimeWindow(base::Value("MONDAY"), CreateTime(18, 0),
CreateTime(8, 00), base::Value(last_updated_two));
base::Value window_limit_entries_two(base::Value::Type::LIST);
window_limit_entries_two.GetList().push_back(
std::move(monday_time_limit_two));
base::Value time_window_limit_two(base::Value::Type::DICTIONARY);
time_window_limit_two.SetKey("entries", std::move(window_limit_entries_two));
time_limit_dictionary->SetKey("time_window_limit",
std::move(time_window_limit_two));
// Check that the new time window limit is enforced.
base::Time time_two = TimeFromString("Mon, 1 Jan 2018 19:10");
State state_two =
GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(120),
time_two, time_two, state_one);
State expected_state_two;
expected_state_two.is_locked = true;
expected_state_two.active_policy = ActivePolicies::kFixedLimit;
expected_state_two.is_time_usage_limit_enabled = false;
expected_state_two.next_state_change_time =
TimeFromString("Tue, 2 Jan 2018 8:00");
expected_state_two.next_state_active_policy = ActivePolicies::kNoActivePolicy;
expected_state_two.last_state_changed = time_two;
AssertEqState(expected_state_two, state_two);
}
// Make sure that the override will only affect policies that started being
// enforced before it was created.
TEST_F(UsageTimeLimitProcessorTest, GetStateOverrideTimeWindowLimitOnly) {
// Setup time window limit.
std::string last_updated = CreatePolicyTimestamp("1 Jan 2018 8:00");
base::Value monday_time_limit =
CreateTimeWindow(base::Value("MONDAY"), CreateTime(21, 0),
CreateTime(10, 0), base::Value(last_updated));
base::Value window_limit_entries(base::Value::Type::LIST);
window_limit_entries.GetList().push_back(std::move(monday_time_limit));
base::Value time_window_limit(base::Value::Type::DICTIONARY);
time_window_limit.SetKey("entries", std::move(window_limit_entries));
// Setup time usage limit.
base::Value monday_time_usage =
CreateTimeUsage(base::Value(60), base::Value(last_updated));
base::Value time_usage_limit = base::Value(base::Value::Type::DICTIONARY);
time_usage_limit.SetKey("monday", std::move(monday_time_usage));
time_usage_limit.SetKey("reset_at", CreateTime(8, 0));
// Setup override.
std::string created_at = CreatePolicyTimestamp("Mon, 1 Jan 2018 22:00");
base::Value override = base::Value(base::Value::Type::DICTIONARY);
override.SetKey("action", base::Value("UNLOCK"));
override.SetKey("created_at_millis", base::Value(created_at));
// Setup policy.
std::unique_ptr<base::Value> time_limit =
std::make_unique<base::Value>(base::Value::Type::DICTIONARY);
time_limit->SetKey("time_window_limit", std::move(time_window_limit));
time_limit->SetKey("time_usage_limit", std::move(time_usage_limit));
time_limit->SetKey("overrides", std::move(override));
std::unique_ptr<base::DictionaryValue> time_limit_dictionary =
base::DictionaryValue::From(std::move(time_limit));
// Check that the override is unlocking the device that should be locked with
// time window limit.
base::Time time_one = TimeFromString("Mon, 1 Jan 2018 22:10");
State state_one =
GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(40),
time_one, time_one, base::nullopt);
State expected_state_one;
expected_state_one.is_locked = false;
expected_state_one.active_policy = ActivePolicies::kOverride;
expected_state_one.is_time_usage_limit_enabled = true;
expected_state_one.remaining_usage = base::TimeDelta::FromMinutes(20);
expected_state_one.next_state_change_time =
TimeFromString("Mon, 1 Jan 2018 22:30");
expected_state_one.next_state_active_policy = ActivePolicies::kUsageLimit;
expected_state_one.last_state_changed = base::Time();
AssertEqState(expected_state_one, state_one);
// Check that the override didn't unlock the device when the time usage limit
// started, and that it will be locked until the time usage limit reset time,
// and not when the time window limit ends.
base::Time time_two = TimeFromString("Mon, 1 Jan 2018 22:30");
State state_two =
GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(60),
time_two, time_two, state_one);
State expected_state_two;
expected_state_two.is_locked = true;
expected_state_two.active_policy = ActivePolicies::kUsageLimit;
expected_state_two.is_time_usage_limit_enabled = true;
expected_state_two.remaining_usage = base::TimeDelta::FromMinutes(0);
expected_state_two.time_usage_limit_started = time_two;
expected_state_two.next_state_change_time =
TimeFromString("Tue, 2 Jan 2018 8:00");
expected_state_two.next_state_active_policy = ActivePolicies::kNoActivePolicy;
expected_state_two.last_state_changed = time_two;
AssertEqState(expected_state_two, state_two);
}
// Test GetExpectedResetTime with an empty policy.
TEST_F(UsageTimeLimitProcessorTest, GetExpectedResetTimeWithEmptyPolicy) {
// Setup policy.
std::unique_ptr<base::Value> time_limit =
std::make_unique<base::Value>(base::Value::Type::DICTIONARY);
std::unique_ptr<base::DictionaryValue> time_limit_dictionary =
base::DictionaryValue::From(std::move(time_limit));
base::Time time_one = TimeFromString("Mon, 1 Jan 2018 22:00");
base::Time reset_time = GetExpectedResetTime(time_limit_dictionary, time_one);
ASSERT_EQ(reset_time, TimeFromString("Tue, 2 Jan 2018 0:00"));
}
// Test GetExpectedResetTime with a custom time usage limit reset time.
TEST_F(UsageTimeLimitProcessorTest, GetExpectedResetTimeWithCustomPolicy) {
// Setup time usage limit.
base::Value time_usage_limit = base::Value(base::Value::Type::DICTIONARY);
time_usage_limit.SetKey("reset_at", CreateTime(8, 0));
// Setup policy.
std::unique_ptr<base::Value> time_limit =
std::make_unique<base::Value>(base::Value::Type::DICTIONARY);
time_limit->SetKey("time_usage_limit", std::move(time_usage_limit));
std::unique_ptr<base::DictionaryValue> time_limit_dictionary =
base::DictionaryValue::From(std::move(time_limit));
// Check that it resets in the same day.
base::Time time_one = TimeFromString("Tue, 2 Jan 2018 6:00");
base::Time reset_time_one =
GetExpectedResetTime(time_limit_dictionary, time_one);
ASSERT_EQ(reset_time_one, TimeFromString("Tue, 2 Jan 2018 8:00"));
// Checks that it resets on the following day.
base::Time time_two = TimeFromString("Tue, 2 Jan 2018 10:00");
base::Time reset_time_two =
GetExpectedResetTime(time_limit_dictionary, time_two);
ASSERT_EQ(reset_time_two, TimeFromString("Wed, 3 Jan 2018 8:00"));
}
} // namespace usage_time_limit
} // namespace chromeos } // namespace chromeos
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment