PM: Add a time provider.

This implements a time provider interface, as well as a real and a fake
implementation.

BUG=chromium:341205
TEST=Unit tests.

Change-Id: Ibc6a865ab868e0f8c760c003dc970b7987896a36
Reviewed-on: https://chromium-review.googlesource.com/190247
Tested-by: Gilad Arnold <garnold@chromium.org>
Reviewed-by: Alex Deymo <deymo@chromium.org>
Commit-Queue: Gilad Arnold <garnold@chromium.org>
diff --git a/policy_manager/fake_state.cc b/policy_manager/fake_state.cc
index 977e9d3..19df440 100644
--- a/policy_manager/fake_state.cc
+++ b/policy_manager/fake_state.cc
@@ -5,12 +5,14 @@
 #include "update_engine/policy_manager/fake_random_provider.h"
 #include "update_engine/policy_manager/fake_shill_provider.h"
 #include "update_engine/policy_manager/fake_state.h"
+#include "update_engine/policy_manager/fake_time_provider.h"
 
 namespace chromeos_policy_manager {
 
 FakeState::FakeState() {
   set_random_provider(new FakeRandomProvider());
   set_shill_provider(new FakeShillProvider());
+  set_time_provider(new FakeTimeProvider());
 }
 
 }  // namespace chromeos_policy_manager
diff --git a/policy_manager/fake_time_provider.h b/policy_manager/fake_time_provider.h
new file mode 100644
index 0000000..6797f5c
--- /dev/null
+++ b/policy_manager/fake_time_provider.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2014 The Chromium OS 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 CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_FAKE_TIME_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_FAKE_TIME_PROVIDER_H_
+
+#include "update_engine/policy_manager/fake_variable.h"
+#include "update_engine/policy_manager/time_provider.h"
+
+namespace chromeos_policy_manager {
+
+// Fake implementation of the TimeProvider base class.
+class FakeTimeProvider : public TimeProvider {
+ public:
+  FakeTimeProvider() {}
+
+ protected:
+  virtual bool DoInit() {
+    set_var_curr_date(
+        new FakeVariable<base::Time>("curr_date", kVariableModePoll));
+    set_var_curr_hour(
+        new FakeVariable<int>("curr_hour", kVariableModePoll));
+    return true;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FakeTimeProvider);
+};
+
+}  // namespace chromeos_policy_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_FAKE_TIME_PROVIDER_H_
diff --git a/policy_manager/real_state.cc b/policy_manager/real_state.cc
index 8f99869..2f9f3cc 100644
--- a/policy_manager/real_state.cc
+++ b/policy_manager/real_state.cc
@@ -6,13 +6,16 @@
 
 #include "update_engine/policy_manager/real_random_provider.h"
 #include "update_engine/policy_manager/real_shill_provider.h"
+#include "update_engine/policy_manager/real_time_provider.h"
 
 namespace chromeos_policy_manager {
 
 RealState::RealState(RandomProvider* random_provider,
-                     ShillProvider* shill_provider) {
+                     ShillProvider* shill_provider,
+                     TimeProvider* time_provider) {
   set_random_provider(random_provider);
   set_shill_provider(shill_provider);
+  set_time_provider(time_provider);
 }
 
 }  // namespace chromeos_policy_manager
