OLD | NEW |
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 // Copyright (c) 2011 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 #include "bootstat_test.h" |
7 | 7 |
8 #include <errno.h> | 8 #include <errno.h> |
| 9 #include <stdio.h> |
9 #include <stdlib.h> | 10 #include <stdlib.h> |
10 #include <sys/fcntl.h> | 11 #include <sys/fcntl.h> |
11 #include <sys/stat.h> | 12 #include <sys/stat.h> |
12 #include <sys/types.h> | 13 #include <sys/types.h> |
13 #include <unistd.h> | 14 #include <unistd.h> |
14 | 15 |
15 #include <string> | 16 #include <string> |
16 #include <iostream> | 17 #include <iostream> |
17 | 18 |
18 #include <gtest/gtest.h> | 19 #include <gtest/gtest.h> |
19 | 20 |
20 namespace { | 21 namespace { |
21 | 22 |
22 using std::string; | 23 using std::string; |
23 | 24 |
24 static void RemoveFile(const string& file_path) { | 25 static void RemoveFile(const string& file_path) { |
25 EXPECT_EQ(0, unlink(file_path.c_str())) | 26 EXPECT_EQ(0, unlink(file_path.c_str())) |
26 << "can't unlink file " << file_path << ": " | 27 << "can't unlink file " << file_path << ": " |
27 << strerror(errno); | 28 << strerror(errno); |
28 } | 29 } |
29 | 30 |
30 | 31 |
31 // Class to track and test the data associated with a single event. | 32 // Class to track and test the data associated with a single event. |
32 // The primary function is TestLogEvent(): This method wraps calls | 33 // The methods TestEventContent() and TestEventCreation() wrap calls |
33 // to bootstat_log() with code to track the expected contents of the | 34 // to bootstat_log() to test various assertions regarding the |
34 // event files. After logging, the expected content is tested | 35 // function. |
35 // against the actual content. | |
36 class EventTracker { | 36 class EventTracker { |
37 public: | 37 public: |
38 EventTracker(const string& name, const string& uptime_prefix, | 38 EventTracker(const string& name, const string& output_dir); |
39 const string& disk_prefix); | 39 void TestEventContent(const char* uptime, const char* diskstats); |
40 void TestLogEvent(const string& uptime, const string& diskstats); | 40 void TestEventCreation(bool expect_success); |
41 void Reset(); | 41 void Reset(); |
42 | 42 |
43 private: | 43 private: |
44 string event_name_; | 44 string event_name_; |
45 string uptime_file_name_; | 45 string uptime_file_name_; |
46 string uptime_content_; | 46 string uptime_content_; |
47 string diskstats_file_name_; | 47 string diskstats_file_name_; |
48 string diskstats_content_; | 48 string diskstats_content_; |
49 }; | 49 }; |
50 | 50 |
51 | 51 |
52 EventTracker::EventTracker(const string& name, | 52 EventTracker::EventTracker(const string& name, |
53 const string& uptime_prefix, | 53 const string& output_dir) |
54 const string& diskstats_prefix) | |
55 : event_name_(name), | 54 : event_name_(name), |
56 uptime_content_(""), | 55 uptime_content_(""), |
57 diskstats_content_("") { | 56 diskstats_content_("") { |
58 string truncated_name = | 57 string truncated_name = |
59 event_name_.substr(0, BOOTSTAT_MAX_EVENT_LEN - 1); | 58 event_name_.substr(0, BOOTSTAT_MAX_EVENT_LEN - 1); |
60 uptime_file_name_ = uptime_prefix + truncated_name; | 59 uptime_file_name_ = output_dir + "/uptime-" + truncated_name; |
61 diskstats_file_name_ = diskstats_prefix + truncated_name; | 60 diskstats_file_name_ = output_dir + "/disk-" + truncated_name; |
62 } | 61 } |
63 | 62 |
64 | 63 |
65 // Basic helper function to test whether the contents of the | 64 // Basic helper function to test whether the contents of the |
66 // specified file exactly match the given contents string. | 65 // specified file exactly match the given contents string. |
67 static void ValidateEventFileContents(const string& file_name, | 66 static void ValidateEventFileContent(const string& file_name, |
68 const string& file_contents) { | 67 const string& file_contents) { |
69 int rv = access(file_name.c_str(), W_OK); | 68 int rv = access(file_name.c_str(), W_OK); |
70 EXPECT_EQ(0, rv) << file_name << " is not writable: " | 69 EXPECT_EQ(0, rv) << file_name << " is not writable: " |
71 << strerror(errno); | 70 << strerror(errno) << "."; |
72 rv = access(file_name.c_str(), R_OK); | 71 rv = access(file_name.c_str(), R_OK); |
73 ASSERT_EQ(0, rv) << file_name << " is not readable: " | 72 ASSERT_EQ(0, rv) << file_name << " is not readable: " |
74 << strerror(errno); | 73 << strerror(errno) << "."; |
75 char *buffer = new char[file_contents.length() + 1]; | 74 char *buffer = new char[file_contents.length() + 1]; |
76 int fd = open(file_name.c_str(), O_RDONLY); | 75 int fd = open(file_name.c_str(), O_RDONLY); |
77 rv = read(fd, buffer, file_contents.length()); | 76 rv = read(fd, buffer, file_contents.length()); |
78 EXPECT_EQ(file_contents.length(), rv); | 77 EXPECT_EQ(file_contents.length(), rv); |
79 buffer[file_contents.length()] = '\0'; | 78 buffer[file_contents.length()] = '\0'; |
80 string actual_contents(buffer); | 79 string actual_contents(buffer); |
81 EXPECT_EQ(file_contents, actual_contents); | 80 EXPECT_EQ(file_contents, actual_contents); |
82 rv = read(fd, buffer, 1); | 81 rv = read(fd, buffer, 1); |
83 EXPECT_EQ(0, rv) << "found data in event file past expected EOF"; | 82 EXPECT_EQ(0, rv) << "found data in event file past expected EOF"; |
84 (void)close(fd); | 83 (void)close(fd); |
85 delete buffer; | 84 delete buffer; |
86 } | 85 } |
87 | 86 |
88 | 87 |
89 // Call bootstat_log() once, and update the expected content for | 88 // Call bootstat_log() once, and update the expected content for |
90 // this event. Test that the new content of the event's files | 89 // this event. Test that the new content of the event's files |
91 // matches the updated expected content. | 90 // matches the updated expected content. |
92 void EventTracker::TestLogEvent(const string& uptime, | 91 void EventTracker::TestEventContent(const char* uptime, |
93 const string& diskstats) { | 92 const char* diskstats) { |
94 bootstat_log(event_name_.c_str()); | 93 bootstat_log(event_name_.c_str()); |
95 uptime_content_ += uptime; | 94 uptime_content_ += string(uptime); |
96 diskstats_content_ += diskstats; | 95 diskstats_content_ += string(diskstats); |
97 ValidateEventFileContents(uptime_file_name_, uptime_content_); | 96 ValidateEventFileContent(uptime_file_name_, uptime_content_); |
98 ValidateEventFileContents(diskstats_file_name_, diskstats_content_); | 97 ValidateEventFileContent(diskstats_file_name_, diskstats_content_); |
99 } | 98 } |
100 | 99 |
101 | 100 |
102 // Reset event state back to initial conditions, by deleting the | 101 // Basic helper function to test whether the contents of the |
103 // associated event files, and clearing the expected contents. | 102 // specified file exactly match the given contents string. |
| 103 // A return value of true indicates that the file contents can |
| 104 // be read. |
| 105 static void ValidateEventFileExistence(const string& file_name, |
| 106 bool expect_success) { |
| 107 int rv = access(file_name.c_str(), F_OK); |
| 108 if (expect_success) { |
| 109 EXPECT_EQ(0, rv) << "Cannot verify existence of " << file_name |
| 110 << ": " << strerror(errno) << "."; |
| 111 } else { |
| 112 EXPECT_LT(rv, 0) << file_name << " exists, but it shouldn't."; |
| 113 } |
| 114 |
| 115 if (rv >= 0) { |
| 116 RemoveFile(file_name); |
| 117 } |
| 118 } |
| 119 |
| 120 |
| 121 // Call bootstat_log() once, and confirm creation of the event |
| 122 // files. The content of the files isn't checked. |
| 123 void EventTracker::TestEventCreation(bool expect_success) { |
| 124 bootstat_log(event_name_.c_str()); |
| 125 ValidateEventFileExistence(uptime_file_name_, expect_success); |
| 126 ValidateEventFileExistence(diskstats_file_name_, expect_success); |
| 127 } |
| 128 |
| 129 |
| 130 // Reset event state back to initial conditions by deleting the |
| 131 // associated event files and clearing the expected contents. |
104 void EventTracker::Reset() { | 132 void EventTracker::Reset() { |
105 uptime_content_.clear(); | 133 uptime_content_.clear(); |
106 diskstats_content_.clear(); | 134 diskstats_content_.clear(); |
107 RemoveFile(diskstats_file_name_); | 135 RemoveFile(diskstats_file_name_); |
108 RemoveFile(uptime_file_name_); | 136 RemoveFile(uptime_file_name_); |
109 } | 137 } |
110 | 138 |
111 | 139 |
112 // Bootstat test class. We use this class to override the | 140 // Bootstat test class. We use this class to override the |
113 // dependencies in bootstat_log() on the file paths for /proc/uptime | 141 // dependencies in bootstat_log() on the file paths for /proc/uptime |
114 // and /sys/block/<device>/stat. | 142 // and /sys/block/<device>/stat. |
115 // | 143 // |
116 // The class uses test-specific interfaces that change the default | 144 // The class uses test-specific interfaces that change the default |
117 // paths from the kernel statistics psuedo-files to temporary paths | 145 // paths from the kernel statistics psuedo-files to temporary paths |
118 // selected by this test. This class also redirects the location for | 146 // selected by this test. This class also redirects the location for |
119 // the event files created by bootstat_log() to a temporary directory. | 147 // the event files created by bootstat_log() to a temporary directory. |
120 class BootstatTest : public ::testing::Test { | 148 class BootstatTest : public ::testing::Test { |
121 protected: | 149 protected: |
122 virtual void SetUp(); | 150 virtual void SetUp(); |
123 virtual void TearDown(); | 151 virtual void TearDown(); |
124 | 152 |
| 153 EventTracker MakeEvent(const string& event_name, |
| 154 const string& output_dir_name) { |
| 155 return EventTracker(event_name, output_dir_name); |
| 156 } |
125 EventTracker MakeEvent(const string& event_name) { | 157 EventTracker MakeEvent(const string& event_name) { |
126 return EventTracker(event_name, uptime_event_prefix_, | 158 return EventTracker(event_name, stats_output_dir_); |
127 disk_event_prefix_); | |
128 } | 159 } |
129 | 160 |
130 void SetStatsContent(const char* uptime_content, | 161 void SetStatsContent(const char* uptime_content, |
131 const char* disk_content); | 162 const char* disk_content); |
132 void TestLogEvent(EventTracker& event); | 163 void ClearStatsContent(); |
| 164 void TestSetOutputDirectory(const string& testdir, |
| 165 const string& testevent, |
| 166 bool expect_success, |
| 167 int expected_errno); |
| 168 void TestSetOutputDirectoryAccess(const string& testdir, mode_t testmode); |
| 169 void TestLogAccess(const string& testdir, mode_t testmode); |
133 | 170 |
134 private: | 171 private: |
135 string stats_output_dir_; | 172 string stats_output_dir_; |
136 string uptime_event_prefix_; | |
137 string disk_event_prefix_; | |
138 | 173 |
139 string uptime_stats_file_name_; | 174 string uptime_stats_file_name_; |
140 string uptime_stats_content_; | |
141 string disk_stats_file_name_; | 175 string disk_stats_file_name_; |
142 string disk_stats_content_; | |
143 }; | 176 }; |
144 | 177 |
145 | 178 |
146 void BootstatTest::SetUp() { | 179 void BootstatTest::SetUp() { |
147 char dir_template[] = "bootstat_test_XXXXXX"; | 180 char dir_template[] = "bootstat_test_XXXXXX"; |
148 stats_output_dir_ = string(mkdtemp(dir_template)); | 181 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"; | 182 uptime_stats_file_name_ = stats_output_dir_ + "/proc_uptime"; |
152 disk_stats_file_name_ = stats_output_dir_ + "/block_stats"; | 183 disk_stats_file_name_ = stats_output_dir_ + "/block_stats"; |
153 bootstat_set_output_directory(stats_output_dir_.c_str()); | 184 EXPECT_EQ(0, bootstat_set_output_directory(stats_output_dir_.c_str())) |
154 bootstat_set_uptime_file_name(uptime_stats_file_name_.c_str()); | 185 << "Failed to select output directory " << stats_output_dir_ |
155 bootstat_set_disk_file_name(disk_stats_file_name_.c_str()); | 186 << ": " << strerror(errno) << "."; |
156 } | 187 } |
157 | 188 |
158 | 189 |
159 void BootstatTest::TearDown() { | 190 void BootstatTest::TearDown() { |
160 bootstat_set_uptime_file_name(NULL); | 191 EXPECT_EQ(0, bootstat_set_output_directory(NULL)) |
161 bootstat_set_disk_file_name(NULL); | 192 << "Failed to set output directory back to default: " |
162 bootstat_set_output_directory(NULL); | 193 << strerror(errno) << "."; |
163 RemoveFile(uptime_stats_file_name_); | |
164 RemoveFile(disk_stats_file_name_); | |
165 EXPECT_EQ(0, rmdir(stats_output_dir_.c_str())) | 194 EXPECT_EQ(0, rmdir(stats_output_dir_.c_str())) |
166 << "Can't remove directory " << stats_output_dir_ | 195 << "Can't remove directory " << stats_output_dir_ |
167 << ": " << strerror(errno) << "."; | 196 << ": " << strerror(errno) << "."; |
168 } | 197 } |
169 | 198 |
170 | 199 |
171 static void WriteStatsContent(const string& content, const string& file_path) { | 200 static void WriteStatsContent(const char *content, const string& file_path) { |
172 const int kFileOpenFlags = O_WRONLY | O_TRUNC | O_CREAT; | 201 const int kFileOpenFlags = O_WRONLY | O_TRUNC | O_CREAT; |
173 const mode_t kFileCreationMode = | 202 const mode_t kFileCreationMode = |
174 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; | 203 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; |
175 int fd = open(file_path.c_str(), kFileOpenFlags, kFileCreationMode); | 204 int fd = open(file_path.c_str(), kFileOpenFlags, kFileCreationMode); |
176 int nwrite = write(fd, content.c_str(), content.length()); | 205 int nwrite = write(fd, content, strlen(content)); |
177 EXPECT_EQ(content.length(), nwrite) | 206 EXPECT_EQ(strlen(content), nwrite) |
178 << "write to stats file " << file_path | 207 << "write to stats file " << file_path |
179 << " failed: " << strerror(errno); | 208 << " failed: " << strerror(errno); |
180 (void)close(fd); | 209 (void)close(fd); |
181 } | 210 } |
182 | 211 |
183 | 212 |
184 // Set the content of the files mocking the contents of the kernel's | 213 // Set the content of the files mocking the contents of the kernel's |
185 // statistics pseudo-files. The strings provided here will be the | 214 // statistics pseudo-files. The strings provided here will be the |
186 // ones recorded for subsequent calls to bootstat_log() for all | 215 // ones recorded for subsequent calls to bootstat_log() for all |
187 // events. | 216 // events. |
188 void BootstatTest::SetStatsContent(const char* uptime_stats, | 217 void BootstatTest::SetStatsContent(const char* uptime_stats, |
189 const char* disk_stats) { | 218 const char* disk_stats) { |
190 uptime_stats_content_ = string(uptime_stats); | 219 WriteStatsContent(uptime_stats, uptime_stats_file_name_); |
191 WriteStatsContent(uptime_stats_content_, uptime_stats_file_name_); | 220 WriteStatsContent(disk_stats, disk_stats_file_name_); |
192 disk_stats_content_ = string(disk_stats); | 221 bootstat_set_uptime_file_name(uptime_stats_file_name_.c_str()); |
193 WriteStatsContent(disk_stats_content_, disk_stats_file_name_); | 222 bootstat_set_disk_file_name(disk_stats_file_name_.c_str()); |
194 } | 223 } |
195 | 224 |
196 | 225 |
197 void BootstatTest::TestLogEvent(EventTracker& event) { | 226 void BootstatTest::ClearStatsContent() { |
198 event.TestLogEvent(uptime_stats_content_, disk_stats_content_); | 227 bootstat_set_uptime_file_name(NULL); |
| 228 bootstat_set_disk_file_name(NULL); |
| 229 RemoveFile(uptime_stats_file_name_); |
| 230 RemoveFile(disk_stats_file_name_); |
199 } | 231 } |
200 | 232 |
201 | 233 |
202 // Test data to be used as input to SetStatsContent(). | 234 // Test data to be used as input to SetStatsContent(). |
203 // | 235 // |
204 // The structure of this array is pairs of strings, terminated by a | 236 // The structure of this array is pairs of strings, terminated by a |
205 // single NULL. The first string in the pair is content for | 237 // single NULL. The first string in the pair is content for |
206 // /proc/uptime, the second for /sys/block/<device>/stat. | 238 // /proc/uptime, the second for /sys/block/<device>/stat. |
207 // | 239 // |
208 // This data is taken directly from a development system, and is | 240 // This data is taken directly from a development system, and is |
209 // representative of valid stats content, though not typical of what | 241 // representative of valid stats content, though not typical of what |
210 // would be seen immediately after boot. | 242 // would be seen immediately after boot. |
211 static const char* bootstat_data[] = { | 243 static const char* bootstat_data[] = { |
212 /* 0 */ | 244 /* 0 */ |
213 /* uptime */ "691448.42 11020440.26\n", | 245 /* uptime */ "691448.42 11020440.26\n", |
214 /* disk */ " 1417116 14896 55561564 10935990 4267850 78379879" | 246 /* disk */ " 1417116 14896 55561564 10935990 4267850 78379879" |
215 " 661568738 1635920520 158 17856450 1649520570\n", | 247 " 661568738 1635920520 158 17856450 1649520570\n", |
216 /* 1 */ | 248 /* 1 */ |
217 /* uptime */ "691623.71 11021372.99\n", | 249 /* uptime */ "691623.71 11021372.99\n", |
218 /* disk */ " 1420714 14918 55689988 11006390 4287385 78594261" | 250 /* disk */ " 1420714 14918 55689988 11006390 4287385 78594261" |
219 " 663441564 1651579200 152 17974280 1665255160\n", | 251 " 663441564 1651579200 152 17974280 1665255160\n", |
220 /* EOT */ NULL | 252 /* EOT */ NULL |
221 }; | 253 }; |
222 | 254 |
223 | 255 |
224 // Tests that event file content matches expectations when an | 256 // This is to test that event file content matches expectations when |
225 // event is logged multiple times. | 257 // an event is logged multiple times. |
226 TEST_F(BootstatTest, ContentGeneration) { | 258 TEST_F(BootstatTest, ContentGeneration) { |
227 EventTracker ev = MakeEvent(string("test_event")); | 259 EventTracker ev = MakeEvent(string("test_event")); |
228 int i = 0; | 260 int i = 0; |
229 while (bootstat_data[i] != NULL) { | 261 while (bootstat_data[i] != NULL) { |
230 SetStatsContent(bootstat_data[i], bootstat_data[i+1]); | 262 SetStatsContent(bootstat_data[i], bootstat_data[i+1]); |
231 TestLogEvent(ev); | 263 ev.TestEventContent(bootstat_data[i], bootstat_data[i+1]); |
232 i += 2; | 264 i += 2; |
233 } | 265 } |
| 266 ClearStatsContent(); |
234 ev.Reset(); | 267 ev.Reset(); |
235 } | 268 } |
236 | 269 |
237 | 270 |
238 // Tests that name truncation of logged events works as advertised. | 271 // This is to test that name truncation of logged events works as |
| 272 // advertised. |
239 TEST_F(BootstatTest, EventNameTruncation) { | 273 TEST_F(BootstatTest, EventNameTruncation) { |
240 static const char kMostVoluminousEventName[] = | 274 static const char kMostVoluminousEventName[] = |
241 // 16 32 48 64 | 275 // 16 32 48 64 |
242 "event-6789abcdef_123456789ABCDEF.123456789abcdef0123456789abcdef" // 64 | 276 "event-6789abcdef_123456789ABCDEF.123456789abcdef0123456789abcdef" // 64 |
243 "=064+56789abcdef_123456789ABCDEF.123456789abcdef0123456789abcdef" // 128 | 277 "=064+56789abcdef_123456789ABCDEF.123456789abcdef0123456789abcdef" // 128 |
244 "=128+56789abcdef_123456789ABCDEF.123456789abcdef0123456789abcdef" // 191 | 278 "=128+56789abcdef_123456789ABCDEF.123456789abcdef0123456789abcdef" // 191 |
245 "=191+56789abcdef_123456789ABCDEF.123456789abcdef0123456789abcdef" // 256 | 279 "=191+56789abcdef_123456789ABCDEF.123456789abcdef0123456789abcdef" // 256 |
246 ; | 280 ; |
247 | 281 |
248 string very_long(kMostVoluminousEventName); | 282 string very_long(kMostVoluminousEventName); |
249 SetStatsContent(bootstat_data[0], bootstat_data[1]); | 283 SetStatsContent(bootstat_data[0], bootstat_data[1]); |
250 | 284 |
251 EventTracker ev = MakeEvent(very_long); | 285 EventTracker ev = MakeEvent(very_long); |
252 TestLogEvent(ev); | 286 ev.TestEventContent(bootstat_data[0], bootstat_data[1]); |
253 ev.Reset(); | 287 ev.Reset(); |
254 ev = MakeEvent(very_long.substr(0, 1)); | 288 ev = MakeEvent(very_long.substr(0, 1)); |
255 TestLogEvent(ev); | 289 ev.TestEventContent(bootstat_data[0], bootstat_data[1]); |
256 ev.Reset(); | 290 ev.Reset(); |
257 ev = MakeEvent(very_long.substr(0, BOOTSTAT_MAX_EVENT_LEN - 1)); | 291 ev = MakeEvent(very_long.substr(0, BOOTSTAT_MAX_EVENT_LEN - 1)); |
258 TestLogEvent(ev); | 292 ev.TestEventContent(bootstat_data[0], bootstat_data[1]); |
259 ev.Reset(); | 293 ev.Reset(); |
260 ev = MakeEvent(very_long.substr(0, BOOTSTAT_MAX_EVENT_LEN)); | 294 ev = MakeEvent(very_long.substr(0, BOOTSTAT_MAX_EVENT_LEN)); |
261 TestLogEvent(ev); | 295 ev.TestEventContent(bootstat_data[0], bootstat_data[1]); |
262 ev.Reset(); | 296 ev.Reset(); |
| 297 |
| 298 ClearStatsContent(); |
263 } | 299 } |
264 | 300 |
| 301 |
| 302 // Test a call to bootstat_set_output_directory(). Check that the |
| 303 // operation succeeds or fails as indicated by the input parameters. |
| 304 // Also tests that bootstat_log() logs in the expected place after |
| 305 // the call: after success, logging should go to the new directory; |
| 306 // after a failure, logging should continue to go to the previous |
| 307 // directory. |
| 308 void BootstatTest::TestSetOutputDirectory(const string& testdir, |
| 309 const string& testevent, |
| 310 bool expect_success, |
| 311 int expected_errno) { |
| 312 ASSERT_EQ(0, bootstat_set_output_directory(stats_output_dir_.c_str())) |
| 313 << "bootstat_set_output_directory() failed for " << stats_output_dir_ |
| 314 << ": " << strerror(errno) << "."; |
| 315 bool set_output_success = |
| 316 (bootstat_set_output_directory(testdir.c_str()) == 0); |
| 317 |
| 318 if (expect_success) { |
| 319 ASSERT_TRUE(set_output_success) |
| 320 << "bootstat_set_output_directory() failed unexpectedly for " |
| 321 << testdir << ": " << strerror(errno) << "."; |
| 322 } else { |
| 323 ASSERT_FALSE(set_output_success) |
| 324 << "bootstat_set_output_directory() succeeded for " |
| 325 << testdir << "; expected error: " << strerror(expected_errno) << "."; |
| 326 EXPECT_EQ(expected_errno, errno); |
| 327 } |
| 328 |
| 329 string eventdir; |
| 330 if (set_output_success) { |
| 331 eventdir = testdir; |
| 332 } else { |
| 333 eventdir = stats_output_dir_; |
| 334 } |
| 335 string eventname = string("test-set-directory-") + testevent; |
| 336 EventTracker ev = MakeEvent(eventname, eventdir); |
| 337 ev.TestEventCreation(true); |
| 338 ASSERT_EQ(0, bootstat_set_output_directory(NULL)) |
| 339 << "bootstat_set_output_directory(NULL) failed: " |
| 340 << strerror(errno) << "."; |
| 341 } |
| 342 |
| 343 |
| 344 // Test that bootstat_set_output_directory() will return ENOENT |
| 345 // when required. |
| 346 TEST_F(BootstatTest, SetOutputDirectoryEnoent) { |
| 347 TestSetOutputDirectory(string("/this-directory-does-not-exist"), |
| 348 string("ENOENT"), false, ENOENT); |
| 349 } |
| 350 |
| 351 |
| 352 // Test that bootstat_set_output_directory() will return ENOTDIR |
| 353 // when required. |
| 354 TEST_F(BootstatTest, SetOutputDirectoryEnotdir) { |
| 355 string ordinary_file_name = string("ordinary-file"); |
| 356 const mode_t kFileCreationMode = |
| 357 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; |
| 358 int fd = creat(ordinary_file_name.c_str(), kFileCreationMode); |
| 359 EXPECT_GE(fd, 0) |
| 360 << "failed to create test file " << ordinary_file_name |
| 361 << ": " << strerror(errno) << "."; |
| 362 if (fd >= 0) { |
| 363 TestSetOutputDirectory(ordinary_file_name, string("ENOTDIR"), |
| 364 false, ENOTDIR); |
| 365 (void) close(fd); |
| 366 RemoveFile(ordinary_file_name); |
| 367 } |
| 368 } |
| 369 |
| 370 |
| 371 // Test that bootstat_set_output_directory() succeeds or fails with |
| 372 // EACCES as expected. |
| 373 void BootstatTest::TestSetOutputDirectoryAccess(const string& testdir, |
| 374 mode_t testmode) { |
| 375 char buffer[8]; |
| 376 sprintf(buffer, "0%03o", testmode); |
| 377 string modestring = string(buffer); |
| 378 bool expect_success = |
| 379 ((testmode & (S_IWUSR | S_IXUSR)) == (S_IWUSR | S_IXUSR)); |
| 380 |
| 381 ASSERT_EQ(0, chmod(testdir.c_str(), testmode)) |
| 382 << "Unable to change directory mode for " << testdir |
| 383 << " to " << modestring << ": " << strerror(errno) << "."; |
| 384 string eventname = string("EACCES-") + modestring; |
| 385 TestSetOutputDirectory(testdir, eventname, expect_success, EACCES); |
| 386 } |
| 387 |
| 388 |
| 389 // Test that the actual access mode requirements enforced by |
| 390 // bootstat_log() match the requirements enforced by |
| 391 // bootstat_set_output_directory(). |
| 392 void BootstatTest::TestLogAccess(const string& testdir, |
| 393 mode_t testmode) { |
| 394 char buffer[8]; |
| 395 sprintf(buffer, "0%03o", testmode); |
| 396 string modestring = string(buffer); |
| 397 bool expect_success = |
| 398 ((testmode & (S_IWUSR | S_IXUSR)) == (S_IWUSR | S_IXUSR)); |
| 399 |
| 400 ASSERT_EQ(0, chmod(testdir.c_str(), S_IRUSR | S_IWUSR | S_IXUSR)) |
| 401 << "Unable to change directory mode for " << testdir |
| 402 << " to 0700: " << strerror(errno) << "."; |
| 403 ASSERT_EQ(0, bootstat_set_output_directory(testdir.c_str())) |
| 404 << "bootstat_set_output_directory() failed for " << testdir |
| 405 << ": " << strerror(errno) << "."; |
| 406 ASSERT_EQ(0, chmod(testdir.c_str(), testmode)) |
| 407 << "Unable to change directory mode for " << testdir |
| 408 << " to " << modestring << ": " << strerror(errno) << "."; |
| 409 |
| 410 string event_name = string("test-log-access-") + modestring; |
| 411 EventTracker ev = MakeEvent(event_name, testdir); |
| 412 ev.TestEventCreation(expect_success); |
| 413 |
| 414 ASSERT_EQ(0, bootstat_set_output_directory(NULL)) |
| 415 << "bootstat_set_output_directory(NULL) failed: " |
| 416 << strerror(errno) << "."; |
| 417 } |
| 418 |
| 419 |
| 420 // Test that bootstat_set_output_directory() will return EACCES |
| 421 // as expected for all directory modes. The test here is |
| 422 // two-pronged. First, the test confirms that EACCES is |
| 423 // returned exactly when the caller has both W and X access. |
| 424 // Second, the test confirms that bootstat_log() fails when |
| 425 // EACCES is returned, but not when it isn't. |
| 426 TEST_F(BootstatTest, SetOutputDirectoryEacces) { |
| 427 char dir_template[] = "bootstat_access_test_XXXXXX"; |
| 428 string testdir = string(mkdtemp(dir_template)); |
| 429 mode_t lobit = ((S_IRUSR - 1) & (S_IWUSR - 1) & (S_IXUSR - 1)) + 1; |
| 430 mode_t allbits = (S_IRUSR | S_IWUSR | S_IXUSR); |
| 431 mode_t dirmode = allbits + lobit; |
| 432 while (dirmode > 0) { |
| 433 dirmode -= lobit; |
| 434 TestSetOutputDirectoryAccess(testdir, dirmode); |
| 435 TestLogAccess(testdir, dirmode); |
| 436 } |
| 437 EXPECT_EQ(0, rmdir(testdir.c_str())) |
| 438 << "Can't remove directory " << testdir |
| 439 << ": " << strerror(errno) << "."; |
| 440 } |
| 441 |
| 442 |
265 } // namespace | 443 } // namespace |
266 | 444 |
267 int main(int argc, char** argv) { | 445 int main(int argc, char** argv) { |
268 testing::InitGoogleTest(&argc, argv); | 446 testing::InitGoogleTest(&argc, argv); |
269 return RUN_ALL_TESTS(); | 447 return RUN_ALL_TESTS(); |
270 } | 448 } |
OLD | NEW |