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