diff --git a/policy_manager/real_state.h b/policy_manager/real_state.h
index e2eddd7..c0f1ac6 100644
--- a/policy_manager/real_state.h
+++ b/policy_manager/real_state.h
@@ -15,7 +15,8 @@
 class RealState : public State {
  public:
   // Instantiate with given providers, assuming ownership of them.
-  RealState(RandomProvider* random_provider, ShillProvider* shill_provider);
+  RealState(RandomProvider* random_provider, ShillProvider* shill_provider,
+            TimeProvider* time_provider);
 
   ~RealState() {}
 
diff --git a/policy_manager/real_state_unittest.cc b/policy_manager/real_state_unittest.cc
index 6078223..0362688 100644
--- a/policy_manager/real_state_unittest.cc
+++ b/policy_manager/real_state_unittest.cc
@@ -6,13 +6,15 @@
 
 #include "update_engine/policy_manager/fake_random_provider.h"
 #include "update_engine/policy_manager/fake_shill_provider.h"
+#include "update_engine/policy_manager/fake_time_provider.h"
 #include "update_engine/policy_manager/real_state.h"
 #include "update_engine/policy_manager/pmtest_utils.h"
 
 namespace chromeos_policy_manager {
 
 TEST(PmRealStateTest, InitTest) {
-  RealState state(new FakeRandomProvider(), new FakeShillProvider());
+  RealState state(new FakeRandomProvider(), new FakeShillProvider(),
+                  new FakeTimeProvider());
   EXPECT_TRUE(state.Init());
 
   // Check that the providers are being initialized. Beyond ensuring that we get
@@ -22,6 +24,8 @@
   PMTEST_EXPECT_NOT_NULL(state.random_provider()->var_seed());
   PMTEST_ASSERT_NOT_NULL(state.shill_provider());
   PMTEST_EXPECT_NOT_NULL(state.shill_provider()->var_is_connected());
+  PMTEST_ASSERT_NOT_NULL(state.time_provider());
+  PMTEST_ASSERT_NOT_NULL(state.time_provider()->var_curr_date());
 }
 
 }  // namespace chromeos_policy_manager
diff --git a/policy_manager/real_time_provider.cc b/policy_manager/real_time_provider.cc
new file mode 100644
index 0000000..0c20e2e
--- /dev/null
+++ b/policy_manager/real_time_provider.cc
@@ -0,0 +1,69 @@
+// Copyright (c) 2014 The Chromium OS 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 "update_engine/policy_manager/real_time_provider.h"
+
+#include <base/time.h>
+
+#include "update_engine/clock_interface.h"
+
+using base::Time;
+using base::TimeDelta;
+using chromeos_update_engine::ClockInterface;
+using std::string;
+
+namespace chromeos_policy_manager {
+
+// A variable returning the current date.
+class CurrDateVariable : public Variable<Time> {
+ public:
+  // TODO(garnold) Turn this into an async variable with the needed callback
+  // logic for when it value changes.
+  CurrDateVariable(const string& name, ClockInterface* clock)
+      : Variable<Time>(name, TimeDelta::FromHours(1)), clock_(clock) {}
+
+ protected:
+  virtual const Time* GetValue(base::TimeDelta /* timeout */,
+                               string* /* errmsg */) {
+    Time::Exploded now_exp;
+    clock_->GetWallclockTime().LocalExplode(&now_exp);
+    now_exp.hour = now_exp.minute = now_exp.second = now_exp.millisecond = 0;
+    return new Time(Time::FromLocalExploded(now_exp));
+  }
+
+ private:
+  ClockInterface* clock_;
+
+  DISALLOW_COPY_AND_ASSIGN(CurrDateVariable);
+};
+
+// A variable returning the current hour in local time.
+class CurrHourVariable : public Variable<int> {
+ public:
+  // TODO(garnold) Turn this into an async variable with the needed callback
+  // logic for when it value changes.
+  CurrHourVariable(const string& name, ClockInterface* clock)
+      : Variable<int>(name, TimeDelta::FromMinutes(5)), clock_(clock) {}
+
+ protected:
+  virtual const int* GetValue(base::TimeDelta /* timeout */,
+                              string* /* errmsg */) {
+    Time::Exploded exploded;
+    clock_->GetWallclockTime().LocalExplode(&exploded);
+    return new int(exploded.hour);
+  }
+
+ private:
+  ClockInterface* clock_;
+
+  DISALLOW_COPY_AND_ASSIGN(CurrHourVariable);
+};
+
+bool RealTimeProvider::DoInit() {
+  set_var_curr_date(new CurrDateVariable("curr_date", clock_));
+  set_var_curr_hour(new CurrHourVariable("curr_hour", clock_));
+  return true;
+}
+
+}  // namespace chromeos_policy_manager
diff --git a/policy_manager/real_time_provider.h b/policy_manager/real_time_provider.h
new file mode 100644
index 0000000..447f435
--- /dev/null
+++ b/policy_manager/real_time_provider.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2014 The Chromium OS 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 CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_REAL_TIME_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_REAL_TIME_PROVIDER_H_
+
+#include <base/time.h>
+
+#include "update_engine/clock_interface.h"
+#include "update_engine/policy_manager/time_provider.h"
+
+namespace chromeos_policy_manager {
+
+// TimeProvider concrete implementation.
+class RealTimeProvider : public TimeProvider {
+ public:
+  RealTimeProvider(chromeos_update_engine::ClockInterface* clock)
+      : clock_(clock) {}
+
+ protected:
+  virtual bool DoInit();
+
+ private:
+  // A clock abstraction (mockable).
+  chromeos_update_engine::ClockInterface* const clock_;
+
+  DISALLOW_COPY_AND_ASSIGN(RealTimeProvider);
+};
+
+}  // namespace chromeos_policy_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_REAL_TIME_PROVIDER_H_
diff --git a/policy_manager/real_time_provider_unittest.cc b/policy_manager/real_time_provider_unittest.cc
new file mode 100644
index 0000000..1ac9083
--- /dev/null
+++ b/policy_manager/real_time_provider_unittest.cc
@@ -0,0 +1,81 @@
+// Copyright (c) 2014 The Chromium OS 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 <base/logging.h>
+#include <base/memory/scoped_ptr.h>
+#include <base/time.h>
+#include <gtest/gtest.h>
+
+#include "update_engine/fake_clock.h"
+#include "update_engine/policy_manager/pmtest_utils.h"
+#include "update_engine/policy_manager/real_time_provider.h"
+
+using base::Time;
+using base::TimeDelta;
+using chromeos_update_engine::FakeClock;
+
+namespace chromeos_policy_manager {
+
+class PmRealTimeProviderTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    // The provider initializes correctly.
+    provider_.reset(new RealTimeProvider(&fake_clock_));
+    PMTEST_ASSERT_NOT_NULL(provider_.get());
+    ASSERT_TRUE(provider_->Init());
+  }
+
+  // Generates a fixed timestamp for use in faking the current time.
+  Time CurrTime() {
+    Time::Exploded now_exp;
+    now_exp.year = 2014;
+    now_exp.month = 3;
+    now_exp.day_of_week = 2;
+    now_exp.day_of_month = 18;
+    now_exp.hour = 8;
+    now_exp.minute = 5;
+    now_exp.second = 33;
+    now_exp.millisecond = 675;
+    return Time::FromLocalExploded(now_exp);
+  }
+
+  const TimeDelta default_timeout_ = TimeDelta::FromSeconds(1);
+  FakeClock fake_clock_;
+  scoped_ptr<RealTimeProvider> provider_;
+};
+
+TEST_F(PmRealTimeProviderTest, CurrDateValid) {
+  const Time now = CurrTime();
+  Time::Exploded expected;
+  now.LocalExplode(&expected);
+  fake_clock_.SetWallclockTime(now);
+  scoped_ptr<const Time> curr_date(
+      provider_->var_curr_date()->GetValue(default_timeout_, NULL));
+  PMTEST_ASSERT_NOT_NULL(curr_date.get());
+
+  Time::Exploded actual;
+  curr_date->LocalExplode(&actual);
+  EXPECT_EQ(expected.year, actual.year);
+  EXPECT_EQ(expected.month, actual.month);
+  EXPECT_EQ(expected.day_of_week, actual.day_of_week);
+  EXPECT_EQ(expected.day_of_month, actual.day_of_month);
+  EXPECT_EQ(0, actual.hour);
+  EXPECT_EQ(0, actual.minute);
+  EXPECT_EQ(0, actual.second);
+  EXPECT_EQ(0, actual.millisecond);
+}
+
+TEST_F(PmRealTimeProviderTest, CurrHourValid) {
+  const Time now = CurrTime();
+  Time::Exploded expected;
+  now.LocalExplode(&expected);
+  fake_clock_.SetWallclockTime(now);
+  scoped_ptr<const int> curr_hour(
+      provider_->var_curr_hour()->GetValue(default_timeout_, NULL));
+  PMTEST_ASSERT_NOT_NULL(curr_hour.get());
+
+  EXPECT_EQ(expected.hour, *curr_hour);
+}
+
+}  // namespace chromeos_policy_manager
diff --git a/policy_manager/state.h b/policy_manager/state.h
index 4950b56..fb847a7 100644
--- a/policy_manager/state.h
+++ b/policy_manager/state.h
@@ -7,6 +7,7 @@
 
 #include "update_engine/policy_manager/random_provider.h"
 #include "update_engine/policy_manager/shill_provider.h"
