blob: fd5a38939e718dbb66f03dc5f639f13951555ad9 [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"
15
16using ::testing::_;
17using ::testing::MockFunction;
18using ::testing::StrictMock;
19
20namespace chromeos_metrics {
21
22static const char kTestRecordFile[] = "record-file";
23static const char kDoesNotExistFile[] = "/does/not/exist";
24
25class RecordTest : public testing::Test {
26 protected:
27 virtual void SetUp() {
28 EXPECT_EQ(0, record_.tag());
29 EXPECT_EQ(0, record_.count());
30 }
31
32 // The record under test.
33 TaggedCounter::Record record_;
34};
35
36class TaggedCounterTest : public testing::Test {
37 protected:
38 virtual void SetUp() {
39 EXPECT_EQ(NULL, counter_.filename_);
40 EXPECT_TRUE(NULL == counter_.reporter_);
41 EXPECT_EQ(NULL, counter_.reporter_handle_);
42 EXPECT_EQ(TaggedCounter::kRecordInvalid, counter_.record_state_);
43
44 counter_.Init(kTestRecordFile, &Reporter, this);
45 EXPECT_TRUE(AssertNoOrEmptyRecordFile());
46 EXPECT_EQ(kTestRecordFile, counter_.filename_);
47 EXPECT_TRUE(Reporter == counter_.reporter_);
48 EXPECT_EQ(this, counter_.reporter_handle_);
49 EXPECT_EQ(TaggedCounter::kRecordInvalid, counter_.record_state_);
50
51 // The test fixture object will be used by the log message handler.
52 test_ = this;
53 logging::SetLogMessageHandler(HandleLogMessages);
54 }
55
56 virtual void TearDown() {
57 logging::SetLogMessageHandler(NULL);
58 test_ = NULL;
59 file_util::Delete(FilePath(kTestRecordFile), false);
60 }
61
62 // Asserts that the record file contains the specified contents.
63 testing::AssertionResult AssertRecord(const char* expr_tag,
64 const char* expr_count,
Darin Petkovcd8c3172010-06-24 10:13:54 -070065 int32 expected_tag,
66 int32 expected_count) {
Darin Petkovf1e85e42010-06-10 15:59:53 -070067 int fd = HANDLE_EINTR(open(kTestRecordFile, O_RDONLY));
68 if (fd < 0) {
69 testing::Message msg;
70 msg << "Unable to open " << kTestRecordFile;
71 return testing::AssertionFailure(msg);
72 }
73
74 TaggedCounter::Record record;
75 if (!file_util::ReadFromFD(fd, reinterpret_cast<char*>(&record),
76 sizeof(record))) {
77 testing::Message msg;
78 msg << "Unable to read " << sizeof(record) << " bytes from "
79 << kTestRecordFile;
80 HANDLE_EINTR(close(fd));
81 return testing::AssertionFailure(msg);
82 }
83
84 if (record.tag() != expected_tag || record.count() != expected_count) {
85 testing::Message msg;
86 msg << "actual record (" << record.tag() << ", " << record.count()
87 << ") expected (" << expected_tag << ", " << expected_count << ")";
88 HANDLE_EINTR(close(fd));
89 return testing::AssertionFailure(msg);
90 }
91
92 HANDLE_EINTR(close(fd));
93 return testing::AssertionSuccess();
94 }
95
96 // Returns true if the persistent record file does not exist or is
97 // empty, false otherwise.
98 bool AssertNoOrEmptyRecordFile() {
99 FilePath record_file(counter_.filename_);
100 int64 record_file_size;
101 return !file_util::PathExists(record_file) ||
102 (file_util::GetFileSize(record_file, &record_file_size) &&
103 record_file_size == 0);
104 }
105
106 // Adds a reporter call expectation that the specified tag/count
107 // callback will be generated.
Darin Petkovcd8c3172010-06-24 10:13:54 -0700108 void ExpectReporterCall(int32 tag, int32 count) {
Darin Petkovf1e85e42010-06-10 15:59:53 -0700109 EXPECT_CALL(reporter_, Call(_, tag, count))
110 .Times(1)
111 .RetiresOnSaturation();
112 }
113
114 // The reporter callback forwards the call to the reporter mock so
115 // that we can set call expectations.
Darin Petkovcd8c3172010-06-24 10:13:54 -0700116 static void Reporter(void* handle, int32 tag, int32 count) {
Darin Petkovf1e85e42010-06-10 15:59:53 -0700117 TaggedCounterTest* test = static_cast<TaggedCounterTest*>(handle);
118 ASSERT_FALSE(NULL == test);
119 test->reporter_.Call(handle, tag, count);
120 }
121
122 // Collects log messages in the |log_| member string so that they
123 // can be analyzed for errors and expected behavior.
124 static bool HandleLogMessages(int severity, const std::string& str) {
125 test_->log_.append(str);
126 test_->log_.append("\n");
127
128 // Returning true would mute the log.
129 return false;
130 }
131
132 // Returns true if the counter log contains |pattern|, false otherwise.
Darin Petkovcd8c3172010-06-24 10:13:54 -0700133 bool LogContains(const std::string& pattern) const {
Darin Petkovf1e85e42010-06-10 15:59:53 -0700134 return log_.find(pattern) != std::string::npos;
135 }
136
137 // The TaggedCounter object under test.
138 TaggedCounter counter_;
139
140 // The accumulated counter log.
141 std::string log_;
142
143 // Reporter mock to set callback expectations on.
Darin Petkovcd8c3172010-06-24 10:13:54 -0700144 StrictMock<MockFunction<void(void* handle,
145 int32 tag, int32 count)> > reporter_;
Darin Petkovf1e85e42010-06-10 15:59:53 -0700146
147 // Pointer to the current test fixture.
148 static TaggedCounterTest* test_;
149};
150
151// static
152TaggedCounterTest* TaggedCounterTest::test_ = NULL;
153
154TEST_F(RecordTest, Init) {
155 record_.Init(/* tag */ 5, /* count */ -1);
156 EXPECT_EQ(5, record_.tag());
157 EXPECT_EQ(0, record_.count());
158
159 record_.Init(/* tag */ -2, /* count */ 10);
160 EXPECT_EQ(-2, record_.tag());
161 EXPECT_EQ(10, record_.count());
162}
163
164TEST_F(RecordTest, Add) {
165 record_.Add(/* count */ -1);
166 EXPECT_EQ(0, record_.count());
167
168 record_.Add(/* count */ 5);
169 EXPECT_EQ(5, record_.count());
170
171 record_.Add(/* count */ 10);
172 EXPECT_EQ(15, record_.count());
173
174 record_.Add(/* count */ -2);
175 EXPECT_EQ(15, record_.count());
176
Darin Petkovcd8c3172010-06-24 10:13:54 -0700177 record_.Add(/* count */ kint32max);
178 EXPECT_EQ(kint32max, record_.count());
Darin Petkovf1e85e42010-06-10 15:59:53 -0700179
180 record_.Add(/* count */ 1);
Darin Petkovcd8c3172010-06-24 10:13:54 -0700181 EXPECT_EQ(kint32max, record_.count());
Darin Petkovf1e85e42010-06-10 15:59:53 -0700182}
183
184TEST_F(TaggedCounterTest, BadFileLocation) {
185 // Checks that the counter doesn't die badly if the file can't be
186 // created.
187 counter_.Init(kDoesNotExistFile,
188 /* reporter */ NULL, /* reporter_handle */ NULL);
189 counter_.Update(/* tag */ 10, /* count */ 20);
190 EXPECT_TRUE(LogContains("Unable to open the persistent counter file: "
191 "No such file or directory"));
192 EXPECT_EQ(TaggedCounter::kRecordInvalid, counter_.record_state_);
193 file_util::Delete(FilePath(kDoesNotExistFile), false);
194}
195
196TEST_F(TaggedCounterTest, Flush) {
197 counter_.Flush();
198 EXPECT_EQ(TaggedCounter::kRecordNull, counter_.record_state_);
199
200 counter_.Update(/* tag */ 40, /* count */ 60);
201 ExpectReporterCall(/* tag */ 40, /* count */ 60);
202 counter_.Flush();
203 EXPECT_TRUE(AssertNoOrEmptyRecordFile());
204 EXPECT_EQ(TaggedCounter::kRecordNull, counter_.record_state_);
205
206 counter_.Update(/* tag */ 41, /* count */ 70);
207 counter_.record_.Init(/* tag */ 0, /* count */ 0);
208 counter_.record_state_ = TaggedCounter::kRecordInvalid;
209 ExpectReporterCall(/* tag */ 41, /* count */ 70);
210 counter_.Flush();
211 EXPECT_TRUE(AssertNoOrEmptyRecordFile());
212 EXPECT_EQ(TaggedCounter::kRecordNull, counter_.record_state_);
213}
214
215TEST_F(TaggedCounterTest, InitFromFile) {
216 counter_.Update(/* tag */ 30, /* count */ 50);
217 EXPECT_PRED_FORMAT2(AssertRecord, /* day */ 30, /* seconds */ 50);
218 EXPECT_EQ(TaggedCounter::kRecordValid, counter_.record_state_);
219
220 counter_.Init(kTestRecordFile, &Reporter, this);
221 counter_.Update(/* tag */ 30, /* count */ 40);
222 EXPECT_PRED_FORMAT2(AssertRecord, /* day */ 30, /* seconds */ 90);
223 EXPECT_EQ(TaggedCounter::kRecordValid, counter_.record_state_);
224
225 counter_.Init(kTestRecordFile, &Reporter, this);
226 ExpectReporterCall(/* tag */ 30, /* count */ 90);
227 counter_.Update(/* tag */ 31, /* count */ 60);
228 EXPECT_PRED_FORMAT2(AssertRecord, /* day */ 31, /* seconds */ 60);
229 EXPECT_EQ(TaggedCounter::kRecordValid, counter_.record_state_);
230
231 ExpectReporterCall(/* tag */ 31, /* count */ 60);
232 counter_.Init(kTestRecordFile, &Reporter, this);
233 counter_.Update(/* tag */ 32, /* count */ 0);
Darin Petkov1bb904e2010-06-16 15:58:06 -0700234 EXPECT_PRED_FORMAT2(AssertRecord, /* day */ 32, /* seconds */ 0);
235 EXPECT_EQ(TaggedCounter::kRecordValid, counter_.record_state_);
Darin Petkovf1e85e42010-06-10 15:59:53 -0700236}
237
238TEST_F(TaggedCounterTest, Update) {
239 counter_.Update(/* tag */ 20, /* count */ 30);
240 EXPECT_PRED_FORMAT2(AssertRecord, /* day */ 20, /* seconds */ 30);
241 EXPECT_EQ(TaggedCounter::kRecordValid, counter_.record_state_);
242
243 counter_.Update(/* tag */ 20, /* count */ 40);
244 EXPECT_PRED_FORMAT2(AssertRecord, /* day */ 20, /* seconds */ 70);
245 EXPECT_EQ(TaggedCounter::kRecordValid, counter_.record_state_);
246
247 ExpectReporterCall(/* tag */ 20, /* count */ 70);
248 counter_.Update(/* tag */ 21, /* count */ 15);
249 EXPECT_PRED_FORMAT2(AssertRecord, /* day */ 21, /* seconds */ 15);
250 EXPECT_EQ(TaggedCounter::kRecordValid, counter_.record_state_);
251
252 ExpectReporterCall(/* tag */ 21, /* count */ 15);
253 counter_.Update(/* tag */ 22, /* count */ 0);
Darin Petkov1bb904e2010-06-16 15:58:06 -0700254 EXPECT_PRED_FORMAT2(AssertRecord, /* day */ 22, /* seconds */ 0);
255 EXPECT_EQ(TaggedCounter::kRecordValid, counter_.record_state_);
Darin Petkovf1e85e42010-06-10 15:59:53 -0700256}
257
258} // namespace chromeos_metrics
259
260int main(int argc, char** argv) {
261 testing::InitGoogleTest(&argc, argv);
262 return RUN_ALL_TESTS();
263}