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