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