ci: fix macOS self-test failures and worker selection (#31196)
* ci: respect macOS self-test workers with fail-fast * builtin: keep vgc thread-cache test allocation at runtime * driver: align wasm array gate tests with string support * tests: use selected C compiler for raw assembly fixture
This commit is contained in:
1 parent
6cce632507
commit
f13fb293ad
6 files changed
+47
-22
No files matched your search
+4
-2
@@ -69,8 +69,10 @@ its checkpoints, so the following invocation starts from the beginning.
|
||||
|
||||
The aggregate `ci` command sets `VTEST_FAIL_FAST=1` and `VJOBS=1`, overriding inherited
|
||||
values. Test and example-build sessions stop at the first reported failure, with no
|
||||
other files already running in parallel. The `self_tests` task retains this single-worker
|
||||
setting; standalone GitHub Actions self-test tasks still use every available CPU.
|
||||
other files already running in parallel. The `self_tests` task retains the explicit
|
||||
`VJOBS` setting, including the workflow's three workers and the aggregate runner's
|
||||
single worker. Without `VJOBS`, GitHub Actions self-tests use one worker when
|
||||
`VTEST_FAIL_FAST=1`, or every available CPU otherwise.
|
||||
`test-cleancode` also stops after a failed
|
||||
vetting session instead of starting formatting checks. The failed task's checkpoint
|
||||
is retained. Existing per-test retry and known-flaky-test policies are unchanged.
|
||||
|
||||
+5
-3
@@ -64,10 +64,12 @@ fn self_tests() {
|
||||
// test the release's own standard library instead of this repository's.
|
||||
// Individual files still fall back to it when the default compiler cannot
|
||||
// build them.
|
||||
// Exercise default caching throughout the standard library suite. Use every
|
||||
// core on the 7 GB runners unless the aggregate runner requires fail-fast.
|
||||
// Exercise default caching throughout the standard library suite. Respect the
|
||||
// workflow's worker count as well as the aggregate runner's serial setting.
|
||||
if common.is_github_job {
|
||||
vjobs := if os.getenv('VTEST_FAIL_FAST') == '1' { '1' } else { '${runtime.nr_cpus()}' }
|
||||
vjobs := os.getenv_opt('VJOBS') or {
|
||||
if os.getenv('VTEST_FAIL_FAST') == '1' { '1' } else { '${runtime.nr_cpus()}' }
|
||||
}
|
||||
exec_args(['env', 'VJOBS=' + '${vjobs}', 'v', '-no-memory-limit', '-silent', 'test-self',
|
||||
'vlib'])
|
||||
} else {
|
||||
|
||||
@@ -39,8 +39,8 @@ if [ "$1" = doctor ]; then
|
||||
fi
|
||||
if [ "$1" = -no-memory-limit ]; then
|
||||
[ "$2" = -silent ] && [ "$3" = test-self ] && [ "$4" = vlib ] || exit 98
|
||||
[ "${VTEST_FAIL_FAST:-}" = 1 ] && [ "${VJOBS:-}" = 1 ] || exit 99
|
||||
echo self-tests >> self.log
|
||||
[ "${VJOBS:-}" = "$SELF_TEST_EXPECTED_JOBS" ] || exit 99
|
||||
printf '%s:%s\n' "$VTEST_FAIL_FAST" "$VJOBS" >> self.log
|
||||
exit 0
|
||||
fi
|
||||
[ "$1" = run ] && [ "$2" = ci/macos_ci.vsh ] || exit 90
|
||||
@@ -134,12 +134,22 @@ run_ci 0 v_doctor
|
||||
cmp "$work/saved" "$checkpoint"
|
||||
[ "$(cat "$checkout/direct.log")" = doctor ] || fail 'individual task did not run'
|
||||
|
||||
# Execute the real self_tests task: its GitHub branch must retain the aggregate
|
||||
# runner's serial fail-fast setting instead of replacing it with the CPU count.
|
||||
(cd "$checkout" && GITHUB_JOB=clang-macos VTEST_FAIL_FAST=1 VJOBS=1 \
|
||||
V_CI_VEXE="$fake_v" "$runner" self_tests) > "$work/output" 2>&1 || \
|
||||
fail 'self_tests replaced the fail-fast worker count'
|
||||
[ "$(cat "$checkout/self.log")" = self-tests ] || fail 'self_tests did not run'
|
||||
# Execute the real self_tests task with both the aggregate runner's serial setting
|
||||
# and the workflow's three workers. Fail-fast must not override an explicit VJOBS.
|
||||
for fast in 0 1; do
|
||||
for jobs in 1 3; do
|
||||
(cd "$checkout" && GITHUB_JOB=clang-macos VTEST_FAIL_FAST="$fast" VJOBS="$jobs" \
|
||||
SELF_TEST_EXPECTED_JOBS="$jobs" V_CI_VEXE="$fake_v" "$runner" self_tests) \
|
||||
> "$work/output" 2>&1 || fail "self_tests replaced VJOBS=$jobs (fail-fast=$fast)"
|
||||
done
|
||||
done
|
||||
printf '0:1\n0:3\n1:1\n1:3\n' > "$work/expected-self"
|
||||
cmp "$work/expected-self" "$checkout/self.log" || fail 'self_tests did not run'
|
||||
|
||||
# Without an explicit worker count, fail-fast still defaults to a serial session.
|
||||
(cd "$checkout" && unset VJOBS && GITHUB_JOB=clang-macos VTEST_FAIL_FAST=1 \
|
||||
SELF_TEST_EXPECTED_JOBS=1 V_CI_VEXE="$fake_v" "$runner" self_tests) \
|
||||
> "$work/output" 2>&1 || fail 'self_tests lost its serial fail-fast default'
|
||||
|
||||
# A second checkout must not consume the first checkout's saved progress.
|
||||
first_checkout=$checkout
|
||||
|
||||
@@ -7,16 +7,18 @@ import sync
|
||||
|
||||
fn C.vgc_get_cache_idx() int
|
||||
|
||||
fn cache_idx_after_allocating() int {
|
||||
s := 'vgc'.repeat(40)
|
||||
assert s.len == 120
|
||||
// Keep the count dynamic so compile-time string folding cannot remove the allocation.
|
||||
@[noinline]
|
||||
fn cache_idx_after_allocating(count int) int {
|
||||
s := 'vgc'.repeat(count)
|
||||
assert s.len == 3 * count
|
||||
return C.vgc_get_cache_idx()
|
||||
}
|
||||
|
||||
// cache_idx_while_others_run keeps the thread alive until all threads have their cache: a
|
||||
// thread that has exited gives its cache slot to the next one.
|
||||
fn cache_idx_while_others_run(started &sync.WaitGroup, release chan bool) int {
|
||||
idx := cache_idx_after_allocating()
|
||||
idx := cache_idx_after_allocating(40)
|
||||
mut wg := unsafe { started }
|
||||
wg.done()
|
||||
_ := <-release
|
||||
@@ -38,7 +40,7 @@ fn allocate_strings(id int) int {
|
||||
|
||||
fn test_spawned_threads_get_their_own_vgc_cache() {
|
||||
$if vgc ? {
|
||||
main_idx := cache_idx_after_allocating()
|
||||
main_idx := cache_idx_after_allocating(40)
|
||||
assert main_idx >= 0
|
||||
mut threads := []thread int{}
|
||||
mut started := sync.new_waitgroup()
|
||||
|
||||
@@ -98,10 +98,12 @@ fn test_all() {
|
||||
no_closures_dir := 'vlib/v/tests/no_closures'
|
||||
js_checker_tests := ['index_expr_implicit_int_downcast_err.vv',
|
||||
'js_number_requires_explicit_cast.vv']
|
||||
raw_asm_checker_tests := ['asm_raw_label_ok.vv']
|
||||
disable_explicit_mutability_tests := ['disable_explicit_mutability.vv']
|
||||
|
||||
checker_tests := get_tests_in_dir(checker_dir, false).filter(!it.contains('with_check_option')
|
||||
&& it !in js_checker_tests && it !in disable_explicit_mutability_tests)
|
||||
&& it !in js_checker_tests && it !in raw_asm_checker_tests
|
||||
&& it !in disable_explicit_mutability_tests)
|
||||
parser_tests := get_tests_in_dir(parser_dir, false)
|
||||
scanner_tests := get_tests_in_dir(scanner_dir, false)
|
||||
global_tests := get_tests_in_dir(global_dir, false)
|
||||
@@ -180,6 +182,8 @@ fn test_all() {
|
||||
tasks.add('', parser_dir, '', '.out', parser_tests, false)
|
||||
tasks.add('', checker_dir, '', '.out', checker_tests, false)
|
||||
tasks.add('', checker_dir, '-b js', '.js.out', js_checker_tests, false)
|
||||
// Keep raw assembly on the compiler selected for this test and its skip rules.
|
||||
tasks.add('', checker_dir, '-cc ${@CCOMPILER}', '.out', raw_asm_checker_tests, false)
|
||||
tasks.add('', scanner_dir, '', '.out', scanner_tests, false)
|
||||
tasks.add('', checker_dir, '-enable-globals run', '.run.out', ['globals_error.vv'], false)
|
||||
tasks.add('', global_run_dir, '-enable-globals run', '.run.out', global_run_tests, false)
|
||||
|
||||
@@ -6,7 +6,7 @@ import v.parser
|
||||
import v.pref
|
||||
import v.types
|
||||
|
||||
// The wasm backend lowers dynamic arrays of primitive elements, so the
|
||||
// The wasm backend lowers dynamic arrays of primitive and string elements, so the
|
||||
// driver gate must admit them while still rejecting maps, structs, fixed
|
||||
// arrays and nested arrays. A rejection here is a hard error before any wasm
|
||||
// is emitted; an admission it should not make would miscompile silently
|
||||
@@ -50,6 +50,11 @@ fn test_wasm_gate_admits_primitive_arrays() {
|
||||
assert wasm_gate_check('module main\nfn main() {\n\tz := []int{len: 4, init: 7}\n\tprintln(z.len)\n}\n') == ''
|
||||
}
|
||||
|
||||
fn test_wasm_gate_admits_string_arrays() {
|
||||
assert wasm_gate_check("module main\nfn main() {\n\ta := ['one', 'two']\n\tprintln(a[0])\n}\n") == ''
|
||||
assert wasm_gate_check("module main\nfn main() {\n\ta := []string{len: 2, init: 'v'}\n\tprintln(a.len)\n}\n") == ''
|
||||
}
|
||||
|
||||
// Struct literals are admitted when every field has a lowering, which is what
|
||||
// lets lesson pages with structs run client-side. The rejection direction is
|
||||
// still pinned: a struct holding a map has no field-wise wasm lowering, so it
|
||||
@@ -77,10 +82,10 @@ fn test_wasm_gate_rejects_maps_structs_fixed_nested() {
|
||||
|
||||
fn test_wasm_supported_array_elem() {
|
||||
for t in ['int', 'i8', 'i16', 'i32', 'i64', 'u8', 'u16', 'u32', 'u64', 'uint', 'f32', 'f64',
|
||||
'bool', 'char', 'rune'] {
|
||||
'bool', 'char', 'rune', 'string'] {
|
||||
assert wasm_supported_array_elem(flat.source_type_id('[]' + t)), t
|
||||
}
|
||||
for t in ['', '[]', 'int', 'map[string]int', 'Point', '[2]int', '[][]int', '[]Point', '[]string',
|
||||
for t in ['', '[]', 'int', 'map[string]int', 'Point', '[2]int', '[][]int', '[][]string', '[]Point',
|
||||
' []int', '[]int ', '[] int', '[]builtin.int'] {
|
||||
assert !wasm_supported_array_elem(flat.source_type_id(t)), t
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user