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 8using base::InjectiveMultimap; 9using base::InjectionArc; 10using base::PerformInjectiveMultimap; 11using base::InjectionDelegate; 12 13namespace { 14typedef testing::Test FileDescriptorShuffleTest; 15} 16 17// 'Duplicated' file descriptors start at this number 18static const int kDuplicateBase = 1000; 19 20struct 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 44class 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 72TEST(FileDescriptorShuffleTest, Empty) { 73 InjectiveMultimap map; 74 InjectionTracer tracer; 75 76 EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); 77 EXPECT_EQ(0u, tracer.actions().size()); 78} 79 80TEST(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 89TEST(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 98TEST(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 108TEST(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 120TEST(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 131TEST(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 143TEST(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 158TEST(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 173TEST(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 188TEST(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 203TEST(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 215TEST(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 228TEST(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 241TEST(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 254class 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 268TEST(FileDescriptorShuffleTest, EmptyWithFailure) { 269 InjectiveMultimap map; 270 FailingDelegate failing; 271 272 EXPECT_TRUE(PerformInjectiveMultimap(map, &failing)); 273} 274 275TEST(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 283TEST(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