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   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   bool Move(int src, int dest) override {
     54     actions_.push_back(Action(Action::MOVE, src, dest));
     55     return true;
     56   }
     57 
     58   void Close(int fd) override { actions_.push_back(Action(Action::CLOSE, fd)); }
     59 
     60   const std::vector<Action>& actions() const { return actions_; }
     61 
     62  private:
     63   int next_duplicate_;
     64   std::vector<Action> actions_;
     65 };
     66 
     67 TEST(FileDescriptorShuffleTest, Empty) {
     68   InjectiveMultimap map;
     69   InjectionTracer tracer;
     70 
     71   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
     72   EXPECT_EQ(0u, tracer.actions().size());
     73 }
     74 
     75 TEST(FileDescriptorShuffleTest, Noop) {
     76   InjectiveMultimap map;
     77   InjectionTracer tracer;
     78   map.push_back(InjectionArc(0, 0, false));
     79 
     80   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
     81   EXPECT_EQ(0u, tracer.actions().size());
     82 }
     83 
     84 TEST(FileDescriptorShuffleTest, NoopAndClose) {
     85   InjectiveMultimap map;
     86   InjectionTracer tracer;
     87   map.push_back(InjectionArc(0, 0, true));
     88 
     89   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
     90   EXPECT_EQ(0u, tracer.actions().size());
     91 }
     92 
     93 TEST(FileDescriptorShuffleTest, Simple1) {
     94   InjectiveMultimap map;
     95   InjectionTracer tracer;
     96   map.push_back(InjectionArc(0, 1, false));
     97 
     98   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
     99   ASSERT_EQ(1u, tracer.actions().size());
    100   EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
    101 }
    102 
    103 TEST(FileDescriptorShuffleTest, Simple2) {
    104   InjectiveMultimap map;
    105   InjectionTracer tracer;
    106   map.push_back(InjectionArc(0, 1, false));
    107   map.push_back(InjectionArc(2, 3, false));
    108 
    109   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
    110   ASSERT_EQ(2u, tracer.actions().size());
    111   EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
    112   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 2, 3));
    113 }
    114 
    115 TEST(FileDescriptorShuffleTest, Simple3) {
    116   InjectiveMultimap map;
    117   InjectionTracer tracer;
    118   map.push_back(InjectionArc(0, 1, true));
    119 
    120   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
    121   ASSERT_EQ(2u, tracer.actions().size());
    122   EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
    123   EXPECT_TRUE(tracer.actions()[1] == Action(Action::CLOSE, 0));
    124 }
    125 
    126 TEST(FileDescriptorShuffleTest, Simple4) {
    127   InjectiveMultimap map;
    128   InjectionTracer tracer;
    129   map.push_back(InjectionArc(10, 0, true));
    130   map.push_back(InjectionArc(1, 1, true));
    131 
    132   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
    133   ASSERT_EQ(2u, tracer.actions().size());
    134   EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 10, 0));
    135   EXPECT_TRUE(tracer.actions()[1] == Action(Action::CLOSE, 10));
    136 }
    137 
    138 TEST(FileDescriptorShuffleTest, Cycle) {
    139   InjectiveMultimap map;
    140   InjectionTracer tracer;
    141   map.push_back(InjectionArc(0, 1, false));
    142   map.push_back(InjectionArc(1, 0, false));
    143 
    144   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
    145   ASSERT_EQ(4u, tracer.actions().size());
    146   EXPECT_TRUE(tracer.actions()[0] ==
    147               Action(Action::DUPLICATE, kDuplicateBase, 1));
    148   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
    149   EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0));
    150   EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase));
    151 }
    152 
    153 TEST(FileDescriptorShuffleTest, CycleAndClose1) {
    154   InjectiveMultimap map;
    155   InjectionTracer tracer;
    156   map.push_back(InjectionArc(0, 1, true));
    157   map.push_back(InjectionArc(1, 0, false));
    158 
    159   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
    160   ASSERT_EQ(4u, tracer.actions().size());
    161   EXPECT_TRUE(tracer.actions()[0] ==
    162               Action(Action::DUPLICATE, kDuplicateBase, 1));
    163   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
    164   EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0));
    165   EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase));
    166 }
    167 
    168 TEST(FileDescriptorShuffleTest, CycleAndClose2) {
    169   InjectiveMultimap map;
    170   InjectionTracer tracer;
    171   map.push_back(InjectionArc(0, 1, false));
    172   map.push_back(InjectionArc(1, 0, true));
    173 
    174   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
    175   ASSERT_EQ(4u, tracer.actions().size());
    176   EXPECT_TRUE(tracer.actions()[0] ==
    177               Action(Action::DUPLICATE, kDuplicateBase, 1));
    178   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
    179   EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0));
    180   EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase));
    181 }
    182 
    183 TEST(FileDescriptorShuffleTest, CycleAndClose3) {
    184   InjectiveMultimap map;
    185   InjectionTracer tracer;
    186   map.push_back(InjectionArc(0, 1, true));
    187   map.push_back(InjectionArc(1, 0, true));
    188 
    189   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
    190   ASSERT_EQ(4u, tracer.actions().size());
    191   EXPECT_TRUE(tracer.actions()[0] ==
    192               Action(Action::DUPLICATE, kDuplicateBase, 1));
    193   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
    194   EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0));
    195   EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase));
    196 }
    197 
    198 TEST(FileDescriptorShuffleTest, Fanout) {
    199   InjectiveMultimap map;
    200   InjectionTracer tracer;
    201   map.push_back(InjectionArc(0, 1, false));
    202   map.push_back(InjectionArc(0, 2, false));
    203 
    204   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
    205   ASSERT_EQ(2u, tracer.actions().size());
    206   EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
    207   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
    208 }
    209 
    210 TEST(FileDescriptorShuffleTest, FanoutAndClose1) {
    211   InjectiveMultimap map;
    212   InjectionTracer tracer;
    213   map.push_back(InjectionArc(0, 1, true));
    214   map.push_back(InjectionArc(0, 2, false));
    215 
    216   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
    217   ASSERT_EQ(3u, tracer.actions().size());
    218   EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
    219   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
    220   EXPECT_TRUE(tracer.actions()[2] == Action(Action::CLOSE, 0));
    221 }
    222 
    223 TEST(FileDescriptorShuffleTest, FanoutAndClose2) {
    224   InjectiveMultimap map;
    225   InjectionTracer tracer;
    226   map.push_back(InjectionArc(0, 1, false));
    227   map.push_back(InjectionArc(0, 2, true));
    228 
    229   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
    230   ASSERT_EQ(3u, tracer.actions().size());
    231   EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
    232   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
    233   EXPECT_TRUE(tracer.actions()[2] == Action(Action::CLOSE, 0));
    234 }
    235 
    236 TEST(FileDescriptorShuffleTest, FanoutAndClose3) {
    237   InjectiveMultimap map;
    238   InjectionTracer tracer;
    239   map.push_back(InjectionArc(0, 1, true));
    240   map.push_back(InjectionArc(0, 2, true));
    241 
    242   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
    243   ASSERT_EQ(3u, tracer.actions().size());
    244   EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
    245   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
    246   EXPECT_TRUE(tracer.actions()[2] == Action(Action::CLOSE, 0));
    247 }
    248 
    249 class FailingDelegate : public InjectionDelegate {
    250  public:
    251   bool Duplicate(int* result, int fd) override { return false; }
    252 
    253   bool Move(int src, int dest) override { return false; }
    254 
    255   void Close(int fd) override {}
    256 };
    257 
    258 TEST(FileDescriptorShuffleTest, EmptyWithFailure) {
    259   InjectiveMultimap map;
    260   FailingDelegate failing;
    261 
    262   EXPECT_TRUE(PerformInjectiveMultimap(map, &failing));
    263 }
    264 
    265 TEST(FileDescriptorShuffleTest, NoopWithFailure) {
    266   InjectiveMultimap map;
    267   FailingDelegate failing;
    268   map.push_back(InjectionArc(0, 0, false));
    269 
    270   EXPECT_TRUE(PerformInjectiveMultimap(map, &failing));
    271 }
    272 
    273 TEST(FileDescriptorShuffleTest, Simple1WithFailure) {
    274   InjectiveMultimap map;
    275   FailingDelegate failing;
    276   map.push_back(InjectionArc(0, 1, false));
    277 
    278   EXPECT_FALSE(PerformInjectiveMultimap(map, &failing));
    279 }
    280 
    281 }  // namespace base
    282