diff --git a/Runner/config/pkg_command_map.conf b/Runner/config/pkg_command_map.conf index 2f07ded7..4c0b2e73 100755 --- a/Runner/config/pkg_command_map.conf +++ b/Runner/config/pkg_command_map.conf @@ -241,6 +241,22 @@ opkg:Sensors:sns_test=qcom-sensors-api qcom-sensors-core qcom-sensors-registry q debian:package-set:fastrpc=fastrpc-support fastrpc-tests ubuntu:package-set:fastrpc=fastrpc-support fastrpc-tests +# --------------------------------------------------------------------------- +# Qualcomm FastCV runtime package set. +# +# FastCV tests recover these packages automatically on supported host distros. +# Yocto and other image-managed targets have no mapping and retain their +# image-provided FastCV stack. The fastcv_test module runner and matching data +# remain external fixtures and are not supplied by this package set. +# --------------------------------------------------------------------------- + +debian:package-set:fastcv-runtime=qcom-fastcv-binaries libfastcvopt-dev +ubuntu:package-set:fastcv-runtime=qcom-fastcv-binaries libfastcvopt-dev +centos:package-set:fastcv-rpm-prerequisites=epel-release +centos:package-set:fastcv-runtime=qcom-fastcv-binaries libfastcvopt-devel +rhel:package-set:fastcv-rpm-prerequisites=epel-release +rhel:package-set:fastcv-runtime=qcom-fastcv-binaries libfastcvopt-devel + # --------------------------------------------------------------------------- # Qualcomm MinkIPC runtime and test packages. # diff --git a/Runner/suites/Multimedia/FastCV/FastCV_Module_Functional_Validation/FastCV_Module_Functional_Validation.yaml b/Runner/suites/Multimedia/FastCV/FastCV_Module_Functional_Validation/FastCV_Module_Functional_Validation.yaml new file mode 100755 index 00000000..85230796 --- /dev/null +++ b/Runner/suites/Multimedia/FastCV/FastCV_Module_Functional_Validation/FastCV_Module_Functional_Validation.yaml @@ -0,0 +1,40 @@ +metadata: + name: FastCV_Module_Functional_Validation + format: "Lava-Test Test Definition 1.0" + description: "Run a user-sideloaded fastcv_test binary with its matching data folder and validate module results" + os: + - linux + scope: + - functional + - external-fixture + +params: + FASTCV_TEST_BINARY: "" + FASTCV_TEST_DATA_DIR: "" + FASTCV_TEST_TARGETS: "6" + FASTCV_TEST_MODULES: "COLORYUV,SCALE,ARITHM,BLUR,TRNS" + FASTCV_TEST_LOOPS: "10" + FASTCV_TEST_LEVEL: "10" + FASTCV_TEST_TIMEOUT: "300" + FASTCV_TEST_FUNCTION: "" + FASTCV_TEST_OPERATION_MODE: "" + FASTCV_TEST_OPERATION_TABLES_ONLY: "0" + FASTCV_TEST_SEED: "" + FASTCV_TEST_NO_BUFFER_POOL: "0" + FASTCV_TEST_PREALLOC_BYTES: "" + FASTCV_TEST_OPENCV: "0" + FASTCV_TEST_UNIT_ONLY: "0" + FASTCV_TEST_PROFILE_ONLY: "0" + FASTCV_TEST_EXHAUSTIVE: "0" + FASTCV_TEST_RESOLUTION: "" + FASTCV_TEST_QDSP_HEAP: "0" + FASTCV_TEST_ELEMENT_ALIGNMENT: "0" + FASTCV_TEST_CACHE_FLUSH: "0" + FASTCV_TEST_WITHOUT_OPERATION_MODE: "0" + +run: + steps: + - REPO_PATH=$PWD + - cd Runner/suites/Multimedia/FastCV/FastCV_Module_Functional_Validation + - ./run.sh --binary "${FASTCV_TEST_BINARY}" --data-dir "${FASTCV_TEST_DATA_DIR}" --targets "${FASTCV_TEST_TARGETS}" --modules "${FASTCV_TEST_MODULES}" --loops "${FASTCV_TEST_LOOPS}" --level "${FASTCV_TEST_LEVEL}" --timeout "${FASTCV_TEST_TIMEOUT}" --function "${FASTCV_TEST_FUNCTION}" --operation-mode "${FASTCV_TEST_OPERATION_MODE}" --operation-tables-only "${FASTCV_TEST_OPERATION_TABLES_ONLY}" --seed "${FASTCV_TEST_SEED}" --no-buffer-pool "${FASTCV_TEST_NO_BUFFER_POOL}" --prealloc-bytes "${FASTCV_TEST_PREALLOC_BYTES}" --opencv "${FASTCV_TEST_OPENCV}" --unit-only "${FASTCV_TEST_UNIT_ONLY}" --profile-only "${FASTCV_TEST_PROFILE_ONLY}" --exhaustive "${FASTCV_TEST_EXHAUSTIVE}" --resolution "${FASTCV_TEST_RESOLUTION}" --qdsp-heap "${FASTCV_TEST_QDSP_HEAP}" --element-alignment "${FASTCV_TEST_ELEMENT_ALIGNMENT}" --cache-flush "${FASTCV_TEST_CACHE_FLUSH}" --without-operation-mode "${FASTCV_TEST_WITHOUT_OPERATION_MODE}" || true + - $REPO_PATH/Runner/utils/send-to-lava.sh FastCV_Module_Functional_Validation.res diff --git a/Runner/suites/Multimedia/FastCV/FastCV_Module_Functional_Validation/README.md b/Runner/suites/Multimedia/FastCV/FastCV_Module_Functional_Validation/README.md new file mode 100644 index 00000000..1becbc73 --- /dev/null +++ b/Runner/suites/Multimedia/FastCV/FastCV_Module_Functional_Validation/README.md @@ -0,0 +1,314 @@ +# FastCV Module Functional Validation + +This suite runs the Qualcomm `fastcv_test` module test using a binary and +matching data folder supplied by the user. These assets are not assumed to be +part of an installable package, root filesystem, or ramdisk. + +The suite does not discover `fastcv_test` from `PATH` or download test data. +The operator must sideload both fixture assets and provide their locations +explicitly. On supported general-purpose distributions, the suite installs +missing FastCV runtime packages before executing a valid fixture. + +## Required fixture + +Provide: + +- the path to the executable `fastcv_test` binary; and +- the directory containing the matching FastCV test data, including the + required `FastCVTestTable.csv` control file. + +Absolute paths are recommended because LAVA invokes the suite from its +repository directory. For example: + +```sh +./run.sh \ + --binary /var/fastcv/fastcv_test \ + --data-dir /var/fastcv/test_data_new +``` + +If neither path is supplied, the suite skips cleanly and prints the required +options. If only one path is supplied, the suite fails as an incomplete fixture +configuration. Invalid, unreadable, empty, or non-executable fixture paths also +fail once explicitly selected. + +The `fastcv_test` executable and test-data directory must come from the same +FastCV release. Warnings such as `Unknown function ... in FastCVTestTable.csv` +usually indicate that the binary and test data do not match. + +## Platform prerequisites + +On Yocto and other image-managed systems, the suite performs no package-manager +operations. The validation ramdisk or image must already contain the required +FastCV runtime libraries. + +On Debian and Ubuntu, the suite checks and installs these missing packages: + +```text +qcom-fastcv-binaries libfastcvopt-dev +``` + +On CentOS Stream 10 and compatible Red Hat Enterprise Linux 10 aarch64 systems, +the suite first installs `epel-release`, then ensures that these two Qualcomm +CentOS 10 repositories are enabled: + +```text +https://softwarecenter.qualcomm.com/nexus/rpm/centos/10/os/aarch64/ +https://softwarecenter.qualcomm.com/nexus/rpm/centos/10/os/noarch/ +``` + +When neither repository ID is already enabled, the suite creates +`/etc/yum.repos.d/qualcomm-linux.repo` with the +`qualcomm-linux-aarch64` and `qualcomm-linux-noarch` definitions from the RPM +image setup guide. It then checks and installs: + +```text +qcom-fastcv-binaries libfastcvopt-devel +``` + +No installed package is upgraded. Package recovery needs root privileges, +network access, and working distro repositories only when a required package +or repository is missing. An incomplete pre-existing Qualcomm repository +configuration fails rather than being overwritten. Package preparation failure +is reported as a suite failure. The RPM path also verifies that the `epel` +repository is enabled after installing `epel-release`. Automatic repository +creation is rejected on other CentOS or Red Hat major versions because the +configured repository URLs are specific to version 10. When the complete +FastCV package set is already installed, the suite skips repository setup and +package-manager network operations. + +These packages provide the FastCV runtime dependencies, but they do not provide +the `fastcv_test` module runner or its matching test data. Sideload both fixture +assets separately, for example: + +```sh +install -d /var/fastcv +install -m 0755 ./fastcv_test /var/fastcv/fastcv_test +tar -xf ./test_data.tar.gz -C /var/fastcv +test -r /var/fastcv/test_data_new/FastCVTestTable.csv +``` + +Then run the suite. Runtime package recovery happens automatically: + +```sh +sudo ./run.sh \ + --binary /var/fastcv/fastcv_test \ + --data-dir /var/fastcv/test_data_new +``` + +`sudo` is needed only when the suite must add a repository or install a missing +package. LAVA target shells commonly already run as root. + +## Default coverage + +The default command is equivalent to: + +```sh +/var/fastcv/fastcv_test /var/fastcv/test_data_new -t 6 -l 10 -m COLORYUV +/var/fastcv/fastcv_test /var/fastcv/test_data_new -t 6 -l 10 -m SCALE +/var/fastcv/fastcv_test /var/fastcv/test_data_new -t 6 -l 10 -m ARITHM +/var/fastcv/fastcv_test /var/fastcv/test_data_new -t 6 -l 10 -m BLUR +/var/fastcv/fastcv_test /var/fastcv/test_data_new -t 6 -l 10 -m TRNS +``` + +This bounded default covers representative color conversion, scaling, +arithmetic, filtering, and transformation operations on CPU and VENUM. Each +module runs as a separate invocation and must report its exact module PASS plus +both overall FIT PASS markers. Any module or overall FIT FAIL marker fails the +suite. + +The complete native matrix remains available explicitly with `--targets 0 +--modules all`. That mode enables every backend reported by the binary and +walks its complete module table. It can take substantially longer, and the +suite replays the retained command output after the invocation completes or +reaches its configured timeout. + +Supported target selectors are: + +| Value | Target requested by `fastcv_test` | +| --- | --- | +| `0` | All targets available to the binary | +| `2` | CPU | +| `4` | VENUM | +| `6` | CPU and VENUM | +| `8` | DSP | + +Multiple targets may be supplied as a comma-separated list. Each target is a +separate bounded invocation. + +## Focused module coverage + +Use `--modules` with one module or a comma-separated module list. Each selected +module runs separately with `-m`. The runner accepts the two output dialects +observed from supported `fastcv_test` builds while retaining fail-closed +validation. + +```sh +./run.sh \ + --binary /var/fastcv/fastcv_test \ + --data-dir /var/fastcv/test_data_new \ + --targets 6 \ + --loops 10 \ + --modules COLORYUV,SCALE,ARITHM,BLUR,TRNS +``` + +The full output dialect reports all three summary markers: + +```text +FASTCV_TEST, SCALE=>PASS +FIT:(FeatureName=>FASTCV, Overall=>PASS) +FASTCV_PROFILE, FIT:(FeatureName=>FASTCV, Overall=>PASS) +``` + +Some host-distribution builds emit only profiling records. For that dialect, +the runner requires at least one function-level profile PASS plus the final +profile FIT PASS: + +```text +FASTCV_PROFILE, fcvScaleDownBy2u8 :: PASS, ... +FASTCV_PROFILE, FIT:(FeatureName=>FASTCV, Overall=>PASS) +``` + +Both dialects also require exit status zero and no function, module, profile, +or FIT failure marker. A profile FIT summary by itself is not sufficient. + +Module names are validated as alphanumeric identifiers with `_`, `+`, or `-` +characters. The suite does not impose a static allowlist because the +sideloaded binary and data revision own the available module set. + +Run one focused module on CPU and VENUM: + +```sh +./run.sh \ + --binary /var/fastcv/fastcv_test \ + --data-dir /var/fastcv/test_data_new \ + --targets 6 \ + --loops 10 \ + --modules COLORYUV +``` + +Run one focused module on DSP: + +```sh +./run.sh \ + --binary /var/fastcv/fastcv_test \ + --data-dir /var/fastcv/test_data_new \ + --targets 8 \ + --loops 10 \ + --modules SCALE +``` + +Run the complete native target and module matrix only in a suitably sized +scheduled job: + +```sh +./run.sh \ + --binary /var/fastcv/fastcv_test \ + --data-dir /var/fastcv/test_data_new \ + --targets 0 \ + --modules all \ + --loops 10 \ + --level 10 \ + --timeout 1800 +``` + +## Options and precedence + +The wrapper exposes the options that are actually parsed by the supplied +`fastcvTest.cpp` Linux implementation: + +| Wrapper option | `fastcv_test` argument | Default and constraints | +| --- | --- | --- | +| `--binary PATH` | executable | Required external fixture path | +| `--data-dir DIR` | first positional argument | Required matching data directory | +| `--targets LIST` | `-t` | Comma-separated `0`, `2`, `4`, `6`, or `8`, default `6` | +| `--modules LIST` | `-m` | `all` or comma-separated modules, default `COLORYUV,SCALE,ARITHM,BLUR,TRNS` | +| `--loops COUNT` | `-l` | Positive integer, default `10` | +| `--level COUNT` | `-L` | Positive integer for all-module runs, default `10` | +| `--timeout SECONDS` | wrapper only | Positive per-invocation bound, default `300` | +| `--function NAME` | `-f` | Optional function, requires exactly one focused module | +| `--operation-mode N` | `-M` | Optional operation-mode bit value `0` through `8` | +| `--operation-tables-only 0\|1` | `-OPT` | Requires a nonzero operation mode | +| `--seed INTEGER` | `-s` | Optional RNG seed, a negative value requests a time-based seed | +| `--no-buffer-pool 0\|1` | `-nbp` | Use ordinary allocations instead of the internal buffer pool | +| `--prealloc-bytes N` | `-psb` | Positive scratch-buffer preallocation size | +| `--opencv 0\|1` | `-o` | Request OpenCV benchmark profiling when supported by the binary build | +| `--unit-only 0\|1` | `-U` | Disable performance profiling | +| `--profile-only 0\|1` | `-P` | Disable unit tests | +| `--exhaustive 0\|1` | `-E` | Enable exhaustive profiling-vector validation | +| `--resolution N` | `-S` | Profiling resolution index `0` through `7` | +| `--qdsp-heap 0\|1` | `-H` | Allocate QDSP test vectors from the ARM heap | +| `--element-alignment 0\|1` | `-AL` | Limit allocation alignment to element size | +| `--cache-flush 0\|1` | `-C` | Request cache flush/invalidate profiling, a no-op in the supplied non-Android source | +| `--without-operation-mode 0\|1` | `-TWOp` | Run the source's additional API checks without calling `fcvSetOperationMode` | + +`--unit-only` and `--profile-only` are mutually exclusive. +`--no-buffer-pool` cannot be combined with `--prealloc-bytes`, because the +source applies preallocation only when its internal buffer pool is enabled. +When `--without-operation-mode 1` is selected, the suite also requires the +source's exact success marker for that additional path. + +The supplied source rejects more than 14 total process arguments. The wrapper +counts the final argument vector and fails before execution when a requested +combination exceeds that source limit. This means all supported switches are +available, but they cannot all be enabled in one invocation. Split such +coverage across multiple suite executions. + +Environment equivalents use the names in the YAML parameters: +`FASTCV_TEST_BINARY`, `FASTCV_TEST_DATA_DIR`, `FASTCV_TEST_TARGETS`, +`FASTCV_TEST_MODULES`, `FASTCV_TEST_LOOPS`, `FASTCV_TEST_LEVEL`, +`FASTCV_TEST_TIMEOUT`, `FASTCV_TEST_FUNCTION`, +`FASTCV_TEST_OPERATION_MODE`, `FASTCV_TEST_OPERATION_TABLES_ONLY`, +`FASTCV_TEST_SEED`, `FASTCV_TEST_NO_BUFFER_POOL`, +`FASTCV_TEST_PREALLOC_BYTES`, `FASTCV_TEST_OPENCV`, +`FASTCV_TEST_UNIT_ONLY`, `FASTCV_TEST_PROFILE_ONLY`, +`FASTCV_TEST_EXHAUSTIVE`, `FASTCV_TEST_RESOLUTION`, +`FASTCV_TEST_QDSP_HEAP`, `FASTCV_TEST_ELEMENT_ALIGNMENT`, +`FASTCV_TEST_CACHE_FLUSH`, and `FASTCV_TEST_WITHOUT_OPERATION_MODE`. +CLI values take precedence. + +For example, a focused function run is: + +```sh +./run.sh \ + --binary /var/fastcv/fastcv_test \ + --data-dir /var/fastcv/test_data_new \ + --targets 6 \ + --modules SCALE \ + --function fcvScaleDownBy2u8 +``` + +The supplied source prints help for `-p`, `-e`, and `-DF`, but its argument +parser does not implement those switches. The wrapper intentionally does not +advertise them. `-AC` is compiled only for Android and is also outside this +Linux suite's interface. + +The full matrix size is the number of targets multiplied by the number of +focused modules. The suite rejects selections above 64 invocations to keep an +accidental selector expansion from consuming an unbounded CI job. Keep large +matrices in an appropriate scheduled job and divide them across executions. + +## Results + +- **PASS**: every requested invocation exits zero and reports either the full + module/FIT marker set or function-level profiling PASS evidence with the + profile FIT summary. Unit-only mode requires the full non-profile marker set. + Selected function and without-operation-mode evidence is required when + applicable, and any official FAIL marker fails the invocation. +- **FAIL**: the explicit fixture is incomplete or invalid, configuration is + malformed, required host-distribution package recovery fails, execution + fails or times out, a FAIL marker is present, or required PASS markers are + missing. +- **SKIP**: neither sideloaded asset path is provided. Kernel-log health is a + separate SKIP if a DSP-capable target was selected but logs are unavailable. + +## Evidence + +Each run stores evidence below: + +```text +results/FastCV_Module_Functional_Validation/run--/ +``` + +Evidence includes binary metadata, a complete data-file listing, normalized +target and module selections, one complete log per invocation, and one retained +FastRPC kernel-log snapshot when target `0` or `8` is selected. diff --git a/Runner/suites/Multimedia/FastCV/FastCV_Module_Functional_Validation/run.sh b/Runner/suites/Multimedia/FastCV/FastCV_Module_Functional_Validation/run.sh new file mode 100755 index 00000000..824a22fc --- /dev/null +++ b/Runner/suites/Multimedia/FastCV/FastCV_Module_Functional_Validation/run.sh @@ -0,0 +1,842 @@ +#!/bin/sh +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause + +# ---------- Repo env + helpers ---------- +SCRIPT_DIR="$( + cd "$(dirname "$0")" || exit 1 + pwd +)" +INIT_ENV="" +SEARCH="$SCRIPT_DIR" + +while [ "$SEARCH" != "/" ]; do + if [ -f "$SEARCH/init_env" ]; then + INIT_ENV="$SEARCH/init_env" + break + fi + SEARCH=$(dirname "$SEARCH") +done + +if [ -z "$INIT_ENV" ]; then + echo "[ERROR] Could not find init_env (starting at $SCRIPT_DIR)" >&2 + exit 1 +fi + +# Only source once (idempotent) +# NOTE: We intentionally **do not export** any new vars. They stay local to this shell. +if [ -z "${__INIT_ENV_LOADED:-}" ]; then + # shellcheck disable=SC1090 + . "$INIT_ENV" + __INIT_ENV_LOADED=1 +fi + +# shellcheck disable=SC1090 +. "$INIT_ENV" +# shellcheck disable=SC1091 +. "$TOOLS/functestlib.sh" +# shellcheck disable=SC1091 +. "$TOOLS/lib_pkg_provider.sh" +# shellcheck disable=SC1091 +. "$TOOLS/lib_fastcv.sh" +TESTNAME="FastCV_Module_Functional_Validation" +RES_FILE="$SCRIPT_DIR/$TESTNAME.res" + +FASTCV_TEST_BINARY="${FASTCV_TEST_BINARY:-}" +FASTCV_TEST_DATA_DIR="${FASTCV_TEST_DATA_DIR:-}" +FASTCV_TEST_TARGETS="${FASTCV_TEST_TARGETS:-6}" +FASTCV_TEST_MODULES="${FASTCV_TEST_MODULES:-COLORYUV,SCALE,ARITHM,BLUR,TRNS}" +FASTCV_TEST_LOOPS="${FASTCV_TEST_LOOPS:-10}" +FASTCV_TEST_LEVEL="${FASTCV_TEST_LEVEL:-10}" +FASTCV_TEST_TIMEOUT="${FASTCV_TEST_TIMEOUT:-300}" +FASTCV_TEST_FUNCTION="${FASTCV_TEST_FUNCTION:-}" +FASTCV_TEST_OPERATION_MODE="${FASTCV_TEST_OPERATION_MODE:-}" +FASTCV_TEST_OPERATION_TABLES_ONLY="${FASTCV_TEST_OPERATION_TABLES_ONLY:-0}" +FASTCV_TEST_SEED="${FASTCV_TEST_SEED:-}" +FASTCV_TEST_NO_BUFFER_POOL="${FASTCV_TEST_NO_BUFFER_POOL:-0}" +FASTCV_TEST_PREALLOC_BYTES="${FASTCV_TEST_PREALLOC_BYTES:-}" +FASTCV_TEST_OPENCV="${FASTCV_TEST_OPENCV:-0}" +FASTCV_TEST_UNIT_ONLY="${FASTCV_TEST_UNIT_ONLY:-0}" +FASTCV_TEST_PROFILE_ONLY="${FASTCV_TEST_PROFILE_ONLY:-0}" +FASTCV_TEST_EXHAUSTIVE="${FASTCV_TEST_EXHAUSTIVE:-0}" +FASTCV_TEST_RESOLUTION="${FASTCV_TEST_RESOLUTION:-}" +FASTCV_TEST_QDSP_HEAP="${FASTCV_TEST_QDSP_HEAP:-0}" +FASTCV_TEST_ELEMENT_ALIGNMENT="${FASTCV_TEST_ELEMENT_ALIGNMENT:-0}" +FASTCV_TEST_CACHE_FLUSH="${FASTCV_TEST_CACHE_FLUSH:-0}" +FASTCV_TEST_WITHOUT_OPERATION_MODE="${FASTCV_TEST_WITHOUT_OPERATION_MODE:-0}" +FASTCV_TEST_MAX_CASES=64 +RESULT_DIR="$SCRIPT_DIR/results/$TESTNAME/run-$(date '+%Y%m%d-%H%M%S')-$$" +BINARY_REPORT="$RESULT_DIR/fastcv_test_binary.log" +DATA_REPORT="$RESULT_DIR/fastcv_test_data_files.log" +CONTROL_TABLE="" +TARGET_LIST="$RESULT_DIR/fastcv_targets.list" +MODULE_LIST="$RESULT_DIR/fastcv_modules.list" +DSP_TARGET_SELECTED=0 + +# usage +# Print required fixture paths and configurable fastcv_test arguments. +# Inputs: none. Output: help text on stdout. Returns: 0. Side effects: none. +usage() { + printf '%s\n' \ + "Usage: ./run.sh --binary PATH --data-dir DIR [options]" \ + " --binary PATH Sideloaded fastcv_test executable" \ + " --data-dir DIR Matching sideloaded FastCV data directory" \ + " --targets LIST Comma-separated 0,2,4,6,8, default: 6" \ + " --modules LIST all or comma-separated modules" \ + " default: COLORYUV,SCALE,ARITHM,BLUR,TRNS" \ + " --loops COUNT Value passed with -l, default: 10" \ + " --level COUNT Value passed with -L for all modules, default: 10" \ + " --timeout SECONDS Bound each invocation, default: 300" \ + " --function NAME Limit to one function, requires one focused module" \ + " --operation-mode N Value passed with -M, accepted: 0 through 8" \ + " --operation-tables-only 0|1 Pass -OPT" \ + " --seed INTEGER Value passed with -s, empty keeps binary default" \ + " --no-buffer-pool 0|1 Pass -nbp" \ + " --prealloc-bytes N Pass -psb N" \ + " --opencv 0|1 Pass -o" \ + " --unit-only 0|1 Pass -U" \ + " --profile-only 0|1 Pass -P" \ + " --exhaustive 0|1 Pass -E" \ + " --resolution N Pass -S, accepted: 0 through 7" \ + " --qdsp-heap 0|1 Pass -H" \ + " --element-alignment 0|1 Pass -AL" \ + " --cache-flush 0|1 Pass -C" \ + " --without-operation-mode 0|1 Pass -TWOp" \ + " -h, --help" \ + "The binary and data folder are external fixture assets and must be provided together." +} + +# parse_args ARG... +# Parse CLI values into the suite configuration globals. +# Inputs: command-line arguments. Output: no stdout. +# Returns: 0 on success, 2 for invalid input, or exits after help. +# Side effects: updates all FASTCV_TEST_* configuration globals. +parse_args() { + while [ "$#" -gt 0 ]; do + case "$1" in + --binary) + [ "$#" -ge 2 ] || return 2 + FASTCV_TEST_BINARY="$2" + shift 2 + ;; + --data-dir) + [ "$#" -ge 2 ] || return 2 + FASTCV_TEST_DATA_DIR="$2" + shift 2 + ;; + --targets) + [ "$#" -ge 2 ] || return 2 + FASTCV_TEST_TARGETS="$2" + shift 2 + ;; + --modules) + [ "$#" -ge 2 ] || return 2 + FASTCV_TEST_MODULES="$2" + shift 2 + ;; + --loops) + [ "$#" -ge 2 ] || return 2 + FASTCV_TEST_LOOPS="$2" + shift 2 + ;; + --level) + [ "$#" -ge 2 ] || return 2 + FASTCV_TEST_LEVEL="$2" + shift 2 + ;; + --timeout) + [ "$#" -ge 2 ] || return 2 + FASTCV_TEST_TIMEOUT="$2" + shift 2 + ;; + --function) + [ "$#" -ge 2 ] || return 2 + FASTCV_TEST_FUNCTION="$2" + shift 2 + ;; + --operation-mode) + [ "$#" -ge 2 ] || return 2 + FASTCV_TEST_OPERATION_MODE="$2" + shift 2 + ;; + --operation-tables-only) + [ "$#" -ge 2 ] || return 2 + FASTCV_TEST_OPERATION_TABLES_ONLY="$2" + shift 2 + ;; + --seed) + [ "$#" -ge 2 ] || return 2 + FASTCV_TEST_SEED="$2" + shift 2 + ;; + --no-buffer-pool) + [ "$#" -ge 2 ] || return 2 + FASTCV_TEST_NO_BUFFER_POOL="$2" + shift 2 + ;; + --prealloc-bytes) + [ "$#" -ge 2 ] || return 2 + FASTCV_TEST_PREALLOC_BYTES="$2" + shift 2 + ;; + --opencv) + [ "$#" -ge 2 ] || return 2 + FASTCV_TEST_OPENCV="$2" + shift 2 + ;; + --unit-only) + [ "$#" -ge 2 ] || return 2 + FASTCV_TEST_UNIT_ONLY="$2" + shift 2 + ;; + --profile-only) + [ "$#" -ge 2 ] || return 2 + FASTCV_TEST_PROFILE_ONLY="$2" + shift 2 + ;; + --exhaustive) + [ "$#" -ge 2 ] || return 2 + FASTCV_TEST_EXHAUSTIVE="$2" + shift 2 + ;; + --resolution) + [ "$#" -ge 2 ] || return 2 + FASTCV_TEST_RESOLUTION="$2" + shift 2 + ;; + --qdsp-heap) + [ "$#" -ge 2 ] || return 2 + FASTCV_TEST_QDSP_HEAP="$2" + shift 2 + ;; + --element-alignment) + [ "$#" -ge 2 ] || return 2 + FASTCV_TEST_ELEMENT_ALIGNMENT="$2" + shift 2 + ;; + --cache-flush) + [ "$#" -ge 2 ] || return 2 + FASTCV_TEST_CACHE_FLUSH="$2" + shift 2 + ;; + --without-operation-mode) + [ "$#" -ge 2 ] || return 2 + FASTCV_TEST_WITHOUT_OPERATION_MODE="$2" + shift 2 + ;; + -h|--help) + usage + exit 0 + ;; + *) + log_error "Unknown argument: $1" + return 2 + ;; + esac + done +} + +# validate_boolean_option NAME VALUE +# Validate one wrapper boolean encoded as 0 or 1. +# Inputs: user-facing option name and value. Output: error log on invalid input. +# Returns: 0 for 0 or 1, and 1 otherwise. Side effects: none beyond logging. +validate_boolean_option() { + vbo_name="$1" + vbo_value="$2" + + case "$vbo_value" in + 0|1) + return 0 + ;; + *) + log_error "$vbo_name must be 0 or 1, observed=${vbo_value:-empty}" + return 1 + ;; + esac +} + +# prepare_target_list TARGETS OUTPUT_FILE +# Validate target selectors and write one deduplicated target per line. +# Inputs: comma-separated selectors and retained output path. +# Output: no stdout. Returns: 0 for valid selectors or 1 otherwise. +# Side effects: replaces OUTPUT_FILE and updates DSP_TARGET_SELECTED. +prepare_target_list() { + ptl_targets="$1" + ptl_output="$2" + ptl_raw="$ptl_output.raw" + ptl_error="" + DSP_TARGET_SELECTED=0 + + rm -f "$ptl_output" "$ptl_raw" + if ! printf '%s\n' "$ptl_targets" | tr ',' '\n' >"$ptl_raw"; then + return 1 + fi + + while IFS= read -r ptl_target; do + case "$ptl_target" in + 0|2|4|6|8) + ;; + *) + ptl_error="Invalid FastCV target selector: ${ptl_target:-empty}" + break + ;; + esac + if grep -Fxq "$ptl_target" "$ptl_output" 2>/dev/null; then + ptl_error="Duplicate FastCV target selector: $ptl_target" + break + fi + printf '%s\n' "$ptl_target" >>"$ptl_output" + case "$ptl_target" in + 0|8) + DSP_TARGET_SELECTED=1 + ;; + esac + done <"$ptl_raw" + rm -f "$ptl_raw" + + if [ -n "$ptl_error" ]; then + log_error "$ptl_error" + return 1 + fi + + [ -s "$ptl_output" ] +} + +# prepare_module_list MODULES OUTPUT_FILE +# Validate a module selector or normalize all-module mode to the ALL token. +# Inputs: all or a comma-separated module list, and retained output path. +# Output: no stdout. Returns: 0 for valid selectors or 1 otherwise. +# Side effects: replaces OUTPUT_FILE and its temporary raw selector file. +prepare_module_list() { + pml_modules="$1" + pml_output="$2" + pml_raw="$pml_output.raw" + pml_normalized=$(printf '%s\n' "$pml_modules" | tr '[:lower:]' '[:upper:]') + pml_error="" + + rm -f "$pml_output" "$pml_raw" + if [ "$pml_normalized" = "ALL" ]; then + printf 'ALL\n' >"$pml_output" + return 0 + fi + if ! printf '%s\n' "$pml_normalized" | tr ',' '\n' >"$pml_raw"; then + return 1 + fi + + while IFS= read -r pml_module; do + case "$pml_module" in + ''|*[!A-Z0-9_+-]*) + pml_error="Invalid FastCV module selector: ${pml_module:-empty}" + break + ;; + esac + if grep -Fxq "$pml_module" "$pml_output" 2>/dev/null; then + pml_error="Duplicate FastCV module selector: $pml_module" + break + fi + printf '%s\n' "$pml_module" >>"$pml_output" + done <"$pml_raw" + rm -f "$pml_raw" + + if [ -n "$pml_error" ]; then + log_error "$pml_error" + return 1 + fi + + [ -s "$pml_output" ] +} + +# run_fastcv_test_case TARGET MODULE +# Execute one bounded fastcv_test target/module selection and classify markers. +# Inputs: validated target value and ALL or one validated module name. +# Output: emits bounded diagnostics through the common logger. +# Returns: 0 for functional PASS or 1 for FAIL. +# Side effects: creates a retained command log and records one testcase result. +run_fastcv_test_case() { + rftc_target="$1" + rftc_module="$2" + case "$rftc_target" in + 0) + rftc_target_name="all" + ;; + 2) + rftc_target_name="cpu" + ;; + 4) + rftc_target_name="venum" + ;; + 6) + rftc_target_name="cpu-venum" + ;; + 8) + rftc_target_name="dsp" + ;; + esac + + rftc_module_label=$(printf '%s\n' "$rftc_module" | tr '[:upper:]' '[:lower:]') + rftc_log="$RESULT_DIR/fastcv_target-${rftc_target}_${rftc_target_name}_module-${rftc_module_label}.log" + rm -f "$rftc_log" + + set -- \ + "$FASTCV_TEST_BINARY" \ + "$FASTCV_TEST_DATA_DIR" \ + -t "$rftc_target" \ + -l "$FASTCV_TEST_LOOPS" + if [ "$rftc_module" = "ALL" ]; then + set -- "$@" -L "$FASTCV_TEST_LEVEL" + rftc_level_applied="$FASTCV_TEST_LEVEL" + else + set -- "$@" -m "$rftc_module" + rftc_level_applied="not-applied" + fi + + if [ -n "$FASTCV_TEST_FUNCTION" ]; then + set -- "$@" -f "$FASTCV_TEST_FUNCTION" + fi + if [ -n "$FASTCV_TEST_OPERATION_MODE" ]; then + set -- "$@" -M "$FASTCV_TEST_OPERATION_MODE" + fi + if [ "$FASTCV_TEST_OPERATION_TABLES_ONLY" -eq 1 ]; then + set -- "$@" -OPT + fi + if [ -n "$FASTCV_TEST_SEED" ]; then + set -- "$@" -s "$FASTCV_TEST_SEED" + fi + if [ "$FASTCV_TEST_NO_BUFFER_POOL" -eq 1 ]; then + set -- "$@" -nbp + fi + if [ -n "$FASTCV_TEST_PREALLOC_BYTES" ]; then + set -- "$@" -psb "$FASTCV_TEST_PREALLOC_BYTES" + fi + if [ "$FASTCV_TEST_OPENCV" -eq 1 ]; then + set -- "$@" -o + fi + if [ "$FASTCV_TEST_UNIT_ONLY" -eq 1 ]; then + set -- "$@" -U + fi + if [ "$FASTCV_TEST_PROFILE_ONLY" -eq 1 ]; then + set -- "$@" -P + fi + if [ "$FASTCV_TEST_EXHAUSTIVE" -eq 1 ]; then + set -- "$@" -E + fi + if [ -n "$FASTCV_TEST_RESOLUTION" ]; then + set -- "$@" -S "$FASTCV_TEST_RESOLUTION" + fi + if [ "$FASTCV_TEST_QDSP_HEAP" -eq 1 ]; then + set -- "$@" -H + fi + if [ "$FASTCV_TEST_ELEMENT_ALIGNMENT" -eq 1 ]; then + set -- "$@" -AL + fi + if [ "$FASTCV_TEST_CACHE_FLUSH" -eq 1 ]; then + set -- "$@" -C + fi + if [ "$FASTCV_TEST_WITHOUT_OPERATION_MODE" -eq 1 ]; then + set -- "$@" -TWOp + fi + + rftc_argc=$# + if [ "$rftc_argc" -gt 14 ]; then + test_result_record \ + "FAIL" \ + "fastcv_test argument selection exceeds the source limit, target=$rftc_target module=$rftc_module argc=$rftc_argc maximum=14" + return 1 + fi + + log_info "[FASTCV-CASE] phase=start target=$rftc_target target_name=$rftc_target_name module=$rftc_module loops=$FASTCV_TEST_LOOPS level=$rftc_level_applied function=${FASTCV_TEST_FUNCTION:-all} operation_mode=${FASTCV_TEST_OPERATION_MODE:-default} operation_tables_only=$FASTCV_TEST_OPERATION_TABLES_ONLY seed=${FASTCV_TEST_SEED:-default} no_buffer_pool=$FASTCV_TEST_NO_BUFFER_POOL prealloc_bytes=${FASTCV_TEST_PREALLOC_BYTES:-none} opencv=$FASTCV_TEST_OPENCV unit_only=$FASTCV_TEST_UNIT_ONLY profile_only=$FASTCV_TEST_PROFILE_ONLY exhaustive=$FASTCV_TEST_EXHAUSTIVE resolution=${FASTCV_TEST_RESOLUTION:-default} qdsp_heap=$FASTCV_TEST_QDSP_HEAP element_alignment=$FASTCV_TEST_ELEMENT_ALIGNMENT cache_flush=$FASTCV_TEST_CACHE_FLUSH without_operation_mode=$FASTCV_TEST_WITHOUT_OPERATION_MODE argc=$rftc_argc timeout=${FASTCV_TEST_TIMEOUT}s" + run_with_timeout_log \ + "$FASTCV_TEST_TIMEOUT" \ + "$rftc_log" \ + "$@" + rftc_rc=$? + + log_file_with_label "FASTCV-TEST-$rftc_target-$rftc_module" "$rftc_log" 120 + if ! fastcv_collect_test_markers \ + "$rftc_log" \ + "$rftc_module" \ + "$FASTCV_TEST_FUNCTION" \ + "$FASTCV_TEST_WITHOUT_OPERATION_MODE"; then + test_result_record \ + "FAIL" \ + "Could not parse fastcv_test evidence, target=$rftc_target module=$rftc_module artifact=$rftc_log" + return 1 + fi + rftc_failure_count="$FASTCV_MARKER_FAILURE_COUNT" + rftc_fit_count="$FASTCV_MARKER_FIT_COUNT" + rftc_profile_count="$FASTCV_MARKER_PROFILE_SUMMARY_COUNT" + rftc_profile_case_count="$FASTCV_MARKER_PROFILE_CASE_PASS_COUNT" + rftc_module_count="$FASTCV_MARKER_MODULE_COUNT" + rftc_function_count="$FASTCV_MARKER_FUNCTION_COUNT" + rftc_without_mode_count="$FASTCV_MARKER_WITHOUT_MODE_COUNT" + rftc_output_bytes=$(wc -c <"$rftc_log" 2>/dev/null | tr -d '[:space:]') + + rftc_profile_required=1 + if [ "$FASTCV_TEST_UNIT_ONLY" -eq 1 ]; then + rftc_profile_required=0 + fi + rftc_marker_dialect="none" + rftc_marker_missing=1 + if [ "$rftc_module_count" -gt 0 ] && + [ "$rftc_fit_count" -gt 0 ] && + { [ "$rftc_profile_required" -eq 0 ] || + [ "$rftc_profile_count" -gt 0 ]; }; then + rftc_marker_dialect="test-and-profile" + rftc_marker_missing=0 + elif [ "$rftc_profile_required" -eq 1 ] && + [ "$rftc_profile_case_count" -gt 0 ] && + [ "$rftc_profile_count" -gt 0 ]; then + rftc_marker_dialect="profile-only" + rftc_marker_missing=0 + fi + if [ -n "$FASTCV_TEST_FUNCTION" ] && [ "$rftc_function_count" -eq 0 ]; then + rftc_marker_missing=1 + fi + if [ "$FASTCV_TEST_WITHOUT_OPERATION_MODE" -eq 1 ] && + [ "$rftc_without_mode_count" -eq 0 ]; then + rftc_marker_missing=1 + fi + + log_info "[FASTCV-CASE] phase=complete target=$rftc_target target_name=$rftc_target_name module=$rftc_module rc=$rftc_rc marker_dialect=$rftc_marker_dialect module_pass_markers=$rftc_module_count fit_pass_markers=$rftc_fit_count profile_case_pass_markers=$rftc_profile_case_count profile_pass_markers=$rftc_profile_count profile_required=$rftc_profile_required function_markers=$rftc_function_count without_operation_mode_markers=$rftc_without_mode_count failure_markers=$rftc_failure_count output_bytes=${rftc_output_bytes:-0} artifact=$rftc_log" + + if [ "$rftc_rc" -ne 0 ]; then + test_result_record \ + "FAIL" \ + "fastcv_test failed or exceeded the ${FASTCV_TEST_TIMEOUT}s bound, target=$rftc_target module=$rftc_module rc=$rftc_rc artifact=$rftc_log" + return 1 + fi + if [ "$rftc_failure_count" -gt 0 ]; then + test_result_record \ + "FAIL" \ + "fastcv_test reported an official FAIL marker, target=$rftc_target module=$rftc_module failure_markers=$rftc_failure_count artifact=$rftc_log" + return 1 + fi + if [ "$rftc_marker_missing" -eq 1 ]; then + test_result_record \ + "FAIL" \ + "fastcv_test omitted required PASS evidence, target=$rftc_target module=$rftc_module marker_dialect=$rftc_marker_dialect module_markers=$rftc_module_count fit_markers=$rftc_fit_count profile_case_markers=$rftc_profile_case_count profile_markers=$rftc_profile_count profile_required=$rftc_profile_required function_markers=$rftc_function_count without_operation_mode_markers=$rftc_without_mode_count artifact=$rftc_log" + return 1 + fi + + test_result_record \ + "PASS" \ + "fastcv_test completed functional module validation, target=$rftc_target target_name=$rftc_target_name module=$rftc_module marker_dialect=$rftc_marker_dialect module_pass_markers=$rftc_module_count profile_case_pass_markers=$rftc_profile_case_count artifact=$rftc_log" + return 0 +} + +parse_args "$@" || { + usage >&2 + exit 2 +} + +test_result_init "$TESTNAME" "$RES_FILE" || exit 1 + +if ! mkdir -p "$RESULT_DIR"; then + test_result_finish \ + "FAIL" \ + "$TESTNAME FAIL: cannot create retained evidence directory $RESULT_DIR" +fi + +log_info "--------------------------------------------------------------------------" +log_info "Starting $TESTNAME" +log_info "Evidence directory: $RESULT_DIR" +log_info "FastCV module functional validation: running a user-sideloaded fastcv_test binary with its matching data folder" +log_info "[FASTCV-POLICY] applicability=explicit-external-fixture binary=${FASTCV_TEST_BINARY:-none} data_dir=${FASTCV_TEST_DATA_DIR:-none} targets=$FASTCV_TEST_TARGETS modules=$FASTCV_TEST_MODULES loops=$FASTCV_TEST_LOOPS level=$FASTCV_TEST_LEVEL timeout=${FASTCV_TEST_TIMEOUT}s max_cases=$FASTCV_TEST_MAX_CASES" +log_info "[FASTCV-OPTIONS] function=${FASTCV_TEST_FUNCTION:-all} operation_mode=${FASTCV_TEST_OPERATION_MODE:-default} operation_tables_only=$FASTCV_TEST_OPERATION_TABLES_ONLY seed=${FASTCV_TEST_SEED:-default} no_buffer_pool=$FASTCV_TEST_NO_BUFFER_POOL prealloc_bytes=${FASTCV_TEST_PREALLOC_BYTES:-none} opencv=$FASTCV_TEST_OPENCV unit_only=$FASTCV_TEST_UNIT_ONLY profile_only=$FASTCV_TEST_PROFILE_ONLY exhaustive=$FASTCV_TEST_EXHAUSTIVE resolution=${FASTCV_TEST_RESOLUTION:-default} qdsp_heap=$FASTCV_TEST_QDSP_HEAP element_alignment=$FASTCV_TEST_ELEMENT_ALIGNMENT cache_flush=$FASTCV_TEST_CACHE_FLUSH without_operation_mode=$FASTCV_TEST_WITHOUT_OPERATION_MODE" + +if [ -z "$FASTCV_TEST_BINARY" ] && [ -z "$FASTCV_TEST_DATA_DIR" ]; then + test_result_record \ + "SKIP" \ + "fastcv_test is a sideloaded fixture, provide both --binary PATH and --data-dir DIR" + test_result_finish +fi +if [ -z "$FASTCV_TEST_BINARY" ] || [ -z "$FASTCV_TEST_DATA_DIR" ]; then + test_result_record \ + "FAIL" \ + "FastCV fixture configuration is incomplete, binary=${FASTCV_TEST_BINARY:-missing} data_dir=${FASTCV_TEST_DATA_DIR:-missing}" + test_result_finish +fi + +case "$FASTCV_TEST_LOOPS" in + ''|*[!0-9]*|0) + test_result_record "FAIL" "FastCV loop count must be a positive integer, observed=${FASTCV_TEST_LOOPS:-empty}" + test_result_finish + ;; +esac +case "$FASTCV_TEST_LEVEL" in + ''|*[!0-9]*|0) + test_result_record "FAIL" "FastCV level must be a positive integer, observed=${FASTCV_TEST_LEVEL:-empty}" + test_result_finish + ;; +esac +case "$FASTCV_TEST_TIMEOUT" in + ''|*[!0-9]*|0) + test_result_record "FAIL" "FastCV timeout must be a positive integer, observed=${FASTCV_TEST_TIMEOUT:-empty}" + test_result_finish + ;; +esac + +if ! validate_boolean_option \ + "--operation-tables-only" \ + "$FASTCV_TEST_OPERATION_TABLES_ONLY" || + ! validate_boolean_option \ + "--no-buffer-pool" \ + "$FASTCV_TEST_NO_BUFFER_POOL" || + ! validate_boolean_option \ + "--opencv" \ + "$FASTCV_TEST_OPENCV" || + ! validate_boolean_option \ + "--unit-only" \ + "$FASTCV_TEST_UNIT_ONLY" || + ! validate_boolean_option \ + "--profile-only" \ + "$FASTCV_TEST_PROFILE_ONLY" || + ! validate_boolean_option \ + "--exhaustive" \ + "$FASTCV_TEST_EXHAUSTIVE" || + ! validate_boolean_option \ + "--qdsp-heap" \ + "$FASTCV_TEST_QDSP_HEAP" || + ! validate_boolean_option \ + "--element-alignment" \ + "$FASTCV_TEST_ELEMENT_ALIGNMENT" || + ! validate_boolean_option \ + "--cache-flush" \ + "$FASTCV_TEST_CACHE_FLUSH" || + ! validate_boolean_option \ + "--without-operation-mode" \ + "$FASTCV_TEST_WITHOUT_OPERATION_MODE"; then + test_result_record \ + "FAIL" \ + "FastCV boolean option validation failed" + test_result_finish +fi + +case "$FASTCV_TEST_FUNCTION" in + ''|*[!A-Za-z0-9_]*) + if [ -n "$FASTCV_TEST_FUNCTION" ]; then + test_result_record \ + "FAIL" \ + "FastCV function selector contains unsupported characters, function=$FASTCV_TEST_FUNCTION" + test_result_finish + fi + ;; +esac +case "$FASTCV_TEST_OPERATION_MODE" in + ''|0|1|2|3|4|5|6|7|8) + ;; + *) + test_result_record \ + "FAIL" \ + "FastCV operation mode must be empty or 0 through 8, observed=$FASTCV_TEST_OPERATION_MODE" + test_result_finish + ;; +esac +if [ "$FASTCV_TEST_OPERATION_TABLES_ONLY" -eq 1 ] && + { [ -z "$FASTCV_TEST_OPERATION_MODE" ] || + [ "$FASTCV_TEST_OPERATION_MODE" -eq 0 ]; }; then + test_result_record \ + "FAIL" \ + "FastCV operation-tables-only mode requires a nonzero --operation-mode" + test_result_finish +fi +case "$FASTCV_TEST_SEED" in + '') + ;; + -*) + seed_digits=${FASTCV_TEST_SEED#-} + case "$seed_digits" in + ''|*[!0-9]*) + test_result_record "FAIL" "FastCV seed must be an integer, observed=$FASTCV_TEST_SEED" + test_result_finish + ;; + esac + ;; + *[!0-9]*) + test_result_record "FAIL" "FastCV seed must be an integer, observed=$FASTCV_TEST_SEED" + test_result_finish + ;; +esac +case "$FASTCV_TEST_PREALLOC_BYTES" in + '') + ;; + *[!0-9]*|0) + test_result_record \ + "FAIL" \ + "FastCV preallocation size must be a positive integer, observed=$FASTCV_TEST_PREALLOC_BYTES" + test_result_finish + ;; +esac +case "$FASTCV_TEST_RESOLUTION" in + ''|0|1|2|3|4|5|6|7) + ;; + *) + test_result_record \ + "FAIL" \ + "FastCV resolution selector must be empty or 0 through 7, observed=$FASTCV_TEST_RESOLUTION" + test_result_finish + ;; +esac +if [ "$FASTCV_TEST_UNIT_ONLY" -eq 1 ] && + [ "$FASTCV_TEST_PROFILE_ONLY" -eq 1 ]; then + test_result_record \ + "FAIL" \ + "FastCV unit-only and profile-only modes cannot be enabled together" + test_result_finish +fi +if [ "$FASTCV_TEST_NO_BUFFER_POOL" -eq 1 ] && + [ -n "$FASTCV_TEST_PREALLOC_BYTES" ]; then + test_result_record \ + "FAIL" \ + "FastCV preallocated buffer bytes cannot be combined with no-buffer-pool mode" + test_result_finish +fi + +if [ ! -e "$FASTCV_TEST_BINARY" ]; then + test_result_record \ + "FAIL" \ + "Sideloaded fastcv_test binary does not exist, binary=$FASTCV_TEST_BINARY" + test_result_finish +fi +if [ ! -f "$FASTCV_TEST_BINARY" ]; then + test_result_record \ + "FAIL" \ + "Sideloaded fastcv_test binary path is not a regular file, binary=$FASTCV_TEST_BINARY" + test_result_finish +fi +if [ ! -x "$FASTCV_TEST_BINARY" ]; then + test_result_record \ + "FAIL" \ + "Sideloaded fastcv_test binary is not executable, binary=$FASTCV_TEST_BINARY" + test_result_finish +fi +if [ ! -d "$FASTCV_TEST_DATA_DIR" ]; then + test_result_record \ + "FAIL" \ + "Sideloaded FastCV data path is not a directory, data_dir=$FASTCV_TEST_DATA_DIR" + test_result_finish +fi +if [ ! -r "$FASTCV_TEST_DATA_DIR" ]; then + test_result_record \ + "FAIL" \ + "Sideloaded FastCV data directory is not readable, data_dir=$FASTCV_TEST_DATA_DIR" + test_result_finish +fi + +CONTROL_TABLE="$FASTCV_TEST_DATA_DIR/FastCVTestTable.csv" +if [ ! -r "$CONTROL_TABLE" ]; then + test_result_record \ + "FAIL" \ + "Sideloaded FastCV data directory is missing the readable FastCVTestTable.csv control file, expected=$CONTROL_TABLE" + test_result_finish +fi + +fastcv_prepare_runtime_packages +fastcv_package_rc=$? +case "$fastcv_package_rc" in + 0|2) + ;; + *) + test_result_record \ + "FAIL" \ + "FastCV runtime package preparation failed, os=$(pkg_detect_os_id) set=fastcv-runtime" + test_result_finish + ;; +esac + +if ! find "$FASTCV_TEST_DATA_DIR" -type f -print >"$DATA_REPORT" 2>/dev/null; then + test_result_record \ + "FAIL" \ + "Could not enumerate the sideloaded FastCV data directory, data_dir=$FASTCV_TEST_DATA_DIR artifact=$DATA_REPORT" + test_result_finish +fi +data_file_count=$(wc -l <"$DATA_REPORT" 2>/dev/null | tr -d '[:space:]') +if [ "${data_file_count:-0}" -eq 0 ]; then + test_result_record \ + "FAIL" \ + "Sideloaded FastCV data directory contains no files, data_dir=$FASTCV_TEST_DATA_DIR artifact=$DATA_REPORT" + test_result_finish +fi + +{ + printf 'binary=%s\n' "$FASTCV_TEST_BINARY" + printf 'architecture=%s\n' "$(uname -m 2>/dev/null || printf 'unknown')" + ls -l "$FASTCV_TEST_BINARY" 2>&1 +} >"$BINARY_REPORT" +log_info "[FASTCV-FIXTURE] binary=$FASTCV_TEST_BINARY executable=1 data_dir=$FASTCV_TEST_DATA_DIR control_table=$CONTROL_TABLE control_table_readable=1 data_files=$data_file_count binary_artifact=$BINARY_REPORT data_artifact=$DATA_REPORT" +log_file_with_label "FASTCV-BINARY" "$BINARY_REPORT" 10 +log_file_with_label "FASTCV-DATA" "$DATA_REPORT" 12 + +if ! prepare_target_list "$FASTCV_TEST_TARGETS" "$TARGET_LIST"; then + test_result_record \ + "FAIL" \ + "FastCV target selection is invalid, requested=${FASTCV_TEST_TARGETS:-empty} accepted=0,2,4,6,8 artifact=$TARGET_LIST" + test_result_finish +fi +if ! prepare_module_list "$FASTCV_TEST_MODULES" "$MODULE_LIST"; then + test_result_record \ + "FAIL" \ + "FastCV module selection is invalid, requested=${FASTCV_TEST_MODULES:-empty} artifact=$MODULE_LIST" + test_result_finish +fi +log_file_with_label "FASTCV-TARGET" "$TARGET_LIST" 10 +log_file_with_label "FASTCV-MODULE" "$MODULE_LIST" 80 + +if grep -Fxq "0" "$TARGET_LIST" 2>/dev/null && + grep -Fxq "ALL" "$MODULE_LIST" 2>/dev/null; then + log_warn "[FASTCV-SELECTION] mode=full-target-full-module runtime=potentially-long output=replayed-after-completion timeout=${FASTCV_TEST_TIMEOUT}s" +fi + +target_count=$(wc -l <"$TARGET_LIST" 2>/dev/null | tr -d '[:space:]') +module_count=$(wc -l <"$MODULE_LIST" 2>/dev/null | tr -d '[:space:]') +if [ -n "$FASTCV_TEST_FUNCTION" ]; then + selected_module=$(sed -n '1p' "$MODULE_LIST") + if [ "$module_count" -ne 1 ] || [ "$selected_module" = "ALL" ]; then + test_result_record \ + "FAIL" \ + "FastCV function selection requires exactly one focused module, function=$FASTCV_TEST_FUNCTION requested_modules=$FASTCV_TEST_MODULES normalized_modules=$module_count" + test_result_finish + fi +fi +case_count=$((target_count * module_count)) +if [ "$case_count" -gt "$FASTCV_TEST_MAX_CASES" ]; then + test_result_record \ + "FAIL" \ + "FastCV selection exceeds the bounded invocation limit, requested=$case_count maximum=$FASTCV_TEST_MAX_CASES targets=$target_count modules=$module_count" + test_result_finish +fi +log_info "[FASTCV-SELECTION] targets=$target_count modules=$module_count invocations=$case_count dsp_target_selected=$DSP_TARGET_SELECTED target_artifact=$TARGET_LIST module_artifact=$MODULE_LIST" + +while IFS= read -r fastcv_target; do + while IFS= read -r fastcv_module; do + run_fastcv_test_case "$fastcv_target" "$fastcv_module" || true + done <"$MODULE_LIST" +done <"$TARGET_LIST" + +if [ "$DSP_TARGET_SELECTED" -eq 1 ]; then + KERNEL_LOG_JOURNAL_FALLBACK=1 + export KERNEL_LOG_JOURNAL_FALLBACK + scan_dmesg_errors \ + "$RESULT_DIR/kernel" \ + "fastrpc|adsprpc|cdsprpc" \ + "not a crash|subsys-restart" + dmesg_rc=$? + + if [ "${DMESG_ACCESS_STATUS:-unknown}" != "available" ]; then + test_result_record \ + "SKIP" \ + "Kernel log access is unavailable for FastCV DSP health validation, status=${DMESG_ACCESS_STATUS:-unknown} provider=${DMESG_ACCESS_PROVIDER:-none} rc=${DMESG_ACCESS_RC:-unknown} artifact=${DMESG_ACCESS_LOG:-$RESULT_DIR/kernel/dmesg_access.log}" + elif [ "$dmesg_rc" -eq 0 ]; then + test_result_record \ + "FAIL" \ + "FastRPC-related kernel errors were found during FastCV DSP validation, artifact=$RESULT_DIR/kernel/dmesg_errors.log" + else + test_result_record \ + "PASS" \ + "No persistent FastRPC kernel errors were found during FastCV DSP validation" + fi +else + log_info "[FASTCV-KERNEL] action=not-required reason=no-dsp-capable-target-selected" +fi + +test_result_finish diff --git a/Runner/suites/Multimedia/FastCV/FastCV_Simple_Deinterleave_Validation/FastCV_Simple_Deinterleave_Validation.yaml b/Runner/suites/Multimedia/FastCV/FastCV_Simple_Deinterleave_Validation/FastCV_Simple_Deinterleave_Validation.yaml new file mode 100755 index 00000000..e82add5b --- /dev/null +++ b/Runner/suites/Multimedia/FastCV/FastCV_Simple_Deinterleave_Validation/FastCV_Simple_Deinterleave_Validation.yaml @@ -0,0 +1,19 @@ +metadata: + name: FastCV_Simple_Deinterleave_Validation + format: "Lava-Test Test Definition 1.0" + description: "Run fastcv_simple_test64 and validate its deinterleave data-integrity result" + os: + - linux + scope: + - functional + +params: + FASTCV_BINARY: "" + FASTCV_TIMEOUT: "60" + +run: + steps: + - REPO_PATH=$PWD + - cd Runner/suites/Multimedia/FastCV/FastCV_Simple_Deinterleave_Validation + - ./run.sh --binary "${FASTCV_BINARY}" --timeout "${FASTCV_TIMEOUT}" || true + - $REPO_PATH/Runner/utils/send-to-lava.sh FastCV_Simple_Deinterleave_Validation.res diff --git a/Runner/suites/Multimedia/FastCV/FastCV_Simple_Deinterleave_Validation/README.md b/Runner/suites/Multimedia/FastCV/FastCV_Simple_Deinterleave_Validation/README.md new file mode 100644 index 00000000..87e6e41f --- /dev/null +++ b/Runner/suites/Multimedia/FastCV/FastCV_Simple_Deinterleave_Validation/README.md @@ -0,0 +1,162 @@ +# FastCV Simple Deinterleave Validation + +This suite runs the image-provided `fastcv_simple_test64` utility as a bounded +FastCV functional regression. It validates the utility status and its exact +deinterleave data-integrity result instead of treating binary or library +presence as a functional pass. + +## Coverage + +The suite: + +- discovers `fastcv_simple_test64` using CLI, environment, then `PATH` + precedence; +- runs the utility with a configurable timeout; +- requires a zero process status; +- requires the exact `Results match, Deinterleave Test passed` marker; +- rejects the exact `Results mismatch, Deinterleave Test failed` marker; +- retains and replays bounded utility output; and +- captures one FastRPC-related kernel-log snapshot through + `scan_dmesg_errors`. + +The public meta-qcom 1.8.9 recipe packages this utility in `fastcv-apps` and +installs it as `/usr/bin/fastcv_simple_test64`. General-purpose distribution +package layouts can differ, so the suite verifies the installed executable +after runtime package preparation. + +The inspected 1.8.9 utility selects FastCV CPU performance mode. This suite +therefore proves FastCV API execution and deinterleave data integrity, but it +does **not** prove CDSP offload. CDSP validation requires a separate utility +that explicitly selects `FASTCV_OP_EXT_CDSP`, performs an operation, and +provides observable offload evidence. + +## Portability and prerequisites + +The suite is intended for Yocto, Debian, Ubuntu, CentOS, and Red Hat targets. + +On Yocto and other image-managed systems, the suite performs no package-manager +operations. The validation ramdisk or image must already contain the FastCV +libraries and `fastcv_simple_test64`. + +On Debian and Ubuntu, the suite checks and installs these missing packages: + +```text +qcom-fastcv-binaries libfastcvopt-dev +``` + +On CentOS Stream 10 and compatible Red Hat Enterprise Linux 10 aarch64 systems, +it first installs `epel-release`, then ensures that the Qualcomm CentOS 10 +`aarch64` and `noarch` repositories are enabled: + +```text +https://softwarecenter.qualcomm.com/nexus/rpm/centos/10/os/aarch64/ +https://softwarecenter.qualcomm.com/nexus/rpm/centos/10/os/noarch/ +``` + +When needed, their definitions are written to +`/etc/yum.repos.d/qualcomm-linux.repo`. The suite then checks and installs: + +```text +qcom-fastcv-binaries libfastcvopt-devel +``` + +No installed package is upgraded. Package recovery needs root privileges, +network access, and working distro repositories only when a required package +or repository is missing. An incomplete pre-existing Qualcomm repository +configuration fails rather than being overwritten. +The RPM path also verifies that the `epel` repository is enabled after +installing `epel-release`. Automatic repository creation is rejected on other +CentOS or Red Hat major versions because the configured repository URLs are +specific to version 10. + +After package preparation, the selected package split must provide +`fastcv_simple_test64` in `PATH`. The suite verifies this dynamically before +execution. To inspect it manually: + +```sh +command -v fastcv_simple_test64 +fastcv_simple_test64 +``` + +If the optional FastCV utility is absent from automatic discovery, the test +skips cleanly. An explicitly requested missing binary fails because the +override declares that binary as required. + +The `--binary` override must identify the packaged `fastcv_simple_test64` +deinterleave utility. It must not point to the separately sideloaded +`fastcv_test` module runner, which requires a test-data directory and exposes a +different CLI and result-marker contract. The suite detects that module CLI and +fails with an explicit wrong-binary diagnostic. + +A present utility that cannot execute, times out, exits nonzero, reports a +mismatch, or omits its success marker fails the functional check. + +## Usage + +Run with automatic discovery: + +```sh +./run.sh +``` + +On a supported general-purpose distribution, this command also performs the +automatic missing-package and repository preparation described above. +Use `sudo ./run.sh` when that preparation is needed and the current shell is +not already root. + +Select a utility explicitly: + +```sh +./run.sh --binary /usr/bin/fastcv_simple_test64 +``` + +The following is intentionally invalid because `fastcv_test` is the separate +module runner and requires its matching test-data directory: + +```sh +./run.sh --binary /var/fastcv/fastcv_test +``` + +Change the execution bound: + +```sh +./run.sh --timeout 90 +``` + +Environment equivalents are `FASTCV_BINARY` and `FASTCV_TIMEOUT`. CLI values +take precedence over environment values. An empty binary value keeps automatic +discovery enabled. + +## Results + +- **PASS**: the utility exits zero, reports at least one exact success marker, + and reports no exact mismatch marker. +- **FAIL**: required host-distribution package recovery fails, an explicitly + requested binary is absent, the discovered binary is not executable, + execution fails or exceeds the timeout, a mismatch is reported, or the + required success marker is absent. +- **SKIP**: automatic discovery finds no image-provided utility. Kernel-log + health is also a separate SKIP when the target does not expose readable + kernel logs. + +Kernel errors matched for FastRPC support are reported as a separate failure +and do not change the scope into a CDSP-offload claim. + +## Evidence + +Each run stores artifacts below: + +```text +results/FastCV_Simple_Deinterleave_Validation/run--/ +``` + +Artifacts include: + +- `fastcv_binary.log`: selected path, source, architecture, and file metadata; +- `fastcv_simple_test.log`: complete utility stdout and stderr; +- `kernel/dmesg_snapshot.log`: captured kernel log when access is available; +- `kernel/dmesg_errors.log`: filtered FastRPC-related errors; and +- `kernel/dmesg_access.log`: kernel-log provider and access diagnostics. + +Live stdout includes the selection source, bounded utility output, exit status, +marker counts, artifact paths, and final PASS, FAIL, or SKIP reasons. diff --git a/Runner/suites/Multimedia/FastCV/FastCV_Simple_Deinterleave_Validation/run.sh b/Runner/suites/Multimedia/FastCV/FastCV_Simple_Deinterleave_Validation/run.sh new file mode 100755 index 00000000..9ba90e25 --- /dev/null +++ b/Runner/suites/Multimedia/FastCV/FastCV_Simple_Deinterleave_Validation/run.sh @@ -0,0 +1,284 @@ +#!/bin/sh +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause + +# ---------- Repo env + helpers ---------- +SCRIPT_DIR="$( + cd "$(dirname "$0")" || exit 1 + pwd +)" +INIT_ENV="" +SEARCH="$SCRIPT_DIR" + +while [ "$SEARCH" != "/" ]; do + if [ -f "$SEARCH/init_env" ]; then + INIT_ENV="$SEARCH/init_env" + break + fi + SEARCH=$(dirname "$SEARCH") +done + +if [ -z "$INIT_ENV" ]; then + echo "[ERROR] Could not find init_env (starting at $SCRIPT_DIR)" >&2 + exit 1 +fi + +# Only source once (idempotent) +# NOTE: We intentionally **do not export** any new vars. They stay local to this shell. +if [ -z "${__INIT_ENV_LOADED:-}" ]; then + # shellcheck disable=SC1090 + . "$INIT_ENV" + __INIT_ENV_LOADED=1 +fi + +# shellcheck disable=SC1090 +. "$INIT_ENV" +# shellcheck disable=SC1091 +. "$TOOLS/functestlib.sh" +# shellcheck disable=SC1091 +. "$TOOLS/lib_pkg_provider.sh" +# shellcheck disable=SC1091 +. "$TOOLS/lib_fastcv.sh" +TESTNAME="FastCV_Simple_Deinterleave_Validation" +RES_FILE="$SCRIPT_DIR/$TESTNAME.res" + +FASTCV_BINARY="${FASTCV_BINARY:-}" +FASTCV_TIMEOUT="${FASTCV_TIMEOUT:-60}" +FASTCV_BINARY_SOURCE="dynamic-discovery" +RESULT_DIR="$SCRIPT_DIR/results/$TESTNAME/run-$(date '+%Y%m%d-%H%M%S')-$$" +RUN_LOG="$RESULT_DIR/fastcv_simple_test.log" +BINARY_REPORT="$RESULT_DIR/fastcv_binary.log" +SUCCESS_MARKER="Results match, Deinterleave Test passed" +FAILURE_MARKER="Results mismatch, Deinterleave Test failed" + +if [ -n "$FASTCV_BINARY" ]; then + FASTCV_BINARY_SOURCE="environment" +fi + +# usage +# Print FastCV CLI options and automatic binary-discovery behavior. +# Inputs: none. Output: help text on stdout. Returns: 0. Side effects: none. +usage() { + printf '%s\n' \ + "Usage: ./run.sh [options]" \ + " --binary PATH Override the FastCV utility path" \ + " --timeout SECONDS Bound the utility runtime, default: 60" \ + " -h, --help" \ + "Binary selection precedence is CLI, FASTCV_BINARY, then PATH." \ + "The packaged utility validates FastCV data integrity and does not prove CDSP offload." +} + +# parse_args ARG... +# Parse CLI overrides into the FastCV binary and timeout globals. +# Inputs: command-line arguments. Output: no stdout. +# Returns: 0 on success, 2 for invalid input, or exits after help. +# Side effects: updates FASTCV_BINARY, FASTCV_BINARY_SOURCE, and FASTCV_TIMEOUT. +parse_args() { + while [ "$#" -gt 0 ]; do + case "$1" in + --binary) + [ "$#" -ge 2 ] || return 2 + FASTCV_BINARY="$2" + if [ -n "$FASTCV_BINARY" ]; then + FASTCV_BINARY_SOURCE="cli" + else + FASTCV_BINARY_SOURCE="dynamic-discovery" + fi + shift 2 + ;; + --timeout) + [ "$#" -ge 2 ] || return 2 + FASTCV_TIMEOUT="$2" + shift 2 + ;; + -h|--help) + usage + exit 0 + ;; + *) + log_error "Unknown argument: $1" + return 2 + ;; + esac + done +} + +parse_args "$@" || { + usage >&2 + exit 2 +} + +test_result_init "$TESTNAME" "$RES_FILE" || exit 1 + +if ! mkdir -p "$RESULT_DIR"; then + test_result_finish \ + "FAIL" \ + "$TESTNAME FAIL: cannot create retained evidence directory $RESULT_DIR" +fi + +log_info "--------------------------------------------------------------------------" +log_info "Starting $TESTNAME" +log_info "Evidence directory: $RESULT_DIR" +log_info "FastCV simple deinterleave validation: running fastcv_simple_test64 with bounded execution and exact result-marker checks" +log_info "[FASTCV-POLICY] applicability=dynamic operation=deinterleave-data-integrity timeout=${FASTCV_TIMEOUT}s offload_claim=none" + +case "$FASTCV_TIMEOUT" in + ''|*[!0-9]*|0) + test_result_record \ + "FAIL" \ + "FastCV configuration is invalid, timeout must be a positive integer" + test_result_finish + ;; +esac + +fastcv_prepare_runtime_packages +fastcv_package_rc=$? +case "$fastcv_package_rc" in + 0|2) + ;; + *) + test_result_record \ + "FAIL" \ + "FastCV runtime package preparation failed, os=$(pkg_detect_os_id) set=fastcv-runtime" + test_result_finish + ;; +esac + +FASTCV_BINARY_PATH="" +if [ -n "$FASTCV_BINARY" ]; then + case "$FASTCV_BINARY" in + */*) + FASTCV_BINARY_PATH="$FASTCV_BINARY" + ;; + *) + FASTCV_BINARY_PATH=$(command -v "$FASTCV_BINARY" 2>/dev/null || true) + ;; + esac +else + FASTCV_BINARY_PATH=$(command -v fastcv_simple_test64 2>/dev/null || true) + if [ -n "$FASTCV_BINARY_PATH" ]; then + FASTCV_BINARY_SOURCE="path-discovery" + fi +fi + +if [ -z "$FASTCV_BINARY_PATH" ] || [ ! -e "$FASTCV_BINARY_PATH" ]; then + log_info "[FASTCV-DISCOVERY] selected=none source=$FASTCV_BINARY_SOURCE path_candidate=fastcv_simple_test64" + case "$FASTCV_BINARY_SOURCE" in + cli|environment) + test_result_record \ + "FAIL" \ + "Requested FastCV utility is not present, requested=${FASTCV_BINARY:-empty} source=$FASTCV_BINARY_SOURCE" + ;; + *) + test_result_record \ + "SKIP" \ + "FastCV utility fastcv_simple_test64 is not installed in PATH" + ;; + esac + test_result_finish +fi + +if [ ! -f "$FASTCV_BINARY_PATH" ]; then + log_info "[FASTCV-DISCOVERY] selected=$FASTCV_BINARY_PATH source=$FASTCV_BINARY_SOURCE regular_file=0" + test_result_record \ + "FAIL" \ + "FastCV utility path is not a regular file, binary=$FASTCV_BINARY_PATH source=$FASTCV_BINARY_SOURCE" + test_result_finish +fi + +if [ ! -x "$FASTCV_BINARY_PATH" ]; then + log_info "[FASTCV-DISCOVERY] selected=$FASTCV_BINARY_PATH source=$FASTCV_BINARY_SOURCE executable=0" + test_result_record \ + "FAIL" \ + "FastCV utility exists but is not executable, binary=$FASTCV_BINARY_PATH source=$FASTCV_BINARY_SOURCE" + test_result_finish +fi + +{ + printf 'binary=%s\n' "$FASTCV_BINARY_PATH" + printf 'source=%s\n' "$FASTCV_BINARY_SOURCE" + printf 'architecture=%s\n' "$(uname -m 2>/dev/null || printf 'unknown')" + ls -l "$FASTCV_BINARY_PATH" 2>&1 +} >"$BINARY_REPORT" + +log_info "[FASTCV-DISCOVERY] selected=$FASTCV_BINARY_PATH source=$FASTCV_BINARY_SOURCE executable=1 artifact=$BINARY_REPORT" +log_file_with_label "FASTCV-BINARY" "$BINARY_REPORT" 10 +log_info "[FASTCV-FUNCTIONAL] phase=start binary=$FASTCV_BINARY_PATH timeout=${FASTCV_TIMEOUT}s expected_marker=$SUCCESS_MARKER" + +run_with_timeout_log "$FASTCV_TIMEOUT" "$RUN_LOG" "$FASTCV_BINARY_PATH" +fastcv_rc=$? +log_file_with_label "FASTCV-OUTPUT" "$RUN_LOG" 80 + +success_count=$(grep -F -c "$SUCCESS_MARKER" "$RUN_LOG" 2>/dev/null || true) +failure_count=$(grep -F -c "$FAILURE_MARKER" "$RUN_LOG" 2>/dev/null || true) +module_cli_count=$(grep -E -c '^USAGE: .*test_data_directory' "$RUN_LOG" 2>/dev/null || true) +output_bytes=$(wc -c <"$RUN_LOG" 2>/dev/null | tr -d '[:space:]') + +case "$success_count" in + ''|*[!0-9]*) + success_count=0 + ;; +esac +case "$failure_count" in + ''|*[!0-9]*) + failure_count=0 + ;; +esac +case "$module_cli_count" in + ''|*[!0-9]*) + module_cli_count=0 + ;; +esac +case "$output_bytes" in + ''|*[!0-9]*) + output_bytes=0 + ;; +esac + +log_info "[FASTCV-FUNCTIONAL] phase=complete rc=$fastcv_rc success_markers=$success_count failure_markers=$failure_count module_cli_markers=$module_cli_count output_bytes=$output_bytes artifact=$RUN_LOG" + +if [ "$module_cli_count" -gt 0 ]; then + test_result_record \ + "FAIL" \ + "Selected executable exposes the fastcv_test module CLI instead of the packaged fastcv_simple_test64 deinterleave contract, binary=$FASTCV_BINARY_PATH artifact=$RUN_LOG" +elif [ "$fastcv_rc" -ne 0 ]; then + test_result_record \ + "FAIL" \ + "FastCV utility failed or exceeded the ${FASTCV_TIMEOUT}s execution bound, rc=$fastcv_rc artifact=$RUN_LOG" +elif [ "$failure_count" -gt 0 ]; then + test_result_record \ + "FAIL" \ + "FastCV utility reported a deinterleave data mismatch, failure_markers=$failure_count artifact=$RUN_LOG" +elif [ "$success_count" -eq 0 ]; then + test_result_record \ + "FAIL" \ + "FastCV utility exited successfully but did not report the required deinterleave success marker, artifact=$RUN_LOG" +else + test_result_record \ + "PASS" \ + "FastCV completed deinterleave data-integrity validation, success_markers=$success_count binary=$FASTCV_BINARY_PATH" +fi + +KERNEL_LOG_JOURNAL_FALLBACK=1 +export KERNEL_LOG_JOURNAL_FALLBACK +scan_dmesg_errors \ + "$RESULT_DIR/kernel" \ + "fastrpc|adsprpc|cdsprpc" \ + "not a crash|subsys-restart" +dmesg_rc=$? + +if [ "${DMESG_ACCESS_STATUS:-unknown}" != "available" ]; then + test_result_record \ + "SKIP" \ + "Kernel log access is unavailable for FastCV runtime health validation, status=${DMESG_ACCESS_STATUS:-unknown} provider=${DMESG_ACCESS_PROVIDER:-none} rc=${DMESG_ACCESS_RC:-unknown} artifact=${DMESG_ACCESS_LOG:-$RESULT_DIR/kernel/dmesg_access.log}" +elif [ "$dmesg_rc" -eq 0 ]; then + test_result_record \ + "FAIL" \ + "FastRPC-related kernel errors were found during FastCV validation, artifact=$RESULT_DIR/kernel/dmesg_errors.log" +else + test_result_record \ + "PASS" \ + "No persistent FastRPC kernel errors were found during FastCV validation" +fi + +test_result_finish diff --git a/Runner/utils/lib_fastcv.sh b/Runner/utils/lib_fastcv.sh new file mode 100755 index 00000000..4b0375d2 --- /dev/null +++ b/Runner/utils/lib_fastcv.sh @@ -0,0 +1,167 @@ +#!/bin/sh +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause + +# fastcv_collect_test_markers LOG_FILE MODULE FUNCTION WITHOUT_OPERATION_MODE +# Classify success and failure markers emitted by supported fastcv_test builds. +# Inputs: a readable command log, the selected module, an optional function, +# and a 0/1 without-operation-mode flag. Output: no stdout. +# Returns: 0 after parsing or 1 when the log is unreadable. +# Side effects: updates FASTCV_MARKER_FAILURE_COUNT, FASTCV_MARKER_FIT_COUNT, +# FASTCV_MARKER_PROFILE_SUMMARY_COUNT, FASTCV_MARKER_PROFILE_CASE_PASS_COUNT, +# FASTCV_MARKER_MODULE_COUNT, FASTCV_MARKER_FUNCTION_COUNT, and +# FASTCV_MARKER_WITHOUT_MODE_COUNT for the caller. +fastcv_collect_test_markers() { + fcctm_log="$1" + fcctm_module="$2" + fcctm_function="$3" + fcctm_without_mode="$4" + + FASTCV_MARKER_FAILURE_COUNT=0 + FASTCV_MARKER_FIT_COUNT=0 + FASTCV_MARKER_PROFILE_SUMMARY_COUNT=0 + FASTCV_MARKER_PROFILE_CASE_PASS_COUNT=0 + FASTCV_MARKER_MODULE_COUNT=0 + FASTCV_MARKER_FUNCTION_COUNT=0 + FASTCV_MARKER_WITHOUT_MODE_COUNT=0 + fcctm_profile_function_count=0 + + [ -r "$fcctm_log" ] || return 1 + + # Exported result state for suite callers. + # shellcheck disable=SC2034 + FASTCV_MARKER_FAILURE_COUNT=$(grep -E -c \ + '(^FASTCV_TEST, .*=>FAIL[[:space:]]*$)|(^FASTCV_PROFILE, .* :: FAIL([,[:space:]]|$))|(^((FASTCV_PROFILE, )?FIT:\(FeatureName=>FASTCV, Overall=>FAIL\))[[:space:]]*$)' \ + "$fcctm_log" 2>/dev/null || true) + # Exported result state for suite callers. + # shellcheck disable=SC2034 + FASTCV_MARKER_FIT_COUNT=$(grep -E -c \ + '^FIT:\(FeatureName=>FASTCV, Overall=>PASS\)[[:space:]]*$' \ + "$fcctm_log" 2>/dev/null || true) + # Exported result state for suite callers. + # shellcheck disable=SC2034 + FASTCV_MARKER_PROFILE_SUMMARY_COUNT=$(grep -E -c \ + '^FASTCV_PROFILE, FIT:\(FeatureName=>FASTCV, Overall=>PASS\)[[:space:]]*$' \ + "$fcctm_log" 2>/dev/null || true) + # Exported result state for suite callers. + # shellcheck disable=SC2034 + FASTCV_MARKER_PROFILE_CASE_PASS_COUNT=$(grep -E -c \ + '^FASTCV_PROFILE, .+ :: PASS(,|[[:space:]]*$)' \ + "$fcctm_log" 2>/dev/null || true) + + if [ "$fcctm_module" = "ALL" ]; then + # Exported result state for suite callers. + # shellcheck disable=SC2034 + FASTCV_MARKER_MODULE_COUNT=$(grep -E -c \ + '^FASTCV_TEST, [^=]+=>PASS[[:space:]]*$' \ + "$fcctm_log" 2>/dev/null || true) + else + # Exported result state for suite callers. + # shellcheck disable=SC2034 + FASTCV_MARKER_MODULE_COUNT=$(grep -F -c \ + "FASTCV_TEST, $fcctm_module=>PASS" \ + "$fcctm_log" 2>/dev/null || true) + fi + + if [ -n "$fcctm_function" ]; then + FASTCV_MARKER_FUNCTION_COUNT=$(grep -E -c \ + "^Function chosen: ${fcctm_function}[[:space:]]*$" \ + "$fcctm_log" 2>/dev/null || true) + fcctm_profile_function_count=$(grep -E -c \ + "^FASTCV_PROFILE, $fcctm_function :: PASS(,|[[:space:]]*$)" \ + "$fcctm_log" 2>/dev/null || true) + FASTCV_MARKER_FUNCTION_COUNT=$(( + FASTCV_MARKER_FUNCTION_COUNT + + fcctm_profile_function_count + )) + fi + + if [ "$fcctm_without_mode" -eq 1 ]; then + # Exported result state for suite callers. + # shellcheck disable=SC2034 + FASTCV_MARKER_WITHOUT_MODE_COUNT=$(grep -F -c \ + 'Running fastCV API without calling setOperationMode is pass' \ + "$fcctm_log" 2>/dev/null || true) + fi + + return 0 +} + +# fastcv_prepare_runtime_packages +# Ensure the FastCV runtime package set on supported host distributions. +# Inputs: none. Output: no machine-readable stdout contract. +# Returns: 0 when packages are ready, 1 when required recovery fails, and 2 +# when the target is an image-managed or otherwise unsupported distribution. +# Side effects: may configure Qualcomm RPM repositories on CentOS/RHEL and may +# install mapped packages through lib_pkg_provider.sh. Package-set upgrades are +# disabled for this operation and the prior policy is restored before return. +# Yocto remains unchanged. +fastcv_prepare_runtime_packages() { + fcprp_os_id="$(pkg_detect_os_id)" + + for fcprp_helper in \ + pkg_provider_init \ + pkg_ensure_host_distro_package_set_present \ + pkg_ensure_required_package_set_present \ + pkg_verify_package_set_installed \ + pkg_package_recovery_supported_os; do + if ! command -v "$fcprp_helper" >/dev/null 2>&1; then + log_error "FastCV package preparation helper is unavailable: $fcprp_helper" + return 1 + fi + done + + if ! pkg_package_recovery_supported_os "$fcprp_os_id"; then + log_info "[FASTCV-PACKAGES] action=image-provided os=$fcprp_os_id set=fastcv-runtime" + return 2 + fi + + if ! pkg_provider_init; then + log_error "FastCV package provider initialization failed" + return 1 + fi + + if pkg_verify_package_set_installed fastcv-runtime; then + log_info "[FASTCV-PACKAGES] action=already-ready os=$fcprp_os_id set=fastcv-runtime upgrades=disabled" + return 0 + fi + + fcprp_previous_set_upgrade="$PKG_PACKAGE_SET_UPGRADE" + PKG_PACKAGE_SET_UPGRADE=0 + fcprp_rc=0 + + case "$fcprp_os_id" in + centos|rhel) + if ! command -v pkg_ensure_qualcomm_rpm_repository >/dev/null 2>&1; then + log_error "FastCV RPM repository preparation helper is unavailable" + fcprp_rc=1 + elif ! pkg_ensure_required_package_set_present \ + fastcv-rpm-prerequisites; then + log_error "FastCV EPEL repository prerequisite installation failed, os=$fcprp_os_id package=epel-release" + fcprp_rc=1 + elif ! command -v pkg_rpm_repository_enabled >/dev/null 2>&1; then + log_error "FastCV RPM repository verification helper is unavailable" + fcprp_rc=1 + elif ! pkg_rpm_repository_enabled epel; then + log_error "FastCV EPEL repository is not enabled after installing epel-release, os=$fcprp_os_id repository=epel" + fcprp_rc=1 + elif ! pkg_ensure_qualcomm_rpm_repository; then + fcprp_rc=1 + fi + ;; + esac + + if [ "$fcprp_rc" -eq 0 ] && + ! pkg_ensure_host_distro_package_set_present fastcv-runtime; then + fcprp_rc=1 + fi + + PKG_PACKAGE_SET_UPGRADE="$fcprp_previous_set_upgrade" + + if [ "$fcprp_rc" -ne 0 ]; then + return "$fcprp_rc" + fi + + log_info "[FASTCV-PACKAGES] action=ready os=$fcprp_os_id set=fastcv-runtime upgrades=disabled" + return 0 +} diff --git a/Runner/utils/lib_pkg_provider.sh b/Runner/utils/lib_pkg_provider.sh index 18918ea2..f3337b67 100755 --- a/Runner/utils/lib_pkg_provider.sh +++ b/Runner/utils/lib_pkg_provider.sh @@ -59,6 +59,9 @@ PKG_APT_AUTH_PASSWORD_FILE="/run/qcom-testkit/secrets/debusine_api_token" PKG_RPM_UPDATED_MARK="/tmp/qcom_testkit_rpm_updated" PKG_RPM_UPGRADED_MARK="/tmp/qcom_testkit_rpm_upgraded" PKG_RPM_BEST_EFFORT_CLEAN="1" +PKG_QCOM_RPM_REPO_FILE="${PKG_QCOM_RPM_REPO_FILE:-/etc/yum.repos.d/qualcomm-linux.repo}" +PKG_QCOM_RPM_AARCH64_BASEURL="${PKG_QCOM_RPM_AARCH64_BASEURL:-https://softwarecenter.qualcomm.com/nexus/rpm/centos/10/os/aarch64/}" +PKG_QCOM_RPM_NOARCH_BASEURL="${PKG_QCOM_RPM_NOARCH_BASEURL:-https://softwarecenter.qualcomm.com/nexus/rpm/centos/10/os/noarch/}" PKG_OPKG_UPDATED_MARK="/tmp/qcom_testkit_opkg_updated" @@ -526,7 +529,7 @@ pkg_package_recovery_supported_os() { recovery_os_id="$1" case "$recovery_os_id" in - debian|ubuntu|centos) + debian|ubuntu|centos|rhel) return 0 ;; *) @@ -1636,6 +1639,174 @@ pkg_rpm_tool() { return 1 } +# pkg_rpm_repository_enabled REPOSITORY_ID +# Check whether one exact RPM repository ID is enabled. +# Inputs: one repository ID containing letters, digits, `.`, `_`, or `-`, and +# not beginning with `-`. Output: no stdout contract. +# Returns: 0 when enabled, and 1 when the ID, RPM tool, or repository listing +# is unavailable. Side effects: invokes a read-only dnf/yum repository query. +pkg_rpm_repository_enabled() { + prre_repo_id="$1" + prre_tool="$(pkg_rpm_tool || true)" + + case "$prre_repo_id" in + ''|-*|*[!A-Za-z0-9._-]*) + return 1 + ;; + esac + [ -n "$prre_tool" ] || return 1 + + if ! prre_repo_list="$($prre_tool repolist enabled 2>/dev/null)"; then + return 1 + fi + + printf '%s\n' "$prre_repo_list" | + awk '{print $1}' | + grep -Fxq "$prre_repo_id" +} + +# pkg_ensure_qualcomm_rpm_repository +# Configure the Qualcomm CentOS 10 aarch64 and noarch RPM repositories. +# Inputs: none. Output: no machine-readable stdout contract. +# Returns: 0 when both repositories are already enabled or configured, and +# 1 when the RPM provider, privileges, architecture, OS version, or +# configuration fails. +# Side effects: may create PKG_QCOM_RPM_REPO_FILE and invalidate the RPM +# metadata-update marker. Existing repository definitions are not overwritten. +pkg_ensure_qualcomm_rpm_repository() { + qrr_os_id="$(pkg_detect_os_id)" + qrr_os_version="$(pkg_os_release_value VERSION_ID || true)" + qrr_provider="$(pkg_active_provider)" + qrr_arch="$(uname -m 2>/dev/null || true)" + qrr_tool="$(pkg_rpm_tool || true)" + + case "$qrr_os_id" in + centos|rhel) + ;; + *) + pkg_log_info "Qualcomm RPM repository setup is not applicable, os=$qrr_os_id" + return 0 + ;; + esac + + if [ "$qrr_provider" != "rpm" ] || [ -z "$qrr_tool" ]; then + pkg_log_fail "Qualcomm RPM repository setup requires dnf or yum, os=$qrr_os_id provider=$qrr_provider" + return 1 + fi + + if [ "$qrr_arch" != "aarch64" ]; then + pkg_log_fail "Qualcomm RPM repository is available only for aarch64 targets, architecture=${qrr_arch:-unknown}" + return 1 + fi + + if ! qrr_repo_list="$($qrr_tool repolist enabled 2>/dev/null)"; then + pkg_log_fail "Could not inspect enabled RPM repositories, tool=$qrr_tool" + return 1 + fi + qrr_aarch64_present=0 + qrr_noarch_present=0 + if printf '%s\n' "$qrr_repo_list" | + awk '{print $1}' | + grep -Fxq "qualcomm-linux-aarch64"; then + qrr_aarch64_present=1 + fi + if printf '%s\n' "$qrr_repo_list" | + awk '{print $1}' | + grep -Fxq "qualcomm-linux-noarch"; then + qrr_noarch_present=1 + fi + + if [ "$qrr_aarch64_present" -eq 1 ] && + [ "$qrr_noarch_present" -eq 1 ]; then + pkg_log_pass "Qualcomm RPM repositories are already configured" + return 0 + fi + + if [ "$qrr_aarch64_present" -ne "$qrr_noarch_present" ]; then + pkg_log_fail "Qualcomm RPM repository configuration is incomplete, aarch64=$qrr_aarch64_present noarch=$qrr_noarch_present" + return 1 + fi + + qrr_os_major=${qrr_os_version%%.*} + if [ "$qrr_os_major" != "10" ]; then + pkg_log_fail "Automatic Qualcomm RPM repository setup supports CentOS/RHEL major version 10, os=$qrr_os_id version=${qrr_os_version:-unknown}" + return 1 + fi + + if [ -e "$PKG_QCOM_RPM_REPO_FILE" ]; then + pkg_log_fail "Qualcomm RPM repository file already exists without both enabled repository IDs, path=$PKG_QCOM_RPM_REPO_FILE" + return 1 + fi + + if ! pkg_can_install; then + pkg_log_fail "Qualcomm RPM repository configuration requires root and package auto-install support" + return 1 + fi + + case "$PKG_QCOM_RPM_REPO_FILE" in + */*) + qrr_repo_dir=${PKG_QCOM_RPM_REPO_FILE%/*} + ;; + *) + qrr_repo_dir=. + ;; + esac + qrr_temp_file="$(mktemp "${TMPDIR:-/tmp}/qcom-linux-fastcv-repo.XXXXXX")" || { + pkg_log_fail "Could not allocate a temporary Qualcomm RPM repository file" + return 1 + } + + if ! mkdir -p "$qrr_repo_dir"; then + pkg_log_fail "Could not create RPM repository directory, path=$qrr_repo_dir" + rm -f "$qrr_temp_file" + return 1 + fi + + { + printf '%s\n' \ + '[qualcomm-linux-aarch64]' \ + 'name=Qualcomm Linux RPM Repository - CentOS Stream 10 (aarch64)' \ + "baseurl=$PKG_QCOM_RPM_AARCH64_BASEURL" \ + 'enabled=1' \ + 'gpgcheck=0' \ + 'priority=10' \ + '' \ + '[qualcomm-linux-noarch]' \ + 'name=Qualcomm Linux RPM Repository - CentOS Stream 10 (noarch)' \ + "baseurl=$PKG_QCOM_RPM_NOARCH_BASEURL" \ + 'enabled=1' \ + 'gpgcheck=0' \ + 'priority=10' + } >"$qrr_temp_file" + + if ! install -m 0644 "$qrr_temp_file" "$PKG_QCOM_RPM_REPO_FILE"; then + pkg_log_fail "Could not install Qualcomm RPM repository configuration, path=$PKG_QCOM_RPM_REPO_FILE" + rm -f "$qrr_temp_file" + return 1 + fi + rm -f "$qrr_temp_file" + rm -f "$PKG_RPM_UPDATED_MARK" 2>/dev/null || true + + if ! qrr_repo_list="$($qrr_tool repolist enabled 2>/dev/null)"; then + pkg_log_fail "Could not verify enabled Qualcomm RPM repositories, tool=$qrr_tool file=$PKG_QCOM_RPM_REPO_FILE" + rm -f "$PKG_QCOM_RPM_REPO_FILE" + return 1 + fi + if ! printf '%s\n' "$qrr_repo_list" | + awk '{print $1}' | + grep -Fxq "qualcomm-linux-aarch64" || + ! printf '%s\n' "$qrr_repo_list" | + awk '{print $1}' | + grep -Fxq "qualcomm-linux-noarch"; then + pkg_log_fail "Qualcomm RPM repository file was created but both repository IDs are not enabled, path=$PKG_QCOM_RPM_REPO_FILE" + rm -f "$PKG_QCOM_RPM_REPO_FILE" + return 1 + fi + + pkg_log_pass "Configured Qualcomm RPM repositories, file=$PKG_QCOM_RPM_REPO_FILE" + return 0 +} + # Refresh rpm metadata. pkg_rpm_update() { rpm_tool="$(pkg_rpm_tool || true)"