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 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. 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. 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. 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. 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. 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. 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 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. 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. 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. 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