# BST-TIMEOUT: 1200 # 218 cases, each a fork+pipe+tmpfile in munit's default mode; # # measured on target and recorded in the design doc. Two module # # instantiations per programme (--list, then the run). . "$BST_LIB" # nghttp2 1.61.0 -- the HTTP/2 C library (poky recipes-support/nghttp2). See # nghttp2_%.bbappend for what the port adds and why. # # --------------------------------------------------------------------------- # WHAT THIS SUITE IS, AND WHY IT IS NOT A PROBE # # It closes on the PACKAGE'S OWN UPSTREAM SUITE: the two munit programmes # tests/CMakeLists.txt declares to ctest, 218 cases between them, staged whole by # the bbappend and run here under ptest-runner. Nothing in this file asserts an # HTTP/2 behaviour of its own -- the assertions are upstream's, over the frame # codec, the HPACK header compressor, the session state machine, the priority and # rate-limit logic, and the containers beneath all of it. # # That matters more here than for most ports. HTTP/2 is a BINARY, MULTIPLEXED # protocol whose hard parts are exactly the ones a hand-written probe would not # think to reach: continuation frames spanning a header block, HPACK's dynamic # table evicting under a size update, flow-control windows going negative on a # SETTINGS change, a stream closed while its data is still queued. Upstream's # session tests drive BOTH endpoints in-process against memory buffers, so they # reach those states deterministically and without a peer, a socket or a clock -- # which is also what makes them runnable on this arm at all. # # THE SECOND PROGRAMME IS THE ALLOCATION-FAILURE SUITE. failmalloc runs the frame # and HPACK paths with nghttp2's own allocator hooks rigged to fail at the Nth # call, walking N outward. It needs no LD_PRELOAD and no symbol interposition -- # nghttp2_mem is a documented public seam -- so unlike most OOM harnesses it is # fully portable and there is no reason not to ship it. On an arm whose allocator # is young, a library that cleans up correctly under a failing malloc is worth # asserting rather than assuming. # # --------------------------------------------------------------------------- # WHY EVERY ONE OF THESE IS EXPECTED TO PASS, WITH NO ARM-DEPENDENT ROW # # The suite is pure computation over memory buffers: no file, no socket, no # device, no configuration, no wall clock in any assertion. What it asserts is a # WIRE FORMAT and a state machine -- byte-exact frame layouts and Huffman-coded # header blocks defined by RFC 9113 and RFC 7541, and the transitions between # them. Those are fixed by the specification, not by word size, endianness, # compiler or allocator, so there is no class of row that may legitimately differ # between x86-64 and wasm32 and none is asserted separately. A red here is a real # defect in the port, the arm, or the codegen beneath it. # # THE ONE THING THAT IS NOT COMPUTATION. munit buffers each case's stderr through # tmpfile(), which resolves under /tmp -- the only filesystem write the whole run # performs, and the rootfs is read-only at browser runtime. run-ptest checks for a # writable /tmp once, up front, and says so in one line rather than letting 218 # cases report ERROR for a reason that has nothing to do with nghttp2. If this # suite ever goes red at nghttp2/ptest-setup alone, read it as an environment # finding. # # --------------------------------------------------------------------------- # THE COUNTS ARE ASKED OF THE SHIPPED BINARIES, NOT ONLY PINNED HERE # # munit builds its case list from C arrays, so unlike libmpc's check_PROGRAMS # there is no declaration the recipe could parse and assert against. The # equivalent invariant is made on target instead: run-ptest asks each programme to # --list its own cases and reports that count beside the count it observed, and # the listed-eq-run cases below assert the two agree. That catches the failure # that actually threatens this suite -- a run that died a third of the way through # and reported a clean green for the third that ran. # # want_total is pinned as well, because listed-eq-run alone cannot see a suite # that got SHORTER: a truncated payload would list less and run less, agreeing # with itself the whole way down. The pinned number is upstream 1.61.0's, and a # version bump that changes it is meant to be a visible decision here rather than # a silent drift. ptestdir=/usr/lib/nghttp2/ptest runner=/usr/bin/ptest-runner hdr=/usr/include/nghttp2/nghttp2.h verhdr=/usr/include/nghttp2/nghttp2ver.h lib=/usr/lib/libnghttp2.a pc=/usr/lib/pkgconfig/libnghttp2.pc # Upstream 1.61.0: tests/CMakeLists.txt declares two add_test() programmes, and # they carry 213 (main) + 5 (failmalloc) munit cases. want_progs=2 want_total=218 # Below this file's BST-TIMEOUT on purpose, so an overrun is reported by # ptest-runner in its own voice instead of this whole file being killed around it # -- the arrangement 77-libpcre.test uses. runner_t=1000 tmp=${TMPDIR:-/tmp}/bst-nghttp2.$$ mkdir -p "$tmp" 2>/dev/null || tmp=/tmp # ----------------------------------------------------------- what shipped ---- # -dev and -staticdev are the whole library: the arm is static-only, so the plain # nghttp2 package is contentless and is not installed at all (it exists only to # depend on the proxy tooling, which is a python3 script this image cannot run -- # see the bbappend). check_rc nghttp2/hdr 0 test -s "$hdr" check_rc nghttp2/ver-hdr 0 test -s "$verhdr" check_rc nghttp2/ar 0 test -s "$lib" check_rc nghttp2/no-so 1 test -e /usr/lib/libnghttp2.so # A pkg-config file DOES ship here, and it is named for the library rather than # the package: libnghttp2.pc, not nghttp2.pc. Verified against a real install of # this version rather than inferred from the recipe name -- asserting the wrong # one would be a red on a correct port. (80-libmpc.test asserts the ABSENCE of # mpc.pc for the same reason, in the other direction.) check_rc nghttp2/pc 0 test -s "$pc" check_rc nghttp2/no-pc-misnamed 1 test -e /usr/lib/pkgconfig/nghttp2.pc # The cmake package config, which is the other half of what a consumer links # against and travels in -dev with the headers. check_rc nghttp2/cmake-targets 0 test -s /usr/lib/cmake/nghttp2/nghttp2-targets.cmake # WHAT DELIBERATELY DID NOT SHIP. The recipe's own ENABLE_APP=OFF means nghttpx # and h2load are never built, and nghttp2-proxy -- one python3 script -- is left # out of the image because this image has no python3 to run it. Asserted so that # either arriving is a visible decision instead of a silent addition. check_rc nghttp2/no-nghttpx 1 test -e /usr/bin/nghttpx check_rc nghttp2/no-h2load 1 test -e /usr/bin/h2load check_rc nghttp2/no-ocsp-script 1 test -e /usr/share/nghttp2/fetch-ocsp-response # The ptest payload the bbappend stages. check_rc nghttp2/ptest-dir 0 test -d "$ptestdir" check_rc nghttp2/ptest-script 0 test -x "$ptestdir/run-ptest" check_rc nghttp2/ptest-progs 0 test -d "$ptestdir/progs" # Counted by glob expansion rather than `ls | wc -l`, which would fork twice. The # bbappend derives this set from cmake's generated add_test() declarations and # bbfatals on a missing binary, so a disagreement here means something was lost # after do_install_ptest. set -- "$ptestdir"/progs/* check_eq nghttp2/prog-count "$want_progs" "$#" # ------------------------------------------------------- run it, once --------- # The harness is preferred wherever it exists, because this ticket closes on the # suite run UNDER ptest-runner -- its discovery and its tally are part of what is # asserted. The fallback runs the identical script directly and SKIPS only the # cases that are about the harness itself; they have no subject on an image that # ships no ptest-runner. out=$tmp/runner.out if [ -x "$runner" ]; then bst_ok nghttp2/ptest-runner-present "$runner" -t "$runner_t" nghttp2 > "$out" 2>&1 rc=$? check_eq nghttp2/ptest-runner-rc 0 "$rc" begin=; end=; rerr= while read -r k v; do case "$k" in BEGIN:) begin=$v ;; END:) end=$v ;; ERROR:) rerr="$v" ;; esac done < "$out" check_eq nghttp2/runner-begin "$ptestdir" "$begin" check_eq nghttp2/runner-end "$ptestdir" "$end" check_eq nghttp2/runner-no-error "" "$rerr" else bst_skip nghttp2/ptest-runner-present "this image ships no ptest-runner" bst_skip nghttp2/ptest-runner-rc "no ptest-runner to run" for c in runner-begin runner-end runner-no-error; do bst_skip "nghttp2/$c" "harness cases have no subject without ptest-runner" done ( cd "$ptestdir" && sh ./run-ptest ) > "$out" 2>&1 fi # ------------------------------------- one case per upstream test case -------- # A single `while read` over the capture: no fork per case, and every case # upstream declared gets its own BST case so a red names the entry point that # broke rather than just the programme it lived in. # # The INFO: line run-ptest emits per programme carries that programme's own # accounting -- what it listed, what it reported, and what munit's summary line # said -- and the four checks after the loop compare them. They are separate # assertions from the per-case ones because they fail differently: a red above is # one broken entry point, whereas a disagreement below means cases never ran at # all (a truncated capture, a harness timeout, a programme that died mid-suite). # # The seed each programme chose is NOT asserted on -- it is different every run by # design -- but run-ptest prints it on the same INFO: line, so it travels in the # captured transcript and a red stays reproducible with `main --seed `. npass=0 nfail=0 nskip=0 nprog=0 agree_listed=0 agree_munit=0 while read -r verdict name f3 f4 f5 f6 f7 f8 f9 f10 _rest; do case "$verdict" in PASS:) bst_ok "nghttp2/$name"; npass=$((npass + 1)) ;; FAIL:) bst_notok "nghttp2/$name" "upstream test case failed"; nfail=$((nfail + 1)) ;; SKIP:) bst_skip "nghttp2/$name" "reported skip by munit"; nskip=$((nskip + 1)) ;; INFO:) # INFO: nghttp2-ptest prog=P listed=L reported=R pass=P fail=F skip=S msucc=M mtotal=T seed=X [ "$name" = "nghttp2-ptest" ] || continue nprog=$((nprog + 1)) l=${f4#listed=}; r=${f5#reported=} p=${f6#pass=}; fl=${f7#fail=} ms=${f9#msucc=}; mt=${f10#mtotal=} [ "$l" = "$r" ] && agree_listed=$((agree_listed + 1)) # munit's own tally: ` of `, where tests_run counts # successes + failures + errors and EXCLUDES skips -- so the comparison is # against pass+fail, not against everything reported. if [ "$p" = "$ms" ] && [ "$((p + fl))" = "$mt" ]; then agree_munit=$((agree_munit + 1)) fi ;; esac done < "$out" # Every programme reported, and each agreed with its own --list and with munit's # summary line. A programme that died before printing its INFO: line fails the # first of these. check_eq nghttp2/info-lines "$want_progs" "$nprog" check_eq nghttp2/listed-eq-run "$want_progs" "$agree_listed" check_eq nghttp2/munit-tally "$want_progs" "$agree_munit" # The pinned totals. Without these, a run that produced three PASS lines and died # would read as three green cases and nothing else. check_eq nghttp2/suite-total "$want_total" "$((npass + nfail + nskip))" check_eq nghttp2/suite-failures 0 "$nfail" rm -rf "$tmp"