Home | History | Annotate | Download | only in posix
      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 "base/posix/file_descriptor_shuffle.h"
      6 #include "testing/gtest/include/gtest/gtest.h"
      7 
      8 namespace {
      9 
     10 // 'Duplicated' file descriptors start at this number
     11 const int kDuplicateBase = 1000;
     12 
     13 }  // namespace
     14 
     15 namespace base {
     16 
     17 struct Action {
     18   enum Type {
     19     CLOSE,
     20     MOVE,
     21     DUPLICATE,
     22   };
     23 
     24   Action(Type in_type, int in_fd1, int in_fd2 = -1)
     25       : type(in_type),
     26         fd1(in_fd1),
     27         fd2(in_fd2) {
     28   }
     29 
     30   bool operator==(const Action& other) const {
     31     return other.type == type &&
     32            other.fd1 == fd1 &&
     33            other.fd2 == fd2;
     34   }
     35 
     36   Type type;
     37   int fd1;
     38   int fd2;
     39 };
     40 
     41 class InjectionTracer : public InjectionDelegate {
     42  public:
     43   InjectionTracer()
     44       : next_duplicate_(kDuplicateBase) {
     45   }
     46 
     47   virtual bool Duplicate(int* result, int fd) OVERRIDE {
     48     *result = next_duplicate_++;
     49     actions_.push_back(Action(Action::DUPLICATE, *result, fd));
     50     return true;
     51   }
     52 
     53   virtual bool Move(int src, int dest) OVERRIDE {
     54     actions_.push_back(Action(Action::MOVE, src, dest));
     55     return true;
     56   }
     57 
     58   virtual void Close(int fd) OVERRIDE {
     59     actions_.push_back(Action(Action::CLOSE, fd));
     60   }
     61 
     62   const std::vector<Action>& actions() const { return actions_; }
     63 
     64  private:
     65   int next_duplicate_;
     66   std::vector<Action> actions_;
     67 };
     68 
     69 TEST(FileDescriptorShuffleTest, Empty) {
     70   InjectiveMultimap map;
     71   InjectionTracer tracer;
     72 
     73   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
     74   EXPECT_EQ(0u, tracer.actions().size());
     75 }
     76 
     77 TEST(FileDescriptorShuffleTest, Noop) {
     78   InjectiveMultimap map;
     79   InjectionTracer tracer;
     80   map.push_back(InjectionArc(0, 0, false));
     81 
     82   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
     83   EXPECT_EQ(0u, tracer.actions().size());
     84 }
     85 
     86 TEST(FileDescriptorShuffleTest, NoopAndClose) {
     87   InjectiveMultimap map;
     88   InjectionTracer tracer;
     89   map.push_back(InjectionArc(0, 0, true));
     90 
     91   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
     92   EXPECT_EQ(0u, tracer.actions().size());
     93 }
     94 
     95 TEST(FileDescriptorShuffleTest, Simple1) {
     96   InjectiveMultimap map;
     97   InjectionTracer tracer;
     98   map.push_back(InjectionArc(0, 1, false));
     99 
    100   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
    101   ASSERT_EQ(1u, tracer.actions().size());
    102   EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
    103 }
    104 
    105 TEST(FileDescriptorShuffleTest, Simple2) {
    106   InjectiveMultimap map;
    107   InjectionTracer tracer;
    108   map.push_back(InjectionArc(0, 1, false));
    109   map.push_back(InjectionArc(2, 3, false));
    110 
    111   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
    112   ASSERT_EQ(2u, tracer.actions().size());
    113   EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
    114   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 2, 3));
    115 }
    116 
    117 TEST(FileDescriptorShuffleTest, Simple3) {
    118   InjectiveMultimap map;
    119   InjectionTracer tracer;
    120   map.push_back(InjectionArc(0, 1, true));
    121 
    122   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
    123   ASSERT_EQ(2u, tracer.actions().size());
    124   EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
    125   EXPECT_TRUE(tracer.actions()[1] == Action(Action::CLOSE, 0));
    126 }
    127 
    128 TEST(FileDescriptorShuffleTest, Simple4) {
    129   InjectiveMultimap map;
    130   InjectionTracer tracer;
    131   map.push_back(InjectionArc(10, 0, true));
    132   map.push_back(InjectionArc(1, 1, true));
    133 
    134   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
    135   ASSERT_EQ(2u, tracer.actions().size());
    136   EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 10, 0));
    137   EXPECT_TRUE(tracer.actions()[1] == Action(Action::CLOSE, 10));
    138 }
    139 
    140 TEST(FileDescriptorShuffleTest, Cycle) {
    141   InjectiveMultimap map;
    142   InjectionTracer tracer;
    143   map.push_back(InjectionArc(0, 1, false));
    144   map.push_back(InjectionArc(1, 0, false));
    145 
    146   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
    147   ASSERT_EQ(4u, tracer.actions().size());
    148   EXPECT_TRUE(tracer.actions()[0] ==
    149               Action(Action::DUPLICATE, kDuplicateBase, 1));
    150   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
    151   EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0));
    152   EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase));
    153 }
    154 
    155 TEST(FileDescriptorShuffleTest, CycleAndClose1) {
    156   InjectiveMultimap map;
    157   InjectionTracer tracer;
    158   map.push_back(InjectionArc(0, 1, true));
    159   map.push_back(InjectionArc(1, 0, false));
    160 
    161   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
    162   ASSERT_EQ(4u, tracer.actions().size());
    163   EXPECT_TRUE(tracer.actions()[0] ==
    164               Action(Action::DUPLICATE, kDuplicateBase, 1));
    165   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
    166   EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0));
    167   EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase));
    168 }
    169 
    170 TEST(FileDescriptorShuffleTest, CycleAndClose2) {
    171   InjectiveMultimap map;
    172   InjectionTracer tracer;
    173   map.push_back(InjectionArc(0, 1, false));
    174   map.push_back(InjectionArc(1, 0, true));
    175 
    176   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
    177   ASSERT_EQ(4u, tracer.actions().size());
    178   EXPECT_TRUE(tracer.actions()[0] ==
    179               Action(Action::DUPLICATE, kDuplicateBase, 1));
    180   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
    181   EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0));
    182   EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase));
    183 }
    184 
    185 TEST(FileDescriptorShuffleTest, CycleAndClose3) {
    186   InjectiveMultimap map;
    187   InjectionTracer tracer;
    188   map.push_back(InjectionArc(0, 1, true));
    189   map.push_back(InjectionArc(1, 0, true));
    190 
    191   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
    192   ASSERT_EQ(4u, tracer.actions().size());
    193   EXPECT_TRUE(tracer.actions()[0] ==
    194               Action(Action::DUPLICATE, kDuplicateBase, 1));
    195   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
    196   EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0));
    197   EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase));
    198 }
    199 
    200 TEST(FileDescriptorShuffleTest, Fanout) {
    201   InjectiveMultimap map;
    202   InjectionTracer tracer;
    203   map.push_back(InjectionArc(0, 1, false));
    204   map.push_back(InjectionArc(0, 2, false));
    205 
    206   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
    207   ASSERT_EQ(2u, tracer.actions().size());
    208   EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
    209   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
    210 }
    211 
    212 TEST(FileDescriptorShuffleTest, FanoutAndClose1) {
    213   InjectiveMultimap map;
    214   InjectionTracer tracer;
    215   map.push_back(InjectionArc(0, 1, true));
    216   map.push_back(InjectionArc(0, 2, false));
    217 
    218   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
    219   ASSERT_EQ(3u, tracer.actions().size());
    220   EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
    221   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
    222   EXPECT_TRUE(tracer.actions()[2] == Action(Action::CLOSE, 0));
    223 }
    224 
    225 TEST(FileDescriptorShuffleTest, FanoutAndClose2) {
    226   InjectiveMultimap map;
    227   InjectionTracer tracer;
    228   map.push_back(InjectionArc(0, 1, false));
    229   map.push_back(InjectionArc(0, 2, true));
    230 
    231   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
    232   ASSERT_EQ(3u, tracer.actions().size());
    233   EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
    234   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
    235   EXPECT_TRUE(tracer.actions()[2] == Action(Action::CLOSE, 0));
    236 }
    237 
    238 TEST(FileDescriptorShuffleTest, FanoutAndClose3) {
    239   InjectiveMultimap map;
    240   InjectionTracer tracer;
    241   map.push_back(InjectionArc(0, 1, true));
    242   map.push_back(InjectionArc(0, 2, true));
    243 
    244   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
    245   ASSERT_EQ(3u, tracer.actions().size());
    246   EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
    247   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
    248   EXPECT_TRUE(tracer.actions()[2] == Action(Action::CLOSE, 0));
    249 }
    250 
    251 class FailingDelegate : public InjectionDelegate {
    252  public:
    253   virtual bool Duplicate(int* result, int fd) OVERRIDE {
    254     return false;
    255   }
    256 
    257   virtual bool Move(int src, int dest) OVERRIDE {
    258     return false;
    259   }
    260 
    261   virtual void Close(int fd) OVERRIDE {}
    262 };
    263 
    264 TEST(FileDescriptorShuffleTest, EmptyWithFailure) {
    265   InjectiveMultimap map;
    266   FailingDelegate failing;
    267 
    268   EXPECT_TRUE(PerformInjectiveMultimap(map, &failing));
    269 }
    270 
    271 TEST(FileDescriptorShuffleTest, NoopWithFailure) {
    272   InjectiveMultimap map;
    273   FailingDelegate failing;
    274   map.push_back(InjectionArc(0, 0, false));
    275 
    276   EXPECT_TRUE(PerformInjectiveMultimap(map, &failing));
    277 }
    278 
    279 TEST(FileDescriptorShuffleTest, Simple1WithFailure) {
    280   InjectiveMultimap map;
    281   FailingDelegate failing;
    282   map.push_back(InjectionArc(0, 1, false));
    283 
    284   EXPECT_FALSE(PerformInjectiveMultimap(map, &failing));
    285 }
    286 
    287 }  // namespace base
    288