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