From 83a6e984ac01657819418746f722163367ec30db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dag-Erling=20Sm=C3=B8rgrav?= Date: Thu, 25 Apr 2024 20:35:24 +0200 Subject: tftpd: Check the server status after each test. * In the setup phase, wait for the server to start (or fail to start) before proceeding with the test. This makes it possible to write test cases that don't expect a response from the server without ending up in a race over the server PID file. * After running each test, wait up to 30 seconds for the server to exit and check that the exit status matches what the test case says to expect (usually 0). * We still kill and collect the server in the cleanup phase, in case the test ended early. MFC after: 1 week Sponsored by: Klara, Inc. Reviewed by: kevans Differential Revision: https://reviews.freebsd.org/D44956 --- libexec/tftpd/tests/functional.c | 44 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/libexec/tftpd/tests/functional.c b/libexec/tftpd/tests/functional.c index bbe4f3782192..3b70962854ba 100644 --- a/libexec/tftpd/tests/functional.c +++ b/libexec/tftpd/tests/functional.c @@ -208,11 +208,14 @@ ATF_TC_HEAD(name ## _v4, tc) \ } \ ATF_TC_BODY(name ## _v4, tc) \ { \ + int exitcode = 0; \ __VA_ARGS__; \ protocol = AF_INET; \ s = setup(&addr, __COUNTER__); \ name ## _body(); \ close(s); \ + if (exitcode >= 0) \ + check_server(exitcode); \ } \ ATF_TC_CLEANUP(name ## _v4, tc) \ { \ @@ -225,11 +228,14 @@ ATF_TC_HEAD(name ## _v6, tc) \ } \ ATF_TC_BODY(name ## _v6, tc) \ { \ + int exitcode = 0; \ __VA_ARGS__; \ protocol = AF_INET6; \ s = setup(&addr, __COUNTER__); \ name ## _body(); \ close(s); \ + if (exitcode >= 0) \ + check_server(exitcode); \ } \ ATF_TC_CLEANUP(name ## _v6, tc) \ { \ @@ -244,6 +250,33 @@ name ## _body(void) ATF_TP_ADD_TC(tp, name ## _v6); \ } while (0) +static void +sigalrm(int signo __unused) +{ +} + +/* Check that server exits with specific exit code */ +static void +check_server(int exitcode) +{ + struct sigaction sa = { .sa_handler = sigalrm }; + struct itimerval it = { .it_value = { .tv_sec = 30 } }; + FILE *f; + pid_t pid; + int wstatus; + + f = fopen(pidfile, "r"); + ATF_REQUIRE(f != NULL); + ATF_REQUIRE_INTEQ(1, fscanf(f, "%d", &pid)); + ATF_CHECK_INTEQ(0, fclose(f)); + ATF_REQUIRE_INTEQ(0, sigaction(SIGALRM, &sa, NULL)); + ATF_REQUIRE_EQ(0, setitimer(ITIMER_REAL, &it, NULL)); + ATF_REQUIRE_EQ(pid, waitpid(pid, &wstatus, 0)); + ATF_CHECK(WIFEXITED(wstatus)); + ATF_CHECK_INTEQ(exitcode, WEXITSTATUS(wstatus)); + unlink(pidfile); +} + /* Standard cleanup used by all testcases */ static void cleanup(void) @@ -254,12 +287,12 @@ cleanup(void) f = fopen(pidfile, "r"); if (f == NULL) return; + unlink(pidfile); if (fscanf(f, "%d", &pid) == 1) { kill(pid, SIGTERM); waitpid(pid, NULL, 0); } fclose(f); - unlink(pidfile); } /* Assert that two binary buffers are identical */ @@ -299,6 +332,9 @@ setup(struct sockaddr_storage *to, uint16_t idx) struct pidfh *pfh; uint16_t port = BASEPORT + idx; socklen_t len; + int pd[2]; + + ATF_REQUIRE_EQ(0, pipe2(pd, O_CLOEXEC)); if (protocol == PF_INET) { len = sizeof(addr4); @@ -358,6 +394,10 @@ setup(struct sockaddr_storage *to, uint16_t idx) break; default: /* In parent */ + ATF_REQUIRE_INTEQ(0, close(pd[1])); + /* block until other end is closed on exec() or exit() */ + ATF_REQUIRE_INTEQ(0, read(pd[0], &pd[1], sizeof(pd[1]))); + ATF_REQUIRE_INTEQ(0, close(pd[0])); bzero(to, sizeof(*to)); if (protocol == PF_INET) { struct sockaddr_in *to4 = (struct sockaddr_in *)to; @@ -374,7 +414,7 @@ setup(struct sockaddr_storage *to, uint16_t idx) to6->sin6_addr = loopback; } - close(server_s); + ATF_REQUIRE_INTEQ(0, close(server_s)); ATF_REQUIRE((client_s = socket(protocol, SOCK_DGRAM, 0)) > 0); break; } -- cgit v1.2.3