# BST-TIMEOUT: 600 # 29 upstream cases + a 6 MB archive census; measured ~90 s, headroom for a loaded host . "$BST_LIB" # libnl 3.9.0 (poky recipes-support/libnl) -- the netlink protocol library, closed # on UPSTREAM'S OWN check-all ptest rather than on a probe we wrote. # # WHAT RUNS. OpenEmbedded already packages tests/check-all as a ptest, so what # executes here is the binary libnl's authors wrote to test libnl: four libcheck # suites, 29 cases -- nl_addr (6), netlink attributes (4), an ematch tree clone # (1), and the netns fixture (18). It is driven through ptest-runner, which is # what this ticket closes on, and the runner/* cases assert the harness itself # rather than assuming it. # # THE ORACLE IS A NATIVE x86_64 CONTROL OF THE IDENTICAL TARBALL. # data/libnl-native.txt is check-all built from libnl-3.9.0.tar.gz (sha256 # aed5070...ee9bb) against a libcheck 0.15.2 built the same static way, configured # as the distro configures it (--disable-shared) and run in the same CK_FORK=no # mode. All 29 pass there, and src/libnl_mknative.sh --check regenerates it over # twelve runs and diffs, so a flaky case cannot enter the file. Every case name # below is read off that run, never off the source. # # THE COUNTS ARE A TRUE ORACLE, not a convenience: nl_addr parsing, attribute # packing and an ematch deep-clone are fixed by the suite's own control flow and # carry no pointer width, no sizeof, no address and no timing. Nothing in them is # ALLOWED to differ between x86_64 and wasm32, so a disagreement is a defect on # this arm rather than a platform difference to reason about. # # EIGHTEEN CASES ARE EXPECTED RED, ONE CAUSE, AND THEY ARE LEFT RED ON PURPOSE. # libnl's netns fixture calls unshare(CLONE_NEWUSER) (tests/nl-test-util.c:125) # and gets ENOSYS: syscall 272 is absent from arch/wasm32/kernel/syscall_table.c # although sys_unshare / __se_sys_unshare / ksys_unshare are all compiled into # kernel/fork.o -- brintos/linux#56. libcheck reports a failing CHECKED FIXTURE # once, under the fixture's own name, with the tests it guards never run # (check_str.c:tr_type_str returns "S" for any non-CK_CTX_TEST context), so the # per-case reds below are named from the CONTROL rather than from a target line # that does not exist. They flip green by themselves when #56 lands, which is the # regression signal this suite is bought for -- so they are reported failing and # not skipped. # # A SECOND PLATFORM GAP DECIDES HOW THE SUITE RUNS AT ALL. libcheck's default fork # mode arms a per-test POSIX timer, and timer_create(2) is ENOSYS here # (brintos/linux#40), so the stock run-ptest dies after the first of four suites # having collected nothing. The shipped run-ptest sets CK_FORK=no; the mode is # ASSERTED below rather than assumed, so a run that silently reverted to fork mode # is caught instead of read as a shorter green. # # SPAWN BUDGET. exec is a fresh wasm module instantiation here (~2-3 s), so this # file runs ptest-runner ONCE, builds the archive index once, joins everything in # ONE awk pass emitting a pre-computed " " triple, and the shell # loop that reports them spawns nothing. Presence checks use check_rc with `test`, # an ash builtin. The index is a TOKEN SET rather than one accumulated string: # the seven archives are 6 MB together, and repeated string concatenation over # that is quadratic in busybox awk. ptestdir=/usr/lib/libnl/ptest runner=/usr/bin/ptest-runner native=$BST_DATA/libnl-native.txt lib=/usr/lib/libnl-3.a pc=/usr/lib/pkgconfig/libnl-3.0.pc tmp=${TMPDIR:-/tmp}/bst-libnl.$$ mkdir -p "$tmp" 2>/dev/null || tmp=/tmp # ----------------------------------------------------------- what shipped ---- check_rc libnl/ptest-dir 0 test -d "$ptestdir" check_rc libnl/ptest-runptest 0 test -x "$ptestdir/run-ptest" check_rc libnl/ptest-checkall 0 test -x "$ptestdir/check-all" check_rc libnl/native-oracle 0 test -s "$native" check_rc libnl/ar-present 0 test -s "$lib" check_rc libnl/pc-present 0 test -f "$pc" # The seven archives the -staticdev split ships, one per sub-library. libnl-cli-3 # is the one the nl-* tools link, so a missing member here and a working tool # below cannot both be true. for a in libnl-3 libnl-cli-3 libnl-genl-3 libnl-idiag-3 libnl-nf-3 \ libnl-route-3 libnl-xfrm-3; do check_rc "libnl/ar-$a" 0 test -s "/usr/lib/$a.a" done # NO SHARED OBJECT ANYWHERE: the distro is static-only and libnl's FILES:${PN} is # otherwise all .so.* globs, which is what makes the bare libnl package the CONFIG # FILES rather than a runtime library. Asserted by file CONTENT, not by the path # being absent for some unrelated reason. check_rc libnl/no-so 1 sh -c 'ls /usr/lib/libnl*.so* 2>/dev/null | grep -q .' check_rc libnl/etc-classid 0 test -s /etc/libnl/classid check_rc libnl/etc-pktloc 0 test -s /etc/libnl/pktloc # The headers a consumer includes: the umbrella, the core types, and one per # sub-library, so a configure flag that did not take shows up as a missing header # rather than at a consumer's first build. for h in netlink/netlink.h netlink/addr.h netlink/attr.h netlink/msg.h \ netlink/cache.h netlink/socket.h netlink/route/link.h \ netlink/genl/genl.h netlink/cli/utils.h; do check_rc "libnl/hdr-$(echo "$h" | tr / -)" 0 test -s "/usr/include/libnl3/$h" done # A representative CLI tool from each family the -cli package ships. for t in nl-link-list nl-addr-list genl-ctrl-list nl-classid-lookup; do check_rc "libnl/bin-$t" 0 test -x "/usr/bin/$t" done # nl-classid-lookup reads /etc/libnl/classid and opens NO netlink socket, so it is # the one CLI tool whose success is a statement about this port rather than about # this arm's networking. "root" is a stock entry in the shipped table and maps to # the well-known qdisc handle ffff:ffff. check_out libnl/cli-classid-lookup "ffff:ffff" nl-classid-lookup root # ------------------------------------------------------- run it, once --------- # ptest-runner resolves /usr/lib itself (DEFAULT_DIRECTORY is compiled in), # discovers libnl/ptest, chdirs in and execs run-ptest under a pty; naming the # ptest confines the run to this one suite. out=$tmp/runner.out harness=0 if [ -x "$runner" ]; then harness=1 bst_ok libnl/ptest-runner-present "$runner" libnl > "$out" 2>&1 else bst_skip libnl/ptest-runner-present "this image ships no ptest-runner" for c in runner-begin runner-end runner-total runner-fail; do bst_skip "libnl/$c" "harness cases have no subject without ptest-runner" done sh "$ptestdir/run-ptest" > "$out" 2>&1 fi # The exit status is deliberately NOT asserted: run-ptest exits non-zero precisely # because the 18 attributed reds below are real, so a case on it would only # restate them and would have to be inverted the day they go green. # --------------------------------------------------- the archive, flattened --- # All seven archives, because the symbols below live in six different ones -- an # index built from libnl-3.a alone reports every route/genl/nf/xfrm/cli symbol # missing. Two processes, once. idx=$tmp/ar.idx cat /usr/lib/libnl-3.a /usr/lib/libnl-cli-3.a /usr/lib/libnl-genl-3.a \ /usr/lib/libnl-idiag-3.a /usr/lib/libnl-nf-3.a /usr/lib/libnl-route-3.a \ /usr/lib/libnl-xfrm-3.a 2>/dev/null | tr -c '\40-\176\n' ' ' > "$idx" # ------------------------------------------------------- the single join ------ awk -v OFS=' ' ' function emit(id, want, got) { print id, want, got } # ---- file 1: the native control ---- FILENAME == NATIVE { if ($0 ~ /^#/ || NF == 0) next native_verdict[$1] = $2 order[++nnative] = $1 next } # ---- file 2: the ptest-runner output ---- FILENAME == RUNOUT { # run-ptest transcription: "PASS: :" / "FAIL: :" if ($1 == "PASS:") { got[$2] = "P"; reported++; next } if ($1 == "FAIL:") { got[$2] = "F"; reported++; next } # libcheck own summary: "37%: Checks: 29, Failures: 18, Errors: 0" if ($0 ~ /Checks: [0-9]+, Failures: [0-9]+, Errors: [0-9]+/) { n = split($0, s, /[ ,]+/) for (i = 1; i <= n; i++) { if (s[i] == "Checks:") checks = s[i+1] if (s[i] == "Errors:") errors = s[i+1] } next } if ($0 ~ /^BEGIN: /) { begin_line = $2; next } if ($0 ~ /^END: /) { end_line = $2; next } if ($0 ~ /^TOTAL: /) { rt_total = $2; rt_fail = $4; next } # the fork-mode gap, recognised by libcheck own message if ($0 ~ /Error in call to timer_create/) forkmode = "fork" next } # ---- file 3: the flattened archive index, as a TOKEN SET ---- FILENAME == IDX { for (i = 1; i <= NF; i++) tok[$i] = 1; next } END { # --- THE SUITE, case by case, named from the control --------------------- # A case the control passed must pass here. The 18 the netns fixture guards # are never reported by name on an arm without unshare(2), so their "got" is # the fixture verdict when the fixture is what failed, and NOT-REPORTED # otherwise -- the two are different diagnoses and are not collapsed. for (i = 1; i <= nnative; i++) { c = order[i] if (c in got) g = got[c] else if ("checked_setup:0" in got) g = "FIXTURE-FAILED" else g = "NOT-REPORTED" emit("libnl/case-" c, native_verdict[c], g) } # --- completeness: the run reached its own summary and counted every case -- # This is what catches a TRUNCATED run whose visible cases all happen to be # green -- the failure mode a per-case-only report cannot see. emit("libnl/suite-checks-ran", nnative "", checks "") emit("libnl/suite-errors", "0", errors "") emit("libnl/suite-reported", nnative "", reported "") # --- the mode the suite ran in, asserted rather than assumed -------------- emit("libnl/ck-fork-off", "no-fork", (forkmode == "fork" ? "fork" : "no-fork")) # --- the harness: discovery, the child plumbing, and the tally ------------ if (HARNESS == "1") { emit("libnl/runner-begin", PTESTDIR, begin_line "") emit("libnl/runner-end", PTESTDIR, end_line "") # ptest-runner counts ptest DIRECTORIES, not cases: exactly one was found # and run, which is the harness contract this ticket closes on and is green. emit("libnl/runner-total", "1", rt_total "") # ...and it must eventually report that one as passing. Red today because # the 18 are real; flips green with them. emit("libnl/runner-fail", "0", rt_fail "") } # --- the archive: one exported entry point per sub-library --------------- # Six of the seven archives are covered, so a partial compile that produced # libnl-3.a but not libnl-route-3.a fails here rather than at a consumer. ns = split("nl_socket_alloc nl_connect nl_addr_parse nl_addr2str nla_put " \ "nlmsg_alloc nl_cache_alloc rtnl_link_alloc rtnl_addr_alloc " \ "genl_connect nl_cli_addr_parse_local nfnl_ct_alloc " \ "xfrmnl_sa_alloc idiagnl_msg_alloc", want_s, " ") for (i = 1; i <= ns; i++) emit("libnl/ar-sym-" want_s[i], want_s[i], (want_s[i] in tok ? want_s[i] : "MISSING")) } ' NATIVE="$native" RUNOUT="$out" IDX="$idx" PTESTDIR="$ptestdir" HARNESS="$harness" \ "$native" "$out" "$idx" > "$tmp/verdicts" 2>/dev/null # ------------------------------------------------------ report, fork-free ----- n=0 while IFS=' ' read -r id want got; do [ -n "$id" ] || continue check_eq "$id" "$want" "$got" n=$((n + 1)) done < "$tmp/verdicts" # A join that emitted half its cases would otherwise read as a short but green # suite, so the count is asserted rather than inferred from what arrived. if [ "$harness" = 1 ]; then check_eq libnl/join-complete 51 "$n" else check_eq libnl/join-complete 47 "$n"; fi rm -rf "$tmp"