aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJP Appel <jeanpierre.appel01@gmail.com>2024-07-26 22:23:17 -0400
committerJP Appel <jeanpierre.appel01@gmail.com>2024-07-26 22:23:17 -0400
commit47f09225b07c33c7657ded5bbe4c7e4f98eb9e30 (patch)
tree3bedbf21474f480af8e4c47b3e0de6e79ab6fb81
parent6f864672834e646aedbdf8c279b58226e8a2a2f3 (diff)
FEAT: test can now time out
Tests now have an extra field `max_time_ms` which is the max duration before it's process gets killed. A time of 0 ms is used to disable eztester managed timeouts, however a test can still return a timeout status which will be handled similarily.
-rw-r--r--README.md10
-rw-r--r--examples/basics.c51
-rw-r--r--eztester.c39
-rw-r--r--eztester.h1
4 files changed, 93 insertions, 8 deletions
diff --git a/README.md b/README.md
index bf88697..f89c277 100644
--- a/README.md
+++ b/README.md
@@ -77,12 +77,12 @@ int main(int argc, char* argv[]){
eztester_list *tests = ezterster_create_list(2);
// runners that always return the same status are provided
- eztester_register(tests, (eztester_test){eztester_always_pass, "Always Pass"});
- eztester_register(tests, (eztester_test){sample_test, "Sample Test"}); // our test, can be defined in a different translation unit
+ eztester_register(tests, (eztester_test){eztester_always_pass, "Always Pass", 0});
+ eztester_register(tests, (eztester_test){sample_test, "Sample Test", 0}); // our test, can be defined in a different translation unit
// a list will resize on register when it doesn't have capacity
- eztester_register(tests, (eztester_test){eztester_always_fail, "Always Fail"});
- eztester_register(tests, (eztester_test){eztester_always_warn, "Always Warn"});
+ eztester_register(tests, (eztester_test){eztester_always_fail, "Always Fail", 0});
+ eztester_register(tests, (eztester_test){eztester_always_warn, "Always Warn", 0});
eztester_register(tests, (eztester_test){sample_shell_test, "Check a non existent url");
@@ -95,6 +95,8 @@ int main(int argc, char* argv[]){
</details>
+More programs are provided in [examples](examples/).
+
### Static
After building, copy the static libraries into your project
diff --git a/examples/basics.c b/examples/basics.c
new file mode 100644
index 0000000..6aab9d2
--- /dev/null
+++ b/examples/basics.c
@@ -0,0 +1,51 @@
+#include "../eztester.h"
+#include <stdio.h>
+#include <unistd.h>
+
+#define EZTESTER_IMPLEMENTATION
+#include "../build/header/eztester.h"
+#undef EZTESTER_IMPLEMENTATION
+
+eztester_status shell_exists() {
+ int status = eztester_shell(NULL);
+ if (status) {
+ return TEST_FAIL;
+ } else {
+ return TEST_PASS;
+ }
+}
+
+eztester_status python3_exists() {
+ int status = eztester_shell("/usr/bin/env python3 --version");
+ if (status) {
+ return TEST_FAIL;
+ } else {
+ return TEST_PASS;
+ }
+}
+
+eztester_status sleepy() {
+ eztester_log("Im feeling sleepy");
+ sleep(2);
+ eztester_log("zzzzzzz");
+ sleep(1);
+ eztester_log("ZZZZZZZZ");
+ sleep(2);
+ eztester_log("oh, hello there.");
+ return TEST_PASS;
+}
+
+int main(int argc, char *argv[]) {
+ eztester_list *list = eztester_create_list(5);
+
+ eztester_register(
+ list, (eztester_test){eztester_always_pass_test, "Always pass", 0});
+ eztester_register(
+ list, (eztester_test){eztester_always_warn_test, "Always warn", 0});
+ eztester_register(list, (eztester_test){sleepy, "Timeout test", 4e3});
+ eztester_register(list, (eztester_test){python3_exists, "Python3 Exists", 0});
+
+ eztester_run(list, EXIT_ON_FAIL);
+
+ return 0;
+}
diff --git a/eztester.c b/eztester.c
index 578d50a..b0a2322 100644
--- a/eztester.c
+++ b/eztester.c
@@ -150,14 +150,16 @@ void eztester_run(eztester_list *test_list, eztester_behavior behavior) {
mem->work_in_queue = false;
mem->behavior = behavior;
- pid_t pid = fork();
+ pid_t pid, child_pgid;
+ pid = fork();
if (pid < 0) {
perror("fork");
exit(1);
- }
- if (pid == 0) {
+ } else if (pid == 0) {
+ setpgrp();
_ez_worker(mem, test_list);
}
+ child_pgid = pid;
eztester_status status;
eztester_test test;
@@ -180,12 +182,41 @@ void eztester_run(eztester_list *test_list, eztester_behavior behavior) {
kill(pid, SIGCONT);
+ unsigned int elapsed_ms = 0;
while (mem->work_in_queue) {
- usleep(50e3);
+ usleep(1e3);
+ elapsed_ms++;
if (_ez_child_premature_exit) {
_ez_premature_exit("Worker Process ended prematurely!", pid, mem,
results);
}
+ if (test.max_time_ms > 0 && elapsed_ms > test.max_time_ms) {
+
+ int status;
+ signal(SIGCHLD, SIG_DFL);
+
+ // ask nicely
+ killpg(child_pgid, SIGTERM);
+ usleep(10e3);
+ if (waitpid(pid, &status, WNOHANG) == 0) {
+ // no longer ask nicely
+ killpg(child_pgid, SIGKILL);
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ perror("fork");
+ exit(1);
+ } else if (pid == 0) {
+ setpgrp();
+ _ez_worker(mem, test_list);
+ }
+ child_pgid = pid;
+ signal(SIGCHLD, _ez_chld_handler);
+
+ mem->work_in_queue = false;
+ mem->status = TEST_TIMEOUT;
+ }
}
status = mem->status;
diff --git a/eztester.h b/eztester.h
index 1f7e385..9a68651 100644
--- a/eztester.h
+++ b/eztester.h
@@ -29,6 +29,7 @@ typedef eztester_status(eztester_runner)();
typedef struct {
eztester_runner *runner;
const char *name;
+ unsigned int max_time_ms;
} eztester_test;
typedef struct {