lesavka/testing/tests/client_rct_transport_probe_contract.rs

176 lines
7.4 KiB
Rust

//! Contract tests for the client-origin transport-to-RCT probe.
//!
//! Scope: statically guard the black-box transport harness and client timeline
//! artifacts used for client->server tuning.
//! Targets: `scripts/manual/run_client_to_rct_transport_probe.sh`,
//! `scripts/manual/client_rct_transport_summary.py`, and
//! `scripts/manual/client_rct_uvc_frame_meta_fetch.sh`, and
//! `client/src/sync_probe/`.
//! Why: this probe is the bridge between synthetic bundled client media and the
//! final RCT sync/freshness/smoothness evidence, so it must not drift into
//! split-stream or sudo-mutating behavior.
const CLIENT_RCT_SCRIPT: &str =
include_str!("../../scripts/manual/run_client_to_rct_transport_probe.sh");
const CLIENT_RCT_SUMMARY: &str =
include_str!("../../scripts/manual/client_rct_transport_summary.py");
const CLIENT_RCT_LAYERS: &str = include_str!("../../scripts/manual/client_rct_transport_layers.py");
const UVC_FRAME_META_FETCH: &str =
include_str!("../../scripts/manual/client_rct_uvc_frame_meta_fetch.sh");
const UVC_FRAME_META_SUMMARY: &str =
include_str!("../../scripts/manual/summarize_uvc_frame_meta_log.py");
const SYNC_PROBE_CONFIG: &str = include_str!("../../client/src/sync_probe/config.rs");
const SYNC_PROBE_RUNNER: &str = include_str!("../../client/src/sync_probe/runner.rs");
const SYNC_PROBE_BUNDLED_TRANSPORT: &str =
include_str!("../../client/src/sync_probe/runner/bundled_transport.rs");
const SYNC_PROBE_TIMELINE: &str = include_str!("../../client/src/sync_probe/timeline.rs");
#[test]
fn client_rct_probe_injects_synthetic_media_through_bundled_transport() {
for expected in [
"lesavka-sync-probe",
"--event-width-codes \"${PROBE_EVENT_WIDTH_CODES}\"",
"PROBE_EVENT_WIDTH_CODES=${PROBE_EVENT_WIDTH_CODES:-1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}",
"--timeline-json \"${LOCAL_CLIENT_TIMELINE_JSON}\"",
"stream_webcam_media",
"UpstreamMediaBundle",
"server does not advertise bundled webcam media",
"refusing to measure split upstream",
] {
assert!(
CLIENT_RCT_SCRIPT.contains(expected)
|| SYNC_PROBE_RUNNER.contains(expected)
|| SYNC_PROBE_BUNDLED_TRANSPORT.contains(expected)
|| SYNC_PROBE_CONFIG.contains(expected),
"client-to-RCT transport probe should contain {expected}"
);
}
for forbidden in [
".stream_camera(Request::new(outbound))",
".stream_microphone(Request::new(outbound))",
] {
assert!(
!SYNC_PROBE_RUNNER.contains(forbidden)
&& !SYNC_PROBE_BUNDLED_TRANSPORT.contains(forbidden),
"synthetic transport probe must not use split upstream RPC {forbidden}"
);
}
}
#[test]
fn client_rct_probe_preserves_black_box_rct_measurement_artifacts() {
for expected in [
"LOCAL_CAPTURE=\"${LOCAL_REPORT_DIR}/capture.mkv\"",
"LOCAL_REPORT_JSON=\"${LOCAL_REPORT_DIR}/report.json\"",
"LOCAL_EVENTS_CSV=\"${LOCAL_REPORT_DIR}/events.csv\"",
"LOCAL_CLIENT_TIMELINE_JSON=\"${LOCAL_REPORT_DIR}/client-transport-timeline.json\"",
"LOCAL_TRANSPORT_SUMMARY_JSON=\"${LOCAL_REPORT_DIR}/client-rct-transport-summary.json\"",
"LOCAL_RUN_LOG=\"${LOCAL_REPORT_DIR}/client-rct-run.log\"",
"capture_start_unix_ns=",
"lesavka-sync-analyze",
"client_rct_transport_summary.py",
"smoothness",
"freshness_budget_ms",
"freshness_bottleneck",
"client_send_summary",
"post_client_send_worst_p95_ms",
"LESAVKA_CLIENT_RCT_UVC_FRAME_META_LOG_REMOTE",
"uvc_frame_meta_log_remote=${LESAVKA_CLIENT_RCT_UVC_FRAME_META_LOG_REMOTE:-disabled}",
"client_rct_uvc_frame_meta_fetch.sh",
"summarize_uvc_frame_meta_log.py",
"required UVC frame metadata log could not be summarized",
"optional UVC frame metadata log could not be summarized",
"uvc_frame_meta_summary_json",
"lesavka.uvc-mjpeg-spool-summary.v1",
"uvc_spool",
"UVC spool boundary",
"synthetic evidence",
"video_age_p95_ms",
"audio_age_p95_ms",
"artifact_dir: ${LOCAL_REPORT_DIR}",
] {
assert!(
CLIENT_RCT_SCRIPT.contains(expected)
|| CLIENT_RCT_SUMMARY.contains(expected)
|| CLIENT_RCT_LAYERS.contains(expected)
|| UVC_FRAME_META_FETCH.contains(expected)
|| UVC_FRAME_META_SUMMARY.contains(expected),
"client-to-RCT probe should preserve artifact/summary marker {expected}"
);
}
}
#[test]
fn client_rct_probe_keeps_shell_harness_focused_under_loc_limit() {
for (name, contents) in [
("run_client_to_rct_transport_probe.sh", CLIENT_RCT_SCRIPT),
("client_rct_uvc_frame_meta_fetch.sh", UVC_FRAME_META_FETCH),
("client_rct_transport_summary.py", CLIENT_RCT_SUMMARY),
] {
let loc = contents.lines().count();
assert!(
loc <= 500,
"{name} should stay under the 500 LOC refactor guard; saw {loc}"
);
}
}
#[test]
fn client_rct_probe_is_non_mutating_and_passwordless_by_default() {
for expected in [
"SSH_OPTS=${SSH_OPTS:-\"-o BatchMode=yes -o ConnectTimeout=5\"}",
"no remote sudo/reconfigure will be attempted by this script",
"LESAVKA_SERVER_ADDR=${LESAVKA_SERVER_ADDR:-auto}",
"LESAVKA_CLIENT_RCT_MODE=${LESAVKA_CLIENT_RCT_MODE:-auto}",
"LESAVKA_CLIENT_RCT_START_DELAY_SECONDS=${LESAVKA_CLIENT_RCT_START_DELAY_SECONDS:-0}",
"LESAVKA_CLIENT_RCT_START_DELAY_SECONDS must be a non-negative number",
"start_delay=${LESAVKA_CLIENT_RCT_START_DELAY_SECONDS}s",
"ExitOnForwardFailure=yes",
"127.0.0.1:${local_port}:127.0.0.1:${SERVER_TUNNEL_REMOTE_PORT}",
] {
assert!(
CLIENT_RCT_SCRIPT.contains(expected),
"client-to-RCT probe should keep unattended marker {expected}"
);
}
for forbidden in ["sudo -S", "read -s", "PASSWORD", "VAULT", "vault"] {
assert!(
!CLIENT_RCT_SCRIPT.contains(forbidden) && !UVC_FRAME_META_FETCH.contains(forbidden),
"client-to-RCT probe should not prompt for or retrieve secrets: {forbidden}"
);
}
}
#[test]
fn client_timeline_schema_captures_origin_and_event_timing() {
for expected in [
"lesavka.client-transport-probe-timeline.v1",
"client-generated",
"client-post-capture-uplink-bundle",
"client_uplink_included: true",
"client_start_unix_ns",
"client_capture_unix_ns",
"planned_start_us",
"planned_end_us",
"marker_tick_period",
"let client_start_unix_ns = capture.start_unix_ns();",
"ProbeTimeline::new(camera, &schedule, config.duration, client_start_unix_ns)",
] {
assert!(
SYNC_PROBE_TIMELINE.contains(expected) || SYNC_PROBE_RUNNER.contains(expected),
"client timeline should contain {expected}"
);
}
assert!(
SYNC_PROBE_RUNNER.find("ProbeTimeline::new").unwrap()
< SYNC_PROBE_RUNNER
.rfind("run_bundled_probe_stream(")
.unwrap(),
"timeline should be written before bundled transport starts so origin evidence matches generated media"
);
assert!(
SYNC_PROBE_BUNDLED_TRANSPORT.contains("let bundled_task = tokio::spawn"),
"bundled transport module should own the spawned streaming task"
);
}