Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(137)

Unified Diff: log_unit_tests.cc

Issue 6870023: Add "bootstat --output-dir" option. Base URL: ssh://gitrw.chromium.org:9222/bootstat.git@master
Patch Set: Get bootstat.c to where it actually compiles. Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « bootstat_test.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: log_unit_tests.cc
diff --git a/log_unit_tests.cc b/log_unit_tests.cc
index b12718a20fad934aa44b3e99f67d9aad510bf8da..9c5c54f430a88e8ddbb30275d1d2be1f5daa8fcb 100644
--- a/log_unit_tests.cc
+++ b/log_unit_tests.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -6,6 +6,7 @@
#include "bootstat_test.h"
#include <errno.h>
+#include <stdio.h>
#include <stdlib.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
@@ -29,15 +30,14 @@ static void RemoveFile(const string& file_path) {
// Class to track and test the data associated with a single event.
-// The primary function is TestLogEvent(): This method wraps calls
-// to bootstat_log() with code to track the expected contents of the
-// event files. After logging, the expected content is tested
-// against the actual content.
+// The methods TestEventContent() and TestEventCreation() wrap calls
+// to bootstat_log() to test various assertions regarding the
+// function.
class EventTracker {
public:
- EventTracker(const string& name, const string& uptime_prefix,
- const string& disk_prefix);
- void TestLogEvent(const string& uptime, const string& diskstats);
+ EventTracker(const string& name, const string& output_dir);
+ void TestEventContent(const char* uptime, const char* diskstats);
+ void TestEventCreation(bool expect_success);
void Reset();
private:
@@ -50,28 +50,27 @@ class EventTracker {
EventTracker::EventTracker(const string& name,
- const string& uptime_prefix,
- const string& diskstats_prefix)
+ const string& output_dir)
: event_name_(name),
uptime_content_(""),
diskstats_content_("") {
string truncated_name =
event_name_.substr(0, BOOTSTAT_MAX_EVENT_LEN - 1);
- uptime_file_name_ = uptime_prefix + truncated_name;
- diskstats_file_name_ = diskstats_prefix + truncated_name;
+ uptime_file_name_ = output_dir + "/uptime-" + truncated_name;
+ diskstats_file_name_ = output_dir + "/disk-" + truncated_name;
}
// Basic helper function to test whether the contents of the
// specified file exactly match the given contents string.
-static void ValidateEventFileContents(const string& file_name,
- const string& file_contents) {
+static void ValidateEventFileContent(const string& file_name,
+ const string& file_contents) {
int rv = access(file_name.c_str(), W_OK);
EXPECT_EQ(0, rv) << file_name << " is not writable: "
- << strerror(errno);
+ << strerror(errno) << ".";
rv = access(file_name.c_str(), R_OK);
ASSERT_EQ(0, rv) << file_name << " is not readable: "
- << strerror(errno);
+ << strerror(errno) << ".";
char *buffer = new char[file_contents.length() + 1];
int fd = open(file_name.c_str(), O_RDONLY);
rv = read(fd, buffer, file_contents.length());
@@ -89,18 +88,47 @@ static void ValidateEventFileContents(const string& file_name,
// Call bootstat_log() once, and update the expected content for
// this event. Test that the new content of the event's files
// matches the updated expected content.
-void EventTracker::TestLogEvent(const string& uptime,
- const string& diskstats) {
+void EventTracker::TestEventContent(const char* uptime,
+ const char* diskstats) {
bootstat_log(event_name_.c_str());
- uptime_content_ += uptime;
- diskstats_content_ += diskstats;
- ValidateEventFileContents(uptime_file_name_, uptime_content_);
- ValidateEventFileContents(diskstats_file_name_, diskstats_content_);
+ uptime_content_ += string(uptime);
+ diskstats_content_ += string(diskstats);
+ ValidateEventFileContent(uptime_file_name_, uptime_content_);
+ ValidateEventFileContent(diskstats_file_name_, diskstats_content_);
}
-// Reset event state back to initial conditions, by deleting the
-// associated event files, and clearing the expected contents.
+// Basic helper function to test whether the contents of the
+// specified file exactly match the given contents string.
+// A return value of true indicates that the file contents can
+// be read.
+static void ValidateEventFileExistence(const string& file_name,
+ bool expect_success) {
+ int rv = access(file_name.c_str(), F_OK);
+ if (expect_success) {
+ EXPECT_EQ(0, rv) << "Cannot verify existence of " << file_name
+ << ": " << strerror(errno) << ".";
+ } else {
+ EXPECT_LT(rv, 0) << file_name << " exists, but it shouldn't.";
+ }
+
+ if (rv >= 0) {
+ RemoveFile(file_name);
+ }
+}
+
+
+// Call bootstat_log() once, and confirm creation of the event
+// files. The content of the files isn't checked.
+void EventTracker::TestEventCreation(bool expect_success) {
+ bootstat_log(event_name_.c_str());
+ ValidateEventFileExistence(uptime_file_name_, expect_success);
+ ValidateEventFileExistence(diskstats_file_name_, expect_success);
+}
+
+
+// Reset event state back to initial conditions by deleting the
+// associated event files and clearing the expected contents.
void EventTracker::Reset() {
uptime_content_.clear();
diskstats_content_.clear();
@@ -122,59 +150,60 @@ class BootstatTest : public ::testing::Test {
virtual void SetUp();
virtual void TearDown();
+ EventTracker MakeEvent(const string& event_name,
+ const string& output_dir_name) {
+ return EventTracker(event_name, output_dir_name);
+ }
EventTracker MakeEvent(const string& event_name) {
- return EventTracker(event_name, uptime_event_prefix_,
- disk_event_prefix_);
+ return EventTracker(event_name, stats_output_dir_);
}
void SetStatsContent(const char* uptime_content,
const char* disk_content);
- void TestLogEvent(EventTracker& event);
+ void ClearStatsContent();
+ void TestSetOutputDirectory(const string& testdir,
+ const string& testevent,
+ bool expect_success,
+ int expected_errno);
+ void TestSetOutputDirectoryAccess(const string& testdir, mode_t testmode);
+ void TestLogAccess(const string& testdir, mode_t testmode);
private:
string stats_output_dir_;
- string uptime_event_prefix_;
- string disk_event_prefix_;
string uptime_stats_file_name_;
- string uptime_stats_content_;
string disk_stats_file_name_;
- string disk_stats_content_;
};
void BootstatTest::SetUp() {
char dir_template[] = "bootstat_test_XXXXXX";
stats_output_dir_ = string(mkdtemp(dir_template));
- uptime_event_prefix_ = stats_output_dir_ + "/uptime-";
- disk_event_prefix_ = stats_output_dir_ + "/disk-";
uptime_stats_file_name_ = stats_output_dir_ + "/proc_uptime";
disk_stats_file_name_ = stats_output_dir_ + "/block_stats";
- bootstat_set_output_directory(stats_output_dir_.c_str());
- bootstat_set_uptime_file_name(uptime_stats_file_name_.c_str());
- bootstat_set_disk_file_name(disk_stats_file_name_.c_str());
+ EXPECT_EQ(0, bootstat_set_output_directory(stats_output_dir_.c_str()))
+ << "Failed to select output directory " << stats_output_dir_
+ << ": " << strerror(errno) << ".";
}
void BootstatTest::TearDown() {
- bootstat_set_uptime_file_name(NULL);
- bootstat_set_disk_file_name(NULL);
- bootstat_set_output_directory(NULL);
- RemoveFile(uptime_stats_file_name_);
- RemoveFile(disk_stats_file_name_);
+ EXPECT_EQ(0, bootstat_set_output_directory(NULL))
+ << "Failed to set output directory back to default: "
+ << strerror(errno) << ".";
EXPECT_EQ(0, rmdir(stats_output_dir_.c_str()))
<< "Can't remove directory " << stats_output_dir_
<< ": " << strerror(errno) << ".";
}
-static void WriteStatsContent(const string& content, const string& file_path) {
+static void WriteStatsContent(const char *content, const string& file_path) {
const int kFileOpenFlags = O_WRONLY | O_TRUNC | O_CREAT;
const mode_t kFileCreationMode =
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
int fd = open(file_path.c_str(), kFileOpenFlags, kFileCreationMode);
- int nwrite = write(fd, content.c_str(), content.length());
- EXPECT_EQ(content.length(), nwrite)
+ int nwrite = write(fd, content, strlen(content));
+ EXPECT_EQ(strlen(content), nwrite)
<< "write to stats file " << file_path
<< " failed: " << strerror(errno);
(void)close(fd);
@@ -187,15 +216,18 @@ static void WriteStatsContent(const string& content, const string& file_path) {
// events.
void BootstatTest::SetStatsContent(const char* uptime_stats,
const char* disk_stats) {
- uptime_stats_content_ = string(uptime_stats);
- WriteStatsContent(uptime_stats_content_, uptime_stats_file_name_);
- disk_stats_content_ = string(disk_stats);
- WriteStatsContent(disk_stats_content_, disk_stats_file_name_);
+ WriteStatsContent(uptime_stats, uptime_stats_file_name_);
+ WriteStatsContent(disk_stats, disk_stats_file_name_);
+ bootstat_set_uptime_file_name(uptime_stats_file_name_.c_str());
+ bootstat_set_disk_file_name(disk_stats_file_name_.c_str());
}
-void BootstatTest::TestLogEvent(EventTracker& event) {
- event.TestLogEvent(uptime_stats_content_, disk_stats_content_);
+void BootstatTest::ClearStatsContent() {
+ bootstat_set_uptime_file_name(NULL);
+ bootstat_set_disk_file_name(NULL);
+ RemoveFile(uptime_stats_file_name_);
+ RemoveFile(disk_stats_file_name_);
}
@@ -221,21 +253,23 @@ static const char* bootstat_data[] = {
};
-// Tests that event file content matches expectations when an
-// event is logged multiple times.
+// This is to test that event file content matches expectations when
+// an event is logged multiple times.
TEST_F(BootstatTest, ContentGeneration) {
EventTracker ev = MakeEvent(string("test_event"));
int i = 0;
while (bootstat_data[i] != NULL) {
SetStatsContent(bootstat_data[i], bootstat_data[i+1]);
- TestLogEvent(ev);
+ ev.TestEventContent(bootstat_data[i], bootstat_data[i+1]);
i += 2;
}
+ ClearStatsContent();
ev.Reset();
}
-// Tests that name truncation of logged events works as advertised.
+// This is to test that name truncation of logged events works as
+// advertised.
TEST_F(BootstatTest, EventNameTruncation) {
static const char kMostVoluminousEventName[] =
// 16 32 48 64
@@ -249,19 +283,163 @@ TEST_F(BootstatTest, EventNameTruncation) {
SetStatsContent(bootstat_data[0], bootstat_data[1]);
EventTracker ev = MakeEvent(very_long);
- TestLogEvent(ev);
+ ev.TestEventContent(bootstat_data[0], bootstat_data[1]);
ev.Reset();
ev = MakeEvent(very_long.substr(0, 1));
- TestLogEvent(ev);
+ ev.TestEventContent(bootstat_data[0], bootstat_data[1]);
ev.Reset();
ev = MakeEvent(very_long.substr(0, BOOTSTAT_MAX_EVENT_LEN - 1));
- TestLogEvent(ev);
+ ev.TestEventContent(bootstat_data[0], bootstat_data[1]);
ev.Reset();
ev = MakeEvent(very_long.substr(0, BOOTSTAT_MAX_EVENT_LEN));
- TestLogEvent(ev);
+ ev.TestEventContent(bootstat_data[0], bootstat_data[1]);
ev.Reset();
+
+ ClearStatsContent();
+}
+
+
+// Test a call to bootstat_set_output_directory(). Check that the
+// operation succeeds or fails as indicated by the input parameters.
+// Also tests that bootstat_log() logs in the expected place after
+// the call: after success, logging should go to the new directory;
+// after a failure, logging should continue to go to the previous
+// directory.
+void BootstatTest::TestSetOutputDirectory(const string& testdir,
+ const string& testevent,
+ bool expect_success,
+ int expected_errno) {
+ ASSERT_EQ(0, bootstat_set_output_directory(stats_output_dir_.c_str()))
+ << "bootstat_set_output_directory() failed for " << stats_output_dir_
+ << ": " << strerror(errno) << ".";
+ bool set_output_success =
+ (bootstat_set_output_directory(testdir.c_str()) == 0);
+
+ if (expect_success) {
+ ASSERT_TRUE(set_output_success)
+ << "bootstat_set_output_directory() failed unexpectedly for "
+ << testdir << ": " << strerror(errno) << ".";
+ } else {
+ ASSERT_FALSE(set_output_success)
+ << "bootstat_set_output_directory() succeeded for "
+ << testdir << "; expected error: " << strerror(expected_errno) << ".";
+ EXPECT_EQ(expected_errno, errno);
+ }
+
+ string eventdir;
+ if (set_output_success) {
+ eventdir = testdir;
+ } else {
+ eventdir = stats_output_dir_;
+ }
+ string eventname = string("test-set-directory-") + testevent;
+ EventTracker ev = MakeEvent(eventname, eventdir);
+ ev.TestEventCreation(true);
+ ASSERT_EQ(0, bootstat_set_output_directory(NULL))
+ << "bootstat_set_output_directory(NULL) failed: "
+ << strerror(errno) << ".";
+}
+
+
+// Test that bootstat_set_output_directory() will return ENOENT
+// when required.
+TEST_F(BootstatTest, SetOutputDirectoryEnoent) {
+ TestSetOutputDirectory(string("/this-directory-does-not-exist"),
+ string("ENOENT"), false, ENOENT);
}
+
+// Test that bootstat_set_output_directory() will return ENOTDIR
+// when required.
+TEST_F(BootstatTest, SetOutputDirectoryEnotdir) {
+ string ordinary_file_name = string("ordinary-file");
+ const mode_t kFileCreationMode =
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+ int fd = creat(ordinary_file_name.c_str(), kFileCreationMode);
+ EXPECT_GE(fd, 0)
+ << "failed to create test file " << ordinary_file_name
+ << ": " << strerror(errno) << ".";
+ if (fd >= 0) {
+ TestSetOutputDirectory(ordinary_file_name, string("ENOTDIR"),
+ false, ENOTDIR);
+ (void) close(fd);
+ RemoveFile(ordinary_file_name);
+ }
+}
+
+
+// Test that bootstat_set_output_directory() succeeds or fails with
+// EACCES as expected.
+void BootstatTest::TestSetOutputDirectoryAccess(const string& testdir,
+ mode_t testmode) {
+ char buffer[8];
+ sprintf(buffer, "0%03o", testmode);
+ string modestring = string(buffer);
+ bool expect_success =
+ ((testmode & (S_IWUSR | S_IXUSR)) == (S_IWUSR | S_IXUSR));
+
+ ASSERT_EQ(0, chmod(testdir.c_str(), testmode))
+ << "Unable to change directory mode for " << testdir
+ << " to " << modestring << ": " << strerror(errno) << ".";
+ string eventname = string("EACCES-") + modestring;
+ TestSetOutputDirectory(testdir, eventname, expect_success, EACCES);
+}
+
+
+// Test that the actual access mode requirements enforced by
+// bootstat_log() match the requirements enforced by
+// bootstat_set_output_directory().
+void BootstatTest::TestLogAccess(const string& testdir,
+ mode_t testmode) {
+ char buffer[8];
+ sprintf(buffer, "0%03o", testmode);
+ string modestring = string(buffer);
+ bool expect_success =
+ ((testmode & (S_IWUSR | S_IXUSR)) == (S_IWUSR | S_IXUSR));
+
+ ASSERT_EQ(0, chmod(testdir.c_str(), S_IRUSR | S_IWUSR | S_IXUSR))
+ << "Unable to change directory mode for " << testdir
+ << " to 0700: " << strerror(errno) << ".";
+ ASSERT_EQ(0, bootstat_set_output_directory(testdir.c_str()))
+ << "bootstat_set_output_directory() failed for " << testdir
+ << ": " << strerror(errno) << ".";
+ ASSERT_EQ(0, chmod(testdir.c_str(), testmode))
+ << "Unable to change directory mode for " << testdir
+ << " to " << modestring << ": " << strerror(errno) << ".";
+
+ string event_name = string("test-log-access-") + modestring;
+ EventTracker ev = MakeEvent(event_name, testdir);
+ ev.TestEventCreation(expect_success);
+
+ ASSERT_EQ(0, bootstat_set_output_directory(NULL))
+ << "bootstat_set_output_directory(NULL) failed: "
+ << strerror(errno) << ".";
+}
+
+
+// Test that bootstat_set_output_directory() will return EACCES
+// as expected for all directory modes. The test here is
+// two-pronged. First, the test confirms that EACCES is
+// returned exactly when the caller has both W and X access.
+// Second, the test confirms that bootstat_log() fails when
+// EACCES is returned, but not when it isn't.
+TEST_F(BootstatTest, SetOutputDirectoryEacces) {
+ char dir_template[] = "bootstat_access_test_XXXXXX";
+ string testdir = string(mkdtemp(dir_template));
+ mode_t lobit = ((S_IRUSR - 1) & (S_IWUSR - 1) & (S_IXUSR - 1)) + 1;
+ mode_t allbits = (S_IRUSR | S_IWUSR | S_IXUSR);
+ mode_t dirmode = allbits + lobit;
+ while (dirmode > 0) {
+ dirmode -= lobit;
+ TestSetOutputDirectoryAccess(testdir, dirmode);
+ TestLogAccess(testdir, dirmode);
+ }
+ EXPECT_EQ(0, rmdir(testdir.c_str()))
+ << "Can't remove directory " << testdir
+ << ": " << strerror(errno) << ".";
+}
+
+
} // namespace
int main(int argc, char** argv) {
« no previous file with comments | « bootstat_test.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698