diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 398c2c1a53..7084537f09 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -66,6 +66,6 @@ test:aarch64: needs: [aarch64] image: "redoxos/redoxer:aarch64" script: - - ./check.sh --arch=aarch64 --test + - timeout -s KILL 9m ./check.sh --arch=aarch64 --test #TODO: Enable more arch once dynamic linker working diff --git a/README.md b/README.md index 44d5cfc13f..ea4dd2c33e 100644 --- a/README.md +++ b/README.md @@ -108,44 +108,22 @@ Note: Do not edit `relibc` inside `prefix` folder! Do your work on `relibc` fold ## Tests -This section explain how to build and run the tests. +Relibc has a test suite that also runs every time a new commit get pushed. You can see `.gitlab-ci.yml` to see how it's being executed. That being said, `./check.sh` is the recommended way to run tests. Here's few examples: -### Build ++ `./check.sh` - Run build, without running the test ++ `./check.sh --test` - Run all tests in x86_64 Redox using Redoxer ++ `./check.sh --test --host` - Run all tests in host (Linux) ++ `./check.sh --test --arch=aarch64` - Run all tests in specified arch + - Arch can be `x86_64`, `aarch64`, `i586`, or `riscv64gc` ++ `./check.sh --test=stdio/printf` - Run a single test + - Can be combined with `--host` or `--arch` + - Will run statically linked test in Linux, dynamically linked in Redox -To build the tests run `make all` on the `tests` folder, it will store the executables at `tests/bins_static` +Couple of notes: -If you did changes to your tests, run `make clean all` to rebuild the executables. - -### Redox OS Testing - -To test on Redox do the following steps: - -- Add the `relibc-tests` recipe on your filesystem configuration at `config/your-cpu/your-config.toml` (generally `desktop.toml`) -- Run the following commands to rebuild relibc with your changes, update the `relibc-tests` recipe and update your QEMU image: - -```sh -touch relibc -``` - -```sh -make prefix cr.relibc-tests image -``` - -- Run the tests - -```sh -/usr/share/relibc-tests/bins_static/test-name -``` - -### Linux Testing - -Run `make test` on the relibc directory. - -If you want to run one test, run the following command: - -```sh -tests/bins_static/test-name -``` +- Relibc and its tests will rebuild if files changed, however switching between arch or host requires you to run `make clean` +- Redoxer is needed to run tests for Redox. You can install it using `cargo install redoxer` +- Tests can hangs, the test runner can anticipate this, assuming the kernel doesn't hang too. ## Issues diff --git a/tests/pthread/exit.c b/tests/pthread/exit.c index 14e1daee1a..5538a0f593 100644 --- a/tests/pthread/exit.c +++ b/tests/pthread/exit.c @@ -9,7 +9,7 @@ void *routine(void *arg) { assert(arg == NULL); - usleep(100); + usleep(100000); puts("Thread succeeded"); diff --git a/tests/pthread/extjoin.c b/tests/pthread/extjoin.c index 8f1737587d..da19101075 100644 --- a/tests/pthread/extjoin.c +++ b/tests/pthread/extjoin.c @@ -15,7 +15,7 @@ struct arg2 { void *routine1(void *arg) { assert(arg == NULL); puts("Thread 1 spawned, waiting 1s."); - usleep(100); + usleep(100000); puts("Thread 1 finished."); return strdup("message from thread 1"); } diff --git a/tests/pthread/main.c b/tests/pthread/main.c index acf51adb48..186e306c2b 100644 --- a/tests/pthread/main.c +++ b/tests/pthread/main.c @@ -20,7 +20,7 @@ int main(void) { int status; puts("Start, sleeping 1 second"); - usleep(100); + usleep(100000); pthread_t thread; void *arg = NULL; if ((status = pthread_create(&thread, NULL, thread_main, arg)) != 0) { diff --git a/tests/ptrace.c b/tests/ptrace.c index 66592f7ed2..23d3c833f1 100644 --- a/tests/ptrace.c +++ b/tests/ptrace.c @@ -26,7 +26,7 @@ int main() { if (pid == 0) { // Test behavior on Redox when TRACEME hasn't been activated // before waitpid is invoked! - usleep(100); + usleep(100000); int result = ptrace(PTRACE_TRACEME, 0, NULL, NULL); ERROR_IF(ptrace, result, == -1); diff --git a/tests/signals/kill-child.c b/tests/signals/kill-child.c index 3db868c984..c2644bd670 100644 --- a/tests/signals/kill-child.c +++ b/tests/signals/kill-child.c @@ -36,7 +36,7 @@ void child_proc(int signum) sigemptyset(&act.sa_mask); sigaction(signum, &act, NULL); - status = usleep(200); + status = usleep(200000); ERROR_IF(usleep, status, == 0); assert(sig_handled != 0); @@ -48,7 +48,7 @@ void parent(int signum, pid_t pid) { int status; - usleep(100); + usleep(100000); status = kill(pid, signum); ERROR_IF(kill, status, != 0); diff --git a/tests/signals/killpg-child.c b/tests/signals/killpg-child.c index c6cfbe1851..d1ef669ca1 100644 --- a/tests/signals/killpg-child.c +++ b/tests/signals/killpg-child.c @@ -37,7 +37,7 @@ int killpg_test2(int signum) int i; sigignore(signum); - usleep(100); + usleep(100000); child_pgid = getpgid(child_pid); ERROR_IF(getpgid, child_pgid, == -1); diff --git a/tests/signals/pthread_kill-self.c b/tests/signals/pthread_kill-self.c index e53db627cf..dcc42b85c2 100644 --- a/tests/signals/pthread_kill-self.c +++ b/tests/signals/pthread_kill-self.c @@ -38,7 +38,7 @@ void *a_thread_func( void *arg) sem1=INMAIN; while(sem1==INMAIN) - usleep(100); + usleep(100000); // sleep(50); @@ -61,16 +61,16 @@ int pthread_kill_test1(int signum) ERROR_IF(pthread_create, status, != 0); while(sem1==INTHREAD) - usleep(100); + usleep(100000); status = pthread_kill(new_th, signum); ERROR_IF(pthread_kill, status, != 0); - usleep(200); + usleep(100000); sem1=INTHREAD; while(handler_called==0) - usleep(100); + usleep(100000); ERROR_IF(pthread_kill, handler_called, == -1); ERROR_IF(pthread_kill, handler_called, == 0); diff --git a/tests/signals/sigpause-error.c b/tests/signals/sigpause-error.c index 2a33a608c0..47d9e38388 100644 --- a/tests/signals/sigpause-error.c +++ b/tests/signals/sigpause-error.c @@ -71,14 +71,14 @@ int sigpause_error(int signum){ status = pthread_create(&new_th, NULL, d_thread_func, (void *)&signum); ERROR_IF(pthread_create, status, != 0); - usleep(100); + usleep(100000); status = pthread_kill(new_th, signum); ERROR_IF(pthread_kill, status, != 0); sem = INTHREAD; while (sem == INTHREAD) - usleep(100); + usleep(100000); if(result == 2) { exit(EXIT_FAILURE); diff --git a/tests/signals/sigpause-pause.c b/tests/signals/sigpause-pause.c index 85ec96f3d5..e2a24c763e 100644 --- a/tests/signals/sigpause-pause.c +++ b/tests/signals/sigpause-pause.c @@ -45,12 +45,12 @@ int sigpause_basic(int signum) status = pthread_create(&new_th, NULL, a_thread_func, (void *)&signum); ERROR_IF(pthread_create, status, != 0); - usleep(100); + usleep(100000); status = pthread_kill(new_th, signum); ERROR_IF(pthread_kill, status, != 0); - usleep(100); + usleep(100000); if (handler_called != 1){ prinft("handler wasn't called\n"); diff --git a/tests/signals/sigpause-revert.c b/tests/signals/sigpause-revert.c index ba8f1d8cdd..7e5fe8a3ab 100644 --- a/tests/signals/sigpause-revert.c +++ b/tests/signals/sigpause-revert.c @@ -77,7 +77,7 @@ int sigpause_revert(int signum) { exit(EXIT_FAILURE); } - usleep(100); + usleep(100000); if((status = pthread_kill(new_th, signum)) != 0) { diff --git a/tests/signals/sigpause-suspend.c b/tests/signals/sigpause-suspend.c index ab67c8380d..ed2ab1d2a5 100644 --- a/tests/signals/sigpause-suspend.c +++ b/tests/signals/sigpause-suspend.c @@ -55,7 +55,7 @@ int sigpause_suspend(int signum) perror("failed to create thread"); return EXIT_FAILURE; } - usleep(100); + usleep(100000); assert(!atomic_load(&completed)); if ((status = pthread_kill(new_th, signum)) != 0) { diff --git a/tests/src/main.rs b/tests/src/main.rs index 31b5444d53..d6b6f8edef 100644 --- a/tests/src/main.rs +++ b/tests/src/main.rs @@ -1,3 +1,5 @@ +#![feature(exit_status_error)] + use std::{ env, fs, io::{self, Read, Write}, @@ -48,12 +50,28 @@ fn expected(bin: &str, kind: &str, generated: &[u8], status: ExitStatus) -> Resu const STATUS_ONLY: &str = "-s"; +fn print_tabbed(output: Vec, name: &str) { + if let Ok(stdout) = String::from_utf8(output) { + let stdout: Vec = stdout.trim().lines().map(|p| format!(" {}", p)).collect(); + let stdout = stdout.join("\n"); + if stdout.as_str() == "" { + println!("{name}: empty content"); + } else { + println!("{name}:\n{}", stdout); + } + } else { + println!("can't print out {name}: not utf8"); + } +} + fn main() { let mut failures = Vec::new(); let timeout = Duration::from_secs(10); let slowtime = Duration::from_secs(1); + let bins: Vec = env::args().skip(1).collect(); + let single_test = bins.len() == 1; - for bin in env::args().skip(1) { + for bin in bins { let status_only = bin.starts_with(STATUS_ONLY); let bin = if bin.starts_with(STATUS_ONLY) { bin.strip_prefix(STATUS_ONLY).unwrap().to_string() @@ -152,13 +170,30 @@ fn main() { } match (status, child) { - (Some(exit_status), Some(child)) => { - if !status_only { - let mut stdout = Vec::new(); - let mut stderr = Vec::new(); - child.stdout.unwrap().read_to_end(&mut stdout).unwrap(); - child.stderr.unwrap().read_to_end(&mut stderr).unwrap(); + (exit_status, Some(mut child)) => { + if exit_status.is_none() { + match child.kill() { + Ok(_) => {} + Err(e) => { + // if can't be killed then getting the output will hang + println!("Unable to kill, can't get output: {:?}", e); + continue; + } + } + } + let mut stdout = Vec::new(); + let mut stderr = Vec::new(); + child.stdout.unwrap().read_to_end(&mut stdout).unwrap(); + child.stderr.unwrap().read_to_end(&mut stderr).unwrap(); + let Some(exit_status) = exit_status else { + // hangs + print_tabbed(stdout, "stdout"); + print_tabbed(stderr, "stderr"); + continue; + }; + + if !status_only { if let Err(failure) = expected(&bin, "stdout", &stdout, exit_status) { println!("{}", failure); failures.push(failure); @@ -168,6 +203,17 @@ fn main() { failures.push(failure); } } + + if let Err(e) = exit_status.exit_ok() { + let failure = format!("# {}: {}", bin, e); + println!("{}", failure); + failures.push(failure); + } + + if single_test { + print_tabbed(stdout, "stdout"); + print_tabbed(stderr, "stderr"); + } } (_, _) => { continue; diff --git a/tests/unistd/sleep.c b/tests/unistd/sleep.c index 4ffb8f67d8..92b254e79f 100644 --- a/tests/unistd/sleep.c +++ b/tests/unistd/sleep.c @@ -32,7 +32,7 @@ int main(void) // exit(EXIT_FAILURE); // } - int us_status = usleep(100); + int us_status = usleep(100000); ERROR_IF(usleep, us_status, == -1); UNEXP_IF(usleep, us_status, != 0); diff --git a/tests/waitpid.c b/tests/waitpid.c index 7f4aaf1213..4d89c078ca 100644 --- a/tests/waitpid.c +++ b/tests/waitpid.c @@ -12,7 +12,7 @@ void for_code(int code) { // Testing successful exit if (pid == 0) { // child - usleep(100); + usleep(100000); _Exit(code); } printf("Testing waitpid of child %d for code %d\n", pid, code); diff --git a/tests/waitpid_multiple.c b/tests/waitpid_multiple.c index 7f1df48ff9..f787c84e04 100644 --- a/tests/waitpid_multiple.c +++ b/tests/waitpid_multiple.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -6,16 +7,15 @@ #include "test_helpers.h" int main(void) { - // Spawn two children, one with same pgid and one with pgid set to its own - // pid, so that the one with different pgid completes first. Then test - // waitpid both for 'any child' and for 'any child with same pgid'. + // Spawn three childrens, one with same pgid and two with pgid set to its own + // pid, so the exit order is two different pgid, then followed with same pgid pid_t pid_samepgid = fork(); ERROR_IF(fork, pid_samepgid, == -1); if (pid_samepgid == 0) { // child - usleep(200); + usleep(300000); _Exit(2); } pid_t pid_diffpgids[2]; @@ -28,7 +28,7 @@ int main(void) { ERROR_IF(setpgid, ret, == -1); // child - usleep(100); + usleep((i + 1) * 100000); _Exit(i); } } @@ -49,7 +49,7 @@ int main(void) { assert(WIFEXITED(status)); assert(WEXITSTATUS(status) == 2); - // Finally, the last same-pgid must have completed. + // Finally, the last different-pgid must have completed. wid = waitpid(-1, &status, WNOHANG); ERROR_IF(waitpid, wid, == -1); assert(wid == pid_diffpgids[1]);