Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / native_client_sdk / src / tests / nacl_io_test / http_fs_test.cc
blob307fb61fcb49744f57ae60d305630581ba30c3bb
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 <fcntl.h>
6 #include <gmock/gmock.h>
7 #include <ppapi/c/ppb_file_io.h>
8 #include <ppapi/c/pp_errors.h>
9 #include <ppapi/c/pp_instance.h>
10 #include <sys/stat.h>
11 #include <sys/types.h>
13 #include "fake_ppapi/fake_pepper_interface_url_loader.h"
15 #include "nacl_io/dir_node.h"
16 #include "nacl_io/httpfs/http_fs.h"
17 #include "nacl_io/kernel_handle.h"
18 #include "nacl_io/kernel_intercept.h"
19 #include "nacl_io/osdirent.h"
20 #include "nacl_io/osunistd.h"
22 using namespace nacl_io;
24 namespace {
26 class HttpFsForTesting : public HttpFs {
27 public:
28 HttpFsForTesting(StringMap_t map, PepperInterface* ppapi) {
29 FsInitArgs args(1);
30 args.string_map = map;
31 args.ppapi = ppapi;
32 EXPECT_EQ(0, Init(args));
35 using HttpFs::GetNodeCacheForTesting;
36 using HttpFs::ParseManifest;
37 using HttpFs::FindOrCreateDir;
40 enum {
41 kStringMapParamCacheNone = 0,
42 kStringMapParamCacheContent = 1,
43 kStringMapParamCacheStat = 2,
44 kStringMapParamCacheContentStat =
45 kStringMapParamCacheContent | kStringMapParamCacheStat,
47 typedef uint32_t StringMapParam;
49 StringMap_t MakeStringMap(StringMapParam param) {
50 StringMap_t smap;
51 if (param & kStringMapParamCacheContent)
52 smap["cache_content"] = "true";
53 else
54 smap["cache_content"] = "false";
56 if (param & kStringMapParamCacheStat)
57 smap["cache_stat"] = "true";
58 else
59 smap["cache_stat"] = "false";
60 return smap;
63 class HttpFsTest : public ::testing::TestWithParam<StringMapParam> {
64 public:
65 HttpFsTest();
67 protected:
68 FakePepperInterfaceURLLoader ppapi_;
69 HttpFsForTesting fs_;
72 HttpFsTest::HttpFsTest() : fs_(MakeStringMap(GetParam()), &ppapi_) {}
74 class HttpFsLargeFileTest : public HttpFsTest {
75 public:
76 HttpFsLargeFileTest() {}
79 } // namespace
81 TEST_P(HttpFsTest, Access) {
82 ASSERT_TRUE(ppapi_.server_template()->AddEntity("foo", "", NULL));
84 ASSERT_EQ(0, fs_.Access(Path("/foo"), R_OK));
85 ASSERT_EQ(EACCES, fs_.Access(Path("/foo"), W_OK));
86 ASSERT_EQ(EACCES, fs_.Access(Path("/foo"), X_OK));
87 ASSERT_EQ(ENOENT, fs_.Access(Path("/bar"), F_OK));
90 TEST_P(HttpFsTest, OpenAndCloseServerError) {
91 EXPECT_TRUE(ppapi_.server_template()->AddError("file", 500));
93 ScopedNode node;
94 ASSERT_EQ(EIO, fs_.Open(Path("/file"), O_RDONLY, &node));
97 TEST_P(HttpFsTest, ReadPartial) {
98 const char contents[] = "0123456789abcdefg";
99 ASSERT_TRUE(ppapi_.server_template()->AddEntity("file", contents, NULL));
100 ppapi_.server_template()->set_allow_partial(true);
102 int result_bytes = 0;
104 char buf[10];
105 memset(&buf[0], 0, sizeof(buf));
107 ScopedNode node;
108 ASSERT_EQ(0, fs_.Open(Path("/file"), O_RDONLY, &node));
109 HandleAttr attr;
110 EXPECT_EQ(0, node->Read(attr, buf, sizeof(buf) - 1, &result_bytes));
111 EXPECT_EQ(sizeof(buf) - 1, result_bytes);
112 EXPECT_STREQ("012345678", &buf[0]);
114 // Read is clamped when reading past the end of the file.
115 attr.offs = 10;
116 ASSERT_EQ(0, node->Read(attr, buf, sizeof(buf) - 1, &result_bytes));
117 ASSERT_EQ(strlen("abcdefg"), result_bytes);
118 buf[result_bytes] = 0;
119 EXPECT_STREQ("abcdefg", &buf[0]);
121 // Read nothing when starting past the end of the file.
122 attr.offs = 100;
123 EXPECT_EQ(0, node->Read(attr, &buf[0], sizeof(buf), &result_bytes));
124 EXPECT_EQ(0, result_bytes);
127 TEST_P(HttpFsTest, ReadPartialNoServerSupport) {
128 const char contents[] = "0123456789abcdefg";
129 ASSERT_TRUE(ppapi_.server_template()->AddEntity("file", contents, NULL));
130 ppapi_.server_template()->set_allow_partial(false);
132 int result_bytes = 0;
134 char buf[10];
135 memset(&buf[0], 0, sizeof(buf));
137 ScopedNode node;
138 ASSERT_EQ(0, fs_.Open(Path("/file"), O_RDONLY, &node));
139 HandleAttr attr;
140 EXPECT_EQ(0, node->Read(attr, buf, sizeof(buf) - 1, &result_bytes));
141 EXPECT_EQ(sizeof(buf) - 1, result_bytes);
142 EXPECT_STREQ("012345678", &buf[0]);
144 // Read is clamped when reading past the end of the file.
145 attr.offs = 10;
146 ASSERT_EQ(0, node->Read(attr, buf, sizeof(buf) - 1, &result_bytes));
147 ASSERT_EQ(strlen("abcdefg"), result_bytes);
148 buf[result_bytes] = 0;
149 EXPECT_STREQ("abcdefg", &buf[0]);
151 // Read nothing when starting past the end of the file.
152 attr.offs = 100;
153 EXPECT_EQ(0, node->Read(attr, &buf[0], sizeof(buf), &result_bytes));
154 EXPECT_EQ(0, result_bytes);
157 TEST_P(HttpFsTest, Write) {
158 const char contents[] = "contents";
159 ASSERT_TRUE(ppapi_.server_template()->AddEntity("file", contents, NULL));
161 ScopedNode node;
162 ASSERT_EQ(0, fs_.Open(Path("/file"), O_WRONLY, &node));
164 // Writing always fails.
165 HandleAttr attr;
166 attr.offs = 3;
167 int bytes_written = 1; // Set to a non-zero value.
168 EXPECT_EQ(EACCES, node->Write(attr, "struct", 6, &bytes_written));
169 EXPECT_EQ(0, bytes_written);
172 TEST_P(HttpFsTest, GetStat) {
173 const char contents[] = "contents";
174 ASSERT_TRUE(ppapi_.server_template()->AddEntity("file", contents, NULL));
176 ScopedNode node;
177 ASSERT_EQ(0, fs_.Open(Path("/file"), O_RDONLY, &node));
179 struct stat statbuf;
180 EXPECT_EQ(0, node->GetStat(&statbuf));
181 EXPECT_EQ(S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH,
182 statbuf.st_mode);
183 EXPECT_EQ(strlen(contents), statbuf.st_size);
184 // These are not currently set.
185 EXPECT_EQ(0, statbuf.st_atime);
186 EXPECT_EQ(0, statbuf.st_ctime);
187 EXPECT_EQ(0, statbuf.st_mtime);
190 TEST_P(HttpFsTest, FTruncate) {
191 const char contents[] = "contents";
192 ASSERT_TRUE(ppapi_.server_template()->AddEntity("file", contents, NULL));
194 ScopedNode node;
195 ASSERT_EQ(0, fs_.Open(Path("/file"), O_RDWR, &node));
196 EXPECT_EQ(EACCES, node->FTruncate(4));
199 // Instantiate the above tests for all caching types.
200 INSTANTIATE_TEST_CASE_P(
201 Default,
202 HttpFsTest,
203 ::testing::Values((uint32_t)kStringMapParamCacheNone,
204 (uint32_t)kStringMapParamCacheContent,
205 (uint32_t)kStringMapParamCacheStat,
206 (uint32_t)kStringMapParamCacheContentStat));
208 TEST_P(HttpFsLargeFileTest, ReadPartial) {
209 const char contents[] = "0123456789abcdefg";
210 off_t size = 0x110000000ll;
211 ASSERT_TRUE(
212 ppapi_.server_template()->AddEntity("file", contents, size, NULL));
213 ppapi_.server_template()->set_send_content_length(true);
214 ppapi_.server_template()->set_allow_partial(true);
216 int result_bytes = 0;
218 char buf[10];
219 memset(&buf[0], 0, sizeof(buf));
221 ScopedNode node;
222 ASSERT_EQ(0, fs_.Open(Path("/file"), O_RDONLY, &node));
223 HandleAttr attr;
224 EXPECT_EQ(0, node->Read(attr, buf, sizeof(buf) - 1, &result_bytes));
225 EXPECT_EQ(sizeof(buf) - 1, result_bytes);
226 EXPECT_STREQ("012345678", &buf[0]);
228 // Read is clamped when reading past the end of the file.
229 attr.offs = size - 7;
230 ASSERT_EQ(0, node->Read(attr, buf, sizeof(buf) - 1, &result_bytes));
231 ASSERT_EQ(strlen("abcdefg"), result_bytes);
232 buf[result_bytes] = 0;
233 EXPECT_STREQ("abcdefg", &buf[0]);
235 // Read nothing when starting past the end of the file.
236 attr.offs = size + 100;
237 EXPECT_EQ(0, node->Read(attr, &buf[0], sizeof(buf), &result_bytes));
238 EXPECT_EQ(0, result_bytes);
241 TEST_P(HttpFsLargeFileTest, GetStat) {
242 const char contents[] = "contents";
243 off_t size = 0x110000000ll;
244 ASSERT_TRUE(
245 ppapi_.server_template()->AddEntity("file", contents, size, NULL));
246 // TODO(binji): If the server doesn't send the content length, this operation
247 // will be incredibly slow; it will attempt to read all of the data from the
248 // server to find the file length. Can we do anything smarter?
249 ppapi_.server_template()->set_send_content_length(true);
251 ScopedNode node;
252 ASSERT_EQ(0, fs_.Open(Path("/file"), O_RDONLY, &node));
254 struct stat statbuf;
255 EXPECT_EQ(0, node->GetStat(&statbuf));
256 EXPECT_EQ(S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH,
257 statbuf.st_mode);
258 EXPECT_EQ(size, statbuf.st_size);
259 // These are not currently set.
260 EXPECT_EQ(0, statbuf.st_atime);
261 EXPECT_EQ(0, statbuf.st_ctime);
262 EXPECT_EQ(0, statbuf.st_mtime);
265 // Instantiate the large file tests, only when cache content is off.
266 // TODO(binji): make cache content smarter, so it doesn't try to cache enormous
267 // files. See http://crbug.com/369279.
268 INSTANTIATE_TEST_CASE_P(Default,
269 HttpFsLargeFileTest,
270 ::testing::Values((uint32_t)kStringMapParamCacheNone,
271 (uint32_t)kStringMapParamCacheStat));
273 TEST(HttpFsDirTest, Mkdir) {
274 StringMap_t args;
275 HttpFsForTesting fs(args, NULL);
276 char manifest[] = "-r-- 123 /mydir/foo\n-rw- 234 /thatdir/bar\n";
277 ASSERT_EQ(0, fs.ParseManifest(manifest));
278 // mkdir of existing directories should give "File exists".
279 EXPECT_EQ(EEXIST, fs.Mkdir(Path("/"), 0));
280 EXPECT_EQ(EEXIST, fs.Mkdir(Path("/mydir"), 0));
281 // mkdir of non-existent directories should give "Permission denied".
282 EXPECT_EQ(EACCES, fs.Mkdir(Path("/non_existent"), 0));
285 TEST(HttpFsDirTest, Rmdir) {
286 StringMap_t args;
287 HttpFsForTesting fs(args, NULL);
288 char manifest[] = "-r-- 123 /mydir/foo\n-rw- 234 /thatdir/bar\n";
289 ASSERT_EQ(0, fs.ParseManifest(manifest));
290 // Rmdir on existing dirs should give "Permission Denied"
291 EXPECT_EQ(EACCES, fs.Rmdir(Path("/")));
292 EXPECT_EQ(EACCES, fs.Rmdir(Path("/mydir")));
293 // Rmdir on existing files should give "Not a direcotory"
294 EXPECT_EQ(ENOTDIR, fs.Rmdir(Path("/mydir/foo")));
295 // Rmdir on non-existent files should give "No such file or directory"
296 EXPECT_EQ(ENOENT, fs.Rmdir(Path("/non_existent")));
299 TEST(HttpFsDirTest, Unlink) {
300 StringMap_t args;
301 HttpFsForTesting fs(args, NULL);
302 char manifest[] = "-r-- 123 /mydir/foo\n-rw- 234 /thatdir/bar\n";
303 ASSERT_EQ(0, fs.ParseManifest(manifest));
304 // Unlink of existing files should give "Permission Denied"
305 EXPECT_EQ(EACCES, fs.Unlink(Path("/mydir/foo")));
306 // Unlink of existing directory should give "Is a directory"
307 EXPECT_EQ(EISDIR, fs.Unlink(Path("/mydir")));
308 // Unlink of non-existent files should give "No such file or directory"
309 EXPECT_EQ(ENOENT, fs.Unlink(Path("/non_existent")));
312 TEST(HttpFsDirTest, Remove) {
313 StringMap_t args;
314 HttpFsForTesting fs(args, NULL);
315 char manifest[] = "-r-- 123 /mydir/foo\n-rw- 234 /thatdir/bar\n";
316 ASSERT_EQ(0, fs.ParseManifest(manifest));
317 // Remove of existing files should give "Permission Denied"
318 EXPECT_EQ(EACCES, fs.Remove(Path("/mydir/foo")));
319 // Remove of existing directory should give "Permission Denied"
320 EXPECT_EQ(EACCES, fs.Remove(Path("/mydir")));
321 // Unlink of non-existent files should give "No such file or directory"
322 EXPECT_EQ(ENOENT, fs.Remove(Path("/non_existent")));
325 TEST(HttpFsDirTest, ParseManifest) {
326 StringMap_t args;
327 off_t result_size = 0;
329 HttpFsForTesting fs(args, NULL);
331 // Multiple consecutive newlines or spaces should be ignored.
332 char manifest[] = "-r-- 123 /mydir/foo\n\n-rw- 234 /thatdir/bar\n";
333 ASSERT_EQ(0, fs.ParseManifest(manifest));
335 ScopedNode root;
336 EXPECT_EQ(0, fs.FindOrCreateDir(Path("/"), &root));
337 ASSERT_NE((Node*)NULL, root.get());
338 EXPECT_EQ(2, root->ChildCount());
340 ScopedNode dir;
341 EXPECT_EQ(0, fs.FindOrCreateDir(Path("/mydir"), &dir));
342 ASSERT_NE((Node*)NULL, dir.get());
343 EXPECT_EQ(1, dir->ChildCount());
345 Node* node = (*fs.GetNodeCacheForTesting())["/mydir/foo"].get();
346 EXPECT_NE((Node*)NULL, node);
347 EXPECT_EQ(0, node->GetSize(&result_size));
348 EXPECT_EQ(123, result_size);
350 // Since these files are cached thanks to the manifest, we can open them
351 // without accessing the PPAPI URL API.
352 ScopedNode foo;
353 ASSERT_EQ(0, fs.Open(Path("/mydir/foo"), O_RDONLY, &foo));
355 ScopedNode bar;
356 ASSERT_EQ(0, fs.Open(Path("/thatdir/bar"), O_RDWR, &bar));
358 struct stat sfoo;
359 struct stat sbar;
361 EXPECT_FALSE(foo->GetStat(&sfoo));
362 EXPECT_FALSE(bar->GetStat(&sbar));
364 EXPECT_EQ(123, sfoo.st_size);
365 EXPECT_EQ(S_IFREG | S_IRALL, sfoo.st_mode);
367 EXPECT_EQ(234, sbar.st_size);
368 EXPECT_EQ(S_IFREG | S_IRALL | S_IWALL, sbar.st_mode);
371 TEST(HttpFsBlobUrlTest, Basic) {
372 const char* kUrl =
373 "blob:http%3A//example.com/6b87a5a6-713e-46a4-9f0c-78066406455d";
374 FakePepperInterfaceURLLoader ppapi;
375 ASSERT_TRUE(ppapi.server_template()->SetBlobEntity(kUrl, "", NULL));
377 StringMap_t args;
378 args["SOURCE"] = kUrl;
380 HttpFsForTesting fs(args, &ppapi);
382 // We have to read from the mount root to read a Blob URL.
383 ASSERT_EQ(0, fs.Access(Path("/"), R_OK));
384 ASSERT_EQ(EACCES, fs.Access(Path("/"), W_OK));
385 ASSERT_EQ(EACCES, fs.Access(Path("/"), X_OK));
387 // Any other path will fail.
388 ScopedNode foo;
389 ASSERT_EQ(ENOENT, fs.Access(Path(""), R_OK));
390 ASSERT_EQ(ENOENT, fs.Access(Path("."), R_OK));
391 ASSERT_EQ(ENOENT, fs.Access(Path("blah"), R_OK));