release prep: rc.1 baseline and gating updates

This commit is contained in:
2026-03-02 15:54:55 -05:00
parent 97a42c8802
commit f43b2b24b6
168 changed files with 14708 additions and 982 deletions

View File

@@ -3,37 +3,234 @@ set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT"
LAB_CONFIG="${ROOT}/../harness/lab/device_lab.yaml"
if [[ ! -f "$LAB_CONFIG" ]]; then
echo "missing lab config: $LAB_CONFIG" >&2
exit 1
fi
REPORT_DIR="${ROOT}/../harness/reports"
mkdir -p "$REPORT_DIR"
TS="$(date +%Y%m%d-%H%M%S)"
REPORT_PATH="${1:-$REPORT_DIR/hardware_smoke_${TS}.json}"
LIST_JSON="$(cargo run -q -p bitdoctl -- --json list 2>/dev/null || echo '[]')"
SUITE="${BITDO_REQUIRED_SUITE:-family}"
REQUIRED_FAMILIES="${BITDO_REQUIRED_FAMILIES:-Standard64,DInput}"
TEST_OUTPUT_FILE="$(mktemp)"
PARSE_OUTPUT="$(mktemp)"
set +e
BITDO_HARDWARE=1 cargo test --workspace --test hardware_smoke -- --ignored >"$TEST_OUTPUT_FILE" 2>&1
TEST_STATUS=$?
python3 - <<'PY' "$LAB_CONFIG" "$SUITE" "$REQUIRED_FAMILIES" >"$PARSE_OUTPUT"
import pathlib
import re
import sys
config_path = pathlib.Path(sys.argv[1])
suite = sys.argv[2].strip()
required_families = [item.strip() for item in sys.argv[3].split(",") if item.strip()]
lines = config_path.read_text().splitlines()
devices = []
current = None
in_devices = False
def parse_scalar(text: str):
value = text.split("#", 1)[0].strip()
if not value:
return value
if value.startswith(("0x", "0X")):
return int(value, 16)
try:
return int(value)
except ValueError:
return value
for line in lines:
stripped = line.strip()
if stripped.startswith("devices:"):
in_devices = True
continue
if not in_devices:
continue
if stripped.startswith("policies:"):
if current:
devices.append(current)
current = None
break
if re.match(r"^\s*-\s+", line):
if current:
devices.append(current)
current = {}
continue
if current is None:
continue
field_match = re.match(r"^\s*([A-Za-z0-9_]+)\s*:\s*(.+)$", line)
if not field_match:
continue
key = field_match.group(1)
value = parse_scalar(field_match.group(2))
current[key] = value
if current:
devices.append(current)
if not devices:
sys.stderr.write(f"no devices found in {config_path}\n")
sys.exit(1)
family_to_pid = {}
fixture_to_pid = {}
for device in devices:
family = device.get("protocol_family")
pid = device.get("pid")
fixture_id = device.get("fixture_id")
if isinstance(family, str) and isinstance(pid, int) and family not in family_to_pid:
family_to_pid[family] = pid
if isinstance(fixture_id, str) and isinstance(pid, int) and fixture_id not in fixture_to_pid:
fixture_to_pid[fixture_id] = pid
if suite == "family":
missing = [fam for fam in required_families if fam not in family_to_pid]
if missing:
available = ", ".join(sorted(family_to_pid.keys())) if family_to_pid else "none"
sys.stderr.write(
f"missing required family fixtures in {config_path}: {', '.join(missing)}; available: {available}\n"
)
sys.exit(1)
for fam in required_families:
print(f"FAMILY:{fam}={family_to_pid[fam]:#06x}")
elif suite == "ultimate2":
if "ultimate2" not in fixture_to_pid:
available = ", ".join(sorted(fixture_to_pid.keys())) if fixture_to_pid else "none"
sys.stderr.write(
f"missing fixture_id=ultimate2 in {config_path}; available fixture_ids: {available}\n"
)
sys.exit(1)
print(f"FIXTURE:ultimate2={fixture_to_pid['ultimate2']:#06x}")
elif suite == "108jp":
if "108jp" not in fixture_to_pid:
available = ", ".join(sorted(fixture_to_pid.keys())) if fixture_to_pid else "none"
sys.stderr.write(
f"missing fixture_id=108jp in {config_path}; available fixture_ids: {available}\n"
)
sys.exit(1)
print(f"FIXTURE:108jp={fixture_to_pid['108jp']:#06x}")
else:
sys.stderr.write(f"unsupported BITDO_REQUIRED_SUITE value: {suite}\n")
sys.exit(1)
PY
PARSE_STATUS=$?
set -e
python3 - <<'PY' "$REPORT_PATH" "$TEST_STATUS" "$TEST_OUTPUT_FILE" "$LIST_JSON"
if [[ $PARSE_STATUS -ne 0 ]]; then
rm -f "$PARSE_OUTPUT"
exit $PARSE_STATUS
fi
while IFS='=' read -r key pid_hex; do
[[ -z "$key" ]] && continue
if [[ "$key" == FAMILY:* ]]; then
family="${key#FAMILY:}"
case "$family" in
DInput) export BITDO_EXPECT_DINPUT_PID="$pid_hex" ;;
Standard64) export BITDO_EXPECT_STANDARD64_PID="$pid_hex" ;;
JpHandshake) export BITDO_EXPECT_JPHANDSHAKE_PID="$pid_hex" ;;
*)
echo "unsupported family in parsed lab config: $family" >&2
rm -f "$PARSE_OUTPUT"
exit 1
;;
esac
elif [[ "$key" == FIXTURE:* ]]; then
fixture="${key#FIXTURE:}"
case "$fixture" in
ultimate2) export BITDO_EXPECT_ULTIMATE2_PID="$pid_hex" ;;
108jp) export BITDO_EXPECT_108JP_PID="$pid_hex" ;;
*)
echo "unsupported fixture in parsed lab config: $fixture" >&2
rm -f "$PARSE_OUTPUT"
exit 1
;;
esac
fi
done <"$PARSE_OUTPUT"
rm -f "$PARSE_OUTPUT"
TEST_OUTPUT_FILE="$(mktemp)"
TEST_STATUS=0
run_test() {
local test_name="$1"
set +e
BITDO_HARDWARE=1 cargo test --workspace --test hardware_smoke -- --ignored --exact "$test_name" >>"$TEST_OUTPUT_FILE" 2>&1
local status=$?
set -e
if [[ $status -ne 0 ]]; then
TEST_STATUS=$status
fi
}
run_test "hardware_smoke_detect_devices"
case "$SUITE" in
family)
IFS=',' read -r -a FAMILY_LIST <<<"$REQUIRED_FAMILIES"
for family in "${FAMILY_LIST[@]}"; do
case "$family" in
DInput) run_test "hardware_smoke_dinput_family" ;;
Standard64) run_test "hardware_smoke_standard64_family" ;;
JpHandshake) run_test "hardware_smoke_jphandshake_family" ;;
*)
echo "unsupported required family for tests: $family" >>"$TEST_OUTPUT_FILE"
TEST_STATUS=1
;;
esac
done
;;
ultimate2)
run_test "hardware_smoke_ultimate2_core_ops"
;;
108jp)
run_test "hardware_smoke_108jp_dedicated_ops"
;;
*)
echo "unsupported suite: $SUITE" >>"$TEST_OUTPUT_FILE"
TEST_STATUS=1
;;
esac
python3 - <<'PY' "$REPORT_PATH" "$TEST_STATUS" "$TEST_OUTPUT_FILE" "$SUITE" "$REQUIRED_FAMILIES" "${BITDO_EXPECT_STANDARD64_PID:-}" "${BITDO_EXPECT_DINPUT_PID:-}" "${BITDO_EXPECT_JPHANDSHAKE_PID:-}" "${BITDO_EXPECT_ULTIMATE2_PID:-}" "${BITDO_EXPECT_108JP_PID:-}"
import json, sys, pathlib, datetime
report_path = pathlib.Path(sys.argv[1])
test_status = int(sys.argv[2])
output_file = pathlib.Path(sys.argv[3])
list_json_raw = sys.argv[4]
try:
devices = json.loads(list_json_raw)
except Exception:
devices = []
suite = sys.argv[4]
required_families = [x for x in sys.argv[5].split(",") if x]
expected_standard64 = sys.argv[6]
expected_dinput = sys.argv[7]
expected_jphandshake = sys.argv[8]
expected_ultimate2 = sys.argv[9]
expected_108jp = sys.argv[10]
report = {
"timestamp_utc": datetime.datetime.utcnow().isoformat() + "Z",
"suite": suite,
"test_status": test_status,
"tests_passed": test_status == 0,
"devices": devices,
"required_families": required_families,
"required_family_fixtures": {
"Standard64": expected_standard64,
"DInput": expected_dinput,
"JpHandshake": expected_jphandshake,
},
"required_device_fixtures": {
"ultimate2": expected_ultimate2,
"108jp": expected_108jp,
},
"raw_test_output": output_file.read_text(errors="replace"),
}
@@ -43,3 +240,4 @@ PY
rm -f "$TEST_OUTPUT_FILE"
echo "hardware smoke report written: $REPORT_PATH"
exit "$TEST_STATUS"