Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / native_client_sdk / src / tests / nacl_io_test / filesystem_test.cc
blob0152cdfe964b2b606da01223dc05e083124314df
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <errno.h>
6 #include <fcntl.h>
7 #include <string.h>
8 #include <sys/stat.h>
9 #include <string>
11 #include "dev_fs_for_testing.h"
12 #include "gtest/gtest.h"
13 #include "nacl_io/filesystem.h"
14 #include "nacl_io/ioctl.h"
15 #include "nacl_io/kernel_handle.h"
16 #include "nacl_io/memfs/mem_fs.h"
17 #include "nacl_io/osdirent.h"
18 #include "nacl_io/osunistd.h"
20 using namespace nacl_io;
22 namespace {
24 class MemFsForTesting : public MemFs {
25 public:
26 MemFsForTesting() {
27 FsInitArgs args(1);
28 EXPECT_EQ(0, Init(args));
31 bool Exists(const char* filename) {
32 ScopedNode node;
33 if (Open(Path(filename), O_RDONLY, &node))
34 return false;
36 struct stat buf;
37 return node->GetStat(&buf) == 0;
40 int num_nodes() { return (int)inode_pool_.size(); }
43 } // namespace
45 TEST(FilesystemTest, Sanity) {
46 MemFsForTesting fs;
48 ScopedNode file;
49 ScopedNode root;
50 ScopedNode result_node;
52 off_t result_size = 0;
53 int result_bytes = 0;
54 struct stat buf;
55 char buf1[1024];
57 // A memory filesystem starts with one directory node: the root.
58 EXPECT_EQ(1, fs.num_nodes());
60 // Fail to open non existent file
61 EXPECT_EQ(ENOENT, fs.Open(Path("/foo"), O_RDWR, &result_node));
62 EXPECT_EQ(NULL, result_node.get());
63 EXPECT_EQ(1, fs.num_nodes());
65 // Create a file
66 EXPECT_EQ(0, fs.Open(Path("/foo"), O_RDWR | O_CREAT, &file));
67 ASSERT_NE(NULL_NODE, file.get());
69 // We now have a directory and a file. The file has a two references
70 // one returned to the test, one for the name->inode map.
71 ASSERT_EQ(2, fs.num_nodes());
72 ASSERT_EQ(2, file->RefCount());
73 ASSERT_EQ(0, file->GetStat(&buf));
74 ASSERT_EQ(0, buf.st_mode & S_IXUSR);
76 // All access should be allowed on the root directory.
77 EXPECT_EQ(0, fs.Open(Path("/"), O_RDONLY, &root));
78 ASSERT_EQ(0, root->GetStat(&buf));
79 ASSERT_EQ(S_IRWXU, buf.st_mode & S_IRWXU);
81 // Open the root directory, should not create a new file
82 EXPECT_EQ(0, fs.Open(Path("/"), O_RDONLY, &root));
83 EXPECT_EQ(2, fs.num_nodes());
84 ASSERT_NE(NULL_NODE, root.get());
85 struct dirent dirs[4];
86 int len;
87 EXPECT_EQ(0, root->GetDents(0, dirs, sizeof(dirs), &len));
88 // 3 == "foo", ".", ".."
89 EXPECT_EQ(3 * sizeof(struct dirent), len);
91 // Fail to re-create the same file
92 EXPECT_EQ(EEXIST,
93 fs.Open(Path("/foo"), O_RDWR | O_CREAT | O_EXCL, &result_node));
94 EXPECT_EQ(NULL_NODE, result_node.get());
95 EXPECT_EQ(2, fs.num_nodes());
97 // Fail to create a directory with the same name
98 EXPECT_EQ(EEXIST, fs.Mkdir(Path("/foo"), O_RDWR));
99 EXPECT_EQ(2, fs.num_nodes());
101 HandleAttr attrs;
103 // Attempt to READ/WRITE
104 EXPECT_EQ(0, file->GetSize(&result_size));
105 EXPECT_EQ(0, result_size);
106 EXPECT_EQ(0, file->Write(attrs, buf1, sizeof(buf1), &result_bytes));
107 EXPECT_EQ(sizeof(buf1), result_bytes);
108 EXPECT_EQ(0, file->GetSize(&result_size));
109 EXPECT_EQ(sizeof(buf1), result_size);
110 EXPECT_EQ(0, file->Read(attrs, buf1, sizeof(buf1), &result_bytes));
111 EXPECT_EQ(sizeof(buf1), result_bytes);
112 EXPECT_EQ(2, fs.num_nodes());
113 EXPECT_EQ(2, file->RefCount());
115 // Attempt to open the same file, create another ref to it, but does not
116 // create a new file.
117 EXPECT_EQ(0, fs.Open(Path("/foo"), O_RDWR | O_CREAT, &result_node));
118 EXPECT_EQ(3, file->RefCount());
119 EXPECT_EQ(2, fs.num_nodes());
120 EXPECT_EQ(file.get(), result_node.get());
121 EXPECT_EQ(0, file->GetSize(&result_size));
122 EXPECT_EQ(sizeof(buf1), result_size);
124 // Remove our references so that only the Filesystem holds it
125 file.reset();
126 result_node.reset();
127 EXPECT_EQ(2, fs.num_nodes());
129 // This should have deleted the object
130 EXPECT_EQ(0, fs.Unlink(Path("/foo")));
131 EXPECT_EQ(1, fs.num_nodes());
133 // We should fail to find it
134 EXPECT_EQ(ENOENT, fs.Unlink(Path("/foo")));
135 EXPECT_EQ(1, fs.num_nodes());
137 // Recreate foo as a directory
138 EXPECT_EQ(0, fs.Mkdir(Path("/foo"), O_RDWR));
139 EXPECT_EQ(2, fs.num_nodes());
141 // Create a file (exclusively)
142 EXPECT_EQ(0, fs.Open(Path("/foo/bar"), O_RDWR | O_CREAT | O_EXCL, &file));
143 ASSERT_NE(NULL_NODE, file.get());
144 EXPECT_EQ(2, file->RefCount());
145 EXPECT_EQ(3, fs.num_nodes());
147 // Attempt to delete the directory and fail
148 EXPECT_EQ(ENOTEMPTY, fs.Rmdir(Path("/foo")));
149 EXPECT_EQ(2, root->RefCount());
150 EXPECT_EQ(2, file->RefCount());
151 EXPECT_EQ(3, fs.num_nodes());
153 // Unlink the file, we should have the only file ref at this point.
154 EXPECT_EQ(0, fs.Unlink(Path("/foo/bar")));
155 EXPECT_EQ(2, root->RefCount());
156 EXPECT_EQ(1, file->RefCount());
157 EXPECT_EQ(3, fs.num_nodes());
159 // Deref the file, to make it go away
160 file.reset();
161 EXPECT_EQ(2, fs.num_nodes());
163 // Deref the directory
164 EXPECT_EQ(0, fs.Rmdir(Path("/foo")));
165 EXPECT_EQ(1, fs.num_nodes());
167 // Verify the directory is gone
168 EXPECT_EQ(ENOENT, fs.Open(Path("/foo"), O_RDONLY, &file));
169 EXPECT_EQ(NULL_NODE, file.get());
172 TEST(FilesystemTest, OpenMode_TRUNC) {
173 MemFsForTesting fs;
174 ScopedNode file;
175 ScopedNode root;
176 ScopedNode result_node;
177 HandleAttr attrs;
178 int result_bytes;
180 // Open a file and write something to it.
181 const char* buf = "hello";
182 ASSERT_EQ(0, fs.Open(Path("/foo"), O_RDWR | O_CREAT, &file));
183 ASSERT_EQ(0, file->Write(attrs, buf, strlen(buf), &result_bytes));
184 ASSERT_EQ(strlen(buf), result_bytes);
186 // Open it again with TRUNC and make sure it is empty
187 char read_buf[10];
188 ASSERT_EQ(0, fs.Open(Path("/foo"), O_RDWR | O_TRUNC, &file));
189 ASSERT_EQ(0, file->Read(attrs, read_buf, sizeof(read_buf), &result_bytes));
190 ASSERT_EQ(0, result_bytes);
193 TEST(FilesystemTest, MemFsRemove) {
194 MemFsForTesting fs;
195 ScopedNode file;
196 ScopedNode result_node;
198 ASSERT_EQ(0, fs.Mkdir(Path("/dir"), O_RDWR));
199 ASSERT_EQ(0, fs.Open(Path("/file"), O_RDWR | O_CREAT | O_EXCL, &file));
200 EXPECT_NE(NULL_NODE, file.get());
201 EXPECT_EQ(3, fs.num_nodes());
202 file.reset();
204 EXPECT_EQ(0, fs.Remove(Path("/dir")));
205 EXPECT_EQ(2, fs.num_nodes());
206 EXPECT_EQ(0, fs.Remove(Path("/file")));
207 EXPECT_EQ(1, fs.num_nodes());
209 ASSERT_EQ(ENOENT, fs.Open(Path("/dir/foo"), O_CREAT | O_RDWR, &result_node));
210 ASSERT_EQ(NULL_NODE, result_node.get());
211 ASSERT_EQ(ENOENT, fs.Open(Path("/file"), O_RDONLY, &result_node));
212 ASSERT_EQ(NULL_NODE, result_node.get());
215 TEST(FilesystemTest, MemFsRename) {
216 MemFsForTesting fs;
217 ASSERT_EQ(0, fs.Mkdir(Path("/dir1"), O_RDWR));
218 ASSERT_EQ(0, fs.Mkdir(Path("/dir2"), O_RDWR));
219 ASSERT_EQ(3, fs.num_nodes());
221 ScopedNode file;
222 ASSERT_EQ(0, fs.Open(Path("/dir1/file"), O_RDWR | O_CREAT | O_EXCL, &file));
223 ASSERT_TRUE(fs.Exists("/dir1/file"));
224 ASSERT_EQ(4, fs.num_nodes());
226 // Move from one directory to another should ok
227 ASSERT_EQ(0, fs.Rename(Path("/dir1/file"), Path("/dir2/new_file")));
228 ASSERT_FALSE(fs.Exists("/dir1/file"));
229 ASSERT_TRUE(fs.Exists("/dir2/new_file"));
230 ASSERT_EQ(4, fs.num_nodes());
232 // Move within the same directory
233 ASSERT_EQ(0, fs.Rename(Path("/dir2/new_file"), Path("/dir2/new_file2")));
234 ASSERT_FALSE(fs.Exists("/dir2/new_file"));
235 ASSERT_TRUE(fs.Exists("/dir2/new_file2"));
236 ASSERT_EQ(4, fs.num_nodes());
238 // Move to another directory but without a filename
239 ASSERT_EQ(0, fs.Rename(Path("/dir2/new_file2"), Path("/dir1")));
240 ASSERT_FALSE(fs.Exists("/dir2/new_file2"));
241 ASSERT_TRUE(fs.Exists("/dir1/new_file2"));
242 ASSERT_EQ(4, fs.num_nodes());
245 TEST(FilesystemTest, MemFsRenameDir) {
246 MemFsForTesting fs;
248 ASSERT_EQ(0, fs.Mkdir(Path("/dir1"), O_RDWR));
249 ASSERT_EQ(0, fs.Mkdir(Path("/dir2"), O_RDWR));
250 EXPECT_EQ(3, fs.num_nodes());
252 // Renaming one directory to another should work
253 ASSERT_EQ(0, fs.Rename(Path("/dir1"), Path("/dir2")));
254 ASSERT_FALSE(fs.Exists("/dir1"));
255 ASSERT_TRUE(fs.Exists("/dir2"));
256 EXPECT_EQ(2, fs.num_nodes());
258 // Reset to initial state
259 ASSERT_EQ(0, fs.Mkdir(Path("/dir1"), O_RDWR));
260 EXPECT_EQ(3, fs.num_nodes());
262 // Renaming a directory to a new name within another
263 ASSERT_EQ(0, fs.Rename(Path("/dir1"), Path("/dir2/foo")));
264 ASSERT_TRUE(fs.Exists("/dir2"));
265 ASSERT_TRUE(fs.Exists("/dir2/foo"));
266 EXPECT_EQ(3, fs.num_nodes());
268 // Reset to initial state
269 ASSERT_EQ(0, fs.Rmdir(Path("/dir2/foo")));
270 ASSERT_EQ(0, fs.Mkdir(Path("/dir1"), O_RDWR));
271 EXPECT_EQ(3, fs.num_nodes());
273 // Renaming one directory to another should fail if the target is non-empty
274 ASSERT_EQ(0, fs.Mkdir(Path("/dir2/dir3"), O_RDWR));
275 ASSERT_EQ(ENOTEMPTY, fs.Rename(Path("/dir1"), Path("/dir2")));
278 TEST(FilesystemTest, DevAccess) {
279 // Should not be able to open non-existent file.
280 FakePepperInterface pepper;
281 DevFsForTesting fs(&pepper);
282 ScopedNode invalid_node, valid_node;
283 ASSERT_FALSE(fs.Exists("/foo"));
284 // Creating non-existent file should return EACCES
285 ASSERT_EQ(EACCES, fs.Open(Path("/foo"), O_CREAT | O_RDWR, &invalid_node));
287 // We should be able to open all existing nodes with O_CREAT and O_RDWR.
288 ASSERT_EQ(0, fs.Open(Path("/null"), O_CREAT | O_RDWR, &valid_node));
289 ASSERT_EQ(0, fs.Open(Path("/zero"), O_CREAT | O_RDWR, &valid_node));
290 ASSERT_EQ(0, fs.Open(Path("/urandom"), O_CREAT | O_RDWR, &valid_node));
291 ASSERT_EQ(0, fs.Open(Path("/console0"), O_CREAT | O_RDWR, &valid_node));
292 ASSERT_EQ(0, fs.Open(Path("/console1"), O_CREAT | O_RDWR, &valid_node));
293 ASSERT_EQ(0, fs.Open(Path("/console3"), O_CREAT | O_RDWR, &valid_node));
294 ASSERT_EQ(0, fs.Open(Path("/tty"), O_CREAT | O_RDWR, &valid_node));
295 ASSERT_EQ(0, fs.Open(Path("/stdin"), O_CREAT | O_RDWR, &valid_node));
296 ASSERT_EQ(0, fs.Open(Path("/stdout"), O_CREAT | O_RDWR, &valid_node));
297 ASSERT_EQ(0, fs.Open(Path("/stderr"), O_CREAT | O_RDWR, &valid_node));
300 TEST(FilesystemTest, DevNull) {
301 FakePepperInterface pepper;
302 DevFsForTesting fs(&pepper);
303 ScopedNode dev_null;
304 int result_bytes = 0;
305 struct stat buf;
307 ASSERT_EQ(0, fs.Open(Path("/null"), O_RDWR, &dev_null));
308 ASSERT_NE(NULL_NODE, dev_null.get());
309 ASSERT_EQ(0, dev_null->GetStat(&buf));
310 ASSERT_EQ(S_IRUSR | S_IWUSR, buf.st_mode & S_IRWXU);
312 // Writing to /dev/null should write everything.
313 const char msg[] = "Dummy test message.";
314 HandleAttr attrs;
315 EXPECT_EQ(0, dev_null->Write(attrs, &msg[0], strlen(msg), &result_bytes));
316 EXPECT_EQ(strlen(msg), result_bytes);
318 // Reading from /dev/null should read nothing.
319 const int kBufferLength = 100;
320 char buffer[kBufferLength];
321 EXPECT_EQ(0, dev_null->Read(attrs, &buffer[0], kBufferLength, &result_bytes));
322 EXPECT_EQ(0, result_bytes);
325 TEST(FilesystemTest, DevZero) {
326 FakePepperInterface pepper;
327 DevFsForTesting fs(&pepper);
328 ScopedNode dev_zero;
329 int result_bytes = 0;
330 struct stat buf;
332 ASSERT_EQ(0, fs.Open(Path("/zero"), O_RDWR, &dev_zero));
333 ASSERT_NE(NULL_NODE, dev_zero.get());
334 ASSERT_EQ(0, dev_zero->GetStat(&buf));
335 ASSERT_EQ(S_IRUSR | S_IWUSR, buf.st_mode & S_IRWXU);
337 // Writing to /dev/zero should write everything.
338 HandleAttr attrs;
339 const char msg[] = "Dummy test message.";
340 EXPECT_EQ(0, dev_zero->Write(attrs, &msg[0], strlen(msg), &result_bytes));
341 EXPECT_EQ(strlen(msg), result_bytes);
343 // Reading from /dev/zero should read all zeroes.
344 const int kBufferLength = 100;
345 char buffer[kBufferLength];
346 // First fill with all 1s.
347 memset(&buffer[0], 0x1, kBufferLength);
348 EXPECT_EQ(0, dev_zero->Read(attrs, &buffer[0], kBufferLength, &result_bytes));
349 EXPECT_EQ(kBufferLength, result_bytes);
351 char zero_buffer[kBufferLength];
352 memset(&zero_buffer[0], 0, kBufferLength);
353 EXPECT_EQ(0, memcmp(&buffer[0], &zero_buffer[0], kBufferLength));
356 // Disabled due to intermittent failures on linux: http://crbug.com/257257
357 TEST(FilesystemTest, DISABLED_DevUrandom) {
358 FakePepperInterface pepper;
359 DevFsForTesting fs(&pepper);
360 ScopedNode dev_urandom;
361 int result_bytes = 0;
362 struct stat buf;
364 ASSERT_EQ(0, fs.Open(Path("/urandom"), O_RDWR, &dev_urandom));
365 ASSERT_NE(NULL_NODE, dev_urandom.get());
366 ASSERT_EQ(0, dev_urandom->GetStat(&buf));
367 ASSERT_EQ(S_IRUSR | S_IWUSR, buf.st_mode & S_IRWXU);
369 // Writing to /dev/urandom should write everything.
370 const char msg[] = "Dummy test message.";
371 HandleAttr attrs;
372 EXPECT_EQ(0, dev_urandom->Write(attrs, &msg[0], strlen(msg), &result_bytes));
373 EXPECT_EQ(strlen(msg), result_bytes);
375 // Reading from /dev/urandom should read random bytes.
376 const int kSampleBatches = 1000;
377 const int kSampleBatchSize = 1000;
378 const int kTotalSamples = kSampleBatches * kSampleBatchSize;
380 int byte_count[256] = {0};
382 unsigned char buffer[kSampleBatchSize];
383 for (int batch = 0; batch < kSampleBatches; ++batch) {
384 int bytes_read = 0;
385 EXPECT_EQ(
386 0, dev_urandom->Read(attrs, &buffer[0], kSampleBatchSize, &bytes_read));
387 EXPECT_EQ(kSampleBatchSize, bytes_read);
389 for (int i = 0; i < bytes_read; ++i) {
390 byte_count[buffer[i]]++;
394 double expected_count = kTotalSamples / 256.;
395 double chi_squared = 0;
396 for (int i = 0; i < 256; ++i) {
397 double difference = byte_count[i] - expected_count;
398 chi_squared += difference * difference / expected_count;
401 // Approximate chi-squared value for p-value 0.05, 255 degrees-of-freedom.
402 EXPECT_LE(chi_squared, 293.24);