Commit b3392d98 authored by Adolfo Victoria's avatar Adolfo Victoria Committed by Commit Bot

Add vector of intervals range checking to Time Restrictions policy

* Add function GetEndOfCurrent interval to obtain the last end of the
interval which contains the current time.
* Add function MaterializeIntervalsToLocalTimezone, which materializes
the given intervals to the current local timezone.
* Add function TimeIsInsideCrosSettingsIntervals, which checks if the
current time is inside the intervals set in cros settings. It then
returns the localized string of the end of the interval that contains
the current time.

BUG=chromium:852860
TEST=added unittests

Change-Id: Ife32e31c8a929827fd14ab9f108c49eacb9c32c3
Reviewed-on: https://chromium-review.googlesource.com/1132676Reviewed-by: default avatarMaksim Ivanov <emaxx@chromium.org>
Commit-Queue: Maksim Ivanov <emaxx@chromium.org>
Cr-Commit-Position: refs/heads/master@{#582403}
parent e4c26fa3
...@@ -1384,6 +1384,8 @@ source_set("chromeos") { ...@@ -1384,6 +1384,8 @@ source_set("chromeos") {
"policy/configuration_policy_handler_chromeos.h", "policy/configuration_policy_handler_chromeos.h",
"policy/device_auto_update_time_restrictions_decoder.cc", "policy/device_auto_update_time_restrictions_decoder.cc",
"policy/device_auto_update_time_restrictions_decoder.h", "policy/device_auto_update_time_restrictions_decoder.h",
"policy/device_auto_update_time_restrictions_utils.cc",
"policy/device_auto_update_time_restrictions_utils.h",
"policy/device_cloud_policy_initializer.cc", "policy/device_cloud_policy_initializer.cc",
"policy/device_cloud_policy_initializer.h", "policy/device_cloud_policy_initializer.h",
"policy/device_cloud_policy_manager_chromeos.cc", "policy/device_cloud_policy_manager_chromeos.cc",
...@@ -2143,6 +2145,7 @@ source_set("unit_tests") { ...@@ -2143,6 +2145,7 @@ source_set("unit_tests") {
"policy/component_active_directory_policy_service_unittest.cc", "policy/component_active_directory_policy_service_unittest.cc",
"policy/configuration_policy_handler_chromeos_unittest.cc", "policy/configuration_policy_handler_chromeos_unittest.cc",
"policy/device_auto_update_time_restrictions_decoder_unittest.cc", "policy/device_auto_update_time_restrictions_decoder_unittest.cc",
"policy/device_auto_update_time_restrictions_utils_unittest.cc",
"policy/device_cloud_policy_initializer_unittest.cc", "policy/device_cloud_policy_initializer_unittest.cc",
"policy/device_cloud_policy_manager_chromeos_unittest.cc", "policy/device_cloud_policy_manager_chromeos_unittest.cc",
"policy/device_cloud_policy_store_chromeos_unittest.cc", "policy/device_cloud_policy_store_chromeos_unittest.cc",
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/policy/device_auto_update_time_restrictions_utils.h"
#include "base/logging.h"
#include "base/time/clock.h"
#include "base/values.h"
#include "chrome/browser/chromeos/policy/device_auto_update_time_restrictions_decoder.h"
#include "chrome/browser/chromeos/policy/weekly_time/time_utils.h"
#include "chrome/browser/chromeos/policy/weekly_time/weekly_time.h"
#include "chrome/browser/chromeos/policy/weekly_time/weekly_time_interval.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chromeos/settings/cros_settings_names.h"
#include "third_party/icu/source/i18n/unicode/timezone.h"
using base::Clock;
using base::ListValue;
using std::vector;
namespace policy {
namespace {
// Expects timezone agnostic |WeeklyTimeInterval|s in |intervals|.
// Transforms |intervals| into |*intervals_out|, converting them to the local
// timezone. The local timezone is determined using |clock|. If this returns
// false, an error occurred and the output vector should not be used. This can
// happen if the local timezone offset can not be determined, or if at least one
// of the passed intervals was already bound to a timezone.
bool MaterializeIntervalsToLocalTimezone(
const vector<WeeklyTimeInterval>& intervals,
Clock* clock,
vector<WeeklyTimeInterval>* intervals_out) {
DCHECK(intervals_out);
int local_to_gmt_offset;
if (!weekly_time_utils::GetOffsetFromTimezoneToGmt(
*icu::TimeZone::createDefault(), clock, &local_to_gmt_offset)) {
LOG(ERROR) << "Unable to get local timezone.";
return false;
}
int gmt_to_local_offset = -local_to_gmt_offset;
intervals_out->clear();
for (const auto& interval : intervals) {
if (interval.start().timezone_offset()) {
LOG(ERROR) << "Intervals are not timezone-agnostic.";
return false;
}
intervals_out->push_back(WeeklyTimeInterval(
interval.start().ConvertToCustomTimezone(gmt_to_local_offset),
interval.end().ConvertToCustomTimezone(gmt_to_local_offset)));
}
return true;
}
} // namespace
bool GetDeviceAutoUpdateTimeRestrictionsIntervalsInLocalTimezone(
Clock* clock,
vector<WeeklyTimeInterval>* intervals_out) {
const ListValue* intervals_list;
if (!chromeos::CrosSettings::Get()->GetList(
chromeos::kDeviceAutoUpdateTimeRestrictions, &intervals_list)) {
return false;
}
vector<WeeklyTimeInterval> decoded_intervals;
if (!WeeklyTimeIntervalsFromListValue(*intervals_list, &decoded_intervals)) {
return false;
}
return MaterializeIntervalsToLocalTimezone(decoded_intervals, clock,
intervals_out);
}
} // namespace policy
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_AUTO_UPDATE_TIME_RESTRICTIONS_UTILS_H_
#define CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_AUTO_UPDATE_TIME_RESTRICTIONS_UTILS_H_
#include <vector>
#include "base/optional.h"
namespace base {
class Clock;
}
namespace policy {
class WeeklyTimeInterval;
// Places the intervals for DeviceAutoUpdateTimeRestrictions according to
// CrosSettings into |intervals_out|. Note that the intervals are specified in
// a timezone-agnostic format by the policy, so this function converts them to
// the local timezone. It is thus not advisable to store the returned intervals
// for extended periods (because the local timezone could change). Returns false
// if there are no intervals set or if the conversion to the local timezone was
// unsuccessful.
bool GetDeviceAutoUpdateTimeRestrictionsIntervalsInLocalTimezone(
base::Clock* clock,
std::vector<WeeklyTimeInterval>* intervals_out);
} // namespace policy
#endif // CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_AUTO_UPDATE_TIME_RESTRICTIONS_UTILS_H_
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/policy/device_auto_update_time_restrictions_utils.h"
#include <memory>
#include <string>
#include <tuple>
#include <utility>
#include "base/strings/string16.h"
#include "base/test/simple_test_clock.h"
#include "base/time/time.h"
#include "base/values.h"
#include "chrome/browser/chromeos/policy/weekly_time/weekly_time.h"
#include "chrome/browser/chromeos/policy/weekly_time/weekly_time_interval.h"
#include "chrome/browser/chromeos/settings/scoped_cros_settings_test_helper.h"
#include "chromeos/settings/cros_settings_names.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/icu/source/i18n/unicode/timezone.h"
using base::ListValue;
using base::Time;
using base::Value;
using std::tuple;
using std::vector;
namespace policy {
namespace {
enum {
kMonday = 1,
kTuesday = 2,
kWednesday = 3,
kThursday = 4,
kFriday = 5,
kSaturday = 6,
kSunday = 7,
};
std::string DayToString(int day_of_week) {
switch (day_of_week) {
case kMonday:
return "Monday";
case kTuesday:
return "Tuesday";
case kWednesday:
return "Wednesday";
case kThursday:
return "Thursday";
case kFriday:
return "Friday";
case kSaturday:
return "Saturday";
case kSunday:
return "Sunday";
}
return "";
}
const char* kNewYorkTimezone = "America/New_York";
constexpr int kMillisecondsInMinute = 60000;
constexpr int kMillisecondsInHour = 3600000;
constexpr int kNewYorkOffset = -4 * kMillisecondsInHour;
constexpr Time::Exploded kDaylightTime{2018, 8, 3, 8, 15, 0, 0, 0};
} // namespace
class DeviceAutoUpdateTimeRestrictionsUtilTest : public testing::Test {
protected:
void SetUp() override {
timezone_.reset(icu::TimeZone::createDefault());
icu::TimeZone::adoptDefault(
icu::TimeZone::createTimeZone(kNewYorkTimezone));
// Use Daylight savings to use EDT.
Time test_time;
ASSERT_TRUE(base::Time::FromUTCExploded(kDaylightTime, &test_time));
test_clock_.SetNow(test_time);
}
void TearDown() override { icu::TimeZone::adoptDefault(timezone_.release()); }
void SetCrosSettings(const std::string& path, const Value& in_value) {
cros_settings_helper_.Set(path, in_value);
cros_settings_helper_.ReplaceProvider(path);
}
ListValue GetIntervalsAsList(const vector<WeeklyTimeInterval>& intervals) {
ListValue list_val;
for (const auto& interval : intervals) {
base::DictionaryValue start;
int start_hours = interval.start().milliseconds() / kMillisecondsInHour;
int start_minutes = (interval.start().milliseconds() -
start_hours * kMillisecondsInHour) /
kMillisecondsInMinute;
start.SetKey("day_of_week",
Value(DayToString(interval.start().day_of_week())));
start.SetKey("hours", Value(start_hours));
start.SetKey("minutes", Value(start_minutes));
base::DictionaryValue end;
int end_hours = interval.end().milliseconds() / kMillisecondsInHour;
int end_minutes =
(interval.end().milliseconds() - end_hours * kMillisecondsInHour) /
kMillisecondsInMinute;
end.SetKey("day_of_week",
Value(DayToString(interval.end().day_of_week())));
end.SetKey("hours", Value(end_hours));
end.SetKey("minutes", Value(end_minutes));
base::DictionaryValue time_dict;
time_dict.SetKey("start", std::move(start));
time_dict.SetKey("end", std::move(end));
list_val.GetList().push_back(std::move(time_dict));
}
return list_val;
}
base::SimpleTestClock test_clock_;
private:
std::unique_ptr<icu::TimeZone> timezone_;
// These initialize CrosSettings and then tear down when the test is done.
chromeos::ScopedCrosSettingsTestHelper cros_settings_helper_;
};
TEST_F(DeviceAutoUpdateTimeRestrictionsUtilTest,
GetDeviceAutoUpdateTimeRestrictionsIntervalsInLocalTimezone) {
const vector<WeeklyTimeInterval> kExpected{
WeeklyTimeInterval(
WeeklyTime(kMonday, 5 * kMillisecondsInHour, kNewYorkOffset),
WeeklyTime(kTuesday, 10 * kMillisecondsInHour, kNewYorkOffset)),
WeeklyTimeInterval(
WeeklyTime(kWednesday, 10 * kMillisecondsInHour, kNewYorkOffset),
WeeklyTime(kWednesday, 15 * kMillisecondsInHour, kNewYorkOffset))};
SetCrosSettings(chromeos::kDeviceAutoUpdateTimeRestrictions,
GetIntervalsAsList(kExpected));
vector<WeeklyTimeInterval> result;
ASSERT_TRUE(GetDeviceAutoUpdateTimeRestrictionsIntervalsInLocalTimezone(
&test_clock_, &result));
EXPECT_EQ(result, kExpected);
}
} // namespace policy
...@@ -120,5 +120,17 @@ base::TimeDelta GetDeltaTillNextTimeInterval( ...@@ -120,5 +120,17 @@ base::TimeDelta GetDeltaTillNextTimeInterval(
return till_next_interval; return till_next_interval;
} }
base::Optional<WeeklyTimeInterval> GetIntervalForCurrentTime(
const std::vector<WeeklyTimeInterval>& intervals,
base::Clock* clock) {
WeeklyTime weekly_time_now = WeeklyTime::GetCurrentGmtWeeklyTime(clock);
for (const auto& interval : intervals) {
if (interval.Contains(weekly_time_now)) {
return interval;
}
}
return base::nullopt;
}
} // namespace weekly_time_utils } // namespace weekly_time_utils
} // namespace policy } // namespace policy
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "base/optional.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "third_party/icu/source/i18n/unicode/timezone.h" #include "third_party/icu/source/i18n/unicode/timezone.h"
...@@ -56,6 +57,14 @@ base::TimeDelta GetDeltaTillNextTimeInterval( ...@@ -56,6 +57,14 @@ base::TimeDelta GetDeltaTillNextTimeInterval(
const WeeklyTime& current_time, const WeeklyTime& current_time,
const std::vector<WeeklyTimeInterval>& weekly_time_intervals); const std::vector<WeeklyTimeInterval>& weekly_time_intervals);
// Takes in a vector of weekly time intervals. If |clock->Now()|
// is inside one of the intervals, then the function returns the
// interval that contains |clock->Now()|. Otherwise, return |base::nullopt|.
// The intervals must have a defined
base::Optional<WeeklyTimeInterval> GetIntervalForCurrentTime(
const std::vector<WeeklyTimeInterval>& intervals,
base::Clock* clock);
} // namespace weekly_time_utils } // namespace weekly_time_utils
} // namespace policy } // namespace policy
......
...@@ -23,9 +23,25 @@ namespace policy { ...@@ -23,9 +23,25 @@ namespace policy {
namespace weekly_time_utils { namespace weekly_time_utils {
namespace { namespace {
enum {
kMonday = 1,
kTuesday = 2,
kWednesday = 3,
kThursday = 4,
kFriday = 5,
kSaturday = 6,
kSunday = 7,
};
constexpr int kMinutesInHour = 60; constexpr int kMinutesInHour = 60;
constexpr int kMillisecondsInHour = 3600000;
constexpr base::TimeDelta kMinute = base::TimeDelta::FromMinutes(1); constexpr base::TimeDelta kMinute = base::TimeDelta::FromMinutes(1);
constexpr base::TimeDelta kHour = base::TimeDelta::FromHours(1); constexpr base::TimeDelta kHour = base::TimeDelta::FromHours(1);
constexpr base::Time::Exploded kDaylightSavingsTime{2018, 8, 3, 8, 15, 0, 0, 0};
constexpr base::Time::Exploded kNonDaylightSavingsTime{2018, 1, 0, 28,
0, 0, 0, 0};
} // namespace } // namespace
class TimeUtilsTimezoneFunctionsTest : public testing::Test { class TimeUtilsTimezoneFunctionsTest : public testing::Test {
...@@ -43,15 +59,15 @@ class TimeUtilsTimezoneFunctionsTest : public testing::Test { ...@@ -43,15 +59,15 @@ class TimeUtilsTimezoneFunctionsTest : public testing::Test {
void SetDaylightSavings(bool is_daylight_savings) { void SetDaylightSavings(bool is_daylight_savings) {
if (is_daylight_savings) { if (is_daylight_savings) {
// Friday July 13th // Friday July 13th
base::Time::Exploded exploded_daylight{2018, 7, 5, 13, 0, 0, 0, 0};
base::Time test_time; base::Time test_time;
ASSERT_TRUE(base::Time::FromUTCExploded(exploded_daylight, &test_time)); ASSERT_TRUE(
base::Time::FromUTCExploded(kDaylightSavingsTime, &test_time));
test_clock_.SetNow(test_time); test_clock_.SetNow(test_time);
} else { } else {
// Sunday January 28 // Sunday January 28
base::Time::Exploded exploded_standard{2018, 1, 0, 28, 0, 0, 0, 0};
base::Time test_time; base::Time test_time;
ASSERT_TRUE(base::Time::FromUTCExploded(exploded_standard, &test_time)); ASSERT_TRUE(
base::Time::FromUTCExploded(kNonDaylightSavingsTime, &test_time));
test_clock_.SetNow(test_time); test_clock_.SetNow(test_time);
} }
} }
...@@ -144,5 +160,116 @@ TEST_F(TimeUtilsTimezoneFunctionsTest, GetOffsetFromTimezoneToGmtNoDaylight) { ...@@ -144,5 +160,116 @@ TEST_F(TimeUtilsTimezoneFunctionsTest, GetOffsetFromTimezoneToGmtNoDaylight) {
EXPECT_EQ(result2, result); EXPECT_EQ(result2, result);
} }
class GetIntervalForCurrentTimeTest
: public testing::TestWithParam<
std::tuple<std::vector<WeeklyTimeInterval>,
base::Optional<WeeklyTimeInterval>>> {
protected:
void SetUp() override {
// Wednesday August 8th at 15:00 GMT
base::Time test_time;
ASSERT_TRUE(base::Time::FromUTCExploded(kDaylightSavingsTime, &test_time));
test_clock_.SetNow(test_time);
}
std::vector<WeeklyTimeInterval> intervals() {
return std::get<0>(GetParam());
}
base::Optional<WeeklyTimeInterval> expected_result() {
return std::get<1>(GetParam());
}
base::SimpleTestClock test_clock_;
};
TEST_P(GetIntervalForCurrentTimeTest, Test) {
base::Optional<WeeklyTimeInterval> result =
GetIntervalForCurrentTime(intervals(), &test_clock_);
EXPECT_EQ(result, expected_result());
}
INSTANTIATE_TEST_CASE_P(
SameTimezoneNone,
GetIntervalForCurrentTimeTest,
testing::Values(std::make_tuple(
std::vector<WeeklyTimeInterval>{
WeeklyTimeInterval(
WeeklyTime(kTuesday, 10 * kMillisecondsInHour, 0),
WeeklyTime(kWednesday, 8 * kMillisecondsInHour, 0)),
WeeklyTimeInterval(
WeeklyTime(kSunday, 5 * kMillisecondsInHour, 0),
WeeklyTime(kSunday, 16 * kMillisecondsInHour, 0))},
base::nullopt)));
INSTANTIATE_TEST_CASE_P(
SameTimezoneResult,
GetIntervalForCurrentTimeTest,
testing::Values(
std::make_tuple(
std::vector<WeeklyTimeInterval>{
WeeklyTimeInterval(
WeeklyTime(kTuesday, 10 * kMillisecondsInHour, 0),
WeeklyTime(kThursday, 8 * kMillisecondsInHour, 0)),
WeeklyTimeInterval(
WeeklyTime(kSunday, 5 * kMillisecondsInHour, 0),
WeeklyTime(kSunday, 16 * kMillisecondsInHour, 0))},
WeeklyTimeInterval(
WeeklyTime(kTuesday, 10 * kMillisecondsInHour, 0),
WeeklyTime(kThursday, 8 * kMillisecondsInHour, 0))),
std::make_tuple(
std::vector<WeeklyTimeInterval>{
WeeklyTimeInterval(
WeeklyTime(kTuesday, 10 * kMillisecondsInHour, 0),
WeeklyTime(kWednesday, 8 * kMillisecondsInHour, 0)),
WeeklyTimeInterval(
WeeklyTime(kSunday, 5 * kMillisecondsInHour, 0),
WeeklyTime(kWednesday, 16 * kMillisecondsInHour, 0))},
WeeklyTimeInterval(
WeeklyTime(kSunday, 5 * kMillisecondsInHour, 0),
WeeklyTime(kWednesday, 16 * kMillisecondsInHour, 0)))));
INSTANTIATE_TEST_CASE_P(
DifferentTimezoneNone,
GetIntervalForCurrentTimeTest,
testing::Values(std::make_tuple(
std::vector<WeeklyTimeInterval>{
WeeklyTimeInterval(WeeklyTime(kTuesday,
10 * kMillisecondsInHour,
5 * kMillisecondsInHour),
WeeklyTime(kWednesday,
17 * kMillisecondsInHour,
5 * kMillisecondsInHour)),
WeeklyTimeInterval(WeeklyTime(kSunday,
5 * kMillisecondsInHour,
5 * kMillisecondsInHour),
WeeklyTime(kSunday,
16 * kMillisecondsInHour,
5 * kMillisecondsInHour))},
base::nullopt)));
INSTANTIATE_TEST_CASE_P(
DifferentTimezoneResult,
GetIntervalForCurrentTimeTest,
testing::Values(std::make_tuple(
std::vector<WeeklyTimeInterval>{
WeeklyTimeInterval(WeeklyTime(kTuesday,
10 * kMillisecondsInHour,
-8 * kMillisecondsInHour),
WeeklyTime(kWednesday,
8 * kMillisecondsInHour,
-8 * kMillisecondsInHour)),
WeeklyTimeInterval(WeeklyTime(kSunday,
5 * kMillisecondsInHour,
-8 * kMillisecondsInHour),
WeeklyTime(kSunday,
16 * kMillisecondsInHour,
-8 * kMillisecondsInHour))},
WeeklyTimeInterval(WeeklyTime(kTuesday,
10 * kMillisecondsInHour,
-8 * kMillisecondsInHour),
WeeklyTime(kWednesday,
8 * kMillisecondsInHour,
-8 * kMillisecondsInHour)))));
} // namespace weekly_time_utils } // namespace weekly_time_utils
} // namespace policy } // namespace policy
...@@ -28,6 +28,12 @@ class WeeklyTime { ...@@ -28,6 +28,12 @@ class WeeklyTime {
WeeklyTime& operator=(const WeeklyTime& rhs); WeeklyTime& operator=(const WeeklyTime& rhs);
bool operator==(const WeeklyTime& rhs) const {
return day_of_week_ == rhs.day_of_week() &&
milliseconds_ == rhs.milliseconds() &&
timezone_offset_ == rhs.timezone_offset();
}
// Return DictionaryValue in format: // Return DictionaryValue in format:
// { "day_of_week" : int # value is from 1 to 7 (1 = Monday, 2 = Tuesday, // { "day_of_week" : int # value is from 1 to 7 (1 = Monday, 2 = Tuesday,
// etc.) // etc.)
......
...@@ -26,6 +26,10 @@ class WeeklyTimeInterval { ...@@ -26,6 +26,10 @@ class WeeklyTimeInterval {
WeeklyTimeInterval& operator=(const WeeklyTimeInterval& rhs); WeeklyTimeInterval& operator=(const WeeklyTimeInterval& rhs);
bool operator==(const WeeklyTimeInterval& rhs) const {
return start_ == rhs.start() && end_ == rhs.end();
}
// Return DictionaryValue in format: // Return DictionaryValue in format:
// { "start" : WeeklyTime, // { "start" : WeeklyTime,
// "end" : WeeklyTime } // "end" : WeeklyTime }
......
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