Ben Murdoch | ca12bfa | 2013-07-23 11:17:05 +0100 | [diff] [blame] | 1 | // 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) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 4 | |
| 5 | #include <errno.h> |
| 6 | #include <fcntl.h> |
| 7 | #include <pthread.h> |
Ben Murdoch | bb1529c | 2013-08-08 10:24:53 +0100 | [diff] [blame^] | 8 | #include <stdio.h> |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 9 | #include <sys/stat.h> |
| 10 | |
| 11 | #include <map> |
| 12 | #include <string> |
| 13 | |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 14 | #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) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 20 | #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 Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 26 | #include "nacl_io/typed_mount_factory.h" |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 27 | |
Ben Murdoch | ca12bfa | 2013-07-23 11:17:05 +0100 | [diff] [blame] | 28 | using namespace nacl_io; |
| 29 | using namespace sdk_util; |
| 30 | |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 31 | using ::testing::_; |
| 32 | using ::testing::DoAll; |
| 33 | using ::testing::Invoke; |
| 34 | using ::testing::Return; |
| 35 | using ::testing::SaveArg; |
| 36 | using ::testing::SetArgPointee; |
| 37 | using ::testing::StrEq; |
| 38 | using ::testing::WithArgs; |
| 39 | |
| 40 | namespace { |
| 41 | |
| 42 | class KernelProxyFriend : public KernelProxy { |
| 43 | public: |
Ben Murdoch | 7dbb3d5 | 2013-07-17 14:55:54 +0100 | [diff] [blame] | 44 | Mount* RootMount() { |
| 45 | ScopedMount mnt; |
| 46 | Path path; |
| 47 | |
| 48 | AcquireMountAndRelPath("/", &mnt, &path); |
| 49 | return mnt.get(); |
| 50 | } |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 51 | }; |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 52 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 53 | class KernelProxyTest : public ::testing::Test { |
| 54 | public: |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 55 | KernelProxyTest() : kp_(new KernelProxyFriend) { |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 56 | 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 Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 67 | protected: |
| 68 | KernelProxyFriend* kp_; |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 69 | }; |
| 70 | |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 71 | } // namespace |
| 72 | |
| 73 | TEST_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) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 97 | TEST_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) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 105 | EXPECT_EQ((char*)NULL, alloc); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 106 | 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 | |
| 135 | TEST_F(KernelProxyTest, MemMountIO) { |
| 136 | char text[1024]; |
| 137 | int fd1, fd2, fd3; |
| 138 | int len; |
| 139 | |
Ben Murdoch | 58e6fbe | 2013-07-26 10:20:38 +0100 | [diff] [blame] | 140 | // Fail to delete non existant "/foo" |
| 141 | EXPECT_EQ(-1, ki_rmdir("/foo")); |
| 142 | EXPECT_EQ(ENOENT, errno); |
| 143 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 144 | // Create "/foo" |
| 145 | EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE)); |
Ben Murdoch | 58e6fbe | 2013-07-26 10:20:38 +0100 | [diff] [blame] | 146 | 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) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 154 | |
| 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) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 180 | if (len > 0) |
| 181 | text[len] = 0; |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 182 | 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) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 192 | if (len >= 0) |
| 193 | text[len] = 0; |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 194 | |
| 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) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 201 | if (len > 0) |
| 202 | text[len] = 0; |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 203 | EXPECT_EQ(10, len); |
| 204 | EXPECT_STREQ("HELLOWORLD", text); |
| 205 | } |
| 206 | |
| 207 | TEST_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 Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 221 | EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_CUR)); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 222 | EXPECT_EQ(4, ki_read(fd, &buffer[0], 4)); |
| 223 | EXPECT_EQ(0, memcmp("\0\0\0\0", buffer, 4)); |
| 224 | } |
| 225 | |
| 226 | TEST_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 | |
| 237 | TEST_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 Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 268 | namespace { |
| 269 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 270 | StringMap_t g_StringMap; |
| 271 | |
| 272 | class MountMockInit : public MountMem { |
| 273 | public: |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 274 | virtual Error Init(int dev, StringMap_t& args, PepperInterface* ppapi) { |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 275 | g_StringMap = args; |
| 276 | if (args.find("false") != args.end()) |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 277 | return EINVAL; |
| 278 | return 0; |
| 279 | } |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 280 | |
| 281 | friend class TypedMountFactory<MountMockInit>; |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 282 | }; |
| 283 | |
| 284 | class KernelProxyMountMock : public KernelProxy { |
| 285 | virtual void Init(PepperInterface* ppapi) { |
| 286 | KernelProxy::Init(NULL); |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 287 | factories_["initfs"] = new TypedMountFactory<MountMockInit>; |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 288 | } |
| 289 | }; |
| 290 | |
| 291 | class KernelProxyMountTest : public ::testing::Test { |
| 292 | public: |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 293 | KernelProxyMountTest() : kp_(new KernelProxyMountMock) { ki_init(kp_); } |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 294 | |
| 295 | ~KernelProxyMountTest() { |
| 296 | ki_uninit(); |
| 297 | delete kp_; |
| 298 | } |
| 299 | |
| 300 | private: |
| 301 | KernelProxy* kp_; |
| 302 | }; |
| 303 | |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 304 | } // namespace |
| 305 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 306 | TEST_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) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 318 | namespace { |
| 319 | |
| 320 | int g_MMapCount = 0; |
| 321 | |
| 322 | class MountNodeMockMMap : public MountNode { |
| 323 | public: |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 324 | MountNodeMockMMap(Mount* mount) : MountNode(mount), node_mmap_count_(0) { |
| 325 | EXPECT_EQ(0, Init(0)); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 326 | } |
| 327 | |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 328 | 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) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 334 | node_mmap_count_++; |
| 335 | switch (g_MMapCount++) { |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 336 | 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) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 347 | } |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 348 | |
| 349 | return 0; |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 350 | } |
| 351 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 352 | private: |
| 353 | int node_mmap_count_; |
| 354 | }; |
| 355 | |
| 356 | class MountMockMMap : public Mount { |
| 357 | public: |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 358 | 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) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 361 | return 0; |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 362 | } |
| 363 | |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 364 | virtual Error OpenResource(const Path& path, ScopedMountNode* out_node) { |
| 365 | out_node->reset(NULL); |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 366 | 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 Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 372 | |
| 373 | friend class TypedMountFactory<MountMockMMap>; |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 374 | }; |
| 375 | |
| 376 | class KernelProxyMockMMap : public KernelProxy { |
| 377 | virtual void Init(PepperInterface* ppapi) { |
| 378 | KernelProxy::Init(NULL); |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 379 | factories_["mmapfs"] = new TypedMountFactory<MountMockMMap>; |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 380 | } |
| 381 | }; |
| 382 | |
| 383 | class KernelProxyMMapTest : public ::testing::Test { |
| 384 | public: |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 385 | KernelProxyMMapTest() : kp_(new KernelProxyMockMMap) { ki_init(kp_); } |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 386 | |
| 387 | ~KernelProxyMMapTest() { |
| 388 | ki_uninit(); |
| 389 | delete kp_; |
| 390 | } |
| 391 | |
| 392 | private: |
| 393 | KernelProxy* kp_; |
| 394 | }; |
| 395 | |
| 396 | } // namespace |
| 397 | |
| 398 | TEST_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) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 416 | ki_close(fd); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 417 | |
Torne (Richard Coles) | 90dce4d | 2013-05-29 14:40:03 +0100 | [diff] [blame] | 418 | // 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) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 422 | } |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 423 | |
| 424 | namespace { |
| 425 | |
| 426 | class 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 | |
| 442 | class 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 | |
| 459 | class 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 | |
| 481 | TEST_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 | |
| 503 | TEST_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 Murdoch | bb1529c | 2013-08-08 10:24:53 +0100 | [diff] [blame^] | 524 | |