OLD | NEW |
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "bootstat.h" | 5 #include "bootstat.h" |
| 6 #include "bootstat_test.h" |
6 | 7 |
7 #include <errno.h> | 8 #include <errno.h> |
| 9 #include <stdlib.h> |
| 10 #include <sys/fcntl.h> |
| 11 #include <sys/stat.h> |
| 12 #include <sys/types.h> |
8 #include <unistd.h> | 13 #include <unistd.h> |
9 | 14 |
10 #include <string> | 15 #include <string> |
11 #include <iostream> | 16 #include <iostream> |
12 | 17 |
13 #include <gtest/gtest.h> | 18 #include <gtest/gtest.h> |
14 | 19 |
15 namespace { | 20 namespace { |
16 | 21 |
17 using std::string; | 22 using std::string; |
18 | 23 |
19 static const char kMostVoluminousEventName[] = | 24 static void RemoveFile(const string& file_path) { |
20 // 16 32 48 64 | 25 EXPECT_EQ(0, unlink(file_path.c_str())) |
21 "event-6789abcdef_123456789ABCDEF.123456789abcdef0123456789abcdef" // 64 | 26 << "can't unlink file " << file_path << ": " |
22 "event-6789abcdef_123456789ABCDEF.123456789abcdef0123456789abcdef" // 128 | 27 << strerror(errno); |
23 "event-6789abcdef_123456789ABCDEF.123456789abcdef0123456789abcdef" // 191 | 28 } |
24 "event-6789abcdef_123456789ABCDEF.123456789abcdef0123456789abcdef" // 256 | 29 |
25 ; | 30 |
26 | 31 // Class to track and test the data associated with a single event. |
27 static const string kUptimeFileNamePrefix("/tmp/uptime-"); | 32 // The primary function is TestLogEvent(): This method wraps calls |
28 static const string kDiskStatFileNamePrefix("/tmp/disk-"); | 33 // to bootstat_log() with code to track the expected contents of the |
29 | 34 // event files. After logging, the expected content is tested |
30 static void TestEventFileAccess(const string& file_name) { | 35 // against the actual content. |
31 int rv = access(file_name.c_str(), R_OK | W_OK); | 36 class EventTracker { |
32 EXPECT_EQ(rv, 0) << "access to " << file_name | 37 public: |
33 << " failed: " << strerror(errno); | 38 EventTracker(const string& name, const string& uptime_prefix, |
34 (void) unlink(file_name.c_str()); | 39 const string& disk_prefix); |
35 } | 40 void TestLogEvent(const string& uptime, const string& diskstats); |
36 | 41 void Reset(); |
37 static void TestEventByName(const string& event_name) { | 42 |
38 bootstat_log(event_name.c_str()); | 43 private: |
39 string truncated_event(event_name.substr(0, BOOTSTAT_MAX_EVENT_LEN - 1)); | 44 string event_name_; |
40 TestEventFileAccess(kUptimeFileNamePrefix + truncated_event); | 45 string uptime_file_name_; |
41 TestEventFileAccess(kDiskStatFileNamePrefix + truncated_event); | 46 string uptime_content_; |
42 } | 47 string diskstats_file_name_; |
43 | 48 string diskstats_content_; |
44 // Tests that name truncation of logged events works as advertised | 49 }; |
45 TEST(BoostatTest, EventNameTruncation) { | 50 |
| 51 |
| 52 EventTracker::EventTracker(const string& name, |
| 53 const string& uptime_prefix, |
| 54 const string& diskstats_prefix) |
| 55 : event_name_(name), |
| 56 uptime_content_(""), |
| 57 diskstats_content_("") { |
| 58 string truncated_name = |
| 59 event_name_.substr(0, BOOTSTAT_MAX_EVENT_LEN - 1); |
| 60 uptime_file_name_ = uptime_prefix + truncated_name; |
| 61 diskstats_file_name_ = diskstats_prefix + truncated_name; |
| 62 } |
| 63 |
| 64 |
| 65 // Basic helper function to test whether the contents of the |
| 66 // specified file exactly match the given contents string. |
| 67 static void ValidateEventFileContents(const string& file_name, |
| 68 const string& file_contents) { |
| 69 int rv = access(file_name.c_str(), W_OK); |
| 70 EXPECT_EQ(0, rv) << file_name << " is not writable: " |
| 71 << strerror(errno); |
| 72 rv = access(file_name.c_str(), R_OK); |
| 73 ASSERT_EQ(0, rv) << file_name << " is not readable: " |
| 74 << strerror(errno); |
| 75 char *buffer = new char[file_contents.length() + 1]; |
| 76 int fd = open(file_name.c_str(), O_RDONLY); |
| 77 rv = read(fd, buffer, file_contents.length()); |
| 78 EXPECT_EQ(file_contents.length(), rv); |
| 79 buffer[file_contents.length()] = '\0'; |
| 80 string actual_contents(buffer); |
| 81 EXPECT_EQ(file_contents, actual_contents); |
| 82 rv = read(fd, buffer, 1); |
| 83 EXPECT_EQ(0, rv) << "found data in event file past expected EOF"; |
| 84 (void)close(fd); |
| 85 delete buffer; |
| 86 } |
| 87 |
| 88 |
| 89 // Call bootstat_log() once, and update the expected content for |
| 90 // this event. Test that the new content of the event's files |
| 91 // matches the updated expected content. |
| 92 void EventTracker::TestLogEvent(const string& uptime, |
| 93 const string& diskstats) { |
| 94 bootstat_log(event_name_.c_str()); |
| 95 uptime_content_ += uptime; |
| 96 diskstats_content_ += diskstats; |
| 97 ValidateEventFileContents(uptime_file_name_, uptime_content_); |
| 98 ValidateEventFileContents(diskstats_file_name_, diskstats_content_); |
| 99 } |
| 100 |
| 101 |
| 102 // Reset event state back to initial conditions, by deleting the |
| 103 // associated event files, and clearing the expected contents. |
| 104 void EventTracker::Reset() { |
| 105 uptime_content_.clear(); |
| 106 diskstats_content_.clear(); |
| 107 RemoveFile(diskstats_file_name_); |
| 108 RemoveFile(uptime_file_name_); |
| 109 } |
| 110 |
| 111 |
| 112 // Bootstat test class. We use this class to override the |
| 113 // dependencies in bootstat_log() on the file paths for /proc/uptime |
| 114 // and /sys/block/<device>/stat. |
| 115 // |
| 116 // The class uses test-specific interfaces that change the default |
| 117 // paths from the kernel statistics psuedo-files to temporary paths |
| 118 // selected by this test. This class also redirects the location for |
| 119 // the event files created by bootstat_log() to a temporary directory. |
| 120 class BootstatTest : public ::testing::Test { |
| 121 protected: |
| 122 virtual void SetUp(); |
| 123 virtual void TearDown(); |
| 124 |
| 125 EventTracker MakeEvent(const string& event_name) { |
| 126 return EventTracker(event_name, uptime_event_prefix_, |
| 127 disk_event_prefix_); |
| 128 } |
| 129 |
| 130 void SetStatsContent(const char* uptime_content, |
| 131 const char* disk_content); |
| 132 void TestLogEvent(EventTracker& event); |
| 133 |
| 134 private: |
| 135 string stats_output_dir_; |
| 136 string uptime_event_prefix_; |
| 137 string disk_event_prefix_; |
| 138 |
| 139 string uptime_stats_file_name_; |
| 140 string uptime_stats_content_; |
| 141 string disk_stats_file_name_; |
| 142 string disk_stats_content_; |
| 143 }; |
| 144 |
| 145 |
| 146 void BootstatTest::SetUp() { |
| 147 char dir_template[] = "bootstat_test_XXXXXX"; |
| 148 stats_output_dir_ = string(mkdtemp(dir_template)); |
| 149 uptime_event_prefix_ = stats_output_dir_ + "/uptime-"; |
| 150 disk_event_prefix_ = stats_output_dir_ + "/disk-"; |
| 151 uptime_stats_file_name_ = stats_output_dir_ + "/proc_uptime"; |
| 152 disk_stats_file_name_ = stats_output_dir_ + "/block_stats"; |
| 153 bootstat_set_output_directory(stats_output_dir_.c_str()); |
| 154 bootstat_set_uptime_file_name(uptime_stats_file_name_.c_str()); |
| 155 bootstat_set_disk_file_name(disk_stats_file_name_.c_str()); |
| 156 } |
| 157 |
| 158 |
| 159 void BootstatTest::TearDown() { |
| 160 bootstat_set_uptime_file_name(NULL); |
| 161 bootstat_set_disk_file_name(NULL); |
| 162 bootstat_set_output_directory(NULL); |
| 163 RemoveFile(uptime_stats_file_name_); |
| 164 RemoveFile(disk_stats_file_name_); |
| 165 EXPECT_EQ(0, rmdir(stats_output_dir_.c_str())) |
| 166 << "Can't remove directory " << stats_output_dir_ |
| 167 << ": " << strerror(errno) << "."; |
| 168 } |
| 169 |
| 170 |
| 171 static void WriteStatsContent(const string& content, const string& file_path) { |
| 172 const int kFileOpenFlags = O_WRONLY | O_TRUNC | O_CREAT; |
| 173 const mode_t kFileCreationMode = |
| 174 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; |
| 175 int fd = open(file_path.c_str(), kFileOpenFlags, kFileCreationMode); |
| 176 int nwrite = write(fd, content.c_str(), content.length()); |
| 177 EXPECT_EQ(content.length(), nwrite) |
| 178 << "write to stats file " << file_path |
| 179 << " failed: " << strerror(errno); |
| 180 (void)close(fd); |
| 181 } |
| 182 |
| 183 |
| 184 // Set the content of the files mocking the contents of the kernel's |
| 185 // statistics pseudo-files. The strings provided here will be the |
| 186 // ones recorded for subsequent calls to bootstat_log() for all |
| 187 // events. |
| 188 void BootstatTest::SetStatsContent(const char* uptime_stats, |
| 189 const char* disk_stats) { |
| 190 uptime_stats_content_ = string(uptime_stats); |
| 191 WriteStatsContent(uptime_stats_content_, uptime_stats_file_name_); |
| 192 disk_stats_content_ = string(disk_stats); |
| 193 WriteStatsContent(disk_stats_content_, disk_stats_file_name_); |
| 194 } |
| 195 |
| 196 |
| 197 void BootstatTest::TestLogEvent(EventTracker& event) { |
| 198 event.TestLogEvent(uptime_stats_content_, disk_stats_content_); |
| 199 } |
| 200 |
| 201 |
| 202 // Test data to be used as input to SetStatsContent(). |
| 203 // |
| 204 // The structure of this array is pairs of strings, terminated by a |
| 205 // single NULL. The first string in the pair is content for |
| 206 // /proc/uptime, the second for /sys/block/<device>/stat. |
| 207 // |
| 208 // This data is taken directly from a development system, and is |
| 209 // representative of valid stats content, though not typical of what |
| 210 // would be seen immediately after boot. |
| 211 static const char* bootstat_data[] = { |
| 212 /* 0 */ |
| 213 /* uptime */ "691448.42 11020440.26\n", |
| 214 /* disk */ " 1417116 14896 55561564 10935990 4267850 78379879" |
| 215 " 661568738 1635920520 158 17856450 1649520570\n", |
| 216 /* 1 */ |
| 217 /* uptime */ "691623.71 11021372.99\n", |
| 218 /* disk */ " 1420714 14918 55689988 11006390 4287385 78594261" |
| 219 " 663441564 1651579200 152 17974280 1665255160\n", |
| 220 /* EOT */ NULL |
| 221 }; |
| 222 |
| 223 |
| 224 // Tests that event file content matches expectations when an |
| 225 // event is logged multiple times. |
| 226 TEST_F(BootstatTest, ContentGeneration) { |
| 227 EventTracker ev = MakeEvent(string("test_event")); |
| 228 int i = 0; |
| 229 while (bootstat_data[i] != NULL) { |
| 230 SetStatsContent(bootstat_data[i], bootstat_data[i+1]); |
| 231 TestLogEvent(ev); |
| 232 i += 2; |
| 233 } |
| 234 ev.Reset(); |
| 235 } |
| 236 |
| 237 |
| 238 // Tests that name truncation of logged events works as advertised. |
| 239 TEST_F(BootstatTest, EventNameTruncation) { |
| 240 static const char kMostVoluminousEventName[] = |
| 241 // 16 32 48 64 |
| 242 "event-6789abcdef_123456789ABCDEF.123456789abcdef0123456789abcdef" // 64 |
| 243 "=064+56789abcdef_123456789ABCDEF.123456789abcdef0123456789abcdef" // 128 |
| 244 "=128+56789abcdef_123456789ABCDEF.123456789abcdef0123456789abcdef" // 191 |
| 245 "=191+56789abcdef_123456789ABCDEF.123456789abcdef0123456789abcdef" // 256 |
| 246 ; |
| 247 |
46 string very_long(kMostVoluminousEventName); | 248 string very_long(kMostVoluminousEventName); |
47 | 249 SetStatsContent(bootstat_data[0], bootstat_data[1]); |
48 TestEventByName(very_long); | 250 |
49 TestEventByName(very_long.substr(0, 1)); | 251 EventTracker ev = MakeEvent(very_long); |
50 TestEventByName(very_long.substr(0, 16)); | 252 TestLogEvent(ev); |
51 TestEventByName(very_long.substr(0, BOOTSTAT_MAX_EVENT_LEN - 1)); | 253 ev.Reset(); |
52 TestEventByName(very_long.substr(0, BOOTSTAT_MAX_EVENT_LEN)); | 254 ev = MakeEvent(very_long.substr(0, 1)); |
| 255 TestLogEvent(ev); |
| 256 ev.Reset(); |
| 257 ev = MakeEvent(very_long.substr(0, BOOTSTAT_MAX_EVENT_LEN - 1)); |
| 258 TestLogEvent(ev); |
| 259 ev.Reset(); |
| 260 ev = MakeEvent(very_long.substr(0, BOOTSTAT_MAX_EVENT_LEN)); |
| 261 TestLogEvent(ev); |
| 262 ev.Reset(); |
53 } | 263 } |
54 | 264 |
55 } // namespace | 265 } // namespace |
56 | 266 |
57 int main(int argc, char** argv) { | 267 int main(int argc, char** argv) { |
58 testing::InitGoogleTest(&argc, argv); | 268 testing::InitGoogleTest(&argc, argv); |
59 return RUN_ALL_TESTS(); | 269 return RUN_ALL_TESTS(); |
60 } | 270 } |
OLD | NEW |