#!/usr/bin/env bash # Shared helpers for the conformance harness. Sourced by run.sh; not executed directly. # shellcheck shell=bash # --- Requirement-tagging convention (single source of truth) -------------------------- # A Chainsaw Test declares the requirement(s) it verifies with a per-requirement label: # # metadata: # labels: # conformance.home.k3s/R-NET-01: "true" # one label per verified R-* ID # annotations: # conformance.home.k3s/requirements: "R-NET-01, R-NET-02" # human summary # conformance.home.k3s/layer: "L2" # conformance.home.k3s/safety-critical: "false" # # The LABEL is authoritative and does double duty: # * `chainsaw test --selector conformance.home.k3s/R-NET-01=true` runs the subset. # * lib/coverage.py reads the same labels to map requirement -> verifying test(s). # The annotation is a convenience for humans/reports and MUST agree with the labels # (coverage.py flags a mismatch). This is the convention referenced in README.md. export CONF_LABEL_PREFIX="conformance.home.k3s" # Absolute path to the conformance root (dir containing run.sh). Set by run.sh. : "${CONF_ROOT:?CONF_ROOT must be set before sourcing common.sh}" # --- Test discovery ------------------------------------------------------------------- # Every leaf test is a directory containing a `chainsaw-test.yaml`. conf_all_test_files() { find "${CONF_ROOT}/tests" -type f -name 'chainsaw-test.yaml' 2>/dev/null | sort } # Directories of tests that carry ANY of the given requirement labels (space-separated # R-IDs). Used to translate `--requirements R-NET-01,R-NET-06` into a set of test dirs # so we run each matching test exactly once (union, deduplicated). conf_dirs_for_requirements() { local reqs="$1" f dir rid matched while IFS= read -r f; do [ -n "$f" ] || continue matched=0 for rid in $reqs; do # Match a label line: conformance.home.k3s/R-NET-01: "true" if grep -Eq "^[[:space:]]*${CONF_LABEL_PREFIX}/${rid}:[[:space:]]*[\"']?true" "$f"; then matched=1; break fi done [ "$matched" = 1 ] && dirname "$f" done < <(conf_all_test_files) | sort -u } # Directories for a given layer subtree: l1 | l2 | l3 | meta | all conf_dirs_for_layer() { local layer="$1" sub case "$layer" in all) find "${CONF_ROOT}/tests" -type f -name 'chainsaw-test.yaml' -exec dirname {} \; | sort -u ;; l1) sub="l1-rendering" ;; l2) sub="l2-behavioral" ;; l3) sub="l3-fault-injection" ;; meta) sub="meta" ;; *) echo "unknown layer: $layer" >&2; return 2 ;; esac if [ "$layer" != all ]; then find "${CONF_ROOT}/tests/${sub}" -type f -name 'chainsaw-test.yaml' -exec dirname {} \; 2>/dev/null | sort -u fi } # Normalize a comma/space separated requirement list to space-separated, uppercased. conf_normalize_reqs() { echo "$1" | tr ',' ' ' | tr '[:lower:]' '[:upper:]' | xargs } # Is a live cluster reachable? (Preflight for L1/L2/L3 execution.) conf_cluster_reachable() { command -v kubectl >/dev/null 2>&1 || return 1 kubectl cluster-info >/dev/null 2>&1 }