1// Copyright (c) 2010 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 "chrome/browser/metrics/metrics_service.h"
6
7#include <string>
8#include <vector>
9
10#include "base/base64.h"
11#include "base/md5.h"
12#include "base/values.h"
13
14#include "testing/gtest/include/gtest/gtest.h"
15
16class MetricsServiceTest : public ::testing::Test {
17};
18
19static const size_t kMaxLocalListSize = 3;
20
21// Ensure the ClientId is formatted as expected.
22TEST(MetricsServiceTest, ClientIdCorrectlyFormatted) {
23  std::string clientid = MetricsService::GenerateClientID();
24  EXPECT_EQ(36U, clientid.length());
25  std::string hexchars = "0123456789ABCDEF";
26  for (uint32 i = 0; i < clientid.length(); i++) {
27    char current = clientid.at(i);
28    if (i == 8 || i == 13 || i == 18 || i == 23) {
29      EXPECT_EQ('-', current);
30    } else {
31      EXPECT_TRUE(std::string::npos != hexchars.find(current));
32    }
33  }
34}
35
36// Store and retrieve empty list.
37TEST(MetricsServiceTest, EmptyLogList) {
38  ListValue list;
39  std::vector<std::string> local_list;
40
41  MetricsService::StoreUnsentLogsHelper(local_list, kMaxLocalListSize, &list);
42  EXPECT_EQ(0U, list.GetSize());
43
44  local_list.clear();  // RecallUnsentLogsHelper() expects empty |local_list|.
45  EXPECT_EQ(MetricsService::LIST_EMPTY,
46            MetricsService::RecallUnsentLogsHelper(list, &local_list));
47  EXPECT_EQ(0U, local_list.size());
48}
49
50// Store and retrieve a single log value.
51TEST(MetricsServiceTest, SingleElementLogList) {
52  ListValue list;
53  std::vector<std::string> local_list;
54
55  local_list.push_back("Hello world!");
56  EXPECT_EQ(1U, local_list.size());
57
58  MetricsService::StoreUnsentLogsHelper(local_list, kMaxLocalListSize, &list);
59
60  // |list| will now contain the following:
61  // [1, Base64Encode("Hello world!"), MD5("Hello world!")].
62  EXPECT_EQ(3U, list.GetSize());
63
64  // Examine each element.
65  ListValue::const_iterator it = list.begin();
66  int size = 0;
67  (*it)->GetAsInteger(&size);
68  EXPECT_EQ(1, size);
69
70  ++it;
71  std::string str;
72  (*it)->GetAsString(&str);  // Base64 encoded "Hello world!" string.
73  std::string encoded;
74  base::Base64Encode("Hello world!", &encoded);
75  EXPECT_TRUE(encoded == str);
76
77  ++it;
78  (*it)->GetAsString(&str);  // MD5 for encoded "Hello world!" string.
79  EXPECT_TRUE(MD5String(encoded) == str);
80
81  ++it;
82  EXPECT_TRUE(it == list.end());  // Reached end of list.
83
84  local_list.clear();
85  EXPECT_EQ(MetricsService::RECALL_SUCCESS,
86            MetricsService::RecallUnsentLogsHelper(list, &local_list));
87  EXPECT_EQ(1U, local_list.size());
88}
89
90// Store elements greater than the limit.
91TEST(MetricsServiceTest, OverLimitLogList) {
92  ListValue list;
93  std::vector<std::string> local_list;
94
95  local_list.push_back("one");
96  local_list.push_back("two");
97  local_list.push_back("three");
98  local_list.push_back("four");
99  EXPECT_EQ(4U, local_list.size());
100
101  std::string expected_first;
102  base::Base64Encode(local_list[local_list.size() - kMaxLocalListSize],
103                     &expected_first);
104  std::string expected_last;
105  base::Base64Encode(local_list[local_list.size() - 1],
106                     &expected_last);
107
108  MetricsService::StoreUnsentLogsHelper(local_list, kMaxLocalListSize, &list);
109  EXPECT_EQ(kMaxLocalListSize + 2, list.GetSize());
110
111  std::string actual_first;
112  EXPECT_TRUE((*(list.begin() + 1))->GetAsString(&actual_first));
113  EXPECT_TRUE(expected_first == actual_first);
114
115  std::string actual_last;
116  EXPECT_TRUE((*(list.end() - 2))->GetAsString(&actual_last));
117  EXPECT_TRUE(expected_last == actual_last);
118
119  local_list.clear();
120  EXPECT_EQ(MetricsService::RECALL_SUCCESS,
121            MetricsService::RecallUnsentLogsHelper(list, &local_list));
122  EXPECT_EQ(kMaxLocalListSize, local_list.size());
123}
124
125// Induce LIST_SIZE_TOO_SMALL corruption
126TEST(MetricsServiceTest, SmallRecoveredListSize) {
127  ListValue list;
128  std::vector<std::string> local_list;
129
130  local_list.push_back("Hello world!");
131  EXPECT_EQ(1U, local_list.size());
132  MetricsService::StoreUnsentLogsHelper(local_list, kMaxLocalListSize, &list);
133  EXPECT_EQ(3U, list.GetSize());
134
135  // Remove last element.
136  list.Remove(list.GetSize() - 1, NULL);
137  EXPECT_EQ(2U, list.GetSize());
138
139  local_list.clear();
140  EXPECT_EQ(MetricsService::LIST_SIZE_TOO_SMALL,
141            MetricsService::RecallUnsentLogsHelper(list, &local_list));
142}
143
144// Remove size from the stored list.
145TEST(MetricsServiceTest, RemoveSizeFromLogList) {
146  ListValue list;
147  std::vector<std::string> local_list;
148
149  local_list.push_back("one");
150  local_list.push_back("two");
151  EXPECT_EQ(2U, local_list.size());
152  MetricsService::StoreUnsentLogsHelper(local_list, kMaxLocalListSize, &list);
153  EXPECT_EQ(4U, list.GetSize());
154
155  list.Remove(0, NULL);  // Delete size (1st element).
156  EXPECT_EQ(3U, list.GetSize());
157
158  local_list.clear();
159  EXPECT_EQ(MetricsService::LIST_SIZE_MISSING,
160            MetricsService::RecallUnsentLogsHelper(list, &local_list));
161}
162
163// Corrupt size of stored list.
164TEST(MetricsServiceTest, CorruptSizeOfLogList) {
165  ListValue list;
166  std::vector<std::string> local_list;
167
168  local_list.push_back("Hello world!");
169  EXPECT_EQ(1U, local_list.size());
170  MetricsService::StoreUnsentLogsHelper(local_list, kMaxLocalListSize, &list);
171  EXPECT_EQ(3U, list.GetSize());
172
173  // Change list size from 1 to 2.
174  EXPECT_TRUE(list.Set(0, Value::CreateIntegerValue(2)));
175  EXPECT_EQ(3U, list.GetSize());
176
177  local_list.clear();
178  EXPECT_EQ(MetricsService::LIST_SIZE_CORRUPTION,
179            MetricsService::RecallUnsentLogsHelper(list, &local_list));
180}
181
182// Corrupt checksum of stored list.
183TEST(MetricsServiceTest, CorruptChecksumOfLogList) {
184  ListValue list;
185  std::vector<std::string> local_list;
186
187  local_list.clear();
188  local_list.push_back("Hello world!");
189  EXPECT_EQ(1U, local_list.size());
190  MetricsService::StoreUnsentLogsHelper(local_list, kMaxLocalListSize, &list);
191  EXPECT_EQ(3U, list.GetSize());
192
193  // Fetch checksum (last element) and change it.
194  std::string checksum;
195  EXPECT_TRUE((*(list.end() - 1))->GetAsString(&checksum));
196  checksum[0] = (checksum[0] == 'a') ? 'b' : 'a';
197  EXPECT_TRUE(list.Set(2, Value::CreateStringValue(checksum)));
198  EXPECT_EQ(3U, list.GetSize());
199
200  local_list.clear();
201  EXPECT_EQ(MetricsService::CHECKSUM_CORRUPTION,
202            MetricsService::RecallUnsentLogsHelper(list, &local_list));
203}
204