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