blob: eb68b2acb79114666ef108ab80d46195ec8d0075 [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
7#include <base/eintr_wrapper.h>
8#include <base/file_util.h>
9#include <base/logging.h>
10#include <base/string_util.h>
11#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.
Darin Petkovf1e85e42010-06-10 15:59:53 -070016
17using ::testing::_;
18using ::testing::MockFunction;
19using ::testing::StrictMock;
20
21namespace chromeos_metrics {
22
23static const char kTestRecordFile[] = "record-file";
24static const char kDoesNotExistFile[] = "/does/not/exist";
25
26class RecordTest : public testing::Test {
27 protected:
28 virtual void SetUp() {
29 EXPECT_EQ(0, record_.tag());
30 EXPECT_EQ(0, record_.count());
31 }
32
33 // The record under test.
34 TaggedCounter::Record record_;
35};
36
37class TaggedCounterTest : public testing::Test {
38 protected:
39 virtual void SetUp() {
40 EXPECT_EQ(NULL, counter_.filename_);
41 EXPECT_TRUE(NULL == counter_.reporter_);
42 EXPECT_EQ(NULL, counter_.reporter_handle_);
43 EXPECT_EQ(TaggedCounter::kRecordInvalid, counter_.record_state_);
44
45 counter_.Init(kTestRecordFile, &Reporter, this);
46 EXPECT_TRUE(AssertNoOrEmptyRecordFile());
47 EXPECT_EQ(kTestRecordFile, counter_.filename_);
48 EXPECT_TRUE(Reporter == counter_.reporter_);
49 EXPECT_EQ(this, counter_.reporter_handle_);
50 EXPECT_EQ(TaggedCounter::kRecordInvalid, counter_.record_state_);
51
52 // The test fixture object will be used by the log message handler.
53 test_ = this;
54 logging::SetLogMessageHandler(HandleLogMessages);
55 }
56
57 virtual void TearDown() {
58 logging::SetLogMessageHandler(NULL);
59 test_ = NULL;
60 file_util::Delete(FilePath(kTestRecordFile), false);
61 }
62
63 // Asserts that the record file contains the specified contents.
64 testing::AssertionResult AssertRecord(const char* expr_tag,
65 const char* expr_count,
Darin Petkovcd8c3172010-06-24 10:13:54 -070066 int32 expected_tag,
67 int32 expected_count) {
Darin Petkovf1e85e42010-06-10 15:59:53 -070068 int fd = HANDLE_EINTR(open(kTestRecordFile, O_RDONLY));
69 if (fd < 0) {
70 testing::Message msg;
71 msg << "Unable to open " << kTestRecordFile;
72 return testing::AssertionFailure(msg);
73 }
74
75 TaggedCounter::Record record;
76 if (!file_util::ReadFromFD(fd, reinterpret_cast<char*>(&record),
77 sizeof(record))) {
78 testing::Message msg;
79 msg << "Unable to read " << sizeof(record) << " bytes from "
80 << kTestRecordFile;
81 HANDLE_EINTR(close(fd));
82 return testing::AssertionFailure(msg);
83 }
84
85 if (record.tag() != expected_tag || record.count() != expected_count) {
86 testing::Message msg;
87 msg << "actual record (" << record.tag() << ", " << record.count()
88 << ") expected (" << expected_tag << ", " << expected_count << ")";
89 HANDLE_EINTR(close(fd));
90 return testing::AssertionFailure(msg);
91 }
92
93 HANDLE_EINTR(close(fd));
94 return testing::AssertionSuccess();
95 }
96
97 // Returns true if the persistent record file does not exist or is
98 // empty, false otherwise.
99 bool AssertNoOrEmptyRecordFile() {
100 FilePath record_file(counter_.filename_);
101 int64 record_file_size;
102 return !file_util::PathExists(record_file) ||
103 (file_util::GetFileSize(record_file, &record_file_size) &&
104 record_file_size == 0);
105 }
106
107 // Adds a reporter call expectation that the specified tag/count
108 // callback will be generated.
Darin Petkovcd8c3172010-06-24 10:13:54 -0700109 void ExpectReporterCall(int32 tag, int32 count) {
Darin Petkovf1e85e42010-06-10 15:59:53 -0700110 EXPECT_CALL(reporter_, Call(_, tag, count))
111 .Times(1)
112 .RetiresOnSaturation();
113 }
114
115 // The reporter callback forwards the call to the reporter mock so
116 // that we can set call expectations.
Darin Petkovcd8c3172010-06-24 10:13:54 -0700117 static void Reporter(void* handle, int32 tag, int32 count) {
Darin Petkovf1e85e42010-06-10 15:59:53 -0700118 TaggedCounterTest* test = static_cast<TaggedCounterTest*>(handle);
119 ASSERT_FALSE(NULL == test);
120 test->reporter_.Call(handle, tag, count);
121 }
122
123 // Collects log messages in the |log_| member string so that they
124 // can be analyzed for errors and expected behavior.
125 static bool HandleLogMessages(int severity, const std::string& str) {
126 test_->log_.append(str);
127 test_->log_.append("\n");
128
129 // Returning true would mute the log.
130 return false;
131 }
132
133 // Returns true if the counter log contains |pattern|, false otherwise.
Darin Petkovcd8c3172010-06-24 10:13:54 -0700134 bool LogContains(const std::string& pattern) const {
Darin Petkovf1e85e42010-06-10 15:59:53 -0700135 return log_.find(pattern) != std::string::npos;
136 }
137
138 // The TaggedCounter object under test.
139 TaggedCounter counter_;
140
141 // The accumulated counter log.
142 std::string log_;
143
144 // Reporter mock to set callback expectations on.
Darin Petkovcd8c3172010-06-24 10:13:54 -0700145 StrictMock<MockFunction<void(void* handle,
146 int32 tag, int32 count)> > reporter_;
Darin Petkovf1e85e42010-06-10 15:59:53 -0700147
148 // Pointer to the current test fixture.
149 static TaggedCounterTest* test_;
150};
151
152// static
153TaggedCounterTest* TaggedCounterTest::test_ = NULL;
154
155TEST_F(RecordTest, Init) {
156 record_.Init(/* tag */ 5, /* count */ -1);
157 EXPECT_EQ(5, record_.tag());
158 EXPECT_EQ(0, record_.count());
159
160 record_.Init(/* tag */ -2, /* count */ 10);
161 EXPECT_EQ(-2, record_.tag());
162 EXPECT_EQ(10, record_.count());
163}
164
165TEST_F(RecordTest, Add) {
166 record_.Add(/* count */ -1);
167 EXPECT_EQ(0, record_.count());
168
169 record_.Add(/* count */ 5);
170 EXPECT_EQ(5, record_.count());
171
172 record_.Add(/* count */ 10);
173 EXPECT_EQ(15, record_.count());
174
175 record_.Add(/* count */ -2);
176 EXPECT_EQ(15, record_.count());
177
Darin Petkovcd8c3172010-06-24 10:13:54 -0700178 record_.Add(/* count */ kint32max);
179 EXPECT_EQ(kint32max, record_.count());
Darin Petkovf1e85e42010-06-10 15:59:53 -0700180
181 record_.Add(/* count */ 1);
Darin Petkovcd8c3172010-06-24 10:13:54 -0700182 EXPECT_EQ(kint32max, record_.count());
Darin Petkovf1e85e42010-06-10 15:59:53 -0700183}
184
185TEST_F(TaggedCounterTest, BadFileLocation) {
186 // Checks that the counter doesn't die badly if the file can't be
187 // created.
188 counter_.Init(kDoesNotExistFile,
189 /* reporter */ NULL, /* reporter_handle */ NULL);
190 counter_.Update(/* tag */ 10, /* count */ 20);
191 EXPECT_TRUE(LogContains("Unable to open the persistent counter file: "
192 "No such file or directory"));
193 EXPECT_EQ(TaggedCounter::kRecordInvalid, counter_.record_state_);
194 file_util::Delete(FilePath(kDoesNotExistFile), false);
195}
196
197TEST_F(TaggedCounterTest, Flush) {
198 counter_.Flush();
199 EXPECT_EQ(TaggedCounter::kRecordNull, counter_.record_state_);
200
201 counter_.Update(/* tag */ 40, /* count */ 60);
202 ExpectReporterCall(/* tag */ 40, /* count */ 60);
203 counter_.Flush();
204 EXPECT_TRUE(AssertNoOrEmptyRecordFile());
205 EXPECT_EQ(TaggedCounter::kRecordNull, counter_.record_state_);
206
207 counter_.Update(/* tag */ 41, /* count */ 70);
208 counter_.record_.Init(/* tag */ 0, /* count */ 0);
209 counter_.record_state_ = TaggedCounter::kRecordInvalid;
210 ExpectReporterCall(/* tag */ 41, /* count */ 70);
211 counter_.Flush();
212 EXPECT_TRUE(AssertNoOrEmptyRecordFile());
213 EXPECT_EQ(TaggedCounter::kRecordNull, counter_.record_state_);
214}
215
216TEST_F(TaggedCounterTest, InitFromFile) {
217 counter_.Update(/* tag */ 30, /* count */ 50);
218 EXPECT_PRED_FORMAT2(AssertRecord, /* day */ 30, /* seconds */ 50);
219 EXPECT_EQ(TaggedCounter::kRecordValid, counter_.record_state_);
220
221 counter_.Init(kTestRecordFile, &Reporter, this);
222 counter_.Update(/* tag */ 30, /* count */ 40);
223 EXPECT_PRED_FORMAT2(AssertRecord, /* day */ 30, /* seconds */ 90);
224 EXPECT_EQ(TaggedCounter::kRecordValid, counter_.record_state_);
225
226 counter_.Init(kTestRecordFile, &Reporter, this);
227 ExpectReporterCall(/* tag */ 30, /* count */ 90);
228 counter_.Update(/* tag */ 31, /* count */ 60);
229 EXPECT_PRED_FORMAT2(AssertRecord, /* day */ 31, /* seconds */ 60);
230 EXPECT_EQ(TaggedCounter::kRecordValid, counter_.record_state_);
231
232 ExpectReporterCall(/* tag */ 31, /* count */ 60);
233 counter_.Init(kTestRecordFile, &Reporter, this);
234 counter_.Update(/* tag */ 32, /* count */ 0);
Darin Petkov1bb904e2010-06-16 15:58:06 -0700235 EXPECT_PRED_FORMAT2(AssertRecord, /* day */ 32, /* seconds */ 0);
236 EXPECT_EQ(TaggedCounter::kRecordValid, counter_.record_state_);
Darin Petkovf1e85e42010-06-10 15:59:53 -0700237}
238
239TEST_F(TaggedCounterTest, Update) {
240 counter_.Update(/* tag */ 20, /* count */ 30);
241 EXPECT_PRED_FORMAT2(AssertRecord, /* day */ 20, /* seconds */ 30);
242 EXPECT_EQ(TaggedCounter::kRecordValid, counter_.record_state_);
243
244 counter_.Update(/* tag */ 20, /* count */ 40);
245 EXPECT_PRED_FORMAT2(AssertRecord, /* day */ 20, /* seconds */ 70);
246 EXPECT_EQ(TaggedCounter::kRecordValid, counter_.record_state_);
247
248 ExpectReporterCall(/* tag */ 20, /* count */ 70);
249 counter_.Update(/* tag */ 21, /* count */ 15);
250 EXPECT_PRED_FORMAT2(AssertRecord, /* day */ 21, /* seconds */ 15);
251 EXPECT_EQ(TaggedCounter::kRecordValid, counter_.record_state_);
252
253 ExpectReporterCall(/* tag */ 21, /* count */ 15);
254 counter_.Update(/* tag */ 22, /* count */ 0);
Darin Petkov1bb904e2010-06-16 15:58:06 -0700255 EXPECT_PRED_FORMAT2(AssertRecord, /* day */ 22, /* seconds */ 0);
256 EXPECT_EQ(TaggedCounter::kRecordValid, counter_.record_state_);
Darin Petkovf1e85e42010-06-10 15:59:53 -0700257}
258
Ken Mixterccd84c02010-08-16 19:57:13 -0700259class FrequencyCounterTest : public testing::Test {
260 protected:
261 virtual void SetUp() {
262 tagged_counter_ = new StrictMock<TaggedCounterMock>;
263 frequency_counter_.tagged_counter_.reset(tagged_counter_);
264 }
265
266 static void FakeReporter(void *, int32, int32) {
267 }
268
269 void CheckInit(int32 cycle_duration);
270 void CheckCycleNumber(int32 cycle_duration);
271
272 FrequencyCounter frequency_counter_;
273 StrictMock<TaggedCounterMock>* tagged_counter_;
274
275 TaggedCounter::Reporter reporter_;
276};
277
278void FrequencyCounterTest::CheckInit(int32 cycle_duration) {
279 EXPECT_CALL(*tagged_counter_, Init(kTestRecordFile, FakeReporter, this))
280 .Times(1)
281 .RetiresOnSaturation();
282 frequency_counter_.Init(kTestRecordFile,
283 FakeReporter,
284 this,
285 cycle_duration);
286 EXPECT_EQ(cycle_duration, frequency_counter_.cycle_duration_);
287}
288
289TEST_F(FrequencyCounterTest, Init) {
290 CheckInit(100);
291}
292
293void FrequencyCounterTest::CheckCycleNumber(int32 cycle_duration) {
294 CheckInit(cycle_duration);
295 EXPECT_EQ(150, frequency_counter_.GetCycleNumber(cycle_duration * 150));
296 EXPECT_EQ(150, frequency_counter_.GetCycleNumber(cycle_duration * 150 +
297 cycle_duration - 1));
298 EXPECT_EQ(151, frequency_counter_.GetCycleNumber(cycle_duration * 151 + 1));
299 EXPECT_EQ(0, frequency_counter_.GetCycleNumber(0));
300}
301
302
303TEST_F(FrequencyCounterTest, GetCycleNumberForWeek) {
304 CheckCycleNumber(kSecondsPerWeek);
305}
306
307TEST_F(FrequencyCounterTest, GetCycleNumberForDay) {
308 CheckCycleNumber(kSecondsPerDay);
309}
310
311TEST_F(FrequencyCounterTest, UpdateInternal) {
312 CheckInit(kSecondsPerWeek);
313 EXPECT_CALL(*tagged_counter_, Update(150, 2));
314 frequency_counter_.UpdateInternal(2, kSecondsPerWeek * 150);
315}
316
Darin Petkovf1e85e42010-06-10 15:59:53 -0700317} // namespace chromeos_metrics
318
319int main(int argc, char** argv) {
320 testing::InitGoogleTest(&argc, argv);
321 return RUN_ALL_TESTS();
322}