Add some basic tests for metrics_daemon.

A separate CL adds a test stanza to the metrics ebuild. More tests
(specifically, for the D-Bus MessageFilter) will also come in a
separate CL.

Review URL: http://codereview.chromium.org/1919005
diff --git a/metrics/Makefile b/metrics/Makefile
index 784ff91..cb85fb9 100644
--- a/metrics/Makefile
+++ b/metrics/Makefile
@@ -12,7 +12,7 @@
 
 CLIENT = metrics_client
 DAEMON = metrics_daemon
-TESTDAEMON = test_daemon
+DAEMON_TEST = metrics_daemon_test
 LIB = libmetrics.a
 SHAREDLIB = libmetrics.so
 
@@ -25,12 +25,14 @@
 	metrics_daemon_main.o
 TESTDAEMON_OBJS = \
 	metrics_daemon.o \
-	metrics_daemon_unittest.o
+	metrics_daemon_test.o
 
 DAEMON_LDFLAGS = $(LDCONFIG) -lrt -lbase -lpthread -lgflags
 TESTDAEMON_LIBS = -lgtest
 
-all: $(LIB) $(SHAREDLIB) $(CLIENT) $(DAEMON) $(TESTDAEMON)
+all: $(LIB) $(SHAREDLIB) $(CLIENT) $(DAEMON)
+
+tests: $(DAEMON_TEST)
 
 $(CLIENT): $(CLIENT_OBJS) $(SHAREDLIB)
 	$(CXX) $(LDFLAGS) $^ -o $@
@@ -38,11 +40,11 @@
 $(DAEMON): $(DAEMON_OBJS) $(SHAREDLIB)
 	$(CXX) -o $@ $^ $(DAEMON_LDFLAGS)
 
-$(TESTDAEMON): $(TESTDAEMON_OBJS) $(SHAREDLIB)
+$(DAEMON_TEST): $(TESTDAEMON_OBJS) $(SHAREDLIB)
 	$(CXX) -o $@ $^ $(DAEMON_LDFLAGS) $(TESTDAEMON_LIBS)
 
 $(LIB): $(LIB_OBJS)
-	ar rcs $@ $^
+	$(AR) rcs $@ $^
 
 $(SHAREDLIB): $(LIB_OBJS)
 	$(CXX) $(LDFLAGS) -shared $^ -o $@
@@ -56,7 +58,7 @@
 	metrics_daemon.h \
 	network_states.h \
 	power_states.h
-metrics_daemon_unittest.o: \
+metrics_daemon_test.o: \
 	metrics_daemon.h \
 	network_states.h \
 	power_states.h
diff --git a/metrics/make_tests.sh b/metrics/make_tests.sh
new file mode 100755
index 0000000..9dcc804
--- /dev/null
+++ b/metrics/make_tests.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Copyright (c) 2010 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.
+
+# Builds tests.
+
+set -e
+make tests
+mkdir -p "${OUT_DIR}"
+cp *_test "${OUT_DIR}"
diff --git a/metrics/metrics_daemon.cc b/metrics/metrics_daemon.cc
index ef973a2..da96dc2 100644
--- a/metrics/metrics_daemon.cc
+++ b/metrics/metrics_daemon.cc
@@ -37,6 +37,20 @@
 static const int kUseMonitorIntervalInit = 1 * kSecondsPerMinute;
 static const int kUseMonitorIntervalMax = 10 * kSecondsPerMinute;
 
+// static metrics parameters.
+const char MetricsDaemon::kMetricDailyUseTimeName[] =
+    "Logging.DailyUseTime";
+const int MetricsDaemon::kMetricDailyUseTimeMin = 1;
+const int MetricsDaemon::kMetricDailyUseTimeMax = kMinutesPerDay;
+const int MetricsDaemon::kMetricDailyUseTimeBuckets = 50;
+
+const char MetricsDaemon::kMetricTimeToNetworkDropName[] =
+    "Network.TimeToDrop";
+const int MetricsDaemon::kMetricTimeToNetworkDropMin = 1;
+const int MetricsDaemon::kMetricTimeToNetworkDropMax =
+    8 /* hours */ * kMinutesPerHour * kSecondsPerMinute;
+const int MetricsDaemon::kMetricTimeToNetworkDropBuckets = 50;
+
 // static
 const char* MetricsDaemon::kDBusMatches_[] = {
   "type='signal',"
@@ -86,8 +100,8 @@
 #include "session_states.h"
 };
 
