root/chrome/browser/network_time/network_time_tracker_unittest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. NowTicks
  2. network_time_notifier_
  3. TearDown
  4. Now
  5. TicksNow
  6. AddToTicksNow
  7. StartTracker
  8. StopTracker
  9. UpdateNetworkTime
  10. ValidateExpectedTime
  11. network_time_tracker
  12. TEST_F
  13. TEST_F
  14. TEST_F
  15. TEST_F

// Copyright 2013 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/network_time/network_time_tracker.h"

#include <math.h>

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/compiler_specific.h"
#include "base/message_loop/message_loop.h"
#include "content/public/test/test_browser_thread.h"
#include "net/base/network_time_notifier.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {

// These are all in milliseconds.
const int64 kLatency1 = 50;
const int64 kLatency2 = 500;

// Can not be smaller than 15, it's the NowFromSystemTime() resolution.
const int64 kResolution1 = 17;
const int64 kResolution2 = 177;

const int64 kPseudoSleepTime1 = 500000001;
const int64 kPseudoSleepTime2 = 1888;

// A custom tick clock that will return an arbitrary time.
class TestTickClock : public base::TickClock {
 public:
  explicit TestTickClock(base::TimeTicks* ticks_now) : ticks_now_(ticks_now) {}
  virtual ~TestTickClock() {}

  virtual base::TimeTicks NowTicks() OVERRIDE {
    return *ticks_now_;
  }

 private:
  base::TimeTicks* ticks_now_;
};

}  // namespace

class NetworkTimeTrackerTest : public testing::Test {
 public:
  NetworkTimeTrackerTest()
      : ui_thread(content::BrowserThread::UI, &message_loop_),
        io_thread(content::BrowserThread::IO, &message_loop_),
        now_(base::Time::NowFromSystemTime()),
        tick_clock_(new TestTickClock(&ticks_now_)),
        network_time_notifier_(
            new net::NetworkTimeNotifier(
                tick_clock_.PassAs<base::TickClock>())) {}
  virtual ~NetworkTimeTrackerTest() {}

  virtual void TearDown() OVERRIDE {
    message_loop_.RunUntilIdle();
  }

  base::Time Now() const {
    return now_ + (ticks_now_ - base::TimeTicks());
  }

  base::TimeTicks TicksNow() const {
    return ticks_now_;
  }

  void AddToTicksNow(int64 ms) {
    ticks_now_ += base::TimeDelta::FromMilliseconds(ms);
  }

  void StartTracker() {
    network_time_tracker_.reset(new NetworkTimeTracker());
    network_time_notifier_->AddObserver(
        network_time_tracker_->BuildObserverCallback());
    message_loop_.RunUntilIdle();
  }

  void StopTracker() {
    network_time_tracker_.reset();
  }

  // Updates the notifier's time with the specified parameters and waits until
  // the observers have been updated.
  void UpdateNetworkTime(const base::Time& network_time,
                         const base::TimeDelta& resolution,
                         const base::TimeDelta& latency,
                         const base::TimeTicks& post_time) {
    message_loop_.PostTask(
        FROM_HERE,
        base::Bind(&net::NetworkTimeNotifier::UpdateNetworkTime,
                   base::Unretained(network_time_notifier_.get()),
                   network_time,
                   resolution,
                   latency,
                   post_time));
    message_loop_.RunUntilIdle();
  }

  // Ensures the network time tracker has a network time and that the
  // disparity between the network time version of |ticks_now_| and the actual
  // |ticks_now_| value is within the uncertainty (should always be true
  // because the network time notifier uses |ticks_now_| for the tick clock).
  testing::AssertionResult ValidateExpectedTime() const {
    base::Time network_time;
    base::TimeDelta uncertainty;
    if (!network_time_tracker_->GetNetworkTime(TicksNow(),
                                               &network_time,
                                               &uncertainty))
      return testing::AssertionFailure() << "Failed to get network time.";
    if (fabs(static_cast<double>(Now().ToInternalValue() -
                                 network_time.ToInternalValue())) >
             static_cast<double>(uncertainty.ToInternalValue())) {
      return testing::AssertionFailure()
          << "Expected network time not within uncertainty.";
    }
    return testing::AssertionSuccess();
  }

