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