1 /* Copyright (c) 2018-2019, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
6 * \brief Test cases for the Process API.
10 #include "core/or/or.h"
11 #include "test/test.h"
12 #include "lib/process/env.h"
14 #define PROCESS_PRIVATE
15 #include "lib/process/process.h"
16 #define PROCESS_UNIX_PRIVATE
17 #include "lib/process/process_unix.h"
18 #define PROCESS_WIN32_PRIVATE
19 #include "lib/process/process_win32.h"
21 static const char *stdout_read_buffer
;
22 static const char *stderr_read_buffer
;
24 struct process_data_t
{
25 smartlist_t
*stdout_data
;
26 smartlist_t
*stderr_data
;
27 smartlist_t
*stdin_data
;
28 process_exit_code_t exit_code
;
31 typedef struct process_data_t process_data_t
;
33 static process_data_t
*
34 process_data_new(void)
36 process_data_t
*process_data
= tor_malloc_zero(sizeof(process_data_t
));
37 process_data
->stdout_data
= smartlist_new();
38 process_data
->stderr_data
= smartlist_new();
39 process_data
->stdin_data
= smartlist_new();
44 process_data_free(process_data_t
*process_data
)
46 if (process_data
== NULL
)
49 SMARTLIST_FOREACH(process_data
->stdout_data
, char *, x
, tor_free(x
));
50 SMARTLIST_FOREACH(process_data
->stderr_data
, char *, x
, tor_free(x
));
51 SMARTLIST_FOREACH(process_data
->stdin_data
, char *, x
, tor_free(x
));
53 smartlist_free(process_data
->stdout_data
);
54 smartlist_free(process_data
->stderr_data
);
55 smartlist_free(process_data
->stdin_data
);
56 tor_free(process_data
);
60 process_mocked_read_stdout(process_t
*process
, buf_t
*buffer
)
64 if (stdout_read_buffer
!= NULL
) {
65 buf_add_string(buffer
, stdout_read_buffer
);
66 stdout_read_buffer
= NULL
;
69 return (int)buf_datalen(buffer
);
73 process_mocked_read_stderr(process_t
*process
, buf_t
*buffer
)
77 if (stderr_read_buffer
!= NULL
) {
78 buf_add_string(buffer
, stderr_read_buffer
);
79 stderr_read_buffer
= NULL
;
82 return (int)buf_datalen(buffer
);
86 process_mocked_write_stdin(process_t
*process
, buf_t
*buffer
)
88 const size_t size
= buf_datalen(buffer
);
93 char *data
= tor_malloc_zero(size
+ 1);
94 process_data_t
*process_data
= process_get_data(process
);
96 buf_get_bytes(buffer
, data
, size
);
97 smartlist_add(process_data
->stdin_data
, data
);
101 process_stdout_callback(process_t
*process
, const char *data
, size_t size
)
103 tt_ptr_op(process
, OP_NE
, NULL
);
104 tt_ptr_op(data
, OP_NE
, NULL
);
105 tt_int_op(strlen(data
), OP_EQ
, size
);
107 process_data_t
*process_data
= process_get_data(process
);
108 smartlist_add(process_data
->stdout_data
, tor_strdup(data
));
115 process_stderr_callback(process_t
*process
, const char *data
, size_t size
)
117 tt_ptr_op(process
, OP_NE
, NULL
);
118 tt_ptr_op(data
, OP_NE
, NULL
);
119 tt_int_op(strlen(data
), OP_EQ
, size
);
121 process_data_t
*process_data
= process_get_data(process
);
122 smartlist_add(process_data
->stderr_data
, tor_strdup(data
));
129 process_exit_callback(process_t
*process
, process_exit_code_t exit_code
)
131 tt_ptr_op(process
, OP_NE
, NULL
);
133 process_data_t
*process_data
= process_get_data(process
);
134 process_data
->exit_code
= exit_code
;
137 /* Do not free up our process_t. */
142 test_default_values(void *arg
)
145 process_t
*process
= process_new("/path/to/nothing");
147 /* We are not running by default. */
148 tt_int_op(PROCESS_STATUS_NOT_RUNNING
, OP_EQ
, process_get_status(process
));
150 /* We use the line protocol by default. */
151 tt_int_op(PROCESS_PROTOCOL_LINE
, OP_EQ
, process_get_protocol(process
));
153 /* We don't set any custom data by default. */
154 tt_ptr_op(NULL
, OP_EQ
, process_get_data(process
));
156 /* Our command was given to the process_t's constructor in process_new(). */
157 tt_str_op("/path/to/nothing", OP_EQ
, process_get_command(process
));
159 /* Make sure we are listed in the list of proccesses. */
160 tt_assert(smartlist_contains(process_get_all_processes(),
163 /* Default PID is 0. */
164 tt_u64_op(0, OP_EQ
, process_get_pid(process
));
166 /* Our arguments should be empty. */
168 smartlist_len(process_get_arguments(process
)));
171 process_free(process
);
175 test_environment(void *arg
)
179 process_t
*process
= process_new("");
180 process_environment_t
*env
= NULL
;
182 process_set_environment(process
, "E", "F");
183 process_set_environment(process
, "C", "D");
184 process_set_environment(process
, "A", "B");
186 env
= process_get_environment(process
);
187 tt_mem_op(env
->windows_environment_block
, OP_EQ
,
188 "A=B\0C=D\0E=F\0", 12);
189 tt_str_op(env
->unixoid_environment_block
[0], OP_EQ
,
191 tt_str_op(env
->unixoid_environment_block
[1], OP_EQ
,
193 tt_str_op(env
->unixoid_environment_block
[2], OP_EQ
,
195 tt_ptr_op(env
->unixoid_environment_block
[3], OP_EQ
,
197 process_environment_free(env
);
199 /* Reset our environment. */
200 smartlist_t
*new_env
= smartlist_new();
201 smartlist_add(new_env
, (char *)"FOO=bar");
202 smartlist_add(new_env
, (char *)"HELLO=world");
204 process_reset_environment(process
, new_env
);
205 smartlist_free(new_env
);
207 env
= process_get_environment(process
);
208 tt_mem_op(env
->windows_environment_block
, OP_EQ
,
209 "FOO=bar\0HELLO=world\0", 20);
210 tt_str_op(env
->unixoid_environment_block
[0], OP_EQ
,
212 tt_str_op(env
->unixoid_environment_block
[1], OP_EQ
,
214 tt_ptr_op(env
->unixoid_environment_block
[2], OP_EQ
,
218 process_environment_free(env
);
219 process_free(process
);
223 test_stringified_types(void *arg
)
227 /* process_protocol_t values. */
228 tt_str_op("Raw", OP_EQ
, process_protocol_to_string(PROCESS_PROTOCOL_RAW
));
229 tt_str_op("Line", OP_EQ
, process_protocol_to_string(PROCESS_PROTOCOL_LINE
));
231 /* process_status_t values. */
232 tt_str_op("not running", OP_EQ
,
233 process_status_to_string(PROCESS_STATUS_NOT_RUNNING
));
234 tt_str_op("running", OP_EQ
,
235 process_status_to_string(PROCESS_STATUS_RUNNING
));
236 tt_str_op("error", OP_EQ
,
237 process_status_to_string(PROCESS_STATUS_ERROR
));
244 test_line_protocol_simple(void *arg
)
248 process_data_t
*process_data
= process_data_new();
250 process_t
*process
= process_new("");
251 process_set_data(process
, process_data
);
253 process_set_stdout_read_callback(process
, process_stdout_callback
);
254 process_set_stderr_read_callback(process
, process_stderr_callback
);
256 MOCK(process_read_stdout
, process_mocked_read_stdout
);
257 MOCK(process_read_stderr
, process_mocked_read_stderr
);
259 /* Make sure we are running with the line protocol. */
260 tt_int_op(PROCESS_PROTOCOL_LINE
, OP_EQ
, process_get_protocol(process
));
262 tt_int_op(0, OP_EQ
, smartlist_len(process_data
->stdout_data
));
263 tt_int_op(0, OP_EQ
, smartlist_len(process_data
->stderr_data
));
265 stdout_read_buffer
= "Hello stdout\n";
266 process_notify_event_stdout(process
);
267 tt_ptr_op(NULL
, OP_EQ
, stdout_read_buffer
);
269 stderr_read_buffer
= "Hello stderr\r\n";
270 process_notify_event_stderr(process
);
271 tt_ptr_op(NULL
, OP_EQ
, stderr_read_buffer
);
273 /* Data should be ready. */
274 tt_int_op(1, OP_EQ
, smartlist_len(process_data
->stdout_data
));
275 tt_int_op(1, OP_EQ
, smartlist_len(process_data
->stderr_data
));
277 /* Check if the data is correct. */
278 tt_str_op(smartlist_get(process_data
->stdout_data
, 0), OP_EQ
,
280 tt_str_op(smartlist_get(process_data
->stderr_data
, 0), OP_EQ
,
284 process_data_free(process_data
);
285 process_free(process
);
287 UNMOCK(process_read_stdout
);
288 UNMOCK(process_read_stderr
);
292 test_line_protocol_multi(void *arg
)
296 process_data_t
*process_data
= process_data_new();
298 process_t
*process
= process_new("");
299 process_set_data(process
, process_data
);
300 process_set_stdout_read_callback(process
, process_stdout_callback
);
301 process_set_stderr_read_callback(process
, process_stderr_callback
);
303 MOCK(process_read_stdout
, process_mocked_read_stdout
);
304 MOCK(process_read_stderr
, process_mocked_read_stderr
);
306 /* Make sure we are running with the line protocol. */
307 tt_int_op(PROCESS_PROTOCOL_LINE
, OP_EQ
, process_get_protocol(process
));
309 tt_int_op(0, OP_EQ
, smartlist_len(process_data
->stdout_data
));
310 tt_int_op(0, OP_EQ
, smartlist_len(process_data
->stderr_data
));
312 stdout_read_buffer
= "Hello stdout\r\nOnion Onion Onion\nA B C D\r\n\r\n";
313 process_notify_event_stdout(process
);
314 tt_ptr_op(NULL
, OP_EQ
, stdout_read_buffer
);
316 stderr_read_buffer
= "Hello stderr\nFoo bar baz\nOnion Onion Onion\n";
317 process_notify_event_stderr(process
);
318 tt_ptr_op(NULL
, OP_EQ
, stderr_read_buffer
);
320 /* Data should be ready. */
321 tt_int_op(4, OP_EQ
, smartlist_len(process_data
->stdout_data
));
322 tt_int_op(3, OP_EQ
, smartlist_len(process_data
->stderr_data
));
324 /* Check if the data is correct. */
325 tt_str_op(smartlist_get(process_data
->stdout_data
, 0), OP_EQ
,
327 tt_str_op(smartlist_get(process_data
->stdout_data
, 1), OP_EQ
,
328 "Onion Onion Onion");
329 tt_str_op(smartlist_get(process_data
->stdout_data
, 2), OP_EQ
,
331 tt_str_op(smartlist_get(process_data
->stdout_data
, 3), OP_EQ
,
334 tt_str_op(smartlist_get(process_data
->stderr_data
, 0), OP_EQ
,
336 tt_str_op(smartlist_get(process_data
->stderr_data
, 1), OP_EQ
,
338 tt_str_op(smartlist_get(process_data
->stderr_data
, 2), OP_EQ
,
339 "Onion Onion Onion");
342 process_data_free(process_data
);
343 process_free(process
);
345 UNMOCK(process_read_stdout
);
346 UNMOCK(process_read_stderr
);
350 test_line_protocol_partial(void *arg
)
354 process_data_t
*process_data
= process_data_new();
356 process_t
*process
= process_new("");
357 process_set_data(process
, process_data
);
358 process_set_stdout_read_callback(process
, process_stdout_callback
);
359 process_set_stderr_read_callback(process
, process_stderr_callback
);
361 MOCK(process_read_stdout
, process_mocked_read_stdout
);
362 MOCK(process_read_stderr
, process_mocked_read_stderr
);
364 /* Make sure we are running with the line protocol. */
365 tt_int_op(PROCESS_PROTOCOL_LINE
, OP_EQ
, process_get_protocol(process
));
367 tt_int_op(0, OP_EQ
, smartlist_len(process_data
->stdout_data
));
368 tt_int_op(0, OP_EQ
, smartlist_len(process_data
->stderr_data
));
370 stdout_read_buffer
= "Hello stdout this is a partial line ...";
371 process_notify_event_stdout(process
);
372 tt_ptr_op(NULL
, OP_EQ
, stdout_read_buffer
);
374 stderr_read_buffer
= "Hello stderr this is a partial line ...";
375 process_notify_event_stderr(process
);
376 tt_ptr_op(NULL
, OP_EQ
, stderr_read_buffer
);
378 /* Data should NOT be ready. */
379 tt_int_op(0, OP_EQ
, smartlist_len(process_data
->stdout_data
));
380 tt_int_op(0, OP_EQ
, smartlist_len(process_data
->stderr_data
));
382 stdout_read_buffer
= " the end\nAnother partial string goes here ...";
383 process_notify_event_stdout(process
);
384 tt_ptr_op(NULL
, OP_EQ
, stdout_read_buffer
);
386 stderr_read_buffer
= " the end\nAnother partial string goes here ...";
387 process_notify_event_stderr(process
);
388 tt_ptr_op(NULL
, OP_EQ
, stderr_read_buffer
);
390 /* Some data should be ready. */
391 tt_int_op(1, OP_EQ
, smartlist_len(process_data
->stdout_data
));
392 tt_int_op(1, OP_EQ
, smartlist_len(process_data
->stderr_data
));
394 stdout_read_buffer
= " the end\nFoo bar baz\n";
395 process_notify_event_stdout(process
);
396 tt_ptr_op(NULL
, OP_EQ
, stdout_read_buffer
);
398 stderr_read_buffer
= " the end\nFoo bar baz\n";
399 process_notify_event_stderr(process
);
400 tt_ptr_op(NULL
, OP_EQ
, stderr_read_buffer
);
402 /* Some data should be ready. */
403 tt_int_op(3, OP_EQ
, smartlist_len(process_data
->stdout_data
));
404 tt_int_op(3, OP_EQ
, smartlist_len(process_data
->stderr_data
));
406 /* Check if the data is correct. */
407 tt_str_op(smartlist_get(process_data
->stdout_data
, 0), OP_EQ
,
408 "Hello stdout this is a partial line ... the end");
409 tt_str_op(smartlist_get(process_data
->stdout_data
, 1), OP_EQ
,
410 "Another partial string goes here ... the end");
411 tt_str_op(smartlist_get(process_data
->stdout_data
, 2), OP_EQ
,
414 tt_str_op(smartlist_get(process_data
->stderr_data
, 0), OP_EQ
,
415 "Hello stderr this is a partial line ... the end");
416 tt_str_op(smartlist_get(process_data
->stderr_data
, 1), OP_EQ
,
417 "Another partial string goes here ... the end");
418 tt_str_op(smartlist_get(process_data
->stderr_data
, 2), OP_EQ
,
422 process_data_free(process_data
);
423 process_free(process
);
425 UNMOCK(process_read_stdout
);
426 UNMOCK(process_read_stderr
);
430 test_raw_protocol_simple(void *arg
)
434 process_data_t
*process_data
= process_data_new();
436 process_t
*process
= process_new("");
437 process_set_data(process
, process_data
);
438 process_set_protocol(process
, PROCESS_PROTOCOL_RAW
);
440 process_set_stdout_read_callback(process
, process_stdout_callback
);
441 process_set_stderr_read_callback(process
, process_stderr_callback
);
443 MOCK(process_read_stdout
, process_mocked_read_stdout
);
444 MOCK(process_read_stderr
, process_mocked_read_stderr
);
446 /* Make sure we are running with the raw protocol. */
447 tt_int_op(PROCESS_PROTOCOL_RAW
, OP_EQ
, process_get_protocol(process
));
449 tt_int_op(0, OP_EQ
, smartlist_len(process_data
->stdout_data
));
450 tt_int_op(0, OP_EQ
, smartlist_len(process_data
->stderr_data
));
452 stdout_read_buffer
= "Hello stdout\n";
453 process_notify_event_stdout(process
);
454 tt_ptr_op(NULL
, OP_EQ
, stdout_read_buffer
);
456 stderr_read_buffer
= "Hello stderr\n";
457 process_notify_event_stderr(process
);
458 tt_ptr_op(NULL
, OP_EQ
, stderr_read_buffer
);
460 /* Data should be ready. */
461 tt_int_op(1, OP_EQ
, smartlist_len(process_data
->stdout_data
));
462 tt_int_op(1, OP_EQ
, smartlist_len(process_data
->stderr_data
));
464 stdout_read_buffer
= "Hello, again, stdout\nThis contains multiple lines";
465 process_notify_event_stdout(process
);
466 tt_ptr_op(NULL
, OP_EQ
, stdout_read_buffer
);
468 stderr_read_buffer
= "Hello, again, stderr\nThis contains multiple lines";
469 process_notify_event_stderr(process
);
470 tt_ptr_op(NULL
, OP_EQ
, stderr_read_buffer
);
472 /* Data should be ready. */
473 tt_int_op(2, OP_EQ
, smartlist_len(process_data
->stdout_data
));
474 tt_int_op(2, OP_EQ
, smartlist_len(process_data
->stderr_data
));
476 /* Check if the data is correct. */
477 tt_str_op(smartlist_get(process_data
->stdout_data
, 0), OP_EQ
,
479 tt_str_op(smartlist_get(process_data
->stdout_data
, 1), OP_EQ
,
480 "Hello, again, stdout\nThis contains multiple lines");
482 tt_str_op(smartlist_get(process_data
->stderr_data
, 0), OP_EQ
,
484 tt_str_op(smartlist_get(process_data
->stderr_data
, 1), OP_EQ
,
485 "Hello, again, stderr\nThis contains multiple lines");
488 process_data_free(process_data
);
489 process_free(process
);
491 UNMOCK(process_read_stdout
);
492 UNMOCK(process_read_stderr
);
496 test_write_simple(void *arg
)
500 process_data_t
*process_data
= process_data_new();
502 process_t
*process
= process_new("");
503 process_set_data(process
, process_data
);
505 MOCK(process_write_stdin
, process_mocked_write_stdin
);
507 process_write(process
, (uint8_t *)"Hello world\n", 12);
508 process_notify_event_stdin(process
);
509 tt_int_op(1, OP_EQ
, smartlist_len(process_data
->stdin_data
));
511 process_printf(process
, "Hello %s !\n", "moon");
512 process_notify_event_stdin(process
);
513 tt_int_op(2, OP_EQ
, smartlist_len(process_data
->stdin_data
));
516 process_data_free(process_data
);
517 process_free(process
);
519 UNMOCK(process_write_stdin
);
523 test_exit_simple(void *arg
)
527 process_data_t
*process_data
= process_data_new();
529 process_t
*process
= process_new("");
530 process_set_data(process
, process_data
);
531 process_set_exit_callback(process
, process_exit_callback
);
533 /* Our default is 0. */
534 tt_u64_op(0, OP_EQ
, process_data
->exit_code
);
536 /* Fake that we are a running process. */
537 process_set_status(process
, PROCESS_STATUS_RUNNING
);
538 tt_int_op(process_get_status(process
), OP_EQ
, PROCESS_STATUS_RUNNING
);
541 process_notify_event_exit(process
, 1337);
543 /* Check if our state changed and if our callback fired. */
544 tt_int_op(process_get_status(process
), OP_EQ
, PROCESS_STATUS_NOT_RUNNING
);
545 tt_u64_op(1337, OP_EQ
, process_data
->exit_code
);
548 process_set_data(process
, process_data
);
549 process_data_free(process_data
);
550 process_free(process
);
554 test_argv_simple(void *arg
)
558 process_t
*process
= process_new("/bin/cat");
561 /* Setup some arguments. */
562 process_append_argument(process
, "foo");
563 process_append_argument(process
, "bar");
564 process_append_argument(process
, "baz");
566 /* Check the number of elements. */
568 smartlist_len(process_get_arguments(process
)));
570 /* Let's try to convert it into a Unix style char **argv. */
571 argv
= process_get_argv(process
);
573 /* Check our values. */
574 tt_str_op(argv
[0], OP_EQ
, "/bin/cat");
575 tt_str_op(argv
[1], OP_EQ
, "foo");
576 tt_str_op(argv
[2], OP_EQ
, "bar");
577 tt_str_op(argv
[3], OP_EQ
, "baz");
578 tt_ptr_op(argv
[4], OP_EQ
, NULL
);
582 process_free(process
);
590 process_t
*process
= process_new("");
592 /* On Unix all processes should have a Unix process handle. */
593 tt_ptr_op(NULL
, OP_NE
, process_get_unix_process(process
));
596 process_free(process
);
601 test_win32(void *arg
)
605 process_t
*process
= process_new("");
606 char *joined_argv
= NULL
;
608 /* On Win32 all processes should have a Win32 process handle. */
609 tt_ptr_op(NULL
, OP_NE
, process_get_win32_process(process
));
611 /* Based on some test cases from "Parsing C++ Command-Line Arguments" in
612 * MSDN but we don't exercise all quoting rules because tor_join_win_cmdline
613 * will try to only generate simple cases for the child process to parse;
614 * i.e. we never embed quoted strings in arguments. */
616 const char *argvs
[][4] = {
617 {"a", "bb", "CCC", NULL
}, // Normal
618 {NULL
, NULL
, NULL
, NULL
}, // Empty argument list
619 {"", NULL
, NULL
, NULL
}, // Empty argument
620 {"\"a", "b\"b", "CCC\"", NULL
}, // Quotes
621 {"a\tbc", "dd dd", "E", NULL
}, // Whitespace
622 {"a\\\\\\b", "de fg", "H", NULL
}, // Backslashes
623 {"a\\\"b", "\\c", "D\\", NULL
}, // Backslashes before quote
624 {"a\\\\b c", "d", "E", NULL
}, // Backslashes not before quote
625 { NULL
} // Terminator
628 const char *cmdlines
[] = {
632 "\\\"a b\\\"b CCC\\\"",
633 "\"a\tbc\" \"dd dd\" E",
634 "a\\\\\\b \"de fg\" H",
635 "a\\\\\\\"b \\c D\\",
642 for (i
=0; cmdlines
[i
]!=NULL
; i
++) {
643 log_info(LD_GENERAL
, "Joining argvs[%d], expecting <%s>", i
, cmdlines
[i
]);
644 joined_argv
= tor_join_win_cmdline(argvs
[i
]);
645 tt_str_op(cmdlines
[i
],OP_EQ
, joined_argv
);
646 tor_free(joined_argv
);
650 tor_free(joined_argv
);
651 process_free(process
);
655 struct testcase_t process_tests
[] = {
656 { "default_values", test_default_values
, TT_FORK
, NULL
, NULL
},
657 { "environment", test_environment
, TT_FORK
, NULL
, NULL
},
658 { "stringified_types", test_stringified_types
, TT_FORK
, NULL
, NULL
},
659 { "line_protocol_simple", test_line_protocol_simple
, TT_FORK
, NULL
, NULL
},
660 { "line_protocol_multi", test_line_protocol_multi
, TT_FORK
, NULL
, NULL
},
661 { "line_protocol_partial", test_line_protocol_partial
, TT_FORK
, NULL
, NULL
},
662 { "raw_protocol_simple", test_raw_protocol_simple
, TT_FORK
, NULL
, NULL
},
663 { "write_simple", test_write_simple
, TT_FORK
, NULL
, NULL
},
664 { "exit_simple", test_exit_simple
, TT_FORK
, NULL
, NULL
},
665 { "argv_simple", test_argv_simple
, TT_FORK
, NULL
, NULL
},
666 { "unix", test_unix
, TT_FORK
, NULL
, NULL
},
667 { "win32", test_win32
, TT_FORK
, NULL
, NULL
},