  NetworkTimeTracker* network_time_tracker() {
    return network_time_tracker_.get();
  }

 private:
  // Message loop and threads for the tracker's internal logic.
  base::MessageLoop message_loop_;
  content::TestBrowserThread ui_thread;
  content::TestBrowserThread io_thread;

  // Used in building the current time that |tick_clock_| reports. See Now()
  // for details.
  base::Time now_;
  base::TimeTicks ticks_now_;

  // A custom clock that allows arbitrary time delays.
  scoped_ptr<TestTickClock> tick_clock_;

  // The network time notifier that receives time updates and posts them to
  // the tracker.
  scoped_ptr<net::NetworkTimeNotifier> network_time_notifier_;

  // The network time tracker being tested.
  scoped_ptr<NetworkTimeTracker> network_time_tracker_;
};

// Should not return a value before UpdateNetworkTime gets called.
TEST_F(NetworkTimeTrackerTest, Uninitialized) {
  base::Time network_time;
  base::TimeDelta uncertainty;
  StartTracker();
  EXPECT_FALSE(network_time_tracker()->GetNetworkTime(base::TimeTicks(),
                                                      &network_time,
                                                      &uncertainty));
}

// Verify that the the tracker receives and properly handles updates to the
// network time.
TEST_F(NetworkTimeTrackerTest, NetworkTimeUpdates) {
  StartTracker();
  UpdateNetworkTime(
      Now(),
      base::TimeDelta::FromMilliseconds(kResolution1),
      base::TimeDelta::FromMilliseconds(kLatency1),
      TicksNow());
  EXPECT_TRUE(ValidateExpectedTime());

  // Fake a wait for kPseudoSleepTime1 to make sure we keep tracking.
  AddToTicksNow(kPseudoSleepTime1);
  EXPECT_TRUE(ValidateExpectedTime());

  // Update the time with a new now value and kLatency2.
  UpdateNetworkTime(
      Now(),
      base::TimeDelta::FromMilliseconds(kResolution2),
      base::TimeDelta::FromMilliseconds(kLatency2),
      TicksNow());

  // Fake a wait for kPseudoSleepTime2 to make sure we keep tracking still.
  AddToTicksNow(kPseudoSleepTime2);
  EXPECT_TRUE(ValidateExpectedTime());

  // Fake a long delay between update task post time and the network notifier
  // updating its network time. The uncertainty should account for the
  // disparity.
  base::Time old_now = Now();
  base::TimeTicks old_ticks = TicksNow();
  AddToTicksNow(kPseudoSleepTime2);
  UpdateNetworkTime(
      old_now,
      base::TimeDelta::FromMilliseconds(kResolution2),
      base::TimeDelta::FromMilliseconds(kLatency2),
      old_ticks);
  EXPECT_TRUE(ValidateExpectedTime());
}

// Starting the tracker after the network time has been set with the notifier
// should update the tracker's time as well.
TEST_F(NetworkTimeTrackerTest, UpdateThenStartTracker) {
  UpdateNetworkTime(
      Now(),
      base::TimeDelta::FromMilliseconds(kResolution1),
      base::TimeDelta::FromMilliseconds(kLatency1),
      TicksNow());
  StartTracker();
  EXPECT_TRUE(ValidateExpectedTime());
}

// Time updates after the tracker has been destroyed should not attempt to
// dereference the destroyed tracker.
TEST_F(NetworkTimeTrackerTest, UpdateAfterTrackerDestroyed) {
  StartTracker();
  StopTracker();
  UpdateNetworkTime(
      Now(),
      base::TimeDelta::FromMilliseconds(kResolution1),
      base::TimeDelta::FromMilliseconds(kLatency1),
      TicksNow());
}

/* [<][>][^][v][top][bottom][index][help] */