From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-lj1-f193.google.com (mail-lj1-f193.google.com [209.85.208.193]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 1B6344696C3 for ; Thu, 26 Mar 2020 11:31:25 +0300 (MSK) Received: by mail-lj1-f193.google.com with SMTP id 19so5445405ljj.7 for ; Thu, 26 Mar 2020 01:31:25 -0700 (PDT) Date: Thu, 26 Mar 2020 11:31:22 +0300 From: Cyrill Gorcunov Message-ID: <20200326083122.GN3197@uranus> References: <20200324100347.15405-1-gorcunov@gmail.com> <20200324100347.15405-3-gorcunov@gmail.com> <20200326004737.nu4dcii7zpwesrsp@tkn_work_nb> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20200326004737.nu4dcii7zpwesrsp@tkn_work_nb> Subject: [Tarantool-patches] [PATCH v2 2/2] test: unit/popen -- provide a child process List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Alexander Turenko Cc: tml Testing via plain C interface with a shell is not stable, the shell might simply be misconfigured or not found and we will simply stuck forever (the signal handling in libev is tricky and requires at least idle cycles or similar to pass event processing). Thus lets rather run a program we know is presenting in the system (popen-child executable). Fixes #4811 Signed-off-by: Cyrill Gorcunov --- - fixed comments - add entry into .gitignore - read/write in a loop pushed into branch gorcunov/gh-4811-popen-coio-3 .gitignore | 1 + test/unit/CMakeLists.txt | 4 ++ test/unit/popen-child.c | 123 +++++++++++++++++++++++++++++++++++++++ test/unit/popen.c | 28 ++++++--- 4 files changed, 148 insertions(+), 8 deletions(-) create mode 100644 test/unit/popen-child.c diff --git a/.gitignore b/.gitignore index e9508fc43..cda28d79f 100644 --- a/.gitignore +++ b/.gitignore @@ -92,6 +92,7 @@ test/unit/fiob test/small test/var test/luajit-tap +test/unit/popen-child third_party/luajit/src/luajit third_party/luajit/lib/vmdef.lua third_party/luajit/src/buildvm diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index bc6aebdcb..e1d506f58 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -246,5 +246,9 @@ target_link_libraries(swim_errinj.test unit swim) add_executable(merger.test merger.test.c) target_link_libraries(merger.test unit core box) +# +# Client for popen.test +add_executable(popen-child popen-child.c) + add_executable(popen.test popen.c) target_link_libraries(popen.test misc unit core) diff --git a/test/unit/popen-child.c b/test/unit/popen-child.c new file mode 100644 index 000000000..d11c4258a --- /dev/null +++ b/test/unit/popen-child.c @@ -0,0 +1,123 @@ +#include +#include +#include +#include +#include + +static ssize_t +read_safe(int pfd, char *dest, ssize_t bytes) +{ + ssize_t left = bytes; + ssize_t off = 0; + + while (left > 0) { + ssize_t nr = read(pfd, &dest[off], left); + printf("read %zd", nr); + if (nr < 0) { + if (errno == EAGAIN || + errno == EWOULDBLOCK || + errno == EINTR) + continue; + return nr; + } else if (nr == 0) { + break; + } + + off += nr; + left -= nr; + } + + return off; +} + +static ssize_t +write_safe(int pfd, char *dest, ssize_t bytes) +{ + ssize_t left = bytes; + ssize_t off = 0; + + while (left > 0) { + ssize_t nr = write(pfd, &dest[off], left); + if (nr < 0) { + if (errno == EAGAIN || + errno == EWOULDBLOCK || + errno == EINTR) + continue; + return nr; + } else if (nr == 0) { + break; + } + + off += nr; + left -= nr; + } + + return off; +} + +int +main(int argc, char *argv[]) +{ + char buf[1024]; + + if (argc < 2) { + fprintf(stderr, "Not enough args\n"); + exit(1); + } + + /* read -n X and the just echo data read */ + if (!strcmp(argv[1], "read") && + !strcmp(argv[2], "-n")) { + ssize_t nr = (ssize_t)atoi(argv[3]); + if (nr <= 0) { + fprintf(stderr, "Wrong number of args\n"); + exit(1); + } + + if (nr >= (ssize_t)sizeof(buf)) { + fprintf(stderr, "Too many bytes to read\n"); + exit(1); + } + + ssize_t n = read_safe(STDIN_FILENO, buf, nr); + if (n != nr) { + fprintf(stderr, "Can't read from stdin\n"); + exit(1); + } + + n = write_safe(STDOUT_FILENO, buf, nr); + if (n != nr) { + fprintf(stderr, "Can't write to stdout\n"); + exit(1); + } + + exit(0); + } + + /* just echo the data */ + if (!strcmp(argv[1], "echo")) { + ssize_t nr = (ssize_t)strlen(argv[2]) + 1; + if (nr <= 0) { + fprintf(stderr, "Wrong number of bytes\n"); + exit(1); + } + + ssize_t n = write_safe(STDOUT_FILENO, argv[2], nr); + if (n != nr) { + fprintf(stderr, "Can't write to stdout\n"); + exit(1); + } + + exit(0); + } + + /* just sleep forever */ + if (!strcmp(argv[1], "loop")) { + for (;;) + sleep(10); + exit(0); + } + + fprintf(stderr, "Unknown command passed\n"); + return 1; +} diff --git a/test/unit/popen.c b/test/unit/popen.c index a40ca514c..caea9d552 100644 --- a/test/unit/popen.c +++ b/test/unit/popen.c @@ -11,9 +11,10 @@ #include "popen.h" #include "say.h" +static char popen_child_path[PATH_MAX]; + #define TEST_POPEN_COMMON_FLAGS \ (POPEN_FLAG_SETSID | \ - POPEN_FLAG_SHELL | \ POPEN_FLAG_RESTORE_SIGNALS) /** @@ -40,8 +41,8 @@ popen_write_exit(void) { struct popen_handle *handle; char *child_argv[] = { - "/bin/sh", "-c", - "prompt=''; read -n 5 prompt; echo $prompt", + popen_child_path, + "read", "-n", "5", NULL, }; @@ -108,8 +109,8 @@ popen_read_exit(void) { struct popen_handle *handle; char *child_argv[] = { - "/bin/sh", "-c", - "echo 1 2 3 4 5", + popen_child_path, + "echo", "1 2 3 4 5", NULL, }; @@ -165,8 +166,8 @@ popen_kill(void) { struct popen_handle *handle; char *child_argv[] = { - "/bin/sh", "-c", - "while [ 1 ]; do sleep 10; done", + popen_child_path, + "loop", NULL, }; @@ -234,9 +235,20 @@ main_f(va_list ap) int main(int argc, char *argv[]) { - //say_logger_init(NULL, S_DEBUG, 0, "plain", 0); +#if 0 + say_logger_init(NULL, S_DEBUG, 0, "plain", 0); +#endif memory_init(); + if (getenv("BUILDDIR") == NULL) { + size_t size = sizeof(popen_child_path); + strncpy(popen_child_path, "./test/unit/popen-child", size); + popen_child_path[size-1] = '\0'; + } else { + snprintf(popen_child_path, sizeof(popen_child_path), + "%s/test/unit/popen-child", getenv("BUILDDIR")); + } + fiber_init(fiber_c_invoke); popen_init(); coio_init(); -- 2.20.1