file_descriptor_shuffle_unittest.cc revision c7f5f8508d98d5952d42ed7648c2a8f30a4da156
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