refactor(streamer): remove gstreamer and legacy rtmp paths
This commit is contained in:
+107
-248
@@ -1,11 +1,10 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -u -o pipefail
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
STREAMER_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
BUILD_DIR="${STREAMER_ROOT}/build"
|
||||
|
||||
EVIDENCE_ROOT="${STREAMER_ROOT}/.sisyphus/evidence"
|
||||
TASK_EVIDENCE_DIR="${EVIDENCE_ROOT}/task-15-fault-suite"
|
||||
SUMMARY_HELPER="${SCRIPT_DIR}/fault_summary_helper.py"
|
||||
@@ -39,17 +38,10 @@ fi
|
||||
|
||||
RUN_ID=""
|
||||
RUN_DIR=""
|
||||
MANIFEST_TSV="${RUN_DIR}/rows.tsv"
|
||||
SUMMARY_JSON="${RUN_DIR}/summary.json"
|
||||
|
||||
if [[ "${MODE}" == "baseline" ]]; then
|
||||
LATEST_SUMMARY_JSON="${EVIDENCE_ROOT}/task-15-fault-suite-summary.json"
|
||||
EVIDENCE_TEXT="${EVIDENCE_ROOT}/task-15-fault-suite.txt"
|
||||
else
|
||||
LATEST_SUMMARY_JSON="${EVIDENCE_ROOT}/task-15-fault-suite-error-summary.json"
|
||||
EVIDENCE_TEXT="${EVIDENCE_ROOT}/task-15-fault-suite-error.txt"
|
||||
fi
|
||||
|
||||
MANIFEST_TSV=""
|
||||
SUMMARY_JSON=""
|
||||
LATEST_SUMMARY_JSON="${EVIDENCE_ROOT}/task-15-fault-suite-summary.json"
|
||||
EVIDENCE_TEXT="${EVIDENCE_ROOT}/task-15-fault-suite.txt"
|
||||
STARTED_AT_UTC="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
||||
|
||||
mkdir -p "${TASK_EVIDENCE_DIR}"
|
||||
@@ -76,50 +68,7 @@ allocate_run_dir() {
|
||||
|
||||
allocate_run_dir || exit 1
|
||||
|
||||
RUN_HASH="$(printf '%s' "${RUN_ID}" | cksum | awk '{print $1}')"
|
||||
PORT_OFFSET="$((RUN_HASH % 1000))"
|
||||
if [[ "${MODE}" == "baseline" ]]; then
|
||||
SCENARIO_PORT_BASE="$((52040 + PORT_OFFSET))"
|
||||
else
|
||||
SCENARIO_PORT_BASE="$((52140 + PORT_OFFSET))"
|
||||
fi
|
||||
|
||||
echo -e "order\tscenario_id\tname\tstatus\treason\tduration_ms\tsim_rc\tstreamer_rc\ttester_rc\tsim_log\tstreamer_log\ttester_log\tsdp_path" > "${MANIFEST_TSV}"
|
||||
|
||||
cleanup_pids=()
|
||||
|
||||
cleanup_all() {
|
||||
for pid in "${cleanup_pids[@]:-}"; do
|
||||
if [[ -n "${pid}" ]] && kill -0 "${pid}" 2>/dev/null; then
|
||||
kill "${pid}" 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
trap cleanup_all EXIT
|
||||
|
||||
binary_exists() {
|
||||
local path="$1"
|
||||
[[ -x "${path}" ]]
|
||||
}
|
||||
|
||||
wait_pid() {
|
||||
local pid="$1"
|
||||
local timeout_s="$2"
|
||||
local elapsed=0
|
||||
while kill -0 "${pid}" 2>/dev/null; do
|
||||
if (( elapsed >= timeout_s )); then
|
||||
kill "${pid}" 2>/dev/null || true
|
||||
wait "${pid}" 2>/dev/null || true
|
||||
return 124
|
||||
fi
|
||||
sleep 1
|
||||
elapsed=$((elapsed + 1))
|
||||
done
|
||||
|
||||
wait "${pid}" 2>/dev/null
|
||||
return $?
|
||||
}
|
||||
echo -e "order\tscenario_id\tname\tstatus\treason\tduration_ms\tcommand_rc\tlog_path" > "${MANIFEST_TSV}"
|
||||
|
||||
append_manifest_row() {
|
||||
local order="$1"
|
||||
@@ -128,145 +77,37 @@ append_manifest_row() {
|
||||
local status="$4"
|
||||
local reason="$5"
|
||||
local duration_ms="$6"
|
||||
local sim_rc="$7"
|
||||
local streamer_rc="$8"
|
||||
local tester_rc="$9"
|
||||
local sim_log="${10}"
|
||||
local streamer_log="${11}"
|
||||
local tester_log="${12}"
|
||||
local sdp_path="${13}"
|
||||
|
||||
echo -e "${order}\t${scenario_id}\t${name}\t${status}\t${reason}\t${duration_ms}\t${sim_rc}\t${streamer_rc}\t${tester_rc}\t${sim_log}\t${streamer_log}\t${tester_log}\t${sdp_path}" >> "${MANIFEST_TSV}"
|
||||
local command_rc="$7"
|
||||
local log_path="$8"
|
||||
echo -e "${order}\t${scenario_id}\t${name}\t${status}\t${reason}\t${duration_ms}\t${command_rc}\t${log_path}" >> "${MANIFEST_TSV}"
|
||||
}
|
||||
|
||||
scenario_port() {
|
||||
local order="$1"
|
||||
echo $((SCENARIO_PORT_BASE + (order - 1) * 2))
|
||||
}
|
||||
|
||||
run_fault_scenario() {
|
||||
run_expected_failure() {
|
||||
local order="$1"
|
||||
local scenario_id="$2"
|
||||
local name="$3"
|
||||
local expected_substring="$4"
|
||||
shift 4
|
||||
|
||||
local row_dir="${RUN_DIR}/${order}-${scenario_id}"
|
||||
mkdir -p "${row_dir}"
|
||||
local log_path="${row_dir}/command.log"
|
||||
|
||||
local sim_log="${row_dir}/sim.log"
|
||||
local streamer_log="${row_dir}/streamer.log"
|
||||
local tester_log="${row_dir}/tester.log"
|
||||
local sdp_path="${row_dir}/stream.sdp"
|
||||
|
||||
local shm_name="fault_${MODE}_${scenario_id}_${RUN_ID}"
|
||||
local zmq_endpoint="ipc:///tmp/fault_${MODE}_${scenario_id}_${RUN_ID}.ipc"
|
||||
local sim_label="f${order}_${MODE:0:3}_${scenario_id:0:3}"
|
||||
|
||||
local sim_frames=360
|
||||
local sim_fps=200
|
||||
local reset_every=""
|
||||
local snapshot_delay_us=0
|
||||
local emit_stall_ms=0
|
||||
local ingest_max_frames=180
|
||||
|
||||
case "${scenario_id}" in
|
||||
torn_read)
|
||||
if [[ "${MODE}" == "baseline" ]]; then
|
||||
snapshot_delay_us=2500
|
||||
sim_fps=240
|
||||
else
|
||||
snapshot_delay_us=25000
|
||||
sim_fps=320
|
||||
fi
|
||||
;;
|
||||
sink_stall)
|
||||
if [[ "${MODE}" == "baseline" ]]; then
|
||||
emit_stall_ms=3
|
||||
ingest_max_frames=140
|
||||
else
|
||||
emit_stall_ms=60
|
||||
ingest_max_frames=160
|
||||
fi
|
||||
;;
|
||||
reset_storm)
|
||||
if [[ "${MODE}" == "baseline" ]]; then
|
||||
reset_every=20
|
||||
ingest_max_frames=120
|
||||
else
|
||||
reset_every=3
|
||||
ingest_max_frames=180
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "unknown scenario_id=${scenario_id}" >&2
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
local rtp_port
|
||||
rtp_port="$(scenario_port "${order}")"
|
||||
|
||||
local streamer_cmd=(
|
||||
"${BUILD_DIR}/cvmmap_streamer"
|
||||
--run-mode pipeline
|
||||
--codec h264
|
||||
--shm-name "${shm_name}"
|
||||
--zmq-endpoint "${zmq_endpoint}"
|
||||
--input-mode dummy
|
||||
--dummy-label "${sim_label}"
|
||||
--dummy-frames "${sim_frames}"
|
||||
--dummy-fps "${sim_fps}"
|
||||
--dummy-width 640
|
||||
--dummy-height 360
|
||||
--dummy-startup-delay-ms 0
|
||||
--queue-size 1
|
||||
--gop 30
|
||||
--b-frames 0
|
||||
--ingest-max-frames "${ingest_max_frames}"
|
||||
--ingest-idle-timeout-ms 8000
|
||||
--snapshot-copy-delay-us "${snapshot_delay_us}"
|
||||
--emit-stall-ms "${emit_stall_ms}"
|
||||
--rtp
|
||||
--rtp-endpoint "127.0.0.1:${rtp_port}"
|
||||
--rtp-payload-type 96
|
||||
--rtp-sdp "${sdp_path}"
|
||||
)
|
||||
if [[ -n "${reset_every}" ]]; then
|
||||
streamer_cmd+=(--dummy-reset-every "${reset_every}")
|
||||
fi
|
||||
|
||||
local tester_cmd=(
|
||||
"${BUILD_DIR}/rtp_receiver_tester"
|
||||
--port "${rtp_port}"
|
||||
--expect-pt 96
|
||||
--packet-threshold 1
|
||||
--timeout-ms 15000
|
||||
)
|
||||
|
||||
local row_start_ms row_end_ms duration_ms
|
||||
local row_start_ms
|
||||
row_start_ms="$(date +%s%3N)"
|
||||
|
||||
"${tester_cmd[@]}" > "${tester_log}" 2>&1 &
|
||||
local tester_pid=$!
|
||||
cleanup_pids+=("${tester_pid}")
|
||||
|
||||
sleep 1
|
||||
: > "${sim_log}"
|
||||
|
||||
"${streamer_cmd[@]}" > "${streamer_log}" 2>&1
|
||||
local streamer_rc=$?
|
||||
|
||||
wait_pid "${tester_pid}" 25
|
||||
local tester_rc=$?
|
||||
local sim_rc=0
|
||||
|
||||
set +e
|
||||
"$@" >"${log_path}" 2>&1
|
||||
local command_rc=$?
|
||||
set -e
|
||||
local row_end_ms
|
||||
row_end_ms="$(date +%s%3N)"
|
||||
duration_ms=$((row_end_ms - row_start_ms))
|
||||
local duration_ms=$((row_end_ms - row_start_ms))
|
||||
|
||||
local status="PASS"
|
||||
local reason="all-processes-ok"
|
||||
if (( sim_rc != 0 || streamer_rc != 0 || tester_rc != 0 )); then
|
||||
status="FAIL"
|
||||
reason="sim_rc=${sim_rc},streamer_rc=${streamer_rc},tester_rc=${tester_rc}"
|
||||
local status="FAIL"
|
||||
local reason="expected non-zero rc and log token '${expected_substring}'"
|
||||
if (( command_rc != 0 )) && grep -Fq "${expected_substring}" "${log_path}"; then
|
||||
status="PASS"
|
||||
reason="command failed as expected"
|
||||
fi
|
||||
|
||||
append_manifest_row \
|
||||
@@ -276,26 +117,21 @@ run_fault_scenario() {
|
||||
"${status}" \
|
||||
"${reason}" \
|
||||
"${duration_ms}" \
|
||||
"${sim_rc}" \
|
||||
"${streamer_rc}" \
|
||||
"${tester_rc}" \
|
||||
"${sim_log}" \
|
||||
"${streamer_log}" \
|
||||
"${tester_log}" \
|
||||
"${sdp_path}"
|
||||
"${command_rc}" \
|
||||
"${log_path}"
|
||||
|
||||
printf "[%s] %s => %s (%s)\n" "${scenario_id}" "${name}" "${status}" "${reason}"
|
||||
}
|
||||
|
||||
main() {
|
||||
local required=(
|
||||
"${BUILD_DIR}/cvmmap_streamer"
|
||||
"${BUILD_DIR}/rtp_receiver_tester"
|
||||
"${BUILD_DIR}/cvmmap_streamer"
|
||||
"${BUILD_DIR}/rtmp_output_tester"
|
||||
)
|
||||
|
||||
local missing=()
|
||||
for bin in "${required[@]}"; do
|
||||
if ! binary_exists "${bin}"; then
|
||||
if [[ ! -x "${bin}" ]]; then
|
||||
missing+=("${bin}")
|
||||
fi
|
||||
done
|
||||
@@ -313,9 +149,68 @@ main() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
run_fault_scenario 1 "torn_read" "fault:torn-read"
|
||||
run_fault_scenario 2 "sink_stall" "fault:sink-stall"
|
||||
run_fault_scenario 3 "reset_storm" "fault:reset-storm"
|
||||
run_expected_failure 1 "removed_encoder_backend" "removed encoder backend rejected" \
|
||||
"invalid encoder backend: 'gstreamer_legacy' was removed; use ffmpeg" \
|
||||
"${BUILD_DIR}/cvmmap_streamer" \
|
||||
--run-mode pipeline \
|
||||
--input-uri cvmmap://default \
|
||||
--encoder-backend gstreamer_legacy
|
||||
|
||||
run_expected_failure 2 "removed_rtmp_transport" "removed RTMP transport rejected" \
|
||||
"invalid rtmp transport: 'legacy_custom' was removed; use libavformat or ffmpeg_process" \
|
||||
"${BUILD_DIR}/cvmmap_streamer" \
|
||||
--run-mode pipeline \
|
||||
--input-uri cvmmap://default \
|
||||
--rtmp \
|
||||
--rtmp-url rtmp://127.0.0.1/live/test \
|
||||
--rtmp-transport legacy_custom
|
||||
|
||||
run_expected_failure 3 "removed_rtmp_mode_cli" "removed RTMP mode flag rejected" \
|
||||
"unknown argument: --rtmp-mode (removed; RTMP always uses enhanced mode)" \
|
||||
"${BUILD_DIR}/cvmmap_streamer" \
|
||||
--rtmp-mode enhanced
|
||||
|
||||
local mode_row_dir="${RUN_DIR}/4-removed_rtmp_mode_toml"
|
||||
mkdir -p "${mode_row_dir}"
|
||||
local mode_config="${mode_row_dir}/removed_rtmp_mode.toml"
|
||||
cat >"${mode_config}" <<'EOF'
|
||||
[outputs.rtmp]
|
||||
enabled = true
|
||||
urls = ["rtmp://127.0.0.1/live/test"]
|
||||
mode = "enhanced"
|
||||
EOF
|
||||
run_expected_failure 4 "removed_rtmp_mode_toml" "removed RTMP mode TOML rejected" \
|
||||
"invalid RTMP config: outputs.rtmp.mode was removed; RTMP always uses enhanced mode" \
|
||||
"${BUILD_DIR}/cvmmap_streamer" \
|
||||
--config "${mode_config}"
|
||||
|
||||
run_expected_failure 5 "missing_rtmp_url" "missing RTMP URL rejected" \
|
||||
"invalid RTMP config: enabled RTMP output requires at least one URL" \
|
||||
"${BUILD_DIR}/cvmmap_streamer" \
|
||||
--run-mode pipeline \
|
||||
--input-uri cvmmap://default \
|
||||
--rtmp
|
||||
|
||||
run_expected_failure 6 "invalid_rtp_endpoint" "invalid RTP endpoint rejected" \
|
||||
"invalid RTP config: endpoint must be in '<host>:<port>' format" \
|
||||
"${BUILD_DIR}/cvmmap_streamer" \
|
||||
--run-mode pipeline \
|
||||
--input-uri cvmmap://default \
|
||||
--rtp \
|
||||
--rtp-endpoint invalid
|
||||
|
||||
run_expected_failure 7 "ffmpeg_process_bad_binary" "ffmpeg_process child failure surfaces" \
|
||||
"child exited before publish completed" \
|
||||
"${BUILD_DIR}/rtmp_output_tester" \
|
||||
--rtmp-url rtmp://127.0.0.1/live/test \
|
||||
--transport ffmpeg_process \
|
||||
--ffmpeg-path /nonexistent/ffmpeg \
|
||||
--codec h264 \
|
||||
--frames 256 \
|
||||
--width 640 \
|
||||
--height 360 \
|
||||
--frame-interval-ms 1 \
|
||||
--linger-ms 0
|
||||
|
||||
local finished_at_utc
|
||||
finished_at_utc="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
||||
@@ -328,54 +223,36 @@ main() {
|
||||
--started-at "${STARTED_AT_UTC}" \
|
||||
--finished-at "${finished_at_utc}" \
|
||||
--mode "${MODE}"
|
||||
local summary_rc=$?
|
||||
|
||||
cp -f "${SUMMARY_JSON}" "${LATEST_SUMMARY_JSON}" 2>/dev/null || true
|
||||
|
||||
local total_count pass_count fail_count all_pass
|
||||
total_count="$(python3 - <<'PY' "${SUMMARY_JSON}"
|
||||
import json
|
||||
import sys
|
||||
import json, sys
|
||||
data = json.load(open(sys.argv[1], "r", encoding="utf-8"))
|
||||
counts = data.get("counts", {})
|
||||
print(counts.get("total", 0))
|
||||
PY
|
||||
)"
|
||||
pass_count="$(python3 - <<'PY' "${SUMMARY_JSON}"
|
||||
import json
|
||||
import sys
|
||||
import json, sys
|
||||
data = json.load(open(sys.argv[1], "r", encoding="utf-8"))
|
||||
counts = data.get("counts", {})
|
||||
print(counts.get("pass", 0))
|
||||
PY
|
||||
)"
|
||||
fail_count="$(python3 - <<'PY' "${SUMMARY_JSON}"
|
||||
import json
|
||||
import sys
|
||||
import json, sys
|
||||
data = json.load(open(sys.argv[1], "r", encoding="utf-8"))
|
||||
counts = data.get("counts", {})
|
||||
print(counts.get("fail", 0))
|
||||
PY
|
||||
)"
|
||||
all_pass="$(python3 - <<'PY' "${SUMMARY_JSON}"
|
||||
import json
|
||||
import sys
|
||||
import json, sys
|
||||
data = json.load(open(sys.argv[1], "r", encoding="utf-8"))
|
||||
print("true" if data.get("all_pass", False) else "false")
|
||||
PY
|
||||
)"
|
||||
|
||||
local violation_lines
|
||||
violation_lines="$(python3 - <<'PY' "${SUMMARY_JSON}"
|
||||
import json
|
||||
import sys
|
||||
|
||||
data = json.load(open(sys.argv[1], "r", encoding="utf-8"))
|
||||
for scenario in data.get("scenarios", []):
|
||||
sid = scenario.get("id", "unknown")
|
||||
for violation in scenario.get("violations", []):
|
||||
print(f"{sid}:{violation}")
|
||||
PY
|
||||
)"
|
||||
|
||||
{
|
||||
@@ -385,42 +262,24 @@ PY
|
||||
echo "run_dir=${RUN_DIR}"
|
||||
echo "manifest=${MANIFEST_TSV}"
|
||||
echo "summary_json=${SUMMARY_JSON}"
|
||||
echo "latest_summary_json=${LATEST_SUMMARY_JSON}"
|
||||
echo "started_at=${STARTED_AT_UTC}"
|
||||
echo "finished_at=${finished_at_utc}"
|
||||
echo "scenario_total=${total_count}"
|
||||
echo "scenario_pass=${pass_count}"
|
||||
echo "scenario_fail=${fail_count}"
|
||||
echo "counts_total=${total_count}"
|
||||
echo "counts_pass=${pass_count}"
|
||||
echo "counts_fail=${fail_count}"
|
||||
echo "all_pass=${all_pass}"
|
||||
echo "summary_helper_rc=${summary_rc}"
|
||||
echo "violated_thresholds_begin"
|
||||
if [[ -n "${violation_lines}" ]]; then
|
||||
echo "${violation_lines}"
|
||||
fi
|
||||
echo "violated_thresholds_end"
|
||||
echo "scenarios=removed_encoder_backend,removed_rtmp_transport,removed_rtmp_mode_cli,removed_rtmp_mode_toml,missing_rtmp_url,invalid_rtp_endpoint,ffmpeg_process_bad_binary"
|
||||
} > "${EVIDENCE_TEXT}"
|
||||
|
||||
if (( summary_rc != 0 )); then
|
||||
echo "summary helper failed with rc=${summary_rc}" >&2
|
||||
return 1
|
||||
if [[ "${all_pass}" == "true" ]]; then
|
||||
echo "fault suite PASS (${pass_count}/${total_count})"
|
||||
echo "summary: ${SUMMARY_JSON}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "fault-suite mode=${MODE} total=${total_count} pass=${pass_count} fail=${fail_count}"
|
||||
echo "summary: ${SUMMARY_JSON}"
|
||||
|
||||
if [[ "${MODE}" == "baseline" ]]; then
|
||||
if [[ "${total_count}" == "3" && "${pass_count}" == "3" && "${fail_count}" == "0" ]]; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ "${fail_count}" != "0" ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "degraded mode did not violate thresholds" >&2
|
||||
return 2
|
||||
echo "fault suite FAIL (${pass_count}/${total_count})" >&2
|
||||
echo "summary: ${SUMMARY_JSON}" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
Reference in New Issue
Block a user