]>
Commit | Line | Data |
---|---|---|
1 | // -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- | |
2 | // vim: ts=8 sw=2 smarttab | |
3 | /* | |
4 | * Ceph distributed storage system | |
5 | * | |
6 | * Copyright (C) 2015 Mirantis Inc | |
7 | * | |
8 | * Author: Mykola Golub <mgolub@mirantis.com> | |
9 | * | |
10 | * This library is free software; you can redistribute it and/or | |
11 | * modify it under the terms of the GNU Lesser General Public | |
12 | * License as published by the Free Software Foundation; either | |
13 | * version 2.1 of the License, or (at your option) any later version. | |
14 | * | |
15 | */ | |
16 | ||
17 | #include <unistd.h> | |
18 | ||
19 | #include <iostream> | |
20 | ||
21 | #include "common/SubProcess.h" | |
22 | #include "common/safe_io.h" | |
23 | #include "gtest/gtest.h" | |
24 | #include "common/fork_function.h" | |
25 | ||
26 | bool read_from_fd(int fd, std::string &out) { | |
27 | out.clear(); | |
28 | char buf[1024]; | |
29 | ssize_t n = safe_read(fd, buf, sizeof(buf) - 1); | |
30 | if (n < 0) | |
31 | return false; | |
32 | buf[n] = '\0'; | |
33 | out = buf; | |
34 | return true; | |
35 | } | |
36 | ||
37 | TEST(SubProcess, True) | |
38 | { | |
39 | SubProcess p("true"); | |
40 | ASSERT_EQ(p.spawn(), 0); | |
41 | ASSERT_EQ(p.join(), 0); | |
42 | ASSERT_TRUE(p.err().c_str()[0] == '\0'); | |
43 | } | |
44 | ||
45 | TEST(SubProcess, False) | |
46 | { | |
47 | SubProcess p("false"); | |
48 | ASSERT_EQ(p.spawn(), 0); | |
49 | ASSERT_EQ(p.join(), 1); | |
50 | ASSERT_FALSE(p.err().c_str()[0] == '\0'); | |
51 | } | |
52 | ||
53 | TEST(SubProcess, NotFound) | |
54 | { | |
55 | SubProcess p("NOTEXISTENTBINARY", SubProcess::CLOSE, SubProcess::CLOSE, SubProcess::PIPE); | |
56 | ASSERT_EQ(p.spawn(), 0); | |
57 | std::string buf; | |
58 | ASSERT_TRUE(read_from_fd(p.get_stderr(), buf)); | |
59 | std::cerr << "stderr: " << buf; | |
60 | ASSERT_EQ(p.join(), 1); | |
61 | std::cerr << "err: " << p.err() << std::endl; | |
62 | ASSERT_FALSE(p.err().c_str()[0] == '\0'); | |
63 | } | |
64 | ||
65 | TEST(SubProcess, Echo) | |
66 | { | |
67 | SubProcess echo("echo", SubProcess::CLOSE, SubProcess::PIPE); | |
68 | echo.add_cmd_args("1", "2", "3", NULL); | |
69 | ||
70 | ASSERT_EQ(echo.spawn(), 0); | |
71 | std::string buf; | |
72 | ASSERT_TRUE(read_from_fd(echo.get_stdout(), buf)); | |
73 | std::cerr << "stdout: " << buf; | |
74 | ASSERT_EQ(buf, "1 2 3\n"); | |
75 | ASSERT_EQ(echo.join(), 0); | |
76 | ASSERT_TRUE(echo.err().c_str()[0] == '\0'); | |
77 | } | |
78 | ||
79 | TEST(SubProcess, Cat) | |
80 | { | |
81 | SubProcess cat("cat", SubProcess::PIPE, SubProcess::PIPE, SubProcess::PIPE); | |
82 | ||
83 | ASSERT_EQ(cat.spawn(), 0); | |
84 | std::string msg("to my, trociny!"); | |
85 | int n = write(cat.get_stdin(), msg.c_str(), msg.size()); | |
86 | ASSERT_EQ(n, (int)msg.size()); | |
87 | cat.close_stdin(); | |
88 | std::string buf; | |
89 | ASSERT_TRUE(read_from_fd(cat.get_stdout(), buf)); | |
90 | std::cerr << "stdout: " << buf << std::endl; | |
91 | ASSERT_EQ(buf, msg); | |
92 | ASSERT_TRUE(read_from_fd(cat.get_stderr(), buf)); | |
93 | ASSERT_EQ(buf, ""); | |
94 | ASSERT_EQ(cat.join(), 0); | |
95 | ASSERT_TRUE(cat.err().c_str()[0] == '\0'); | |
96 | } | |
97 | ||
98 | TEST(SubProcess, CatDevNull) | |
99 | { | |
100 | SubProcess cat("cat", SubProcess::PIPE, SubProcess::PIPE, SubProcess::PIPE); | |
101 | cat.add_cmd_arg("/dev/null"); | |
102 | ||
103 | ASSERT_EQ(cat.spawn(), 0); | |
104 | std::string buf; | |
105 | ASSERT_TRUE(read_from_fd(cat.get_stdout(), buf)); | |
106 | ASSERT_EQ(buf, ""); | |
107 | ASSERT_TRUE(read_from_fd(cat.get_stderr(), buf)); | |
108 | ASSERT_EQ(buf, ""); | |
109 | ASSERT_EQ(cat.join(), 0); | |
110 | ASSERT_TRUE(cat.err().c_str()[0] == '\0'); | |
111 | } | |
112 | ||
113 | TEST(SubProcess, Killed) | |
114 | { | |
115 | SubProcessTimed cat("cat", SubProcess::PIPE, SubProcess::PIPE); | |
116 | ||
117 | ASSERT_EQ(cat.spawn(), 0); | |
118 | cat.kill(); | |
119 | ASSERT_EQ(cat.join(), 128 + SIGTERM); | |
120 | std::cerr << "err: " << cat.err() << std::endl; | |
121 | ASSERT_FALSE(cat.err().c_str()[0] == '\0'); | |
122 | } | |
123 | ||
124 | TEST(SubProcess, CatWithArgs) | |
125 | { | |
126 | SubProcess cat("cat", SubProcess::PIPE, SubProcess::PIPE, SubProcess::PIPE); | |
127 | cat.add_cmd_args("/dev/stdin", "/dev/null", "/NOTEXIST", NULL); | |
128 | ||
129 | ASSERT_EQ(cat.spawn(), 0); | |
130 | std::string msg("Hello, Word!"); | |
131 | int n = write(cat.get_stdin(), msg.c_str(), msg.size()); | |
132 | ASSERT_EQ(n, (int)msg.size()); | |
133 | cat.close_stdin(); | |
134 | std::string buf; | |
135 | ASSERT_TRUE(read_from_fd(cat.get_stdout(), buf)); | |
136 | std::cerr << "stdout: " << buf << std::endl; | |
137 | ASSERT_EQ(buf, msg); | |
138 | ASSERT_TRUE(read_from_fd(cat.get_stderr(), buf)); | |
139 | std::cerr << "stderr: " << buf; | |
140 | ASSERT_FALSE(buf.empty()); | |
141 | ASSERT_EQ(cat.join(), 1); | |
142 | std::cerr << "err: " << cat.err() << std::endl; | |
143 | ASSERT_FALSE(cat.err().c_str()[0] == '\0'); | |
144 | } | |
145 | ||
146 | TEST(SubProcess, Subshell) | |
147 | { | |
148 | SubProcess sh("/bin/sh", SubProcess::PIPE, SubProcess::PIPE, SubProcess::PIPE); | |
149 | sh.add_cmd_args("-c", | |
150 | "sleep 0; " | |
151 | "cat; " | |
152 | "echo 'error from subshell' >&2; " | |
153 | "/bin/sh -c 'exit 13'", NULL); | |
154 | ASSERT_EQ(sh.spawn(), 0); | |
155 | std::string msg("hello via subshell"); | |
156 | int n = write(sh.get_stdin(), msg.c_str(), msg.size()); | |
157 | ASSERT_EQ(n, (int)msg.size()); | |
158 | sh.close_stdin(); | |
159 | std::string buf; | |
160 | ASSERT_TRUE(read_from_fd(sh.get_stdout(), buf)); | |
161 | std::cerr << "stdout: " << buf << std::endl; | |
162 | ASSERT_EQ(buf, msg); | |
163 | ASSERT_TRUE(read_from_fd(sh.get_stderr(), buf)); | |
164 | std::cerr << "stderr: " << buf; | |
165 | ASSERT_EQ(buf, "error from subshell\n"); | |
166 | ASSERT_EQ(sh.join(), 13); | |
167 | std::cerr << "err: " << sh.err() << std::endl; | |
168 | ASSERT_FALSE(sh.err().c_str()[0] == '\0'); | |
169 | } | |
170 | ||
171 | TEST(SubProcessTimed, True) | |
172 | { | |
173 | SubProcessTimed p("true", SubProcess::CLOSE, SubProcess::CLOSE, SubProcess::CLOSE, 10); | |
174 | ASSERT_EQ(p.spawn(), 0); | |
175 | ASSERT_EQ(p.join(), 0); | |
176 | ASSERT_TRUE(p.err().c_str()[0] == '\0'); | |
177 | } | |
178 | ||
179 | TEST(SubProcessTimed, SleepNoTimeout) | |
180 | { | |
181 | SubProcessTimed sleep("sleep", SubProcess::CLOSE, SubProcess::CLOSE, SubProcess::CLOSE, 0); | |
182 | sleep.add_cmd_arg("1"); | |
183 | ||
184 | ASSERT_EQ(sleep.spawn(), 0); | |
185 | ASSERT_EQ(sleep.join(), 0); | |
186 | ASSERT_TRUE(sleep.err().c_str()[0] == '\0'); | |
187 | } | |
188 | ||
189 | TEST(SubProcessTimed, Killed) | |
190 | { | |
191 | SubProcessTimed cat("cat", SubProcess::PIPE, SubProcess::PIPE, SubProcess::PIPE, 5); | |
192 | ||
193 | ASSERT_EQ(cat.spawn(), 0); | |
194 | cat.kill(); | |
195 | std::string buf; | |
196 | ASSERT_TRUE(read_from_fd(cat.get_stdout(), buf)); | |
197 | ASSERT_TRUE(buf.empty()); | |
198 | ASSERT_TRUE(read_from_fd(cat.get_stderr(), buf)); | |
199 | ASSERT_TRUE(buf.empty()); | |
200 | ASSERT_EQ(cat.join(), 128 + SIGTERM); | |
201 | std::cerr << "err: " << cat.err() << std::endl; | |
202 | ASSERT_FALSE(cat.err().c_str()[0] == '\0'); | |
203 | } | |
204 | ||
205 | TEST(SubProcessTimed, SleepTimedout) | |
206 | { | |
207 | SubProcessTimed sleep("sleep", SubProcess::CLOSE, SubProcess::CLOSE, SubProcess::PIPE, 1); | |
208 | sleep.add_cmd_arg("10"); | |
209 | ||
210 | ASSERT_EQ(sleep.spawn(), 0); | |
211 | std::string buf; | |
212 | ASSERT_TRUE(read_from_fd(sleep.get_stderr(), buf)); | |
213 | std::cerr << "stderr: " << buf; | |
214 | ASSERT_FALSE(buf.empty()); | |
215 | ASSERT_EQ(sleep.join(), 128 + SIGKILL); | |
216 | std::cerr << "err: " << sleep.err() << std::endl; | |
217 | ASSERT_FALSE(sleep.err().c_str()[0] == '\0'); | |
218 | } | |
219 | ||
220 | TEST(SubProcessTimed, SubshellNoTimeout) | |
221 | { | |
222 | SubProcessTimed sh("/bin/sh", SubProcess::PIPE, SubProcess::PIPE, SubProcess::PIPE, 0); | |
223 | sh.add_cmd_args("-c", "cat >&2", NULL); | |
224 | ASSERT_EQ(sh.spawn(), 0); | |
225 | std::string msg("the quick brown fox jumps over the lazy dog"); | |
226 | int n = write(sh.get_stdin(), msg.c_str(), msg.size()); | |
227 | ASSERT_EQ(n, (int)msg.size()); | |
228 | sh.close_stdin(); | |
229 | std::string buf; | |
230 | ASSERT_TRUE(read_from_fd(sh.get_stdout(), buf)); | |
231 | std::cerr << "stdout: " << buf << std::endl; | |
232 | ASSERT_TRUE(buf.empty()); | |
233 | ASSERT_TRUE(read_from_fd(sh.get_stderr(), buf)); | |
234 | std::cerr << "stderr: " << buf << std::endl; | |
235 | ASSERT_EQ(buf, msg); | |
236 | ASSERT_EQ(sh.join(), 0); | |
237 | ASSERT_TRUE(sh.err().c_str()[0] == '\0'); | |
238 | } | |
239 | ||
240 | TEST(SubProcessTimed, SubshellKilled) | |
241 | { | |
242 | SubProcessTimed sh("/bin/sh", SubProcess::PIPE, SubProcess::PIPE, SubProcess::PIPE, 10); | |
243 | sh.add_cmd_args("-c", "sh -c cat", NULL); | |
244 | ASSERT_EQ(sh.spawn(), 0); | |
245 | std::string msg("etaoin shrdlu"); | |
246 | int n = write(sh.get_stdin(), msg.c_str(), msg.size()); | |
247 | ASSERT_EQ(n, (int)msg.size()); | |
248 | sh.kill(); | |
249 | std::string buf; | |
250 | ASSERT_TRUE(read_from_fd(sh.get_stderr(), buf)); | |
251 | ASSERT_TRUE(buf.empty()); | |
252 | ASSERT_EQ(sh.join(), 128 + SIGTERM); | |
253 | std::cerr << "err: " << sh.err() << std::endl; | |
254 | ASSERT_FALSE(sh.err().c_str()[0] == '\0'); | |
255 | } | |
256 | ||
257 | TEST(SubProcessTimed, SubshellTimedout) | |
258 | { | |
259 | SubProcessTimed sh("/bin/sh", SubProcess::PIPE, SubProcess::PIPE, SubProcess::PIPE, 1, SIGTERM); | |
260 | sh.add_cmd_args("-c", "sleep 1000& cat; NEVER REACHED", NULL); | |
261 | ASSERT_EQ(sh.spawn(), 0); | |
262 | std::string buf; | |
263 | ASSERT_TRUE(read_from_fd(sh.get_stderr(), buf)); | |
264 | std::cerr << "stderr: " << buf; | |
265 | ASSERT_FALSE(buf.empty()); | |
266 | ASSERT_EQ(sh.join(), 128 + SIGTERM); | |
267 | std::cerr << "err: " << sh.err() << std::endl; | |
268 | ASSERT_FALSE(sh.err().c_str()[0] == '\0'); | |
269 | } | |
270 | ||
271 | TEST(fork_function, normal) | |
272 | { | |
273 | ASSERT_EQ(0, fork_function(10, std::cerr, [&]() { return 0; })); | |
274 | ASSERT_EQ(1, fork_function(10, std::cerr, [&]() { return 1; })); | |
275 | ASSERT_EQ(13, fork_function(10, std::cerr, [&]() { return 13; })); | |
276 | ASSERT_EQ(-1, fork_function(10, std::cerr, [&]() { return -1; })); | |
277 | ASSERT_EQ(-13, fork_function(10, std::cerr, [&]() { return -13; })); | |
278 | ASSERT_EQ(-ETIMEDOUT, | |
279 | fork_function(10, std::cerr, [&]() { return -ETIMEDOUT; })); | |
280 | } | |
281 | ||
282 | TEST(fork_function, timeout) | |
283 | { | |
284 | ASSERT_EQ(-ETIMEDOUT, fork_function(2, std::cerr, [&]() { | |
285 | sleep(60); | |
286 | return 0; })); | |
287 | ASSERT_EQ(-ETIMEDOUT, fork_function(2, std::cerr, [&]() { | |
288 | sleep(60); | |
289 | return 1; })); | |
290 | ASSERT_EQ(-ETIMEDOUT, fork_function(2, std::cerr, [&]() { | |
291 | sleep(60); | |
292 | return -111; })); | |
293 | } |