diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9973f125e0..583af95b36 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -58,8 +58,7 @@ test:x86_64: stage: test needs: [x86_64] script: - # TODO: sigaction and sigaltstack hangs with multi core - - REDOXER_QEMU_ARGS="-smp 1" ./check.sh --arch=x86_64 --test + - ./check.sh --arch=x86_64 --test test:aarch64: stage: test diff --git a/Makefile b/Makefile index d06a41e73b..8a49bd401f 100644 --- a/Makefile +++ b/Makefile @@ -114,7 +114,6 @@ test: sysroot/$(TARGET) # TODO: Fix SIGILL when running cargo test # $(CARGO_TEST) test $(MAKE) -C tests run - $(MAKE) -C tests verify $(BUILD)/$(PROFILE)/libc.so: $(BUILD)/$(PROFILE)/librelibc.a $(BUILD)/openlibm/libopenlibm.a diff --git a/check.sh b/check.sh index 8785d6138a..6117129ac6 100755 --- a/check.sh +++ b/check.sh @@ -98,7 +98,7 @@ run_redoxer() { redoxer toolchain || { echo -e "${RED}Fail: redoxer toolchain for: $target.${NC}" && exit 1; } export CARGOFLAGS="" export CARGO_TEST="redoxer" - export TEST_RUNNER="redoxer exec --folder . --" + export TEST_RUNNER="redoxer exec --folder ../sysroot/$TARGET:/usr --folder . --" MAKE_ACTION="$MAKE_ACTION SKIP_REDOX=1 NATIVE_RELIBC=1" else REDOXER_ENV="" diff --git a/tests/Makefile b/tests/Makefile index 74eb934f4e..fc4e7b6d41 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -10,7 +10,10 @@ REDOX_FAILING_TESTS=tls \ futimens \ mkfifo \ stdlib/ptsname \ - sys_mman + sys_mman \ +# resource/getrusage +# time/times +# netdb/netdb endif @@ -178,10 +181,7 @@ EXPECT_NAMES=\ wctype/towlower \ wctype/towupper \ mknod \ - mknodat \ - $(REDOX_FAILING_TESTS) - # TODO: Fix this - # netdb/netdb \ + mknodat BUILD?=. @@ -190,8 +190,7 @@ DYNAMIC_ONLY_NAMES=\ dlopen_scopes # Binaries that may generate varied output -NAMES=\ - $(EXPECT_NAMES) \ +VARIED_NAMES=\ dirent/main \ dirent/posix_getdents \ kill-waitpid \ @@ -293,9 +292,8 @@ NAMES=\ grp/gr_iter \ waitpid \ waitpid_multiple \ - sigqueue -# resource/getrusage -# time/times + sigqueue \ + $(REDOX_FAILING_TESTS) # Tests run with `expect` (require a .c file and an .exp file # that takes the produced binary as the first argument) @@ -303,18 +301,20 @@ EXPECT_INPUT_NAMES=\ unistd/getpass # TODO: Dynamic linking doesn't work with NATIVE_RELIBC=0 -# TODO: Some tests in NAMES break the kernel -# TODO: Reduce bins_static tests? +# TODO: Reduce bins_static tests, only execute it when static link difference matters ifeq ($(SKIP_REDOX),0) -BINS=$(patsubst %,$(BUILD)/bins_static/%,$(NAMES)) -BINS+=$(patsubst %,$(BUILD)/bins_dynamic/%,$(NAMES)) -BINS+=$(patsubst %,$(BUILD)/bins_dynamic/%,$(DYNAMIC_ONLY_NAMES)) +BINS+=$(patsubst %,$(BUILD)/bins_static/%,$(VARIED_NAMES)) +BINS+=$(patsubst %,$(BUILD)/bins_dynamic/%,$(VARIED_NAMES)) +EXPECT_BINS+=$(patsubst %,$(BUILD)/bins_static/%,$(EXPECT_NAMES)) EXPECT_BINS+=$(patsubst %,$(BUILD)/bins_dynamic/%,$(EXPECT_NAMES)) EXPECT_BINS+=$(patsubst %,$(BUILD)/bins_dynamic/%,$(DYNAMIC_ONLY_NAMES)) EXPECT_INPUT_BINS=$(patsubst %,$(BUILD)/bins_expect_input/%,$(EXPECT_INPUT_NAMES)) else +# TODO: Not compiling static tests, too heavy for redoxerd +BINS+=$(patsubst %,$(BUILD)/bins_dynamic/%,$(VARIED_NAMES)) EXPECT_BINS+=$(patsubst %,$(BUILD)/bins_dynamic/%,$(EXPECT_NAMES)) EXPECT_BINS+=$(patsubst %,$(BUILD)/bins_dynamic/%,$(DYNAMIC_ONLY_NAMES)) +# TODO: EXPECT_INPUT_BINS endif CARGO_TEST?=cargo @@ -327,35 +327,18 @@ all: $(BINS) clean: rm -rf bins_* gen *.out -run: | $(BINS) $(EXPECT_INPUT_BINS) +run: bins_verify/relibc-tests $(BINS) $(EXPECT_BINS) $(EXPECT_INPUT_BINS) @echo "\033[1;36;49mRunning tests\033[0m" - @for bin in $(BINS); \ - do \ - echo "\033[0;96;49m# $${bin} #\033[0m"; \ - ${TEST_RUNNER} "$${bin}" test args || exit $$?; \ - done + $(TEST_RUNNER) $< $(patsubst %,-s%,$(BINS)) $(EXPECT_BINS) for exp in $(EXPECT_INPUT_BINS); \ do \ echo "# expect $$(readlink -e $${exp}.exp) $$(readlink -e $${exp}) #"; \ expect "$$(readlink -e $${exp}.exp)" "$$(readlink -e $${exp})" test args || exit $$?; \ done -expected: | $(EXPECT_BINS) - rm -rf expected - mkdir -p expected - for bin in $(EXPECT_BINS); \ - do \ - echo "# $${bin} #"; \ - mkdir -p expected/`dirname $${bin}`; \ - "$${bin}" test args > "expected/$${bin}.stdout" 2> "expected/$${bin}.stderr" || exit $$?; \ - done - bins_verify/relibc-tests: src/main.rs $(CARGO_TEST) build --release --bin relibc-tests --out-dir bins_verify -Z unstable-options -verify: bins_verify/relibc-tests | $(EXPECT_BINS) - $(TEST_RUNNER) $< $(EXPECT_BINS) - FLAGS=\ -std=c11 \ -fno-builtin \ diff --git a/tests/src/main.rs b/tests/src/main.rs index 80aa38dcc8..d6d4e15c8c 100644 --- a/tests/src/main.rs +++ b/tests/src/main.rs @@ -1,8 +1,11 @@ use std::{ env, fs, - io::{self, Write}, + io::{self, Read, Write}, path::PathBuf, - process::{self, Command, ExitStatus}, + process::{self, Command, ExitStatus, Stdio}, + sync::mpsc, + thread, + time::{Duration, Instant}, }; fn expected(bin: &str, kind: &str, generated: &[u8], status: ExitStatus) -> Result<(), String> { @@ -47,6 +50,8 @@ const STATUS_ONLY: &str = "-s"; fn main() { let mut failures = Vec::new(); + let timeout = Duration::from_secs(10); + let slowtime = Duration::from_secs(1); for bin in env::args().skip(1) { let status_only = bin.starts_with(STATUS_ONLY); @@ -58,30 +63,124 @@ fn main() { println!("# {} #", bin); - match Command::new(&bin).arg("test").arg("args").output() { - Ok(output) => { + let start_time = Instant::now(); + + let (tx, rx) = mpsc::channel(); + let bin_for_spawn = bin.clone(); + + // There's an issue when pthread hangs, spawn() also hangs, so let's use separate thread to spawn + thread::spawn(move || { + let result = Command::new(&bin_for_spawn) + .arg("test") + .arg("args") + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn(); + tx.send(result).expect("Can't send"); + }); + + let mut status = None; + let mut child = None; + + loop { + if start_time.elapsed() > timeout { + let failure = format!( + "\x1b[0;91;49m{}: assumed hangs after {}ms\x1b[0m", + bin, + start_time.elapsed().as_millis() + ); + println!("{}", failure); + failures.push(failure); + break; + } + // A pretty rare hang on pthread/barrier which also stops this loop :( + // https://gitlab.redox-os.org/redox-os/relibc/-/issues/238 + if &bin == "./bins_dynamic/pthread/barrier" || start_time.elapsed() > slowtime { + println!("# waiting {}ms", start_time.elapsed().as_millis()); + } + + let c = match &mut child { + Some(child) => child, + None => match rx.try_recv() { + Ok(Ok(c)) => { + child = Some(c); + continue; + } + Ok(Err(err)) => { + let failure = format!("{}: failed to execute: {}", bin, err); + println!("{}", failure); + failures.push(failure); + break; + } + Err(mpsc::TryRecvError::Disconnected) => { + let failure = format!("{}: failed to execute: thread died", bin); + println!("{}", failure); + failures.push(failure); + break; + } + Err(mpsc::TryRecvError::Empty) => { + thread::sleep(Duration::from_millis(if start_time.elapsed() < slowtime { + 25 + } else { + 500 + })); + continue; + } + }, + }; + + match c.try_wait() { + Ok(Some(s)) => { + status = Some(s); + break; + } + Ok(None) => { + thread::sleep(Duration::from_millis(if start_time.elapsed() < slowtime { + 25 + } else { + 500 + })); + } + Err(e) => { + failures.push(format!("{}: error waiting: {}", bin, e)); + break; + } + } + } + + match (status, child) { + (Some(exit_status), Some(child)) => { if !status_only { - if let Err(failure) = expected(&bin, "stdout", &output.stdout, output.status) { + 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(); + + if let Err(failure) = expected(&bin, "stdout", &stdout, exit_status) { println!("{}", failure); failures.push(failure); } - - if let Err(failure) = expected(&bin, "stderr", &output.stderr, output.status) { + if let Err(failure) = expected(&bin, "stderr", &stderr, exit_status) { println!("{}", failure); failures.push(failure); } } } - Err(err) => { - let failure = format!("{}: failed to execute: {}", bin, err); - println!("{}", failure); - failures.push(failure); + (_, _) => { + continue; } } + + if start_time.elapsed() > slowtime { + println!( + "\x1b[0;93;49m test exection took too long: {}ms\x1b[0m", + start_time.elapsed().as_millis() + ); + } } if !failures.is_empty() { - println!("# FAILURES #"); + println!("\x1b[1;91;49m# FAILURES #\x1b[0m"); for failure in failures { println!("{}", failure); }