| 1 | #include "libnetdata/libnetdata.h" |
| 2 | |
| 3 | #define ENV_VAR_KEY "SPAWN_TESTER" |
| 4 | #define ENV_VAR_VALUE "1234567890" |
| 5 | |
| 6 | size_t warnings = 0; |
| 7 | |
| 8 | void child_check_environment(void) { |
| 9 | const char *s = getenv(ENV_VAR_KEY); |
| 10 | if(!s || !*s || strcmp(s, ENV_VAR_VALUE) != 0) { |
| 11 | nd_log(NDLS_COLLECTORS, NDLP_ERR, |
| 12 | "Wrong environment. Variable '%s' should have value '%s' but it has '%s'", |
| 13 | ENV_VAR_KEY, ENV_VAR_VALUE, s ? s : "(unset)"); |
| 14 | |
| 15 | exit(1); |
| 16 | } |
| 17 | } |
| 18 | |
| 19 | static bool is_valid_fd(int fd) { |
| 20 | errno_clear(); |
| 21 | return fcntl(fd, F_GETFD) != -1 || errno != EBADF; |
| 22 | } |
| 23 | |
| 24 | void child_check_fds(void) { |
| 25 | for(int fd = 0; fd < 3; fd++) { |
| 26 | if(!is_valid_fd(fd)) { |
| 27 | nd_log(NDLS_COLLECTORS, NDLP_ERR, |
| 28 | "fd No %d should be a valid file descriptor - but it isn't.", fd); |
| 29 | |
| 30 | exit(1); |
| 31 | } |
| 32 | } |
| 33 | |
| 34 | for(int fd = 3; fd < /* os_get_fd_open_max() */ 1024; fd++) { |
| 35 | if(is_valid_fd(fd)) { |
| 36 | nd_log(NDLS_COLLECTORS, NDLP_ERR, |
| 37 | "fd No %d is a valid file descriptor - it shouldn't.", fd); |
| 38 | |
| 39 | exit(1); |
| 40 | } |
| 41 | } |
| 42 | |
| 43 | errno_clear(); |
| 44 | } |
| 45 | |
| 46 | // -------------------------------------------------------------------------------------------------------------------- |
| 47 | |
| 48 | static void test_int_fds_echo_loop(SPAWN_INSTANCE *si, const char *msg, size_t iterations) { |
| 49 | if(!msg || !*msg) return; |
| 50 | |
| 51 | const size_t max_msg_len = (size_t)(SSIZE_MAX / 2); |
| 52 | size_t ulen = strnlen(msg, max_msg_len + 1); |
| 53 | if(unlikely(ulen > max_msg_len)) |
| 54 | return; |
| 55 | |
| 56 | ssize_t len = (ssize_t)ulen; |
| 57 | size_t buffer_size = ulen * 2; |
| 58 | CLEAN_CHAR_P *buffer = mallocz(buffer_size); |
| 59 | |
| 60 | for(size_t j = 0; j < iterations; j++) { |
| 61 | fprintf(stderr, "-"); |
| 62 | memset(buffer, 0, buffer_size); |
| 63 | |
| 64 | ssize_t rc = write(spawn_server_instance_write_fd(si), msg, len); |
| 65 | if (rc != len) { |
| 66 | nd_log(NDLS_COLLECTORS, NDLP_ERR, |
| 67 | "Cannot write to plugin. Expected to write %zd bytes, wrote %zd bytes", |
| 68 | len, rc); |
| 69 | exit(1); |
| 70 | } |
| 71 | |
| 72 | rc = read(spawn_server_instance_read_fd(si), buffer, buffer_size); |
| 73 | if (rc != len) { |
| 74 | nd_log(NDLS_COLLECTORS, NDLP_ERR, |
| 75 | "Cannot read from plugin. Expected to read %zd bytes, read %zd bytes", |
| 76 | len, rc); |
| 77 | exit(1); |
| 78 | } |
| 79 | |
| 80 | if (memcmp(msg, buffer, len) != 0) { |
| 81 | nd_log(NDLS_COLLECTORS, NDLP_ERR, |
| 82 | "Read corrupted data. Expected '%s', Read '%s'", |
| 83 | msg, buffer); |
| 84 | exit(1); |
| 85 | } |
| 86 | } |
| 87 | fprintf(stderr, "\n"); |
| 88 | } |
| 89 | |
| 90 | static void test_popen_echo_loop(POPEN_INSTANCE *pi, const char *msg, size_t iterations) { |
| 91 | if(!msg || !*msg) return; |
| 92 | |
| 93 | const size_t max_msg_len = |
| 94 | ((size_t)(INT_MAX / 2) < (size_t)(SSIZE_MAX / 2)) ? (size_t)(INT_MAX / 2) : (size_t)(SSIZE_MAX / 2); |
| 95 | size_t len = strnlen(msg, max_msg_len + 1); |
| 96 | if(unlikely(len > max_msg_len)) |
| 97 | return; |
| 98 | |
| 99 | size_t buffer_size = len * 2; |
| 100 | CLEAN_CHAR_P *buffer = mallocz(buffer_size); |
| 101 | |
| 102 | for(size_t j = 0; j < iterations; j++) { |
| 103 | fprintf(stderr, "-"); |
| 104 | memset(buffer, 0, buffer_size); |
| 105 | |
| 106 | size_t rc = fwrite(msg, 1, len, spawn_popen_stdin(pi)); |
| 107 | if (rc != len) { |
| 108 | nd_log(NDLS_COLLECTORS, NDLP_ERR, |
| 109 | "Cannot write to plugin. Expected to write %zu bytes, wrote %zu bytes", |
| 110 | len, rc); |
| 111 | exit(1); |
| 112 | } |
| 113 | fflush(spawn_popen_stdin(pi)); |
| 114 | |
| 115 | char *s = fgets(buffer, (int)buffer_size, spawn_popen_stdout(pi)); |
| 116 | if (!s || strlen(s) != len) { |
| 117 | nd_log(NDLS_COLLECTORS, NDLP_ERR, |
| 118 | "Cannot read from plugin. Expected to read %zu bytes, read %zu bytes", |
| 119 | len, (size_t)(s ? strlen(s) : 0)); |
| 120 | exit(1); |
| 121 | } |
| 122 | if (memcmp(msg, buffer, len) != 0) { |
| 123 | nd_log(NDLS_COLLECTORS, NDLP_ERR, |
| 124 | "Read corrupted data. Expected '%s', Read '%s'", |
| 125 | msg, buffer); |
| 126 | exit(1); |
| 127 | } |
| 128 | } |
| 129 | fprintf(stderr, "\n"); |
| 130 | } |
| 131 | |
| 132 | // -------------------------------------------------------------------------------------------------------------------- |
| 133 | // kill to stop |
| 134 | |
| 135 | int plugin_kill_to_stop() { |
| 136 | child_check_fds(); |
| 137 | child_check_environment(); |
| 138 | |
| 139 | char buffer[1024]; |
| 140 | while (fgets(buffer, sizeof(buffer), stdin) != NULL) { |
| 141 | fprintf(stderr, "+"); |
| 142 | printf("%s", buffer); |
| 143 | fflush(stdout); |
| 144 | } |
| 145 | |
| 146 | return 0; |
| 147 | } |
| 148 | |
| 149 | void test_int_fds_plugin_kill_to_stop(SPAWN_SERVER *server, const char *argv0) { |
| 150 | const char *params[] = { |
| 151 | argv0, |
| 152 | "plugin-kill-to-stop", |
| 153 | NULL, |
| 154 | }; |
| 155 | |
| 156 | SPAWN_INSTANCE *si = spawn_server_exec(server, STDERR_FILENO, 0, params, NULL, 0, SPAWN_INSTANCE_TYPE_EXEC); |
| 157 | if(!si) { |
| 158 | nd_log(NDLS_COLLECTORS, NDLP_ERR, "Cannot run myself as plugin (spawn)"); |
| 159 | exit(1); |
| 160 | } |
| 161 | |
| 162 | test_int_fds_echo_loop(si, "Hello World!\n", 30); |
| 163 | |
| 164 | int code = spawn_server_exec_kill(server, si, 0); |
| 165 | |
| 166 | nd_log(NDLS_COLLECTORS, NDLP_ERR, |
| 167 | "child exited with code %d", |
| 168 | code); |
| 169 | |
| 170 | if(code != 15 && code != 0) { |
| 171 | nd_log(NDLS_COLLECTORS, NDLP_WARNING, "child should exit with code 0 or 15, but exited with code %d", code); |
| 172 | warnings++; |
| 173 | } |
| 174 | } |
| 175 | |
| 176 | void test_popen_plugin_kill_to_stop(const char *argv0) { |
| 177 | char cmd[FILENAME_MAX + 100]; |
| 178 | snprintfz(cmd, sizeof(cmd), "exec %s plugin-kill-to-stop", argv0); |
| 179 | POPEN_INSTANCE *pi = spawn_popen_run(cmd); |
| 180 | if(!pi) { |
| 181 | nd_log(NDLS_COLLECTORS, NDLP_ERR, "Cannot run myself as plugin (popen)"); |
| 182 | exit(1); |
| 183 | } |
| 184 | |
| 185 | test_popen_echo_loop(pi, "Hello World!\n", 30); |
| 186 | |
| 187 | int code = spawn_popen_kill(pi, 0); |
| 188 | |
| 189 | nd_log(NDLS_COLLECTORS, NDLP_ERR, |
| 190 | "child exited with code %d", |
| 191 | code); |
| 192 | |
| 193 | if(code != 0) { |
| 194 | nd_log(NDLS_COLLECTORS, NDLP_WARNING, "child should exit with code 0, but exited with code %d", code); |
| 195 | warnings++; |
| 196 | } |
| 197 | } |
| 198 | |
| 199 | // -------------------------------------------------------------------------------------------------------------------- |
| 200 | // close to stop |
| 201 | |
| 202 | int plugin_close_to_stop() { |
| 203 | child_check_fds(); |
| 204 | child_check_environment(); |
| 205 | |
| 206 | char buffer[1024]; |
| 207 | while (fgets(buffer, sizeof(buffer), stdin) != NULL) { |
| 208 | fprintf(stderr, "+"); |
| 209 | printf("%s", buffer); |
| 210 | fflush(stdout); |
| 211 | } |
| 212 | |
| 213 | nd_log(NDLS_COLLECTORS, NDLP_ERR, "child detected a closed pipe."); |
| 214 | exit(1); |
| 215 | } |
| 216 | |
| 217 | void test_int_fds_plugin_close_to_stop(SPAWN_SERVER *server, const char *argv0) { |
| 218 | const char *params[] = { |
| 219 | argv0, |
| 220 | "plugin-close-to-stop", |
| 221 | NULL, |
| 222 | }; |
| 223 | |
| 224 | SPAWN_INSTANCE *si = spawn_server_exec(server, STDERR_FILENO, 0, params, NULL, 0, SPAWN_INSTANCE_TYPE_EXEC); |
| 225 | if(!si) { |
| 226 | nd_log(NDLS_COLLECTORS, NDLP_ERR, "Cannot run myself as plugin (spawn)"); |
| 227 | exit(1); |
| 228 | } |
| 229 | |
| 230 | test_int_fds_echo_loop(si, "Hello World!\n", 1); |
| 231 | |
| 232 | int code = spawn_server_exec_wait(server, si); |
| 233 | |
| 234 | nd_log(NDLS_COLLECTORS, NDLP_ERR, |
| 235 | "child exited with code %d", |
| 236 | code); |
| 237 | |
| 238 | if(!WIFEXITED(code) || WEXITSTATUS(code) != 1) { |
| 239 | nd_log(NDLS_COLLECTORS, NDLP_WARNING, "child should exit with code 1, but exited with code %d", code); |
| 240 | warnings++; |
| 241 | } |
| 242 | } |
| 243 | |
| 244 | void test_popen_plugin_close_to_stop(const char *argv0) { |
| 245 | char cmd[FILENAME_MAX + 100]; |
| 246 | snprintfz(cmd, sizeof(cmd), "exec %s plugin-close-to-stop", argv0); |
| 247 | POPEN_INSTANCE *pi = spawn_popen_run(cmd); |
| 248 | if(!pi) { |
| 249 | nd_log(NDLS_COLLECTORS, NDLP_ERR, "Cannot run myself as plugin (popen)"); |
| 250 | exit(1); |
| 251 | } |
| 252 | |
| 253 | test_popen_echo_loop(pi, "Hello World!\n", 1); |
| 254 | |
| 255 | int code = spawn_popen_wait(pi); |
| 256 | |
| 257 | nd_log(NDLS_COLLECTORS, NDLP_ERR, |
| 258 | "child exited with code %d", |
| 259 | code); |
| 260 | |
| 261 | if(code != 1) { |
| 262 | nd_log(NDLS_COLLECTORS, NDLP_WARNING, "child should exit with code 1, but exited with code %d", code); |
| 263 | warnings++; |
| 264 | } |
| 265 | } |
| 266 | |
| 267 | // -------------------------------------------------------------------------------------------------------------------- |
| 268 | // echo and exit |
| 269 | |
| 270 | #define ECHO_AND_EXIT_MSG "GOODBYE\n" |
| 271 | |
| 272 | int plugin_echo_and_exit() { |
| 273 | child_check_fds(); |
| 274 | child_check_environment(); |
| 275 | |
| 276 | printf(ECHO_AND_EXIT_MSG); |
| 277 | exit(0); |
| 278 | } |
| 279 | |
| 280 | void test_int_fds_plugin_echo_and_exit(SPAWN_SERVER *server, const char *argv0) { |
| 281 | const char *params[] = { |
| 282 | argv0, |
| 283 | "plugin-echo-and-exit", |
| 284 | NULL, |
| 285 | }; |
| 286 | |
| 287 | SPAWN_INSTANCE *si = spawn_server_exec(server, STDERR_FILENO, 0, params, NULL, 0, SPAWN_INSTANCE_TYPE_EXEC); |
| 288 | if(!si) { |
| 289 | nd_log(NDLS_COLLECTORS, NDLP_ERR, "Cannot run myself as plugin (spawn)"); |
| 290 | exit(1); |
| 291 | } |
| 292 | |
| 293 | char buffer[1024]; |
| 294 | size_t reads = 0; |
| 295 | |
| 296 | for(size_t j = 0; j < 30 ;j++) { |
| 297 | fprintf(stderr, "-"); |
| 298 | memset(buffer, 0, sizeof(buffer)); |
| 299 | |
| 300 | ssize_t rc = read(spawn_server_instance_read_fd(si), buffer, sizeof(buffer)); |
| 301 | if(rc <= 0) |
| 302 | break; |
| 303 | |
| 304 | reads++; |
| 305 | |
| 306 | if (rc != strlen(ECHO_AND_EXIT_MSG)) { |
| 307 | nd_log(NDLS_COLLECTORS, NDLP_ERR, |
| 308 | "Cannot read from plugin. Expected to read %zu bytes, read %zd bytes", |
| 309 | strlen(ECHO_AND_EXIT_MSG), rc); |
| 310 | exit(1); |
| 311 | } |
| 312 | if (memcmp(ECHO_AND_EXIT_MSG, buffer, strlen(ECHO_AND_EXIT_MSG)) != 0) { |
| 313 | nd_log(NDLS_COLLECTORS, NDLP_ERR, |
| 314 | "Read corrupted data. Expected '%s', Read '%s'", |
| 315 | ECHO_AND_EXIT_MSG, buffer); |
| 316 | exit(1); |
| 317 | } |
| 318 | } |
| 319 | fprintf(stderr, "\n"); |
| 320 | |
| 321 | if(reads != 1) { |
| 322 | nd_log(NDLS_COLLECTORS, NDLP_ERR, |
| 323 | "Cannot read from plugin. Expected to read %d times, but read %zu", |
| 324 | 1, reads); |
| 325 | exit(1); |
| 326 | } |
| 327 | |
| 328 | int code = spawn_server_exec_wait(server, si); |
| 329 | |
| 330 | nd_log(NDLS_COLLECTORS, NDLP_ERR, |
| 331 | "child exited with code %d", |
| 332 | code); |
| 333 | |
| 334 | if(code != 0) { |
| 335 | nd_log(NDLS_COLLECTORS, NDLP_WARNING, "child should exit with code 0, but exited with code %d", code); |
| 336 | warnings++; |
| 337 | } |
| 338 | } |
| 339 | |
| 340 | void test_popen_plugin_echo_and_exit(const char *argv0) { |
| 341 | char cmd[FILENAME_MAX + 100]; |
| 342 | snprintfz(cmd, sizeof(cmd), "exec %s plugin-echo-and-exit", argv0); |
| 343 | POPEN_INSTANCE *pi = spawn_popen_run(cmd); |
| 344 | if(!pi) { |
| 345 | nd_log(NDLS_COLLECTORS, NDLP_ERR, "Cannot run myself as plugin (popen)"); |
| 346 | exit(1); |
| 347 | } |
| 348 | |
| 349 | char buffer[1024]; |
| 350 | size_t reads = 0; |
| 351 | for(size_t j = 0; j < 30 ;j++) { |
| 352 | fprintf(stderr, "-"); |
| 353 | memset(buffer, 0, sizeof(buffer)); |
| 354 | |
| 355 | char *s = fgets(buffer, sizeof(buffer), spawn_popen_stdout(pi)); |
| 356 | if(!s) break; |
| 357 | reads++; |
| 358 | if (strlen(s) != strlen(ECHO_AND_EXIT_MSG)) { |
| 359 | nd_log(NDLS_COLLECTORS, NDLP_ERR, |
| 360 | "Cannot read from plugin. Expected to read %zu bytes, read %zu bytes", |
| 361 | strlen(ECHO_AND_EXIT_MSG), (size_t)(s ? strlen(s) : 0)); |
| 362 | exit(1); |
| 363 | } |
| 364 | if (memcmp(ECHO_AND_EXIT_MSG, buffer, strlen(ECHO_AND_EXIT_MSG)) != 0) { |
| 365 | nd_log(NDLS_COLLECTORS, NDLP_ERR, |
| 366 | "Read corrupted data. Expected '%s', Read '%s'", |
| 367 | ECHO_AND_EXIT_MSG, buffer); |
| 368 | exit(1); |
| 369 | } |
| 370 | } |
| 371 | fprintf(stderr, "\n"); |
| 372 | |
| 373 | if(reads != 1) { |
| 374 | nd_log(NDLS_COLLECTORS, NDLP_ERR, |
| 375 | "Cannot read from plugin. Expected to read %d times, but read %zu", |
| 376 | 1, reads); |
| 377 | exit(1); |
| 378 | } |
| 379 | |
| 380 | int code = spawn_popen_wait(pi); |
| 381 | |
| 382 | nd_log(NDLS_COLLECTORS, NDLP_ERR, |
| 383 | "child exited with code %d", |
| 384 | code); |
| 385 | |
| 386 | if(code != 0) { |
| 387 | nd_log(NDLS_COLLECTORS, NDLP_WARNING, "child should exit with code 0, but exited with code %d", code); |
| 388 | warnings++; |
| 389 | } |
| 390 | } |
| 391 | |
| 392 | // -------------------------------------------------------------------------------------------------------------------- |
| 393 | // timed wait |
| 394 | |
| 395 | int plugin_sleep_to_stop(void) { |
| 396 | child_check_fds(); |
| 397 | child_check_environment(); |
| 398 | |
| 399 | // ignore the pipes - only a kill can stop us within the test's lifetime |
| 400 | sleep_usec(3600 * USEC_PER_SEC); |
| 401 | return 0; |
| 402 | } |
| 403 | |
| 404 | void test_popen_plugin_timedwait_exits(const char *argv0) { |
| 405 | // a child that exits on its own must be reaped by spawn_popen_timedwait() |
| 406 | char cmd[FILENAME_MAX + 100]; |
| 407 | snprintfz(cmd, sizeof(cmd), "exec %s plugin-echo-and-exit", argv0); |
| 408 | POPEN_INSTANCE *pi = spawn_popen_run(cmd); |
| 409 | if(!pi) { |
| 410 | nd_log(NDLS_COLLECTORS, NDLP_ERR, "Cannot run myself as plugin (popen)"); |
| 411 | exit(1); |
| 412 | } |
| 413 | |
| 414 | int code = -1; |
| 415 | size_t slices = 0; |
| 416 | for(;;) { |
| 417 | SPAWN_TIMEDWAIT_RESULT r = spawn_popen_timedwait(pi, 100, &code); |
| 418 | if(r == SPAWN_TIMEDWAIT_EXITED) |
| 419 | break; |
| 420 | |
| 421 | if(r == SPAWN_TIMEDWAIT_ERROR) { |
| 422 | // ERROR must never be looped over; for a cleanly-exiting child it should not happen at all. |
| 423 | // pi is still owned on ERROR, so reclaim it before bailing out. |
| 424 | nd_log(NDLS_COLLECTORS, NDLP_ERR, "spawn_popen_timedwait() returned ERROR for a child that should exit cleanly"); |
| 425 | spawn_popen_kill(pi, 0); |
| 426 | exit(1); |
| 427 | } |
| 428 | |
| 429 | // SPAWN_TIMEDWAIT_RUNNING - pi is still owned |
| 430 | if(++slices > 100) { |
| 431 | nd_log(NDLS_COLLECTORS, NDLP_ERR, "spawn_popen_timedwait() did not reap a child that exits immediately"); |
| 432 | spawn_popen_kill(pi, 0); |
| 433 | exit(1); |
| 434 | } |
| 435 | } |
| 436 | |
| 437 | nd_log(NDLS_COLLECTORS, NDLP_ERR, |
| 438 | "child exited with code %d (after %zu timedwait slices)", |
| 439 | code, slices); |
| 440 | |
| 441 | if(code != 0) { |
| 442 | nd_log(NDLS_COLLECTORS, NDLP_WARNING, "child should exit with code 0, but exited with code %d", code); |
| 443 | warnings++; |
| 444 | } |
| 445 | } |
| 446 | |
| 447 | void test_popen_plugin_timedwait_kill(const char *argv0) { |
| 448 | // a child that never exits must be reported still-running on every slice, then killed |
| 449 | char cmd[FILENAME_MAX + 100]; |
| 450 | snprintfz(cmd, sizeof(cmd), "exec %s plugin-sleep-to-stop", argv0); |
| 451 | POPEN_INSTANCE *pi = spawn_popen_run(cmd); |
| 452 | if(!pi) { |
| 453 | nd_log(NDLS_COLLECTORS, NDLP_ERR, "Cannot run myself as plugin (popen)"); |
| 454 | exit(1); |
| 455 | } |
| 456 | |
| 457 | int code = 0; |
| 458 | for(size_t i = 0; i < 5; i++) { |
| 459 | SPAWN_TIMEDWAIT_RESULT r = spawn_popen_timedwait(pi, 200, &code); |
| 460 | if(r != SPAWN_TIMEDWAIT_RUNNING) { |
| 461 | nd_log(NDLS_COLLECTORS, NDLP_ERR, |
| 462 | "spawn_popen_timedwait() did not report RUNNING for a sleeping child"); |
| 463 | // on ERROR we still own pi and must reclaim it; on EXITED it was already freed |
| 464 | if(r == SPAWN_TIMEDWAIT_ERROR) spawn_popen_kill(pi, 0); |
| 465 | exit(1); |
| 466 | } |
| 467 | } |
| 468 | |
| 469 | code = spawn_popen_kill(pi, 0); |
| 470 | |
| 471 | nd_log(NDLS_COLLECTORS, NDLP_ERR, |
| 472 | "child killed, exited with code %d", |
| 473 | code); |
| 474 | |
| 475 | if(code != 0) { |
| 476 | nd_log(NDLS_COLLECTORS, NDLP_WARNING, "killed child should report code 0, but reported code %d", code); |
| 477 | warnings++; |
| 478 | } |
| 479 | } |
| 480 | |
| 481 | // -------------------------------------------------------------------------------------------------------------------- |
| 482 | |
| 483 | int main(int argc, const char **argv) { |
| 484 | if(argc > 1 && strcmp(argv[1], "plugin-kill-to-stop") == 0) |
| 485 | return plugin_kill_to_stop(); |
| 486 | |
| 487 | if(argc > 1 && strcmp(argv[1], "plugin-sleep-to-stop") == 0) |
| 488 | return plugin_sleep_to_stop(); |
| 489 | |
| 490 | if(argc > 1 && strcmp(argv[1], "plugin-echo-and-exit") == 0) |
| 491 | return plugin_echo_and_exit(); |
| 492 | |
| 493 | if(argc > 1 && strcmp(argv[1], "plugin-close-to-stop") == 0) |
| 494 | return plugin_close_to_stop(); |
| 495 | |
| 496 | if(argc <= 1 || strcmp(argv[1], "test") != 0) { |
| 497 | fprintf(stderr, "Run me with 'test' parameter!\n"); |
| 498 | exit(1); |
| 499 | } |
| 500 | |
| 501 | nd_setenv(ENV_VAR_KEY, ENV_VAR_VALUE, 1); |
| 502 | |
| 503 | fprintf(stderr, "\n\nTESTING fds\n\n"); |
| 504 | SPAWN_SERVER *server = spawn_server_create(SPAWN_SERVER_OPTION_EXEC, "test", NULL, argc, argv); |
| 505 | if(!server) { |
| 506 | nd_log(NDLS_COLLECTORS, NDLP_ERR, "Cannot create spawn server"); |
| 507 | exit(1); |
| 508 | } |
| 509 | for(size_t i = 0; i < 5; i++) { |
| 510 | fprintf(stderr, "\n\nTESTING fds No %zu (kill to stop)\n\n", i + 1); |
| 511 | test_int_fds_plugin_kill_to_stop(server, argv[0]); |
| 512 | } |
| 513 | for(size_t i = 0; i < 5; i++) { |
| 514 | fprintf(stderr, "\n\nTESTING fds No %zu (echo and exit)\n\n", i + 1); |
| 515 | test_int_fds_plugin_echo_and_exit(server, argv[0]); |
| 516 | } |
| 517 | for(size_t i = 0; i < 5; i++) { |
| 518 | fprintf(stderr, "\n\nTESTING fds No %zu (close to stop)\n\n", i + 1); |
| 519 | test_int_fds_plugin_close_to_stop(server, argv[0]); |
| 520 | } |
| 521 | spawn_server_destroy(server); |
| 522 | |
| 523 | fprintf(stderr, "\n\nTESTING popen\n\n"); |
| 524 | netdata_main_spawn_server_init("test", argc, argv); |
| 525 | for(size_t i = 0; i < 5; i++) { |
| 526 | fprintf(stderr, "\n\nTESTING popen No %zu (kill to stop)\n\n", i + 1); |
| 527 | test_popen_plugin_kill_to_stop(argv[0]); |
| 528 | } |
| 529 | for(size_t i = 0; i < 5; i++) { |
| 530 | fprintf(stderr, "\n\nTESTING popen No %zu (echo and exit)\n\n", i + 1); |
| 531 | test_popen_plugin_echo_and_exit(argv[0]); |
| 532 | } |
| 533 | for(size_t i = 0; i < 5; i++) { |
| 534 | fprintf(stderr, "\n\nTESTING popen No %zu (close to stop)\n\n", i + 1); |
| 535 | test_popen_plugin_close_to_stop(argv[0]); |
| 536 | } |
| 537 | for(size_t i = 0; i < 5; i++) { |
| 538 | fprintf(stderr, "\n\nTESTING popen No %zu (timedwait exits)\n\n", i + 1); |
| 539 | test_popen_plugin_timedwait_exits(argv[0]); |
| 540 | } |
| 541 | for(size_t i = 0; i < 5; i++) { |
| 542 | fprintf(stderr, "\n\nTESTING popen No %zu (timedwait kill)\n\n", i + 1); |
| 543 | test_popen_plugin_timedwait_kill(argv[0]); |
| 544 | } |
| 545 | netdata_main_spawn_server_cleanup(); |
| 546 | |
| 547 | fprintf(stderr, "\n\nTests passed! (%zu warnings)\n\n", warnings); |
| 548 | |
| 549 | exit(0); |
| 550 | } |