blob: 9d53d7935f1f8943cbc029ee86464ba8e41b9ce1 [file] [log] [blame]
// Copyright (c) 2011 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 "content/common/inter_process_time_ticks_converter.h"
#include <stdint.h>
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::TimeTicks;
namespace content {
namespace {
struct TestParams {
int64_t local_lower_bound;
int64_t remote_lower_bound;
int64_t remote_upper_bound;
int64_t local_upper_bound;
int64_t test_time;
int64_t test_delta;
};
struct TestResults {
int64_t result_time;
int32_t result_delta;
bool is_skew_additive;
int64_t skew;
};
TestResults RunTest(const TestParams& params) {
TimeTicks local_lower_bound = TimeTicks::FromInternalValue(
params.local_lower_bound);
TimeTicks local_upper_bound = TimeTicks::FromInternalValue(
params.local_upper_bound);
TimeTicks remote_lower_bound = TimeTicks::FromInternalValue(
params.remote_lower_bound);
TimeTicks remote_upper_bound = TimeTicks::FromInternalValue(
params.remote_upper_bound);
TimeTicks test_time = TimeTicks::FromInternalValue(params.test_time);
InterProcessTimeTicksConverter converter(
LocalTimeTicks::FromTimeTicks(local_lower_bound),
LocalTimeTicks::FromTimeTicks(local_upper_bound),
RemoteTimeTicks::FromTimeTicks(remote_lower_bound),
RemoteTimeTicks::FromTimeTicks(remote_upper_bound));
TestResults results;
results.result_time = converter.ToLocalTimeTicks(
RemoteTimeTicks::FromTimeTicks(
test_time)).ToTimeTicks().ToInternalValue();
results.result_delta = converter.ToLocalTimeDelta(
RemoteTimeDelta::FromRawDelta(params.test_delta)).ToInt32();
results.is_skew_additive = converter.IsSkewAdditiveForMetrics();
results.skew = converter.GetSkewForMetrics().ToInternalValue();
return results;
}
TEST(InterProcessTimeTicksConverterTest, NullTime) {
// Null / zero times should remain null.
TestParams p;
p.local_lower_bound = 1;
p.remote_lower_bound = 2;
p.remote_upper_bound = 5;
p.local_upper_bound = 6;
p.test_time = 0;
p.test_delta = 0;
TestResults results = RunTest(p);
EXPECT_EQ(0, results.result_time);
EXPECT_EQ(0, results.result_delta);
}
TEST(InterProcessTimeTicksConverterTest, NoSkew) {
// All times are monotonic and centered, so no adjustment should occur.
TestParams p;
p.local_lower_bound = 1;
p.remote_lower_bound = 2;
p.remote_upper_bound = 5;
p.local_upper_bound = 6;
p.test_time = 3;
p.test_delta = 1;
TestResults results = RunTest(p);
EXPECT_EQ(3, results.result_time);
EXPECT_EQ(1, results.result_delta);
EXPECT_TRUE(results.is_skew_additive);
EXPECT_EQ(0, results.skew);
}
TEST(InterProcessTimeTicksConverterTest, OffsetMidpoints) {
// All times are monotonic, but not centered. Adjust the |remote_*| times so
// they are centered within the |local_*| times.
TestParams p;
p.local_lower_bound = 1;
p.remote_lower_bound = 3;
p.remote_upper_bound = 6;
p.local_upper_bound = 6;
p.test_time = 4;
p.test_delta = 1;
TestResults results = RunTest(p);
EXPECT_EQ(3, results.result_time);
EXPECT_EQ(1, results.result_delta);
EXPECT_TRUE(results.is_skew_additive);
EXPECT_EQ(1, results.skew);
}
TEST(InterProcessTimeTicksConverterTest, DoubleEndedSkew) {
// |remote_lower_bound| occurs before |local_lower_bound| and
// |remote_upper_bound| occurs after |local_upper_bound|. We must adjust both
// bounds and scale down the delta. |test_time| is on the midpoint, so it
// doesn't change. The ratio of local time to network time is 1:2, so we scale
// |test_delta| to half.
TestParams p;
p.local_lower_bound = 3;
p.remote_lower_bound = 1;
p.remote_upper_bound = 9;
p.local_upper_bound = 7;
p.test_time = 5;
p.test_delta = 2;
TestResults results = RunTest(p);
EXPECT_EQ(5, results.result_time);
EXPECT_EQ(1, results.result_delta);
EXPECT_FALSE(results.is_skew_additive);
}
TEST(InterProcessTimeTicksConverterTest, FrontEndSkew) {
// |remote_upper_bound| is coherent, but |remote_lower_bound| is not. So we
// adjust the lower bound and move |test_time| out. The scale factor is 2:3,
// but since we use integers, the numbers truncate from 3.33 to 3 and 1.33
// to 1.
TestParams p;
p.local_lower_bound = 3;
p.remote_lower_bound = 1;
p.remote_upper_bound = 7;
p.local_upper_bound = 7;
p.test_time = 3;
p.test_delta = 2;
TestResults results = RunTest(p);
EXPECT_EQ(4, results.result_time);
EXPECT_EQ(1, results.result_delta);
EXPECT_FALSE(results.is_skew_additive);
}
TEST(InterProcessTimeTicksConverterTest, BackEndSkew) {
// Like the previous test, but |remote_lower_bound| is coherent and
// |remote_upper_bound| is skewed.
TestParams p;
p.local_lower_bound = 1;
p.remote_lower_bound = 1;
p.remote_upper_bound = 7;
p.local_upper_bound = 5;
p.test_time = 3;
p.test_delta = 2;
TestResults results = RunTest(p);
EXPECT_EQ(2, results.result_time);
EXPECT_EQ(1, results.result_delta);
EXPECT_FALSE(results.is_skew_additive);
}
TEST(InterProcessTimeTicksConverterTest, Instantaneous) {
// The bounds are all okay, but the |remote_lower_bound| and
// |remote_upper_bound| have the same value. No adjustments should be made and
// no divide-by-zero errors should occur.
TestParams p;
p.local_lower_bound = 1;
p.remote_lower_bound = 2;
p.remote_upper_bound = 2;
p.local_upper_bound = 3;
p.test_time = 2;
p.test_delta = 0;
TestResults results = RunTest(p);
EXPECT_EQ(2, results.result_time);
EXPECT_EQ(0, results.result_delta);
}
TEST(InterProcessTimeTicksConverterTest, OffsetInstantaneous) {
// The bounds are all okay, but the |remote_lower_bound| and
// |remote_upper_bound| have the same value and are offset from the midpoint
// of |local_lower_bound| and |local_upper_bound|. An offset should be applied
// to make the midpoints line up.
TestParams p;
p.local_lower_bound = 1;
p.remote_lower_bound = 3;
p.remote_upper_bound = 3;
p.local_upper_bound = 3;
p.test_time = 3;
p.test_delta = 0;
TestResults results = RunTest(p);
EXPECT_EQ(2, results.result_time);
EXPECT_EQ(0, results.result_delta);
}
TEST(InterProcessTimeTicksConverterTest, DisjointInstantaneous) {
// |local_lower_bound| and |local_upper_bound| are the same. No matter what
// the other values are, they must fit within [local_lower_bound,
// local_upper_bound]. So, all of the values should be adjusted so they are
// exactly that value.
TestParams p;
p.local_lower_bound = 1;
p.remote_lower_bound = 2;
p.remote_upper_bound = 2;
p.local_upper_bound = 1;
p.test_time = 2;
p.test_delta = 0;
TestResults results = RunTest(p);
EXPECT_EQ(1, results.result_time);
EXPECT_EQ(0, results.result_delta);
}
TEST(InterProcessTimeTicksConverterTest, RoundingNearEdges) {
// Verify that rounding never causes a value to appear outside the given
// |local_*| range.
const int kMaxRange = 101;
for (int i = 1; i < kMaxRange; ++i) {
for (int j = 1; j < kMaxRange; ++j) {
TestParams p;
p.local_lower_bound = 1;
p.remote_lower_bound = 1;
p.remote_upper_bound = j;
p.local_upper_bound = i;
p.test_time = 1;
p.test_delta = 0;
TestResults results = RunTest(p);
EXPECT_LE(1, results.result_time);
EXPECT_EQ(0, results.result_delta);
p.test_time = j;
p.test_delta = j - 1;
results = RunTest(p);
EXPECT_GE(i, results.result_time);
EXPECT_GE(i - 1, results.result_delta);
}
}
}
TEST(InterProcessTimeTicksConverterTest, DisjointRanges) {
TestParams p;
p.local_lower_bound = 10;
p.remote_lower_bound = 30;
p.remote_upper_bound = 41;
p.local_upper_bound = 20;
p.test_time = 41;
p.test_delta = 0;
TestResults results = RunTest(p);
EXPECT_EQ(20, results.result_time);
EXPECT_EQ(0, results.result_delta);
}
TEST(InterProcessTimeTicksConverterTest, ValuesOutsideOfRange) {
InterProcessTimeTicksConverter converter(
LocalTimeTicks::FromTimeTicks(TimeTicks::FromInternalValue(15)),
LocalTimeTicks::FromTimeTicks(TimeTicks::FromInternalValue(20)),
RemoteTimeTicks::FromTimeTicks(TimeTicks::FromInternalValue(10)),
RemoteTimeTicks::FromTimeTicks(TimeTicks::FromInternalValue(25)));
RemoteTimeTicks remote_ticks =
RemoteTimeTicks::FromTimeTicks(TimeTicks::FromInternalValue(10));
int64_t result =
converter.ToLocalTimeTicks(remote_ticks).ToTimeTicks().ToInternalValue();
EXPECT_EQ(15, result);
remote_ticks =
RemoteTimeTicks::FromTimeTicks(TimeTicks::FromInternalValue(25));
result =
converter.ToLocalTimeTicks(remote_ticks).ToTimeTicks().ToInternalValue();
EXPECT_EQ(20, result);
remote_ticks =
RemoteTimeTicks::FromTimeTicks(TimeTicks::FromInternalValue(9));
result =
converter.ToLocalTimeTicks(remote_ticks).ToTimeTicks().ToInternalValue();
EXPECT_EQ(14, result);
}
} // anonymous namespace
} // namespace content