]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/test_subprocess.cc
import ceph quincy 17.2.6
[ceph.git] / ceph / src / test / test_subprocess.cc
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 #ifdef _WIN32
27 // Some of the tests expect GNU binaries to be available. We'll just rely on
28 // the ones provided by Msys (which also comes with Git for Windows).
29 #define SHELL "bash.exe"
30 #else
31 #define SHELL "/bin/sh"
32 #endif
33
34 bool read_from_fd(int fd, std::string &out) {
35 out.clear();
36 char buf[1024];
37 ssize_t n = safe_read(fd, buf, sizeof(buf) - 1);
38 if (n < 0)
39 return false;
40 buf[n] = '\0';
41 out = buf;
42 return true;
43 }
44
45 TEST(SubProcess, True)
46 {
47 SubProcess p("true");
48 ASSERT_EQ(p.spawn(), 0);
49 ASSERT_EQ(p.join(), 0);
50 ASSERT_TRUE(p.err().c_str()[0] == '\0');
51 }
52
53 TEST(SubProcess, False)
54 {
55 SubProcess p("false");
56 ASSERT_EQ(p.spawn(), 0);
57 ASSERT_EQ(p.join(), 1);
58 ASSERT_FALSE(p.err().c_str()[0] == '\0');
59 }
60
61 TEST(SubProcess, NotFound)
62 {
63 SubProcess p("NOTEXISTENTBINARY", SubProcess::CLOSE, SubProcess::CLOSE, SubProcess::PIPE);
64 #ifdef _WIN32
65 // Windows will error out early.
66 ASSERT_EQ(p.spawn(), -1);
67 #else
68 ASSERT_EQ(p.spawn(), 0);
69 std::string buf;
70 ASSERT_TRUE(read_from_fd(p.get_stderr(), buf));
71 std::cerr << "stderr: " << buf;
72 ASSERT_EQ(p.join(), 1);
73 std::cerr << "err: " << p.err() << std::endl;
74 ASSERT_FALSE(p.err().c_str()[0] == '\0');
75 #endif
76 }
77
78 TEST(SubProcess, Echo)
79 {
80 SubProcess echo("echo", SubProcess::CLOSE, SubProcess::PIPE);
81 echo.add_cmd_args("1", "2", "3", NULL);
82
83 ASSERT_EQ(echo.spawn(), 0);
84 std::string buf;
85 ASSERT_TRUE(read_from_fd(echo.get_stdout(), buf));
86 std::cerr << "stdout: " << buf;
87 ASSERT_EQ(buf, "1 2 3\n");
88 ASSERT_EQ(echo.join(), 0);
89 ASSERT_TRUE(echo.err().c_str()[0] == '\0');
90 }
91
92 TEST(SubProcess, Cat)
93 {
94 SubProcess cat("cat", SubProcess::PIPE, SubProcess::PIPE, SubProcess::PIPE);
95
96 ASSERT_EQ(cat.spawn(), 0);
97 std::string msg("to my, trociny!");
98 int n = write(cat.get_stdin(), msg.c_str(), msg.size());
99 ASSERT_EQ(n, (int)msg.size());
100 cat.close_stdin();
101 std::string buf;
102 ASSERT_TRUE(read_from_fd(cat.get_stdout(), buf));
103 std::cerr << "stdout: " << buf << std::endl;
104 ASSERT_EQ(buf, msg);
105 ASSERT_TRUE(read_from_fd(cat.get_stderr(), buf));
106 ASSERT_EQ(buf, "");
107 ASSERT_EQ(cat.join(), 0);
108 ASSERT_TRUE(cat.err().c_str()[0] == '\0');
109 }
110
111 TEST(SubProcess, CatDevNull)
112 {
113 SubProcess cat("cat", SubProcess::PIPE, SubProcess::PIPE, SubProcess::PIPE);
114 cat.add_cmd_arg("/dev/null");
115
116 ASSERT_EQ(cat.spawn(), 0);
117 std::string buf;
118 ASSERT_TRUE(read_from_fd(cat.get_stdout(), buf));
119 ASSERT_EQ(buf, "");
120 ASSERT_TRUE(read_from_fd(cat.get_stderr(), buf));
121 ASSERT_EQ(buf, "");
122 ASSERT_EQ(cat.join(), 0);
123 ASSERT_TRUE(cat.err().c_str()[0] == '\0');
124 }
125
126 TEST(SubProcess, Killed)
127 {
128 SubProcessTimed cat("cat", SubProcess::PIPE, SubProcess::PIPE);
129
130 ASSERT_EQ(cat.spawn(), 0);
131 cat.kill();
132 ASSERT_EQ(cat.join(), 128 + SIGTERM);
133 std::cerr << "err: " << cat.err() << std::endl;
134 ASSERT_FALSE(cat.err().c_str()[0] == '\0');
135 }
136
137 #ifndef _WIN32
138 TEST(SubProcess, CatWithArgs)
139 {
140 SubProcess cat("cat", SubProcess::PIPE, SubProcess::PIPE, SubProcess::PIPE);
141 cat.add_cmd_args("/dev/stdin", "/dev/null", "/NOTEXIST", NULL);
142
143 ASSERT_EQ(cat.spawn(), 0);
144 std::string msg("Hello, Word!");
145 int n = write(cat.get_stdin(), msg.c_str(), msg.size());
146 ASSERT_EQ(n, (int)msg.size());
147 cat.close_stdin();
148 std::string buf;
149 ASSERT_TRUE(read_from_fd(cat.get_stdout(), buf));
150 std::cerr << "stdout: " << buf << std::endl;
151 ASSERT_EQ(buf, msg);
152 ASSERT_TRUE(read_from_fd(cat.get_stderr(), buf));
153 std::cerr << "stderr: " << buf;
154 ASSERT_FALSE(buf.empty());
155 ASSERT_EQ(cat.join(), 1);
156 std::cerr << "err: " << cat.err() << std::endl;
157 ASSERT_FALSE(cat.err().c_str()[0] == '\0');
158 }
159 #endif
160
161 TEST(SubProcess, Subshell)
162 {
163 SubProcess sh(SHELL, SubProcess::PIPE, SubProcess::PIPE, SubProcess::PIPE);
164 sh.add_cmd_args("-c",
165 "sleep 0; "
166 "cat; "
167 "echo 'error from subshell' >&2; "
168 SHELL " -c 'exit 13'", NULL);
169 ASSERT_EQ(sh.spawn(), 0);
170 std::string msg("hello via subshell");
171 int n = write(sh.get_stdin(), msg.c_str(), msg.size());
172 ASSERT_EQ(n, (int)msg.size());
173 sh.close_stdin();
174 std::string buf;
175 ASSERT_TRUE(read_from_fd(sh.get_stdout(), buf));
176 std::cerr << "stdout: " << buf << std::endl;
177 ASSERT_EQ(buf, msg);
178 ASSERT_TRUE(read_from_fd(sh.get_stderr(), buf));
179 std::cerr << "stderr: " << buf;
180 ASSERT_EQ(buf, "error from subshell\n");
181 ASSERT_EQ(sh.join(), 13);
182 std::cerr << "err: " << sh.err() << std::endl;
183 ASSERT_FALSE(sh.err().c_str()[0] == '\0');
184 }
185
186 TEST(SubProcessTimed, True)
187 {
188 SubProcessTimed p("true", SubProcess::CLOSE, SubProcess::CLOSE, SubProcess::CLOSE, 10);
189 ASSERT_EQ(p.spawn(), 0);
190 ASSERT_EQ(p.join(), 0);
191 ASSERT_TRUE(p.err().c_str()[0] == '\0');
192 }
193
194 TEST(SubProcessTimed, SleepNoTimeout)
195 {
196 SubProcessTimed sleep("sleep", SubProcess::CLOSE, SubProcess::CLOSE, SubProcess::CLOSE, 0);
197 sleep.add_cmd_arg("1");
198
199 ASSERT_EQ(sleep.spawn(), 0);
200 ASSERT_EQ(sleep.join(), 0);
201 ASSERT_TRUE(sleep.err().c_str()[0] == '\0');
202 }
203
204 TEST(SubProcessTimed, Killed)
205 {
206 SubProcessTimed cat("cat", SubProcess::PIPE, SubProcess::PIPE, SubProcess::PIPE, 5);
207
208 ASSERT_EQ(cat.spawn(), 0);
209 cat.kill();
210 std::string buf;
211 ASSERT_TRUE(read_from_fd(cat.get_stdout(), buf));
212 ASSERT_TRUE(buf.empty());
213 ASSERT_TRUE(read_from_fd(cat.get_stderr(), buf));
214 ASSERT_TRUE(buf.empty());
215 ASSERT_EQ(cat.join(), 128 + SIGTERM);
216 std::cerr << "err: " << cat.err() << std::endl;
217 ASSERT_FALSE(cat.err().c_str()[0] == '\0');
218 }
219
220 TEST(SubProcessTimed, SleepTimedout)
221 {
222 SubProcessTimed sleep("sleep", SubProcess::CLOSE, SubProcess::CLOSE, SubProcess::PIPE, 1);
223 sleep.add_cmd_arg("10");
224
225 ASSERT_EQ(sleep.spawn(), 0);
226 std::string buf;
227 ASSERT_TRUE(read_from_fd(sleep.get_stderr(), buf));
228 #ifndef _WIN32
229 std::cerr << "stderr: " << buf;
230 ASSERT_FALSE(buf.empty());
231 #endif
232 ASSERT_EQ(sleep.join(), 128 + SIGKILL);
233 std::cerr << "err: " << sleep.err() << std::endl;
234 ASSERT_FALSE(sleep.err().c_str()[0] == '\0');
235 }
236
237 TEST(SubProcessTimed, SubshellNoTimeout)
238 {
239 SubProcessTimed sh(SHELL, SubProcess::PIPE, SubProcess::PIPE, SubProcess::PIPE, 0);
240 sh.add_cmd_args("-c", "cat >&2", NULL);
241 ASSERT_EQ(sh.spawn(), 0);
242 std::string msg("the quick brown fox jumps over the lazy dog");
243 int n = write(sh.get_stdin(), msg.c_str(), msg.size());
244 ASSERT_EQ(n, (int)msg.size());
245 sh.close_stdin();
246 std::string buf;
247 ASSERT_TRUE(read_from_fd(sh.get_stdout(), buf));
248 std::cerr << "stdout: " << buf << std::endl;
249 ASSERT_TRUE(buf.empty());
250 ASSERT_TRUE(read_from_fd(sh.get_stderr(), buf));
251 std::cerr << "stderr: " << buf << std::endl;
252 ASSERT_EQ(buf, msg);
253 ASSERT_EQ(sh.join(), 0);
254 ASSERT_TRUE(sh.err().c_str()[0] == '\0');
255 }
256
257 TEST(SubProcessTimed, SubshellKilled)
258 {
259 SubProcessTimed sh(SHELL, SubProcess::PIPE, SubProcess::PIPE, SubProcess::PIPE, 10);
260 sh.add_cmd_args("-c", SHELL "-c cat", NULL);
261 ASSERT_EQ(sh.spawn(), 0);
262 std::string msg("etaoin shrdlu");
263 int n = write(sh.get_stdin(), msg.c_str(), msg.size());
264 ASSERT_EQ(n, (int)msg.size());
265 sh.kill();
266 std::string buf;
267 ASSERT_TRUE(read_from_fd(sh.get_stderr(), buf));
268 ASSERT_TRUE(buf.empty());
269 ASSERT_EQ(sh.join(), 128 + SIGTERM);
270 std::cerr << "err: " << sh.err() << std::endl;
271 ASSERT_FALSE(sh.err().c_str()[0] == '\0');
272 }
273
274 TEST(SubProcessTimed, SubshellTimedout)
275 {
276 SubProcessTimed sh(SHELL, SubProcess::PIPE, SubProcess::PIPE, SubProcess::PIPE, 1, SIGTERM);
277 sh.add_cmd_args("-c", "sleep 1000& cat; NEVER REACHED", NULL);
278 ASSERT_EQ(sh.spawn(), 0);
279 std::string buf;
280 #ifndef _WIN32
281 ASSERT_TRUE(read_from_fd(sh.get_stderr(), buf));
282 std::cerr << "stderr: " << buf;
283 ASSERT_FALSE(buf.empty());
284 #endif
285 ASSERT_EQ(sh.join(), 128 + SIGTERM);
286 std::cerr << "err: " << sh.err() << std::endl;
287 ASSERT_FALSE(sh.err().c_str()[0] == '\0');
288 }
289
290 #ifndef _WIN32
291 TEST(fork_function, normal)
292 {
293 ASSERT_EQ(0, fork_function(10, std::cerr, [&]() { return 0; }));
294 ASSERT_EQ(1, fork_function(10, std::cerr, [&]() { return 1; }));
295 ASSERT_EQ(13, fork_function(10, std::cerr, [&]() { return 13; }));
296 ASSERT_EQ(-1, fork_function(10, std::cerr, [&]() { return -1; }));
297 ASSERT_EQ(-13, fork_function(10, std::cerr, [&]() { return -13; }));
298 ASSERT_EQ(-ETIMEDOUT,
299 fork_function(10, std::cerr, [&]() { return -ETIMEDOUT; }));
300 }
301
302 TEST(fork_function, timeout)
303 {
304 ASSERT_EQ(-ETIMEDOUT, fork_function(2, std::cerr, [&]() {
305 sleep(60);
306 return 0; }));
307 ASSERT_EQ(-ETIMEDOUT, fork_function(2, std::cerr, [&]() {
308 sleep(60);
309 return 1; }));
310 ASSERT_EQ(-ETIMEDOUT, fork_function(2, std::cerr, [&]() {
311 sleep(60);
312 return -111; }));
313 }
314 #endif