Home | History | Annotate | Download | only in nacl_io_test
      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.
      4 
      5 #include <errno.h>
      6 #include <fcntl.h>
      7 #include <pthread.h>
      8 #include <sys/stat.h>
      9 
     10 #include <map>
     11 #include <string>
     12 
     13 #include "gtest/gtest.h"
     14 
     15 #include "nacl_io/filesystem.h"
     16 #include "nacl_io/kernel_handle.h"
     17 #include "nacl_io/kernel_object.h"
     18 #include "nacl_io/path.h"
     19 
     20 using namespace nacl_io;
     21 
     22 namespace {
     23 
     24 class NodeForTesting : public Node {
     25  public:
     26   explicit NodeForTesting(Filesystem* fs) : Node(fs) {}
     27 };
     28 
     29 class FilesystemForTesting : public Filesystem {
     30  public:
     31   FilesystemForTesting() {}
     32 
     33  public:
     34   Error Access(const Path& path, int a_mode) { return ENOSYS; }
     35   Error Open(const Path& path, int mode, ScopedNode* out_node) {
     36     out_node->reset(NULL);
     37     return ENOSYS;
     38   }
     39   Error Unlink(const Path& path) { return 0; }
     40   Error Mkdir(const Path& path, int permissions) { return 0; }
     41   Error Rmdir(const Path& path) { return 0; }
     42   Error Remove(const Path& path) { return 0; }
     43   Error Rename(const Path& path, const Path& newpath) { return 0; }
     44 };
     45 
     46 class KernelHandleForTesting : public KernelHandle {
     47  public:
     48   KernelHandleForTesting(const ScopedFilesystem& fs, const ScopedNode& node)
     49       : KernelHandle(fs, node) {}
     50 };
     51 
     52 class KernelObjectTest : public ::testing::Test {
     53  public:
     54   void SetUp() {
     55     fs.reset(new FilesystemForTesting());
     56     node.reset(new NodeForTesting(fs.get()));
     57   }
     58 
     59   void TearDown() {
     60     // fs is ref-counted, it doesn't need to be explicitly deleted.
     61     node.reset(NULL);
     62     fs.reset(NULL);
     63   }
     64 
     65   KernelObject proxy;
     66   ScopedFilesystem fs;
     67   ScopedNode node;
     68 };
     69 
     70 }  // namespace
     71 
     72 TEST_F(KernelObjectTest, Referencing) {
     73   // The filesystem and node should have 1 ref count at this point
     74   EXPECT_EQ(1, fs->RefCount());
     75   EXPECT_EQ(1, node->RefCount());
     76 
     77   // Pass the filesystem and node into a KernelHandle
     78   KernelHandle* raw_handle = new KernelHandleForTesting(fs, node);
     79   ScopedKernelHandle handle_a(raw_handle);
     80 
     81   // The filesystem and node should have 1 ref count at this point
     82   EXPECT_EQ(1, handle_a->RefCount());
     83   EXPECT_EQ(2, fs->RefCount());
     84   EXPECT_EQ(2, node->RefCount());
     85 
     86   ScopedKernelHandle handle_b = handle_a;
     87 
     88   // There should be two references to the KernelHandle, the filesystem and node
     89   // should be unchanged.
     90   EXPECT_EQ(2, handle_a->RefCount());
     91   EXPECT_EQ(2, handle_b->RefCount());
     92   EXPECT_EQ(handle_a.get(), handle_b.get());
     93   EXPECT_EQ(2, fs->RefCount());
     94   EXPECT_EQ(2, node->RefCount());
     95 
     96   // Allocating an FD should cause the KernelProxy to ref the handle and
     97   // the node and filesystem should be unchanged.
     98   int fd1 = proxy.AllocateFD(handle_a, "/example");
     99   EXPECT_EQ(3, handle_a->RefCount());
    100   EXPECT_EQ(2, fs->RefCount());
    101   EXPECT_EQ(2, node->RefCount());
    102 
    103   // If we "dup" the handle, we should bump the ref count on the handle
    104   int fd2 = proxy.AllocateFD(handle_b, "");
    105   EXPECT_EQ(4, handle_a->RefCount());
    106   EXPECT_EQ(2, fs->RefCount());
    107   EXPECT_EQ(2, node->RefCount());
    108 
    109   // Handles are expected to come out in order
    110   EXPECT_EQ(0, fd1);
    111   EXPECT_EQ(1, fd2);
    112 
    113   // Now we "free" the handles, since the proxy should hold them.
    114   handle_a.reset(NULL);
    115   handle_b.reset(NULL);
    116   EXPECT_EQ(2, fs->RefCount());
    117   EXPECT_EQ(2, node->RefCount());
    118 
    119   // We should find the handle by either fd
    120   EXPECT_EQ(0, proxy.AcquireHandle(fd1, &handle_a));
    121   EXPECT_EQ(0, proxy.AcquireHandle(fd2, &handle_b));
    122   EXPECT_EQ(raw_handle, handle_a.get());
    123   EXPECT_EQ(raw_handle, handle_b.get());
    124 
    125   EXPECT_EQ(4, handle_a->RefCount());
    126   EXPECT_EQ(2, fs->RefCount());
    127   EXPECT_EQ(2, node->RefCount());
    128 
    129   // A non existent fd should fail, and handleA should decrement as handleB
    130   // is released by the call.
    131   EXPECT_EQ(EBADF, proxy.AcquireHandle(-1, &handle_b));
    132   EXPECT_EQ(NULL, handle_b.get());
    133   EXPECT_EQ(3, handle_a->RefCount());
    134 
    135   EXPECT_EQ(EBADF, proxy.AcquireHandle(100, &handle_b));
    136   EXPECT_EQ(NULL, handle_b.get());
    137 
    138   // Now only the KernelProxy should reference the KernelHandle in the
    139   // FD to KernelHandle Map.
    140   handle_a.reset();
    141   handle_b.reset();
    142 
    143   EXPECT_EQ(2, raw_handle->RefCount());
    144   EXPECT_EQ(2, fs->RefCount());
    145   EXPECT_EQ(2, node->RefCount());
    146   proxy.FreeFD(fd2);
    147   EXPECT_EQ(1, raw_handle->RefCount());
    148   EXPECT_EQ(2, fs->RefCount());
    149   EXPECT_EQ(2, node->RefCount());
    150 
    151   proxy.FreeFD(fd1);
    152   EXPECT_EQ(1, fs->RefCount());
    153   EXPECT_EQ(1, node->RefCount());
    154 }
    155 
    156 TEST_F(KernelObjectTest, FreeAndReassignFD) {
    157   // The filesystem and node should have 1 ref count at this point
    158   EXPECT_EQ(1, fs->RefCount());
    159   EXPECT_EQ(1, node->RefCount());
    160 
    161   KernelHandle* raw_handle = new KernelHandleForTesting(fs, node);
    162   ScopedKernelHandle handle(raw_handle);
    163 
    164   EXPECT_EQ(2, fs->RefCount());
    165   EXPECT_EQ(2, node->RefCount());
    166   EXPECT_EQ(1, raw_handle->RefCount());
    167 
    168   proxy.AllocateFD(handle, "/example");
    169   EXPECT_EQ(2, fs->RefCount());
    170   EXPECT_EQ(2, node->RefCount());
    171   EXPECT_EQ(2, raw_handle->RefCount());
    172 
    173   proxy.FreeAndReassignFD(5, handle, "/example");
    174   EXPECT_EQ(2, fs->RefCount());
    175   EXPECT_EQ(2, node->RefCount());
    176   EXPECT_EQ(3, raw_handle->RefCount());
    177 
    178 
    179   handle.reset();
    180   EXPECT_EQ(2, raw_handle->RefCount());
    181 
    182   proxy.AcquireHandle(5, &handle);
    183   EXPECT_EQ(3, raw_handle->RefCount());
    184   EXPECT_EQ(raw_handle, handle.get());
    185 }
    186