1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/common/inter_process_time_ticks_converter.h"
6
7#include "base/time/time.h"
8#include "testing/gtest/include/gtest/gtest.h"
9
10using base::TimeTicks;
11
12namespace content {
13
14namespace {
15
16struct TestParams {
17  int64 local_lower_bound;
18  int64 remote_lower_bound;
19  int64 remote_upper_bound;
20  int64 local_upper_bound;
21  int64 test_time;
22  int64 test_delta;
23};
24
25struct TestResults {
26  int64 result_time;
27  int32 result_delta;
28  bool is_skew_additive;
29  int64 skew;
30};
31
32TestResults RunTest(const TestParams& params) {
33  TimeTicks local_lower_bound = TimeTicks::FromInternalValue(
34      params.local_lower_bound);
35  TimeTicks local_upper_bound = TimeTicks::FromInternalValue(
36      params.local_upper_bound);
37  TimeTicks remote_lower_bound = TimeTicks::FromInternalValue(
38      params.remote_lower_bound);
39  TimeTicks remote_upper_bound = TimeTicks::FromInternalValue(
40      params.remote_upper_bound);
41  TimeTicks test_time = TimeTicks::FromInternalValue(params.test_time);
42
43  InterProcessTimeTicksConverter converter(
44      LocalTimeTicks::FromTimeTicks(local_lower_bound),
45      LocalTimeTicks::FromTimeTicks(local_upper_bound),
46      RemoteTimeTicks::FromTimeTicks(remote_lower_bound),
47      RemoteTimeTicks::FromTimeTicks(remote_upper_bound));
48
49  TestResults results;
50  results.result_time = converter.ToLocalTimeTicks(
51      RemoteTimeTicks::FromTimeTicks(
52          test_time)).ToTimeTicks().ToInternalValue();
53  results.result_delta = converter.ToLocalTimeDelta(
54      RemoteTimeDelta::FromRawDelta(params.test_delta)).ToInt32();
55  results.is_skew_additive = converter.IsSkewAdditiveForMetrics();
56  results.skew = converter.GetSkewForMetrics().ToInternalValue();
57  return results;
58}
59
60TEST(InterProcessTimeTicksConverterTest, NullTime) {
61  // Null / zero times should remain null.
62  TestParams p;
63  p.local_lower_bound = 1;
64  p.remote_lower_bound = 2;
65  p.remote_upper_bound = 5;
66  p.local_upper_bound = 6;
67  p.test_time = 0;
68  p.test_delta = 0;
69  TestResults results = RunTest(p);
70  EXPECT_EQ(0, results.result_time);
71  EXPECT_EQ(0, results.result_delta);
72}
73
74TEST(InterProcessTimeTicksConverterTest, NoSkew) {
75  // All times are monotonic and centered, so no adjustment should occur.
76  TestParams p;
77  p.local_lower_bound = 1;
78  p.remote_lower_bound = 2;
79  p.remote_upper_bound = 5;
80  p.local_upper_bound = 6;
81  p.test_time = 3;
82  p.test_delta = 1;
83  TestResults results = RunTest(p);
84  EXPECT_EQ(3, results.result_time);
85  EXPECT_EQ(1, results.result_delta);
86  EXPECT_TRUE(results.is_skew_additive);
87  EXPECT_EQ(0, results.skew);
88}
89
90TEST(InterProcessTimeTicksConverterTest, OffsetMidpoints) {
91  // All times are monotonic, but not centered. Adjust the |remote_*| times so
92  // they are centered within the |local_*| times.
93  TestParams p;
94  p.local_lower_bound = 1;
95  p.remote_lower_bound = 3;
96  p.remote_upper_bound = 6;
97  p.local_upper_bound = 6;
98  p.test_time = 4;
99  p.test_delta = 1;
100  TestResults results = RunTest(p);
101  EXPECT_EQ(3, results.result_time);
102  EXPECT_EQ(1, results.result_delta);
103  EXPECT_TRUE(results.is_skew_additive);
104  EXPECT_EQ(1, results.skew);
105}
106
107TEST(InterProcessTimeTicksConverterTest, DoubleEndedSkew) {
108  // |remote_lower_bound| occurs before |local_lower_bound| and
109  // |remote_upper_bound| occurs after |local_upper_bound|. We must adjust both
110  // bounds and scale down the delta. |test_time| is on the midpoint, so it
111  // doesn't change. The ratio of local time to network time is 1:2, so we scale
112  // |test_delta| to half.
113  TestParams p;
114  p.local_lower_bound = 3;
115  p.remote_lower_bound = 1;
116  p.remote_upper_bound = 9;
117  p.local_upper_bound = 7;
118  p.test_time = 5;
119  p.test_delta = 2;
120  TestResults results = RunTest(p);
121  EXPECT_EQ(5, results.result_time);
122  EXPECT_EQ(1, results.result_delta);
123  EXPECT_FALSE(results.is_skew_additive);
124}
125
126TEST(InterProcessTimeTicksConverterTest, FrontEndSkew) {
127  // |remote_upper_bound| is coherent, but |remote_lower_bound| is not. So we
128  // adjust the lower bound and move |test_time| out. The scale factor is 2:3,
129  // but since we use integers, the numbers truncate from 3.33 to 3 and 1.33
130  // to 1.
131  TestParams p;
132  p.local_lower_bound = 3;
133  p.remote_lower_bound = 1;
134  p.remote_upper_bound = 7;
135  p.local_upper_bound = 7;
136  p.test_time = 3;
137  p.test_delta = 2;
138  TestResults results = RunTest(p);
139  EXPECT_EQ(4, results.result_time);
140  EXPECT_EQ(1, results.result_delta);
141  EXPECT_FALSE(results.is_skew_additive);
142}
143
144TEST(InterProcessTimeTicksConverterTest, BackEndSkew) {
145  // Like the previous test, but |remote_lower_bound| is coherent and
146  // |remote_upper_bound| is skewed.
147  TestParams p;
148  p.local_lower_bound = 1;
149  p.remote_lower_bound = 1;
150  p.remote_upper_bound = 7;
151  p.local_upper_bound = 5;
152  p.test_time = 3;
153  p.test_delta = 2;
154  TestResults results = RunTest(p);
155  EXPECT_EQ(2, results.result_time);
156  EXPECT_EQ(1, results.result_delta);
157  EXPECT_FALSE(results.is_skew_additive);
158}
159
160TEST(InterProcessTimeTicksConverterTest, Instantaneous) {
161  // The bounds are all okay, but the |remote_lower_bound| and
162  // |remote_upper_bound| have the same value. No adjustments should be made and
163  // no divide-by-zero errors should occur.
164  TestParams p;
165  p.local_lower_bound = 1;
166  p.remote_lower_bound = 2;
167  p.remote_upper_bound = 2;
168  p.local_upper_bound = 3;
169  p.test_time = 2;
170  p.test_delta = 0;
171  TestResults results = RunTest(p);
172  EXPECT_EQ(2, results.result_time);
173  EXPECT_EQ(0, results.result_delta);
174}
175
176TEST(InterProcessTimeTicksConverterTest, OffsetInstantaneous) {
177  // The bounds are all okay, but the |remote_lower_bound| and
178  // |remote_upper_bound| have the same value and are offset from the midpoint
179  // of |local_lower_bound| and |local_upper_bound|. An offset should be applied
180  // to make the midpoints line up.
181  TestParams p;
182  p.local_lower_bound = 1;
183  p.remote_lower_bound = 3;
184  p.remote_upper_bound = 3;
185  p.local_upper_bound = 3;
186  p.test_time = 3;
187  p.test_delta = 0;
188  TestResults results = RunTest(p);
189  EXPECT_EQ(2, results.result_time);
190  EXPECT_EQ(0, results.result_delta);
191}
192
193TEST(InterProcessTimeTicksConverterTest, DisjointInstantaneous) {
194  // |local_lower_bound| and |local_upper_bound| are the same. No matter what
195  // the other values are, they must fit within [local_lower_bound,
196  // local_upper_bound].  So, all of the values should be adjusted so they are
197  // exactly that value.
198  TestParams p;
199  p.local_lower_bound = 1;
200  p.remote_lower_bound = 2;
201  p.remote_upper_bound = 2;
202  p.local_upper_bound = 1;
203  p.test_time = 2;
204  p.test_delta = 0;
205  TestResults results = RunTest(p);
206  EXPECT_EQ(1, results.result_time);
207  EXPECT_EQ(0, results.result_delta);
208}
209
210TEST(InterProcessTimeTicksConverterTest, RoundingNearEdges) {
211  // Verify that rounding never causes a value to appear outside the given
212  // |local_*| range.
213  const int kMaxRange = 101;
214  for (int i = 1; i < kMaxRange; ++i) {
215    for (int j = 1; j < kMaxRange; ++j) {
216      TestParams p;
217      p.local_lower_bound = 1;
218      p.remote_lower_bound = 1;
219      p.remote_upper_bound = j;
220      p.local_upper_bound = i;
221
222      p.test_time = 1;
223      p.test_delta = 0;
224      TestResults results = RunTest(p);
225      EXPECT_LE(1, results.result_time);
226      EXPECT_EQ(0, results.result_delta);
227
228      p.test_time = j;
229      p.test_delta = j - 1;
230      results = RunTest(p);
231      EXPECT_GE(i, results.result_time);
232      EXPECT_GE(i - 1, results.result_delta);
233    }
234  }
235}
236
237TEST(InterProcessTimeTicksConverterTest, DisjointRanges) {
238  TestParams p;
239  p.local_lower_bound = 10;
240  p.remote_lower_bound = 30;
241  p.remote_upper_bound = 41;
242  p.local_upper_bound = 20;
243  p.test_time = 41;
244  p.test_delta = 0;
245  TestResults results = RunTest(p);
246  EXPECT_EQ(20, results.result_time);
247  EXPECT_EQ(0, results.result_delta);
248}
249
250}  // anonymous namespace
251
252}  // namespace content
253