Line data Source code
1 : // Copyright (c) 2012-2021 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/eventdispatcher
4 : // contact@m2osw.com
5 : //
6 : // This program is free software; you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation; either version 2 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 :
20 : // self
21 : //
22 : #include "catch_main.h"
23 :
24 :
25 : // cppprocess lib
26 : //
27 : #include <cppprocess/process.h>
28 :
29 :
30 : // snapdev lib
31 : //
32 : #include <snapdev/file_contents.h>
33 :
34 :
35 : // C++ lib
36 : //
37 : #include <fstream>
38 :
39 :
40 : // C lib
41 : //
42 : //#include <sys/resource.h>
43 : //#include <sys/times.h>
44 :
45 :
46 : // last include
47 : //
48 : #include <snapdev/poison.h>
49 :
50 :
51 :
52 8 : CATCH_TEST_CASE("Process", "[process]")
53 : {
54 12 : CATCH_START_SECTION("simple cat")
55 : {
56 2 : cppprocess::process p("simple-cat");
57 :
58 1 : CATCH_REQUIRE(p.get_name() == "simple-cat");
59 :
60 1 : CATCH_REQUIRE_FALSE(p.get_forced_environment());
61 1 : p.set_forced_environment(true);
62 1 : CATCH_REQUIRE(p.get_forced_environment());
63 1 : p.set_forced_environment(false);
64 1 : CATCH_REQUIRE_FALSE(p.get_forced_environment());
65 :
66 1 : CATCH_REQUIRE(p.get_command() == std::string());
67 1 : p.set_command("cat");
68 1 : CATCH_REQUIRE(p.get_command() == "cat");
69 :
70 1 : CATCH_REQUIRE(p.get_arguments().empty());
71 1 : p.add_argument("/proc/self/comm");
72 1 : CATCH_REQUIRE(p.get_arguments().size() == 1);
73 :
74 1 : CATCH_REQUIRE(p.get_environ().empty());
75 :
76 1 : CATCH_REQUIRE(p.get_input().empty());
77 1 : CATCH_REQUIRE(p.get_binary_input().empty());
78 1 : CATCH_REQUIRE(p.get_input_pipe() == nullptr);
79 :
80 1 : CATCH_REQUIRE_FALSE(p.get_capture_output());
81 1 : p.set_capture_output();
82 1 : CATCH_REQUIRE(p.get_capture_output());
83 :
84 1 : CATCH_REQUIRE(p.get_output().empty());
85 1 : CATCH_REQUIRE(p.get_binary_output().empty());
86 1 : CATCH_REQUIRE(p.get_output_pipe() == nullptr);
87 1 : CATCH_REQUIRE(p.get_next_processes().empty());
88 :
89 1 : CATCH_REQUIRE(p.get_error().empty());
90 1 : CATCH_REQUIRE(p.get_binary_error().empty());
91 1 : CATCH_REQUIRE(p.get_error_pipe() == nullptr);
92 :
93 1 : CATCH_REQUIRE(p.start() == 0);
94 :
95 1 : int const code(p.wait());
96 1 : CATCH_REQUIRE(code == 0);
97 :
98 1 : CATCH_REQUIRE(p.get_input().empty());
99 1 : CATCH_REQUIRE(p.get_binary_input().empty());
100 1 : CATCH_REQUIRE(p.get_input_pipe() == nullptr);
101 :
102 1 : CATCH_REQUIRE(p.get_error().empty());
103 1 : CATCH_REQUIRE(p.get_binary_error().empty());
104 1 : CATCH_REQUIRE(p.get_error_pipe() == nullptr);
105 :
106 1 : CATCH_REQUIRE(p.get_output() == "cat\n");
107 1 : CATCH_REQUIRE(p.get_trimmed_output() == "cat");
108 :
109 2 : cppprocess::buffer_t const output(p.get_binary_output());
110 1 : CATCH_REQUIRE(output.size() == 4);
111 1 : CATCH_REQUIRE(output[0] == 'c');
112 1 : CATCH_REQUIRE(output[1] == 'a');
113 1 : CATCH_REQUIRE(output[2] == 't');
114 1 : CATCH_REQUIRE(output[3] == '\n');
115 : }
116 : CATCH_END_SECTION()
117 :
118 12 : CATCH_START_SECTION("simple logger, we pipe the input as the message")
119 : {
120 2 : cppprocess::process p("in-logger");
121 :
122 1 : CATCH_REQUIRE(p.get_name() == "in-logger");
123 :
124 1 : CATCH_REQUIRE(p.get_command() == std::string());
125 1 : p.set_command("logger");
126 1 : CATCH_REQUIRE(p.get_command() == "logger");
127 :
128 1 : CATCH_REQUIRE(p.get_arguments().empty());
129 :
130 1 : CATCH_REQUIRE(p.get_environ().empty());
131 :
132 1 : CATCH_REQUIRE(p.get_input().empty());
133 1 : CATCH_REQUIRE(p.get_binary_input().empty());
134 1 : CATCH_REQUIRE(p.get_input_pipe() == nullptr);
135 :
136 1 : p.add_input("Event Dispatcher Process Test\n");
137 :
138 1 : CATCH_REQUIRE(p.get_input() == std::string("Event Dispatcher Process Test\n"));
139 1 : CATCH_REQUIRE(p.get_binary_input().size() == 30);
140 1 : CATCH_REQUIRE(p.get_input_pipe() == nullptr);
141 :
142 1 : CATCH_REQUIRE_FALSE(p.get_capture_output());
143 1 : CATCH_REQUIRE(p.get_output().empty());
144 1 : CATCH_REQUIRE(p.get_binary_output().empty());
145 1 : CATCH_REQUIRE(p.get_output_pipe() == nullptr);
146 1 : CATCH_REQUIRE(p.get_next_processes().empty());
147 :
148 1 : CATCH_REQUIRE(p.get_error().empty());
149 1 : CATCH_REQUIRE(p.get_binary_error().empty());
150 1 : CATCH_REQUIRE(p.get_error_pipe() == nullptr);
151 :
152 1 : CATCH_REQUIRE(p.start() == 0);
153 :
154 1 : int const code(p.wait());
155 1 : CATCH_REQUIRE(code == 0);
156 : }
157 : CATCH_END_SECTION()
158 :
159 12 : CATCH_START_SECTION("in | sed | out")
160 : {
161 2 : cppprocess::process p("in-sed-out");
162 :
163 1 : CATCH_REQUIRE(p.get_name() == "in-sed-out");
164 :
165 1 : CATCH_REQUIRE_FALSE(p.get_forced_environment());
166 1 : p.set_forced_environment(true);
167 1 : CATCH_REQUIRE(p.get_forced_environment());
168 1 : p.set_forced_environment(false);
169 1 : CATCH_REQUIRE_FALSE(p.get_forced_environment());
170 :
171 1 : CATCH_REQUIRE(p.get_command() == std::string());
172 1 : p.set_command("sed");
173 1 : CATCH_REQUIRE(p.get_command() == "sed");
174 :
175 1 : CATCH_REQUIRE(p.get_arguments().empty());
176 1 : p.add_argument("-e");
177 1 : p.add_argument("s/Hello/Hi/");
178 1 : p.add_argument("-");
179 1 : CATCH_REQUIRE(p.get_arguments().size() == 3);
180 :
181 1 : CATCH_REQUIRE(p.get_environ().empty());
182 :
183 1 : CATCH_REQUIRE(p.get_input().empty());
184 1 : CATCH_REQUIRE(p.get_binary_input().empty());
185 1 : CATCH_REQUIRE(p.get_input_pipe() == nullptr);
186 :
187 1 : p.add_input("Hello World!\n");
188 :
189 1 : CATCH_REQUIRE(p.get_input() == std::string("Hello World!\n"));
190 1 : CATCH_REQUIRE(p.get_binary_input().size() == 14);
191 1 : CATCH_REQUIRE(p.get_input_pipe() == nullptr);
192 :
193 1 : CATCH_REQUIRE_FALSE(p.get_capture_output());
194 1 : p.set_capture_output();
195 1 : CATCH_REQUIRE(p.get_capture_output());
196 :
197 1 : CATCH_REQUIRE(p.get_output().empty());
198 1 : CATCH_REQUIRE(p.get_binary_output().empty());
199 1 : CATCH_REQUIRE(p.get_output_pipe() == nullptr);
200 1 : CATCH_REQUIRE(p.get_next_processes().empty());
201 :
202 1 : CATCH_REQUIRE(p.get_error().empty());
203 1 : CATCH_REQUIRE(p.get_binary_error().empty());
204 1 : CATCH_REQUIRE(p.get_error_pipe() == nullptr);
205 :
206 1 : CATCH_REQUIRE(p.start() == 0);
207 :
208 1 : int const code(p.wait());
209 1 : CATCH_REQUIRE(code == 0);
210 :
211 1 : CATCH_REQUIRE(p.get_output() == "Hi World!\n");
212 1 : CATCH_REQUIRE(p.get_trimmed_output(true) == "Hi World!");
213 :
214 2 : cppprocess::buffer_t const output(p.get_binary_output());
215 1 : CATCH_REQUIRE(output.size() == 11);
216 1 : CATCH_REQUIRE(output[ 0] == 'H');
217 1 : CATCH_REQUIRE(output[ 1] == 'i');
218 1 : CATCH_REQUIRE(output[ 2] == ' ');
219 1 : CATCH_REQUIRE(output[ 3] == ' ');
220 1 : CATCH_REQUIRE(output[ 4] == 'W');
221 1 : CATCH_REQUIRE(output[ 5] == 'o');
222 1 : CATCH_REQUIRE(output[ 6] == 'r');
223 1 : CATCH_REQUIRE(output[ 7] == 'l');
224 1 : CATCH_REQUIRE(output[ 8] == 'd');
225 1 : CATCH_REQUIRE(output[ 9] == '!');
226 1 : CATCH_REQUIRE(output[10] == '\n');
227 : }
228 : CATCH_END_SECTION()
229 :
230 12 : CATCH_START_SECTION("ls unknown-file, expect an error")
231 : {
232 2 : cppprocess::process p("ls-unknown-file");
233 :
234 1 : CATCH_REQUIRE(p.get_name() == "ls-unknown-file");
235 :
236 1 : p.set_command("ls");
237 1 : CATCH_REQUIRE(p.get_command() == "ls");
238 :
239 1 : p.add_argument("unknown-file");
240 1 : CATCH_REQUIRE(p.get_arguments().size() == 1);
241 :
242 1 : CATCH_REQUIRE(p.get_environ().empty());
243 :
244 1 : CATCH_REQUIRE_FALSE(p.get_capture_error());
245 1 : p.set_capture_error();
246 1 : CATCH_REQUIRE(p.get_capture_error());
247 :
248 1 : CATCH_REQUIRE(p.get_error().empty());
249 1 : CATCH_REQUIRE(p.get_binary_error().empty());
250 1 : CATCH_REQUIRE(p.get_error_pipe() == nullptr);
251 :
252 1 : CATCH_REQUIRE(p.start() == 0);
253 :
254 1 : int const code(p.wait());
255 1 : CATCH_REQUIRE(code != 0);
256 :
257 1 : CATCH_REQUIRE(p.get_output().empty());
258 :
259 1 : CATCH_REQUIRE(!p.get_error().empty());
260 : // the error message can change under our feet so at this time I
261 : // don't compare anything
262 : }
263 : CATCH_END_SECTION()
264 :
265 12 : CATCH_START_SECTION("cat | tr")
266 : {
267 2 : cppprocess::process::pointer_t tr(std::make_shared<cppprocess::process>("tr"));
268 1 : tr->set_command("tr");
269 1 : tr->add_argument("TASP");
270 1 : tr->add_argument("tasp");
271 1 : tr->set_capture_output();
272 :
273 2 : cppprocess::process p("cat");
274 1 : p.set_command("cat");
275 1 : p.add_argument("-");
276 1 : p.add_input("Test A Simple Pipeline\n");
277 1 : p.add_next_process(tr);
278 :
279 1 : CATCH_REQUIRE(p.start() == 0);
280 :
281 1 : int const code(p.wait());
282 1 : CATCH_REQUIRE(code == 0);
283 :
284 1 : CATCH_REQUIRE(tr->get_output() == "test a simple pipeline\n");
285 : }
286 : CATCH_END_SECTION()
287 :
288 12 : CATCH_START_SECTION("file based: cat | tr")
289 : {
290 : // Equivalent to:
291 : //
292 : // cat - < input.data | tr TASP tasp > output.data
293 : //
294 1 : std::string & tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
295 2 : std::string const input_filename(tmpdir + "/input.data");
296 2 : std::string const output_filename(tmpdir + "/output.data");
297 : {
298 2 : std::ofstream input_data(input_filename);
299 1 : input_data << "Test A Simple Pipeline\n";
300 : }
301 :
302 2 : cppprocess::process::pointer_t tr(std::make_shared<cppprocess::process>("tr"));
303 1 : tr->set_command("tr");
304 1 : tr->add_argument("TASP");
305 1 : tr->add_argument("tasp");
306 1 : tr->set_output_filename(output_filename);
307 :
308 : // we could directly cat the file here, obviously but we want
309 : // to test the `< <filename>` functionality
310 : //
311 2 : cppprocess::process p("cat");
312 1 : p.set_command("cat");
313 1 : p.add_argument("-");
314 1 : p.set_input_filename(input_filename);
315 1 : p.add_next_process(tr);
316 :
317 1 : CATCH_REQUIRE(p.start() == 0);
318 :
319 1 : int const code(p.wait());
320 1 : CATCH_REQUIRE(code == 0);
321 :
322 2 : snap::file_contents output(output_filename);
323 1 : CATCH_REQUIRE(output.read_all());
324 1 : CATCH_REQUIRE(output.contents() == "test a simple pipeline\n");
325 : }
326 : CATCH_END_SECTION()
327 12 : }
328 :
329 :
330 : // vim: ts=4 sw=4 et
|