aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2024-04-25 18:35:24 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2024-04-25 18:36:13 +0000
commit83a6e984ac01657819418746f722163367ec30db (patch)
tree443a935a5c64eae9abf3c23a7a12226b4b384345
parent7ab7ecfcfe777f7816e3e01df5f277060b2b609a (diff)
downloadsrc-83a6e984ac01657819418746f722163367ec30db.tar.gz
src-83a6e984ac01657819418746f722163367ec30db.zip
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
-rw-r--r--libexec/tftpd/tests/functional.c44
1 files 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;
}