// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/metrics/metrics_service.h"
#include <string>
#include <vector>
#include "base/base64.h"
#include "base/md5.h"
#include "base/values.h"
#include "testing/gtest/include/gtest/gtest.h"
class MetricsServiceTest : public ::testing::Test {
};
static const size_t kMaxLocalListSize = 3;
// Ensure the ClientId is formatted as expected.
TEST(MetricsServiceTest, ClientIdCorrectlyFormatted) {
std::string clientid = MetricsService::GenerateClientID();
EXPECT_EQ(36U, clientid.length());
std::string hexchars = "0123456789ABCDEF";
for (uint32 i = 0; i < clientid.length(); i++) {
char current = clientid.at(i);
if (i == 8 || i == 13 || i == 18 || i == 23) {
EXPECT_EQ('-', current);
} else {
EXPECT_TRUE(std::string::npos != hexchars.find(current));
}
}
}
// Store and retrieve empty list.
TEST(MetricsServiceTest, EmptyLogList) {
ListValue list;
std::vector<std::string> local_list;
MetricsService::StoreUnsentLogsHelper(local_list, kMaxLocalListSize, &list);
EXPECT_EQ(0U, list.GetSize());
local_list.clear(); // RecallUnsentLogsHelper() expects empty |local_list|.
EXPECT_EQ(MetricsService::LIST_EMPTY,
MetricsService::RecallUnsentLogsHelper(list, &local_list));
EXPECT_EQ(0U, local_list.size());
}
// Store and retrieve a single log value.
TEST(MetricsServiceTest, SingleElementLogList) {
ListValue list;
std::vector<std::string> local_list;
local_list.push_back("Hello world!");
EXPECT_EQ(1U, local_list.size());
MetricsService::StoreUnsentLogsHelper(local_list, kMaxLocalListSize, &list);
// |list| will now contain the following:
// [1, Base64Encode("Hello world!"), MD5("Hello world!")].
EXPECT_EQ(3U, list.GetSize());
// Examine each element.
ListValue::const_iterator it = list.begin();
int size = 0;
(*it)->GetAsInteger(&size);
EXPECT_EQ(1, size);
++it;
std::string str;
(*it)->GetAsString(&str); // Base64 encoded "Hello world!" string.
std::string encoded;
base::Base64Encode("Hello world!", &encoded);
EXPECT_TRUE(encoded == str);
++it;
(*it)->GetAsString(&str); // MD5 for encoded "Hello world!" string.
EXPECT_TRUE(MD5String(encoded) == str);
++it;
EXPECT_TRUE(it == list.end()); // Reached end of list.
local_list.clear();
EXPECT_EQ(MetricsService::RECALL_SUCCESS,
MetricsService::RecallUnsentLogsHelper(list, &local_list));
EXPECT_EQ(1U, local_list.size());
}
// Store elements greater than the limit.
TEST(MetricsServiceTest, OverLimitLogList) {
ListValue list;
std::vector<std::string> local_list;
local_list.push_back("one");
local_list.push_back("two");
local_list.push_back("three");
local_list.push_back("four");
EXPECT_EQ(4U, local_list.size());
std::string expected_first;
base::Base64Encode(local_list[local_list.size() - kMaxLocalListSize],
&expected_first);
std::string expected_last;
base::Base64Encode(local_list[local_list.size() - 1],
&expected_last);
MetricsService::StoreUnsentLogsHelper(local_list, kMaxLocalListSize, &list);
EXPECT_EQ(kMaxLocalListSize + 2, list.GetSize());
std::string actual_first;
EXPECT_TRUE((*(list.begin() + 1))->GetAsString(&actual_first));
EXPECT_TRUE(expected_first == actual_first);
std::string actual_last;
EXPECT_TRUE((*(list.end() - 2))->GetAsString(&actual_last));
EXPECT_TRUE(expected_last == actual_last);
local_list.clear();
EXPECT_EQ(MetricsService::RECALL_SUCCESS,
MetricsService::RecallUnsentLogsHelper(list, &local_list));
EXPECT_EQ(kMaxLocalListSize, local_list.size());
}
// Induce LIST_SIZE_TOO_SMALL corruption
TEST(MetricsServiceTest, SmallRecoveredListSize) {
ListValue list;
std::vector<std::string> local_list;
local_list.push_back("Hello world!");
EXPECT_EQ(1U, local_list.size());
MetricsService::StoreUnsentLogsHelper(local_list, kMaxLocalListSize, &list);
EXPECT_EQ(3U, list.GetSize());
// Remove last element.
list.Remove(list.GetSize() - 1, NULL);
EXPECT_EQ(2U, list.GetSize());
local_list.clear();
EXPECT_EQ(MetricsService::LIST_SIZE_TOO_SMALL,
MetricsService::RecallUnsentLogsHelper(list, &local_list));
}
// Remove size from the stored list.
TEST(MetricsServiceTest, RemoveSizeFromLogList) {
ListValue list;
std::vector<std::string> local_list;
local_list.push_back("one");
local_list.push_back("two");
EXPECT_EQ(2U, local_list.size());
MetricsService::StoreUnsentLogsHelper(local_list, kMaxLocalListSize, &list);
EXPECT_EQ(4U, list.GetSize());
list.Remove(0, NULL); // Delete size (1st element).
EXPECT_EQ(3U, list.GetSize());
local_list.clear();
EXPECT_EQ(MetricsService::LIST_SIZE_MISSING,
MetricsService::RecallUnsentLogsHelper(list, &local_list));
}
// Corrupt size of stored list.
TEST(MetricsServiceTest, CorruptSizeOfLogList) {
ListValue list;
std::vector<std::string> local_list;
local_list.push_back("Hello world!");
EXPECT_EQ(1U, local_list.size());
MetricsService::StoreUnsentLogsHelper(local_list, kMaxLocalListSize, &list);
EXPECT_EQ(3U, list.GetSize());
// Change list size from 1 to 2.
EXPECT_TRUE(list.Set(0, Value::CreateIntegerValue(2)));
EXPECT_EQ(3U, list.GetSize());
local_list.clear();
EXPECT_EQ(MetricsService::LIST_SIZE_CORRUPTION,
MetricsService::RecallUnsentLogsHelper(list, &local_list));
}
// Corrupt checksum of stored list.
TEST(MetricsServiceTest, CorruptChecksumOfLogList) {
ListValue list;
std::vector<std::string> local_list;
local_list.clear();
local_list.push_back("Hello world!");
EXPECT_EQ(1U, local_list.size());
MetricsService::StoreUnsentLogsHelper(local_list, kMaxLocalListSize, &list);
EXPECT_EQ(3U, list.GetSize());
// Fetch checksum (last element) and change it.
std::string checksum;
EXPECT_TRUE((*(list.end() - 1))->GetAsString(&checksum));
checksum[0] = (checksum[0] == 'a') ? 'b' : 'a';
EXPECT_TRUE(list.Set(2, Value::CreateStringValue(checksum)));
EXPECT_EQ(3U, list.GetSize());
local_list.clear();
EXPECT_EQ(MetricsService::CHECKSUM_CORRUPTION,
MetricsService::RecallUnsentLogsHelper(list, &local_list));
}