# BST-TIMEOUT: 300 # measured 66 s on target (104 execs, ~0.63 s apiece); 300 is # # ~4.5x that, and the runner's own 60 s default would trip it. # # NOT the ~520 s first predicted from libmpc's 4.9 s/exec: a # # 5.3 MB module instantiates far faster than that suite's 33 MB # # of test binaries, so per-exec cost tracks module size. See below. . "$BST_LIB" # libsolv 0.7.28 -- the SAT-based package dependency solver behind libzypp, dnf and # zypper: it reads repository metadata into a compact pool and answers # install/erase/update/distupgrade requests with a provably correct transaction. # Depends on expat, zlib and zstd, all already on this image. # See libsolv_%.bbappend for what the port adds and why. # # --------------------------------------------------------------------------- # WHAT THIS SUITE IS, AND WHY IT IS NOT A PROBE # # This ticket is held to Epic BRINTOS-642's stricter bar: it closes on the # PACKAGE'S OWN UPSTREAM SUITE. libsolv ships one -- 104 cases under # test/testcases/, each a text file declaring repositories, a job and the expected # transaction inline -- and test/CMakeLists.txt drives them from ctest through # test/runtestcases.sh. The bbappend stages that corpus whole and run-ptest is # semantically that script, so what runs here is upstream's suite and not our # reading of it. # # That matters more for a solver than for most libraries. What is being asserted is # not "the code did not crash" but "the SAT engine reached the RIGHT ANSWER" -- and # the corpus is organised by the solver behaviours that are hard to get right and # easy to break silently: choicerules, cleandeps, distupgrade, multiversion, # lockstep, forcebest, weak dependencies and their exclusion, complex (boolean) # dependencies, namespace providers, repository priorities, and yum-style obsoletes. # Nobody writing a probe from the outside would have derived that list. # # --------------------------------------------------------------------------- # WHY EVERY ONE OF THESE IS EXPECTED TO PASS, WITH NO ARM-DEPENDENT ROW # # A libsolv testcase is pure computation over data carried inside the case file: # no repository is fetched, no package is installed, no network peer, no device # node, no TTY, and no clock. The expected transaction is written into the same # file, so the oracle travels with the input. Dependency solving is integer and # string arithmetic over a pool built from that text -- it is not a function of # word size, endianness, or libc beyond malloc and qsort. # # So the pass criterion is flat: 104 run, 104 pass, 0 skip. A red here is a real # defect in the port, the arm, or the solver beneath it -- never a platform # difference to be explained away. The measured native reference on x86-64, built # from the same SRCREV with this arm's own cmake switches, is 104/104/0. # # THE ONE THING THAT IS NOT PURE COMPUTATION. testcase_read() resolves a case's # EXTERNAL repository files relative to the directory of the .t that named them # (ext/testcase.c:2172-2182, :2275). Only evrcmp/testevr.t uses that path, reading # system.repo and conflicts.repo from beside itself. It is therefore the one case # whose result depends on the payload's directory structure rather than on the # solver, which is why the two .repo files are asserted separately below: if this # suite ever goes red at t-evrcmp-testevr alone, read it as a packaging finding, # not a solver one. # # NO WRITABLE WORKING DIRECTORY IS ASSERTED OR NEEDED. testsolv writes only under # its -T option, which run-ptest does not pass; the whole corpus was measured # passing with the ptest tree read-only, which is the deployed rootfs's condition. # # --------------------------------------------------------------------------- # SPAWN BUDGET IS THE CONSTRAINT, WHICH IS WHY THE HARNESS RUNS ONCE # # 104 cases is 104 fresh wasm module instantiations of testsolv. The whole corpus # measures 0.09 s natively and 66 s here, so the instantiations alone are three # orders of magnitude above the solving they carry. The file therefore runs # ptest-runner ONCE, reads back the PASS:/FAIL:/SKIP: lines it collected, and # reports from a fork-free `while read` loop -- printf and `test` are ash builtins, # and the counts below are glob expansions rather than `ls | wc -l`. # # ~0.63 s per exec here against libmpc's measured 4.9 s is the one number worth # carrying to the next port of this shape: the two suites differ by ~8x per spawn # and by ~6x in module size (5.3 MB of tools here, 33 MB of test binaries there), # so a bound extrapolated from another package's per-exec figure will be wrong in # whichever direction the module sizes differ. Measure, then declare. ptestdir=/usr/lib/libsolv/ptest runner=/usr/bin/ptest-runner driver=/usr/bin/testsolv # Upstream's own corpus, from the 0.7.28 tag the recipe pins # (SRCREV c8dbb3a77c86600ce09d4f80a504cf4e78a3c359): 104 .t cases in 27 # directories, plus the 2 .repo files evrcmp/testevr.t reads from beside itself. # The bbappend bbfatals if packaging stages a different number than the source # tree holds, so these three can only disagree with the recipe if the tarball # itself moved -- which is then a visible decision here rather than a silently # shorter suite. want_cases=104 want_dirs=27 want_repos=2 # 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 and 80-libmpc.test use. runner_t=240 tmp=${TMPDIR:-/tmp}/bst-libsolv.$$ mkdir -p "$tmp" 2>/dev/null || tmp=/tmp # ----------------------------------------------------------- what shipped ---- # The library half. libsolv is static-only on this arm, so the two archives ARE # the library; the headers live under a solv/ subdirectory, not at the top of # ${includedir}. check_rc libsolv/hdr-pool 0 test -s /usr/include/solv/pool.h check_rc libsolv/hdr-solver 0 test -s /usr/include/solv/solver.h check_rc libsolv/ar 0 test -s /usr/lib/libsolv.a check_rc libsolv/ar-ext 0 test -s /usr/lib/libsolvext.a check_rc libsolv/no-so 1 test -e /usr/lib/libsolv.so check_rc libsolv/no-so-ext 1 test -e /usr/lib/libsolvext.so # TWO pkg-config FILES ARE ASSERTED PRESENT, and that is the opposite of the call # 80-libmpc.test had to make. mpc ships none, so that suite asserts absence; # libsolv ships libsolv.pc and libsolvext.pc from libsolv.pc.in / libsolvext.pc.in # at the top of the tree, verified against a real install of this same SRCREV in # this same static configuration. Neither file was assumed from the neighbour. check_rc libsolv/pc 0 test -s /usr/lib/pkgconfig/libsolv.pc check_rc libsolv/pc-ext 0 test -s /usr/lib/pkgconfig/libsolvext.pc # The tools half -- and testsolv in particular, because it is the suite's driver. # It is asserted here as a SHIPPED BINARY rather than taken for granted by # run-ptest: this is the case that distinguishes "the tool is missing from the # image" from "the tool ran and got the wrong answer", which the ptest tally # below cannot tell apart on its own. check_rc libsolv/bin-testsolv 0 test -x "$driver" check_rc libsolv/bin-dumpsolv 0 test -x /usr/bin/dumpsolv check_rc libsolv/bin-mergesolv 0 test -x /usr/bin/mergesolv check_rc libsolv/bin-repo2solv 0 test -x /usr/bin/repo2solv check_rc libsolv/bin-installcheck 0 test -x /usr/bin/installcheck # The cheapest end-to-end statement that the wasm module instantiates, links # against both archives and reaches main -- independent of any test case. # # `-h` AND NOT A BARE INVOCATION: testsolv distinguishes the two, and only one of # them is a success. tools/testsolv.c:233 reaches usage(0) from -h, while :264 # reaches usage(1) when no testcase was given -- both print the same line, so a # bare `$driver` prints exactly what is wanted here and still exits 1. check_out # asserts rc 0 as well as the substring, so writing it the obvious way scores a # working driver as broken. Measured, not read: rc(-h)=0, rc(no args)=1. check_out libsolv/driver-runs "Usage: testsolv" "$driver" -h # ------------------------------------------------------ the ptest payload ---- check_rc libsolv/ptest-dir 0 test -d "$ptestdir" check_rc libsolv/ptest-script 0 test -x "$ptestdir/run-ptest" check_rc libsolv/ptest-corpus 0 test -d "$ptestdir/testcases" # Counted by glob expansion rather than `ls | wc -l`, which would fork twice per # count. A short count is the failure this asserts against: the bbappend bbfatals # on a staged count that disagrees with the source tree, so a disagreement HERE # means something was lost after do_install_ptest. set -- "$ptestdir"/testcases/*/*.t check_eq libsolv/case-count "$want_cases" "$#" set -- "$ptestdir"/testcases/*/ check_eq libsolv/dir-count "$want_dirs" "$#" # The external repository files, asserted by name as well as by count: they are # the payload's one structural dependency (see the header), and the count alone # would not say they landed in the directory that needs them. set -- "$ptestdir"/testcases/*/*.repo check_eq libsolv/repo-count "$want_repos" "$#" check_rc libsolv/repo-system 0 test -s "$ptestdir/testcases/evrcmp/system.repo" check_rc libsolv/repo-conflicts 0 test -s "$ptestdir/testcases/evrcmp/conflicts.repo" # ------------------------------------------------------- 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 libsolv/ptest-runner-present "$runner" -t "$runner_t" libsolv > "$out" 2>&1 rc=$? check_eq libsolv/ptest-runner-rc 0 "$rc" # ptest-runner's own framing, read back from the same capture. 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 libsolv/runner-begin "$ptestdir" "$begin" check_eq libsolv/runner-end "$ptestdir" "$end" check_eq libsolv/runner-no-error "" "$rerr" else bst_skip libsolv/ptest-runner-present "this image ships no ptest-runner" bst_skip libsolv/ptest-runner-rc "no ptest-runner to run" for c in runner-begin runner-end runner-no-error; do bst_skip "libsolv/$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 # ships gets its own BST case so a red names the solver behaviour that broke # (t-cleandeps-*, t-choicerules-*, t-distupgrade-*) rather than just the suite. npass=0 nfail=0 nskip=0 while read -r verdict name _rest; do case "$verdict" in PASS:) bst_ok "libsolv/t-$name"; npass=$((npass + 1)) ;; FAIL:) bst_notok "libsolv/t-$name" "upstream test case failed"; nfail=$((nfail + 1)) ;; # testsolv exits 77 for a case needing a solver feature this build lacks. The # reference build of this SRCREV with this arm's cmake switches skips NOTHING, # so a skip appearing here is a real finding about the port's configuration -- # it is reported as a skip rather than a pass so it cannot be mistaken for one, # and the tally below still counts it toward the total. SKIP:) bst_skip "libsolv/t-$name" "testsolv reported a missing solver feature"; nskip=$((nskip + 1)) ;; esac done < "$out" # The tally is asserted separately from the individual cases, because the two fail # differently: a red above is one broken solver behaviour, whereas a short total # means cases never ran at all -- a truncated capture, a harness timeout, or a # driver that could not start. Without this, a run that produced three PASS lines # and died would read as three green cases and nothing else. check_eq libsolv/suite-total "$want_cases" "$((npass + nfail + nskip))" check_eq libsolv/suite-failures 0 "$nfail" # Asserted separately from the failure count, because a skip is not a failure and # would not show up in the line above -- but on this build it is not an expected # outcome either, and a corpus that quietly began skipping half its cases would # otherwise still read green. check_eq libsolv/suite-skips 0 "$nskip" rm -rf "$tmp"