blob: cac2c52dbf199808bd21ffd4c08e38e9dbb238ed [file] [log] [blame]
// Copyright 2015 The Chromium OS 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 "webservd/log_manager.h"
#include <arpa/inet.h>
#include <netinet/in.h>
#include <set>
#include <vector>
#include <base/files/file_enumerator.h>
#include <base/files/file_util.h>
#include <base/files/scoped_temp_dir.h>
#include <base/strings/stringprintf.h>
#include <gtest/gtest.h>
namespace webservd {
namespace {
struct TestLogger : public LogManager::LoggerInterface {
explicit TestLogger(std::string& last_entry) : last_entry_{last_entry} {}
void Log(const base::Time& timestamp, const std::string& entry) override {
last_entry_ = entry;
}
std::string& last_entry_;
};
} // Anonymous namespace
class LogManagerTest : public testing::Test {
public:
void SetUp() override { ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); }
// Adds a test log entry to the file corresponding to the give |timestamp|.
void LogEntry(const base::Time& timestamp) {
sockaddr_in client_addr = {};
client_addr.sin_family = AF_INET;
client_addr.sin_port = 80;
inet_aton("10.11.12.13", &client_addr.sin_addr);
LogManager::OnRequestCompleted(
timestamp, reinterpret_cast<const sockaddr*>(&client_addr), "POST",
"/test", "HTTP/1.0", 200, 123456);
}
// Get the list of current log files in the test log directory.
std::set<std::string> GetLogFiles() const {
std::set<std::string> log_files;
base::FileEnumerator enumerator{temp_dir.GetPath(), false,
base::FileEnumerator::FILES, "*.log"};
base::FilePath file = enumerator.Next();
while (!file.empty()) {
log_files.insert(file.BaseName().value());
file = enumerator.Next();
}
return log_files;
}
base::ScopedTempDir temp_dir;
};
TEST_F(LogManagerTest, OnRequestCompleted) {
std::string last_entry;
LogManager::SetLogger(
std::unique_ptr<LogManager::LoggerInterface>(new TestLogger{last_entry}));
base::Time timestamp = base::Time::Now();
LogEntry(timestamp);
tm time_buf = {};
char str_buf[32] = {};
time_t time = timestamp.ToTimeT();
strftime(str_buf, sizeof(str_buf), "%d/%b/%Y:%H:%M:%S %z",
localtime_r(&time, &time_buf));
std::string match = base::StringPrintf(
"10.11.12.13 - - [%s] \"POST /test HTTP/1.0\" 200 123456\n", str_buf);
EXPECT_EQ(match, last_entry);
}
TEST_F(LogManagerTest, LogFileManagement) {
LogManager::Init(temp_dir.GetPath());
EXPECT_TRUE(GetLogFiles().empty());
// Feb 25, 2015, 0:00:00 Local time
tm date = {0, 0, 0, 25, 1, 115, 2, 55, 0};
base::Time timestamp = base::Time::FromTimeT(mktime(&date));
for (size_t i = 0; i < 10; i++) {
LogEntry(timestamp);
LogEntry(timestamp);
LogEntry(timestamp);
LogEntry(timestamp);
timestamp += base::TimeDelta::FromDays(1);
}
std::set<std::string> expected_files{
"2015-02-28.log", "2015-03-01.log", "2015-03-02.log", "2015-03-03.log",
"2015-03-04.log", "2015-03-05.log", "2015-03-06.log",
};
EXPECT_EQ(expected_files, GetLogFiles());
}
TEST_F(LogManagerTest, LargeLogs) {
const size_t log_line_len = 78; // Test log entries are 78 chars long.
LogManager::Init(temp_dir.GetPath());
EXPECT_TRUE(GetLogFiles().empty());
// Feb 25, 2015, 0:00:00 Local time
tm date = {0, 0, 0, 25, 1, 115, 2, 55, 0};
base::Time timestamp = base::Time::FromTimeT(mktime(&date));
// Create 2015-02-25.log
LogEntry(timestamp);
timestamp += base::TimeDelta::FromDays(1);
// Write a large 2015-02-26.log but with enough room for one more log line.
std::vector<char> data(1024 * 1024 - (log_line_len * 3 / 2), ' ');
base::FilePath current_file = temp_dir.GetPath().Append("2015-02-26.log");
ASSERT_EQ(static_cast<int>(data.size()),
base::WriteFile(current_file, data.data(), data.size()));
// Add the line. Should still go to the same file.
LogEntry(timestamp);
std::set<std::string> expected_files{
"2015-02-25.log",
"2015-02-26.log",
};
EXPECT_EQ(expected_files, GetLogFiles());
// Now this log entry will not fit and will end up creating a new file.
LogEntry(timestamp);
expected_files = {
"2015-02-25.log",
"2015-02-26-a.log",
"2015-02-26.log",
};
EXPECT_EQ(expected_files, GetLogFiles());
// Add some more data to the current file.
ASSERT_TRUE(base::AppendToFile(current_file, data.data(), data.size()));
LogEntry(timestamp);
expected_files = {
"2015-02-25.log",
"2015-02-26-a.log",
"2015-02-26-b.log",
"2015-02-26.log",
};
}
} // namespace webservd