# BST-TIMEOUT: 300 # measured elapsed=62s cases=52 (local verify, 2026-08-22); # 62s is over the 60s default, so the marker is needed at all # # cim-schema-final 2.40.0 -- the DMTF CIM final schema, the released MOF class # definitions a CIM server and its providers compile against. There is no CIM # server on this image, so the deliverable IS the payload: this suite asserts the # payload is complete, internally consistent, and byte-identical to the same # recipe version installed on x86-64. It cannot assert that a CIM server accepts # the schema, and does not claim to. # # The realistic failure mode for a 1441-file data package is a PARTIAL unpack, so # completeness is asserted three independent ways: the file count and per-subtree # tallies off one find; the whole path+size inventory and every file's sha256 # against an x86-64 reference; and the schema's own manifest of itself -- the # 1440 `#pragma include` lines in cim_schema_2.40.0.mof, which must resolve # one-to-one onto the 1440 non-master files present. The third needs no reference # file at all, so it still fires if the reference and the payload were ever to # drift together. # # WRITTEN TO EXEC AS LITTLE AS POSSIBLE, AND THAT IS NOT A STYLE CHOICE. On this # arm a process's memory is not returned when it exits and /bin/sh alone is a # 16 MB wasm module, so the guest grows by tens of MB per exec -- the same cost # 99-poppler-data.test records. Every batch below does its whole job in ONE # program and hands back shell assignments. # # THE 1441 FILENAMES NEVER GO ON A COMMAND LINE. The guest's argument buffer # (__wasm32_args_buf) is 8192 bytes and naming every MOF costs 95410, and that # does not fail the exec -- the exec never returns and the whole suite is lost # with the guest (measured 2026-08-22 on this very suite, twice; the limit is # brintos/hardwarejs#15). So the one find below writes the relative paths to a # file and gawk opens them itself. Any future case that wants to walk the tree # must do the same: a `find`-substitution or a `"$V"/*/*.mof` glob wedges the # boot rather than erroring, which is the failure mode that reads as a flake. . "$BST_LIB" P=/usr/share/mof V=$P/cimv2.40.0 DOC=/usr/share/doc/cim-schema-2.40.0 EXPER=$P/cimv2.50.0 S=cim-schema-final D=$BST_DATA tmp=${TMPDIR:-/tmp} W=$tmp/bst-cim.$$ require gawk $S/gawk-present require sha256sum $S/sha256sum-present if [ -d "$P" ]; then bst_ok $S/root; else bst_notok $S/root "$P is not a directory"; return 2>/dev/null || exit 0 fi if [ -d "$V" ]; then bst_ok $S/version-dir; else bst_notok $S/version-dir "$V is not a directory"; return 2>/dev/null || exit 0 fi # ---------------------------------------------------------------- payload shape # ONE find over THIS VERSION'S tree and its licence directory -- deliberately NOT # over $P, which cim-schema-exper also populates: a walk of the shared parent # counts that schema's 1896 files as strays and its directories as ours, which is # how a co-installed pair breaks each other's suite rather than each other's # payload. The shared parent is asserted separately below. # %p is absolute because the two roots have # no common relative frame; gawk strips the prefix where it needs a relative path. find "$V" "$DOC" -printf '%y %m %s %p|%l\n' > "$W.ls" 2>/dev/null # An empty listing would leave the three zero-valued cases below reading green on # nothing at all, so say outright that the walk produced something. if [ -s "$W.ls" ]; then bst_ok $S/payload-walk; else bst_notok $S/payload-walk "find over $P and $DOC produced no output"; fi gawk -v ref="$D/cim-schema-final-inventory.txt" -v V="$V" -v P="$P" -v DOC="$DOC" \ -v filesout="$W.files" ' function q(k, v) { printf "%s='"'"'%s'"'"'\n", k, v } { split($0, a, "|"); link = a[2] ty = $1; mode = $2; sz = $3 path = $4; for (i = 5; i <= NF; i++) path = path " " $i # a space in a path sub(/\|.*$/, "", path) if (ty == "d") { dirs++; if (mode != "755") badmode++ } else if (ty == "l") { links++; tgt[path] = link } else if (ty == "f") { if (index(path, V "/") == 1) { rel = substr(path, length(V) + 2) n++; bytes += sz; if (sz == 0) empty++ live[rel] = sz print rel > filesout k = index(rel, "/") if (k == 0) top++; else st[substr(rel, 1, k - 1)]++ } else if (index(path, DOC "/") == 1) { docn++; docbytes += sz docrel[substr(path, length(DOC) + 2)] = sz } else { stray++; if (!strayex) strayex = path } if (mode != "644") badmode++ } } END { close(filesout) while ((getline l < ref) > 0) { if (l ~ /^#/) continue i = length(l); while (i > 0 && substr(l, i, 1) != " ") i-- rp = substr(l, 1, i - 1); rs = substr(l, i + 1) + 0 refn++ if (!(rp in live)) { diffs++; if (!ex) ex = "missing " rp } else if (live[rp] != rs) { diffs++; if (!ex) ex = rp " is " live[rp] " bytes, want " rs } seen[rp] = 1 } for (f in live) if (!(f in seen)) { diffs++; if (!ex) ex = "extra " f } for (s in st) q("CIM_ST_" toupper(s), st[s]) q("CIM_FILES", n + 0); q("CIM_BYTES", bytes + 0); q("CIM_EMPTY", empty + 0) q("CIM_TOP", top + 0); q("CIM_SUBTREES", length(st)) q("CIM_DIRS", dirs + 0); q("CIM_LINKS", links + 0); q("CIM_BADMODE", badmode + 0) q("CIM_STRAY", stray + 0); q("CIM_STRAY_EX", strayex) q("CIM_CURRENT_TGT", tgt[P "/cim-current"]) q("CIM_SCHEMA_TGT", tgt[V "/CIM_Schema.mof"]) q("CIM_DOCN", docn + 0); q("CIM_LICENSE_SZ", docrel["LICENSE"] + 0) q("CIM_INV_DIFFS", diffs + 0); q("CIM_INV_REF", refn + 0); q("CIM_INV_EX", ex) }' "$W.ls" > "$W.f1" . "$W.f1" check_eq $S/payload-files 1441 "$CIM_FILES" check_eq $S/payload-bytes 4130790 "$CIM_BYTES" check_eq $S/payload-empty 0 "$CIM_EMPTY" check_eq $S/payload-toplevel 3 "$CIM_TOP" check_eq $S/payload-subtrees 14 "$CIM_SUBTREES" # Each schema subtree by name with its file count -- a directory that exists and # is empty is the partial install `test -d` cannot see. check_eq $S/subtree-Application 139 "$CIM_ST_APPLICATION" check_eq $S/subtree-Core 175 "$CIM_ST_CORE" check_eq $S/subtree-Database 19 "$CIM_ST_DATABASE" check_eq $S/subtree-Device 296 "$CIM_ST_DEVICE" check_eq $S/subtree-Event 30 "$CIM_ST_EVENT" check_eq $S/subtree-IPsecPolicy 25 "$CIM_ST_IPSECPOLICY" check_eq $S/subtree-Interop 32 "$CIM_ST_INTEROP" check_eq $S/subtree-Metrics 21 "$CIM_ST_METRICS" check_eq $S/subtree-Network 277 "$CIM_ST_NETWORK" check_eq $S/subtree-Physical 46 "$CIM_ST_PHYSICAL" check_eq $S/subtree-Policy 56 "$CIM_ST_POLICY" check_eq $S/subtree-Support 61 "$CIM_ST_SUPPORT" check_eq $S/subtree-System 145 "$CIM_ST_SYSTEM" check_eq $S/subtree-User 116 "$CIM_ST_USER" # 16 = cimv2.40.0 + its 14 subtrees + the doc directory; every file 0644, every # directory 0755, and nothing installed outside the two trees the recipe names. check_eq $S/payload-dirs 16 "$CIM_DIRS" check_eq $S/payload-modes 0 "$CIM_BADMODE" check_eq $S/payload-stray 0 "$CIM_STRAY" # --------------------------------------------------------------- the symlinks # Both are created by do_install, not by the tarball, and both are the kind of # thing a rootfs packer can flatten into a copy or drop entirely. Only # CIM_Schema.mof lies inside the scoped walk above; cim-current sits at the shared # parent and is read directly. check_eq $S/symlink-count 1 "$CIM_LINKS" check_eq $S/cim-current-target cimv2.40.0 "$(readlink "$P/cim-current")" check_eq $S/CIM_Schema-target cim_schema_2.40.0.mof "$CIM_SCHEMA_TGT" # ------------------------------------------- the payload against the reference # cim-schema-final compiles nothing, so the wasm32 package and an x86-64 install # of the same recipe version must be the same bytes. The reference was produced # independently on x86-64 -- upstream release zip + the recipe's own do_install # transform -- not from this package. The path+size half came off the find above. check_eq $S/inventory-x86-64-ref 1441 "$CIM_INV_REF" if [ "${CIM_INV_DIFFS:-1}" = 0 ]; then bst_ok $S/inventory-x86-64; else bst_notok $S/inventory-x86-64 "$CIM_INV_DIFFS difference(s) vs the x86-64 reference; first: $CIM_INV_EX"; fi # and the same bytes, not merely the same sizes ( cd "$V" && grep -v '^#' "$D/cim-schema-final-sha256.txt" | sha256sum -c --quiet ) > "$W.sha" 2>&1 if [ -s "$W.sha" ]; then bst_notok $S/sha256-x86-64 "$(gawk 'END{print NR" mismatch(es)"}' "$W.sha"); first: $(gawk 'NR==1{print}' "$W.sha")" else bst_ok $S/sha256-x86-64 fi # ------------------------------------------ the schema's own manifest of itself # cim_schema_2.40.0.mof is a list of 1440 `#pragma include ("path")` lines, one # per class file. Every include must resolve onto a file that is present, and # every file except the master must be included exactly once -- so a partial # unpack fails here even if the reference manifests were absent. The same pass # reads every file's class declaration (the CIM convention is one class per file, # named for the file) and checks for the CR bytes do_install strips. gawk -v list="$W.files" -v V="$V" ' function q(k, v) { printf "%s='"'"'%s'"'"'\n", k, v } BEGIN { while ((getline rel < list) > 0) { if (rel == "") continue nfiles++; have[rel] = 1 base = rel; sub(/.*\//, "", base); sub(/\.mof$/, "", base) master = (rel == "cim_schema_2.40.0.mof") path = V "/" rel cls = "" while ((getline line < path) > 0) { if (index(line, "\r")) crlf[rel] = 1 if (master) { if (line ~ /^[ \t]*#pragma[ \t]+include/) { if (match(line, /\("[^"]+"\)/)) { inc_p = substr(line, RSTART + 2, RLENGTH - 4) if (inc_p in inc) dup++ inc[inc_p]++; ninc++ } else badinc++ continue } if (line ~ /^[ \t]*#pragma[ \t]+locale/) { nloc++; continue } } if (cls == "" && line ~ /^[ \t]*class[ \t]+[A-Za-z0-9_]+/) { match(line, /class[ \t]+[A-Za-z0-9_]+/) c = substr(line, RSTART + 5, RLENGTH - 5); gsub(/^[ \t]+/, "", c) cls = c; nclass++ if (c != base) { mism++; if (!mex) mex = rel " declares class " c } } } close(path) if (cls == "") { noclass++; nclist = nclist (nclist ? " " : "") rel } } close(list) for (inc_p in inc) if (!(inc_p in have)) { dangling++; if (!dex) dex = inc_p } for (f in have) if (!(f in inc) && f != "cim_schema_2.40.0.mof") { notinc++; if (!nex) nex = f } q("CIM_NFILES", nfiles + 0) q("CIM_INC", ninc + 0); q("CIM_INC_DISTINCT", length(inc)); q("CIM_INC_DUP", dup + 0) q("CIM_INC_BAD", badinc + 0); q("CIM_LOCALE", nloc + 0) q("CIM_DANGLING", dangling + 0); q("CIM_DANGLING_EX", dex) q("CIM_NOTINC", notinc + 0); q("CIM_NOTINC_EX", nex) q("CIM_CLASS", nclass + 0); q("CIM_CLASS_MISM", mism + 0); q("CIM_CLASS_MISM_EX", mex) q("CIM_NOCLASS", noclass + 0); q("CIM_NOCLASS_LIST", nclist) q("CIM_CRLF", length(crlf)) }' > "$W.f2" . "$W.f2" # The parse pass has to see exactly the regular files the find did, or every # count below is short. CIM_Schema.mof is a symlink, so it is not in the list and # is not double-counted here; the symlink cases above are what cover it. check_eq $S/parse-files-seen 1441 "$CIM_NFILES" check_eq $S/include-count 1440 "$CIM_INC" check_eq $S/include-distinct 1440 "$CIM_INC_DISTINCT" check_eq $S/include-duplicated 0 "$CIM_INC_DUP" check_eq $S/include-malformed 0 "$CIM_INC_BAD" check_eq $S/pragma-locale 1 "$CIM_LOCALE" if [ "${CIM_DANGLING:-1}" = 0 ]; then bst_ok $S/include-resolves; else bst_notok $S/include-resolves "$CIM_DANGLING include(s) name a file that is not installed; first: $CIM_DANGLING_EX"; fi if [ "${CIM_NOTINC:-1}" = 0 ]; then bst_ok $S/include-covers-tree; else bst_notok $S/include-covers-tree "$CIM_NOTINC file(s) not referenced by the master MOF; first: $CIM_NOTINC_EX"; fi # 1438 class files + the master + the two qualifier files = 1441. The CIM # convention is one class per file named for it; 2.40.0 Final holds to it # exactly, so a mismatch is a repacked or substituted file, not a style drift. check_eq $S/class-files 1438 "$CIM_CLASS" if [ "${CIM_CLASS_MISM:-1}" = 0 ]; then bst_ok $S/class-name-matches-file; else bst_notok $S/class-name-matches-file "$CIM_CLASS_MISM mismatch(es); first: $CIM_CLASS_MISM_EX"; fi check_eq $S/classless-files 3 "$CIM_NOCLASS" check_eq $S/classless-which \ "cim_schema_2.40.0.mof qualifiers.mof qualifiers_optional.mof" \ "$(printf '%s\n' $CIM_NOCLASS_LIST | LC_ALL=C sort | tr '\n' ' ' | sed 's/ $//')" # do_install strips CR from every *.mof. The 2.40.0 release zip carries none, so # this asserts the strip did not have to fire rather than that it did -- a red # here means CRs reached the target, whichever end put them there. check_eq $S/no-cr-bytes 0 "$CIM_CRLF" # ------------------------------------------------- reading through the symlinks # A symlink whose target is right and which cannot be read through is the failure # a `readlink` assertion misses. One exec covers both links and the LICENSE. sha256sum "$V/cim_schema_2.40.0.mof" "$V/CIM_Schema.mof" \ "$P/cim-current/qualifiers.mof" "$V/qualifiers.mof" \ "$DOC/LICENSE" > "$W.sums" 2>&1 gawk ' function q(k, v) { printf "%s='"'"'%s'"'"'\n", k, v } { h[$2] = $1 } END { q("CIM_H_MASTER", h["'"$V"'/cim_schema_2.40.0.mof"]) q("CIM_H_ALIAS", h["'"$V"'/CIM_Schema.mof"]) q("CIM_H_QDIR", h["'"$P"'/cim-current/qualifiers.mof"]) q("CIM_H_QUAL", h["'"$V"'/qualifiers.mof"]) q("CIM_H_LIC", h["'"$DOC"'/LICENSE"]) }' "$W.sums" > "$W.f3" . "$W.f3" # CIM_Schema.mof is the stable name a consumer compiles against; it must be the # 2.40.0 master, byte for byte, reached through the link. check_eq $S/master-sha256 \ 1feb44aebb7cb573afdd114756c7b70289f6b8f655b3119d095d07d3bffe21c2 "$CIM_H_MASTER" check_eq $S/CIM_Schema-reads-master "$CIM_H_MASTER" "$CIM_H_ALIAS" # and cim-current/ must be a way into the versioned tree, not an empty directory check_eq $S/cim-current-reads-tree "$CIM_H_QUAL" "$CIM_H_QDIR" check_eq $S/qualifiers-sha256 \ 11e34ea60136b75969ad250202aee8270d0248c22f5022b9734b68550e5e7b70 "$CIM_H_QUAL" # ------------------------------------------------------------------- packaging # This recipe puts the licence in the RUNTIME package -- `FILES:${PN}` claims # `${datadir}/doc/*` and `FILES:${PN}-doc` is set empty -- so the file arriving # is the evidence that the payload landed in a package the image installs rather # than in a -doc package it does not. That is the ticket's stated risk, and it is # the one assertion here that fails if the packaging is wrong and everything else # is right. check_eq $S/doc-files 1 "$CIM_DOCN" check_eq $S/license-size 2073 "$CIM_LICENSE_SZ" check_eq $S/license-sha256 \ 7864f0e2d5f202bfcc5987d19de661142865fd5e7a20aa0d3e08cf766c93d36b "$CIM_H_LIC" # ------------------------------------------- co-installation with -exper # THIS IMAGE NOW SHIPS BOTH SCHEMAS, WHICH IS A REVERSAL OF WHAT THIS SUITE USED # TO ASSERT. Upstream declares the two recipes mutually exclusive over exactly one # path -- both create $P/cim-current -- while their payload trees and licence # directories were already disjoint. meta-brintos gives cim-current one owner # (this recipe, the RELEASED schema), gives the experimental tree # cim-experimental instead, and clears both RCONFLICTS. The case below therefore # asserts the opposite of its predecessor: the experimental tree is EXPECTED, and # its absence means the pair was resolved by dropping a package again. if [ -d "$EXPER" ]; then bst_ok $S/exper-installed-alongside; else bst_notok $S/exper-installed-alongside "$EXPER is absent -- the two schemas are meant to ship together"; fi # Exactly four entries under the shared parent: the two version trees and the two # entry-point symlinks, each pointing at its own tree. A cim-current found # pointing at cimv2.50.0 means the ownership flipped and this schema's consumers # now compile against the experimental classes. find "$P" -maxdepth 1 -mindepth 1 -printf '%y %P %l\n' | LC_ALL=C sort > "$W.top" check_eq $S/mof-top-level "d cimv2.40.0 |d cimv2.50.0 |l cim-current cimv2.40.0|l cim-experimental cimv2.50.0" \ "$(gawk '{printf "%s%s", (NR>1?"|":""), $0} END{print ""}' "$W.top")" # The experimental schema's master, read from ITS tree. 99-cim-schema-exper.test # pins this same value; asserting it from here too is what catches an install # order in which this package's 1441 files landed on top of that one's 1896. check_eq $S/exper-master-untouched \ 784461eea5c8d1b261b270aba3d9533b88a0bbc71a8e5640300e5d6e6ca42af2 \ "$(sha256sum "$EXPER/cim_schema_2.50.0.mof" 2>/dev/null | gawk '{print $1}')" rm -f "$W".*