xref: /aosp_15_r20/external/cronet/base/posix/file_descriptor_shuffle_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2012 The Chromium Authors
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 
7 #include "testing/gtest/include/gtest/gtest.h"
8 
9 namespace {
10 
11 // 'Duplicated' file descriptors start at this number
12 const int kDuplicateBase = 1000;
13 
14 }  // namespace
15 
16 namespace base {
17 
18 struct Action {
19   enum Type {
20     CLOSE,
21     MOVE,
22     DUPLICATE,
23   };
24 
Actionbase::Action25   Action(Type in_type, int in_fd1, int in_fd2 = -1)
26       : type(in_type),
27         fd1(in_fd1),
28         fd2(in_fd2) {
29   }
30 
operator ==base::Action31   bool operator==(const Action& other) const {
32     return other.type == type &&
33            other.fd1 == fd1 &&
34            other.fd2 == fd2;
35   }
36 
37   Type type;
38   int fd1;
39   int fd2;
40 };
41 
42 class InjectionTracer : public InjectionDelegate {
43  public:
InjectionTracer()44   InjectionTracer()
45       : next_duplicate_(kDuplicateBase) {
46   }
47 
Duplicate(int * result,int fd)48   bool Duplicate(int* result, int fd) override {
49     *result = next_duplicate_++;
50     actions_.push_back(Action(Action::DUPLICATE, *result, fd));
51     return true;
52   }
53 
Move(int src,int dest)54   bool Move(int src, int dest) override {
55     actions_.push_back(Action(Action::MOVE, src, dest));
56     return true;
57   }
58 
Close(int fd)59   void Close(int fd) override { actions_.push_back(Action(Action::CLOSE, fd)); }
60 
actions() const61   const std::vector<Action>& actions() const { return actions_; }
62 
63  private:
64   int next_duplicate_;
65   std::vector<Action> actions_;
66 };
67 
TEST(FileDescriptorShuffleTest,Empty)68 TEST(FileDescriptorShuffleTest, Empty) {
69   InjectiveMultimap map;
70   InjectionTracer tracer;
71 
72   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
73   EXPECT_EQ(0u, tracer.actions().size());
74 }
75 
TEST(FileDescriptorShuffleTest,Noop)76 TEST(FileDescriptorShuffleTest, Noop) {
77   InjectiveMultimap map;
78   InjectionTracer tracer;
79   map.push_back(InjectionArc(0, 0, false));
80 
81   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
82   EXPECT_EQ(0u, tracer.actions().size());
83 }
84 
TEST(FileDescriptorShuffleTest,NoopAndClose)85 TEST(FileDescriptorShuffleTest, NoopAndClose) {
86   InjectiveMultimap map;
87   InjectionTracer tracer;
88   map.push_back(InjectionArc(0, 0, true));
89 
90   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
91   EXPECT_EQ(0u, tracer.actions().size());
92 }
93 
TEST(FileDescriptorShuffleTest,Simple1)94 TEST(FileDescriptorShuffleTest, Simple1) {
95   InjectiveMultimap map;
96   InjectionTracer tracer;
97   map.push_back(InjectionArc(0, 1, false));
98 
99   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
100   ASSERT_EQ(1u, tracer.actions().size());
101   EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
102 }
103 
TEST(FileDescriptorShuffleTest,Simple2)104 TEST(FileDescriptorShuffleTest, Simple2) {
105   InjectiveMultimap map;
106   InjectionTracer tracer;
107   map.push_back(InjectionArc(0, 1, false));
108   map.push_back(InjectionArc(2, 3, false));
109 
110   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
111   ASSERT_EQ(2u, tracer.actions().size());
112   EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
113   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 2, 3));
114 }
115 
TEST(FileDescriptorShuffleTest,Simple3)116 TEST(FileDescriptorShuffleTest, Simple3) {
117   InjectiveMultimap map;
118   InjectionTracer tracer;
119   map.push_back(InjectionArc(0, 1, true));
120 
121   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
122   ASSERT_EQ(2u, tracer.actions().size());
123   EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
124   EXPECT_TRUE(tracer.actions()[1] == Action(Action::CLOSE, 0));
125 }
126 
TEST(FileDescriptorShuffleTest,Simple4)127 TEST(FileDescriptorShuffleTest, Simple4) {
128   InjectiveMultimap map;
129   InjectionTracer tracer;
130   map.push_back(InjectionArc(10, 0, true));
131   map.push_back(InjectionArc(1, 1, true));
132 
133   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
134   ASSERT_EQ(2u, tracer.actions().size());
135   EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 10, 0));
136   EXPECT_TRUE(tracer.actions()[1] == Action(Action::CLOSE, 10));
137 }
138 
TEST(FileDescriptorShuffleTest,Cycle)139 TEST(FileDescriptorShuffleTest, Cycle) {
140   InjectiveMultimap map;
141   InjectionTracer tracer;
142   map.push_back(InjectionArc(0, 1, false));
143   map.push_back(InjectionArc(1, 0, false));
144 
145   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
146   ASSERT_EQ(4u, tracer.actions().size());
147   EXPECT_TRUE(tracer.actions()[0] ==
148               Action(Action::DUPLICATE, kDuplicateBase, 1));
149   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
150   EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0));
151   EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase));
152 }
153 
TEST(FileDescriptorShuffleTest,CycleAndClose1)154 TEST(FileDescriptorShuffleTest, CycleAndClose1) {
155   InjectiveMultimap map;
156   InjectionTracer tracer;
157   map.push_back(InjectionArc(0, 1, true));
158   map.push_back(InjectionArc(1, 0, false));
159 
160   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
161   ASSERT_EQ(4u, tracer.actions().size());
162   EXPECT_TRUE(tracer.actions()[0] ==
163               Action(Action::DUPLICATE, kDuplicateBase, 1));
164   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
165   EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0));
166   EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase));
167 }
168 
TEST(FileDescriptorShuffleTest,CycleAndClose2)169 TEST(FileDescriptorShuffleTest, CycleAndClose2) {
170   InjectiveMultimap map;
171   InjectionTracer tracer;
172   map.push_back(InjectionArc(0, 1, false));
173   map.push_back(InjectionArc(1, 0, true));
174 
175   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
176   ASSERT_EQ(4u, tracer.actions().size());
177   EXPECT_TRUE(tracer.actions()[0] ==
178               Action(Action::DUPLICATE, kDuplicateBase, 1));
179   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
180   EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0));
181   EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase));
182 }
183 
TEST(FileDescriptorShuffleTest,CycleAndClose3)184 TEST(FileDescriptorShuffleTest, CycleAndClose3) {
185   InjectiveMultimap map;
186   InjectionTracer tracer;
187   map.push_back(InjectionArc(0, 1, true));
188   map.push_back(InjectionArc(1, 0, true));
189 
190   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
191   ASSERT_EQ(4u, tracer.actions().size());
192   EXPECT_TRUE(tracer.actions()[0] ==
193               Action(Action::DUPLICATE, kDuplicateBase, 1));
194   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
195   EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0));
196   EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase));
197 }
198 
TEST(FileDescriptorShuffleTest,Fanout)199 TEST(FileDescriptorShuffleTest, Fanout) {
200   InjectiveMultimap map;
201   InjectionTracer tracer;
202   map.push_back(InjectionArc(0, 1, false));
203   map.push_back(InjectionArc(0, 2, false));
204 
205   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
206   ASSERT_EQ(2u, tracer.actions().size());
207   EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
208   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
209 }
210 
TEST(FileDescriptorShuffleTest,FanoutAndClose1)211 TEST(FileDescriptorShuffleTest, FanoutAndClose1) {
212   InjectiveMultimap map;
213   InjectionTracer tracer;
214   map.push_back(InjectionArc(0, 1, true));
215   map.push_back(InjectionArc(0, 2, false));
216 
217   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
218   ASSERT_EQ(3u, tracer.actions().size());
219   EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
220   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
221   EXPECT_TRUE(tracer.actions()[2] == Action(Action::CLOSE, 0));
222 }
223 
TEST(FileDescriptorShuffleTest,FanoutAndClose2)224 TEST(FileDescriptorShuffleTest, FanoutAndClose2) {
225   InjectiveMultimap map;
226   InjectionTracer tracer;
227   map.push_back(InjectionArc(0, 1, false));
228   map.push_back(InjectionArc(0, 2, true));
229 
230   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
231   ASSERT_EQ(3u, tracer.actions().size());
232   EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
233   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
234   EXPECT_TRUE(tracer.actions()[2] == Action(Action::CLOSE, 0));
235 }
236 
TEST(FileDescriptorShuffleTest,FanoutAndClose3)237 TEST(FileDescriptorShuffleTest, FanoutAndClose3) {
238   InjectiveMultimap map;
239   InjectionTracer tracer;
240   map.push_back(InjectionArc(0, 1, true));
241   map.push_back(InjectionArc(0, 2, true));
242 
243   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
244   ASSERT_EQ(3u, tracer.actions().size());
245   EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
246   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
247   EXPECT_TRUE(tracer.actions()[2] == Action(Action::CLOSE, 0));
248 }
249 
TEST(FileDescriptorShuffleTest,DuplicateClash)250 TEST(FileDescriptorShuffleTest, DuplicateClash) {
251   InjectiveMultimap map;
252   InjectionTracer tracer;
253   map.push_back(InjectionArc(0, 1, false));
254   // Duplicating 1 puts the fd in the spot it's supposed to go already.
255   map.push_back(InjectionArc(1, kDuplicateBase, false));
256 
257   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
258   ASSERT_EQ(2u, tracer.actions().size());
259   // This duplication "accidentally" fulfills the second mapping.
260   EXPECT_TRUE(tracer.actions()[0] ==
261               Action(Action::DUPLICATE, kDuplicateBase, 1));
262   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
263   // There should be no extra MOVE or CLOSE as the mapping is done and there are
264   // no superfluous fds left around.
265 }
266 
TEST(FileDescriptorShuffleTest,DuplicateClashBad)267 TEST(FileDescriptorShuffleTest, DuplicateClashBad) {
268   InjectiveMultimap map;
269   InjectionTracer tracer;
270   map.push_back(InjectionArc(0, 2, false));
271   map.push_back(InjectionArc(1, kDuplicateBase, false));
272   map.push_back(InjectionArc(2, 3, false));
273 
274   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
275   ASSERT_EQ(6u, tracer.actions().size());
276   // Clashes with the second mapping.
277   EXPECT_TRUE(tracer.actions()[0] ==
278               Action(Action::DUPLICATE, kDuplicateBase, 2));
279   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
280   EXPECT_TRUE(tracer.actions()[2] ==
281               Action(Action::DUPLICATE, kDuplicateBase + 1, kDuplicateBase));
282   EXPECT_TRUE(tracer.actions()[3] == Action(Action::MOVE, 1, kDuplicateBase));
283   EXPECT_TRUE(tracer.actions()[4] ==
284               Action(Action::MOVE, kDuplicateBase + 1, 3));
285   EXPECT_TRUE(tracer.actions()[5] == Action(Action::CLOSE, kDuplicateBase + 1));
286 }
287 
TEST(FileDescriptorShuffleTest,DuplicateClashBadWithClose)288 TEST(FileDescriptorShuffleTest, DuplicateClashBadWithClose) {
289   InjectiveMultimap map;
290   InjectionTracer tracer;
291   map.push_back(InjectionArc(0, 2, true));
292   map.push_back(InjectionArc(1, kDuplicateBase, true));
293   map.push_back(InjectionArc(2, 3, true));
294 
295   EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
296   ASSERT_EQ(8u, tracer.actions().size());
297   // Clashes with the second mapping.
298   EXPECT_TRUE(tracer.actions()[0] ==
299               Action(Action::DUPLICATE, kDuplicateBase, 2));
300   EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
301   EXPECT_TRUE(tracer.actions()[2] == Action(Action::CLOSE, 0));
302   EXPECT_TRUE(tracer.actions()[3] ==
303               Action(Action::DUPLICATE, kDuplicateBase + 1, kDuplicateBase));
304   EXPECT_TRUE(tracer.actions()[4] == Action(Action::MOVE, 1, kDuplicateBase));
305   EXPECT_TRUE(tracer.actions()[5] == Action(Action::CLOSE, 1));
306   EXPECT_TRUE(tracer.actions()[6] ==
307               Action(Action::MOVE, kDuplicateBase + 1, 3));
308   EXPECT_TRUE(tracer.actions()[7] == Action(Action::CLOSE, kDuplicateBase + 1));
309 }
310 
311 class FailingDelegate : public InjectionDelegate {
312  public:
Duplicate(int * result,int fd)313   bool Duplicate(int* result, int fd) override { return false; }
314 
Move(int src,int dest)315   bool Move(int src, int dest) override { return false; }
316 
Close(int fd)317   void Close(int fd) override {}
318 };
319 
TEST(FileDescriptorShuffleTest,EmptyWithFailure)320 TEST(FileDescriptorShuffleTest, EmptyWithFailure) {
321   InjectiveMultimap map;
322   FailingDelegate failing;
323 
324   EXPECT_TRUE(PerformInjectiveMultimap(map, &failing));
325 }
326 
TEST(FileDescriptorShuffleTest,NoopWithFailure)327 TEST(FileDescriptorShuffleTest, NoopWithFailure) {
328   InjectiveMultimap map;
329   FailingDelegate failing;
330   map.push_back(InjectionArc(0, 0, false));
331 
332   EXPECT_TRUE(PerformInjectiveMultimap(map, &failing));
333 }
334 
TEST(FileDescriptorShuffleTest,Simple1WithFailure)335 TEST(FileDescriptorShuffleTest, Simple1WithFailure) {
336   InjectiveMultimap map;
337   FailingDelegate failing;
338   map.push_back(InjectionArc(0, 1, false));
339 
340   EXPECT_FALSE(PerformInjectiveMultimap(map, &failing));
341 }
342 
343 }  // namespace base
344