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
Actionbase::Action24 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
operator ==base::Action30 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:
InjectionTracer()43 InjectionTracer()
44 : next_duplicate_(kDuplicateBase) {
45 }
46
Duplicate(int * result,int fd)47 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
Move(int src,int dest)53 bool Move(int src, int dest) override {
54 actions_.push_back(Action(Action::MOVE, src, dest));
55 return true;
56 }
57
Close(int fd)58 void Close(int fd) override { actions_.push_back(Action(Action::CLOSE, fd)); }
59
actions() const60 const std::vector<Action>& actions() const { return actions_; }
61
62 private:
63 int next_duplicate_;
64 std::vector<Action> actions_;
65 };
66
TEST(FileDescriptorShuffleTest,Empty)67 TEST(FileDescriptorShuffleTest, Empty) {
68 InjectiveMultimap map;
69 InjectionTracer tracer;
70
71 EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
72 EXPECT_EQ(0u, tracer.actions().size());
73 }
74
TEST(FileDescriptorShuffleTest,Noop)75 TEST(FileDescriptorShuffleTest, Noop) {
76 InjectiveMultimap map;
77 InjectionTracer tracer;
78 map.push_back(InjectionArc(0, 0, false));
79
80 EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
81 EXPECT_EQ(0u, tracer.actions().size());
82 }
83
TEST(FileDescriptorShuffleTest,NoopAndClose)84 TEST(FileDescriptorShuffleTest, NoopAndClose) {
85 InjectiveMultimap map;
86 InjectionTracer tracer;
87 map.push_back(InjectionArc(0, 0, true));
88
89 EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
90 EXPECT_EQ(0u, tracer.actions().size());
91 }
92
TEST(FileDescriptorShuffleTest,Simple1)93 TEST(FileDescriptorShuffleTest, Simple1) {
94 InjectiveMultimap map;
95 InjectionTracer tracer;
96 map.push_back(InjectionArc(0, 1, false));
97
98 EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
99 ASSERT_EQ(1u, tracer.actions().size());
100 EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
101 }
102
TEST(FileDescriptorShuffleTest,Simple2)103 TEST(FileDescriptorShuffleTest, Simple2) {
104 InjectiveMultimap map;
105 InjectionTracer tracer;
106 map.push_back(InjectionArc(0, 1, false));
107 map.push_back(InjectionArc(2, 3, false));
108
109 EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
110 ASSERT_EQ(2u, tracer.actions().size());
111 EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
112 EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 2, 3));
113 }
114
TEST(FileDescriptorShuffleTest,Simple3)115 TEST(FileDescriptorShuffleTest, Simple3) {
116 InjectiveMultimap map;
117 InjectionTracer tracer;
118 map.push_back(InjectionArc(0, 1, true));
119
120 EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
121 ASSERT_EQ(2u, tracer.actions().size());
122 EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
123 EXPECT_TRUE(tracer.actions()[1] == Action(Action::CLOSE, 0));
124 }
125
TEST(FileDescriptorShuffleTest,Simple4)126 TEST(FileDescriptorShuffleTest, Simple4) {
127 InjectiveMultimap map;
128 InjectionTracer tracer;
129 map.push_back(InjectionArc(10, 0, true));
130 map.push_back(InjectionArc(1, 1, true));
131
132 EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
133 ASSERT_EQ(2u, tracer.actions().size());
134 EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 10, 0));
135 EXPECT_TRUE(tracer.actions()[1] == Action(Action::CLOSE, 10));
136 }
137
TEST(FileDescriptorShuffleTest,Cycle)138 TEST(FileDescriptorShuffleTest, Cycle) {
139 InjectiveMultimap map;
140 InjectionTracer tracer;
141 map.push_back(InjectionArc(0, 1, false));
142 map.push_back(InjectionArc(1, 0, false));
143
144 EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
145 ASSERT_EQ(4u, tracer.actions().size());
146 EXPECT_TRUE(tracer.actions()[0] ==
147 Action(Action::DUPLICATE, kDuplicateBase, 1));
148 EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
149 EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0));
150 EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase));
151 }
152
TEST(FileDescriptorShuffleTest,CycleAndClose1)153 TEST(FileDescriptorShuffleTest, CycleAndClose1) {
154 InjectiveMultimap map;
155 InjectionTracer tracer;
156 map.push_back(InjectionArc(0, 1, true));
157 map.push_back(InjectionArc(1, 0, false));
158
159 EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
160 ASSERT_EQ(4u, tracer.actions().size());
161 EXPECT_TRUE(tracer.actions()[0] ==
162 Action(Action::DUPLICATE, kDuplicateBase, 1));
163 EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
164 EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0));
165 EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase));
166 }
167
TEST(FileDescriptorShuffleTest,CycleAndClose2)168 TEST(FileDescriptorShuffleTest, CycleAndClose2) {
169 InjectiveMultimap map;
170 InjectionTracer tracer;
171 map.push_back(InjectionArc(0, 1, false));
172 map.push_back(InjectionArc(1, 0, true));
173
174 EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
175 ASSERT_EQ(4u, tracer.actions().size());
176 EXPECT_TRUE(tracer.actions()[0] ==
177 Action(Action::DUPLICATE, kDuplicateBase, 1));
178 EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
179 EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0));
180 EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase));
181 }
182
TEST(FileDescriptorShuffleTest,CycleAndClose3)183 TEST(FileDescriptorShuffleTest, CycleAndClose3) {
184 InjectiveMultimap map;
185 InjectionTracer tracer;
186 map.push_back(InjectionArc(0, 1, true));
187 map.push_back(InjectionArc(1, 0, true));
188
189 EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
190 ASSERT_EQ(4u, tracer.actions().size());
191 EXPECT_TRUE(tracer.actions()[0] ==
192 Action(Action::DUPLICATE, kDuplicateBase, 1));
193 EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
194 EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0));
195 EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase));
196 }
197
TEST(FileDescriptorShuffleTest,Fanout)198 TEST(FileDescriptorShuffleTest, Fanout) {
199 InjectiveMultimap map;
200 InjectionTracer tracer;
201 map.push_back(InjectionArc(0, 1, false));
202 map.push_back(InjectionArc(0, 2, false));
203
204 EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
205 ASSERT_EQ(2u, tracer.actions().size());
206 EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
207 EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
208 }
209
TEST(FileDescriptorShuffleTest,FanoutAndClose1)210 TEST(FileDescriptorShuffleTest, FanoutAndClose1) {
211 InjectiveMultimap map;
212 InjectionTracer tracer;
213 map.push_back(InjectionArc(0, 1, true));
214 map.push_back(InjectionArc(0, 2, false));
215
216 EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
217 ASSERT_EQ(3u, tracer.actions().size());
218 EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
219 EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
220 EXPECT_TRUE(tracer.actions()[2] == Action(Action::CLOSE, 0));
221 }
222
TEST(FileDescriptorShuffleTest,FanoutAndClose2)223 TEST(FileDescriptorShuffleTest, FanoutAndClose2) {
224 InjectiveMultimap map;
225 InjectionTracer tracer;
226 map.push_back(InjectionArc(0, 1, false));
227 map.push_back(InjectionArc(0, 2, true));
228
229 EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
230 ASSERT_EQ(3u, tracer.actions().size());
231 EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
232 EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
233 EXPECT_TRUE(tracer.actions()[2] == Action(Action::CLOSE, 0));
234 }
235
TEST(FileDescriptorShuffleTest,FanoutAndClose3)236 TEST(FileDescriptorShuffleTest, FanoutAndClose3) {
237 InjectiveMultimap map;
238 InjectionTracer tracer;
239 map.push_back(InjectionArc(0, 1, true));
240 map.push_back(InjectionArc(0, 2, true));
241
242 EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
243 ASSERT_EQ(3u, tracer.actions().size());
244 EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
245 EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
246 EXPECT_TRUE(tracer.actions()[2] == Action(Action::CLOSE, 0));
247 }
248
249 class FailingDelegate : public InjectionDelegate {
250 public:
Duplicate(int * result,int fd)251 bool Duplicate(int* result, int fd) override { return false; }
252
Move(int src,int dest)253 bool Move(int src, int dest) override { return false; }
254
Close(int fd)255 void Close(int fd) override {}
256 };
257
TEST(FileDescriptorShuffleTest,EmptyWithFailure)258 TEST(FileDescriptorShuffleTest, EmptyWithFailure) {
259 InjectiveMultimap map;
260 FailingDelegate failing;
261
262 EXPECT_TRUE(PerformInjectiveMultimap(map, &failing));
263 }
264
TEST(FileDescriptorShuffleTest,NoopWithFailure)265 TEST(FileDescriptorShuffleTest, NoopWithFailure) {
266 InjectiveMultimap map;
267 FailingDelegate failing;
268 map.push_back(InjectionArc(0, 0, false));
269
270 EXPECT_TRUE(PerformInjectiveMultimap(map, &failing));
271 }
272
TEST(FileDescriptorShuffleTest,Simple1WithFailure)273 TEST(FileDescriptorShuffleTest, Simple1WithFailure) {
274 InjectiveMultimap map;
275 FailingDelegate failing;
276 map.push_back(InjectionArc(0, 1, false));
277
278 EXPECT_FALSE(PerformInjectiveMultimap(map, &failing));
279 }
280
281 } // namespace base
282