blob: 1eabdd03e4d23481ce1e61492c0e2184f28b1d26 [file] [log] [blame]
Ben Murdochca12bfa2013-07-23 11:17:05 +01001// Copyright (c) 2012 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.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00004
5#include <errno.h>
6#include <fcntl.h>
7#include <pthread.h>
Ben Murdochbb1529c2013-08-08 10:24:53 +01008#include <stdio.h>
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00009#include <sys/stat.h>
10
11#include <map>
12#include <string>
13
Ben Murdocheb525c52013-07-10 11:40:50 +010014#include "gmock/gmock.h"
15#include "gtest/gtest.h"
16
17#include "mount_mock.h"
18#include "mount_node_mock.h"
19
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000020#include "nacl_io/kernel_intercept.h"
21#include "nacl_io/kernel_proxy.h"
22#include "nacl_io/mount.h"
23#include "nacl_io/mount_mem.h"
24#include "nacl_io/osmman.h"
25#include "nacl_io/path.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010026#include "nacl_io/typed_mount_factory.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000027
Ben Murdochca12bfa2013-07-23 11:17:05 +010028using namespace nacl_io;
29using namespace sdk_util;
30
Ben Murdocheb525c52013-07-10 11:40:50 +010031using ::testing::_;
32using ::testing::DoAll;
33using ::testing::Invoke;
34using ::testing::Return;
35using ::testing::SaveArg;
36using ::testing::SetArgPointee;
37using ::testing::StrEq;
38using ::testing::WithArgs;
39
40namespace {
41
42class KernelProxyFriend : public KernelProxy {
43 public:
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010044 Mount* RootMount() {
45 ScopedMount mnt;
46 Path path;
47
48 AcquireMountAndRelPath("/", &mnt, &path);
49 return mnt.get();
50 }
Ben Murdocheb525c52013-07-10 11:40:50 +010051};
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000052
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000053class KernelProxyTest : public ::testing::Test {
54 public:
Ben Murdocheb525c52013-07-10 11:40:50 +010055 KernelProxyTest() : kp_(new KernelProxyFriend) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000056 ki_init(kp_);
57 // Unmount the passthrough FS and mount a memfs.
58 EXPECT_EQ(0, kp_->umount("/"));
59 EXPECT_EQ(0, kp_->mount("", "/", "memfs", 0, NULL));
60 }
61
62 ~KernelProxyTest() {
63 ki_uninit();
64 delete kp_;
65 }
66
Ben Murdocheb525c52013-07-10 11:40:50 +010067 protected:
68 KernelProxyFriend* kp_;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000069};
70
Ben Murdocheb525c52013-07-10 11:40:50 +010071} // namespace
72
73TEST_F(KernelProxyTest, FileLeak) {
74 const size_t buffer_size = 1024;
75 char filename[128];
76 int file_num;
77 int garbage[buffer_size];
78
79 MountMem* mount = (MountMem*)kp_->RootMount();
80 ScopedMountNode root;
81
82 EXPECT_EQ(0, mount->Open(Path("/"), O_RDONLY, &root));
83 EXPECT_EQ(0, root->ChildCount());
84
85 for (file_num = 0; file_num < 4096; file_num++) {
86 sprintf(filename, "/foo%i.tmp", file_num++);
87 FILE* f = fopen(filename, "w");
88 EXPECT_NE((FILE*)0, f);
89 EXPECT_EQ(1, root->ChildCount());
90 EXPECT_EQ(buffer_size, fwrite(garbage, 1, buffer_size, f));
91 fclose(f);
92 EXPECT_EQ(0, remove(filename));
93 }
94 EXPECT_EQ(0, root->ChildCount());
95}
96
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000097TEST_F(KernelProxyTest, WorkingDirectory) {
98 char text[1024];
99
100 text[0] = 0;
101 ki_getcwd(text, sizeof(text));
102 EXPECT_STREQ("/", text);
103
104 char* alloc = ki_getwd(NULL);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100105 EXPECT_EQ((char*)NULL, alloc);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000106 EXPECT_EQ(EFAULT, errno);
107
108 text[0] = 0;
109 alloc = ki_getwd(text);
110 EXPECT_STREQ("/", alloc);
111
112 EXPECT_EQ(-1, ki_chdir("/foo"));
113 EXPECT_EQ(ENOENT, errno);
114
115 EXPECT_EQ(0, ki_chdir("/"));
116
117 EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE));
118 EXPECT_EQ(-1, ki_mkdir("/foo", S_IREAD | S_IWRITE));
119 EXPECT_EQ(EEXIST, errno);
120
121 memset(text, 0, sizeof(text));
122 EXPECT_EQ(0, ki_chdir("foo"));
123 EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
124 EXPECT_STREQ("/foo", text);
125
126 memset(text, 0, sizeof(text));
127 EXPECT_EQ(-1, ki_chdir("foo"));
128 EXPECT_EQ(ENOENT, errno);
129 EXPECT_EQ(0, ki_chdir(".."));
130 EXPECT_EQ(0, ki_chdir("/foo"));
131 EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
132 EXPECT_STREQ("/foo", text);
133}
134
135TEST_F(KernelProxyTest, MemMountIO) {
136 char text[1024];
137 int fd1, fd2, fd3;
138 int len;
139
Ben Murdoch58e6fbe2013-07-26 10:20:38 +0100140 // Fail to delete non existant "/foo"
141 EXPECT_EQ(-1, ki_rmdir("/foo"));
142 EXPECT_EQ(ENOENT, errno);
143
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000144 // Create "/foo"
145 EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE));
Ben Murdoch58e6fbe2013-07-26 10:20:38 +0100146 EXPECT_EQ(-1, ki_mkdir("/foo", S_IREAD | S_IWRITE));
147 EXPECT_EQ(EEXIST, errno);
148
149 // Delete "/foo"
150 EXPECT_EQ(0, ki_rmdir("/foo"));
151
152 // Recreate "/foo"
153 EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000154
155 // Fail to open "/foo/bar"
156 EXPECT_EQ(-1, ki_open("/foo/bar", O_RDONLY));
157 EXPECT_EQ(ENOENT, errno);
158
159 // Create bar "/foo/bar"
160 fd1 = ki_open("/foo/bar", O_RDONLY | O_CREAT);
161 EXPECT_NE(-1, fd1);
162
163 // Open (optionally create) bar "/foo/bar"
164 fd2 = ki_open("/foo/bar", O_RDONLY | O_CREAT);
165 EXPECT_NE(-1, fd2);
166
167 // Fail to exclusively create bar "/foo/bar"
168 EXPECT_EQ(-1, ki_open("/foo/bar", O_RDONLY | O_CREAT | O_EXCL));
169 EXPECT_EQ(EEXIST, errno);
170
171 // Write hello and world to same node with different descriptors
172 // so that we overwrite each other
173 EXPECT_EQ(5, ki_write(fd2, "WORLD", 5));
174 EXPECT_EQ(5, ki_write(fd1, "HELLO", 5));
175
176 fd3 = ki_open("/foo/bar", O_WRONLY);
177 EXPECT_NE(-1, fd3);
178
179 len = ki_read(fd3, text, sizeof(text));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100180 if (len > 0)
181 text[len] = 0;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000182 EXPECT_EQ(5, len);
183 EXPECT_STREQ("HELLO", text);
184 EXPECT_EQ(0, ki_close(fd1));
185 EXPECT_EQ(0, ki_close(fd2));
186
187 fd1 = ki_open("/foo/bar", O_WRONLY | O_APPEND);
188 EXPECT_NE(-1, fd1);
189 EXPECT_EQ(5, ki_write(fd1, "WORLD", 5));
190
191 len = ki_read(fd3, text, sizeof(text));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100192 if (len >= 0)
193 text[len] = 0;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000194
195 EXPECT_EQ(5, len);
196 EXPECT_STREQ("WORLD", text);
197
198 fd2 = ki_open("/foo/bar", O_RDONLY);
199 EXPECT_NE(-1, fd2);
200 len = ki_read(fd2, text, sizeof(text));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100201 if (len > 0)
202 text[len] = 0;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000203 EXPECT_EQ(10, len);
204 EXPECT_STREQ("HELLOWORLD", text);
205}
206
207TEST_F(KernelProxyTest, MemMountLseek) {
208 int fd = ki_open("/foo", O_CREAT | O_RDWR);
209 EXPECT_EQ(9, ki_write(fd, "Some text", 9));
210
211 EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
212 EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_END));
213 EXPECT_EQ(-1, ki_lseek(fd, -1, SEEK_SET));
214 EXPECT_EQ(EINVAL, errno);
215
216 // Seek past end of file.
217 EXPECT_EQ(13, ki_lseek(fd, 13, SEEK_SET));
218 char buffer[4];
219 memset(&buffer[0], 0xfe, 4);
220 EXPECT_EQ(9, ki_lseek(fd, -4, SEEK_END));
Ben Murdocheb525c52013-07-10 11:40:50 +0100221 EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000222 EXPECT_EQ(4, ki_read(fd, &buffer[0], 4));
223 EXPECT_EQ(0, memcmp("\0\0\0\0", buffer, 4));
224}
225
226TEST_F(KernelProxyTest, CloseTwice) {
227 int fd = ki_open("/foo", O_CREAT | O_RDWR);
228 EXPECT_EQ(9, ki_write(fd, "Some text", 9));
229
230 int fd2 = ki_dup(fd);
231 EXPECT_NE(-1, fd2);
232
233 EXPECT_EQ(0, ki_close(fd));
234 EXPECT_EQ(0, ki_close(fd2));
235}
236
237TEST_F(KernelProxyTest, MemMountDup) {
238 int fd = ki_open("/foo", O_CREAT | O_RDWR);
239
240 int dup_fd = ki_dup(fd);
241 EXPECT_NE(-1, dup_fd);
242
243 EXPECT_EQ(9, ki_write(fd, "Some text", 9));
244 EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
245 EXPECT_EQ(9, ki_lseek(dup_fd, 0, SEEK_CUR));
246
247 int dup2_fd = 123;
248 EXPECT_EQ(dup2_fd, ki_dup2(fd, dup2_fd));
249 EXPECT_EQ(9, ki_lseek(dup2_fd, 0, SEEK_CUR));
250
251 int new_fd = ki_open("/bar", O_CREAT | O_RDWR);
252
253 EXPECT_EQ(fd, ki_dup2(new_fd, fd));
254 // fd, new_fd -> "/bar"
255 // dup_fd, dup2_fd -> "/foo"
256
257 // We should still be able to write to dup_fd (i.e. it should not be closed).
258 EXPECT_EQ(4, ki_write(dup_fd, "more", 4));
259
260 EXPECT_EQ(0, ki_close(dup2_fd));
261 // fd, new_fd -> "/bar"
262 // dup_fd -> "/foo"
263
264 EXPECT_EQ(dup_fd, ki_dup2(fd, dup_fd));
265 // fd, new_fd, dup_fd -> "/bar"
266}
267
Ben Murdocheb525c52013-07-10 11:40:50 +0100268namespace {
269
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000270StringMap_t g_StringMap;
271
272class MountMockInit : public MountMem {
273 public:
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100274 virtual Error Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000275 g_StringMap = args;
276 if (args.find("false") != args.end())
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100277 return EINVAL;
278 return 0;
279 }
Ben Murdocheb525c52013-07-10 11:40:50 +0100280
281 friend class TypedMountFactory<MountMockInit>;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000282};
283
284class KernelProxyMountMock : public KernelProxy {
285 virtual void Init(PepperInterface* ppapi) {
286 KernelProxy::Init(NULL);
Ben Murdocheb525c52013-07-10 11:40:50 +0100287 factories_["initfs"] = new TypedMountFactory<MountMockInit>;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000288 }
289};
290
291class KernelProxyMountTest : public ::testing::Test {
292 public:
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100293 KernelProxyMountTest() : kp_(new KernelProxyMountMock) { ki_init(kp_); }
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000294
295 ~KernelProxyMountTest() {
296 ki_uninit();
297 delete kp_;
298 }
299
300 private:
301 KernelProxy* kp_;
302};
303
Ben Murdocheb525c52013-07-10 11:40:50 +0100304} // namespace
305
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000306TEST_F(KernelProxyMountTest, MountInit) {
307 int res1 = ki_mount("/", "/mnt1", "initfs", 0, "false,foo=bar");
308
309 EXPECT_EQ("bar", g_StringMap["foo"]);
310 EXPECT_EQ(-1, res1);
311 EXPECT_EQ(EINVAL, errno);
312
313 int res2 = ki_mount("/", "/mnt2", "initfs", 0, "true,bar=foo,x=y");
314 EXPECT_NE(-1, res2);
315 EXPECT_EQ("y", g_StringMap["x"]);
316}
317
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000318namespace {
319
320int g_MMapCount = 0;
321
322class MountNodeMockMMap : public MountNode {
323 public:
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100324 MountNodeMockMMap(Mount* mount) : MountNode(mount), node_mmap_count_(0) {
325 EXPECT_EQ(0, Init(0));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000326 }
327
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100328 virtual Error MMap(void* addr,
329 size_t length,
330 int prot,
331 int flags,
332 size_t offset,
333 void** out_addr) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000334 node_mmap_count_++;
335 switch (g_MMapCount++) {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100336 case 0:
337 *out_addr = reinterpret_cast<void*>(0x1000);
338 break;
339 case 1:
340 *out_addr = reinterpret_cast<void*>(0x2000);
341 break;
342 case 2:
343 *out_addr = reinterpret_cast<void*>(0x3000);
344 break;
345 default:
346 return EPERM;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000347 }
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100348
349 return 0;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000350 }
351
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000352 private:
353 int node_mmap_count_;
354};
355
356class MountMockMMap : public Mount {
357 public:
Ben Murdocheb525c52013-07-10 11:40:50 +0100358 virtual Error Access(const Path& path, int a_mode) { return 0; }
359 virtual Error Open(const Path& path, int mode, ScopedMountNode* out_node) {
360 out_node->reset(new MountNodeMockMMap(this));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100361 return 0;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000362 }
363
Ben Murdocheb525c52013-07-10 11:40:50 +0100364 virtual Error OpenResource(const Path& path, ScopedMountNode* out_node) {
365 out_node->reset(NULL);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100366 return ENOSYS;
367 }
368 virtual Error Unlink(const Path& path) { return ENOSYS; }
369 virtual Error Mkdir(const Path& path, int permissions) { return ENOSYS; }
370 virtual Error Rmdir(const Path& path) { return ENOSYS; }
371 virtual Error Remove(const Path& path) { return ENOSYS; }
Ben Murdocheb525c52013-07-10 11:40:50 +0100372
373 friend class TypedMountFactory<MountMockMMap>;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000374};
375
376class KernelProxyMockMMap : public KernelProxy {
377 virtual void Init(PepperInterface* ppapi) {
378 KernelProxy::Init(NULL);
Ben Murdocheb525c52013-07-10 11:40:50 +0100379 factories_["mmapfs"] = new TypedMountFactory<MountMockMMap>;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000380 }
381};
382
383class KernelProxyMMapTest : public ::testing::Test {
384 public:
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100385 KernelProxyMMapTest() : kp_(new KernelProxyMockMMap) { ki_init(kp_); }
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000386
387 ~KernelProxyMMapTest() {
388 ki_uninit();
389 delete kp_;
390 }
391
392 private:
393 KernelProxy* kp_;
394};
395
396} // namespace
397
398TEST_F(KernelProxyMMapTest, MMap) {
399 EXPECT_EQ(0, ki_umount("/"));
400 EXPECT_EQ(0, ki_mount("", "/", "mmapfs", 0, NULL));
401 int fd = ki_open("/file", O_RDWR | O_CREAT);
402 EXPECT_NE(-1, fd);
403
404 void* addr1 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
405 EXPECT_EQ(reinterpret_cast<void*>(0x1000), addr1);
406 EXPECT_EQ(1, g_MMapCount);
407
408 void* addr2 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
409 EXPECT_EQ(reinterpret_cast<void*>(0x2000), addr2);
410 EXPECT_EQ(2, g_MMapCount);
411
412 void* addr3 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
413 EXPECT_EQ(reinterpret_cast<void*>(0x3000), addr3);
414 EXPECT_EQ(3, g_MMapCount);
415
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000416 ki_close(fd);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000417
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100418 // We no longer track mmap'd regions, so munmap is a no-op.
419 EXPECT_EQ(0, ki_munmap(reinterpret_cast<void*>(0x1000), 0x2800));
420 // We don't track regions, so the mmap count hasn't changed.
421 EXPECT_EQ(3, g_MMapCount);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000422}
Ben Murdocheb525c52013-07-10 11:40:50 +0100423
424namespace {
425
426class SingletonMountFactory : public MountFactory {
427 public:
428 SingletonMountFactory(const ScopedMount& mount) : mount_(mount) {}
429
430 virtual Error CreateMount(int dev,
431 StringMap_t& args,
432 PepperInterface* ppapi,
433 ScopedMount* out_mount) {
434 *out_mount = mount_;
435 return 0;
436 }
437
438 private:
439 ScopedMount mount_;
440};
441
442class KernelProxyError : public KernelProxy {
443 public:
444 KernelProxyError() : mnt_(new MountMock) {}
445
446 virtual void Init(PepperInterface* ppapi) {
447 KernelProxy::Init(ppapi);
448 factories_["testfs"] = new SingletonMountFactory(mnt_);
449
450 EXPECT_CALL(*mnt_, Destroy()).Times(1);
451 }
452
453 ScopedRef<MountMock> mnt() { return mnt_; }
454
455 private:
456 ScopedRef<MountMock> mnt_;
457};
458
459class KernelProxyErrorTest : public ::testing::Test {
460 public:
461 KernelProxyErrorTest() : kp_(new KernelProxyError) {
462 ki_init(kp_);
463 // Unmount the passthrough FS and mount a testfs.
464 EXPECT_EQ(0, kp_->umount("/"));
465 EXPECT_EQ(0, kp_->mount("", "/", "testfs", 0, NULL));
466 }
467
468 ~KernelProxyErrorTest() {
469 ki_uninit();
470 delete kp_;
471 }
472
473 ScopedRef<MountMock> mnt() { return kp_->mnt(); }
474
475 private:
476 KernelProxyError* kp_;
477};
478
479} // namespace
480
481TEST_F(KernelProxyErrorTest, WriteError) {
482 ScopedRef<MountMock> mock_mnt(mnt());
483 ScopedRef<MountNodeMock> mock_node(new MountNodeMock(&*mock_mnt));
484 EXPECT_CALL(*mock_mnt, Open(_, _, _))
485 .WillOnce(DoAll(SetArgPointee<2>(mock_node), Return(0)));
486
487 EXPECT_CALL(*mock_node, Write(_, _, _, _))
488 .WillOnce(DoAll(SetArgPointee<3>(0), // Wrote 0 bytes.
489 Return(1234))); // Returned error 1234.
490
491 EXPECT_CALL(*mock_node, Destroy()).Times(1);
492
493 int fd = ki_open("/dummy", O_WRONLY);
494 EXPECT_NE(0, fd);
495
496 char buf[20];
497 EXPECT_EQ(-1, ki_write(fd, &buf[0], 20));
498 // The Mount should be able to return whatever error it wants and have it
499 // propagate through.
500 EXPECT_EQ(1234, errno);
501}
502
503TEST_F(KernelProxyErrorTest, ReadError) {
504 ScopedRef<MountMock> mock_mnt(mnt());
505 ScopedRef<MountNodeMock> mock_node(new MountNodeMock(&*mock_mnt));
506 EXPECT_CALL(*mock_mnt, Open(_, _, _))
507 .WillOnce(DoAll(SetArgPointee<2>(mock_node), Return(0)));
508
509 EXPECT_CALL(*mock_node, Read(_, _, _, _))
510 .WillOnce(DoAll(SetArgPointee<3>(0), // Read 0 bytes.
511 Return(1234))); // Returned error 1234.
512
513 EXPECT_CALL(*mock_node, Destroy()).Times(1);
514
515 int fd = ki_open("/dummy", O_RDONLY);
516 EXPECT_NE(0, fd);
517
518 char buf[20];
519 EXPECT_EQ(-1, ki_read(fd, &buf[0], 20));
520 // The Mount should be able to return whatever error it wants and have it
521 // propagate through.
522 EXPECT_EQ(1234, errno);
523}
Ben Murdochbb1529c2013-08-08 10:24:53 +0100524