test_process.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. /* Copyright (c) 2018, The Tor Project, Inc. */
  2. /* See LICENSE for licensing information */
  3. /**
  4. * \file test_process.c
  5. * \brief Test cases for the Process API.
  6. */
  7. #include "orconfig.h"
  8. #include "core/or/or.h"
  9. #include "test/test.h"
  10. #define PROCESS_PRIVATE
  11. #include "lib/process/process.h"
  12. static const char *stdout_read_buffer;
  13. static const char *stderr_read_buffer;
  14. struct process_data_t {
  15. smartlist_t *stdout_data;
  16. smartlist_t *stderr_data;
  17. smartlist_t *stdin_data;
  18. process_exit_code_t exit_code;
  19. };
  20. typedef struct process_data_t process_data_t;
  21. static process_data_t *
  22. process_data_new(void)
  23. {
  24. process_data_t *process_data = tor_malloc_zero(sizeof(process_data_t));
  25. process_data->stdout_data = smartlist_new();
  26. process_data->stderr_data = smartlist_new();
  27. process_data->stdin_data = smartlist_new();
  28. return process_data;
  29. }
  30. static void
  31. process_data_free(process_data_t *process_data)
  32. {
  33. if (process_data == NULL)
  34. return;
  35. SMARTLIST_FOREACH(process_data->stdout_data, char *, x, tor_free(x));
  36. SMARTLIST_FOREACH(process_data->stderr_data, char *, x, tor_free(x));
  37. SMARTLIST_FOREACH(process_data->stdin_data, char *, x, tor_free(x));
  38. smartlist_free(process_data->stdout_data);
  39. smartlist_free(process_data->stderr_data);
  40. smartlist_free(process_data->stdin_data);
  41. tor_free(process_data);
  42. }
  43. static int
  44. process_mocked_read_stdout(process_t *process, buf_t *buffer)
  45. {
  46. (void)process;
  47. if (stdout_read_buffer != NULL) {
  48. buf_add_string(buffer, stdout_read_buffer);
  49. stdout_read_buffer = NULL;
  50. }
  51. return (int)buf_datalen(buffer);
  52. }
  53. static int
  54. process_mocked_read_stderr(process_t *process, buf_t *buffer)
  55. {
  56. (void)process;
  57. if (stderr_read_buffer != NULL) {
  58. buf_add_string(buffer, stderr_read_buffer);
  59. stderr_read_buffer = NULL;
  60. }
  61. return (int)buf_datalen(buffer);
  62. }
  63. static void
  64. process_mocked_write_stdin(process_t *process, buf_t *buffer)
  65. {
  66. const size_t size = buf_datalen(buffer);
  67. if (size == 0)
  68. return;
  69. char *data = tor_malloc_zero(size + 1);
  70. process_data_t *process_data = process_get_data(process);
  71. buf_get_bytes(buffer, data, size);
  72. smartlist_add(process_data->stdin_data, data);
  73. }
  74. static void
  75. process_stdout_callback(process_t *process, char *data, size_t size)
  76. {
  77. tt_ptr_op(process, OP_NE, NULL);
  78. tt_ptr_op(data, OP_NE, NULL);
  79. tt_int_op(strlen(data), OP_EQ, size);
  80. process_data_t *process_data = process_get_data(process);
  81. smartlist_add(process_data->stdout_data, tor_strdup(data));
  82. done:
  83. return;
  84. }
  85. static void
  86. process_stderr_callback(process_t *process, char *data, size_t size)
  87. {
  88. tt_ptr_op(process, OP_NE, NULL);
  89. tt_ptr_op(data, OP_NE, NULL);
  90. tt_int_op(strlen(data), OP_EQ, size);
  91. process_data_t *process_data = process_get_data(process);
  92. smartlist_add(process_data->stderr_data, tor_strdup(data));
  93. done:
  94. return;
  95. }
  96. static void
  97. process_exit_callback(process_t *process, process_exit_code_t exit_code)
  98. {
  99. tt_ptr_op(process, OP_NE, NULL);
  100. process_data_t *process_data = process_get_data(process);
  101. process_data->exit_code = exit_code;
  102. done:
  103. return;
  104. }
  105. static void
  106. test_default_values(void *arg)
  107. {
  108. (void)arg;
  109. process_init();
  110. process_t *process = process_new("/path/to/nothing");
  111. /* We are not running by default. */
  112. tt_int_op(PROCESS_STATUS_NOT_RUNNING, OP_EQ, process_get_status(process));
  113. /* We use the line protocol by default. */
  114. tt_int_op(PROCESS_PROTOCOL_LINE, OP_EQ, process_get_protocol(process));
  115. /* We don't set any custom data by default. */
  116. tt_ptr_op(NULL, OP_EQ, process_get_data(process));
  117. /* Our command was given to the process_t's constructor in process_new(). */
  118. tt_str_op("/path/to/nothing", OP_EQ, process_get_command(process));
  119. /* Make sure we are listed in the list of proccesses. */
  120. tt_assert(smartlist_contains(process_get_all_processes(),
  121. process));
  122. /* Our arguments should be empty. */
  123. tt_int_op(0, OP_EQ,
  124. smartlist_len(process_get_arguments(process)));
  125. done:
  126. process_free(process);
  127. process_free_all();
  128. }
  129. static void
  130. test_stringified_types(void *arg)
  131. {
  132. (void)arg;
  133. /* process_protocol_t values. */
  134. tt_str_op("Raw", OP_EQ, process_protocol_to_string(PROCESS_PROTOCOL_RAW));
  135. tt_str_op("Line", OP_EQ, process_protocol_to_string(PROCESS_PROTOCOL_LINE));
  136. /* process_status_t values. */
  137. tt_str_op("not running", OP_EQ,
  138. process_status_to_string(PROCESS_STATUS_NOT_RUNNING));
  139. tt_str_op("running", OP_EQ,
  140. process_status_to_string(PROCESS_STATUS_RUNNING));
  141. tt_str_op("error", OP_EQ,
  142. process_status_to_string(PROCESS_STATUS_ERROR));
  143. done:
  144. return;
  145. }
  146. static void
  147. test_line_protocol_simple(void *arg)
  148. {
  149. (void)arg;
  150. process_init();
  151. process_data_t *process_data = process_data_new();
  152. process_t *process = process_new("");
  153. process_set_data(process, process_data);
  154. process_set_stdout_read_callback(process, process_stdout_callback);
  155. process_set_stderr_read_callback(process, process_stderr_callback);
  156. MOCK(process_read_stdout, process_mocked_read_stdout);
  157. MOCK(process_read_stderr, process_mocked_read_stderr);
  158. /* Make sure we are running with the line protocol. */
  159. tt_int_op(PROCESS_PROTOCOL_LINE, OP_EQ, process_get_protocol(process));
  160. tt_int_op(0, OP_EQ, smartlist_len(process_data->stdout_data));
  161. tt_int_op(0, OP_EQ, smartlist_len(process_data->stderr_data));
  162. stdout_read_buffer = "Hello stdout\n";
  163. process_notify_event_stdout(process);
  164. tt_ptr_op(NULL, OP_EQ, stdout_read_buffer);
  165. stderr_read_buffer = "Hello stderr\r\n";
  166. process_notify_event_stderr(process);
  167. tt_ptr_op(NULL, OP_EQ, stderr_read_buffer);
  168. /* Data should be ready. */
  169. tt_int_op(1, OP_EQ, smartlist_len(process_data->stdout_data));
  170. tt_int_op(1, OP_EQ, smartlist_len(process_data->stderr_data));
  171. /* Check if the data is correct. */
  172. tt_str_op(smartlist_get(process_data->stdout_data, 0), OP_EQ,
  173. "Hello stdout");
  174. tt_str_op(smartlist_get(process_data->stderr_data, 0), OP_EQ,
  175. "Hello stderr");
  176. done:
  177. process_data_free(process_data);
  178. process_free(process);
  179. process_free_all();
  180. UNMOCK(process_read_stdout);
  181. UNMOCK(process_read_stderr);
  182. }
  183. static void
  184. test_line_protocol_multi(void *arg)
  185. {
  186. (void)arg;
  187. process_init();
  188. process_data_t *process_data = process_data_new();
  189. process_t *process = process_new("");
  190. process_set_data(process, process_data);
  191. process_set_stdout_read_callback(process, process_stdout_callback);
  192. process_set_stderr_read_callback(process, process_stderr_callback);
  193. MOCK(process_read_stdout, process_mocked_read_stdout);
  194. MOCK(process_read_stderr, process_mocked_read_stderr);
  195. /* Make sure we are running with the line protocol. */
  196. tt_int_op(PROCESS_PROTOCOL_LINE, OP_EQ, process_get_protocol(process));
  197. tt_int_op(0, OP_EQ, smartlist_len(process_data->stdout_data));
  198. tt_int_op(0, OP_EQ, smartlist_len(process_data->stderr_data));
  199. stdout_read_buffer = "Hello stdout\r\nOnion Onion Onion\nA B C D\r\n\r\n";
  200. process_notify_event_stdout(process);
  201. tt_ptr_op(NULL, OP_EQ, stdout_read_buffer);
  202. stderr_read_buffer = "Hello stderr\nFoo bar baz\nOnion Onion Onion\n";
  203. process_notify_event_stderr(process);
  204. tt_ptr_op(NULL, OP_EQ, stderr_read_buffer);
  205. /* Data should be ready. */
  206. tt_int_op(4, OP_EQ, smartlist_len(process_data->stdout_data));
  207. tt_int_op(3, OP_EQ, smartlist_len(process_data->stderr_data));
  208. /* Check if the data is correct. */
  209. tt_str_op(smartlist_get(process_data->stdout_data, 0), OP_EQ,
  210. "Hello stdout");
  211. tt_str_op(smartlist_get(process_data->stdout_data, 1), OP_EQ,
  212. "Onion Onion Onion");
  213. tt_str_op(smartlist_get(process_data->stdout_data, 2), OP_EQ,
  214. "A B C D");
  215. tt_str_op(smartlist_get(process_data->stdout_data, 3), OP_EQ,
  216. "");
  217. tt_str_op(smartlist_get(process_data->stderr_data, 0), OP_EQ,
  218. "Hello stderr");
  219. tt_str_op(smartlist_get(process_data->stderr_data, 1), OP_EQ,
  220. "Foo bar baz");
  221. tt_str_op(smartlist_get(process_data->stderr_data, 2), OP_EQ,
  222. "Onion Onion Onion");
  223. done:
  224. process_data_free(process_data);
  225. process_free(process);
  226. process_free_all();
  227. UNMOCK(process_read_stdout);
  228. UNMOCK(process_read_stderr);
  229. }
  230. static void
  231. test_line_protocol_partial(void *arg)
  232. {
  233. (void)arg;
  234. process_init();
  235. process_data_t *process_data = process_data_new();
  236. process_t *process = process_new("");
  237. process_set_data(process, process_data);
  238. process_set_stdout_read_callback(process, process_stdout_callback);
  239. process_set_stderr_read_callback(process, process_stderr_callback);
  240. MOCK(process_read_stdout, process_mocked_read_stdout);
  241. MOCK(process_read_stderr, process_mocked_read_stderr);
  242. /* Make sure we are running with the line protocol. */
  243. tt_int_op(PROCESS_PROTOCOL_LINE, OP_EQ, process_get_protocol(process));
  244. tt_int_op(0, OP_EQ, smartlist_len(process_data->stdout_data));
  245. tt_int_op(0, OP_EQ, smartlist_len(process_data->stderr_data));
  246. stdout_read_buffer = "Hello stdout this is a partial line ...";
  247. process_notify_event_stdout(process);
  248. tt_ptr_op(NULL, OP_EQ, stdout_read_buffer);
  249. stderr_read_buffer = "Hello stderr this is a partial line ...";
  250. process_notify_event_stderr(process);
  251. tt_ptr_op(NULL, OP_EQ, stderr_read_buffer);
  252. /* Data should NOT be ready. */
  253. tt_int_op(0, OP_EQ, smartlist_len(process_data->stdout_data));
  254. tt_int_op(0, OP_EQ, smartlist_len(process_data->stderr_data));
  255. stdout_read_buffer = " the end\nAnother partial string goes here ...";
  256. process_notify_event_stdout(process);
  257. tt_ptr_op(NULL, OP_EQ, stdout_read_buffer);
  258. stderr_read_buffer = " the end\nAnother partial string goes here ...";
  259. process_notify_event_stderr(process);
  260. tt_ptr_op(NULL, OP_EQ, stderr_read_buffer);
  261. /* Some data should be ready. */
  262. tt_int_op(1, OP_EQ, smartlist_len(process_data->stdout_data));
  263. tt_int_op(1, OP_EQ, smartlist_len(process_data->stderr_data));
  264. stdout_read_buffer = " the end\nFoo bar baz\n";
  265. process_notify_event_stdout(process);
  266. tt_ptr_op(NULL, OP_EQ, stdout_read_buffer);
  267. stderr_read_buffer = " the end\nFoo bar baz\n";
  268. process_notify_event_stderr(process);
  269. tt_ptr_op(NULL, OP_EQ, stderr_read_buffer);
  270. /* Some data should be ready. */
  271. tt_int_op(3, OP_EQ, smartlist_len(process_data->stdout_data));
  272. tt_int_op(3, OP_EQ, smartlist_len(process_data->stderr_data));
  273. /* Check if the data is correct. */
  274. tt_str_op(smartlist_get(process_data->stdout_data, 0), OP_EQ,
  275. "Hello stdout this is a partial line ... the end");
  276. tt_str_op(smartlist_get(process_data->stdout_data, 1), OP_EQ,
  277. "Another partial string goes here ... the end");
  278. tt_str_op(smartlist_get(process_data->stdout_data, 2), OP_EQ,
  279. "Foo bar baz");
  280. tt_str_op(smartlist_get(process_data->stderr_data, 0), OP_EQ,
  281. "Hello stderr this is a partial line ... the end");
  282. tt_str_op(smartlist_get(process_data->stderr_data, 1), OP_EQ,
  283. "Another partial string goes here ... the end");
  284. tt_str_op(smartlist_get(process_data->stderr_data, 2), OP_EQ,
  285. "Foo bar baz");
  286. done:
  287. process_data_free(process_data);
  288. process_free(process);
  289. process_free_all();
  290. UNMOCK(process_read_stdout);
  291. UNMOCK(process_read_stderr);
  292. }
  293. static void
  294. test_raw_protocol_simple(void *arg)
  295. {
  296. (void)arg;
  297. process_init();
  298. process_data_t *process_data = process_data_new();
  299. process_t *process = process_new("");
  300. process_set_data(process, process_data);
  301. process_set_protocol(process, PROCESS_PROTOCOL_RAW);
  302. process_set_stdout_read_callback(process, process_stdout_callback);
  303. process_set_stderr_read_callback(process, process_stderr_callback);
  304. MOCK(process_read_stdout, process_mocked_read_stdout);
  305. MOCK(process_read_stderr, process_mocked_read_stderr);
  306. /* Make sure we are running with the raw protocol. */
  307. tt_int_op(PROCESS_PROTOCOL_RAW, OP_EQ, process_get_protocol(process));
  308. tt_int_op(0, OP_EQ, smartlist_len(process_data->stdout_data));
  309. tt_int_op(0, OP_EQ, smartlist_len(process_data->stderr_data));
  310. stdout_read_buffer = "Hello stdout\n";
  311. process_notify_event_stdout(process);
  312. tt_ptr_op(NULL, OP_EQ, stdout_read_buffer);
  313. stderr_read_buffer = "Hello stderr\n";
  314. process_notify_event_stderr(process);
  315. tt_ptr_op(NULL, OP_EQ, stderr_read_buffer);
  316. /* Data should be ready. */
  317. tt_int_op(1, OP_EQ, smartlist_len(process_data->stdout_data));
  318. tt_int_op(1, OP_EQ, smartlist_len(process_data->stderr_data));
  319. stdout_read_buffer = "Hello, again, stdout\nThis contains multiple lines";
  320. process_notify_event_stdout(process);
  321. tt_ptr_op(NULL, OP_EQ, stdout_read_buffer);
  322. stderr_read_buffer = "Hello, again, stderr\nThis contains multiple lines";
  323. process_notify_event_stderr(process);
  324. tt_ptr_op(NULL, OP_EQ, stderr_read_buffer);
  325. /* Data should be ready. */
  326. tt_int_op(2, OP_EQ, smartlist_len(process_data->stdout_data));
  327. tt_int_op(2, OP_EQ, smartlist_len(process_data->stderr_data));
  328. /* Check if the data is correct. */
  329. tt_str_op(smartlist_get(process_data->stdout_data, 0), OP_EQ,
  330. "Hello stdout\n");
  331. tt_str_op(smartlist_get(process_data->stdout_data, 1), OP_EQ,
  332. "Hello, again, stdout\nThis contains multiple lines");
  333. tt_str_op(smartlist_get(process_data->stderr_data, 0), OP_EQ,
  334. "Hello stderr\n");
  335. tt_str_op(smartlist_get(process_data->stderr_data, 1), OP_EQ,
  336. "Hello, again, stderr\nThis contains multiple lines");
  337. done:
  338. process_data_free(process_data);
  339. process_free(process);
  340. process_free_all();
  341. UNMOCK(process_read_stdout);
  342. UNMOCK(process_read_stderr);
  343. }
  344. static void
  345. test_write_simple(void *arg)
  346. {
  347. (void)arg;
  348. process_init();
  349. process_data_t *process_data = process_data_new();
  350. process_t *process = process_new("");
  351. process_set_data(process, process_data);
  352. MOCK(process_write_stdin, process_mocked_write_stdin);
  353. process_write(process, (uint8_t *)"Hello world\n", 12);
  354. process_notify_event_stdin(process);
  355. tt_int_op(1, OP_EQ, smartlist_len(process_data->stdin_data));
  356. process_printf(process, "Hello %s !\n", "moon");
  357. process_notify_event_stdin(process);
  358. tt_int_op(2, OP_EQ, smartlist_len(process_data->stdin_data));
  359. done:
  360. process_data_free(process_data);
  361. process_free(process);
  362. process_free_all();
  363. UNMOCK(process_write_stdin);
  364. }
  365. static void
  366. test_exit_simple(void *arg)
  367. {
  368. (void)arg;
  369. process_init();
  370. process_data_t *process_data = process_data_new();
  371. process_t *process = process_new("");
  372. process_set_data(process, process_data);
  373. process_set_exit_callback(process, process_exit_callback);
  374. /* Our default is 0. */
  375. tt_int_op(0, OP_EQ, process_data->exit_code);
  376. /* Fake that we are a running process. */
  377. process_set_status(process, PROCESS_STATUS_RUNNING);
  378. tt_int_op(process_get_status(process), OP_EQ, PROCESS_STATUS_RUNNING);
  379. /* Fake an exit. */
  380. process_notify_event_exit(process, 1337);
  381. /* Check if our state changed and if our callback fired. */
  382. tt_int_op(process_get_status(process), OP_EQ, PROCESS_STATUS_NOT_RUNNING);
  383. tt_int_op(1337, OP_EQ, process_data->exit_code);
  384. done:
  385. process_set_data(process, process_data);
  386. process_data_free(process_data);
  387. process_free(process);
  388. process_free_all();
  389. }
  390. static void
  391. test_argv_simple(void *arg)
  392. {
  393. (void)arg;
  394. process_init();
  395. process_t *process = process_new("/bin/cat");
  396. char **argv = NULL;
  397. /* Setup some arguments. */
  398. process_append_argument(process, "foo");
  399. process_append_argument(process, "bar");
  400. process_append_argument(process, "baz");
  401. /* Check the number of elements. */
  402. tt_int_op(3, OP_EQ,
  403. smartlist_len(process_get_arguments(process)));
  404. /* Let's try to convert it into a Unix style char **argv. */
  405. argv = process_get_argv(process);
  406. /* Check our values. */
  407. tt_str_op(argv[0], OP_EQ, "/bin/cat");
  408. tt_str_op(argv[1], OP_EQ, "foo");
  409. tt_str_op(argv[2], OP_EQ, "bar");
  410. tt_str_op(argv[3], OP_EQ, "baz");
  411. tt_ptr_op(argv[4], OP_EQ, NULL);
  412. done:
  413. tor_free(argv);
  414. process_free(process);
  415. process_free_all();
  416. }
  417. struct testcase_t process_tests[] = {
  418. { "default_values", test_default_values, TT_FORK, NULL, NULL },
  419. { "stringified_types", test_stringified_types, TT_FORK, NULL, NULL },
  420. { "line_protocol_simple", test_line_protocol_simple, TT_FORK, NULL, NULL },
  421. { "line_protocol_multi", test_line_protocol_multi, TT_FORK, NULL, NULL },
  422. { "line_protocol_partial", test_line_protocol_partial, TT_FORK, NULL, NULL },
  423. { "raw_protocol_simple", test_raw_protocol_simple, TT_FORK, NULL, NULL },
  424. { "write_simple", test_write_simple, TT_FORK, NULL, NULL },
  425. { "exit_simple", test_exit_simple, TT_FORK, NULL, NULL },
  426. { "argv_simple", test_argv_simple, TT_FORK, NULL, NULL },
  427. END_OF_TESTCASES
  428. };