//! Contract tests for the server-to-RCT mode matrix harness. //! //! Scope: statically guard the hardware-in-the-loop matrix script defaults and //! summary artifacts. //! Targets: `scripts/manual/run_server_to_rc_mode_matrix.sh`. //! Why: server-to-RCT calibration is now considered complete, so the matrix //! script must keep the blessed offsets and evidence outputs stable. const SERVER_RC_MODE_MATRIX_SCRIPT: &str = include_str!("../../scripts/manual/run_server_to_rc_mode_matrix.sh"); #[test] fn server_rc_mode_matrix_validates_advertised_uvc_profiles() { for expected in [ "LESAVKA_SERVER_RC_CORE_WEBCAM_MODES=${LESAVKA_SERVER_RC_CORE_WEBCAM_MODES:-1280x720@20,1280x720@30,1920x1080@20,1920x1080@30}", "LESAVKA_SERVER_RC_MODES=${LESAVKA_SERVER_RC_MODES:-${LESAVKA_SERVER_RC_CORE_WEBCAM_MODES}}", "LESAVKA_SERVER_REPO=${LESAVKA_SERVER_REPO:-auto}", "LESAVKA_SERVER_RC_DEFAULT_AUDIO_DELAY_US=${LESAVKA_SERVER_RC_DEFAULT_AUDIO_DELAY_US:-${LESAVKA_OUTPUT_DELAY_PROBE_AUDIO_DELAY_US:-0}}", "LESAVKA_SERVER_RC_DEFAULT_VIDEO_DELAY_US=${LESAVKA_SERVER_RC_DEFAULT_VIDEO_DELAY_US:-135090}", "LESAVKA_SERVER_RC_MODE_AUDIO_DELAYS_US=${LESAVKA_SERVER_RC_MODE_AUDIO_DELAYS_US:-1280x720@20=${LESAVKA_SERVER_RC_DEFAULT_AUDIO_DELAY_US},1280x720@30=${LESAVKA_SERVER_RC_DEFAULT_AUDIO_DELAY_US},1920x1080@20=${LESAVKA_SERVER_RC_DEFAULT_AUDIO_DELAY_US},1920x1080@30=${LESAVKA_SERVER_RC_DEFAULT_AUDIO_DELAY_US}}", "LESAVKA_SERVER_RC_MODE_DELAYS_US=${LESAVKA_SERVER_RC_MODE_DELAYS_US:-1280x720@20=162659,1280x720@30=135090,1920x1080@20=160045,1920x1080@30=127952}", "LESAVKA_SERVER_RC_MODE_DISCOVERY_SIZES=${LESAVKA_SERVER_RC_MODE_DISCOVERY_SIZES:-1280x720,1920x1080}", "LESAVKA_SERVER_RC_MODE_DISCOVERY_FPS=${LESAVKA_SERVER_RC_MODE_DISCOVERY_FPS:-20,30}", "LESAVKA_SERVER_RC_MODE_DISCOVERY_INCLUDE_REGEX=${LESAVKA_SERVER_RC_MODE_DISCOVERY_INCLUDE_REGEX:-Logitech|BRIO|C9[0-9]+|HD UVC WebCam|USB2[.]0 HD|Integrated Camera|Webcam|Camera}", "LESAVKA_SERVER_RC_MODE_DISCOVERY_EXCLUDE_REGEX=${LESAVKA_SERVER_RC_MODE_DISCOVERY_EXCLUDE_REGEX:-Lesavka|UGREEN|MACROSILICON|Composite|Capture}", "LESAVKA_SERVER_RC_MODE_SOURCE=${LESAVKA_SERVER_RC_MODE_SOURCE:-configured}", "LESAVKA_SERVER_RC_RECONFIGURE=${LESAVKA_SERVER_RC_RECONFIGURE:-0}", "LESAVKA_SERVER_RC_RECONFIGURE_UPDATE=${LESAVKA_SERVER_RC_RECONFIGURE_UPDATE:-0}", "LESAVKA_SERVER_RC_RECONFIGURE_STRATEGY=${LESAVKA_SERVER_RC_RECONFIGURE_STRATEGY:-runtime}", "LESAVKA_SERVER_RC_ALLOW_GADGET_RESET=${LESAVKA_SERVER_RC_ALLOW_GADGET_RESET:-1}", "LESAVKA_SERVER_RC_RECONFIGURE_VERBOSE=${LESAVKA_SERVER_RC_RECONFIGURE_VERBOSE:-0}", "LESAVKA_SERVER_RC_PROMPT_SUDO_EARLY=${LESAVKA_SERVER_RC_PROMPT_SUDO_EARLY:-1}", "LESAVKA_SERVER_RC_START_DELAY_SECONDS=${LESAVKA_SERVER_RC_START_DELAY_SECONDS:-0}", "LESAVKA_SERVER_RC_WAIT_TETHYS_READY=${LESAVKA_SERVER_RC_WAIT_TETHYS_READY:-1}", "LESAVKA_SERVER_RC_TETHYS_READY_TIMEOUT_SECONDS=${LESAVKA_SERVER_RC_TETHYS_READY_TIMEOUT_SECONDS:-60}", "LESAVKA_SERVER_RC_TETHYS_SETTLE_SECONDS=${LESAVKA_SERVER_RC_TETHYS_SETTLE_SECONDS:-6}", "LESAVKA_SERVER_RC_PREROLL_DISCARD_SECONDS=${LESAVKA_SERVER_RC_PREROLL_DISCARD_SECONDS:-3}", "LESAVKA_SERVER_RC_PROBE_PREBUILD=${LESAVKA_SERVER_RC_PROBE_PREBUILD:-1}", "LESAVKA_SERVER_RC_TUNE_DELAYS=${LESAVKA_SERVER_RC_TUNE_DELAYS:-1}", "LESAVKA_SERVER_RC_TUNE_CONFIRM=${LESAVKA_SERVER_RC_TUNE_CONFIRM:-1}", "LESAVKA_SERVER_RC_TUNE_MIN_PAIRS=${LESAVKA_SERVER_RC_TUNE_MIN_PAIRS:-13}", "LESAVKA_SERVER_RC_TUNE_MAX_ABS_SKEW_MS=${LESAVKA_SERVER_RC_TUNE_MAX_ABS_SKEW_MS:-1000}", "LESAVKA_SERVER_RC_TUNE_MAX_STEP_US=${LESAVKA_SERVER_RC_TUNE_MAX_STEP_US:-500000}", "LESAVKA_SERVER_RC_TUNE_MIN_CHANGE_US=${LESAVKA_SERVER_RC_TUNE_MIN_CHANGE_US:-5000}", "Theia sudo password for %s", "==> priming remote sudo on ${LESAVKA_SERVER_HOST}", "sleep_start_delay", "==> delaying server-to-RC matrix start for ${LESAVKA_SERVER_RC_START_DELAY_SECONDS}s", "remote sudo has already been primed; sleeping before prebuild/reconfigure/capture", "LESAVKA_SERVER_RC_START_DELAY_SECONDS must be a non-negative number", "start_delay=${LESAVKA_SERVER_RC_START_DELAY_SECONDS}s", "==> prebuilding relay control/analyzer once for the mode matrix", "LESAVKA_SERVER_RC_MODES=auto", "discover_local_webcam_modes", "lookup_audio_delay_us", "local webcam", "mode_source=${LESAVKA_SERVER_RC_MODE_SOURCE}", "video_delays=${LESAVKA_SERVER_RC_MODE_DELAYS_US}", "audio_delays=${LESAVKA_SERVER_RC_MODE_AUDIO_DELAYS_US}", "pulse_tool=${REMOTE_PULSE_CAPTURE_TOOL}", "fast runtime env updated: CAM_OUTPUT=uvc", "cycling UVC gadget descriptors", "lesavka-core reconfigure log:", "missing /usr/local/bin/lesavka-core.sh", "wait_tethys_media_ready", "==> waiting for Tethys media endpoints for ${mode}", "Tethys media ready: video=%s mode=%s audio_stack=%s", "timed out waiting for Tethys Lesavka media endpoints", "LESAVKA_SERVER_RC_FRESHNESS_MAX_AGE_MS=${LESAVKA_SERVER_RC_FRESHNESS_MAX_AGE_MS:-350}", "LESAVKA_SERVER_RC_FRESHNESS_MIN_PAIRS=${LESAVKA_SERVER_RC_FRESHNESS_MIN_PAIRS:-${LESAVKA_SERVER_RC_TUNE_MIN_PAIRS}}", "LESAVKA_SERVER_RC_MIN_CODED_PAIRS=${LESAVKA_SERVER_RC_MIN_CODED_PAIRS:-${LESAVKA_SERVER_RC_FRESHNESS_MIN_PAIRS}}", "LESAVKA_SERVER_RC_REQUIRE_ALL_CODED_PAIRS=${LESAVKA_SERVER_RC_REQUIRE_ALL_CODED_PAIRS:-0}", "LESAVKA_SERVER_RC_REQUIRE_SMOOTHNESS_PASS=${LESAVKA_SERVER_RC_REQUIRE_SMOOTHNESS_PASS:-0}", "LESAVKA_SERVER_RC_SIGNAL_READY=${LESAVKA_SERVER_RC_SIGNAL_READY:-1}", "LESAVKA_SERVER_RC_SIGNAL_READY_MODE=${LESAVKA_SERVER_RC_SIGNAL_READY_MODE:-conditioned_capture}", "LESAVKA_SERVER_RC_SIGNAL_READY_MIN_PAIRS=${LESAVKA_SERVER_RC_SIGNAL_READY_MIN_PAIRS:-3}", "LESAVKA_SERVER_RC_SIGNAL_READY_DURATION_SECONDS=${LESAVKA_SERVER_RC_SIGNAL_READY_DURATION_SECONDS:-12}", "LESAVKA_SERVER_RC_SIGNAL_READY_ATTEMPTS=${LESAVKA_SERVER_RC_SIGNAL_READY_ATTEMPTS:-4}", "LESAVKA_SERVER_RC_SIGNAL_READY_RETRY_DELAY_SECONDS=${LESAVKA_SERVER_RC_SIGNAL_READY_RETRY_DELAY_SECONDS:-5}", "LESAVKA_SERVER_RC_SIGNAL_CONDITION_SECONDS=${LESAVKA_SERVER_RC_SIGNAL_CONDITION_SECONDS:-12}", "LESAVKA_SERVER_RC_SIGNAL_CONDITION_WARMUP_SECONDS=${LESAVKA_SERVER_RC_SIGNAL_CONDITION_WARMUP_SECONDS:-1}", "LESAVKA_SERVER_RC_SIGNAL_CONDITION_GAP_SECONDS=${LESAVKA_SERVER_RC_SIGNAL_CONDITION_GAP_SECONDS:-1}", "LESAVKA_SERVER_RC_ANALYSIS_TIMELINE_WINDOW=${LESAVKA_SERVER_RC_ANALYSIS_TIMELINE_WINDOW:-auto}", "signal_readiness_passed", "write_signal_readiness_attempt_result", "write_signal_readiness_attempts_summary", "schema\": \"lesavka.server-rc-signal-readiness-attempt.v1\"", "schema\": \"lesavka.server-rc-signal-readiness-summary.v1\"", "using same-capture signal conditioning before measured probe", "proving Tethys signal readiness before measured probe", "readiness attempt ${readiness_attempt}/${LESAVKA_SERVER_RC_SIGNAL_READY_ATTEMPTS}", "waiting ${LESAVKA_SERVER_RC_SIGNAL_READY_RETRY_DELAY_SECONDS}s before retrying signal readiness", "signal readiness did not pass", "signal attempt ", "smoothness_required", "smoothness_warnings", "smoothness warning:", "coded visibility:", "LESAVKA_SERVER_RC_MAX_VIDEO_HICCUPS=${LESAVKA_SERVER_RC_MAX_VIDEO_HICCUPS:-0}", "LESAVKA_SERVER_RC_MAX_AUDIO_HICCUPS=${LESAVKA_SERVER_RC_MAX_AUDIO_HICCUPS:-0}", "LESAVKA_SERVER_RC_MAX_VIDEO_MISSING_FRAMES=${LESAVKA_SERVER_RC_MAX_VIDEO_MISSING_FRAMES:-12}", "mode-matrix-summary.json", "mode-matrix-summary.csv", "mode-matrix-summary.txt", "mode-delay-recommendations.json", "mode-delay-recommendations.env", "schema\": \"lesavka.server-rc-mode-result.v1\"", "schema\": \"lesavka.server-rc-mode-matrix-summary.v1\"", "schema\": \"lesavka.server-rc-mode-delay-recommendations.v1\"", "output_delay_calibration", "write_tune_candidate_env", "annotate_mode_result", "LESAVKA_SERVER_RC_REPEAT_COUNT=${LESAVKA_SERVER_RC_REPEAT_COUNT:-1}", "mode-static-calibration.json", "mode-matrix-run.log", "mode-result-seed.json", "mode-result-tuned.json", "==> mode ${mode} run ${mode_run_index}: confirming tuned delays", "calibration_ready", "calibration_video_target_offset_us", "calibration_audio_target_offset_us", "calibration:", "capture_timebase_status", "capture timebase invalid", "capture timing:", "signature_coverage", "paired coded signatures", "signature_missing_codes", "probe_env=(", "\"REMOTE_PULSE_CAPTURE_TOOL=${REMOTE_PULSE_CAPTURE_TOOL}\"", "\"REMOTE_PULSE_VIDEO_MODE=${REMOTE_PULSE_VIDEO_MODE}\"", "\"REMOTE_CAPTURE_STACK=${REMOTE_CAPTURE_STACK}\"", "\"REMOTE_CAPTURE_ALLOW_ALSA_FALLBACK=${REMOTE_CAPTURE_ALLOW_ALSA_FALLBACK}\"", "\"REMOTE_CAPTURE_PREROLL_DISCARD_SECONDS=${LESAVKA_SERVER_RC_PREROLL_DISCARD_SECONDS}\"", "\"REMOTE_CAPTURE_READY_SETTLE_SECONDS=${REMOTE_CAPTURE_READY_SETTLE_SECONDS}\"", "\"PROBE_PREBUILD=0\"", "\"VIDEO_SIZE=${width}x${height}\"", "\"VIDEO_FPS=${fps}\"", "\"REMOTE_EXPECT_UVC_WIDTH=${width}\"", "\"REMOTE_EXPECT_UVC_HEIGHT=${height}\"", "\"REMOTE_EXPECT_UVC_FPS=${fps}\"", "\"LESAVKA_OUTPUT_DELAY_PROBE_AUDIO_DELAY_US=${audio_delay_us}\"", "\"LESAVKA_OUTPUT_DELAY_PROBE_VIDEO_DELAY_US=${video_delay_us}\"", "\"LESAVKA_OUTPUT_DELAY_APPLY=0\"", "\"LESAVKA_OUTPUT_DELAY_SAVE=0\"", "\"LESAVKA_OUTPUT_FRESHNESS_MAX_AGE_MS=${LESAVKA_SERVER_RC_FRESHNESS_MAX_AGE_MS}\"", "\"LESAVKA_OUTPUT_FRESHNESS_MAX_CLOCK_UNCERTAINTY_MS=${LESAVKA_SERVER_RC_FRESHNESS_MAX_CLOCK_UNCERTAINTY_MS}\"", "\"LESAVKA_OUTPUT_FRESHNESS_MIN_PAIRS=${min_pairs}\"", "sync did not pass", "freshness did not pass", "video hiccups", "estimated missing video frames", "audio hiccups", ] { assert!( SERVER_RC_MODE_MATRIX_SCRIPT.contains(expected), "server-to-RC mode matrix script should contain {expected}" ); } let prime = SERVER_RC_MODE_MATRIX_SCRIPT .find("prime_remote_sudo\nsleep_start_delay\nprebuild_probe_tools") .expect("matrix should prime remote sudo before delayed start and prebuild"); let prompt = SERVER_RC_MODE_MATRIX_SCRIPT .find("Theia sudo password for %s") .expect("matrix should contain the immediate Theia password prompt"); assert!( prompt < prime, "password prompt machinery should be defined before the matrix startup sequence" ); }