-void MetricsDaemon::Run(bool run_as_daemon, bool testing) {
-  Init(testing);
+void MetricsDaemon::Run(bool run_as_daemon) {
+  Init(false);
   if (!run_as_daemon || daemon(0, 0) == 0) {
     Loop();
   }
@@ -95,6 +109,11 @@
 
 void MetricsDaemon::Init(bool testing) {
   testing_ = testing;
+  daily_use_record_file_ = kDailyUseRecordFile;
+
+  // Don't setup D-Bus and GLib in test mode.
+  if (testing)
+    return;
 
   g_thread_init(NULL);
   g_type_init();
@@ -192,17 +211,19 @@
   NetworkState state = LookupNetworkState(state_name);
 
   // Logs the time in seconds between the network going online to
-  // going offline in order to measure the mean time to network
-  // dropping. Going offline as part of suspend-to-RAM is not logged
-  // as network drop -- the assumption is that the message for
-  // suspend-to-RAM comes before the network offline message which
-  // seems to and should be the case.
-  if (state == kNetworkStateOffline &&
+  // going offline (or, more precisely, going not online) in order to
+  // measure the mean time to network dropping. Going offline as part
+  // of suspend-to-RAM is not logged as network drop -- the assumption
+  // is that the message for suspend-to-RAM comes before the network
+  // offline message which seems to and should be the case.
+  if (state != kNetworkStateOnline &&
       network_state_ == kNetworkStateOnline &&
       power_state_ != kPowerStateMem) {
     int online_time = static_cast<int>(now - network_state_last_);
-    PublishMetric("Network.TimeToDrop", online_time,
-                  1, 8 /* hours */ * 60 * 60, 50);
+    PublishMetric(kMetricTimeToNetworkDropName, online_time,
+                  kMetricTimeToNetworkDropMin,
+                  kMetricTimeToNetworkDropMax,
+                  kMetricTimeToNetworkDropBuckets);
   }
 
   network_state_ = state;
@@ -304,11 +325,11 @@
     return;
 
   DLOG(INFO) << "day: " << day << " usage: " << seconds << " seconds";
-  int fd = HANDLE_EINTR(open(kDailyUseRecordFile,
+  int fd = HANDLE_EINTR(open(daily_use_record_file_,
                              O_RDWR | O_CREAT,
                              S_IRUSR | S_IWUSR));
   if (fd < 0) {
-    DLOG(WARNING) << "Unable to open the daily use file.";
+    PLOG(WARNING) << "Unable to open the daily use file";
     return;
   }
 
@@ -325,12 +346,14 @@
       // the usage to the nearest minute and sends it to UMA.
       int minutes =
           (record.seconds_ + kSecondsPerMinute / 2) / kSecondsPerMinute;
-      PublishMetric("Logging.DailyUseTime",
-                    minutes, 1, kMinutesPerDay, 50);
+      PublishMetric(kMetricDailyUseTimeName, minutes,
+                    kMetricDailyUseTimeMin,
+                    kMetricDailyUseTimeMax,
+                    kMetricDailyUseTimeBuckets);
 
       // Truncates the usage file to ensure that no duplicate usage is
       // sent to UMA.
-      LOG_IF(WARNING, HANDLE_EINTR(ftruncate(fd, 0)) != 0);
+      PLOG_IF(WARNING, HANDLE_EINTR(ftruncate(fd, 0)) != 0);
     }
   }
 
@@ -344,9 +367,10 @@
     // else an already existing record for the same day will be
     // overwritten with updated usage below.
 
-    LOG_IF(WARNING, HANDLE_EINTR(lseek(fd, 0, SEEK_SET)) != 0);
-    LOG_IF(WARNING,
-           HANDLE_EINTR(write(fd, &record, sizeof(record))) != sizeof(record));
+    PLOG_IF(WARNING, HANDLE_EINTR(lseek(fd, 0, SEEK_SET)) != 0);
+    PLOG_IF(WARNING,
+            HANDLE_EINTR(write(fd, &record, sizeof(record))) !=
+            sizeof(record));
   }
 
   HANDLE_EINTR(close(fd));
@@ -374,6 +398,9 @@
 
 bool MetricsDaemon::ScheduleUseMonitor(int interval, bool backoff)
 {
+  if (testing_)
+    return false;
+
   // Caps the interval -- the bigger the interval, the more active use
   // time will be potentially dropped on system shutdown.
   if (interval > kUseMonitorIntervalMax)
@@ -417,8 +444,8 @@
 
 void MetricsDaemon::PublishMetric(const char* name, int sample,
                                   int min, int max, int nbuckets) {
-  DLOG(INFO) << "received metric: " << name << " " << sample << " "
-             << min << " " << max << " " << nbuckets;
+  LOG(INFO) << "received metric: " << name << " " << sample << " "
+            << min << " " << max << " " << nbuckets;
   if (!testing_) {
     MetricsLibrary::SendToChrome(name, sample, min, max, nbuckets);
   }
diff --git a/metrics/metrics_daemon.h b/metrics/metrics_daemon.h
index 99f76d0..028525a 100644
--- a/metrics/metrics_daemon.h
+++ b/metrics/metrics_daemon.h
@@ -9,11 +9,14 @@
 #include <glib.h>
 #include <time.h>
 
+#include <gtest/gtest_prod.h>  // for FRIEND_TEST
+
 class MetricsDaemon {
 
  public:
   MetricsDaemon()
-      : network_state_(kUnknownNetworkState),
+      : daily_use_record_file_(NULL),
+        network_state_(kUnknownNetworkState),
         network_state_last_(0),
         power_state_(kUnknownPowerState),
         screensaver_state_(kUnknownScreenSaverState),
@@ -26,11 +29,23 @@
   ~MetricsDaemon() {}
 
   // Does all the work. If |run_as_daemon| is true, daemonizes by
-  // forking. If |testing| is true, logs the stats instead of sending
-  // them to Chrome.
-  void Run(bool run_as_daemon, bool testing);
+  // forking.
+  void Run(bool run_as_daemon);
 
  private:
+  friend class MetricsDaemonTest;
+  FRIEND_TEST(MetricsDaemonTest, LogDailyUseRecord);
+  FRIEND_TEST(MetricsDaemonTest, LookupNetworkState);
+  FRIEND_TEST(MetricsDaemonTest, LookupPowerState);
+  FRIEND_TEST(MetricsDaemonTest, LookupScreenSaverState);
+  FRIEND_TEST(MetricsDaemonTest, LookupSessionState);
+  FRIEND_TEST(MetricsDaemonTest, NetStateChanged);
+  FRIEND_TEST(MetricsDaemonTest, PowerStateChanged);
+  FRIEND_TEST(MetricsDaemonTest, PublishMetric);
+  FRIEND_TEST(MetricsDaemonTest, ScreenSaverStateChanged);
+  FRIEND_TEST(MetricsDaemonTest, SessionStateChanged);
+  FRIEND_TEST(MetricsDaemonTest, SetUserActiveState);
+
   // The network states (see network_states.h).
   enum NetworkState {
     kUnknownNetworkState = -1, // Initial/unknown network state.
@@ -71,6 +86,16 @@
     int seconds_;
   };
 
+  // Metric parameters.
+  static const char kMetricDailyUseTimeName[];
+  static const int kMetricDailyUseTimeMin;
+  static const int kMetricDailyUseTimeMax;
+  static const int kMetricDailyUseTimeBuckets;
+  static const char kMetricTimeToNetworkDropName[];
+  static const int kMetricTimeToNetworkDropMin;
+  static const int kMetricTimeToNetworkDropMax;
+  static const int kMetricTimeToNetworkDropBuckets;
+
   // D-Bus message match strings.
   static const char* kDBusMatches_[];
 
@@ -161,9 +186,11 @@
   void PublishMetric(const char* name, int sample,
                      int min, int max, int nbuckets);
 
-  // Testing mode.
+  // Test mode.
   bool testing_;
 
+  const char* daily_use_record_file_;
+
   // Current network state.
   NetworkState network_state_;
 
diff --git a/metrics/metrics_daemon_main.cc b/metrics/metrics_daemon_main.cc
index 302bdcb..7ace333 100644
--- a/metrics/metrics_daemon_main.cc
+++ b/metrics/metrics_daemon_main.cc
@@ -12,5 +12,5 @@
 int main(int argc, char** argv) {
   MetricsDaemon::MetricsDaemon d;
   google::ParseCommandLineFlags(&argc, &argv, true);
-  d.Run(FLAGS_daemon, false);
+  d.Run(FLAGS_daemon);
 }
diff --git a/metrics/metrics_daemon_test.cc b/metrics/metrics_daemon_test.cc
new file mode 100644
index 0000000..043be72
--- /dev/null
+++ b/metrics/metrics_daemon_test.cc
@@ -0,0 +1,459 @@
+// Copyright (c) 2010 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 "metrics_daemon.h"
+
+#include <sys/file.h>
+
+#include <base/eintr_wrapper.h>
+#include <base/file_util.h>
+#include <base/logging.h>
+#include <base/string_util.h>
+#include <gtest/gtest.h>
+
+static const char kTestDailyUseRecordFile[] = "/tmp/daily-usage-test";
+static const char kDoesNotExistFile[] = "/does/not/exist";
+
+static const int kSecondsPerDay = 24 * 60 * 60;
+
+class MetricsDaemonTest : public testing::Test {
+ protected:
+  virtual void SetUp() {
+    daemon_.Init(true);
+    daemon_.daily_use_record_file_ = kTestDailyUseRecordFile;
+
+    // The test fixture object will be used by the log message handler.
+    daemon_test_ = this;
+    logging::SetLogMessageHandler(LogMessageHandler);
+  }
+
+  virtual void TearDown() {
+    logging::SetLogMessageHandler(NULL);
+    daemon_test_ = NULL;
+    file_util::Delete(FilePath(kTestDailyUseRecordFile), false);
+  }
+
+  // Collects log messages in the |daemon_log_| member string so that
+  // they can be analyzed for errors and expected behavior.
+  static bool LogMessageHandler(int severity, const std::string& str) {
+    daemon_test_->daemon_log_.append(str);
+    daemon_test_->daemon_log_.append("\n");
+
+    // Returning true would mute the log.
+    return false;
+  }
+
+  // Returns true if the daemon log contains |pattern|, false otherwise.
+  bool LogContains(const std::string& pattern) {
+    return daemon_log_.find(pattern) != std::string::npos;
+  }
+
+  // Resets the daemon log history to empty.
+  void LogReset() {
+    daemon_log_.clear();
+  }
+
+  // Returns true if the specified metric is found in the generated
+  // log so far, false otherwise.
+  bool AssertMetricGenerated(const std::string& name, int sample,
+                             int min, int max, int buckets) {
+    return LogContains(StringPrintf("received metric: %s %d %d %d %d",
+                                    name.c_str(), sample, min, max, buckets));
+  }
+
+  // Returns true if the specified daily use time metric is found in
+  // the generated log so far, false otherwise.
+  bool AssertDailyUseTimeMetric(int sample) {
+    return AssertMetricGenerated(
+        MetricsDaemon::kMetricDailyUseTimeName, sample,
+        MetricsDaemon::kMetricDailyUseTimeMin,
+        MetricsDaemon::kMetricDailyUseTimeMax,
+        MetricsDaemon::kMetricDailyUseTimeBuckets);
+  }
+
+  // Returns true if the specified time to network drop metric is
+  // found in the generated log so far, false otherwise.
+  bool AssertTimeToNetworkDropMetric(int sample) {
+    return AssertMetricGenerated(
+        MetricsDaemon::kMetricTimeToNetworkDropName, sample,
+        MetricsDaemon::kMetricTimeToNetworkDropMin,
+        MetricsDaemon::kMetricTimeToNetworkDropMax,
+        MetricsDaemon::kMetricTimeToNetworkDropBuckets);
+  }
+
+  // Returns true if no metric can be found in the generated log so
+  // far, false otherwise.
+  bool NoMetricGenerated() {
+    return !LogContains("received metric");
+  }
+
+  // Asserts that the daily use record file contains the specified
+  // contents.
+  testing::AssertionResult AssertDailyUseRecord(const char* expr_day,
+                                                const char* expr_seconds,
+                                                int expected_day,
+                                                int expected_seconds) {
+    int fd = HANDLE_EINTR(open(daemon_.daily_use_record_file_, O_RDONLY));
+    if (fd < 0) {
+      testing::Message msg;
+      msg << "Unable to open " << daemon_.daily_use_record_file_;
+      return testing::AssertionFailure(msg);
+    }
+
+    MetricsDaemon::UseRecord record;
+    if (!file_util::ReadFromFD(fd, reinterpret_cast<char*>(&record),
+                               sizeof(record))) {
+      testing::Message msg;
+      msg << "Unable to read " << sizeof(record) << " bytes from "
+          << daemon_.daily_use_record_file_;
+      HANDLE_EINTR(close(fd));
+      return testing::AssertionFailure(msg);
+    }
+
+    if (record.day_ != expected_day || record.seconds_ != expected_seconds) {
+      testing::Message msg;
+      msg << "actual use record (" << record.day_ << ", " << record.seconds_
+          << ") expected (" << expected_day << ", " << expected_seconds << ")";
+      HANDLE_EINTR(close(fd));
+      return testing::AssertionFailure(msg);
+    }
+
+    HANDLE_EINTR(close(fd));
+    return testing::AssertionSuccess();
+  }
+
+  bool NoOrEmptyUseRecordFile() {
+    FilePath record_file(daemon_.daily_use_record_file_);
+    int64 record_file_size;
+    return !file_util::PathExists(record_file) ||
+        (file_util::GetFileSize(record_file, &record_file_size) &&
+         record_file_size == 0);
+  }
+
+  // Pointer to the current test fixture.
+  static MetricsDaemonTest* daemon_test_;
+
+  // The MetricsDaemon under test.
+  MetricsDaemon daemon_;
+
+  // The accumulated metrics daemon log.
+  std::string daemon_log_;
+};
+
+// static
+MetricsDaemonTest* MetricsDaemonTest::daemon_test_ = NULL;
+
+TEST_F(MetricsDaemonTest, LogDailyUseRecord) {
+  EXPECT_EQ(0, daemon_.daily_use_day_last_);
+  EXPECT_TRUE(NoOrEmptyUseRecordFile());
+
+  daemon_.LogDailyUseRecord(/* day */ 5, /* seconds */ 120);
+  EXPECT_PRED_FORMAT2(AssertDailyUseRecord, /* day */ 5, /* seconds */ 120);
+  EXPECT_EQ(5, daemon_.daily_use_day_last_);
+
+  daemon_.LogDailyUseRecord(/* day */ 5, /* seconds */ 0);
+  EXPECT_PRED_FORMAT2(AssertDailyUseRecord, /* day */ 5, /* seconds */ 120);
+  EXPECT_EQ(5, daemon_.daily_use_day_last_);
+
+  daemon_.LogDailyUseRecord(/* day */ 5, /* seconds */ 240);
+  EXPECT_PRED_FORMAT2(AssertDailyUseRecord, /* day */ 5, /* seconds */ 360);
+  EXPECT_EQ(5, daemon_.daily_use_day_last_);
+
+  EXPECT_TRUE(NoMetricGenerated());
+
+  LogReset();
+  daemon_.LogDailyUseRecord(/* day */ 6, /* seconds */ 0);
+  EXPECT_TRUE(NoOrEmptyUseRecordFile());
+  EXPECT_TRUE(AssertDailyUseTimeMetric(/* sample */ 6));
+  EXPECT_EQ(6, daemon_.daily_use_day_last_);
+
+  // Tests rounding use time to the closest minute.
+  daemon_.LogDailyUseRecord(/* day */ 6, /* seconds */ 90);
+  EXPECT_PRED_FORMAT2(AssertDailyUseRecord, /* day */ 6, /* seconds */ 90);
+  EXPECT_EQ(6, daemon_.daily_use_day_last_);
+
+  LogReset();
+  daemon_.LogDailyUseRecord(/* day */ 7, /* seconds */ 89);
+  EXPECT_PRED_FORMAT2(AssertDailyUseRecord, /* day */ 7, /* seconds */ 89);
+  EXPECT_TRUE(AssertDailyUseTimeMetric(/* sample */ 2));
+  EXPECT_EQ(7, daemon_.daily_use_day_last_);
+
+  LogReset();
+  daemon_.LogDailyUseRecord(/* day */ 6, /* seconds */ 15);
+  EXPECT_PRED_FORMAT2(AssertDailyUseRecord, /* day */ 6, /* seconds */ 15);
+  EXPECT_TRUE(AssertDailyUseTimeMetric(/* sample */ 1));
+  EXPECT_EQ(6, daemon_.daily_use_day_last_);
+
+  // Checks that the daemon doesn't die badly if the file can't be
+  // created.
+  LogReset();
+  daemon_.daily_use_record_file_ = kDoesNotExistFile;
+  daemon_.LogDailyUseRecord(10, 20);
+  EXPECT_TRUE(LogContains("Unable to open the daily use file: "
+                          "No such file or directory"));
+  EXPECT_EQ(6, daemon_.daily_use_day_last_);
+  file_util::Delete(FilePath(kDoesNotExistFile), false);
+}
+
+TEST_F(MetricsDaemonTest, LookupNetworkState) {
+  EXPECT_EQ(MetricsDaemon::kNetworkStateOnline,
+            daemon_.LookupNetworkState("online"));
+  EXPECT_EQ(MetricsDaemon::kNetworkStateOffline,
+            daemon_.LookupNetworkState("offline"));
+  EXPECT_EQ(MetricsDaemon::kUnknownNetworkState,
+            daemon_.LookupNetworkState("somestate"));
+}
+
+TEST_F(MetricsDaemonTest, LookupPowerState) {
+  EXPECT_EQ(MetricsDaemon::kPowerStateOn,
+            daemon_.LookupPowerState("on"));
+  EXPECT_EQ(MetricsDaemon::kPowerStateMem,
+            daemon_.LookupPowerState("mem"));
+  EXPECT_EQ(MetricsDaemon::kUnknownPowerState,
+            daemon_.LookupPowerState("somestate"));
+}
+
+TEST_F(MetricsDaemonTest, LookupScreenSaverState) {
+  EXPECT_EQ(MetricsDaemon::kScreenSaverStateLocked,
+            daemon_.LookupScreenSaverState("locked"));
+  EXPECT_EQ(MetricsDaemon::kScreenSaverStateUnlocked,
+            daemon_.LookupScreenSaverState("unlocked"));
+  EXPECT_EQ(MetricsDaemon::kUnknownScreenSaverState,
+            daemon_.LookupScreenSaverState("somestate"));
+}
+
+TEST_F(MetricsDaemonTest, LookupSessionState) {
+  EXPECT_EQ(MetricsDaemon::kSessionStateStarted,
+            daemon_.LookupSessionState("started"));
+  EXPECT_EQ(MetricsDaemon::kSessionStateStopped,
+            daemon_.LookupSessionState("stopped"));
+  EXPECT_EQ(MetricsDaemon::kUnknownSessionState,
+            daemon_.LookupSessionState("somestate"));
+}
+
+TEST_F(MetricsDaemonTest, NetStateChanged) {
+  EXPECT_EQ(MetricsDaemon::kUnknownNetworkState, daemon_.network_state_);
+  EXPECT_EQ(0, daemon_.network_state_last_);
+  EXPECT_EQ(MetricsDaemon::kUnknownPowerState, daemon_.power_state_);
+
+  daemon_.NetStateChanged("online", /* now */ 10);
+  EXPECT_EQ(MetricsDaemon::kNetworkStateOnline, daemon_.network_state_);
+  EXPECT_EQ(10, daemon_.network_state_last_);
+
+  EXPECT_TRUE(NoMetricGenerated());
+
+  daemon_.NetStateChanged("offline", /* now */ 30);
+  EXPECT_EQ(MetricsDaemon::kNetworkStateOffline, daemon_.network_state_);
+  EXPECT_EQ(30, daemon_.network_state_last_);
+  EXPECT_TRUE(AssertTimeToNetworkDropMetric(/* sample */ 20));
+
+  LogReset();
+  daemon_.NetStateChanged("online", /* now */ 60);
+  EXPECT_EQ(MetricsDaemon::kNetworkStateOnline, daemon_.network_state_);
+  EXPECT_EQ(60, daemon_.network_state_last_);
+
+  daemon_.PowerStateChanged("mem", /* now */ 80);
+  EXPECT_EQ(MetricsDaemon::kPowerStateMem, daemon_.power_state_);
+  EXPECT_EQ(MetricsDaemon::kNetworkStateOnline, daemon_.network_state_);
+  EXPECT_EQ(60, daemon_.network_state_last_);
+
+  daemon_.NetStateChanged("offline", /* now */ 85);
+  EXPECT_EQ(MetricsDaemon::kNetworkStateOffline, daemon_.network_state_);
+  EXPECT_EQ(85, daemon_.network_state_last_);
+
+  daemon_.NetStateChanged("somestate", /* now */ 90);
+  EXPECT_EQ(MetricsDaemon::kUnknownNetworkState, daemon_.network_state_);
+  EXPECT_EQ(90, daemon_.network_state_last_);
+
+  daemon_.NetStateChanged("offline", /* now */ 95);
+  EXPECT_EQ(MetricsDaemon::kNetworkStateOffline, daemon_.network_state_);
+  EXPECT_EQ(95, daemon_.network_state_last_);
+
+  daemon_.PowerStateChanged("on", /* now */ 100);
+  EXPECT_EQ(MetricsDaemon::kPowerStateOn, daemon_.power_state_);
+  EXPECT_EQ(MetricsDaemon::kNetworkStateOffline, daemon_.network_state_);
+  EXPECT_EQ(95, daemon_.network_state_last_);
+
+  daemon_.NetStateChanged("online", /* now */ 105);
+  EXPECT_EQ(MetricsDaemon::kNetworkStateOnline, daemon_.network_state_);
+  EXPECT_EQ(105, daemon_.network_state_last_);
+
+  EXPECT_TRUE(NoMetricGenerated());
+
+  daemon_.NetStateChanged("offline", /* now */ 108);
+  EXPECT_EQ(MetricsDaemon::kNetworkStateOffline, daemon_.network_state_);
+  EXPECT_EQ(108, daemon_.network_state_last_);
+  EXPECT_TRUE(AssertTimeToNetworkDropMetric(/* sample */ 3));
+}
+
+TEST_F(MetricsDaemonTest, PowerStateChanged) {
+  EXPECT_EQ(MetricsDaemon::kUnknownPowerState, daemon_.power_state_);
+  EXPECT_FALSE(daemon_.user_active_);
+  EXPECT_EQ(0, daemon_.user_active_last_);
+  EXPECT_EQ(0, daemon_.daily_use_day_last_);
+  EXPECT_TRUE(NoOrEmptyUseRecordFile());
+
+  daemon_.SetUserActiveState(/* active */ true, 7 * kSecondsPerDay + 15);
+  EXPECT_TRUE(daemon_.user_active_);
+  EXPECT_EQ(7 * kSecondsPerDay + 15, daemon_.user_active_last_);
+  EXPECT_EQ(7, daemon_.daily_use_day_last_);
+  EXPECT_TRUE(NoOrEmptyUseRecordFile());
+
+  daemon_.PowerStateChanged("mem", 7 * kSecondsPerDay + 45);
+  EXPECT_EQ(MetricsDaemon::kPowerStateMem, daemon_.power_state_);
+  EXPECT_FALSE(daemon_.user_active_);
+  EXPECT_EQ(7 * kSecondsPerDay + 45, daemon_.user_active_last_);
+  EXPECT_PRED_FORMAT2(AssertDailyUseRecord, /* day */ 7, /* seconds */ 30);
+
+  daemon_.PowerStateChanged("on", 7 * kSecondsPerDay + 85);
+  EXPECT_EQ(MetricsDaemon::kPowerStateOn, daemon_.power_state_);
+  EXPECT_FALSE(daemon_.user_active_);
+  EXPECT_EQ(7 * kSecondsPerDay + 45, daemon_.user_active_last_);
+  EXPECT_PRED_FORMAT2(AssertDailyUseRecord, /* day */ 7, /* seconds */ 30);
+
+  daemon_.PowerStateChanged("otherstate", 7 * kSecondsPerDay + 185);
+  EXPECT_EQ(MetricsDaemon::kUnknownPowerState, daemon_.power_state_);
+  EXPECT_FALSE(daemon_.user_active_);
+  EXPECT_EQ(7 * kSecondsPerDay + 185, daemon_.user_active_last_);
+  EXPECT_PRED_FORMAT2(AssertDailyUseRecord, /* day */ 7, /* seconds */ 30);
+
+  EXPECT_TRUE(NoMetricGenerated());
+}
+
+TEST_F(MetricsDaemonTest, PublishMetric) {
+  daemon_.PublishMetric("Dummy.Metric", /* sample */ 3,
+                        /* min */ 1, /* max */ 100, /* buckets */ 50);
+  EXPECT_TRUE(AssertMetricGenerated("Dummy.Metric", 3, 1, 100, 50));
+}
+
+TEST_F(MetricsDaemonTest, ScreenSaverStateChanged) {
+  EXPECT_EQ(MetricsDaemon::kUnknownScreenSaverState,
+            daemon_.screensaver_state_);
+  EXPECT_FALSE(daemon_.user_active_);
+  EXPECT_EQ(0, daemon_.user_active_last_);
+  EXPECT_EQ(0, daemon_.daily_use_day_last_);
+  EXPECT_TRUE(NoOrEmptyUseRecordFile());
+
+  daemon_.ScreenSaverStateChanged("locked", 5 * kSecondsPerDay + 10);
+  EXPECT_EQ(MetricsDaemon::kScreenSaverStateLocked,
+            daemon_.screensaver_state_);
+  EXPECT_FALSE(daemon_.user_active_);
+  EXPECT_EQ(5 * kSecondsPerDay + 10, daemon_.user_active_last_);
+  EXPECT_EQ(5, daemon_.daily_use_day_last_);
+  EXPECT_TRUE(NoOrEmptyUseRecordFile());
+
+  daemon_.ScreenSaverStateChanged("unlocked", 5 * kSecondsPerDay + 100);
+  EXPECT_EQ(MetricsDaemon::kScreenSaverStateUnlocked,
+            daemon_.screensaver_state_);
+  EXPECT_TRUE(daemon_.user_active_);
+  EXPECT_EQ(5 * kSecondsPerDay + 100, daemon_.user_active_last_);
+  EXPECT_TRUE(NoOrEmptyUseRecordFile());
+
+  daemon_.ScreenSaverStateChanged("otherstate", 5 * kSecondsPerDay + 300);
+  EXPECT_EQ(MetricsDaemon::kUnknownScreenSaverState,
+            daemon_.screensaver_state_);
+  EXPECT_FALSE(daemon_.user_active_);
+  EXPECT_EQ(5 * kSecondsPerDay + 300, daemon_.user_active_last_);
+  EXPECT_PRED_FORMAT2(AssertDailyUseRecord, /* day */ 5, /* seconds */ 200);
+
+  EXPECT_TRUE(NoMetricGenerated());
+}
+
+TEST_F(MetricsDaemonTest, SessionStateChanged) {
+  EXPECT_EQ(MetricsDaemon::kUnknownSessionState, daemon_.session_state_);
+  EXPECT_FALSE(daemon_.user_active_);
+  EXPECT_EQ(0, daemon_.user_active_last_);
+  EXPECT_EQ(0, daemon_.daily_use_day_last_);
+  EXPECT_TRUE(NoOrEmptyUseRecordFile());
+
+  daemon_.SessionStateChanged("started", 15 * kSecondsPerDay + 20);
+  EXPECT_EQ(MetricsDaemon::kSessionStateStarted, daemon_.session_state_);
+  EXPECT_TRUE(daemon_.user_active_);
+  EXPECT_EQ(15 * kSecondsPerDay + 20, daemon_.user_active_last_);
+  EXPECT_EQ(15, daemon_.daily_use_day_last_);
+  EXPECT_TRUE(NoOrEmptyUseRecordFile());
+
+  daemon_.SessionStateChanged("stopped", 15 * kSecondsPerDay + 150);
+  EXPECT_EQ(MetricsDaemon::kSessionStateStopped, daemon_.session_state_);
+  EXPECT_FALSE(daemon_.user_active_);
+  EXPECT_EQ(15 * kSecondsPerDay + 150, daemon_.user_active_last_);
+  EXPECT_PRED_FORMAT2(AssertDailyUseRecord, /* day */ 15, /* seconds */ 130);
+
+  daemon_.SessionStateChanged("otherstate", 15 * kSecondsPerDay + 300);
+  EXPECT_EQ(MetricsDaemon::kUnknownSessionState, daemon_.session_state_);
+  EXPECT_FALSE(daemon_.user_active_);
+  EXPECT_EQ(15 * kSecondsPerDay + 300, daemon_.user_active_last_);
+  EXPECT_PRED_FORMAT2(AssertDailyUseRecord, /* day */ 15, /* seconds */ 130);
+
+  EXPECT_TRUE(NoMetricGenerated());
+}
+
+TEST_F(MetricsDaemonTest, SetUserActiveState) {
+  EXPECT_FALSE(daemon_.user_active_);
+  EXPECT_EQ(0, daemon_.user_active_last_);
+  EXPECT_EQ(0, daemon_.daily_use_day_last_);
+  EXPECT_TRUE(NoOrEmptyUseRecordFile());
+
+  daemon_.SetUserActiveState(/* active */ false, 5 * kSecondsPerDay + 10);
+  EXPECT_FALSE(daemon_.user_active_);
+  EXPECT_EQ(5 * kSecondsPerDay + 10, daemon_.user_active_last_);
+  EXPECT_EQ(5, daemon_.daily_use_day_last_);
+  EXPECT_TRUE(NoOrEmptyUseRecordFile());
+
+  daemon_.SetUserActiveState(/* active */ true, 6 * kSecondsPerDay + 20);
+  EXPECT_TRUE(daemon_.user_active_);
+  EXPECT_EQ(6 * kSecondsPerDay + 20, daemon_.user_active_last_);
+  EXPECT_EQ(6, daemon_.daily_use_day_last_);
+  EXPECT_TRUE(NoOrEmptyUseRecordFile());
+
+  daemon_.SetUserActiveState(/* active */ true, 6 * kSecondsPerDay + 120);
+  EXPECT_TRUE(daemon_.user_active_);
+  EXPECT_EQ(6 * kSecondsPerDay + 120, daemon_.user_active_last_);
+  EXPECT_EQ(6, daemon_.daily_use_day_last_);
+  EXPECT_PRED_FORMAT2(AssertDailyUseRecord, /* day */ 6, /* seconds */ 100);
+
+  daemon_.SetUserActiveState(/* active */ false, 6 * kSecondsPerDay + 220);
+  EXPECT_FALSE(daemon_.user_active_);
+  EXPECT_EQ(6 * kSecondsPerDay + 220, daemon_.user_active_last_);
+  EXPECT_EQ(6, daemon_.daily_use_day_last_);
+  EXPECT_PRED_FORMAT2(AssertDailyUseRecord, /* day */ 6, /* seconds */ 200);
+
+  EXPECT_TRUE(NoMetricGenerated());
+
+  LogReset();
+  daemon_.SetUserActiveState(/* active */ true, 8 * kSecondsPerDay - 300);
+  EXPECT_TRUE(daemon_.user_active_);
+  EXPECT_EQ(8 * kSecondsPerDay - 300, daemon_.user_active_last_);
+  EXPECT_EQ(7, daemon_.daily_use_day_last_);
+  EXPECT_TRUE(NoOrEmptyUseRecordFile());
+  EXPECT_TRUE(AssertDailyUseTimeMetric(/* sample */ 3));
+
+  LogReset();
+  daemon_.SetUserActiveState(/* active */ false, 8 * kSecondsPerDay + 300);
+  EXPECT_FALSE(daemon_.user_active_);
+  EXPECT_EQ(8 * kSecondsPerDay + 300, daemon_.user_active_last_);
+  EXPECT_EQ(8, daemon_.daily_use_day_last_);
+  EXPECT_PRED_FORMAT2(AssertDailyUseRecord, /* day */ 8, /* seconds */ 600);
+
+  daemon_.SetUserActiveState(/* active */ true, 9 * kSecondsPerDay - 400);
+  EXPECT_TRUE(daemon_.user_active_);
+  EXPECT_EQ(9 * kSecondsPerDay - 400, daemon_.user_active_last_);
+  EXPECT_EQ(8, daemon_.daily_use_day_last_);
+  EXPECT_PRED_FORMAT2(AssertDailyUseRecord, /* day */ 8, /* seconds */ 600);
+
+  EXPECT_TRUE(NoMetricGenerated());
+
+  LogReset();
+  daemon_.SetUserActiveState(/* active */ true, 9 * kSecondsPerDay + 400);
+  EXPECT_TRUE(daemon_.user_active_);
+  EXPECT_EQ(9 * kSecondsPerDay + 400, daemon_.user_active_last_);
+  EXPECT_EQ(9, daemon_.daily_use_day_last_);
+  EXPECT_PRED_FORMAT2(AssertDailyUseRecord, /* day */ 9, /* seconds */ 800);
+  EXPECT_TRUE(AssertDailyUseTimeMetric(/* sample */ 10));
+}
+
+int main(int argc, char **argv) {
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/metrics/metrics_daemon_unittest.cc b/metrics/metrics_daemon_unittest.cc
deleted file mode 100644
index 222cefa..0000000
--- a/metrics/metrics_daemon_unittest.cc
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright (c) 2009 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 "metrics_daemon.h"
-
-int main(int argc, char** argv) {
-  MetricsDaemon d;
-  d.Run(false, true);
-}