filesystem_test.cc revision 010d83a9304c5a91596085d917d248abff47903a
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h>
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <fcntl.h>
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/stat.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "dev_fs_for_testing.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "gtest/gtest.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "nacl_io/filesystem.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "nacl_io/ioctl.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "nacl_io/kernel_handle.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "nacl_io/memfs/mem_fs.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "nacl_io/osdirent.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "nacl_io/osunistd.h"
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using namespace nacl_io;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MemFsForTesting : public MemFs {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MemFsForTesting() {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FsInitArgs args(1);
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(0, Init(args));
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int num_nodes() { return (int)inode_pool_.size(); }
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(FilesystemTest, Sanity) {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MemFsForTesting fs;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedNode file;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedNode root;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedNode result_node;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  off_t result_size = 0;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int result_bytes = 0;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char buf1[1024];
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // A memory filesystem starts with one directory node: the root.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(1, fs.num_nodes());
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fail to open non existent file
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(ENOENT, fs.Access(Path("/foo"), R_OK | W_OK));
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(ENOENT, fs.Open(Path("/foo"), O_RDWR, &result_node));
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(NULL, result_node.get());
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(1, fs.num_nodes());
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create a file
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0, fs.Open(Path("/foo"), O_RDWR | O_CREAT, &file));
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_NE(NULL_NODE, file.get());
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We now have a directory and a file.  The file has a two references
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // one returned to the test, one for the name->inode map.
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(2, fs.num_nodes());
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(2, file->RefCount());
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0, fs.Access(Path("/foo"), R_OK | W_OK));
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(EACCES, fs.Access(Path("/foo"), X_OK));
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // All access should be allowed on the root directory.
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(0, fs.Access(Path("/"), R_OK | W_OK | X_OK));
69116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Open the root directory for write should fail.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(EISDIR, fs.Open(Path("/"), O_RDWR, &root));
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(2, fs.num_nodes());
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Open the root directory, should not create a new file
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0, fs.Open(Path("/"), O_RDONLY, &root));
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(2, fs.num_nodes());
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_NE(NULL_NODE, root.get());
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct dirent dirs[4];
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int len;
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(0, root->GetDents(0, dirs, sizeof(dirs), &len));
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 3 == "foo", ".", ".."
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(3 * sizeof(struct dirent), len);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fail to re-create the same file
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(EEXIST,
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            fs.Open(Path("/foo"), O_RDWR | O_CREAT | O_EXCL, &result_node));
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(NULL_NODE, result_node.get());
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(2, fs.num_nodes());
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fail to create a directory with the same name
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(EEXIST, fs.Mkdir(Path("/foo"), O_RDWR));
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(2, fs.num_nodes());
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HandleAttr attrs;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Attempt to READ/WRITE
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0, file->GetSize(&result_size));
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0, result_size);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0, file->Write(attrs, buf1, sizeof(buf1), &result_bytes));
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(sizeof(buf1), result_bytes);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0, file->GetSize(&result_size));
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(sizeof(buf1), result_size);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0, file->Read(attrs, buf1, sizeof(buf1), &result_bytes));
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(sizeof(buf1), result_bytes);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(2, fs.num_nodes());
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(2, file->RefCount());
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Attempt to open the same file, create another ref to it, but does not
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // create a new file.
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0, fs.Open(Path("/foo"), O_RDWR | O_CREAT, &result_node));
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(3, file->RefCount());
111  EXPECT_EQ(2, fs.num_nodes());
112  EXPECT_EQ(file.get(), result_node.get());
113  EXPECT_EQ(0, file->GetSize(&result_size));
114  EXPECT_EQ(sizeof(buf1), result_size);
115
116  // Remove our references so that only the Filesystem holds it
117  file.reset();
118  result_node.reset();
119  EXPECT_EQ(2, fs.num_nodes());
120
121  // This should have deleted the object
122  EXPECT_EQ(0, fs.Unlink(Path("/foo")));
123  EXPECT_EQ(1, fs.num_nodes());
124
125  // We should fail to find it
126  EXPECT_EQ(ENOENT, fs.Unlink(Path("/foo")));
127  EXPECT_EQ(1, fs.num_nodes());
128
129  // Recreate foo as a directory
130  EXPECT_EQ(0, fs.Mkdir(Path("/foo"), O_RDWR));
131  EXPECT_EQ(2, fs.num_nodes());
132
133  // Create a file (exclusively)
134  EXPECT_EQ(0, fs.Open(Path("/foo/bar"), O_RDWR | O_CREAT | O_EXCL, &file));
135  ASSERT_NE(NULL_NODE, file.get());
136  EXPECT_EQ(2, file->RefCount());
137  EXPECT_EQ(3, fs.num_nodes());
138
139  // Attempt to delete the directory and fail
140  EXPECT_EQ(ENOTEMPTY, fs.Rmdir(Path("/foo")));
141  EXPECT_EQ(2, root->RefCount());
142  EXPECT_EQ(2, file->RefCount());
143  EXPECT_EQ(3, fs.num_nodes());
144
145  // Unlink the file, we should have the only file ref at this point.
146  EXPECT_EQ(0, fs.Unlink(Path("/foo/bar")));
147  EXPECT_EQ(2, root->RefCount());
148  EXPECT_EQ(1, file->RefCount());
149  EXPECT_EQ(3, fs.num_nodes());
150
151  // Deref the file, to make it go away
152  file.reset();
153  EXPECT_EQ(2, fs.num_nodes());
154
155  // Deref the directory
156  EXPECT_EQ(0, fs.Rmdir(Path("/foo")));
157  EXPECT_EQ(1, fs.num_nodes());
158
159  // Verify the directory is gone
160  EXPECT_EQ(ENOENT, fs.Access(Path("/foo"), F_OK));
161  EXPECT_EQ(ENOENT, fs.Open(Path("/foo"), O_RDWR, &file));
162  EXPECT_EQ(NULL_NODE, file.get());
163}
164
165TEST(FilesystemTest, OpenMode_TRUNC) {
166  MemFsForTesting fs;
167  ScopedNode file;
168  ScopedNode root;
169  ScopedNode result_node;
170  HandleAttr attrs;
171  int result_bytes;
172
173  // Open a file and write something to it.
174  const char* buf = "hello";
175  ASSERT_EQ(0, fs.Open(Path("/foo"), O_RDWR | O_CREAT, &file));
176  ASSERT_EQ(0, file->Write(attrs, buf, strlen(buf), &result_bytes));
177  ASSERT_EQ(strlen(buf), result_bytes);
178
179  // Open it again with TRUNC and make sure it is empty
180  char read_buf[10];
181  ASSERT_EQ(0, fs.Open(Path("/foo"), O_RDWR | O_TRUNC, &file));
182  ASSERT_EQ(0, file->Read(attrs, read_buf, sizeof(read_buf), &result_bytes));
183  ASSERT_EQ(0, result_bytes);
184}
185
186TEST(FilesystemTest, MemFsRemove) {
187  MemFsForTesting fs;
188  ScopedNode file;
189  ScopedNode result_node;
190
191  ASSERT_EQ(0, fs.Mkdir(Path("/dir"), O_RDWR));
192  ASSERT_EQ(0, fs.Open(Path("/file"), O_RDWR | O_CREAT | O_EXCL, &file));
193  EXPECT_NE(NULL_NODE, file.get());
194  EXPECT_EQ(3, fs.num_nodes());
195  file.reset();
196
197  EXPECT_EQ(0, fs.Remove(Path("/dir")));
198  EXPECT_EQ(2, fs.num_nodes());
199  EXPECT_EQ(0, fs.Remove(Path("/file")));
200  EXPECT_EQ(1, fs.num_nodes());
201
202  ASSERT_EQ(ENOENT, fs.Open(Path("/dir/foo"), O_CREAT | O_RDWR, &result_node));
203  ASSERT_EQ(NULL_NODE, result_node.get());
204  ASSERT_EQ(ENOENT, fs.Open(Path("/file"), O_RDONLY, &result_node));
205  ASSERT_EQ(NULL_NODE, result_node.get());
206}
207
208TEST(FilesystemTest, MemFsRename) {
209  MemFsForTesting fs;
210  ASSERT_EQ(0, fs.Mkdir(Path("/dir1"), O_RDWR));
211  ASSERT_EQ(0, fs.Mkdir(Path("/dir2"), O_RDWR));
212  ASSERT_EQ(3, fs.num_nodes());
213
214  ScopedNode file;
215  ASSERT_EQ(0, fs.Open(Path("/dir1/file"), O_RDWR | O_CREAT | O_EXCL, &file));
216  ASSERT_EQ(0, fs.Access(Path("/dir1/file"), R_OK));
217  ASSERT_EQ(4, fs.num_nodes());
218
219  // Move from one directory to another should ok
220  ASSERT_EQ(0, fs.Rename(Path("/dir1/file"), Path("/dir2/new_file")));
221  ASSERT_NE(0, fs.Access(Path("/dir1/file"), R_OK));
222  ASSERT_EQ(0, fs.Access(Path("/dir2/new_file"), R_OK));
223  ASSERT_EQ(4, fs.num_nodes());
224
225  // Move within the same directory
226  ASSERT_EQ(0, fs.Rename(Path("/dir2/new_file"), Path("/dir2/new_file2")));
227  ASSERT_NE(0, fs.Access(Path("/dir2/new_file"), R_OK));
228  ASSERT_EQ(0, fs.Access(Path("/dir2/new_file2"), R_OK));
229  ASSERT_EQ(4, fs.num_nodes());
230
231  // Move to another directory but without a filename
232  ASSERT_EQ(0, fs.Rename(Path("/dir2/new_file2"), Path("/dir1")));
233  ASSERT_NE(0, fs.Access(Path("/dir2/new_file2"), R_OK));
234  ASSERT_EQ(0, fs.Access(Path("/dir1/new_file2"), R_OK));
235  ASSERT_EQ(4, fs.num_nodes());
236}
237
238TEST(FilesystemTest, MemFsRenameDir) {
239  MemFsForTesting fs;
240
241  ASSERT_EQ(0, fs.Mkdir(Path("/dir1"), O_RDWR));
242  ASSERT_EQ(0, fs.Mkdir(Path("/dir2"), O_RDWR));
243  EXPECT_EQ(3, fs.num_nodes());
244
245  // Renaming one directory to another should work
246  ASSERT_EQ(0, fs.Rename(Path("/dir1"), Path("/dir2")));
247  ASSERT_NE(0, fs.Access(Path("/dir1"), R_OK));
248  ASSERT_EQ(0, fs.Access(Path("/dir2"), R_OK));
249  EXPECT_EQ(2, fs.num_nodes());
250
251  // Reset to initial state
252  ASSERT_EQ(0, fs.Mkdir(Path("/dir1"), O_RDWR));
253  EXPECT_EQ(3, fs.num_nodes());
254
255  // Renaming a directory to a new name within another
256  ASSERT_EQ(0, fs.Rename(Path("/dir1"), Path("/dir2/foo")));
257  ASSERT_EQ(0, fs.Access(Path("/dir2"), R_OK));
258  ASSERT_EQ(0, fs.Access(Path("/dir2/foo"), R_OK));
259  EXPECT_EQ(3, fs.num_nodes());
260
261  // Reset to initial state
262  ASSERT_EQ(0, fs.Rmdir(Path("/dir2/foo")));
263  ASSERT_EQ(0, fs.Mkdir(Path("/dir1"), O_RDWR));
264  EXPECT_EQ(3, fs.num_nodes());
265
266  // Renaming one directory to another should fail if the target is non-empty
267  ASSERT_EQ(0, fs.Mkdir(Path("/dir2/dir3"), O_RDWR));
268  ASSERT_EQ(ENOTEMPTY, fs.Rename(Path("/dir1"), Path("/dir2")));
269}
270
271TEST(FilesystemTest, DevAccess) {
272  // Should not be able to open non-existent file.
273  FakePepperInterface pepper;
274  DevFsForTesting fs(&pepper);
275  ScopedNode invalid_node, valid_node;
276  ASSERT_EQ(ENOENT, fs.Access(Path("/foo"), F_OK));
277  // Creating non-existent file should return EACCES
278  ASSERT_EQ(EACCES, fs.Open(Path("/foo"), O_CREAT | O_RDWR, &invalid_node));
279
280  // We should be able to open all existing nodes with O_CREAT and O_RDWR.
281  ASSERT_EQ(0, fs.Open(Path("/null"), O_CREAT | O_RDWR, &valid_node));
282  ASSERT_EQ(0, fs.Open(Path("/zero"), O_CREAT | O_RDWR, &valid_node));
283  ASSERT_EQ(0, fs.Open(Path("/urandom"), O_CREAT | O_RDWR, &valid_node));
284  ASSERT_EQ(0, fs.Open(Path("/console0"), O_CREAT | O_RDWR, &valid_node));
285  ASSERT_EQ(0, fs.Open(Path("/console1"), O_CREAT | O_RDWR, &valid_node));
286  ASSERT_EQ(0, fs.Open(Path("/console3"), O_CREAT | O_RDWR, &valid_node));
287  ASSERT_EQ(0, fs.Open(Path("/tty"), O_CREAT | O_RDWR, &valid_node));
288  ASSERT_EQ(0, fs.Open(Path("/stdin"), O_CREAT | O_RDWR, &valid_node));
289  ASSERT_EQ(0, fs.Open(Path("/stdout"), O_CREAT | O_RDWR, &valid_node));
290  ASSERT_EQ(0, fs.Open(Path("/stderr"), O_CREAT | O_RDWR, &valid_node));
291}
292
293TEST(FilesystemTest, DevNull) {
294  FakePepperInterface pepper;
295  DevFsForTesting fs(&pepper);
296  ScopedNode dev_null;
297  int result_bytes = 0;
298
299  ASSERT_EQ(0, fs.Access(Path("/null"), R_OK | W_OK));
300  ASSERT_EQ(EACCES, fs.Access(Path("/null"), X_OK));
301  ASSERT_EQ(0, fs.Open(Path("/null"), O_RDWR, &dev_null));
302  ASSERT_NE(NULL_NODE, dev_null.get());
303
304  // Writing to /dev/null should write everything.
305  const char msg[] = "Dummy test message.";
306  HandleAttr attrs;
307  EXPECT_EQ(0, dev_null->Write(attrs, &msg[0], strlen(msg), &result_bytes));
308  EXPECT_EQ(strlen(msg), result_bytes);
309
310  // Reading from /dev/null should read nothing.
311  const int kBufferLength = 100;
312  char buffer[kBufferLength];
313  EXPECT_EQ(0, dev_null->Read(attrs, &buffer[0], kBufferLength, &result_bytes));
314  EXPECT_EQ(0, result_bytes);
315}
316
317TEST(FilesystemTest, DevZero) {
318  FakePepperInterface pepper;
319  DevFsForTesting fs(&pepper);
320  ScopedNode dev_zero;
321  int result_bytes = 0;
322
323  ASSERT_EQ(0, fs.Access(Path("/zero"), R_OK | W_OK));
324  ASSERT_EQ(EACCES, fs.Access(Path("/zero"), X_OK));
325  ASSERT_EQ(0, fs.Open(Path("/zero"), O_RDWR, &dev_zero));
326  ASSERT_NE(NULL_NODE, dev_zero.get());
327
328  // Writing to /dev/zero should write everything.
329  HandleAttr attrs;
330  const char msg[] = "Dummy test message.";
331  EXPECT_EQ(0, dev_zero->Write(attrs, &msg[0], strlen(msg), &result_bytes));
332  EXPECT_EQ(strlen(msg), result_bytes);
333
334  // Reading from /dev/zero should read all zeroes.
335  const int kBufferLength = 100;
336  char buffer[kBufferLength];
337  // First fill with all 1s.
338  memset(&buffer[0], 0x1, kBufferLength);
339  EXPECT_EQ(0, dev_zero->Read(attrs, &buffer[0], kBufferLength, &result_bytes));
340  EXPECT_EQ(kBufferLength, result_bytes);
341
342  char zero_buffer[kBufferLength];
343  memset(&zero_buffer[0], 0, kBufferLength);
344  EXPECT_EQ(0, memcmp(&buffer[0], &zero_buffer[0], kBufferLength));
345}
346
347// Disabled due to intermittent failures on linux: http://crbug.com/257257
348TEST(FilesystemTest, DISABLED_DevUrandom) {
349  FakePepperInterface pepper;
350  DevFsForTesting fs(&pepper);
351  ScopedNode dev_urandom;
352  int result_bytes = 0;
353
354  ASSERT_EQ(0, fs.Access(Path("/urandom"), R_OK | W_OK));
355  ASSERT_EQ(EACCES, fs.Access(Path("/urandom"), X_OK));
356  ASSERT_EQ(0, fs.Open(Path("/urandom"), O_RDWR, &dev_urandom));
357  ASSERT_NE(NULL_NODE, dev_urandom.get());
358
359  // Writing to /dev/urandom should write everything.
360  const char msg[] = "Dummy test message.";
361  HandleAttr attrs;
362  EXPECT_EQ(0, dev_urandom->Write(attrs, &msg[0], strlen(msg), &result_bytes));
363  EXPECT_EQ(strlen(msg), result_bytes);
364
365  // Reading from /dev/urandom should read random bytes.
366  const int kSampleBatches = 1000;
367  const int kSampleBatchSize = 1000;
368  const int kTotalSamples = kSampleBatches * kSampleBatchSize;
369
370  int byte_count[256] = {0};
371
372  unsigned char buffer[kSampleBatchSize];
373  for (int batch = 0; batch < kSampleBatches; ++batch) {
374    int bytes_read = 0;
375    EXPECT_EQ(
376        0, dev_urandom->Read(attrs, &buffer[0], kSampleBatchSize, &bytes_read));
377    EXPECT_EQ(kSampleBatchSize, bytes_read);
378
379    for (int i = 0; i < bytes_read; ++i) {
380      byte_count[buffer[i]]++;
381    }
382  }
383
384  double expected_count = kTotalSamples / 256.;
385  double chi_squared = 0;
386  for (int i = 0; i < 256; ++i) {
387    double difference = byte_count[i] - expected_count;
388    chi_squared += difference * difference / expected_count;
389  }
390
391  // Approximate chi-squared value for p-value 0.05, 255 degrees-of-freedom.
392  EXPECT_LE(chi_squared, 293.24);
393}
394