+#include "update_engine/policy_manager/time_provider.h"
 
 namespace chromeos_policy_manager {
 
@@ -20,12 +21,14 @@
   // succeeded.
   bool Init() {
     return (random_provider_ && random_provider_->Init() &&
-            shill_provider_ && shill_provider_->Init());
+            shill_provider_ && shill_provider_->Init() &&
+            time_provider_ && time_provider_->Init());
   }
 
   // These functions return the given provider.
   RandomProvider* random_provider() { return random_provider_.get(); }
   ShillProvider* shill_provider() { return shill_provider_.get(); }
+  TimeProvider* time_provider() { return time_provider_.get(); }
 
  protected:
   // Initialize the private scoped_ptr for each provider.
@@ -37,10 +40,15 @@
     return shill_provider_.reset(shill_provider);
   }
 
+  void set_time_provider(TimeProvider* time_provider) {
+    return time_provider_.reset(time_provider);
+  }
+
  private:
   // Instances of the providers.
   scoped_ptr<RandomProvider> random_provider_;
   scoped_ptr<ShillProvider> shill_provider_;
+  scoped_ptr<TimeProvider> time_provider_;
 };
 
 }  // namespace chromeos_policy_manager
diff --git a/policy_manager/time_provider.h b/policy_manager/time_provider.h
new file mode 100644
index 0000000..d09097b
--- /dev/null
+++ b/policy_manager/time_provider.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2014 The Chromium OS 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 CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_TIME_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_TIME_PROVIDER_H_
+
+#include <base/memory/scoped_ptr.h>
+#include <base/time.h>
+
+#include "update_engine/policy_manager/provider.h"
+#include "update_engine/policy_manager/variable.h"
+
+namespace chromeos_policy_manager {
+
+// Provider for time related information.
+class TimeProvider : public Provider {
+ public:
+  // Returns the current date. The time of day component will be zero.
+  Variable<base::Time>* var_curr_date() const {
+    return var_curr_date_.get();
+  }
+
+  // Returns the current hour (0 to 23) in local time. The type is int to keep
+  // consistent with base::Time.
+  Variable<int>* var_curr_hour() const {
+    return var_curr_hour_.get();
+  }
+
+  // TODO(garnold) Implement a method/variable for querying whether a given
+  // point in time was reached.
+
+ protected:
+  TimeProvider() {}
+
+  void set_var_curr_date(Variable<base::Time>* var_curr_date) {
+    var_curr_date_.reset(var_curr_date);
+  }
+
+  void set_var_curr_hour(Variable<int>* var_curr_hour) {
+    var_curr_hour_.reset(var_curr_hour);
+  }
+
+ private:
+  scoped_ptr<Variable<base::Time>> var_curr_date_;
+  scoped_ptr<Variable<int>> var_curr_hour_;
+
+  DISALLOW_COPY_AND_ASSIGN(TimeProvider);
+};
+
+}  // namespace chromeos_policy_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_TIME_PROVIDER_H_
diff --git a/policy_manager/variable.h b/policy_manager/variable.h
index be3fdb1..b00eca4 100644
--- a/policy_manager/variable.h
+++ b/policy_manager/variable.h
@@ -145,6 +145,9 @@
   FRIEND_TEST(PmRealShillProviderTest, ReadChangedValuesConnectedViaEthernet);
   FRIEND_TEST(PmRealShillProviderTest, ReadChangedValuesConnectedViaVpn);
   FRIEND_TEST(PmRealShillProviderTest, ReadChangedValuesConnectedTwoSignals);
+  friend class PmRealTimeProviderTest;
+  FRIEND_TEST(PmRealTimeProviderTest, CurrDateValid);
+  FRIEND_TEST(PmRealTimeProviderTest, CurrHourValid);
 
   Variable(const std::string& name, VariableMode mode)
       : BaseVariable(name, mode) {}