// Copyright (c) 2012 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 <errno.h>
#include <sys/file.h>
#include "base/basictypes.h"
#include "base/containers/hash_tables.h"
#include "base/memory/scoped_ptr.h"
#include "chrome/browser/chromeos/external_metrics.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos { // Need this because of the FRIEND_TEST
class ExternalMetricsTest : public testing::Test {
};
// Because the metrics service is not essential, errors will not cause the
// program to terminate. However, the errors produce logs.
#define MAXLENGTH ExternalMetrics::kMetricsMessageMaxLength
static void SendMessage(const char* path, const char* name, const char* value) {
int fd = open(path, O_CREAT | O_APPEND | O_WRONLY, 0666);
int32 l = strlen(name) + strlen(value) + 2 + sizeof(l);
size_t num_bytes = 0;
num_bytes += write(fd, &l, sizeof(l));
num_bytes += write(fd, name, strlen(name) + 1);
num_bytes += write(fd, value, strlen(value) + 1);
EXPECT_EQ(num_bytes, sizeof(l) + strlen(name) + strlen(value) + 2);
close(fd);
}
static scoped_ptr<std::string> received_name;
static scoped_ptr<std::string> received_value;
int received_count = 0;
static void ReceiveMessage(const char* name, const char* value) {
received_name.reset(new std::string(name));
received_value.reset(new std::string(value));
received_count++;
}
static void CheckMessage(const char* name, const char* value, int count) {
EXPECT_EQ(*received_name.get(), name);
EXPECT_EQ(*received_value.get(), value);
EXPECT_EQ(received_count, count);
}
TEST(ExternalMetricsTest, ParseExternalMetricsFile) {
const char *histogram_data[] = {
"BootTime 9500 0 20000 50",
"BootTime 10000 0 20000 50",
"BootTime 9200 0 20000 50",
"ConnmanIdle 1000 0 2000 20",
"ConnmanIdle 1200 0 2000 20",
"ConnmanDisconnect 1000 0 2000 20",
"ConnmanFailure 1000 0 2000 20",
"ConnmanFailure 13000 2000 20",
"ConnmanAssociation 1000 0 2000 20",
"ConnmanConfiguration 1000 0 2000 20",
"ConnmanOffline 1000 0 2000 20",
"ConnmanOnline 1000 0 2000 20",
"ConnmanOffline 2000 0 2000 20",
"ConnmanReady 33000 0 100000 50",
"ConnmanReady 44000 0 100000 50",
"ConnmanReady 22000 0 100000 50",
};
int nhist = ARRAYSIZE_UNSAFE(histogram_data);
int32 i;
const char* path = "/tmp/.chromeos-metrics";
scoped_refptr<chromeos::ExternalMetrics>
external_metrics(new chromeos::ExternalMetrics());
external_metrics->test_recorder_ = &ReceiveMessage;
external_metrics->test_path_ = base::FilePath(path);
EXPECT_TRUE(unlink(path) == 0 || errno == ENOENT);
// Sends a few valid messages. Once in a while, collects them and checks the
// last message. We don't want to check every single message because we also
// want to test the ability to deal with a file containing more than one
// message.
for (i = 0; i < nhist; i++) {
SendMessage(path, "histogram", histogram_data[i]);
if (i % 3 == 2) {
external_metrics->CollectEvents();
CheckMessage("histogram", histogram_data[i], i + 1);
}
}
// Sends a crash message.
int expect_count = nhist;
SendMessage(path, "crash", "user");
external_metrics->CollectEvents();
CheckMessage("crash", "user", ++expect_count);
// Sends a message that's too large.
char b[MAXLENGTH + 100];
for (i = 0; i < MAXLENGTH + 99; i++) {
b[i] = 'x';
}
b[i] = '\0';
SendMessage(path, b, "yyy");
// Expect logged errors about bad message size.
external_metrics->CollectEvents();
EXPECT_EQ(expect_count, received_count);
// Sends a malformed message (first string is not null-terminated).
i = 100 + sizeof(i);
int fd = open(path, O_CREAT | O_WRONLY, 0666);
EXPECT_GT(fd, 0);
EXPECT_EQ(static_cast<int>(sizeof(i)), write(fd, &i, sizeof(i)));
EXPECT_EQ(i, write(fd, b, i));
EXPECT_EQ(0, close(fd));
external_metrics->CollectEvents();
EXPECT_EQ(expect_count, received_count);
// Sends a malformed message (second string is not null-terminated).
b[50] = '\0';
fd = open(path, O_CREAT | O_WRONLY, 0666);
EXPECT_GT(fd, 0);
EXPECT_EQ(static_cast<int>(sizeof(i)), write(fd, &i, sizeof(i)));
EXPECT_EQ(i, write(fd, b, i));
EXPECT_EQ(0, close(fd));
external_metrics->CollectEvents();
EXPECT_EQ(expect_count, received_count);
// Checks that we survive when file doesn't exist.
EXPECT_EQ(0, unlink(path));
external_metrics->CollectEvents();
EXPECT_EQ(expect_count, received_count);
}
} // namespace chromeos