test_process.c (20274B)
1 /* Copyright (c) 2018-2021, The Tor Project, Inc. */ 2 /* See LICENSE for licensing information */ 3 4 /** 5 * \file test_process.c 6 * \brief Test cases for the Process API. 7 */ 8 9 #include "orconfig.h" 10 #include "core/or/or.h" 11 #include "test/test.h" 12 #include "lib/process/env.h" 13 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" 20 21 static const char *stdout_read_buffer; 22 static const char *stderr_read_buffer; 23 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; 29 }; 30 31 typedef struct process_data_t process_data_t; 32 33 static process_data_t * 34 process_data_new(void) 35 { 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(); 40 return process_data; 41 } 42 43 static void 44 process_data_free(process_data_t *process_data) 45 { 46 if (process_data == NULL) 47 return; 48 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)); 52 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); 57 } 58 59 static int 60 process_mocked_read_stdout(process_t *process, buf_t *buffer) 61 { 62 (void)process; 63 64 if (stdout_read_buffer != NULL) { 65 buf_add_string(buffer, stdout_read_buffer); 66 stdout_read_buffer = NULL; 67 } 68 69 return (int)buf_datalen(buffer); 70 } 71 72 static int 73 process_mocked_read_stderr(process_t *process, buf_t *buffer) 74 { 75 (void)process; 76 77 if (stderr_read_buffer != NULL) { 78 buf_add_string(buffer, stderr_read_buffer); 79 stderr_read_buffer = NULL; 80 } 81 82 return (int)buf_datalen(buffer); 83 } 84 85 static void 86 process_mocked_write_stdin(process_t *process, buf_t *buffer) 87 { 88 const size_t size = buf_datalen(buffer); 89 90 if (size == 0) 91 return; 92 93 char *data = tor_malloc_zero(size + 1); 94 process_data_t *process_data = process_get_data(process); 95 96 buf_get_bytes(buffer, data, size); 97 smartlist_add(process_data->stdin_data, data); 98 } 99 100 static void 101 process_stdout_callback(process_t *process, const char *data, size_t size) 102 { 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); 106 107 process_data_t *process_data = process_get_data(process); 108 smartlist_add(process_data->stdout_data, tor_strdup(data)); 109 110 done: 111 return; 112 } 113 114 static void 115 process_stderr_callback(process_t *process, const char *data, size_t size) 116 { 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); 120 121 process_data_t *process_data = process_get_data(process); 122 smartlist_add(process_data->stderr_data, tor_strdup(data)); 123 124 done: 125 return; 126 } 127 128 static bool 129 process_exit_callback(process_t *process, process_exit_code_t exit_code) 130 { 131 tt_ptr_op(process, OP_NE, NULL); 132 133 process_data_t *process_data = process_get_data(process); 134 process_data->exit_code = exit_code; 135 136 done: 137 /* Do not free up our process_t. */ 138 return false; 139 } 140 141 static void 142 test_default_values(void *arg) 143 { 144 (void)arg; 145 process_t *process = process_new("/path/to/nothing"); 146 147 /* We are not running by default. */ 148 tt_int_op(PROCESS_STATUS_NOT_RUNNING, OP_EQ, process_get_status(process)); 149 150 /* We use the line protocol by default. */ 151 tt_int_op(PROCESS_PROTOCOL_LINE, OP_EQ, process_get_protocol(process)); 152 153 /* We don't set any custom data by default. */ 154 tt_ptr_op(NULL, OP_EQ, process_get_data(process)); 155 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)); 158 159 /* Make sure we are listed in the list of processes. */ 160 tt_assert(smartlist_contains(process_get_all_processes(), 161 process)); 162 163 /* Default PID is 0. */ 164 tt_u64_op(0, OP_EQ, process_get_pid(process)); 165 166 /* Our arguments should be empty. */ 167 tt_int_op(0, OP_EQ, 168 smartlist_len(process_get_arguments(process))); 169 170 done: 171 process_free(process); 172 } 173 174 static void 175 test_environment(void *arg) 176 { 177 (void)arg; 178 179 process_t *process = process_new(""); 180 process_environment_t *env = NULL; 181 182 process_set_environment(process, "E", "F"); 183 process_set_environment(process, "C", "D"); 184 process_set_environment(process, "A", "B"); 185 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, 190 "A=B"); 191 tt_str_op(env->unixoid_environment_block[1], OP_EQ, 192 "C=D"); 193 tt_str_op(env->unixoid_environment_block[2], OP_EQ, 194 "E=F"); 195 tt_ptr_op(env->unixoid_environment_block[3], OP_EQ, 196 NULL); 197 process_environment_free(env); 198 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"); 203 204 process_reset_environment(process, new_env); 205 smartlist_free(new_env); 206 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, 211 "FOO=bar"); 212 tt_str_op(env->unixoid_environment_block[1], OP_EQ, 213 "HELLO=world"); 214 tt_ptr_op(env->unixoid_environment_block[2], OP_EQ, 215 NULL); 216 217 done: 218 process_environment_free(env); 219 process_free(process); 220 } 221 222 static void 223 test_stringified_types(void *arg) 224 { 225 (void)arg; 226 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)); 230 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)); 238 239 done: 240 return; 241 } 242 243 static void 244 test_line_protocol_simple(void *arg) 245 { 246 (void)arg; 247 248 process_data_t *process_data = process_data_new(); 249 250 process_t *process = process_new(""); 251 process_set_data(process, process_data); 252 253 process_set_stdout_read_callback(process, process_stdout_callback); 254 process_set_stderr_read_callback(process, process_stderr_callback); 255 256 MOCK(process_read_stdout, process_mocked_read_stdout); 257 MOCK(process_read_stderr, process_mocked_read_stderr); 258 259 /* Make sure we are running with the line protocol. */ 260 tt_int_op(PROCESS_PROTOCOL_LINE, OP_EQ, process_get_protocol(process)); 261 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)); 264 265 stdout_read_buffer = "Hello stdout\n"; 266 process_notify_event_stdout(process); 267 tt_ptr_op(NULL, OP_EQ, stdout_read_buffer); 268 269 stderr_read_buffer = "Hello stderr\r\n"; 270 process_notify_event_stderr(process); 271 tt_ptr_op(NULL, OP_EQ, stderr_read_buffer); 272 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)); 276 277 /* Check if the data is correct. */ 278 tt_str_op(smartlist_get(process_data->stdout_data, 0), OP_EQ, 279 "Hello stdout"); 280 tt_str_op(smartlist_get(process_data->stderr_data, 0), OP_EQ, 281 "Hello stderr"); 282 283 done: 284 process_data_free(process_data); 285 process_free(process); 286 287 UNMOCK(process_read_stdout); 288 UNMOCK(process_read_stderr); 289 } 290 291 static void 292 test_line_protocol_multi(void *arg) 293 { 294 (void)arg; 295 296 process_data_t *process_data = process_data_new(); 297 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); 302 303 MOCK(process_read_stdout, process_mocked_read_stdout); 304 MOCK(process_read_stderr, process_mocked_read_stderr); 305 306 /* Make sure we are running with the line protocol. */ 307 tt_int_op(PROCESS_PROTOCOL_LINE, OP_EQ, process_get_protocol(process)); 308 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)); 311 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); 315 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); 319 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)); 323 324 /* Check if the data is correct. */ 325 tt_str_op(smartlist_get(process_data->stdout_data, 0), OP_EQ, 326 "Hello stdout"); 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, 330 "A B C D"); 331 tt_str_op(smartlist_get(process_data->stdout_data, 3), OP_EQ, 332 ""); 333 334 tt_str_op(smartlist_get(process_data->stderr_data, 0), OP_EQ, 335 "Hello stderr"); 336 tt_str_op(smartlist_get(process_data->stderr_data, 1), OP_EQ, 337 "Foo bar baz"); 338 tt_str_op(smartlist_get(process_data->stderr_data, 2), OP_EQ, 339 "Onion Onion Onion"); 340 341 done: 342 process_data_free(process_data); 343 process_free(process); 344 345 UNMOCK(process_read_stdout); 346 UNMOCK(process_read_stderr); 347 } 348 349 static void 350 test_line_protocol_partial(void *arg) 351 { 352 (void)arg; 353 354 process_data_t *process_data = process_data_new(); 355 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); 360 361 MOCK(process_read_stdout, process_mocked_read_stdout); 362 MOCK(process_read_stderr, process_mocked_read_stderr); 363 364 /* Make sure we are running with the line protocol. */ 365 tt_int_op(PROCESS_PROTOCOL_LINE, OP_EQ, process_get_protocol(process)); 366 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)); 369 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); 373 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); 377 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)); 381 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); 385 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); 389 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)); 393 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); 397 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); 401 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)); 405 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, 412 "Foo bar baz"); 413 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, 419 "Foo bar baz"); 420 421 done: 422 process_data_free(process_data); 423 process_free(process); 424 425 UNMOCK(process_read_stdout); 426 UNMOCK(process_read_stderr); 427 } 428 429 static void 430 test_raw_protocol_simple(void *arg) 431 { 432 (void)arg; 433 434 process_data_t *process_data = process_data_new(); 435 436 process_t *process = process_new(""); 437 process_set_data(process, process_data); 438 process_set_protocol(process, PROCESS_PROTOCOL_RAW); 439 440 process_set_stdout_read_callback(process, process_stdout_callback); 441 process_set_stderr_read_callback(process, process_stderr_callback); 442 443 MOCK(process_read_stdout, process_mocked_read_stdout); 444 MOCK(process_read_stderr, process_mocked_read_stderr); 445 446 /* Make sure we are running with the raw protocol. */ 447 tt_int_op(PROCESS_PROTOCOL_RAW, OP_EQ, process_get_protocol(process)); 448 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)); 451 452 stdout_read_buffer = "Hello stdout\n"; 453 process_notify_event_stdout(process); 454 tt_ptr_op(NULL, OP_EQ, stdout_read_buffer); 455 456 stderr_read_buffer = "Hello stderr\n"; 457 process_notify_event_stderr(process); 458 tt_ptr_op(NULL, OP_EQ, stderr_read_buffer); 459 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)); 463 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); 467 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); 471 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)); 475 476 /* Check if the data is correct. */ 477 tt_str_op(smartlist_get(process_data->stdout_data, 0), OP_EQ, 478 "Hello stdout\n"); 479 tt_str_op(smartlist_get(process_data->stdout_data, 1), OP_EQ, 480 "Hello, again, stdout\nThis contains multiple lines"); 481 482 tt_str_op(smartlist_get(process_data->stderr_data, 0), OP_EQ, 483 "Hello stderr\n"); 484 tt_str_op(smartlist_get(process_data->stderr_data, 1), OP_EQ, 485 "Hello, again, stderr\nThis contains multiple lines"); 486 487 done: 488 process_data_free(process_data); 489 process_free(process); 490 491 UNMOCK(process_read_stdout); 492 UNMOCK(process_read_stderr); 493 } 494 495 static void 496 test_write_simple(void *arg) 497 { 498 (void)arg; 499 500 process_data_t *process_data = process_data_new(); 501 502 process_t *process = process_new(""); 503 process_set_data(process, process_data); 504 505 MOCK(process_write_stdin, process_mocked_write_stdin); 506 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)); 510 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)); 514 515 done: 516 process_data_free(process_data); 517 process_free(process); 518 519 UNMOCK(process_write_stdin); 520 } 521 522 static void 523 test_exit_simple(void *arg) 524 { 525 (void)arg; 526 527 process_data_t *process_data = process_data_new(); 528 529 process_t *process = process_new(""); 530 process_set_data(process, process_data); 531 process_set_exit_callback(process, process_exit_callback); 532 533 /* Our default is 0. */ 534 tt_u64_op(0, OP_EQ, process_data->exit_code); 535 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); 539 540 /* Fake an exit. */ 541 process_notify_event_exit(process, 1337); 542 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); 546 547 done: 548 process_set_data(process, process_data); 549 process_data_free(process_data); 550 process_free(process); 551 } 552 553 static void 554 test_argv_simple(void *arg) 555 { 556 (void)arg; 557 558 process_t *process = process_new("/bin/cat"); 559 char **argv = NULL; 560 561 /* Setup some arguments. */ 562 process_append_argument(process, "foo"); 563 process_append_argument(process, "bar"); 564 process_append_argument(process, "baz"); 565 566 /* Check the number of elements. */ 567 tt_int_op(3, OP_EQ, 568 smartlist_len(process_get_arguments(process))); 569 570 /* Let's try to convert it into a Unix style char **argv. */ 571 argv = process_get_argv(process); 572 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); 579 580 done: 581 tor_free(argv); 582 process_free(process); 583 } 584 585 static void 586 test_unix(void *arg) 587 { 588 (void)arg; 589 #ifndef _WIN32 590 process_t *process = process_new(""); 591 592 /* On Unix all processes should have a Unix process handle. */ 593 tt_ptr_op(NULL, OP_NE, process_get_unix_process(process)); 594 595 done: 596 process_free(process); 597 #endif /* !defined(_WIN32) */ 598 } 599 600 static void 601 test_win32(void *arg) 602 { 603 (void)arg; 604 #ifdef _WIN32 605 process_t *process = process_new(""); 606 char *joined_argv = NULL; 607 608 /* On Win32 all processes should have a Win32 process handle. */ 609 tt_ptr_op(NULL, OP_NE, process_get_win32_process(process)); 610 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. */ 615 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 626 }; 627 628 const char *cmdlines[] = { 629 "a bb CCC", 630 "", 631 "\"\"", 632 "\\\"a b\\\"b CCC\\\"", 633 "\"a\tbc\" \"dd dd\" E", 634 "a\\\\\\b \"de fg\" H", 635 "a\\\\\\\"b \\c D\\", 636 "\"a\\\\b c\" d E", 637 NULL // Terminator 638 }; 639 640 int i; 641 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); 647 } 648 649 done: 650 tor_free(joined_argv); 651 process_free(process); 652 #endif /* defined(_WIN32) */ 653 } 654 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 }, 668 END_OF_TESTCASES 669 };