Files
marte-benchmark-suite/launcher/marte_benchmark_launcher.sh
T
2026-08-27 11:12:22 +02:00

1247 lines
37 KiB
Bash
Executable File

#!/usr/bin/env bash
set -u
LAUNCHER_DIR="$(
cd "$(dirname "${BASH_SOURCE[0]}")" &&
pwd
)"
if [ -n "${MARTE_BENCHMARK_SUITE_ROOT:-}" ]; then
SUITE="$(cd "$MARTE_BENCHMARK_SUITE_ROOT" && pwd)"
else
SUITE="$(cd "$LAUNCHER_DIR/.." && pwd)"
fi
PATCHER_S01="$SUITE/patchers/configuration/build_s01_from_s00.sh"
PATCHER_S02="$SUITE/patchers/configuration/build_s02_from_s01.sh"
PATCHER_S03="${MARTE_S03_PATCHER_OVERRIDE:-$SUITE/patchers/configuration/build_s03_from_s02.sh}"
RUNNER="$SUITE/common/marte_runner.sh"
VALIDATOR_S01="$SUITE/scenarios/S01_timing_display/validate.sh"
VALIDATOR_S02="$SUITE/scenarios/S02_binary_recording/validate.sh"
VALIDATOR_S03="${MARTE_S03_VALIDATOR_OVERRIDE:-$SUITE/scenarios/S03_semantic_sentinels/validate.sh}"
S00_CONFIG="$SUITE/configurations/generated/S00/smoke_s0_core.marte"
S01_PATCHED_CONFIG="$SUITE/configurations/generated/S01/from_patcher/smoke_s1_timing_from_s00.marte"
S02_PATCHED_CONFIG="$SUITE/configurations/generated/S02/from_patcher/smoke_s2_binary_recording_from_s01.marte"
S03_PATCHED_CONFIG="${MARTE_S03_CONFIG_OVERRIDE:-$SUITE/configurations/generated/S03/from_patcher/smoke_s3_semantic_sentinels_from_s02.marte}"
CONSTANT_GAM_LIB_DIR="$SUITE/../MARTe2-components/Build/x86-linux/Components/GAMs/ConstantGAM"
if [ -f "$SUITE/common/paths.sh" ]; then
# Il file espone i percorsi canonici usati dalla suite. Il sourcing non
# modifica file e permette di rispettare target e root non standard.
source "$SUITE/common/paths.sh"
CONSTANT_GAM_LIB_DIR="$MARTE2_COMPONENTS_ROOT/Build/$MARTE_TARGET/Components/GAMs/ConstantGAM"
fi
CONSTANT_GAM_LIB="$CONSTANT_GAM_LIB_DIR/ConstantGAM.so"
EXPECTED_S00_SHA256="49a9b48595aab88cd8fd11d1e58ace4ab11d7d0a649e9b143bdc25c8866253d5"
EXPECTED_S01_SHA256="1513e1ca72eba56d53079ac7328908f12ddc72772456e2d75bcbacb6465d2427"
EXPECTED_S02_SHA256="8ecc8ba55e46e9f6fb8f304404d4070ff4c2ea5b9c783a69113bc08b457859d1"
EXPECTED_S03_SHA256="0f8916735ff67a9be2b167b52f147687fe131a063f410a81bfbf3bf9ff65f1e4"
DEFAULT_DURATION_SECONDS="8"
S00_STATUS="NOT_CHECKED"
S01_STATUS="NOT_CHECKED"
S02_STATUS="NOT_CHECKED"
S03_STATUS="NOT_CHECKED"
S01_PATCHER_RC="NOT_RUN"
S02_PATCHER_RC="NOT_RUN"
S03_PATCHER_RC="NOT_RUN"
print_usage() {
printf "Uso:\n"
printf " %s\n" "$0"
printf " %s S01 [durata-secondi]\n" "$0"
printf " %s S02 [durata-secondi]\n" "$0"
printf " %s S03 [durata-secondi]\n" "$0"
printf "\n"
printf "Dipendenze automatiche:\n"
printf " S01: catena S00 -> S01; esegue e valida S01.\n"
printf " S02: catena S00 -> S01 -> S02; esegue e valida S02.\n"
printf " S03: catena S00 -> S01 -> S02 -> S03; valida le sentinelle.\n"
}
fail() {
code="$1"
shift
printf "ERRORE: %s\n" "$*" >&2
exit "$code"
}
check_executable() {
file="$1"
description="$2"
if [ ! -x "$file" ]; then
fail 30 "$description assente o non eseguibile: $file"
fi
}
validate_duration() {
duration="$1"
case "$duration" in
*[!0-9]*|"")
printf "ERRORE: durata non valida: %s\n" "$duration" >&2
return 1
;;
esac
if [ "$duration" -le 0 ]; then
printf "ERRORE: la durata deve essere maggiore di zero.\n" >&2
return 1
fi
return 0
}
verify_file_hash() {
file="$1"
expected_hash="$2"
description="$3"
if [ ! -f "$file" ]; then
printf "ERRORE: %s assente: %s\n" "$description" "$file" >&2
return 1
fi
actual_hash="$(sha256sum -- "$file" | awk '{print $1}')"
if [ "$actual_hash" != "$expected_hash" ]; then
printf "ERRORE: hash inatteso per %s.\n" "$description" >&2
printf "Atteso: %s\n" "$expected_hash" >&2
printf "Reale: %s\n" "$actual_hash" >&2
printf "File: %s\n" "$file" >&2
return 1
fi
printf "%s pronta: %s\n" "$description" "$file"
printf "SHA-256: %s\n" "$actual_hash"
return 0
}
ensure_s00() {
printf "\n============================================================\n"
printf "DIPENDENZA S00 — CONFIGURAZIONE BASE\n"
printf "============================================================\n"
if ! verify_file_hash \
"$S00_CONFIG" \
"$EXPECTED_S00_SHA256" \
"Configurazione S00"
then
S00_STATUS="FAILED"
return 50
fi
S00_STATUS="READY"
return 0
}
ensure_s01() {
ensure_s00
dependency_rc=$?
if [ "$dependency_rc" -ne 0 ]; then
return "$dependency_rc"
fi
printf "\n============================================================\n"
printf "DIPENDENZA S01 — PATCH S00 -> S01\n"
printf "============================================================\n"
check_executable "$PATCHER_S01" "Patcher S01"
timeout 10s "$PATCHER_S01"
S01_PATCHER_RC=$?
printf "Codice patcher S01: %s\n" "$S01_PATCHER_RC"
if [ "$S01_PATCHER_RC" -ne 0 ]; then
S01_STATUS="FAILED"
return 51
fi
if ! verify_file_hash \
"$S01_PATCHED_CONFIG" \
"$EXPECTED_S01_SHA256" \
"Configurazione S01"
then
S01_STATUS="FAILED"
return 52
fi
S01_STATUS="READY"
return 0
}
ensure_s02() {
ensure_s01
dependency_rc=$?
if [ "$dependency_rc" -ne 0 ]; then
return "$dependency_rc"
fi
printf "\n============================================================\n"
printf "DIPENDENZA S02 — PATCH S01 -> S02\n"
printf "============================================================\n"
check_executable "$PATCHER_S02" "Patcher S02"
timeout 10s "$PATCHER_S02"
S02_PATCHER_RC=$?
printf "Codice patcher S02: %s\n" "$S02_PATCHER_RC"
if [ "$S02_PATCHER_RC" -ne 0 ]; then
S02_STATUS="FAILED"
return 53
fi
if ! verify_file_hash \
"$S02_PATCHED_CONFIG" \
"$EXPECTED_S02_SHA256" \
"Configurazione S02"
then
S02_STATUS="FAILED"
return 54
fi
S02_STATUS="READY"
return 0
}
ensure_s03() {
ensure_s02
dependency_rc=$?
if [ "$dependency_rc" -ne 0 ]; then
return "$dependency_rc"
fi
printf "\n============================================================\n"
printf "DIPENDENZA S03 — PATCH S02 -> S03\n"
printf "============================================================\n"
check_executable "$PATCHER_S03" "Patcher S03"
check_executable "$VALIDATOR_S03" "Validatore S03"
if [ ! -f "$CONSTANT_GAM_LIB" ]; then
printf "ERRORE: libreria ConstantGAM assente: %s\n" "$CONSTANT_GAM_LIB" >&2
S03_STATUS="FAILED"
return 55
fi
case ":${LD_LIBRARY_PATH-}:" in
*":${CONSTANT_GAM_LIB_DIR}:"*)
;;
*)
if [ -n "${LD_LIBRARY_PATH-}" ]; then
LD_LIBRARY_PATH="${CONSTANT_GAM_LIB_DIR}:${LD_LIBRARY_PATH}"
else
LD_LIBRARY_PATH="$CONSTANT_GAM_LIB_DIR"
fi
;;
esac
export LD_LIBRARY_PATH
timeout 10s "$PATCHER_S03" "$S02_PATCHED_CONFIG" "$S03_PATCHED_CONFIG"
S03_PATCHER_RC=$?
printf "Codice patcher S03: %s\n" "$S03_PATCHER_RC"
if [ "$S03_PATCHER_RC" -ne 0 ]; then
S03_STATUS="FAILED"
return 56
fi
if ! verify_file_hash \
"$S03_PATCHED_CONFIG" \
"$EXPECTED_S03_SHA256" \
"Configurazione S03"
then
S03_STATUS="FAILED"
return 57
fi
S03_STATUS="READY"
return 0
}
# ------------------------------------------------------------------
# S02-H2 — lettura contrattuale di validation.txt
# ------------------------------------------------------------------
#
# parse_validation_field <nome-campo> <file>
#
# Richiede ESATTAMENTE una riga "NOME=VALORE" nel file indicato.
# Il valore ammesso e' un token maiuscolo [A-Z][A-Z0-9_]*.
#
# Imposta:
# PARSED_FIELD_VALUE valore letto, oppure stringa vuota
# PARSED_FIELD_ERROR MISSING | DUPLICATED | MALFORMED | NO_FILE, oppure vuoto
#
# Ritorna 0 se e solo se il campo e' presente una sola volta e ben formato.
parse_validation_field() {
field_name="$1"
field_file="$2"
PARSED_FIELD_VALUE=""
PARSED_FIELD_ERROR=""
if [ ! -f "$field_file" ]; then
PARSED_FIELD_ERROR="NO_FILE"
return 1
fi
field_occurrences="$(grep -c -- "^${field_name}=" "$field_file" || true)"
if [ -z "$field_occurrences" ]; then
field_occurrences=0
fi
if [ "$field_occurrences" -eq 0 ]; then
PARSED_FIELD_ERROR="MISSING"
return 1
fi
if [ "$field_occurrences" -gt 1 ]; then
PARSED_FIELD_ERROR="DUPLICATED"
return 1
fi
field_value="$(
grep -- "^${field_name}=" "$field_file" |
head -n 1 |
cut -d '=' -f 2- |
tr -d '\r'
)"
case "$field_value" in
""|*[!A-Z0-9_]*)
PARSED_FIELD_ERROR="MALFORMED"
return 1
;;
esac
case "$field_value" in
[A-Z]*)
;;
*)
PARSED_FIELD_ERROR="MALFORMED"
return 1
;;
esac
PARSED_FIELD_VALUE="$field_value"
return 0
}
# ------------------------------------------------------------------
# classify_run <validator-rc> <tee-rc> <validation-file> <timing-contract>
#
# timing_contract:
# required lo scenario DEVE esporre FUNCTIONAL_STATUS e TIMING_STATUS
# not_applicable lo scenario non espone stato temporale (comportamento S01)
#
# Imposta:
# FUNCTIONAL_RESULT esito storico basato sull'exit code del validatore
# PARSED_FUNCTIONAL_STATUS
# PARSED_TIMING_STATUS
# MEASUREMENT_ELIGIBILITY YES | NO | UNKNOWN | NOT_APPLICABLE
# BLOCK_REASON NONE oppure motivo del blocco
# FINAL_RESULT
# FINAL_RC
# ------------------------------------------------------------------
classify_run() {
classify_validator_rc="$1"
classify_tee_rc="$2"
classify_validation_file="$3"
classify_timing_contract="$4"
PARSED_FUNCTIONAL_STATUS="NOT_APPLICABLE"
PARSED_TIMING_STATUS="NOT_APPLICABLE"
MEASUREMENT_ELIGIBILITY="NOT_APPLICABLE"
BLOCK_REASON="NONE"
# --- Contratto temporale: fail-closed su token sconosciuti (H2-04) ---
case "$classify_timing_contract" in
required|not_applicable)
;;
*)
FUNCTIONAL_RESULT="NOT_EVALUATED"
PARSED_FUNCTIONAL_STATUS="NOT_EVALUATED"
PARSED_TIMING_STATUS="NOT_EVALUATED"
MEASUREMENT_ELIGIBILITY="NO"
BLOCK_REASON="TIMING_CONTRACT_UNRECOGNISED_$classify_timing_contract"
FINAL_RESULT="INVALID_TIMING_CONTRACT"
FINAL_RC=24
return 0
;;
esac
# --- validation.txt non scritto: nessun parsing possibile ---
if [ "$classify_tee_rc" -ne 0 ]; then
FUNCTIONAL_RESULT="FAIL_VALIDATION_LOG"
FINAL_RESULT="FAIL_VALIDATION_LOG"
PARSED_FUNCTIONAL_STATUS="NOT_EVALUATED"
PARSED_TIMING_STATUS="NOT_EVALUATED"
MEASUREMENT_ELIGIBILITY="NO"
BLOCK_REASON="VALIDATION_LOG_NOT_WRITTEN"
FINAL_RC=67
return 0
fi
# --- Esito funzionale storico, dall'exit code del validatore ---
case "$classify_validator_rc" in
0)
FUNCTIONAL_RESULT="PASS"
FINAL_RC=0
FUNCTIONAL_ESTABLISHED=1
;;
10)
FUNCTIONAL_RESULT="PASS_WITH_KNOWN_SHUTDOWN_ANOMALY"
FINAL_RC=10
FUNCTIONAL_ESTABLISHED=1
;;
11)
FUNCTIONAL_RESULT="PASS_WITH_UNCLASSIFIED_SHUTDOWN_ANOMALY"
FINAL_RC=11
FUNCTIONAL_ESTABLISHED=1
;;
20|21)
FUNCTIONAL_RESULT="INCONCLUSIVE"
FINAL_RC=20
FUNCTIONAL_ESTABLISHED=0
;;
*)
FUNCTIONAL_RESULT="FAIL_VALIDATOR"
FINAL_RC=68
FUNCTIONAL_ESTABLISHED=0
;;
esac
FINAL_RESULT="$FUNCTIONAL_RESULT"
if [ "$classify_timing_contract" = "not_applicable" ]; then
return 0
fi
# ------------------------------------------------------------------
# Contratto temporale richiesto.
#
# H2-01: il parsing e' SEMPRE tentato quando il tee della validazione
# e' riuscito, indipendentemente dall'exit code del validatore. Il
# validatore H1 stampa FUNCTIONAL_STATUS e TIMING_STATUS anche prima
# di uscire con 20; nasconderli sarebbe una propagazione falsa.
#
# La precedenza numerica resta invece all'exit code del validatore:
# 20 rimane 20, 68 rimane 68. Il parsing arricchisce il riepilogo,
# non riscrive un verdetto funzionale gia' emesso.
# ------------------------------------------------------------------
CLASSIFY_PARSE_ERROR="NONE"
if parse_validation_field "FUNCTIONAL_STATUS" "$classify_validation_file"; then
PARSED_FUNCTIONAL_STATUS="$PARSED_FIELD_VALUE"
else
PARSED_FUNCTIONAL_STATUS="PARSE_ERROR_$PARSED_FIELD_ERROR"
CLASSIFY_PARSE_ERROR="FUNCTIONAL_STATUS_$PARSED_FIELD_ERROR"
fi
if parse_validation_field "TIMING_STATUS" "$classify_validation_file"; then
PARSED_TIMING_STATUS="$PARSED_FIELD_VALUE"
else
PARSED_TIMING_STATUS="PARSE_ERROR_$PARSED_FIELD_ERROR"
if [ "$CLASSIFY_PARSE_ERROR" = "NONE" ]; then
CLASSIFY_PARSE_ERROR="TIMING_STATUS_$PARSED_FIELD_ERROR"
fi
fi
# --- Nessuna run puo' essere idonea a una misura prestazionale ---
MEASUREMENT_ELIGIBILITY="NO"
if [ "$CLASSIFY_PARSE_ERROR" != "NONE" ]; then
BLOCK_REASON="$CLASSIFY_PARSE_ERROR"
if [ "$FUNCTIONAL_ESTABLISHED" -eq 1 ]; then
FINAL_RESULT="INCONCLUSIVE_TIMING_CONTRACT"
FINAL_RC=22
fi
return 0
fi
if [ "$FUNCTIONAL_ESTABLISHED" -eq 0 ]; then
# Exit 20/21/altro: il verdetto funzionale prevale, ma i campi
# realmente presenti sono comunque riportati.
if [ "$PARSED_FUNCTIONAL_STATUS" = "PASS" ]; then
BLOCK_REASON="FUNCTIONAL_STATUS_CONFLICT_WITH_EXIT_CODE"
else
BLOCK_REASON="FUNCTIONAL_STATUS_NOT_PASS"
fi
return 0
fi
if [ "$PARSED_FUNCTIONAL_STATUS" != "PASS" ]; then
BLOCK_REASON="FUNCTIONAL_STATUS_NOT_PASS"
FINAL_RESULT="FUNCTIONAL_STATUS_CONFLICT"
FINAL_RC=23
return 0
fi
case "$PARSED_TIMING_STATUS" in
NOT_VALID_*)
BLOCK_REASON="$PARSED_TIMING_STATUS"
FINAL_RESULT="FUNCTIONAL_PASS_TIMING_NOT_VALID"
FINAL_RC=12
;;
UNASSESSED_*)
MEASUREMENT_ELIGIBILITY="UNKNOWN"
BLOCK_REASON="$PARSED_TIMING_STATUS"
FINAL_RESULT="FUNCTIONAL_PASS_TIMING_UNASSESSED"
FINAL_RC=13
;;
VALID)
# H2-05: il vocabolario H1 installato non emette VALID e il
# PERFORMANCE MEASUREMENT GATE completo non esiste ancora.
# H2 non autorizza mai da solo l'idoneita' prestazionale.
BLOCK_REASON="TIMING_STATUS_VALID_NOT_YET_CONTRACTED"
FINAL_RESULT="INCONCLUSIVE_TIMING_CONTRACT"
FINAL_RC=22
;;
*)
BLOCK_REASON="TIMING_STATUS_UNRECOGNISED_$PARSED_TIMING_STATUS"
FINAL_RESULT="INCONCLUSIVE_TIMING_CONTRACT"
FINAL_RC=22
;;
esac
return 0
}
# ------------------------------------------------------------------
# S03 — contratto funzionale, semantico e temporale separato.
#
# Exit code candidati (non installati):
# 14 funzionalita' e semantica PASS, timing non valido
# 15 funzionalita' e semantica PASS, timing non valutato
# 20 validatore inconcludente o input mancante
# 22 contratto S03 non interpretabile / timing VALID non autorizzato
# 23 conflitto FUNCTIONAL_STATUS
# 25 conflitto SEMANTIC_STATUS
# 67 validation.txt non scritto
# 68 exit code validatore non riconosciuto
# 69 launcher_summary.txt non scritto
# ------------------------------------------------------------------
classify_s03_run() {
classify_validator_rc="$1"
classify_tee_rc="$2"
classify_validation_file="$3"
PARSED_FUNCTIONAL_STATUS="NOT_EVALUATED"
PARSED_SEMANTIC_STATUS="NOT_EVALUATED"
PARSED_TIMING_STATUS="NOT_EVALUATED"
PARSED_VALIDATOR_ELIGIBILITY="NOT_EVALUATED"
MEASUREMENT_ELIGIBILITY="NO"
BLOCK_REASON="NONE"
if [ "$classify_tee_rc" -ne 0 ]; then
FUNCTIONAL_RESULT="FAIL_VALIDATION_LOG"
FINAL_RESULT="FAIL_VALIDATION_LOG"
BLOCK_REASON="VALIDATION_LOG_NOT_WRITTEN"
FINAL_RC=67
return 0
fi
case "$classify_validator_rc" in
0)
FUNCTIONAL_RESULT="PASS"
FUNCTIONAL_ESTABLISHED=1
FINAL_RC=0
;;
10)
FUNCTIONAL_RESULT="PASS_WITH_KNOWN_SHUTDOWN_ANOMALY"
FUNCTIONAL_ESTABLISHED=1
FINAL_RC=10
;;
11)
FUNCTIONAL_RESULT="PASS_WITH_UNCLASSIFIED_SHUTDOWN_ANOMALY"
FUNCTIONAL_ESTABLISHED=1
FINAL_RC=11
;;
20|21)
FUNCTIONAL_RESULT="INCONCLUSIVE"
FUNCTIONAL_ESTABLISHED=0
FINAL_RC=20
;;
*)
FUNCTIONAL_RESULT="FAIL_VALIDATOR"
FUNCTIONAL_ESTABLISHED=0
FINAL_RC=68
;;
esac
FINAL_RESULT="$FUNCTIONAL_RESULT"
S03_PARSE_ERROR="NONE"
for field_name in \
FUNCTIONAL_STATUS \
SEMANTIC_STATUS \
TIMING_STATUS \
MEASUREMENT_ELIGIBILITY
do
if parse_validation_field "$field_name" "$classify_validation_file"; then
case "$field_name" in
FUNCTIONAL_STATUS)
PARSED_FUNCTIONAL_STATUS="$PARSED_FIELD_VALUE"
;;
SEMANTIC_STATUS)
PARSED_SEMANTIC_STATUS="$PARSED_FIELD_VALUE"
;;
TIMING_STATUS)
PARSED_TIMING_STATUS="$PARSED_FIELD_VALUE"
;;
MEASUREMENT_ELIGIBILITY)
PARSED_VALIDATOR_ELIGIBILITY="$PARSED_FIELD_VALUE"
;;
esac
else
case "$field_name" in
FUNCTIONAL_STATUS)
PARSED_FUNCTIONAL_STATUS="PARSE_ERROR_$PARSED_FIELD_ERROR"
;;
SEMANTIC_STATUS)
PARSED_SEMANTIC_STATUS="PARSE_ERROR_$PARSED_FIELD_ERROR"
;;
TIMING_STATUS)
PARSED_TIMING_STATUS="PARSE_ERROR_$PARSED_FIELD_ERROR"
;;
MEASUREMENT_ELIGIBILITY)
PARSED_VALIDATOR_ELIGIBILITY="PARSE_ERROR_$PARSED_FIELD_ERROR"
;;
esac
if [ "$S03_PARSE_ERROR" = "NONE" ]; then
S03_PARSE_ERROR="${field_name}_$PARSED_FIELD_ERROR"
fi
fi
done
if [ "$S03_PARSE_ERROR" != "NONE" ]; then
BLOCK_REASON="$S03_PARSE_ERROR"
FINAL_RESULT="INCONCLUSIVE_S03_CONTRACT"
if [ "$FUNCTIONAL_ESTABLISHED" -eq 1 ]; then
FINAL_RC=22
fi
return 0
fi
case "$PARSED_FUNCTIONAL_STATUS" in
PASS|NOT_DEMONSTRATED)
;;
*)
BLOCK_REASON="FUNCTIONAL_STATUS_UNRECOGNISED_$PARSED_FUNCTIONAL_STATUS"
FINAL_RESULT="INCONCLUSIVE_S03_CONTRACT"
FINAL_RC=22
return 0
;;
esac
case "$PARSED_SEMANTIC_STATUS" in
PASS|FAIL|NOT_DEMONSTRATED)
;;
*)
BLOCK_REASON="SEMANTIC_STATUS_UNRECOGNISED_$PARSED_SEMANTIC_STATUS"
FINAL_RESULT="INCONCLUSIVE_S03_CONTRACT"
FINAL_RC=22
return 0
;;
esac
if [ "$PARSED_VALIDATOR_ELIGIBILITY" != "NO" ]; then
BLOCK_REASON="ELIGIBILITY_CONTRACT_VIOLATION_$PARSED_VALIDATOR_ELIGIBILITY"
FINAL_RESULT="INCONCLUSIVE_S03_CONTRACT"
FINAL_RC=22
return 0
fi
if [ "$FUNCTIONAL_ESTABLISHED" -eq 0 ]; then
if [ "$PARSED_FUNCTIONAL_STATUS" != "PASS" ]; then
BLOCK_REASON="FUNCTIONAL_STATUS_NOT_PASS"
elif [ "$PARSED_SEMANTIC_STATUS" != "PASS" ]; then
BLOCK_REASON="SEMANTIC_STATUS_$PARSED_SEMANTIC_STATUS"
else
BLOCK_REASON="VALIDATOR_EXIT_NOT_PASS"
fi
FINAL_RESULT="S03_VALIDATION_INCONCLUSIVE"
return 0
fi
if [ "$PARSED_FUNCTIONAL_STATUS" != "PASS" ]; then
BLOCK_REASON="FUNCTIONAL_STATUS_CONFLICT_WITH_EXIT_CODE"
FINAL_RESULT="FUNCTIONAL_STATUS_CONFLICT"
FINAL_RC=23
return 0
fi
if [ "$PARSED_SEMANTIC_STATUS" != "PASS" ]; then
BLOCK_REASON="SEMANTIC_STATUS_CONFLICT_$PARSED_SEMANTIC_STATUS"
FINAL_RESULT="SEMANTIC_STATUS_CONFLICT"
FINAL_RC=25
return 0
fi
case "$PARSED_TIMING_STATUS" in
NOT_VALID_*)
BLOCK_REASON="$PARSED_TIMING_STATUS"
FINAL_RESULT="FUNCTIONAL_AND_SEMANTIC_PASS_TIMING_NOT_VALID"
FINAL_RC=14
;;
UNASSESSED_*)
BLOCK_REASON="$PARSED_TIMING_STATUS"
FINAL_RESULT="FUNCTIONAL_AND_SEMANTIC_PASS_TIMING_UNASSESSED"
FINAL_RC=15
;;
VALID)
BLOCK_REASON="TIMING_STATUS_VALID_NOT_YET_CONTRACTED"
FINAL_RESULT="INCONCLUSIVE_TIMING_CONTRACT"
FINAL_RC=22
;;
NOT_EVALUATED)
BLOCK_REASON="TIMING_STATUS_NOT_EVALUATED"
FINAL_RESULT="INCONCLUSIVE_TIMING_CONTRACT"
FINAL_RC=22
;;
*)
BLOCK_REASON="TIMING_STATUS_UNRECOGNISED_$PARSED_TIMING_STATUS"
FINAL_RESULT="INCONCLUSIVE_TIMING_CONTRACT"
FINAL_RC=22
;;
esac
return 0
}
emit_s03_summary() {
summary_destination="$1"
{
printf "============================================================\n"
printf "RIEPILOGO LAUNCHER S03 CANDIDATO\n"
printf "============================================================\n"
printf "Scenario: S03\n"
printf "Durata: %s secondi\n" "${duration:-NOT_AVAILABLE}"
printf "Catena dipendenze: S00 -> S01 -> S02 -> S03\n"
printf "Stato S00: %s\n" "$S00_STATUS"
printf "Stato S01: %s\n" "$S01_STATUS"
printf "Stato S02: %s\n" "$S02_STATUS"
printf "Stato S03: %s\n" "$S03_STATUS"
printf "Codice patcher S01: %s\n" "$S01_PATCHER_RC"
printf "Codice patcher S02: %s\n" "$S02_PATCHER_RC"
printf "Codice patcher S03: %s\n" "$S03_PATCHER_RC"
printf "Configurazione: %s\n" "${S03_PATCHED_CONFIG:-NOT_AVAILABLE}"
printf "Run directory: %s\n" "${RUN_DIR:-NOT_AVAILABLE}"
printf "Run log: %s\n" "${RUN_LOG:-NOT_AVAILABLE}"
printf "Validazione: %s\n" "${VALIDATION_LOG:-NOT_AVAILABLE}"
printf "Codice runner: %s\n" "${RUNNER_RC:-NOT_AVAILABLE}"
printf "Codice validatore: %s\n" "${VALIDATOR_RC:-NOT_AVAILABLE}"
printf "Esito storico validatore: %s\n" "${FUNCTIONAL_RESULT:-NOT_AVAILABLE}"
printf "FUNCTIONAL_STATUS=%s\n" "$PARSED_FUNCTIONAL_STATUS"
printf "SEMANTIC_STATUS=%s\n" "$PARSED_SEMANTIC_STATUS"
printf "TIMING_STATUS=%s\n" "$PARSED_TIMING_STATUS"
printf "MEASUREMENT_ELIGIBILITY=%s\n" "$MEASUREMENT_ELIGIBILITY"
printf "BLOCK_REASON=%s\n" "$BLOCK_REASON"
printf "FINAL_RESULT=%s\n" "$FINAL_RESULT"
printf "FINAL_RC=%s\n" "$FINAL_RC"
} | tee "$summary_destination"
summary_codes=("${PIPESTATUS[@]}")
if [ "${summary_codes[1]}" -ne 0 ]; then
return 69
fi
return 0
}
run_prepared_s03() {
duration="$1"
check_executable "$RUNNER" "Common runner"
check_executable "$VALIDATOR_S03" "Validatore S03"
CAPTURE="$(mktemp "${TMPDIR:-/tmp}/marte_benchmark_launcher_s03.XXXXXX")" ||
return 60
trap 'rm -f -- "$CAPTURE"' EXIT HUP INT TERM
printf "\n============================================================\n"
printf "ESECUZIONE COMMON RUNNER — S03\n"
printf "============================================================\n"
"$RUNNER" \
"S03_launcher" \
"$S03_PATCHED_CONFIG" \
"State1" \
"$duration" \
2>&1 | tee "$CAPTURE"
RUNNER_CODES=("${PIPESTATUS[@]}")
RUNNER_RC="${RUNNER_CODES[0]}"
CAPTURE_TEE_RC="${RUNNER_CODES[1]}"
if [ "$RUNNER_RC" -ne 0 ]; then
printf "RISULTATO FINALE: FAIL_RUNNER\n"
return 61
fi
if [ "$CAPTURE_TEE_RC" -ne 0 ]; then
printf "RISULTATO FINALE: FAIL_LAUNCHER_LOG\n"
return 62
fi
RUN_DIR="$(sed -n 's/^RUN_DIR=//p' "$CAPTURE" | tail -n 1)"
if [ -z "$RUN_DIR" ]; then
printf "ERRORE: RUN_DIR non individuata.\n" >&2
return 63
fi
if [ ! -d "$RUN_DIR" ]; then
printf "ERRORE: directory di run assente: %s\n" "$RUN_DIR" >&2
return 64
fi
RUN_LOG="$RUN_DIR/run.log"
VALIDATION_LOG="$RUN_DIR/validation.txt"
LAUNCHER_SUMMARY="$RUN_DIR/launcher_summary.txt"
if [ ! -f "$RUN_LOG" ]; then
printf "ERRORE: run.log assente: %s\n" "$RUN_LOG" >&2
return 65
fi
printf "\n============================================================\n"
printf "VALIDAZIONE S03\n"
printf "============================================================\n"
timeout 20s "$VALIDATOR_S03" "$RUN_DIR" 2>&1 | tee "$VALIDATION_LOG"
VALIDATION_CODES=("${PIPESTATUS[@]}")
VALIDATOR_RC="${VALIDATION_CODES[0]}"
VALIDATION_TEE_RC="${VALIDATION_CODES[1]}"
classify_s03_run "$VALIDATOR_RC" "$VALIDATION_TEE_RC" "$VALIDATION_LOG"
if ! emit_s03_summary "$LAUNCHER_SUMMARY"; then
FINAL_RESULT="FAIL_LAUNCHER_SUMMARY"
FINAL_RC=69
printf "ERRORE: riepilogo launcher S03 non scritto: %s\n" \
"$LAUNCHER_SUMMARY" >&2
fi
printf "\nRISULTATO FINALE: %s\n" "$FINAL_RESULT"
printf "Riepilogo: %s\n" "$LAUNCHER_SUMMARY"
rm -f -- "$CAPTURE"
trap - EXIT HUP INT TERM
return "$FINAL_RC"
}
run_prepared_scenario() {
scenario_name="$1"
scenario_id="$2"
config_file="$3"
validator="$4"
validator_input_mode="$5"
duration="$6"
dependency_chain="$7"
timing_contract="$8"
check_executable "$RUNNER" "Common runner"
check_executable "$validator" "Validatore $scenario_name"
CAPTURE="$(
mktemp "${TMPDIR:-/tmp}/marte_benchmark_launcher.XXXXXX"
)" || return 60
trap 'rm -f "$CAPTURE"' EXIT HUP INT TERM
printf "\n============================================================\n"
printf "ESECUZIONE COMMON RUNNER — %s\n" "$scenario_name"
printf "============================================================\n"
"$RUNNER" \
"${scenario_id}_launcher" \
"$config_file" \
"State1" \
"$duration" \
2>&1 | tee "$CAPTURE"
RUNNER_CODES=("${PIPESTATUS[@]}")
RUNNER_RC="${RUNNER_CODES[0]}"
CAPTURE_TEE_RC="${RUNNER_CODES[1]}"
printf "\nCodice common runner: %s\n" "$RUNNER_RC"
printf "Codice tee launcher: %s\n" "$CAPTURE_TEE_RC"
if [ "$RUNNER_RC" -ne 0 ]; then
printf "RISULTATO FINALE: FAIL_RUNNER\n"
return 61
fi
if [ "$CAPTURE_TEE_RC" -ne 0 ]; then
printf "RISULTATO FINALE: FAIL_LAUNCHER_LOG\n"
return 62
fi
RUN_DIR="$(
sed -n 's/^RUN_DIR=//p' "$CAPTURE" |
tail -n 1
)"
if [ -z "$RUN_DIR" ]; then
printf "ERRORE: RUN_DIR non individuata.\n" >&2
return 63
fi
if [ ! -d "$RUN_DIR" ]; then
printf "ERRORE: directory di run assente: %s\n" "$RUN_DIR" >&2
return 64
fi
RUN_LOG="$RUN_DIR/run.log"
VALIDATION_LOG="$RUN_DIR/validation.txt"
LAUNCHER_SUMMARY="$RUN_DIR/launcher_summary.txt"
if [ ! -f "$RUN_LOG" ]; then
printf "ERRORE: run.log assente: %s\n" "$RUN_LOG" >&2
return 65
fi
case "$validator_input_mode" in
run_log)
VALIDATOR_INPUT="$RUN_LOG"
;;
run_dir)
VALIDATOR_INPUT="$RUN_DIR"
;;
*)
printf "ERRORE: modalità input validatore non riconosciuta: %s\n" \
"$validator_input_mode" >&2
return 66
;;
esac
printf "\n============================================================\n"
printf "VALIDAZIONE %s\n" "$scenario_name"
printf "============================================================\n"
timeout 15s "$validator" "$VALIDATOR_INPUT" 2>&1 |
tee "$VALIDATION_LOG"
VALIDATION_CODES=("${PIPESTATUS[@]}")
VALIDATOR_RC="${VALIDATION_CODES[0]}"
VALIDATION_TEE_RC="${VALIDATION_CODES[1]}"
classify_run \
"$VALIDATOR_RC" \
"$VALIDATION_TEE_RC" \
"$VALIDATION_LOG" \
"$timing_contract"
{
printf "============================================================\n"
printf "RIEPILOGO LAUNCHER\n"
printf "============================================================\n"
printf "Scenario: %s\n" "$scenario_name"
printf "Durata: %s secondi\n" "$duration"
printf "Catena dipendenze: %s\n" "$dependency_chain"
printf "Stato S00: %s\n" "$S00_STATUS"
printf "Stato S01: %s\n" "$S01_STATUS"
printf "Stato S02: %s\n" "$S02_STATUS"
printf "Codice patcher S01: %s\n" "$S01_PATCHER_RC"
printf "Codice patcher S02: %s\n" "$S02_PATCHER_RC"
printf "Configurazione: %s\n" "$config_file"
printf "Run directory: %s\n" "$RUN_DIR"
printf "Run log: %s\n" "$RUN_LOG"
printf "Validazione: %s\n" "$VALIDATION_LOG"
printf "Codice runner: %s\n" "$RUNNER_RC"
printf "Codice validatore: %s\n" "$VALIDATOR_RC"
printf "Esito funzionale: %s\n" "$FUNCTIONAL_RESULT"
printf "FUNCTIONAL_STATUS: %s\n" "$PARSED_FUNCTIONAL_STATUS"
printf "TIMING_STATUS: %s\n" "$PARSED_TIMING_STATUS"
printf "MEASUREMENT_ELIGIBILITY: %s\n" "$MEASUREMENT_ELIGIBILITY"
printf "Motivo blocco: %s\n" "$BLOCK_REASON"
printf "Codice finale launcher: %s\n" "$FINAL_RC"
printf "Risultato finale: %s\n" "$FINAL_RESULT"
} | tee "$LAUNCHER_SUMMARY"
SUMMARY_CODES=("${PIPESTATUS[@]}")
SUMMARY_TEE_RC="${SUMMARY_CODES[1]}"
# H2-06: il riepilogo e' il documento che porta il nuovo contratto.
# Se non e' stato scritto, il risultato non e' verificabile a posteriori
# e non puo' essere presentato come esito valido.
if [ "$SUMMARY_TEE_RC" -ne 0 ]; then
printf "ERRORE: riepilogo launcher non scritto: %s\n" \
"$LAUNCHER_SUMMARY" >&2
FINAL_RESULT="FAIL_LAUNCHER_SUMMARY"
FINAL_RC=69
fi
printf "\nRISULTATO FINALE: %s\n" "$FINAL_RESULT"
printf "Riepilogo: %s\n" "$LAUNCHER_SUMMARY"
rm -f -- "$CAPTURE"
trap - EXIT HUP INT TERM
return "$FINAL_RC"
}
run_s01() {
duration="$1"
if ! validate_duration "$duration"; then
return 31
fi
S00_STATUS="NOT_CHECKED"
S01_STATUS="NOT_CHECKED"
S02_STATUS="NOT_REQUIRED"
S03_STATUS="NOT_REQUIRED"
S01_PATCHER_RC="NOT_RUN"
S02_PATCHER_RC="NOT_REQUIRED"
S03_PATCHER_RC="NOT_REQUIRED"
printf "============================================================\n"
printf "SCENARIO S01 — TIMING DISPLAY\n"
printf "============================================================\n"
printf "Durata: %s secondi\n" "$duration"
printf "Catena automatica: S00 -> S01\n"
ensure_s01
PREPARE_RC=$?
if [ "$PREPARE_RC" -ne 0 ]; then
printf "RISULTATO FINALE: FAIL_DEPENDENCY_CHAIN\n"
return "$PREPARE_RC"
fi
run_prepared_scenario \
"S01" \
"S01" \
"$S01_PATCHED_CONFIG" \
"$VALIDATOR_S01" \
"run_log" \
"$duration" \
"S00 -> S01" \
"not_applicable"
}
run_s02() {
duration="$1"
if ! validate_duration "$duration"; then
return 31
fi
S00_STATUS="NOT_CHECKED"
S01_STATUS="NOT_CHECKED"
S02_STATUS="NOT_CHECKED"
S03_STATUS="NOT_REQUIRED"
S01_PATCHER_RC="NOT_RUN"
S02_PATCHER_RC="NOT_RUN"
S03_PATCHER_RC="NOT_REQUIRED"
printf "============================================================\n"
printf "SCENARIO S02 — BINARY RECORDING\n"
printf "============================================================\n"
printf "Durata: %s secondi\n" "$duration"
printf "Catena automatica: S00 -> S01 -> S02\n"
ensure_s02
PREPARE_RC=$?
if [ "$PREPARE_RC" -ne 0 ]; then
printf "RISULTATO FINALE: FAIL_DEPENDENCY_CHAIN\n"
return "$PREPARE_RC"
fi
run_prepared_scenario \
"S02" \
"S02" \
"$S02_PATCHED_CONFIG" \
"$VALIDATOR_S02" \
"run_dir" \
"$duration" \
"S00 -> S01 -> S02" \
"required"
}
run_s03() {
duration="$1"
if ! validate_duration "$duration"; then
return 31
fi
S00_STATUS="NOT_CHECKED"
S01_STATUS="NOT_CHECKED"
S02_STATUS="NOT_CHECKED"
S03_STATUS="NOT_CHECKED"
S01_PATCHER_RC="NOT_RUN"
S02_PATCHER_RC="NOT_RUN"
S03_PATCHER_RC="NOT_RUN"
printf "============================================================\n"
printf "SCENARIO S03 — SENTINELLE E VALIDAZIONE SEMANTICA\n"
printf "============================================================\n"
printf "Durata: %s secondi\n" "$duration"
printf "Catena automatica: S00 -> S01 -> S02 -> S03\n"
printf "Gate prestazionale: CHIUSO\n"
ensure_s03
PREPARE_RC=$?
if [ "$PREPARE_RC" -ne 0 ]; then
printf "RISULTATO FINALE: FAIL_DEPENDENCY_CHAIN\n"
return "$PREPARE_RC"
fi
run_prepared_s03 "$duration"
}
ask_duration_and_run() {
scenario="$1"
printf "Durata in secondi [%s]: " "$DEFAULT_DURATION_SECONDS"
if ! IFS= read -r duration; then
printf "\nERRORE: input non disponibile.\n" >&2
return 2
fi
if [ -z "$duration" ]; then
duration="$DEFAULT_DURATION_SECONDS"
fi
case "$scenario" in
S01)
run_s01 "$duration"
;;
S02)
run_s02 "$duration"
;;
S03)
run_s03 "$duration"
;;
*)
printf "ERRORE: scenario interno non riconosciuto: %s\n" "$scenario" >&2
return 2
;;
esac
}
interactive_menu() {
printf "============================================================\n"
printf "MARTe2 BENCHMARK SUITE\n"
printf "============================================================\n"
printf "1) S01 — catena automatica S00 -> S01, esegue e valida CycleTime\n"
printf "2) S02 — catena automatica S00 -> S01 -> S02, registra e valida il binario\n"
printf "3) S03 — catena S00 -> S01 -> S02 -> S03, valida le sentinelle\n"
printf "0) Esci\n"
printf "\nSelezione: "
if ! IFS= read -r selection; then
printf "\nERRORE: input non disponibile.\n" >&2
return 2
fi
case "$selection" in
1|S01|s01)
ask_duration_and_run "S01"
;;
2|S02|s02)
ask_duration_and_run "S02"
;;
3|S03|s03)
ask_duration_and_run "S03"
;;
0)
printf "Uscita.\n"
return 0
;;
*)
printf "Selezione non valida: %s\n" "$selection" >&2
return 2
;;
esac
}
# S02-H2: consente di caricare le sole funzioni (per i test) senza
# eseguire il menu interattivo o il dispatch degli argomenti.
#
# La modalita' e' accettata SOLTANTO quando il file viene caricato con
# "source". Se il launcher viene eseguito direttamente con la variabile
# impostata, deve fallire in modo esplicito: un exit 0 senza avere
# eseguito alcuna run sarebbe un falso successo.
if [ "${MARTE_LAUNCHER_LIB_ONLY:-0}" = "1" ]; then
if [ "${BASH_SOURCE[0]}" != "$0" ]; then
return 0
fi
printf "ERRORE: MARTE_LAUNCHER_LIB_ONLY=1 e' ammesso solo con 'source'.\n" >&2
printf "Il launcher e' stato eseguito direttamente: nessuna run avviata.\n" >&2
exit 3
fi
case "$#" in
0)
interactive_menu
exit $?
;;
1)
case "$1" in
S01|s01)
run_s01 "$DEFAULT_DURATION_SECONDS"
exit $?
;;
S02|s02)
run_s02 "$DEFAULT_DURATION_SECONDS"
exit $?
;;
S03|s03)
run_s03 "$DEFAULT_DURATION_SECONDS"
exit $?
;;
-h|--help)
print_usage
exit 0
;;
*)
print_usage >&2
exit 2
;;
esac
;;
2)
case "$1" in
S01|s01)
run_s01 "$2"
exit $?
;;
S02|s02)
run_s02 "$2"
exit $?
;;
S03|s03)
run_s03 "$2"
exit $?
;;
*)
print_usage >&2
exit 2
;;
esac
;;
*)
print_usage >&2
exit 2
;;
esac