blob: c0761e2e79e6756a4c83086a67eeb21a43ae70e4 [file] [log] [blame]
Darin Petkovf1e85e42010-06-10 15:59:53 -07001// Copyright (c) 2010 The Chromium OS 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 <sys/file.h>
6
Darin Petkovf1e85e42010-06-10 15:59:53 -07007#include <base/file_util.h>
8#include <base/logging.h>
Chris Masonee10b5482013-02-14 12:15:35 -08009#include <base/posix/eintr_wrapper.h>
Ben Chan2e6543d2014-02-05 23:26:25 -080010#include <base/strings/string_util.h>
Darin Petkovf1e85e42010-06-10 15:59:53 -070011#include <gmock/gmock.h>
12#include <gtest/gtest.h>
13
14#include "counter.h"
Ken Mixterccd84c02010-08-16 19:57:13 -070015#include "counter_mock.h" // For TaggedCounterMock.
Ken Mixter4c5daa42010-08-26 18:35:06 -070016#include "metrics_library_mock.h"
Darin Petkovf1e85e42010-06-10 15:59:53 -070017
Ben Chan2e6543d2014-02-05 23:26:25 -080018using base::FilePath;
Darin Petkovf1e85e42010-06-10 15:59:53 -070019using ::testing::_;
20using ::testing::MockFunction;
21using ::testing::StrictMock;
22
23namespace chromeos_metrics {
24
25static const char kTestRecordFile[] = "record-file";
26static const char kDoesNotExistFile[] = "/does/not/exist";
27
28class RecordTest : public testing::Test {
29 protected:
30 virtual void SetUp() {
31 EXPECT_EQ(0, record_.tag());
32 EXPECT_EQ(0, record_.count());
33 }
34
35 // The record under test.
36 TaggedCounter::Record record_;
37};
38
39class TaggedCounterTest : public testing::Test {
40 protected:
41 virtual void SetUp() {
Ken Mixter4c5daa42010-08-26 18:35:06 -070042 EXPECT_TRUE(counter_.filename_.empty());
Darin Petkovf1e85e42010-06-10 15:59:53 -070043 EXPECT_TRUE(NULL == counter_.reporter_);
44 EXPECT_EQ(NULL, counter_.reporter_handle_);
45 EXPECT_EQ(TaggedCounter::kRecordInvalid, counter_.record_state_);
46
47 counter_.Init(kTestRecordFile, &Reporter, this);
48 EXPECT_TRUE(AssertNoOrEmptyRecordFile());
49 EXPECT_EQ(kTestRecordFile, counter_.filename_);
50 EXPECT_TRUE(Reporter == counter_.reporter_);
51 EXPECT_EQ(this, counter_.reporter_handle_);
52 EXPECT_EQ(TaggedCounter::kRecordInvalid, counter_.record_state_);
53
54 // The test fixture object will be used by the log message handler.
55 test_ = this;
56 logging::SetLogMessageHandler(HandleLogMessages);
57 }
58
59 virtual void TearDown() {
60 logging::SetLogMessageHandler(NULL);
61 test_ = NULL;
Ben Chan2e6543d2014-02-05 23:26:25 -080062 base::DeleteFile(FilePath(kTestRecordFile), false);
Darin Petkovf1e85e42010-06-10 15:59:53 -070063 }
64
65 // Asserts that the record file contains the specified contents.
66 testing::AssertionResult AssertRecord(const char* expr_tag,
67 const char* expr_count,
Darin Petkovcd8c3172010-06-24 10:13:54 -070068 int32 expected_tag,
69 int32 expected_count) {
Darin Petkovf1e85e42010-06-10 15:59:53 -070070 int fd = HANDLE_EINTR(open(kTestRecordFile, O_RDONLY));
71 if (fd < 0) {
72 testing::Message msg;
73 msg << "Unable to open " << kTestRecordFile;
74 return testing::AssertionFailure(msg);
75 }
76
77 TaggedCounter::Record record;
Ben Chan2e6543d2014-02-05 23:26:25 -080078 if (!base::ReadFromFD(fd, reinterpret_cast<char*>(&record),
79 sizeof(record))) {
Darin Petkovf1e85e42010-06-10 15:59:53 -070080 testing::Message msg;
81 msg << "Unable to read " << sizeof(record) << " bytes from "
82 << kTestRecordFile;
83 HANDLE_EINTR(close(fd));
84 return testing::AssertionFailure(msg);
85 }
86
87 if (record.tag() != expected_tag || record.count() != expected_count) {
88 testing::Message msg;
89 msg << "actual record (" << record.tag() << ", " << record.count()
90 << ") expected (" << expected_tag << ", " << expected_count << ")";
91 HANDLE_EINTR(close(fd));
92 return testing::AssertionFailure(msg);
93 }
94
95 HANDLE_EINTR(close(fd));
96 return testing::AssertionSuccess();
97 }
98
99 // Returns true if the persistent record file does not exist or is
100 // empty, false otherwise.
101 bool AssertNoOrEmptyRecordFile() {
102 FilePath record_file(counter_.filename_);
103 int64 record_file_size;
Ben Chan2e6543d2014-02-05 23:26:25 -0800104 return !base::PathExists(record_file) ||
105 (base::GetFileSize(record_file, &record_file_size) &&
106 record_file_size == 0);
Darin Petkovf1e85e42010-06-10 15:59:53 -0700107 }
108
109 // Adds a reporter call expectation that the specified tag/count
110 // callback will be generated.
Darin Petkovcd8c3172010-06-24 10:13:54 -0700111 void ExpectReporterCall(int32 tag, int32 count) {
Darin Petkovf1e85e42010-06-10 15:59:53 -0700112 EXPECT_CALL(reporter_, Call(_, tag, count))
113 .Times(1)
114 .RetiresOnSaturation();
115 }
116
117 // The reporter callback forwards the call to the reporter mock so
118 // that we can set call expectations.
Darin Petkovcd8c3172010-06-24 10:13:54 -0700119 static void Reporter(void* handle, int32 tag, int32 count) {
Darin Petkovf1e85e42010-06-10 15:59:53 -0700120 TaggedCounterTest* test = static_cast<TaggedCounterTest*>(handle);
121 ASSERT_FALSE(NULL == test);
122 test->reporter_.Call(handle, tag, count);
123 }
124
125 // Collects log messages in the |log_| member string so that they
126 // can be analyzed for errors and expected behavior.
Chris Masone817016a2011-05-12 14:14:48 -0700127 static bool HandleLogMessages(int severity,
128 const char* file,
129 int line,
130 size_t message_start,
131 const std::string& str) {
Darin Petkovf1e85e42010-06-10 15:59:53 -0700132 test_->log_.append(str);
133 test_->log_.append("\n");
134
135 // Returning true would mute the log.
136 return false;
137 }
138
139 // Returns true if the counter log contains |pattern|, false otherwise.
Darin Petkovcd8c3172010-06-24 10:13:54 -0700140 bool LogContains(const std::string& pattern) const {
Darin Petkovf1e85e42010-06-10 15:59:53 -0700141 return log_.find(pattern) != std::string::npos;
142 }
143
144 // The TaggedCounter object under test.
145 TaggedCounter counter_;
146
147 // The accumulated counter log.
148 std::string log_;
149
150 // Reporter mock to set callback expectations on.
Darin Petkovcd8c3172010-06-24 10:13:54 -0700151 StrictMock<MockFunction<void(void* handle,
152 int32 tag, int32 count)> > reporter_;
Darin Petkovf1e85e42010-06-10 15:59:53 -0700153
154 // Pointer to the current test fixture.
155 static TaggedCounterTest* test_;
156};
157
158// static
159TaggedCounterTest* TaggedCounterTest::test_ = NULL;
160
161TEST_F(RecordTest, Init) {
162 record_.Init(/* tag */ 5, /* count */ -1);
163 EXPECT_EQ(5, record_.tag());
164 EXPECT_EQ(0, record_.count());
165
166 record_.Init(/* tag */ -2, /* count */ 10);
167 EXPECT_EQ(-2, record_.tag());
168 EXPECT_EQ(10, record_.count());
169}
170
171TEST_F(RecordTest, Add) {
172 record_.Add(/* count */ -1);
173 EXPECT_EQ(0, record_.count());
174
175 record_.Add(/* count */ 5);
176 EXPECT_EQ(5, record_.count());
177
178 record_.Add(/* count */ 10);
179 EXPECT_EQ(15, record_.count());
180
181 record_.Add(/* count */ -2);
182 EXPECT_EQ(15, record_.count());
183
Darin Petkovcd8c3172010-06-24 10:13:54 -0700184 record_.Add(/* count */ kint32max);
185 EXPECT_EQ(kint32max, record_.count());
Darin Petkovf1e85e42010-06-10 15:59:53 -0700186
187 record_.Add(/* count */ 1);
Darin Petkovcd8c3172010-06-24 10:13:54 -0700188 EXPECT_EQ(kint32max, record_.count());
Darin Petkovf1e85e42010-06-10 15:59:53 -0700189}
190
191TEST_F(TaggedCounterTest, BadFileLocation) {
192 // Checks that the counter doesn't die badly if the file can't be
193 // created.
194 counter_.Init(kDoesNotExistFile,
195 /* reporter */ NULL, /* reporter_handle */ NULL);
196 counter_.Update(/* tag */ 10, /* count */ 20);
197 EXPECT_TRUE(LogContains("Unable to open the persistent counter file: "
198 "No such file or directory"));
199 EXPECT_EQ(TaggedCounter::kRecordInvalid, counter_.record_state_);
Ben Chan2e6543d2014-02-05 23:26:25 -0800200 base::DeleteFile(FilePath(kDoesNotExistFile), false);
Darin Petkovf1e85e42010-06-10 15:59:53 -0700201}
202
203TEST_F(TaggedCounterTest, Flush) {
204 counter_.Flush();
205 EXPECT_EQ(TaggedCounter::kRecordNull, counter_.record_state_);
206
207 counter_.Update(/* tag */ 40, /* count */ 60);
208 ExpectReporterCall(/* tag */ 40, /* count */ 60);
209 counter_.Flush();
210 EXPECT_TRUE(AssertNoOrEmptyRecordFile());
211 EXPECT_EQ(TaggedCounter::kRecordNull, counter_.record_state_);
212
213 counter_.Update(/* tag */ 41, /* count */ 70);
214 counter_.record_.Init(/* tag */ 0, /* count */ 0);
215 counter_.record_state_ = TaggedCounter::kRecordInvalid;
216 ExpectReporterCall(/* tag */ 41, /* count */ 70);
217 counter_.Flush();
218 EXPECT_TRUE(AssertNoOrEmptyRecordFile());
219 EXPECT_EQ(TaggedCounter::kRecordNull, counter_.record_state_);
220}
221
222TEST_F(TaggedCounterTest, InitFromFile) {
223 counter_.Update(/* tag */ 30, /* count */ 50);
224 EXPECT_PRED_FORMAT2(AssertRecord, /* day */ 30, /* seconds */ 50);
225 EXPECT_EQ(TaggedCounter::kRecordValid, counter_.record_state_);
226
227 counter_.Init(kTestRecordFile, &Reporter, this);
228 counter_.Update(/* tag */ 30, /* count */ 40);
229 EXPECT_PRED_FORMAT2(AssertRecord, /* day */ 30, /* seconds */ 90);
230 EXPECT_EQ(TaggedCounter::kRecordValid, counter_.record_state_);
231
232 counter_.Init(kTestRecordFile, &Reporter, this);
233 ExpectReporterCall(/* tag */ 30, /* count */ 90);
234 counter_.Update(/* tag */ 31, /* count */ 60);
235 EXPECT_PRED_FORMAT2(AssertRecord, /* day */ 31, /* seconds */ 60);
236 EXPECT_EQ(TaggedCounter::kRecordValid, counter_.record_state_);
237
238 ExpectReporterCall(/* tag */ 31, /* count */ 60);
239 counter_.Init(kTestRecordFile, &Reporter, this);
240 counter_.Update(/* tag */ 32, /* count */ 0);
Darin Petkov1bb904e2010-06-16 15:58:06 -0700241 EXPECT_PRED_FORMAT2(AssertRecord, /* day */ 32, /* seconds */ 0);
242 EXPECT_EQ(TaggedCounter::kRecordValid, counter_.record_state_);
Darin Petkovf1e85e42010-06-10 15:59:53 -0700243}
244
245TEST_F(TaggedCounterTest, Update) {
246 counter_.Update(/* tag */ 20, /* count */ 30);
247 EXPECT_PRED_FORMAT2(AssertRecord, /* day */ 20, /* seconds */ 30);
248 EXPECT_EQ(TaggedCounter::kRecordValid, counter_.record_state_);
249
250 counter_.Update(/* tag */ 20, /* count */ 40);
251 EXPECT_PRED_FORMAT2(AssertRecord, /* day */ 20, /* seconds */ 70);
252 EXPECT_EQ(TaggedCounter::kRecordValid, counter_.record_state_);
253
254 ExpectReporterCall(/* tag */ 20, /* count */ 70);
255 counter_.Update(/* tag */ 21, /* count */ 15);
256 EXPECT_PRED_FORMAT2(AssertRecord, /* day */ 21, /* seconds */ 15);
257 EXPECT_EQ(TaggedCounter::kRecordValid, counter_.record_state_);
258
259 ExpectReporterCall(/* tag */ 21, /* count */ 15);
260 counter_.Update(/* tag */ 22, /* count */ 0);
Darin Petkov1bb904e2010-06-16 15:58:06 -0700261 EXPECT_PRED_FORMAT2(AssertRecord, /* day */ 22, /* seconds */ 0);
262 EXPECT_EQ(TaggedCounter::kRecordValid, counter_.record_state_);
Darin Petkovf1e85e42010-06-10 15:59:53 -0700263}
264
Ken Mixter4c5daa42010-08-26 18:35:06 -0700265static const char kTestFilename[] = "test_filename";
266static const char kTestHistogram[] = "test_histogram";
267const int kHistogramMin = 15;
268const int kHistogramMax = 1024;
269const int kHistogramBuckets = 23;
270
271class TaggedCounterReporterTest : public testing::Test {
272 protected:
273 virtual void SetUp() {
274 tagged_counter_ = new StrictMock<TaggedCounterMock>();
275 reporter_.tagged_counter_.reset(tagged_counter_);
276 metrics_lib_.reset(new StrictMock<MetricsLibraryMock>);
277 reporter_.SetMetricsLibraryInterface(metrics_lib_.get());
278 ASSERT_TRUE(metrics_lib_.get() == reporter_.metrics_lib_);
279 }
280 virtual void TearDown() {
281 reporter_.SetMetricsLibraryInterface(NULL);
282 }
283
284 void DoInit();
285 StrictMock<TaggedCounterMock>* tagged_counter_;
286 TaggedCounterReporter reporter_;
287 scoped_ptr<MetricsLibraryMock> metrics_lib_;
288};
289
290void TaggedCounterReporterTest::DoInit() {
291 EXPECT_CALL(*tagged_counter_,
292 Init(kTestFilename,
293 TaggedCounterReporter::Report,
294 &reporter_))
295 .Times(1)
296 .RetiresOnSaturation();
297 reporter_.Init(kTestFilename,
298 kTestHistogram,
299 kHistogramMin,
300 kHistogramMax,
301 kHistogramBuckets);
302 EXPECT_EQ(kTestHistogram, reporter_.histogram_name_);
303 EXPECT_EQ(kHistogramBuckets, reporter_.buckets_);
304 EXPECT_EQ(kHistogramMax, reporter_.max_);
305 EXPECT_EQ(kHistogramMin, reporter_.min_);
306}
307
308TEST_F(TaggedCounterReporterTest, Init) {
309 DoInit();
310}
311
312TEST_F(TaggedCounterReporterTest, Update) {
313 DoInit();
314 EXPECT_CALL(*tagged_counter_, Update(1, 2))
315 .Times(1)
316 .RetiresOnSaturation();
317 reporter_.Update(1, 2);
318}
319
320TEST_F(TaggedCounterReporterTest, Flush) {
321 DoInit();
322 EXPECT_CALL(*tagged_counter_, Flush())
323 .Times(1)
324 .RetiresOnSaturation();
325 reporter_.Flush();
326}
327
328TEST_F(TaggedCounterReporterTest, Report) {
329 DoInit();
330 EXPECT_CALL(*metrics_lib_, SendToUMA(kTestHistogram,
331 301,
332 kHistogramMin,
333 kHistogramMax,
334 kHistogramBuckets))
335 .Times(1)
336 .RetiresOnSaturation();
337 reporter_.Report(&reporter_, 127, 301);
338}
339
Ken Mixterccd84c02010-08-16 19:57:13 -0700340class FrequencyCounterTest : public testing::Test {
341 protected:
342 virtual void SetUp() {
Ken Mixter4c5daa42010-08-26 18:35:06 -0700343 tagged_counter_ = NULL;
Ken Mixterccd84c02010-08-16 19:57:13 -0700344 }
345
346 void CheckInit(int32 cycle_duration);
347 void CheckCycleNumber(int32 cycle_duration);
348
349 FrequencyCounter frequency_counter_;
350 StrictMock<TaggedCounterMock>* tagged_counter_;
351
352 TaggedCounter::Reporter reporter_;
353};
354
355void FrequencyCounterTest::CheckInit(int32 cycle_duration) {
Ken Mixter4c5daa42010-08-26 18:35:06 -0700356 tagged_counter_ = new StrictMock<TaggedCounterMock>;
357 frequency_counter_.Init(tagged_counter_, cycle_duration);
Ken Mixterccd84c02010-08-16 19:57:13 -0700358 EXPECT_EQ(cycle_duration, frequency_counter_.cycle_duration_);
Ken Mixter4c5daa42010-08-26 18:35:06 -0700359 EXPECT_EQ(tagged_counter_, frequency_counter_.tagged_counter_.get());
Ken Mixterccd84c02010-08-16 19:57:13 -0700360}
361
362TEST_F(FrequencyCounterTest, Init) {
363 CheckInit(100);
364}
365
366void FrequencyCounterTest::CheckCycleNumber(int32 cycle_duration) {
367 CheckInit(cycle_duration);
Ken Mixter4c5daa42010-08-26 18:35:06 -0700368 EXPECT_EQ(150, frequency_counter_.GetCycleNumber(
369 cycle_duration * 150));
370 EXPECT_EQ(150, frequency_counter_.GetCycleNumber(
371 cycle_duration * 150 + cycle_duration - 1));
372 EXPECT_EQ(151, frequency_counter_.GetCycleNumber(
373 cycle_duration * 151 + 1));
Ken Mixterccd84c02010-08-16 19:57:13 -0700374 EXPECT_EQ(0, frequency_counter_.GetCycleNumber(0));
375}
376
377
378TEST_F(FrequencyCounterTest, GetCycleNumberForWeek) {
379 CheckCycleNumber(kSecondsPerWeek);
380}
381
382TEST_F(FrequencyCounterTest, GetCycleNumberForDay) {
383 CheckCycleNumber(kSecondsPerDay);
384}
385
386TEST_F(FrequencyCounterTest, UpdateInternal) {
387 CheckInit(kSecondsPerWeek);
Ken Mixter4c5daa42010-08-26 18:35:06 -0700388 EXPECT_CALL(*tagged_counter_, Update(150, 2))
389 .Times(1)
390 .RetiresOnSaturation();
Ken Mixterccd84c02010-08-16 19:57:13 -0700391 frequency_counter_.UpdateInternal(2, kSecondsPerWeek * 150);
392}
393
Darin Petkovf1e85e42010-06-10 15:59:53 -0700394} // namespace chromeos_metrics
395
396int main(int argc, char** argv) {
397 testing::InitGoogleTest(&argc, argv);
398 return RUN_ALL_TESTS();
399}