1 // Copyright (c) 2012 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 "base/base64.h"
6 #include "base/md5.h"
7 #include "base/values.h"
8 #include "chrome/browser/metrics/metrics_log_serializer.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10
11 namespace {
12
13 const size_t kListLengthLimit = 3;
14 const size_t kLogByteLimit = 1000;
15
SetLogText(const std::string & log_text,MetricsLogManager::SerializedLog * log)16 void SetLogText(const std::string& log_text,
17 MetricsLogManager::SerializedLog* log) {
18 std::string log_text_copy = log_text;
19 log->SwapLogText(&log_text_copy);
20 }
21
22 } // namespace
23
24 // Store and retrieve empty list.
TEST(MetricsLogSerializerTest,EmptyLogList)25 TEST(MetricsLogSerializerTest, EmptyLogList) {
26 ListValue list;
27 std::vector<MetricsLogManager::SerializedLog> local_list;
28
29 MetricsLogSerializer::WriteLogsToPrefList(local_list, kListLengthLimit,
30 kLogByteLimit, &list);
31 EXPECT_EQ(0U, list.GetSize());
32
33 local_list.clear(); // ReadLogsFromPrefList() expects empty |local_list|.
34 EXPECT_EQ(
35 MetricsLogSerializer::LIST_EMPTY,
36 MetricsLogSerializer::ReadLogsFromPrefList(list, &local_list));
37 EXPECT_EQ(0U, local_list.size());
38 }
39
40 // Store and retrieve a single log value.
TEST(MetricsLogSerializerTest,SingleElementLogList)41 TEST(MetricsLogSerializerTest, SingleElementLogList) {
42 ListValue list;
43
44 std::vector<MetricsLogManager::SerializedLog> local_list(1);
45 SetLogText("Hello world!", &local_list[0]);
46
47 MetricsLogSerializer::WriteLogsToPrefList(local_list, kListLengthLimit,
48 kLogByteLimit, &list);
49
50 // |list| will now contain the following:
51 // [1, Base64Encode("Hello world!"), MD5("Hello world!")].
52 ASSERT_EQ(3U, list.GetSize());
53
54 // Examine each element.
55 ListValue::const_iterator it = list.begin();
56 int size = 0;
57 (*it)->GetAsInteger(&size);
58 EXPECT_EQ(1, size);
59
60 ++it;
61 std::string str;
62 (*it)->GetAsString(&str); // Base64 encoded "Hello world!" string.
63 std::string encoded;
64 base::Base64Encode("Hello world!", &encoded);
65 EXPECT_TRUE(encoded == str);
66
67 ++it;
68 (*it)->GetAsString(&str); // MD5 for encoded "Hello world!" string.
69 EXPECT_TRUE(base::MD5String(encoded) == str);
70
71 ++it;
72 EXPECT_TRUE(it == list.end()); // Reached end of list.
73
74 local_list.clear();
75 EXPECT_EQ(
76 MetricsLogSerializer::RECALL_SUCCESS,
77 MetricsLogSerializer::ReadLogsFromPrefList(list, &local_list));
78 EXPECT_EQ(1U, local_list.size());
79 }
80
81 // Store a set of logs over the length limit, but smaller than the min number of
82 // bytes.
TEST(MetricsLogSerializerTest,LongButTinyLogList)83 TEST(MetricsLogSerializerTest, LongButTinyLogList) {
84 ListValue list;
85
86 size_t log_count = kListLengthLimit * 5;
87 std::vector<MetricsLogManager::SerializedLog> local_list(log_count);
88 for (size_t i = 0; i < local_list.size(); ++i)
89 SetLogText("x", &local_list[i]);
90
91 MetricsLogSerializer::WriteLogsToPrefList(local_list, kListLengthLimit,
92 kLogByteLimit, &list);
93 std::vector<MetricsLogManager::SerializedLog> result_list;
94 EXPECT_EQ(
95 MetricsLogSerializer::RECALL_SUCCESS,
96 MetricsLogSerializer::ReadLogsFromPrefList(list, &result_list));
97 EXPECT_EQ(local_list.size(), result_list.size());
98
99 EXPECT_TRUE(result_list.front().log_text().find("x") == 0);
100 }
101
102 // Store a set of logs over the length limit, but that doesn't reach the minimum
103 // number of bytes until after passing the length limit.
TEST(MetricsLogSerializerTest,LongButSmallLogList)104 TEST(MetricsLogSerializerTest, LongButSmallLogList) {
105 ListValue list;
106
107 size_t log_count = kListLengthLimit * 5;
108 // Make log_count logs each slightly larger than
109 // kLogByteLimit / (log_count - 2)
110 // so that the minimum is reached before the oldest (first) two logs.
111 std::vector<MetricsLogManager::SerializedLog> local_list(log_count);
112 size_t log_size = (kLogByteLimit / (log_count - 2)) + 2;
113 SetLogText("one", &local_list[0]);
114 SetLogText("two", &local_list[1]);
115 SetLogText("three", &local_list[2]);
116 SetLogText("last", &local_list[log_count - 1]);
117 for (size_t i = 0; i < local_list.size(); ++i) {
118 std::string log_text = local_list[i].log_text();
119 log_text.resize(log_size, ' ');
120 local_list[i].SwapLogText(&log_text);
121 }
122
123 MetricsLogSerializer::WriteLogsToPrefList(local_list, kListLengthLimit,
124 kLogByteLimit, &list);
125 std::vector<MetricsLogManager::SerializedLog> result_list;
126 EXPECT_EQ(
127 MetricsLogSerializer::RECALL_SUCCESS,
128 MetricsLogSerializer::ReadLogsFromPrefList(list, &result_list));
129 EXPECT_EQ(local_list.size() - 2, result_list.size());
130
131 EXPECT_TRUE(result_list.front().log_text().find("three") == 0);
132 EXPECT_TRUE(result_list.back().log_text().find("last") == 0);
133 }
134
135 // Store a set of logs within the length limit, but well over the minimum
136 // number of bytes.
TEST(MetricsLogSerializerTest,ShortButLargeLogList)137 TEST(MetricsLogSerializerTest, ShortButLargeLogList) {
138 ListValue list;
139
140 std::vector<MetricsLogManager::SerializedLog> local_list(kListLengthLimit);
141 // Make the total byte count about twice the minimum.
142 size_t log_size = (kLogByteLimit / local_list.size()) * 2;
143 for (size_t i = 0; i < local_list.size(); ++i) {
144 std::string log_text = local_list[i].log_text();
145 log_text.resize(log_size, ' ');
146 local_list[i].SwapLogText(&log_text);
147 }
148
149 MetricsLogSerializer::WriteLogsToPrefList(local_list, kListLengthLimit,
150 kLogByteLimit, &list);
151 std::vector<MetricsLogManager::SerializedLog> result_list;
152 EXPECT_EQ(
153 MetricsLogSerializer::RECALL_SUCCESS,
154 MetricsLogSerializer::ReadLogsFromPrefList(list, &result_list));
155 EXPECT_EQ(local_list.size(), result_list.size());
156 }
157
158 // Store a set of logs over the length limit, and over the minimum number of
159 // bytes.
TEST(MetricsLogSerializerTest,LongAndLargeLogList)160 TEST(MetricsLogSerializerTest, LongAndLargeLogList) {
161 ListValue list;
162
163 // Include twice the max number of logs.
164 std::vector<MetricsLogManager::SerializedLog>
165 local_list(kListLengthLimit * 2);
166 // Make the total byte count about four times the minimum.
167 size_t log_size = (kLogByteLimit / local_list.size()) * 4;
168 SetLogText("First to keep",
169 &local_list[local_list.size() - kListLengthLimit]);
170 for (size_t i = 0; i < local_list.size(); ++i) {
171 std::string log_text = local_list[i].log_text();
172 log_text.resize(log_size, ' ');
173 local_list[i].SwapLogText(&log_text);
174 }
175
176 MetricsLogSerializer::WriteLogsToPrefList(local_list, kListLengthLimit,
177 kLogByteLimit, &list);
178 std::vector<MetricsLogManager::SerializedLog> result_list;
179 EXPECT_EQ(
180 MetricsLogSerializer::RECALL_SUCCESS,
181 MetricsLogSerializer::ReadLogsFromPrefList(list, &result_list));
182 // The max length should control the resulting size.
183 EXPECT_EQ(kListLengthLimit, result_list.size());
184 EXPECT_TRUE(result_list.front().log_text().find("First to keep") == 0);
185 }
186
187 // Induce LIST_SIZE_TOO_SMALL corruption
TEST(MetricsLogSerializerTest,SmallRecoveredListSize)188 TEST(MetricsLogSerializerTest, SmallRecoveredListSize) {
189 ListValue list;
190
191 std::vector<MetricsLogManager::SerializedLog> local_list(1);
192 SetLogText("Hello world!", &local_list[0]);
193
194 MetricsLogSerializer::WriteLogsToPrefList(local_list, kListLengthLimit,
195 kLogByteLimit, &list);
196 EXPECT_EQ(3U, list.GetSize());
197
198 // Remove last element.
199 list.Remove(list.GetSize() - 1, NULL);
200 EXPECT_EQ(2U, list.GetSize());
201
202 local_list.clear();
203 EXPECT_EQ(
204 MetricsLogSerializer::LIST_SIZE_TOO_SMALL,
205 MetricsLogSerializer::ReadLogsFromPrefList(list, &local_list));
206 }
207
208 // Remove size from the stored list.
TEST(MetricsLogSerializerTest,RemoveSizeFromLogList)209 TEST(MetricsLogSerializerTest, RemoveSizeFromLogList) {
210 ListValue list;
211
212 std::vector<MetricsLogManager::SerializedLog> local_list(2);
213 SetLogText("one", &local_list[0]);
214 SetLogText("two", &local_list[1]);
215 EXPECT_EQ(2U, local_list.size());
216 MetricsLogSerializer::WriteLogsToPrefList(local_list, kListLengthLimit,
217 kLogByteLimit, &list);
218 EXPECT_EQ(4U, list.GetSize());
219
220 list.Remove(0, NULL); // Delete size (1st element).
221 EXPECT_EQ(3U, list.GetSize());
222
223 local_list.clear();
224 EXPECT_EQ(
225 MetricsLogSerializer::LIST_SIZE_MISSING,
226 MetricsLogSerializer::ReadLogsFromPrefList(list, &local_list));
227 }
228
229 // Corrupt size of stored list.
TEST(MetricsLogSerializerTest,CorruptSizeOfLogList)230 TEST(MetricsLogSerializerTest, CorruptSizeOfLogList) {
231 ListValue list;
232
233 std::vector<MetricsLogManager::SerializedLog> local_list(1);
234 SetLogText("Hello world!", &local_list[0]);
235
236 MetricsLogSerializer::WriteLogsToPrefList(local_list, kListLengthLimit,
237 kLogByteLimit, &list);
238 EXPECT_EQ(3U, list.GetSize());
239
240 // Change list size from 1 to 2.
241 EXPECT_TRUE(list.Set(0, Value::CreateIntegerValue(2)));
242 EXPECT_EQ(3U, list.GetSize());
243
244 local_list.clear();
245 EXPECT_EQ(
246 MetricsLogSerializer::LIST_SIZE_CORRUPTION,
247 MetricsLogSerializer::ReadLogsFromPrefList(list, &local_list));
248 }
249
250 // Corrupt checksum of stored list.
TEST(MetricsLogSerializerTest,CorruptChecksumOfLogList)251 TEST(MetricsLogSerializerTest, CorruptChecksumOfLogList) {
252 ListValue list;
253
254 std::vector<MetricsLogManager::SerializedLog> local_list(1);
255 SetLogText("Hello world!", &local_list[0]);
256
257 MetricsLogSerializer::WriteLogsToPrefList(local_list, kListLengthLimit,
258 kLogByteLimit, &list);
259 EXPECT_EQ(3U, list.GetSize());
260
261 // Fetch checksum (last element) and change it.
262 std::string checksum;
263 EXPECT_TRUE((*(list.end() - 1))->GetAsString(&checksum));
264 checksum[0] = (checksum[0] == 'a') ? 'b' : 'a';
265 EXPECT_TRUE(list.Set(2, Value::CreateStringValue(checksum)));
266 EXPECT_EQ(3U, list.GetSize());
267
268 local_list.clear();
269 EXPECT_EQ(
270 MetricsLogSerializer::CHECKSUM_CORRUPTION,
271 MetricsLogSerializer::ReadLogsFromPrefList(list, &local_list));
272 }
273