. "$BST_LIB" # BST-TIMEOUT: 300 # NOT MEASURED ON TARGET YET. One probe run plus ~130 shell # extractions -- the shape of 57-libxfixes.test, which # carries the same 300 for ~118 of them. Replace this note # with a measured elapsed the first time the suite runs on # target. # libXtst 1.2.4 -- the client half of the XTEST and RECORD extensions (poky # recipes-graphics/xorg-lib). See libxtst_%.bbappend for what the port adds and # why. # # --------------------------------------------------------------------------- # NOTHING HERE HAS RUN ON A TARGET YET # # Every expectation below is DERIVED FROM THE SOURCE of libXtst 1.2.4, from the # staged xorgproto headers, and -- for groups R and D -- from a reference run of # this same probe against x86-64 shared libXtst/libXext/libX11. It was written # in a phase that builds at recipe scope only and never boots an image, so no # value in it is a finding: they are predictions, and the first on-target run is # what turns them into results. Where a red appears, read it as this file having # been wrong until the case is checked against the source again. # # The reference run is worth naming precisely, because it did NOT cover # everything. It confirmed groups V (constants), R (allocation) and D (the six # connectionless entry points) exactly as written; group A's sizes and offsets # differ there because that host is LP64 and this arm is ILP32, so A is derived # rather than confirmed; and groups L, X, N and I could not run at all on it -- # see the next section. # # --------------------------------------------------------------------------- # NEITHER EXTENSION CAN REACH A SERVER HERE, AND THAT IS WHAT IS MEASURED # # XTEST synthesises input events; RECORD asks the server to intercept protocol. # Both are server-side extensions by definition and this image has no X server # -- 57-libx11 (test plan section 631) measures XOpenDisplay returning NULL, in # four forms, and this suite does not repeat it. So twenty-three of libXtst's # twenty-nine entry points cannot complete here. They are not untested; they are # unreachable past a guard, by construction. # # What IS reachable is three separate things: # # SIX ENTRY POINTS NEVER TOUCH A CONNECTION (group D, and R for two of them): # XRecordAllocRange, XRecordFreeState, XRecordIdBaseMask, # XTestSetGContextOfGC, XTestSetVisualIDOfVisual and XTestDiscard are executed # exactly as a consumer would execute them. # # THE GUARD EVERY OTHER ENTRY POINT PASSES FIRST, and there are TWO of them # (groups X and N): # # XextCheckExtension via XTestCheckExtension / XTestICheckExtension / # XRecordCheckExtension -- calls XMissingExtension and # returns the family's documented value # the `else' arm XTestQueryExtension alone -- returns False and calls # nothing at all # # The probe installs an extension-error handler, so "returned 0" and "returned # 0 having raised the missing-extension error" are DIFFERENT measurements. That # is why the honest-failure arm here is not one undifferentiated "no display" # case. # # THE INITIALISATION PATH (group I): what libXtst's two find_display # generators ask Xlib, in what order, and what they leave on the Display. # # HOW THE GUARDS ARE REACHED. libXtst's find_display is static, so its extension # list cannot be seeded the way libXfixes' can. The reachable end is the other # one: the only thing between find_display and a wire is XQueryExtension, which # XInitExtension calls first and returns NULL on. The probe DEFINES # XQueryExtension, and in a static link that definition is taken from the # probe's object while libX11's QuExt.o -- which holds that function and nothing # else -- is never pulled. The stub's answer is the truthful one for this image: # no XTEST, no RECORD, no XInputExtension. What it does not reproduce is Xlib's # own round trip, which on an image with no display has no answer to reproduce. # The guards below are libXtst's, executed; the shortening is Xlib's, stated. # # --------------------------------------------------------------------------- # THE CASE EVERYTHING IN X, N AND I RESTS ON IS L01 -- AND WHY IT IS ALSO A # SAFETY PROPERTY # # If that link-order argument were wrong, the real XQueryExtension would run # over a Display with no socket and the fault would take the guest's console # down with it -- on an image several tickets share. It cannot. Every path into # Xlib's request machinery begins with LockDisplay; the probe supplies the # Display's lock_fns; and before each guarded call it arms a trap with the # number of stub answers that must have arrived before any lock is legitimate. # A lock that comes too early prints `TRAP ...', prints PROBE-ABORT instead of # PROBE-END, and exits 0. # # That is not a theory. It fires, exactly so, on the x86-64 shared-library # reference build, where libXtst's own call to XQueryExtension binds to the # probe but libX11's internal one does not (Debian builds libX11 with # -Bsymbolic-functions). So a red on L01 with `no-trap' red beside it and every # X/N/I case absent is the method failing SAFELY, not the library failing -- # and libxtst/probe-complete says so in the same run. # # The same trap catches the other failure worth catching: a guard that stopped # firing, whose call would reach LockDisplay with no stub answer in between. PROBE=${BST_LIBXTST_PROBE:-/usr/libexec/libxtst-tests/libxtst-probe} ARCHIVE=/usr/lib/libXtst.a PCFILE=/usr/lib/pkgconfig/xtst.pc HDR_TEST=/usr/include/X11/extensions/XTest.h HDR_REC=/usr/include/X11/extensions/record.h # The version the recipe pins. Asserted rather than read back, so a recipe # bumped without revisiting this suite is a red here instead of a silent change # of subject -- every expectation below is derived from THIS version's source. WANT_VERSION=1.2.4 # The first BST result line of a suite is dropped by the guest console # (brintos/linux#96), consistently and every run. This case asserts something # already true so that what is lost is a line that costs nothing; remove it when # #96 lands. if [ -f "$ARCHIVE" ]; then bst_ok libxtst/suite-canary else bst_notok libxtst/suite-canary "$ARCHIVE is not a file"; fi if [ ! -f "$ARCHIVE" ]; then bst_skip libxtst/present "libxtst not installed on this image" exit 0 fi bst_ok libxtst/present # --- the package is whole ----------------------------------------------------- check libxtst/staticlib test -s "$ARCHIVE" check libxtst/pkgconfig test -s "$PCFILE" check libxtst/hdr-xtest test -s "$HDR_TEST" check libxtst/hdr-record test -s "$HDR_REC" # --disable-shared is image-wide, so the archive is the whole library # deliverable. A .so here would mean that stopped being true. if [ -e /usr/lib/libXtst.so ] || [ -e /usr/lib/libXtst.so.6 ]; then bst_notok libxtst/no-shared "a shared libXtst is installed on a static-only distro" else bst_ok libxtst/no-shared fi pcver=$(sed -n 's/^Version: *//p' "$PCFILE" 2>/dev/null | head -1) check_eq libxtst/pkgconfig-version "$WANT_VERSION" "$pcver" # xtst.pc must name what a consumer resolves through it. On a static-only distro # a missing entry is not a warning -- it is a link that fails in the consumer, # because there is no shared object to carry the dependency. Upstream splits # them: recordproto is public (a consumer compiles against its headers through # this file) and x11, xext, xextproto and xi are private (needed to link, not to # compile). Both halves matter here, since every link is static. pcpub=$(sed -n 's/^Requires: *//p' "$PCFILE" 2>/dev/null | head -1) case "$pcpub" in *recordproto*) bst_ok libxtst/pkgconfig-requires-recordproto ;; *) bst_notok libxtst/pkgconfig-requires-recordproto "xtst.pc Requires does not name recordproto: '$pcpub'" ;; esac pcpriv=$(sed -n 's/^Requires\.private: *//p' "$PCFILE" 2>/dev/null | head -1) for want in x11 xext xextproto xi; do case " $pcpriv " in *" $want "*) bst_ok "libxtst/pkgconfig-requires-$want" ;; *) bst_notok "libxtst/pkgconfig-requires-$want" "xtst.pc Requires.private does not name $want: '$pcpriv'" ;; esac done # --- the premise: there is no X server on this image -------------------------- # Stated here rather than executed, because 57-libx11 owns the executed form and # runs it last for a reason. These two are free and they fix what the rest of # this file means: with a display, groups X and N would be measuring something # else entirely. if [ -z "${DISPLAY:-}" ]; then bst_ok libxtst/no-display else bst_notok libxtst/no-display "DISPLAY is set to '$DISPLAY' on an image with no X server"; fi if [ ! -d /tmp/.X11-unix ]; then bst_ok libxtst/no-x-socket-dir else bst_notok libxtst/no-x-socket-dir "/tmp/.X11-unix exists"; fi # The archive carries the API. grep rather than nm: the image ships no binutils # nm, and the names are present as plain bytes. -a where the grep supports it -- # on this arm the archive members are LLVM IR bitcode (ThinLTO), so a grep that # suppresses matches in a file containing NULs reports nothing; GNU grep needs # -a, busybox grep as shipped does not. Probing keeps this measuring libXtst # rather than measuring the image's grep. if echo x | grep -aq x 2>/dev/null; then _grepq="grep -aq"; else _grepq="grep -q"; fi # Both source files represented, and within each one the calls a consumer of # this library actually reaches for, so a dropped object is named rather than # merely counted. The probe's link is the exhaustive check; this is the part # that survives the probe being absent. for sym in XRecordAllocRange XRecordFreeState XRecordIdBaseMask \ XRecordQueryVersion XRecordCreateContext XRecordGetContext \ XRecordEnableContext XRecordEnableContextAsync XRecordFreeData \ XRecordProcessReplies XRecordFreeContext \ XTestQueryExtension XTestFakeKeyEvent XTestFakeButtonEvent \ XTestFakeMotionEvent XTestFakeDeviceKeyEvent XTestGrabControl \ XTestDiscard XTestSetGContextOfGC XTestSetVisualIDOfVisual; do if $_grepq "$sym" "$ARCHIVE" 2>/dev/null; then bst_ok "libxtst/sym-$sym" else bst_notok "libxtst/sym-$sym" "$sym absent from $ARCHIVE" fi done # The installed headers must declare what a consumer compiles against. record.h # carries the structures a caller BUILDS (a range, a state, an intercepted # datum) as well as the calls, which is why the type names are checked beside # the function names. for decl in XTestQueryExtension XTestFakeKeyEvent XTestFakeDeviceKeyEvent \ XTestGrabControl XTestDiscard XTestSetGContextOfGC; do if grep -q "$decl" "$HDR_TEST" 2>/dev/null; then bst_ok "libxtst/hdr-decl-$decl" else bst_notok "libxtst/hdr-decl-$decl" "$decl is not declared in $HDR_TEST" fi done for decl in XRecordAllocRange XRecordFreeState XRecordCreateContext \ XRecordEnableContextAsync XRecordRange XRecordExtRange \ XRecordState XRecordClientInfo XRecordInterceptData \ XRecordClientSpec XRecordContext XRecordInterceptProc; do if grep -q "$decl" "$HDR_REC" 2>/dev/null; then bst_ok "libxtst/hdr-decl-$decl" else bst_notok "libxtst/hdr-decl-$decl" "$decl is not declared in $HDR_REC" fi done # --- the probe ---------------------------------------------------------------- if [ ! -x "$PROBE" ]; then bst_skip libxtst/probe-runs "$PROBE absent from the image" exit 0 fi pout=${TMPDIR:-/tmp}/bst-libxtst-out.$$ "$PROBE" > "$pout" 2>&1 prc=$? if [ "$prc" -eq 0 ]; then bst_ok libxtst/probe-runs elif bst_execfail "$(head -c 200 "$pout" 2>/dev/null)"; then bst_unrun libxtst/probe-runs "$(head -c 200 "$pout" 2>/dev/null)" rm -f "$pout" exit 0 else bst_notok libxtst/probe-runs "probe exited $prc: $(_bst_1line "$(head -c 300 "$pout")")" fi if grep -q '^PROBE-END$' "$pout" 2>/dev/null; then bst_ok libxtst/probe-complete else bst_notok libxtst/probe-complete "probe output has no PROBE-END terminator (last line: $(tail -1 "$pout" 2>/dev/null))" fi # The trap described at the top of this file. A TRAP line means the probe # stopped ITSELF rather than faulting, so this case and probe-complete going red # together, with X/N/I absent, is the method failing safely. if grep -q '^TRAP ' "$pout" 2>/dev/null; then bst_notok libxtst/no-trap "the probe trapped: $(grep -m1 '^TRAP ' "$pout")" else bst_ok libxtst/no-trap fi # val -- the probe's value for one case, empty when the probe stopped # first. Matches on the ID in field 1 rather than taking the line by position, # because the probe's output is captured with 2>&1 and a platform diagnostic # could land in the middle of it. val() { awk -v k="$1" '$1==k { $1=""; sub(/^ /,""); print; exit }' "$pout"; } # want -- score one probe value against a derived answer. # A missing value is reported as the probe having stopped early rather than as a # mismatch against '', which is a different fault and localises to a different # line. want() { _got=$(val "$1") if [ -z "$_got" ]; then bst_notok "libxtst/$2" "no value on target (probe stopped before $1); want='$3'" elif [ "$_got" = "$3" ]; then bst_ok "libxtst/$2" else bst_notok "libxtst/$2" "want:'$3' got:'$_got'" fi } # --- V: the constants the archive and the staged protocol headers must agree on # V16..V18 are the client-spec triple the ticket names -- the three magic # XRecordClientSpec values a caller passes instead of a resource id. V12..V15, # V19 and V20 are the six protocol-element categories an intercept callback # switches on, which is the other half of the same API. want V01 record-name RECORD want V02 record-major 1 want V03 record-minor 13 want V04 record-lowest-major 1 want V05 record-lowest-minor 12 want V06 bad-context 0 want V07 num-errors 1 want V08 num-events 0 want V09 from-server-time 1 want V10 from-client-time 2 want V11 from-client-sequence 4 want V12 cat-from-server 0 want V13 cat-from-client 1 want V14 cat-client-started 2 want V15 cat-client-died 3 want V16 spec-current-clients 1 want V17 spec-future-clients 2 want V18 spec-all-clients 3 want V19 cat-start-of-data 4 want V20 cat-end-of-data 5 want V21 xtest-name XTEST want V22 xtest-major 2 want V23 xtest-minor 2 want V24 xtest-num-events 0 want V25 xtest-num-errors 0 want V26 xtest-current-cursor 1 # --- A: the in-memory layout this arm hands the packages above it ------------- # ILP32 against the LP64 host these declarations are usually read on, which is # the whole reason to print them -- and the one group the x86-64 reference run # could NOT confirm, since it measured that host's LP64 answers (8/24/24/48/16/ # 40 where this arm should say 4/12/16/28/12/24). Derived from record.h with # unsigned long, XID, Time and every pointer at 4 bytes: # # XRecordRange8 two unsigned char = 2 # XRecordRange16 two unsigned short = 4 # XRecordExtRange Range8 at 0, Range16 at 2, alignment 2 = 6 # XRecordRange 2,2,6,6,2,2,2 then two Bool (int) aligned to 4 = 32 # XRecordClientInfo spec + nranges + ranges = 12 # XRecordState enabled, datum_flags, nclients, client_info = 16 # XRecordInterceptData XID, Time, ulong, int, Bool, ptr, ulong = 28 # # The XRecordRange offsets are the ticket's "range structure's field layout". # They are not decoration: SendRange in the archive copies all nine members onto # the wire field by field, and WireToLibRange copies them back, so an offset # this suite and that archive disagreed about would corrupt a recording rather # than fail to build. want A01 sizeof-pointer 4 want A02 sizeof-xid 4 want A03 sizeof-ulong 4 want A04 sizeof-client-spec 4 want A05 sizeof-context 4 want A06 sizeof-range8 2 want A07 sizeof-range16 4 want A08 sizeof-ext-range 6 want A09 sizeof-range 32 want A10 sizeof-client-info 12 want A11 sizeof-state 16 want A12 sizeof-intercept 28 want A13 off-core-requests 0 want A14 off-core-replies 2 want A15 off-ext-requests 4 want A16 off-ext-replies 10 want A17 off-delivered-events 16 want A18 off-device-events 18 want A19 off-errors 20 want A20 off-client-started 24 want A21 off-client-died 28 want A22 off-ext-major 0 want A23 off-ext-minor 2 want A24 off-state-enabled 0 want A25 off-state-datum 4 want A26 off-state-nclients 8 want A27 off-state-clients 12 want A28 off-intercept-data 20 want A29 off-intercept-len 24 # --- C: the census ------------------------------------------------------------- # The probe names every public entry point by address, so the recipe's link is # what proves the archive still contains each one. This case is the floor on the # table itself: a probe cut down in some future change would keep passing while # quietly proving less. want C01 census-entry-points 29 cens=$(grep -c '^CENSUS ' "$pout" 2>/dev/null) check_eq libxtst/census-lines 29 "$cens" unres=$(awk '$1=="CENSUS" && $3!="resolved" { print $2 }' "$pout" | tr '\n' ' ') if [ -z "$unres" ]; then bst_ok libxtst/census-all-resolved else bst_notok libxtst/census-all-resolved "unresolved: $unres"; fi # --- R: the allocator contract, executed -------------------------------------- # R02..R11 are XRecordAllocRange returning a range zeroed in EVERY protocol # category -- Xcalloc, not Xmalloc -- which is what lets a caller set only the # categories it wants and leave the rest empty. R12 writes a distinct value into # each and reads it back. # # R13..R15 are XRecordFreeState over the three sizes of the SHAPE # XRecordGetContext allocates: an array of pointers into one contiguous client # block, and per client an array of pointers into one contiguous range block. # The assertion is that CONTROL RETURNED -- a walk that disagreed with that # shape would hand the C library a pointer it never allocated, and the probe # would end there rather than print 1. Confirmed on the x86-64 reference run. want R01 alloc-range-nonnull nonnull want R02 alloc-zero-core-requests 1 want R03 alloc-zero-core-replies 1 want R04 alloc-zero-ext-req-major 1 want R05 alloc-zero-ext-req-minor 1 want R06 alloc-zero-ext-rep-major 1 want R07 alloc-zero-ext-rep-minor 1 want R08 alloc-zero-delivered 1 want R09 alloc-zero-device 1 want R10 alloc-zero-errors 1 want R11 alloc-zero-client-flags 1 want R12 range-roundtrip 1 want R13 free-state-no-clients 1 want R14 free-state-one-client 1 want R15 free-state-two-clients 1 # --- D: the six entry points that never reach a connection -------------------- # D01..D03: XRecordIdBaseMask is `0x1fffffff & ~dpy->resource_mask' -- the mask a # client ANDs a recorded XID with to find which connection made it. 0 gives the # whole 29-bit field; a real 21-bit mask gives 0x1fe00000; an all-ones mask # gives nothing. The three answers are the same on ILP32 and LP64, which is why # the reference run could confirm them. # # D07..D14: XTestDiscard, both arms. The probe queues three well-formed xReq # headers of 1, 2 and 3 words and the walk steps by each request's OWN length # field, so D11 -- exactly three off the sequence counter -- is what says the # walk read those lengths rather than assuming a size. D14 reads back # libXtst's own static _dummy_request through the pointer the call left behind. # # D15/D16: the display lock. XTestDiscard is the only entry point in this # library that takes it here, and it must give it back. want D01 idbase-mask-zero 536870911 want D02 idbase-mask-21bit 534773760 want D03 idbase-mask-all 0 want D04 set-gcontext 44040199 want D05 gc-untouched 1 want D06 set-visualid 33 want D07 discard-empty 0 want D08 discard-empty-seq 100 want D09 discard-empty-bufptr 1 want D10 discard-queued 1 want D11 discard-queued-seq 97 want D12 discard-rewound 1 want D13 discard-last-req-moved 1 want D14 discard-dummy-request 1 want D15 lock-taken-twice 2 want D16 lock-given-back 2 # --- L: the method itself, before anything rests on it ------------------------ # L01 is printed only if the first guarded call came back at all; the trap # described at the top of this file is what stands between "it did not" and a # fault on a shared image. want L01 stub-is-the-one-xlib-calls 1 # --- X: the server has no XTEST ----------------------------------------------- # X01..X03 are XTestQueryExtension's OWN `else' arm: False, no missing-extension # error raised, and none of its four out-parameters written. X04 onward are # XextCheckExtension's arm, which is the other documented path: it raises the # error and returns the family's value. # # THE ERROR COUNTS ARE THE LOAD-BEARING PART. A guard compiled away would not # change a return value -- it would send the call to the wire. X05 is one error # for one call; X09 four for the four simple fake-input and grab calls; X11 four # for the four XInput-device calls, which reach the same first half of # XTestICheckExtension; X13 two for the two cursor comparisons. X14 is the sum # over the whole group, 11, which is every XTEST entry point that has a guard. want X01 no-ext-query-extension 0 want X02 query-extension-raises-nothing 0 want X03 query-extension-outs-untouched 1 want X04 no-ext-fake-key 0 want X05 fake-key-raises-error 1 want X06 error-names-xtest XTEST want X07 error-reason-is-missing 1 want X08 no-ext-simple-returns 4 want X09 simple-raise-four-errors 4 want X10 no-ext-device-returns 4 want X11 device-raise-four-errors 4 want X12 no-ext-cursor-compare 2 want X13 cursor-raise-two-errors 2 want X14 xtest-errors-total 11 # --- N: the server has no RECORD ---------------------------------------------- # A separate find_display, a separate extension name and separate return values, # so a regression that moved one family cannot hide behind the other. # # N06 is the one out-parameter contract in this half: XRecordGetContext writes # *state_return only AFTER LockDisplay, so a caller's sentinel must survive the # guard. That is upstream's ordering, asserted rather than assumed. # # N09 is nine: one each for XRecordQueryVersion and XRecordGetContext plus the # seven of N07 -- every RECORD entry point that has a guard. want N01 no-ext-query-version 0 want N02 query-version-raises-error 1 want N03 error-names-record RECORD want N04 version-outs-untouched 1 want N05 no-ext-get-context 0 want N06 get-context-state-untouched 1 want N07 no-ext-record-returns 7 want N08 record-raise-seven-errors 7 want N09 record-errors-total 9 # --- I: what the initialisation asked, and what it left behind ---------------- # I01/I02: three XQueryExtension calls in all, in a fixed order. # XInputExtension and XTEST come from the FIRST XTEST call -- # XTestQueryExtension's find_display, whose `data' argument is # get_xinput_base(dpy) and is therefore evaluated before XInitExtension runs # inside XextAddDisplay -- and RECORD from the first RECORD call. There is no # fourth, because both generators cache on extinfo->cur: every later call in # groups X and N went through that cache, which is why the count does not rise # with the number of calls made. # # I03..I05: with codes NULL, XextAddDisplay takes its XBUG-7955 arm and hangs # each family's close_display hook on a private Xlib extension slot of its own # (XAddExtension). Two families, two slots, two hooks. A family that silently # stopped registering close_display would leak its per-display cache at # XCloseDisplay, and this is where that would show. want I01 xquery-calls 3 want I02 xquery-order XInputExtension,XTEST,RECORD want I03 ext-number 2 want I04 ext-slots 2 want I05 close-display-hooks 2 # L02/L03: the display lock over the whole run, and SIX is the whole of it -- # not the two XTestDiscard alone. The probe's own header says which other calls # lock and why it wants them counted: XAddExtension and XESetCloseDisplay both # take the lock, both are reached on the no-extension arm, and both run AFTER # the stub has answered, which is what distinguishes them from a request path # that locks before anything asks about an extension. # # So the arithmetic is the suite's own, from three cases above that are already # green: # # D15 lock-taken-twice 2 XTestDiscard, the only library entry point # here that takes it # I04 ext-slots 2 one XAddExtension per family # I05 close-display-hooks 2 one XESetCloseDisplay per family # - # 6 # # Two families, XTEST and RECORD, so each of the two init calls happens twice. # The count is equal to the give-backs, which is the half an "it locked" # assertion misses: nothing here leaks the lock. want L02 lock-total 6 want L03 unlock-total 6 rm -f "$pout"