S03-H3 CLOSED baseline
This commit is contained in:
+24
@@ -0,0 +1,24 @@
|
|||||||
|
# ============================================================
|
||||||
|
# MARTe Benchmark Suite - Git exclusions
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
# Runtime execution outputs.
|
||||||
|
# Every MARTe benchmark run generates its own directory here.
|
||||||
|
# These outputs are operational evidence, not source code.
|
||||||
|
runs/
|
||||||
|
|
||||||
|
# Python bytecode/cache
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
|
||||||
|
# Editor temporary files
|
||||||
|
*~
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
|
||||||
|
# Generic temporary files
|
||||||
|
*.tmp
|
||||||
|
|
||||||
|
# Desktop metadata
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
@@ -0,0 +1,738 @@
|
|||||||
|
# MARTe Benchmark Suite
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
`marte-benchmark-suite` is a validation and benchmarking infrastructure
|
||||||
|
developed around the MARTe2 real-time framework.
|
||||||
|
|
||||||
|
The project is designed to build a sequence of progressively more advanced
|
||||||
|
test scenarios while preserving known-good baselines from the previous stages.
|
||||||
|
|
||||||
|
The suite does not modify MARTe2 itself.
|
||||||
|
|
||||||
|
Instead, it provides:
|
||||||
|
|
||||||
|
- MARTe configuration files;
|
||||||
|
- launchers;
|
||||||
|
- configuration patchers;
|
||||||
|
- runtime orchestration;
|
||||||
|
- output parsers;
|
||||||
|
- structural validators;
|
||||||
|
- semantic validators;
|
||||||
|
- execution evidence.
|
||||||
|
|
||||||
|
The development philosophy is incremental:
|
||||||
|
|
||||||
|
> each new stage introduces one new capability while preserving the validated
|
||||||
|
> behaviour of the previous stages.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Current project status
|
||||||
|
|
||||||
|
Current validated development baseline:
|
||||||
|
|
||||||
|
```text
|
||||||
|
S03-H3
|
||||||
|
STATUS=CLOSED
|
||||||
|
BASELINE=KNOWN-GOOD
|
||||||
|
```
|
||||||
|
|
||||||
|
S03-H3 is currently the authoritative baseline on which the next stages of the
|
||||||
|
benchmark suite are intended to be built.
|
||||||
|
|
||||||
|
The next planned stages are:
|
||||||
|
|
||||||
|
```text
|
||||||
|
S04 → Repeatability / Multi-Run
|
||||||
|
S05 → Deterministic Parametric Generator
|
||||||
|
S06 → MARTe2 Core Scaling
|
||||||
|
```
|
||||||
|
|
||||||
|
These stages are not part of the current S03-H3 baseline unless explicitly
|
||||||
|
implemented and accepted later.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Project purpose
|
||||||
|
|
||||||
|
The suite is intended to answer increasingly complex questions about a MARTe2
|
||||||
|
application.
|
||||||
|
|
||||||
|
Conceptually:
|
||||||
|
|
||||||
|
```text
|
||||||
|
S00
|
||||||
|
Can MARTe2 execute the basic reference application?
|
||||||
|
↓
|
||||||
|
S01
|
||||||
|
Can execution timing information be observed?
|
||||||
|
↓
|
||||||
|
S02
|
||||||
|
Can deterministic binary data be recorded?
|
||||||
|
↓
|
||||||
|
S03
|
||||||
|
Can the recorded data be checked semantically?
|
||||||
|
↓
|
||||||
|
S03-H1
|
||||||
|
Can different execution/debug profiles be supported?
|
||||||
|
↓
|
||||||
|
S03-H3
|
||||||
|
Can those profiles be formalized and validated
|
||||||
|
against an authoritative runtime contract?
|
||||||
|
↓
|
||||||
|
S04
|
||||||
|
Does the same valid workload remain correct
|
||||||
|
when executed repeatedly?
|
||||||
|
↓
|
||||||
|
S05
|
||||||
|
Can deterministic test workloads be generated
|
||||||
|
from parameters?
|
||||||
|
↓
|
||||||
|
S06
|
||||||
|
How does MARTe2 Core behave as workload complexity grows?
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# High-level architecture
|
||||||
|
|
||||||
|
The benchmark suite is layered around the installed MARTe2 runtime.
|
||||||
|
|
||||||
|
```text
|
||||||
|
+------------------+
|
||||||
|
| MARTe2 |
|
||||||
|
| MARTeApp.ex |
|
||||||
|
+---------+--------+
|
||||||
|
^
|
||||||
|
|
|
||||||
|
common/marte_runner.sh
|
||||||
|
^
|
||||||
|
|
|
||||||
|
launcher/
|
||||||
|
^
|
||||||
|
|
|
||||||
|
scenario / configuration
|
||||||
|
|
|
||||||
|
v
|
||||||
|
MARTe execution
|
||||||
|
|
|
||||||
|
v
|
||||||
|
RUN DIRECTORY
|
||||||
|
|
|
||||||
|
+------------+-------------+
|
||||||
|
| |
|
||||||
|
v v
|
||||||
|
runtime logs output files
|
||||||
|
| |
|
||||||
|
+------------+-------------+
|
||||||
|
|
|
||||||
|
v
|
||||||
|
parser / validator
|
||||||
|
|
|
||||||
|
v
|
||||||
|
PASS / FAIL result
|
||||||
|
```
|
||||||
|
|
||||||
|
MARTe2 and MARTe2-components remain external dependencies.
|
||||||
|
|
||||||
|
The benchmark suite orchestrates and validates them but is intentionally kept
|
||||||
|
separate from their source trees.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Repository structure
|
||||||
|
|
||||||
|
Current source structure:
|
||||||
|
|
||||||
|
```text
|
||||||
|
marte-benchmark-suite/
|
||||||
|
│
|
||||||
|
├── common/
|
||||||
|
│ ├── environment.sh
|
||||||
|
│ ├── marte_runner.sh
|
||||||
|
│ └── paths.sh
|
||||||
|
│
|
||||||
|
├── configurations/
|
||||||
|
│ └── generated/
|
||||||
|
│ ├── S00/
|
||||||
|
│ ├── S01/
|
||||||
|
│ ├── S02/
|
||||||
|
│ ├── S03/
|
||||||
|
│ ├── S03H1/
|
||||||
|
│ └── S03H3/
|
||||||
|
│
|
||||||
|
├── launcher/
|
||||||
|
│ ├── marte_benchmark_launcher.sh
|
||||||
|
│ ├── marte_benchmark_launcher_s03h1.sh
|
||||||
|
│ ├── marte_benchmark_launcher_s03h3.sh
|
||||||
|
│ └── marte_benchmark_menu.sh
|
||||||
|
│
|
||||||
|
├── patchers/
|
||||||
|
│ └── configuration/
|
||||||
|
│
|
||||||
|
├── scenarios/
|
||||||
|
│ ├── S01_timing_display/
|
||||||
|
│ ├── S02_binary_recording/
|
||||||
|
│ ├── S03_semantic_sentinels/
|
||||||
|
│ ├── S03H1_execution_profiles/
|
||||||
|
│ └── S03H3_execution_profiles/
|
||||||
|
│
|
||||||
|
└── runs/
|
||||||
|
```
|
||||||
|
|
||||||
|
`runs/` contains execution outputs and is intentionally excluded from normal
|
||||||
|
Git version control.
|
||||||
|
|
||||||
|
The configurations under `configurations/generated/` are NOT generic build
|
||||||
|
artifacts. They represent configuration baselines produced by controlled
|
||||||
|
project stages and are therefore versioned.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Common runtime layer
|
||||||
|
|
||||||
|
## `common/paths.sh`
|
||||||
|
|
||||||
|
Centralizes the paths used by the benchmark infrastructure.
|
||||||
|
|
||||||
|
Its purpose is to avoid hard-coding the same MARTe and project locations in
|
||||||
|
multiple scripts.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## `common/environment.sh`
|
||||||
|
|
||||||
|
Defines the common execution environment used by the benchmark scripts.
|
||||||
|
|
||||||
|
Keeping environment handling in one place improves reproducibility and avoids
|
||||||
|
different scenarios silently using different runtime assumptions.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## `common/marte_runner.sh`
|
||||||
|
|
||||||
|
Provides the common MARTe execution mechanism shared by benchmark stages.
|
||||||
|
|
||||||
|
Conceptually:
|
||||||
|
|
||||||
|
```text
|
||||||
|
launcher
|
||||||
|
↓
|
||||||
|
common runner
|
||||||
|
↓
|
||||||
|
MARTeApp.ex
|
||||||
|
↓
|
||||||
|
run directory
|
||||||
|
↓
|
||||||
|
logs / outputs
|
||||||
|
```
|
||||||
|
|
||||||
|
Higher-level stages should reuse the authoritative runner rather than create
|
||||||
|
alternative MARTe execution paths unless a future specification explicitly
|
||||||
|
authorizes such a change.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Launchers
|
||||||
|
|
||||||
|
The `launcher/` directory contains the user-facing execution layer.
|
||||||
|
|
||||||
|
The project currently includes launchers from different development stages,
|
||||||
|
including the S03-H1 and S03-H3 generations.
|
||||||
|
|
||||||
|
The current S03-H3 architecture supports execution profiles such as:
|
||||||
|
|
||||||
|
```text
|
||||||
|
MINIMAL
|
||||||
|
TEST
|
||||||
|
DIAGNOSTIC
|
||||||
|
```
|
||||||
|
|
||||||
|
The profiles allow the same benchmark infrastructure to expose different
|
||||||
|
levels of runtime/debug functionality without changing the fundamental
|
||||||
|
correctness contract.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Patchers
|
||||||
|
|
||||||
|
Configuration patchers live under:
|
||||||
|
|
||||||
|
```text
|
||||||
|
patchers/configuration/
|
||||||
|
```
|
||||||
|
|
||||||
|
They transform an already-known configuration into the configuration required
|
||||||
|
by the next development stage.
|
||||||
|
|
||||||
|
The dependency chain currently visible in the repository is:
|
||||||
|
|
||||||
|
```text
|
||||||
|
S00
|
||||||
|
↓
|
||||||
|
build_s01_from_s00.sh
|
||||||
|
↓
|
||||||
|
S01
|
||||||
|
↓
|
||||||
|
build_s02_from_s01.sh
|
||||||
|
↓
|
||||||
|
S02
|
||||||
|
↓
|
||||||
|
build_s03_from_s02.sh
|
||||||
|
↓
|
||||||
|
S03
|
||||||
|
```
|
||||||
|
|
||||||
|
Additional controlled transformations support S03-H1 and S03-H3.
|
||||||
|
|
||||||
|
This model helps preserve provenance:
|
||||||
|
|
||||||
|
```text
|
||||||
|
new configuration
|
||||||
|
=
|
||||||
|
known parent
|
||||||
|
+
|
||||||
|
explicit transformation
|
||||||
|
```
|
||||||
|
|
||||||
|
rather than independently rewriting every configuration from scratch.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Validation layer
|
||||||
|
|
||||||
|
The suite does not consider a MARTe process exit by itself sufficient proof
|
||||||
|
that a test succeeded.
|
||||||
|
|
||||||
|
Validation is layered.
|
||||||
|
|
||||||
|
Depending on the stage, the suite can inspect:
|
||||||
|
|
||||||
|
```text
|
||||||
|
configuration structure
|
||||||
|
+
|
||||||
|
runtime execution
|
||||||
|
+
|
||||||
|
generated files
|
||||||
|
+
|
||||||
|
semantic content
|
||||||
|
+
|
||||||
|
expected sentinels
|
||||||
|
```
|
||||||
|
|
||||||
|
and only then derive the corresponding result.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# S00 — Core reference
|
||||||
|
|
||||||
|
S00 provides the basic MARTe2 reference configuration:
|
||||||
|
|
||||||
|
```text
|
||||||
|
configurations/generated/S00/smoke_s0_core.marte
|
||||||
|
```
|
||||||
|
|
||||||
|
It acts as the root from which later benchmark configurations are progressively
|
||||||
|
derived.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# S01 — Timing
|
||||||
|
|
||||||
|
S01 introduces timing-related observation on top of the S00 reference
|
||||||
|
configuration.
|
||||||
|
|
||||||
|
Relevant current files include:
|
||||||
|
|
||||||
|
```text
|
||||||
|
patchers/configuration/build_s01_from_s00.sh
|
||||||
|
configurations/generated/S01/from_patcher/
|
||||||
|
scenarios/S01_timing_display/validate.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
S01 established infrastructure that later stages could reuse rather than
|
||||||
|
reimplement.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# S02 — Binary recording
|
||||||
|
|
||||||
|
S02 extends the previous stage with binary data recording.
|
||||||
|
|
||||||
|
Relevant components include:
|
||||||
|
|
||||||
|
```text
|
||||||
|
patchers/configuration/build_s02_from_s01.sh
|
||||||
|
|
||||||
|
configurations/generated/S02/from_patcher/
|
||||||
|
smoke_s2_binary_recording_from_s01.marte
|
||||||
|
|
||||||
|
scenarios/S02_binary_recording/validate.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Binary recording provides machine-readable data that later stages can parse
|
||||||
|
and validate.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# S03 — Semantic validation
|
||||||
|
|
||||||
|
S03 adds semantic verification of the generated data.
|
||||||
|
|
||||||
|
Relevant components include:
|
||||||
|
|
||||||
|
```text
|
||||||
|
patchers/configuration/build_s03_from_s02.sh
|
||||||
|
|
||||||
|
configurations/generated/S03/from_patcher/
|
||||||
|
smoke_s3_semantic_sentinels_from_s02.marte
|
||||||
|
|
||||||
|
scenarios/S03_semantic_sentinels/
|
||||||
|
parse_s03_binary.py
|
||||||
|
validate.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
The key conceptual change is:
|
||||||
|
|
||||||
|
```text
|
||||||
|
"data file exists"
|
||||||
|
```
|
||||||
|
|
||||||
|
is not enough.
|
||||||
|
|
||||||
|
The project also checks whether the data means what the test expected it to
|
||||||
|
mean.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# S03-H1 — Execution profiles
|
||||||
|
|
||||||
|
S03-H1 introduced explicit execution profiles and supporting validation
|
||||||
|
infrastructure.
|
||||||
|
|
||||||
|
Current repository elements include:
|
||||||
|
|
||||||
|
```text
|
||||||
|
launcher/marte_benchmark_launcher_s03h1.sh
|
||||||
|
|
||||||
|
patchers/configuration/
|
||||||
|
build_s03h1_from_s02.sh
|
||||||
|
|
||||||
|
scenarios/S03H1_execution_profiles/
|
||||||
|
export_s03_csv.py
|
||||||
|
validate.sh
|
||||||
|
verify_s03h1_config.py
|
||||||
|
```
|
||||||
|
|
||||||
|
The historical S03-H1 configurations currently retained are:
|
||||||
|
|
||||||
|
```text
|
||||||
|
TEST
|
||||||
|
DIAGNOSTIC
|
||||||
|
```
|
||||||
|
|
||||||
|
They remain important because S03-H3 intentionally reuses validated historical
|
||||||
|
configurations where appropriate instead of duplicating them unnecessarily.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# S03-H3 — Current known-good baseline
|
||||||
|
|
||||||
|
S03-H3 is the current closed benchmark stage.
|
||||||
|
|
||||||
|
Its role is to formalize the execution-profile architecture and protect the
|
||||||
|
runtime contract used by future development.
|
||||||
|
|
||||||
|
Relevant repository elements include:
|
||||||
|
|
||||||
|
```text
|
||||||
|
launcher/
|
||||||
|
marte_benchmark_launcher_s03h3.sh
|
||||||
|
marte_benchmark_menu.sh
|
||||||
|
|
||||||
|
patchers/configuration/
|
||||||
|
build_s03h3_minimal_from_s03h1_test.sh
|
||||||
|
|
||||||
|
configurations/generated/S03H3/from_patcher/
|
||||||
|
smoke_s03h3_execution_profiles_minimal_from_s03h1_test.marte
|
||||||
|
|
||||||
|
scenarios/S03H3_execution_profiles/
|
||||||
|
validate.sh
|
||||||
|
verify_s03h3_minimal_structure.py
|
||||||
|
```
|
||||||
|
|
||||||
|
S03-H3 defines three go-forward execution profiles:
|
||||||
|
|
||||||
|
```text
|
||||||
|
MINIMAL
|
||||||
|
TEST
|
||||||
|
DIAGNOSTIC
|
||||||
|
```
|
||||||
|
|
||||||
|
The MINIMAL configuration is derived from the validated S03-H1 TEST
|
||||||
|
configuration by explicitly removing unnecessary display functionality while
|
||||||
|
preserving the required execution behaviour.
|
||||||
|
|
||||||
|
TEST and DIAGNOSTIC reuse their validated historical configurations.
|
||||||
|
|
||||||
|
This avoids unnecessary duplication and reduces the number of independent
|
||||||
|
configuration variants that must be trusted.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Why S03-H3 matters
|
||||||
|
|
||||||
|
Before advancing toward larger benchmark campaigns, the project needs one
|
||||||
|
well-understood baseline.
|
||||||
|
|
||||||
|
S03-H3 provides that reference point.
|
||||||
|
|
||||||
|
Conceptually:
|
||||||
|
|
||||||
|
```text
|
||||||
|
KNOWN INPUT
|
||||||
|
↓
|
||||||
|
KNOWN CONFIGURATION
|
||||||
|
↓
|
||||||
|
KNOWN LAUNCHER
|
||||||
|
↓
|
||||||
|
KNOWN RUNTIME DEPENDENCIES
|
||||||
|
↓
|
||||||
|
KNOWN VALIDATION
|
||||||
|
↓
|
||||||
|
KNOWN-GOOD RESULT
|
||||||
|
```
|
||||||
|
|
||||||
|
Future stages should extend this baseline rather than silently redefine it.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Runtime dependencies
|
||||||
|
|
||||||
|
The benchmark suite depends on an external MARTe installation.
|
||||||
|
|
||||||
|
The current runtime environment includes:
|
||||||
|
|
||||||
|
```text
|
||||||
|
MARTe2
|
||||||
|
MARTe2-components
|
||||||
|
```
|
||||||
|
|
||||||
|
Important runtime objects include MARTe executables/libraries and component
|
||||||
|
libraries required by the active configurations.
|
||||||
|
|
||||||
|
These external projects are not copied into this repository.
|
||||||
|
|
||||||
|
This repository therefore acts as:
|
||||||
|
|
||||||
|
```text
|
||||||
|
benchmark source + configuration + validation infrastructure
|
||||||
|
```
|
||||||
|
|
||||||
|
and not as a complete binary backup of MARTe.
|
||||||
|
|
||||||
|
A separate verified restore mechanism is required for complete disaster
|
||||||
|
recovery of the known-good runtime environment.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Run directories
|
||||||
|
|
||||||
|
Runtime execution artifacts are written under:
|
||||||
|
|
||||||
|
```text
|
||||||
|
runs/
|
||||||
|
```
|
||||||
|
|
||||||
|
A run directory may contain logs, generated data and validation evidence.
|
||||||
|
|
||||||
|
These files can be large and are produced repeatedly.
|
||||||
|
|
||||||
|
For this reason:
|
||||||
|
|
||||||
|
```text
|
||||||
|
runs/
|
||||||
|
```
|
||||||
|
|
||||||
|
is intentionally excluded through `.gitignore`.
|
||||||
|
|
||||||
|
Git is used for source/configuration history.
|
||||||
|
|
||||||
|
Runtime evidence and full environment recovery are handled separately.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Git versus full restore backup
|
||||||
|
|
||||||
|
The Git repository and the full restore point serve different purposes.
|
||||||
|
|
||||||
|
```text
|
||||||
|
Git
|
||||||
|
│
|
||||||
|
├── scripts
|
||||||
|
├── configurations
|
||||||
|
├── validators
|
||||||
|
├── parsers
|
||||||
|
├── documentation
|
||||||
|
└── development history
|
||||||
|
```
|
||||||
|
|
||||||
|
while a complete restore point additionally needs the external runtime
|
||||||
|
environment required to reproduce the validated MARTe execution.
|
||||||
|
|
||||||
|
Therefore:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Git backup ≠ complete runtime restore point
|
||||||
|
```
|
||||||
|
|
||||||
|
Both mechanisms are complementary.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Development governance
|
||||||
|
|
||||||
|
The project follows a controlled development process.
|
||||||
|
|
||||||
|
A typical new stage follows approximately:
|
||||||
|
|
||||||
|
```text
|
||||||
|
DESIGN / SPECIFICATION
|
||||||
|
↓
|
||||||
|
independent technical review
|
||||||
|
↓
|
||||||
|
technical arbitration
|
||||||
|
↓
|
||||||
|
human freeze
|
||||||
|
↓
|
||||||
|
implementation
|
||||||
|
↓
|
||||||
|
tests
|
||||||
|
↓
|
||||||
|
independent implementation review
|
||||||
|
↓
|
||||||
|
technical arbitration
|
||||||
|
↓
|
||||||
|
human acceptance
|
||||||
|
↓
|
||||||
|
new known-good baseline
|
||||||
|
```
|
||||||
|
|
||||||
|
A development-stage implementation is therefore not automatically considered
|
||||||
|
part of the authoritative baseline simply because code exists.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Planned roadmap
|
||||||
|
|
||||||
|
## S04 — Repeatability / Multi-Run
|
||||||
|
|
||||||
|
Main question:
|
||||||
|
|
||||||
|
> Does the same already-valid S03-H3 workload remain correct when executed
|
||||||
|
> repeatedly?
|
||||||
|
|
||||||
|
Conceptually:
|
||||||
|
|
||||||
|
```text
|
||||||
|
S03-H3 run #1 → result
|
||||||
|
S03-H3 run #2 → result
|
||||||
|
S03-H3 run #3 → result
|
||||||
|
...
|
||||||
|
S03-H3 run #N → result
|
||||||
|
↓
|
||||||
|
campaign-level repeatability result
|
||||||
|
```
|
||||||
|
|
||||||
|
S04 is primarily a correctness/repeatability stage.
|
||||||
|
|
||||||
|
It is not intended to turn repeatability percentages or CycleTime observations
|
||||||
|
into performance claims.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## S05 — Deterministic Parametric Generator
|
||||||
|
|
||||||
|
Main question:
|
||||||
|
|
||||||
|
> Can test workloads be generated automatically from controlled parameters
|
||||||
|
> while remaining reproducible?
|
||||||
|
|
||||||
|
Conceptually:
|
||||||
|
|
||||||
|
```text
|
||||||
|
parameters
|
||||||
|
+
|
||||||
|
seed
|
||||||
|
↓
|
||||||
|
generator
|
||||||
|
↓
|
||||||
|
deterministic MARTe scenario
|
||||||
|
```
|
||||||
|
|
||||||
|
The same inputs should regenerate the same intended scenario.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## S06 — MARTe2 Core Scaling
|
||||||
|
|
||||||
|
Main question:
|
||||||
|
|
||||||
|
> How does the MARTe2 Core workload behave as controlled complexity increases?
|
||||||
|
|
||||||
|
S06 is expected to reuse the capabilities established by the preceding stages:
|
||||||
|
|
||||||
|
```text
|
||||||
|
S03-H3 → correctness baseline
|
||||||
|
S04 → repeatable execution
|
||||||
|
S05 → deterministic workload generation
|
||||||
|
S06 → controlled scaling study
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Current boundary
|
||||||
|
|
||||||
|
At the time of this README baseline:
|
||||||
|
|
||||||
|
```text
|
||||||
|
S03-H3 = CLOSED / KNOWN-GOOD
|
||||||
|
|
||||||
|
S04 = next development target
|
||||||
|
S05 = planned
|
||||||
|
S06 = planned
|
||||||
|
```
|
||||||
|
|
||||||
|
The existence of this roadmap must not be interpreted as evidence that S04,
|
||||||
|
S05 or S06 have already been implemented or validated.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Repository philosophy
|
||||||
|
|
||||||
|
The repository should remain:
|
||||||
|
|
||||||
|
```text
|
||||||
|
small
|
||||||
|
reviewable
|
||||||
|
deterministic
|
||||||
|
traceable
|
||||||
|
reproducible
|
||||||
|
```
|
||||||
|
|
||||||
|
Generated runtime outputs should not be mixed with source history.
|
||||||
|
|
||||||
|
Known-good configurations, however, may intentionally be versioned even when
|
||||||
|
they were produced by controlled patchers, because they are part of the
|
||||||
|
validated benchmark baseline.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# License and distribution
|
||||||
|
|
||||||
|
The licensing and distribution policy for this benchmark suite must be defined
|
||||||
|
by the project owners before public redistribution.
|
||||||
|
|
||||||
|
MARTe2 and MARTe2-components retain their respective upstream licensing and
|
||||||
|
ownership terms.
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Determina la directory common indipendentemente dalla directory corrente.
|
||||||
|
MARTE_COMMON_DIR="$(
|
||||||
|
cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 &&
|
||||||
|
pwd
|
||||||
|
)"
|
||||||
|
|
||||||
|
# Carica i percorsi canonici della benchmark suite.
|
||||||
|
source "$MARTE_COMMON_DIR/paths.sh"
|
||||||
|
|
||||||
|
# Directory contenenti le librerie richieste dagli scenari S00, S01 e S02.
|
||||||
|
MARTE2_CORE_LIB_DIR="$MARTE2_ROOT/Build/$MARTE_TARGET/Core"
|
||||||
|
LINUX_TIMER_LIB_DIR="$MARTE2_COMPONENTS_ROOT/Build/$MARTE_TARGET/Components/DataSources/LinuxTimer"
|
||||||
|
LOGGER_DATA_SOURCE_LIB_DIR="$MARTE2_COMPONENTS_ROOT/Build/$MARTE_TARGET/Components/DataSources/LoggerDataSource"
|
||||||
|
FILE_DATA_SOURCE_LIB_DIR="$MARTE2_COMPONENTS_ROOT/Build/$MARTE_TARGET/Components/DataSources/FileDataSource"
|
||||||
|
IOGAM_LIB_DIR="$MARTE2_COMPONENTS_ROOT/Build/$MARTE_TARGET/Components/GAMs/IOGAM"
|
||||||
|
|
||||||
|
# Librerie che devono essere presenti.
|
||||||
|
MARTE2_CORE_LIB="$MARTE2_CORE_LIB_DIR/MARTe2.so"
|
||||||
|
LINUX_TIMER_LIB="$LINUX_TIMER_LIB_DIR/LinuxTimer.so"
|
||||||
|
LOGGER_DATA_SOURCE_LIB="$LOGGER_DATA_SOURCE_LIB_DIR/LoggerDataSource.so"
|
||||||
|
FILE_DATA_SOURCE_LIB="$FILE_DATA_SOURCE_LIB_DIR/FileDataSource.so"
|
||||||
|
IOGAM_LIB="$IOGAM_LIB_DIR/IOGAM.so"
|
||||||
|
|
||||||
|
# Verifica delle directory runtime.
|
||||||
|
for marte_runtime_dir in \
|
||||||
|
"$MARTE2_CORE_LIB_DIR" \
|
||||||
|
"$LINUX_TIMER_LIB_DIR" \
|
||||||
|
"$LOGGER_DATA_SOURCE_LIB_DIR" \
|
||||||
|
"$FILE_DATA_SOURCE_LIB_DIR" \
|
||||||
|
"$IOGAM_LIB_DIR"
|
||||||
|
do
|
||||||
|
if [ ! -d "$marte_runtime_dir" ]; then
|
||||||
|
printf "DIRECTORY RUNTIME ASSENTE: %s\n" "$marte_runtime_dir" >&2
|
||||||
|
return 2 2>/dev/null || exit 2
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Verifica delle librerie runtime.
|
||||||
|
for marte_runtime_lib in \
|
||||||
|
"$MARTE2_CORE_LIB" \
|
||||||
|
"$LINUX_TIMER_LIB" \
|
||||||
|
"$LOGGER_DATA_SOURCE_LIB" \
|
||||||
|
"$FILE_DATA_SOURCE_LIB" \
|
||||||
|
"$IOGAM_LIB"
|
||||||
|
do
|
||||||
|
if [ ! -f "$marte_runtime_lib" ]; then
|
||||||
|
printf "LIBRERIA RUNTIME ASSENTE: %s\n" "$marte_runtime_lib" >&2
|
||||||
|
return 3 2>/dev/null || exit 3
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Inserisce una directory allinizio di LD_LIBRARY_PATH solo se non è già presente.
|
||||||
|
marte_prepend_library_path() {
|
||||||
|
marte_directory="$1"
|
||||||
|
|
||||||
|
case ":${LD_LIBRARY_PATH-}:" in
|
||||||
|
*":${marte_directory}:"*)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [ -n "${LD_LIBRARY_PATH-}" ]; then
|
||||||
|
LD_LIBRARY_PATH="${marte_directory}:${LD_LIBRARY_PATH}"
|
||||||
|
else
|
||||||
|
LD_LIBRARY_PATH="${marte_directory}"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Ordine inverso perché ogni voce viene inserita in testa.
|
||||||
|
marte_prepend_library_path "$FILE_DATA_SOURCE_LIB_DIR"
|
||||||
|
marte_prepend_library_path "$IOGAM_LIB_DIR"
|
||||||
|
marte_prepend_library_path "$LOGGER_DATA_SOURCE_LIB_DIR"
|
||||||
|
marte_prepend_library_path "$LINUX_TIMER_LIB_DIR"
|
||||||
|
marte_prepend_library_path "$MARTE2_CORE_LIB_DIR"
|
||||||
|
|
||||||
|
export MARTE2_CORE_LIB_DIR
|
||||||
|
export LINUX_TIMER_LIB_DIR
|
||||||
|
export LOGGER_DATA_SOURCE_LIB_DIR
|
||||||
|
export FILE_DATA_SOURCE_LIB_DIR
|
||||||
|
export IOGAM_LIB_DIR
|
||||||
|
export LD_LIBRARY_PATH
|
||||||
|
|
||||||
|
unset marte_runtime_dir
|
||||||
|
unset marte_runtime_lib
|
||||||
|
unset marte_directory
|
||||||
|
unset -f marte_prepend_library_path
|
||||||
Executable
+196
@@ -0,0 +1,196 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -u
|
||||||
|
|
||||||
|
if [ "$#" -ne 4 ]; then
|
||||||
|
printf "Uso: %s <scenario-id> <configurazione> <stato> <durata-secondi>\n" \
|
||||||
|
"$0" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
SCENARIO_ID="$1"
|
||||||
|
CONFIG_FILE="$2"
|
||||||
|
REQUESTED_STATE="$3"
|
||||||
|
DURATION_SECONDS="$4"
|
||||||
|
|
||||||
|
COMMON_DIR="$(
|
||||||
|
cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 &&
|
||||||
|
pwd
|
||||||
|
)"
|
||||||
|
|
||||||
|
ENV_FILE="$COMMON_DIR/environment.sh"
|
||||||
|
PATHS_FILE="$COMMON_DIR/paths.sh"
|
||||||
|
|
||||||
|
if [ ! -f "$ENV_FILE" ]; then
|
||||||
|
printf "FILE AMBIENTE ASSENTE: %s\n" "$ENV_FILE" >&2
|
||||||
|
exit 3
|
||||||
|
fi
|
||||||
|
|
||||||
|
source "$ENV_FILE"
|
||||||
|
|
||||||
|
if [ ! -x "$MARTE_APP" ]; then
|
||||||
|
printf "MARTeApp ASSENTE O NON ESEGUIBILE: %s\n" "$MARTE_APP" >&2
|
||||||
|
exit 4
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$CONFIG_FILE" ]; then
|
||||||
|
printf "CONFIGURAZIONE ASSENTE: %s\n" "$CONFIG_FILE" >&2
|
||||||
|
exit 5
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$SCENARIO_ID" in
|
||||||
|
*[!A-Za-z0-9_-]*|"")
|
||||||
|
printf "IDENTIFICATORE SCENARIO NON VALIDO: %s\n" "$SCENARIO_ID" >&2
|
||||||
|
exit 6
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "$REQUESTED_STATE" in
|
||||||
|
*[!A-Za-z0-9_-]*|"")
|
||||||
|
printf "NOME STATO NON VALIDO: %s\n" "$REQUESTED_STATE" >&2
|
||||||
|
exit 7
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "$DURATION_SECONDS" in
|
||||||
|
*[!0-9]*|"")
|
||||||
|
printf "DURATA NON VALIDA: %s\n" "$DURATION_SECONDS" >&2
|
||||||
|
exit 8
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ "$DURATION_SECONDS" -le 0 ]; then
|
||||||
|
printf "LA DURATA DEVE ESSERE MAGGIORE DI ZERO.\n" >&2
|
||||||
|
exit 8
|
||||||
|
fi
|
||||||
|
|
||||||
|
STAMP="$(date +%Y%m%d_%H%M%S)"
|
||||||
|
RUN_DIR="$RUNS_ROOT/${STAMP}_${SCENARIO_ID}"
|
||||||
|
RUN_CONFIG="$RUN_DIR/configuration.marte"
|
||||||
|
RUN_LOG="$RUN_DIR/run.log"
|
||||||
|
RUN_SUMMARY="$RUN_DIR/runner_summary.txt"
|
||||||
|
RUN_HASHES="$RUN_DIR/hashes.sha256"
|
||||||
|
RUN_COMMAND="$RUN_DIR/command.txt"
|
||||||
|
|
||||||
|
mkdir -p -- "$RUN_DIR"
|
||||||
|
|
||||||
|
cp --preserve=mode,timestamps -- "$CONFIG_FILE" "$RUN_CONFIG"
|
||||||
|
|
||||||
|
RUN_DIR_PLACEHOLDER="__MARTE_RUN_DIR__"
|
||||||
|
|
||||||
|
PLACEHOLDER_COUNT="$(
|
||||||
|
python3 - "$RUN_CONFIG" "$RUN_DIR_PLACEHOLDER" "$RUN_DIR" <<'PYRUNNER'
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
config_path = Path(sys.argv[1])
|
||||||
|
placeholder = sys.argv[2]
|
||||||
|
run_dir = sys.argv[3]
|
||||||
|
|
||||||
|
text = config_path.read_text(encoding="utf-8")
|
||||||
|
count = text.count(placeholder)
|
||||||
|
|
||||||
|
if count > 0:
|
||||||
|
config_path.write_text(
|
||||||
|
text.replace(placeholder, run_dir),
|
||||||
|
encoding="utf-8"
|
||||||
|
)
|
||||||
|
|
||||||
|
remaining = config_path.read_text(
|
||||||
|
encoding="utf-8"
|
||||||
|
).count(placeholder)
|
||||||
|
|
||||||
|
if remaining != 0:
|
||||||
|
print(
|
||||||
|
f"PLACEHOLDER_RESIDUI={remaining}",
|
||||||
|
file=sys.stderr
|
||||||
|
)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print(count)
|
||||||
|
PYRUNNER
|
||||||
|
)"
|
||||||
|
PLACEHOLDER_RC=$?
|
||||||
|
|
||||||
|
if [ "$PLACEHOLDER_RC" -ne 0 ]; then
|
||||||
|
printf "ERRORE DURANTE LA SOSTITUZIONE DEL PERCORSO RUN.\n" >&2
|
||||||
|
exit 9
|
||||||
|
fi
|
||||||
|
|
||||||
|
{
|
||||||
|
printf "%q " \
|
||||||
|
timeout \
|
||||||
|
--signal=INT \
|
||||||
|
--kill-after=2s \
|
||||||
|
"${DURATION_SECONDS}s" \
|
||||||
|
"$MARTE_APP" \
|
||||||
|
-l RealTimeLoader \
|
||||||
|
-f "$RUN_CONFIG" \
|
||||||
|
-s "$REQUESTED_STATE"
|
||||||
|
printf "\n"
|
||||||
|
} > "$RUN_COMMAND"
|
||||||
|
|
||||||
|
{
|
||||||
|
sha256sum -- "$CONFIG_FILE"
|
||||||
|
sha256sum -- "$RUN_CONFIG"
|
||||||
|
sha256sum -- "$PATHS_FILE"
|
||||||
|
sha256sum -- "$ENV_FILE"
|
||||||
|
sha256sum -- "${BASH_SOURCE[0]}"
|
||||||
|
} > "$RUN_HASHES"
|
||||||
|
|
||||||
|
printf "============================================================\n"
|
||||||
|
printf "MARTe2 COMMON RUNNER\n"
|
||||||
|
printf "============================================================\n"
|
||||||
|
printf "Scenario: %s\n" "$SCENARIO_ID"
|
||||||
|
printf "Configurazione: %s\n" "$RUN_CONFIG"
|
||||||
|
printf "Stato: %s\n" "$REQUESTED_STATE"
|
||||||
|
printf "Durata: %s secondi\n" "$DURATION_SECONDS"
|
||||||
|
printf "Run directory: %s\n" "$RUN_DIR"
|
||||||
|
printf "Placeholder: %s sostituzioni\n" "$PLACEHOLDER_COUNT"
|
||||||
|
printf "\n"
|
||||||
|
|
||||||
|
set +e
|
||||||
|
|
||||||
|
timeout \
|
||||||
|
--signal=INT \
|
||||||
|
--kill-after=2s \
|
||||||
|
"${DURATION_SECONDS}s" \
|
||||||
|
"$MARTE_APP" \
|
||||||
|
-l RealTimeLoader \
|
||||||
|
-f "$RUN_CONFIG" \
|
||||||
|
-s "$REQUESTED_STATE" \
|
||||||
|
2>&1 |
|
||||||
|
tee "$RUN_LOG"
|
||||||
|
|
||||||
|
PIPE_CODES=("${PIPESTATUS[@]}")
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
MARTE_EXIT_CODE="${PIPE_CODES[0]}"
|
||||||
|
TEE_EXIT_CODE="${PIPE_CODES[1]}"
|
||||||
|
|
||||||
|
{
|
||||||
|
printf "============================================================\n"
|
||||||
|
printf "RIEPILOGO COMMON RUNNER\n"
|
||||||
|
printf "============================================================\n"
|
||||||
|
printf "Data: %s\n" "$(date --iso-8601=seconds)"
|
||||||
|
printf "Scenario: %s\n" "$SCENARIO_ID"
|
||||||
|
printf "Configurazione fonte: %s\n" "$CONFIG_FILE"
|
||||||
|
printf "Configurazione usata: %s\n" "$RUN_CONFIG"
|
||||||
|
printf "Stato richiesto: %s\n" "$REQUESTED_STATE"
|
||||||
|
printf "Durata richiesta: %s secondi\n" "$DURATION_SECONDS"
|
||||||
|
printf "Placeholder sostituiti: %s\n" "$PLACEHOLDER_COUNT"
|
||||||
|
printf "Exit code MARTe: %s\n" "$MARTE_EXIT_CODE"
|
||||||
|
printf "Exit code tee: %s\n" "$TEE_EXIT_CODE"
|
||||||
|
printf "Run log: %s\n" "$RUN_LOG"
|
||||||
|
printf "Hash: %s\n" "$RUN_HASHES"
|
||||||
|
printf "Comando: %s\n" "$RUN_COMMAND"
|
||||||
|
} | tee "$RUN_SUMMARY"
|
||||||
|
|
||||||
|
printf "\nRUN_DIR=%s\n" "$RUN_DIR"
|
||||||
|
|
||||||
|
if [ "$TEE_EXIT_CODE" -ne 0 ]; then
|
||||||
|
printf "ERRORE DURANTE LA SCRITTURA DEL LOG.\n" >&2
|
||||||
|
exit 30
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Percorso padre dei repository e della benchmark suite.
|
||||||
|
MARTE_ROOT="/home/dariodf/Scrivania/MARTE"
|
||||||
|
|
||||||
|
# Repository esterni usati dalla benchmark suite.
|
||||||
|
MARTE2_ROOT="$MARTE_ROOT/MARTe2"
|
||||||
|
MARTE2_COMPONENTS_ROOT="$MARTE_ROOT/MARTe2-components"
|
||||||
|
MARTE_DEBUG_ROOT="$MARTE_ROOT/marte-debug"
|
||||||
|
|
||||||
|
# Directory principale della nuova infrastruttura di test.
|
||||||
|
BENCHMARK_SUITE_ROOT="$MARTE_ROOT/marte-benchmark-suite"
|
||||||
|
|
||||||
|
# Target di compilazione attualmente utilizzato.
|
||||||
|
MARTE_TARGET="x86-linux"
|
||||||
|
|
||||||
|
# Eseguibile MARTe2.
|
||||||
|
MARTE_APP="$MARTE2_ROOT/Build/$MARTE_TARGET/App/MARTeApp.ex"
|
||||||
|
|
||||||
|
# Directory delle configurazioni.
|
||||||
|
CONFIGURATIONS_ROOT="$BENCHMARK_SUITE_ROOT/configurations"
|
||||||
|
BASELINES_ROOT="$CONFIGURATIONS_ROOT/baselines"
|
||||||
|
GENERATED_CONFIGURATIONS_ROOT="$CONFIGURATIONS_ROOT/generated"
|
||||||
|
|
||||||
|
# Configurazioni attualmente disponibili.
|
||||||
|
OFFICIAL_HELLOWORLD_CONFIG="$BASELINES_ROOT/RTApp-HelloWorld-2-solution.cfg"
|
||||||
|
S00_CONFIG="$GENERATED_CONFIGURATIONS_ROOT/S00/smoke_s0_core.marte"
|
||||||
|
S01_CONFIG="$GENERATED_CONFIGURATIONS_ROOT/S01/smoke_s1_timing.marte"
|
||||||
|
|
||||||
|
# Directory operative della suite.
|
||||||
|
SCENARIOS_ROOT="$BENCHMARK_SUITE_ROOT/scenarios"
|
||||||
|
PATCHERS_ROOT="$BENCHMARK_SUITE_ROOT/patchers"
|
||||||
|
RUNS_ROOT="$BENCHMARK_SUITE_ROOT/runs"
|
||||||
|
ANALYSIS_ROOT="$BENCHMARK_SUITE_ROOT/analysis"
|
||||||
|
LOGGING_ROOT="$BENCHMARK_SUITE_ROOT/logging"
|
||||||
|
ARCHIVE_ROOT="$BENCHMARK_SUITE_ROOT/archive"
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
$HelloWorldApp = {
|
||||||
|
Class = RealTimeApplication
|
||||||
|
+Functions = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
+GAMTimer = {
|
||||||
|
Class = IOGAM
|
||||||
|
InputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = Timer
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
Frequency = 10
|
||||||
|
DataSource = Timer
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+GAMDisplay = {
|
||||||
|
Class = IOGAM
|
||||||
|
InputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = Display
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+Data = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
DefaultDataSource = DDB1
|
||||||
|
+DDB1 = {
|
||||||
|
Class = GAMDataSource
|
||||||
|
}
|
||||||
|
+Display = {
|
||||||
|
Class = LoggerDataSource
|
||||||
|
}
|
||||||
|
+Timings = {
|
||||||
|
Class = TimingDataSource
|
||||||
|
}
|
||||||
|
+Timer = {
|
||||||
|
Class = LinuxTimer
|
||||||
|
SleepNature = "Default"
|
||||||
|
Signals = {
|
||||||
|
Counter = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+States = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
+State1 = {
|
||||||
|
Class = RealTimeState
|
||||||
|
+Threads = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
+Thread1 = {
|
||||||
|
Class = RealTimeThread
|
||||||
|
CPUs = 0x1
|
||||||
|
Functions = {GAMTimer GAMDisplay}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+Scheduler = {
|
||||||
|
Class = GAMScheduler
|
||||||
|
TimingDataSource = Timings
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
$HelloWorldApp = {
|
||||||
|
Class = RealTimeApplication
|
||||||
|
+Functions = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
+GAMTimer = {
|
||||||
|
Class = IOGAM
|
||||||
|
InputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = Timer
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
Frequency = 10
|
||||||
|
DataSource = Timer
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+GAMDisplay = {
|
||||||
|
Class = IOGAM
|
||||||
|
InputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
State1_Thread1_CycleTime = {
|
||||||
|
Alias = State1.Thread1_CycleTime
|
||||||
|
DataSource = Timings
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = Display
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
State1_Thread1_CycleTime = {
|
||||||
|
DataSource = Display
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+Data = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
DefaultDataSource = DDB1
|
||||||
|
+DDB1 = {
|
||||||
|
Class = GAMDataSource
|
||||||
|
}
|
||||||
|
+Display = {
|
||||||
|
Class = LoggerDataSource
|
||||||
|
}
|
||||||
|
+Timings = {
|
||||||
|
Class = TimingDataSource
|
||||||
|
}
|
||||||
|
+Timer = {
|
||||||
|
Class = LinuxTimer
|
||||||
|
SleepNature = "Default"
|
||||||
|
Signals = {
|
||||||
|
Counter = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+States = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
+State1 = {
|
||||||
|
Class = RealTimeState
|
||||||
|
+Threads = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
+Thread1 = {
|
||||||
|
Class = RealTimeThread
|
||||||
|
CPUs = 0x1
|
||||||
|
Functions = {GAMTimer GAMDisplay}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+Scheduler = {
|
||||||
|
Class = GAMScheduler
|
||||||
|
TimingDataSource = Timings
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
$HelloWorldApp = {
|
||||||
|
Class = RealTimeApplication
|
||||||
|
+Functions = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
+GAMTimer = {
|
||||||
|
Class = IOGAM
|
||||||
|
InputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = Timer
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
Frequency = 10
|
||||||
|
DataSource = Timer
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+GAMDisplay = {
|
||||||
|
Class = IOGAM
|
||||||
|
InputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
State1_Thread1_CycleTime = {
|
||||||
|
Alias = State1.Thread1_CycleTime
|
||||||
|
DataSource = Timings
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = Display
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
State1_Thread1_CycleTime = {
|
||||||
|
DataSource = Display
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+IOGAM_Writer = {
|
||||||
|
Class = IOGAM
|
||||||
|
InputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
State1_Thread1_CycleTime = {
|
||||||
|
Alias = State1.Thread1_CycleTime
|
||||||
|
DataSource = Timings
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
State1_Thread1_CycleTime = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+Data = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
DefaultDataSource = DDB1
|
||||||
|
+DDB1 = {
|
||||||
|
Class = GAMDataSource
|
||||||
|
}
|
||||||
|
+Display = {
|
||||||
|
Class = LoggerDataSource
|
||||||
|
}
|
||||||
|
+Timings = {
|
||||||
|
Class = TimingDataSource
|
||||||
|
}
|
||||||
|
+Timer = {
|
||||||
|
Class = LinuxTimer
|
||||||
|
SleepNature = "Default"
|
||||||
|
Signals = {
|
||||||
|
Counter = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+FileWriter = {
|
||||||
|
Class = FileDataSource::FileWriter
|
||||||
|
NumberOfBuffers = 100
|
||||||
|
CPUMask = 0x1
|
||||||
|
StackSize = 10000000
|
||||||
|
Filename = "__MARTE_RUN_DIR__/s02_output.bin"
|
||||||
|
Overwrite = "yes"
|
||||||
|
FileFormat = "binary"
|
||||||
|
StoreOnTrigger = 0
|
||||||
|
RefreshContent = 0
|
||||||
|
Signals = {
|
||||||
|
Counter = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
State1_Thread1_CycleTime = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+States = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
+State1 = {
|
||||||
|
Class = RealTimeState
|
||||||
|
+Threads = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
+Thread1 = {
|
||||||
|
Class = RealTimeThread
|
||||||
|
CPUs = 0x1
|
||||||
|
Functions = {GAMTimer GAMDisplay IOGAM_Writer}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+Scheduler = {
|
||||||
|
Class = GAMScheduler
|
||||||
|
TimingDataSource = Timings
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,220 @@
|
|||||||
|
$HelloWorldApp = {
|
||||||
|
Class = RealTimeApplication
|
||||||
|
+Functions = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
+GAMTimer = {
|
||||||
|
Class = IOGAM
|
||||||
|
InputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = Timer
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
Frequency = 10
|
||||||
|
DataSource = Timer
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+SentinelProducer = {
|
||||||
|
Class = ConstantGAM
|
||||||
|
OutputSignals = {
|
||||||
|
SentinelScalarA = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
Default = 324508639
|
||||||
|
}
|
||||||
|
SentinelScalarB = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
Default = 610839776
|
||||||
|
}
|
||||||
|
SentinelVector = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfDimensions = 1
|
||||||
|
NumberOfElements = 3
|
||||||
|
Default = {16909060 286397204 555885348}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+GAMDisplay = {
|
||||||
|
Class = IOGAM
|
||||||
|
InputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
State1_Thread1_CycleTime = {
|
||||||
|
Alias = State1.Thread1_CycleTime
|
||||||
|
DataSource = Timings
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = Display
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
State1_Thread1_CycleTime = {
|
||||||
|
DataSource = Display
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+IOGAM_Writer = {
|
||||||
|
Class = IOGAM
|
||||||
|
InputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
State1_Thread1_CycleTime = {
|
||||||
|
Alias = State1.Thread1_CycleTime
|
||||||
|
DataSource = Timings
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
SentinelScalarA = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelScalarB = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelVector = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfDimensions = 1
|
||||||
|
NumberOfElements = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
State1_Thread1_CycleTime = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
SentinelScalarA = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelScalarB = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelVector = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
NumberOfDimensions = 1
|
||||||
|
NumberOfElements = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+Data = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
DefaultDataSource = DDB1
|
||||||
|
+DDB1 = {
|
||||||
|
Class = GAMDataSource
|
||||||
|
}
|
||||||
|
+Display = {
|
||||||
|
Class = LoggerDataSource
|
||||||
|
}
|
||||||
|
+Timings = {
|
||||||
|
Class = TimingDataSource
|
||||||
|
}
|
||||||
|
+Timer = {
|
||||||
|
Class = LinuxTimer
|
||||||
|
SleepNature = "Default"
|
||||||
|
Signals = {
|
||||||
|
Counter = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+FileWriter = {
|
||||||
|
Class = FileDataSource::FileWriter
|
||||||
|
NumberOfBuffers = 100
|
||||||
|
CPUMask = 0x1
|
||||||
|
StackSize = 10000000
|
||||||
|
Filename = "__MARTE_RUN_DIR__/s03_output.bin"
|
||||||
|
Overwrite = "yes"
|
||||||
|
FileFormat = "binary"
|
||||||
|
StoreOnTrigger = 0
|
||||||
|
RefreshContent = 0
|
||||||
|
Signals = {
|
||||||
|
Counter = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
State1_Thread1_CycleTime = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
SentinelScalarA = {
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelScalarB = {
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelVector = {
|
||||||
|
Type = uint32
|
||||||
|
NumberOfDimensions = 1
|
||||||
|
NumberOfElements = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+States = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
+State1 = {
|
||||||
|
Class = RealTimeState
|
||||||
|
+Threads = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
+Thread1 = {
|
||||||
|
Class = RealTimeThread
|
||||||
|
CPUs = 0x1
|
||||||
|
Functions = {GAMTimer SentinelProducer GAMDisplay IOGAM_Writer}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+Scheduler = {
|
||||||
|
Class = GAMScheduler
|
||||||
|
TimingDataSource = Timings
|
||||||
|
}
|
||||||
|
}
|
||||||
+260
@@ -0,0 +1,260 @@
|
|||||||
|
$HelloWorldApp = {
|
||||||
|
Class = RealTimeApplication
|
||||||
|
+Functions = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
+GAMTimer = {
|
||||||
|
Class = IOGAM
|
||||||
|
InputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = Timer
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
Frequency = 10
|
||||||
|
DataSource = Timer
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+SentinelProducer = {
|
||||||
|
Class = ConstantGAM
|
||||||
|
OutputSignals = {
|
||||||
|
SentinelScalarA = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
Default = 324508639
|
||||||
|
}
|
||||||
|
SentinelScalarB = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
Default = 610839776
|
||||||
|
}
|
||||||
|
SentinelVector = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfDimensions = 1
|
||||||
|
NumberOfElements = 3
|
||||||
|
Default = {16909060 286397204 555885348}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+GAMDisplay = {
|
||||||
|
Class = IOGAM
|
||||||
|
InputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
State1_Thread1_CycleTime = {
|
||||||
|
Alias = State1.Thread1_CycleTime
|
||||||
|
DataSource = Timings
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
SentinelScalarA = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelScalarB = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelVector = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfDimensions = 1
|
||||||
|
NumberOfElements = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = Display
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
DataSource = Display
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
State1_Thread1_CycleTime = {
|
||||||
|
DataSource = Display
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
SentinelScalarA = {
|
||||||
|
DataSource = Display
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelScalarB = {
|
||||||
|
DataSource = Display
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelVector = {
|
||||||
|
DataSource = Display
|
||||||
|
Type = uint32
|
||||||
|
NumberOfDimensions = 1
|
||||||
|
NumberOfElements = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+IOGAM_Writer = {
|
||||||
|
Class = IOGAM
|
||||||
|
InputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
State1_Thread1_CycleTime = {
|
||||||
|
Alias = State1.Thread1_CycleTime
|
||||||
|
DataSource = Timings
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
SentinelScalarA = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelScalarB = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelVector = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfDimensions = 1
|
||||||
|
NumberOfElements = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
State1_Thread1_CycleTime = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
SentinelScalarA = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelScalarB = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelVector = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
NumberOfDimensions = 1
|
||||||
|
NumberOfElements = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+Data = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
DefaultDataSource = DDB1
|
||||||
|
+DDB1 = {
|
||||||
|
Class = GAMDataSource
|
||||||
|
}
|
||||||
|
+Display = {
|
||||||
|
Class = LoggerDataSource
|
||||||
|
}
|
||||||
|
+Timings = {
|
||||||
|
Class = TimingDataSource
|
||||||
|
}
|
||||||
|
+Timer = {
|
||||||
|
Class = LinuxTimer
|
||||||
|
SleepNature = "Default"
|
||||||
|
Signals = {
|
||||||
|
Counter = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+FileWriter = {
|
||||||
|
Class = FileDataSource::FileWriter
|
||||||
|
NumberOfBuffers = 100
|
||||||
|
CPUMask = 0x1
|
||||||
|
StackSize = 10000000
|
||||||
|
Filename = "__MARTE_RUN_DIR__/s03_output.bin"
|
||||||
|
Overwrite = "yes"
|
||||||
|
FileFormat = "binary"
|
||||||
|
StoreOnTrigger = 0
|
||||||
|
RefreshContent = 0
|
||||||
|
Signals = {
|
||||||
|
Counter = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
State1_Thread1_CycleTime = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
SentinelScalarA = {
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelScalarB = {
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelVector = {
|
||||||
|
Type = uint32
|
||||||
|
NumberOfDimensions = 1
|
||||||
|
NumberOfElements = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+States = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
+State1 = {
|
||||||
|
Class = RealTimeState
|
||||||
|
+Threads = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
+Thread1 = {
|
||||||
|
Class = RealTimeThread
|
||||||
|
CPUs = 0x1
|
||||||
|
Functions = {GAMTimer SentinelProducer GAMDisplay IOGAM_Writer}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+Scheduler = {
|
||||||
|
Class = GAMScheduler
|
||||||
|
TimingDataSource = Timings
|
||||||
|
}
|
||||||
|
}
|
||||||
+260
@@ -0,0 +1,260 @@
|
|||||||
|
$HelloWorldApp = {
|
||||||
|
Class = RealTimeApplication
|
||||||
|
+Functions = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
+GAMTimer = {
|
||||||
|
Class = IOGAM
|
||||||
|
InputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = Timer
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
Frequency = 10
|
||||||
|
DataSource = Timer
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+SentinelProducer = {
|
||||||
|
Class = ConstantGAM
|
||||||
|
OutputSignals = {
|
||||||
|
SentinelScalarA = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
Default = 324508639
|
||||||
|
}
|
||||||
|
SentinelScalarB = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
Default = 610839776
|
||||||
|
}
|
||||||
|
SentinelVector = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfDimensions = 1
|
||||||
|
NumberOfElements = 3
|
||||||
|
Default = {16909060 286397204 555885348}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+GAMDisplay = {
|
||||||
|
Class = IOGAM
|
||||||
|
InputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
State1_Thread1_CycleTime = {
|
||||||
|
Alias = State1.Thread1_CycleTime
|
||||||
|
DataSource = Timings
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
SentinelScalarA = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelScalarB = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelVector = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfDimensions = 1
|
||||||
|
NumberOfElements = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = Display
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
DataSource = Display
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
State1_Thread1_CycleTime = {
|
||||||
|
DataSource = Display
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
SentinelScalarA = {
|
||||||
|
DataSource = Display
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelScalarB = {
|
||||||
|
DataSource = Display
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelVector = {
|
||||||
|
DataSource = Display
|
||||||
|
Type = uint32
|
||||||
|
NumberOfDimensions = 1
|
||||||
|
NumberOfElements = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+IOGAM_Writer = {
|
||||||
|
Class = IOGAM
|
||||||
|
InputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
State1_Thread1_CycleTime = {
|
||||||
|
Alias = State1.Thread1_CycleTime
|
||||||
|
DataSource = Timings
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
SentinelScalarA = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelScalarB = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelVector = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfDimensions = 1
|
||||||
|
NumberOfElements = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
State1_Thread1_CycleTime = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
SentinelScalarA = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelScalarB = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelVector = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
NumberOfDimensions = 1
|
||||||
|
NumberOfElements = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+Data = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
DefaultDataSource = DDB1
|
||||||
|
+DDB1 = {
|
||||||
|
Class = GAMDataSource
|
||||||
|
}
|
||||||
|
+Display = {
|
||||||
|
Class = GAMDataSource
|
||||||
|
}
|
||||||
|
+Timings = {
|
||||||
|
Class = TimingDataSource
|
||||||
|
}
|
||||||
|
+Timer = {
|
||||||
|
Class = LinuxTimer
|
||||||
|
SleepNature = "Default"
|
||||||
|
Signals = {
|
||||||
|
Counter = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+FileWriter = {
|
||||||
|
Class = FileDataSource::FileWriter
|
||||||
|
NumberOfBuffers = 100
|
||||||
|
CPUMask = 0x1
|
||||||
|
StackSize = 10000000
|
||||||
|
Filename = "__MARTE_RUN_DIR__/s03_output.bin"
|
||||||
|
Overwrite = "yes"
|
||||||
|
FileFormat = "binary"
|
||||||
|
StoreOnTrigger = 0
|
||||||
|
RefreshContent = 0
|
||||||
|
Signals = {
|
||||||
|
Counter = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
State1_Thread1_CycleTime = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
SentinelScalarA = {
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelScalarB = {
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelVector = {
|
||||||
|
Type = uint32
|
||||||
|
NumberOfDimensions = 1
|
||||||
|
NumberOfElements = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+States = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
+State1 = {
|
||||||
|
Class = RealTimeState
|
||||||
|
+Threads = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
+Thread1 = {
|
||||||
|
Class = RealTimeThread
|
||||||
|
CPUs = 0x1
|
||||||
|
Functions = {GAMTimer SentinelProducer GAMDisplay IOGAM_Writer}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+Scheduler = {
|
||||||
|
Class = GAMScheduler
|
||||||
|
TimingDataSource = Timings
|
||||||
|
}
|
||||||
|
}
|
||||||
+193
@@ -0,0 +1,193 @@
|
|||||||
|
$HelloWorldApp = {
|
||||||
|
Class = RealTimeApplication
|
||||||
|
+Functions = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
+GAMTimer = {
|
||||||
|
Class = IOGAM
|
||||||
|
InputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = Timer
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
Frequency = 10
|
||||||
|
DataSource = Timer
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+SentinelProducer = {
|
||||||
|
Class = ConstantGAM
|
||||||
|
OutputSignals = {
|
||||||
|
SentinelScalarA = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
Default = 324508639
|
||||||
|
}
|
||||||
|
SentinelScalarB = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
Default = 610839776
|
||||||
|
}
|
||||||
|
SentinelVector = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfDimensions = 1
|
||||||
|
NumberOfElements = 3
|
||||||
|
Default = {16909060 286397204 555885348}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+IOGAM_Writer = {
|
||||||
|
Class = IOGAM
|
||||||
|
InputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
State1_Thread1_CycleTime = {
|
||||||
|
Alias = State1.Thread1_CycleTime
|
||||||
|
DataSource = Timings
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
SentinelScalarA = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelScalarB = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelVector = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfDimensions = 1
|
||||||
|
NumberOfElements = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
State1_Thread1_CycleTime = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
SentinelScalarA = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelScalarB = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelVector = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
NumberOfDimensions = 1
|
||||||
|
NumberOfElements = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+Data = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
DefaultDataSource = DDB1
|
||||||
|
+DDB1 = {
|
||||||
|
Class = GAMDataSource
|
||||||
|
}
|
||||||
|
+Timings = {
|
||||||
|
Class = TimingDataSource
|
||||||
|
}
|
||||||
|
+Timer = {
|
||||||
|
Class = LinuxTimer
|
||||||
|
SleepNature = "Default"
|
||||||
|
Signals = {
|
||||||
|
Counter = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+FileWriter = {
|
||||||
|
Class = FileDataSource::FileWriter
|
||||||
|
NumberOfBuffers = 100
|
||||||
|
CPUMask = 0x1
|
||||||
|
StackSize = 10000000
|
||||||
|
Filename = "__MARTE_RUN_DIR__/s03_output.bin"
|
||||||
|
Overwrite = "yes"
|
||||||
|
FileFormat = "binary"
|
||||||
|
StoreOnTrigger = 0
|
||||||
|
RefreshContent = 0
|
||||||
|
Signals = {
|
||||||
|
Counter = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
State1_Thread1_CycleTime = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
SentinelScalarA = {
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelScalarB = {
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelVector = {
|
||||||
|
Type = uint32
|
||||||
|
NumberOfDimensions = 1
|
||||||
|
NumberOfElements = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+States = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
+State1 = {
|
||||||
|
Class = RealTimeState
|
||||||
|
+Threads = {
|
||||||
|
Class = ReferenceContainer
|
||||||
|
+Thread1 = {
|
||||||
|
Class = RealTimeThread
|
||||||
|
CPUs = 0x1
|
||||||
|
Functions = {GAMTimer SentinelProducer IOGAM_Writer}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+Scheduler = {
|
||||||
|
Class = GAMScheduler
|
||||||
|
TimingDataSource = Timings
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+1246
File diff suppressed because it is too large
Load Diff
Executable
+572
@@ -0,0 +1,572 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -u
|
||||||
|
|
||||||
|
LAUNCHER_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
CANDIDATE_ROOT="$(cd "$LAUNCHER_DIR/.." && pwd)"
|
||||||
|
|
||||||
|
if [ -n "${MARTE_BENCHMARK_SUITE_ROOT:-}" ]; then
|
||||||
|
SUITE="$(cd "$MARTE_BENCHMARK_SUITE_ROOT" && pwd)"
|
||||||
|
else
|
||||||
|
SUITE="/home/dariodf/Scrivania/MARTE/marte-benchmark-suite"
|
||||||
|
fi
|
||||||
|
|
||||||
|
PATCHER="$CANDIDATE_ROOT/patchers/configuration/build_s03h1_from_s02.sh"
|
||||||
|
VALIDATOR="$CANDIDATE_ROOT/scenarios/S03H1_execution_profiles/validate.sh"
|
||||||
|
CONFIG_VERIFIER="$CANDIDATE_ROOT/scenarios/S03H1_execution_profiles/verify_s03h1_config.py"
|
||||||
|
CSV_EXPORTER="$CANDIDATE_ROOT/scenarios/S03H1_execution_profiles/export_s03_csv.py"
|
||||||
|
TEST_CONFIG="$CANDIDATE_ROOT/configurations/generated/S03H1/from_patcher/smoke_s03h1_execution_profiles_test_from_s02.marte"
|
||||||
|
DIAGNOSTIC_CONFIG="$CANDIDATE_ROOT/configurations/generated/S03H1/from_patcher/smoke_s03h1_execution_profiles_diagnostic_from_s02.marte"
|
||||||
|
|
||||||
|
RUNNER="$SUITE/common/marte_runner.sh"
|
||||||
|
LIVE_PATHS="$SUITE/common/paths.sh"
|
||||||
|
LIVE_ENVIRONMENT="$SUITE/common/environment.sh"
|
||||||
|
LIVE_OPERATIONAL_LAUNCHER="$SUITE/launcher/marte_benchmark_launcher.sh"
|
||||||
|
LIVE_PATCHER_S01="$SUITE/patchers/configuration/build_s01_from_s00.sh"
|
||||||
|
LIVE_PATCHER_S02="$SUITE/patchers/configuration/build_s02_from_s01.sh"
|
||||||
|
LIVE_PATCHER_S03="$SUITE/patchers/configuration/build_s03_from_s02.sh"
|
||||||
|
LIVE_VALIDATOR_S02="$SUITE/scenarios/S02_binary_recording/validate.sh"
|
||||||
|
LIVE_VALIDATOR_S03="$SUITE/scenarios/S03_semantic_sentinels/validate.sh"
|
||||||
|
LIVE_PARSER_S03="$SUITE/scenarios/S03_semantic_sentinels/parse_s03_binary.py"
|
||||||
|
LIVE_S00_CONFIG="$SUITE/configurations/generated/S00/smoke_s0_core.marte"
|
||||||
|
LIVE_S01_CONFIG="$SUITE/configurations/generated/S01/from_patcher/smoke_s1_timing_from_s00.marte"
|
||||||
|
LIVE_S02_CONFIG="$SUITE/configurations/generated/S02/from_patcher/smoke_s2_binary_recording_from_s01.marte"
|
||||||
|
LIVE_S03_CONFIG="$SUITE/configurations/generated/S03/from_patcher/smoke_s3_semantic_sentinels_from_s02.marte"
|
||||||
|
|
||||||
|
EXPECTED_TEST_CONFIG_SHA256="d037561b32760fbd0e2aec9f1eefc5efda27b1918eca4742c89092a8a2f7e92e"
|
||||||
|
EXPECTED_DIAGNOSTIC_CONFIG_SHA256="cd999ff249452298d650a22c8fe5b0b03bf48c0735f4630befdec8209cbb13a3"
|
||||||
|
EXPECTED_PATCHER_SHA256="5db5f71db4ab8f007b2e78230c2506bed4c62a8e502fb1c08ca04eb14b645b82"
|
||||||
|
EXPECTED_VALIDATOR_SHA256="748f403a045f9dbed64910de67e75ba5529c02ab5894417a866225518c10b5e5"
|
||||||
|
EXPECTED_CONFIG_VERIFIER_SHA256="2f1c41b186bd2e79a9fb51fab0461a7a0dce104bf0852c0ec1ade2c55a017443"
|
||||||
|
EXPECTED_CSV_EXPORTER_SHA256="b413ad113e188141891b61b930a607890b8468051e8a61cb0f0454c519a51fb7"
|
||||||
|
|
||||||
|
print_usage() {
|
||||||
|
printf "Uso:\n"
|
||||||
|
printf " %s S03H1 <durata-secondi> TEST\n" "$0"
|
||||||
|
printf " %s S03H1 <durata-secondi> DIAGNOSTIC\n" "$0"
|
||||||
|
printf "\n"
|
||||||
|
printf "La candidata non installa e non modifica la baseline S03 R3.\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
code="$1"
|
||||||
|
shift
|
||||||
|
printf "S03_H1_LAUNCHER_STATUS=FAIL\n" >&2
|
||||||
|
printf "S03_H1_LAUNCHER_ERROR=%s\n" "$*" >&2
|
||||||
|
exit "$code"
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_duration() {
|
||||||
|
candidate_duration="$1"
|
||||||
|
case "$candidate_duration" in
|
||||||
|
*[!0-9]*|"")
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
[ "$candidate_duration" -gt 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_hash() {
|
||||||
|
candidate_file="$1"
|
||||||
|
candidate_expected="$2"
|
||||||
|
candidate_label="$3"
|
||||||
|
if [ ! -f "$candidate_file" ]; then
|
||||||
|
printf "HASH_CHECK=%s STATUS=MISSING FILE=%s\n" \
|
||||||
|
"$candidate_label" "$candidate_file" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
candidate_actual="$(sha256sum -- "$candidate_file" | awk '{print $1}')"
|
||||||
|
printf "HASH_CHECK=%s EXPECTED=%s ACTUAL=%s FILE=%s\n" \
|
||||||
|
"$candidate_label" "$candidate_expected" "$candidate_actual" "$candidate_file"
|
||||||
|
[ "$candidate_actual" = "$candidate_expected" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_candidate_components() {
|
||||||
|
verify_hash "$PATCHER" "$EXPECTED_PATCHER_SHA256" "S03H1_PATCHER" || return 1
|
||||||
|
verify_hash "$VALIDATOR" "$EXPECTED_VALIDATOR_SHA256" "S03H1_VALIDATOR" || return 1
|
||||||
|
verify_hash "$CONFIG_VERIFIER" "$EXPECTED_CONFIG_VERIFIER_SHA256" "S03H1_CONFIG_VERIFIER" || return 1
|
||||||
|
verify_hash "$CSV_EXPORTER" "$EXPECTED_CSV_EXPORTER_SHA256" "S03H1_CSV_EXPORTER" || return 1
|
||||||
|
verify_hash "$CANDIDATE_CONFIG" "$EXPECTED_CANDIDATE_CONFIG_SHA256" "S03H1_${MODE}_CONFIG" || return 1
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PROTECTED_PATHS=(
|
||||||
|
"$LIVE_OPERATIONAL_LAUNCHER"
|
||||||
|
"$LIVE_S00_CONFIG"
|
||||||
|
"$LIVE_S01_CONFIG"
|
||||||
|
"$LIVE_S02_CONFIG"
|
||||||
|
"$LIVE_S03_CONFIG"
|
||||||
|
"$LIVE_PATCHER_S01"
|
||||||
|
"$LIVE_PATCHER_S02"
|
||||||
|
"$LIVE_PATCHER_S03"
|
||||||
|
"$LIVE_VALIDATOR_S02"
|
||||||
|
"$LIVE_VALIDATOR_S03"
|
||||||
|
"$LIVE_PARSER_S03"
|
||||||
|
"$RUNNER"
|
||||||
|
"$LIVE_PATHS"
|
||||||
|
"$LIVE_ENVIRONMENT"
|
||||||
|
)
|
||||||
|
PROTECTED_EXPECTED_HASHES=(
|
||||||
|
"7ef0419826c85c0364aad2403db4b8340cd815e9d9ce17edfbe5da8e6fbf2683"
|
||||||
|
"49a9b48595aab88cd8fd11d1e58ace4ab11d7d0a649e9b143bdc25c8866253d5"
|
||||||
|
"1513e1ca72eba56d53079ac7328908f12ddc72772456e2d75bcbacb6465d2427"
|
||||||
|
"8ecc8ba55e46e9f6fb8f304404d4070ff4c2ea5b9c783a69113bc08b457859d1"
|
||||||
|
"0f8916735ff67a9be2b167b52f147687fe131a063f410a81bfbf3bf9ff65f1e4"
|
||||||
|
"a8cced1ea1711806863606e27c3ba52a3e72794dbe8c36c253570709ce3f7ccb"
|
||||||
|
"8ac51d09f6f7984af3522e373bab59e2553775c418f69a53ccb93d8d1b893391"
|
||||||
|
"96c778ba6a15353fd969b19960706d7c0ca810c0c6fd61a14b5f88960e4e2b7a"
|
||||||
|
"7cd29b216b5edc3c72750a3326aebe5a9fdfb3b7522f1d7a6e8b0a1a97b3d60a"
|
||||||
|
"95caf207c4d29037c4973d756ff5a7004a3360aad9656d068948e222a4ba0c98"
|
||||||
|
"91c4d66770197e1986ed91eb6a4870e7da7df5a522ffdf4329b6d9250f238307"
|
||||||
|
"9e4f1a6b0dabc244fd0726fd18bf07e86b29a9fc6a76d54fcaf61c79f13c9633"
|
||||||
|
"468d92c3eb048b7137ea52a768f459d2d1f26f83f5a5c174d3333d032c9583c6"
|
||||||
|
"b1faa567e480c326c72107b886f387f108907900804621337524f1f856f056ac"
|
||||||
|
)
|
||||||
|
|
||||||
|
verify_protected_baseline() {
|
||||||
|
candidate_index=0
|
||||||
|
while [ "$candidate_index" -lt "${#PROTECTED_PATHS[@]}" ]; do
|
||||||
|
verify_hash \
|
||||||
|
"${PROTECTED_PATHS[$candidate_index]}" \
|
||||||
|
"${PROTECTED_EXPECTED_HASHES[$candidate_index]}" \
|
||||||
|
"PROTECTED_${candidate_index}" || return 1
|
||||||
|
candidate_index=$((candidate_index + 1))
|
||||||
|
done
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
write_protected_hashes() {
|
||||||
|
candidate_destination="$1"
|
||||||
|
sha256sum -- "${PROTECTED_PATHS[@]}" >"$candidate_destination"
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_contract_field() {
|
||||||
|
candidate_field="$1"
|
||||||
|
candidate_file="$2"
|
||||||
|
PARSED_FIELD_VALUE=""
|
||||||
|
PARSED_FIELD_ERROR=""
|
||||||
|
if [ ! -f "$candidate_file" ]; then
|
||||||
|
PARSED_FIELD_ERROR="NO_FILE"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
candidate_count="$(grep -Ec "^${candidate_field}=[A-Z][A-Z0-9_]*$" "$candidate_file" || true)"
|
||||||
|
candidate_any_count="$(grep -Ec "^${candidate_field}=" "$candidate_file" || true)"
|
||||||
|
if [ "$candidate_any_count" -eq 0 ]; then
|
||||||
|
PARSED_FIELD_ERROR="MISSING"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [ "$candidate_any_count" -ne 1 ]; then
|
||||||
|
PARSED_FIELD_ERROR="DUPLICATED"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [ "$candidate_count" -ne 1 ]; then
|
||||||
|
PARSED_FIELD_ERROR="MALFORMED"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
PARSED_FIELD_VALUE="$(sed -n "s/^${candidate_field}=//p" "$candidate_file")"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
classify_s03h1_run() {
|
||||||
|
classify_validator_rc="$1"
|
||||||
|
classify_tee_rc="$2"
|
||||||
|
classify_validation_file="$3"
|
||||||
|
classify_csv_rc="$4"
|
||||||
|
classify_invariance_status="$5"
|
||||||
|
|
||||||
|
FINAL_RC=20
|
||||||
|
FINAL_RESULT="INCONCLUSIVE"
|
||||||
|
BLOCK_REASON="NONE"
|
||||||
|
PARSED_MODE_STATUS="NOT_EVALUATED"
|
||||||
|
PARSED_PROFILE_CONFIG_STATUS="NOT_EVALUATED"
|
||||||
|
PARSED_OBSERVABILITY_STATUS="NOT_EVALUATED"
|
||||||
|
PARSED_FUNCTIONAL_STATUS="NOT_EVALUATED"
|
||||||
|
PARSED_SEMANTIC_STATUS="NOT_EVALUATED"
|
||||||
|
PARSED_TIMING_STATUS="NOT_EVALUATED"
|
||||||
|
PARSED_MEASUREMENT_ELIGIBILITY="NOT_EVALUATED"
|
||||||
|
|
||||||
|
if [ "$classify_tee_rc" -ne 0 ]; then
|
||||||
|
FINAL_RC=67
|
||||||
|
FINAL_RESULT="FAIL_VALIDATION_LOG"
|
||||||
|
BLOCK_REASON="VALIDATION_LOG_NOT_WRITTEN"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
CONTRACT_PARSE_ERROR="NONE"
|
||||||
|
for candidate_field in \
|
||||||
|
MODE_STATUS \
|
||||||
|
PROFILE_CONFIG_STATUS \
|
||||||
|
OBSERVABILITY_STATUS \
|
||||||
|
FUNCTIONAL_STATUS \
|
||||||
|
SEMANTIC_STATUS \
|
||||||
|
TIMING_STATUS \
|
||||||
|
MEASUREMENT_ELIGIBILITY
|
||||||
|
do
|
||||||
|
if parse_contract_field "$candidate_field" "$classify_validation_file"; then
|
||||||
|
case "$candidate_field" in
|
||||||
|
MODE_STATUS) PARSED_MODE_STATUS="$PARSED_FIELD_VALUE" ;;
|
||||||
|
PROFILE_CONFIG_STATUS) PARSED_PROFILE_CONFIG_STATUS="$PARSED_FIELD_VALUE" ;;
|
||||||
|
OBSERVABILITY_STATUS) PARSED_OBSERVABILITY_STATUS="$PARSED_FIELD_VALUE" ;;
|
||||||
|
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_MEASUREMENT_ELIGIBILITY="$PARSED_FIELD_VALUE" ;;
|
||||||
|
esac
|
||||||
|
elif [ "$CONTRACT_PARSE_ERROR" = "NONE" ]; then
|
||||||
|
CONTRACT_PARSE_ERROR="${candidate_field}_${PARSED_FIELD_ERROR}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$CONTRACT_PARSE_ERROR" != "NONE" ]; then
|
||||||
|
FINAL_RC=22
|
||||||
|
FINAL_RESULT="INCONCLUSIVE_S03H1_CONTRACT"
|
||||||
|
BLOCK_REASON="$CONTRACT_PARSE_ERROR"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [ "$PARSED_MEASUREMENT_ELIGIBILITY" != "NO" ]; then
|
||||||
|
FINAL_RC=22
|
||||||
|
FINAL_RESULT="INCONCLUSIVE_S03H1_CONTRACT"
|
||||||
|
BLOCK_REASON="ELIGIBILITY_CONTRACT_VIOLATION_${PARSED_MEASUREMENT_ELIGIBILITY}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [ "$classify_invariance_status" != "PASS" ]; then
|
||||||
|
FINAL_RC=71
|
||||||
|
FINAL_RESULT="FAIL_PROTECTED_BASELINE_CHANGED"
|
||||||
|
BLOCK_REASON="PROTECTED_BASELINE_INVARIANCE_${classify_invariance_status}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [ "$classify_csv_rc" -ne 0 ]; then
|
||||||
|
FINAL_RC=70
|
||||||
|
FINAL_RESULT="FAIL_DERIVED_CSV_EXPORT"
|
||||||
|
BLOCK_REASON="CSV_EXPORT_RC_${classify_csv_rc}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$classify_validator_rc" in
|
||||||
|
0|10|11)
|
||||||
|
;;
|
||||||
|
20|21)
|
||||||
|
FINAL_RC=20
|
||||||
|
FINAL_RESULT="S03H1_VALIDATION_INCONCLUSIVE"
|
||||||
|
BLOCK_REASON="VALIDATOR_RC_${classify_validator_rc}"
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
FINAL_RC=68
|
||||||
|
FINAL_RESULT="FAIL_VALIDATOR_EXIT"
|
||||||
|
BLOCK_REASON="UNRECOGNISED_VALIDATOR_RC_${classify_validator_rc}"
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
for candidate_status in \
|
||||||
|
"$PARSED_MODE_STATUS" \
|
||||||
|
"$PARSED_PROFILE_CONFIG_STATUS" \
|
||||||
|
"$PARSED_OBSERVABILITY_STATUS" \
|
||||||
|
"$PARSED_FUNCTIONAL_STATUS" \
|
||||||
|
"$PARSED_SEMANTIC_STATUS"
|
||||||
|
do
|
||||||
|
if [ "$candidate_status" != "PASS" ]; then
|
||||||
|
FINAL_RC=25
|
||||||
|
FINAL_RESULT="S03H1_CONTRACT_STATUS_NOT_PASS"
|
||||||
|
BLOCK_REASON="REQUIRED_STATUS_${candidate_status}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
case "$PARSED_TIMING_STATUS" in
|
||||||
|
NOT_VALID_*)
|
||||||
|
FINAL_RC=14
|
||||||
|
FINAL_RESULT="FUNCTIONAL_AND_SEMANTIC_PASS_TIMING_NOT_VALID"
|
||||||
|
BLOCK_REASON="$PARSED_TIMING_STATUS"
|
||||||
|
;;
|
||||||
|
UNASSESSED_*)
|
||||||
|
FINAL_RC=15
|
||||||
|
FINAL_RESULT="FUNCTIONAL_AND_SEMANTIC_PASS_TIMING_UNASSESSED"
|
||||||
|
BLOCK_REASON="$PARSED_TIMING_STATUS"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
FINAL_RC=22
|
||||||
|
FINAL_RESULT="INCONCLUSIVE_TIMING_CONTRACT"
|
||||||
|
BLOCK_REASON="TIMING_STATUS_${PARSED_TIMING_STATUS}"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
run_s03h1() {
|
||||||
|
duration="$1"
|
||||||
|
MODE="$2"
|
||||||
|
|
||||||
|
case "$MODE" in
|
||||||
|
TEST)
|
||||||
|
CANDIDATE_CONFIG="$TEST_CONFIG"
|
||||||
|
EXPECTED_CANDIDATE_CONFIG_SHA256="$EXPECTED_TEST_CONFIG_SHA256"
|
||||||
|
;;
|
||||||
|
DIAGNOSTIC)
|
||||||
|
CANDIDATE_CONFIG="$DIAGNOSTIC_CONFIG"
|
||||||
|
EXPECTED_CANDIDATE_CONFIG_SHA256="$EXPECTED_DIAGNOSTIC_CONFIG_SHA256"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf "ERRORE: MODE non riconosciuto: %s\n" "$MODE" >&2
|
||||||
|
return 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ ! -d "$SUITE" ]; then
|
||||||
|
printf "ERRORE: suite operativa assente: %s\n" "$SUITE" >&2
|
||||||
|
return 50
|
||||||
|
fi
|
||||||
|
if ! verify_candidate_components; then
|
||||||
|
printf "ERRORE: integrita' candidata non dimostrata.\n" >&2
|
||||||
|
return 51
|
||||||
|
fi
|
||||||
|
if ! verify_protected_baseline; then
|
||||||
|
printf "ERRORE: baseline protetta assente o con hash inatteso.\n" >&2
|
||||||
|
return 52
|
||||||
|
fi
|
||||||
|
|
||||||
|
WORK_ROOT="$(mktemp -d "${TMPDIR:-/tmp}/s03h1_launcher.XXXXXX")" || return 53
|
||||||
|
trap 'rm -rf -- "$WORK_ROOT"' EXIT HUP INT TERM
|
||||||
|
GENERATED_CONFIG="$WORK_ROOT/generated_${MODE}.marte"
|
||||||
|
PATCHER_LOG="$WORK_ROOT/patcher.log"
|
||||||
|
PROTECTED_BEFORE="$WORK_ROOT/protected_baseline_before.sha256"
|
||||||
|
CAPTURE="$WORK_ROOT/runner_capture.log"
|
||||||
|
|
||||||
|
"$PATCHER" "$LIVE_S02_CONFIG" "$GENERATED_CONFIG" "$MODE" >"$PATCHER_LOG" 2>&1
|
||||||
|
PATCHER_RC=$?
|
||||||
|
if [ "$PATCHER_RC" -ne 0 ]; then
|
||||||
|
printf "ERRORE: patcher candidato fallito rc=%s\n" "$PATCHER_RC" >&2
|
||||||
|
cat -- "$PATCHER_LOG" >&2
|
||||||
|
return 54
|
||||||
|
fi
|
||||||
|
if ! cmp -s -- "$GENERATED_CONFIG" "$CANDIDATE_CONFIG"; then
|
||||||
|
printf "ERRORE: build candidato non coincide con config confezionata.\n" >&2
|
||||||
|
return 55
|
||||||
|
fi
|
||||||
|
|
||||||
|
write_protected_hashes "$PROTECTED_BEFORE" || return 56
|
||||||
|
|
||||||
|
if [ ! -f "$LIVE_PATHS" ]; then
|
||||||
|
printf "ERRORE: paths.sh assente: %s\n" "$LIVE_PATHS" >&2
|
||||||
|
return 57
|
||||||
|
fi
|
||||||
|
# shellcheck source=/dev/null
|
||||||
|
source "$LIVE_PATHS"
|
||||||
|
CONSTANT_GAM_LIB_DIR="$MARTE2_COMPONENTS_ROOT/Build/$MARTE_TARGET/Components/GAMs/ConstantGAM"
|
||||||
|
CONSTANT_GAM_LIB="$CONSTANT_GAM_LIB_DIR/ConstantGAM.so"
|
||||||
|
if [ ! -f "$CONSTANT_GAM_LIB" ]; then
|
||||||
|
printf "ERRORE: ConstantGAM assente: %s\n" "$CONSTANT_GAM_LIB" >&2
|
||||||
|
return 58
|
||||||
|
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
|
||||||
|
|
||||||
|
printf "============================================================\n"
|
||||||
|
printf "S03-H1 EXECUTION PROFILES - RUN CANDIDATA\n"
|
||||||
|
printf "============================================================\n"
|
||||||
|
printf "MODE=%s\n" "$MODE"
|
||||||
|
printf "DURATION=%s\n" "$duration"
|
||||||
|
printf "CURRENT_OPERATIONAL_BASELINE=S03_R3_INSTALLED\n"
|
||||||
|
printf "S03_H1_INSTALLATION_AUTHORIZED=NO\n"
|
||||||
|
|
||||||
|
"$RUNNER" \
|
||||||
|
"S03H1_${MODE}_launcher" \
|
||||||
|
"$CANDIDATE_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 "ERRORE: common runner fallito rc=%s\n" "$RUNNER_RC" >&2
|
||||||
|
return 60
|
||||||
|
fi
|
||||||
|
if [ "$CAPTURE_TEE_RC" -ne 0 ]; then
|
||||||
|
printf "ERRORE: capture common runner fallita.\n" >&2
|
||||||
|
return 61
|
||||||
|
fi
|
||||||
|
|
||||||
|
RUN_DIR="$(sed -n 's/^RUN_DIR=//p' "$CAPTURE" | tail -n 1)"
|
||||||
|
if [ -z "$RUN_DIR" ] || [ ! -d "$RUN_DIR" ]; then
|
||||||
|
printf "ERRORE: RUN_DIR non individuata o assente: %s\n" "$RUN_DIR" >&2
|
||||||
|
return 62
|
||||||
|
fi
|
||||||
|
|
||||||
|
RUN_LOG="$RUN_DIR/run.log"
|
||||||
|
RUNNER_SUMMARY="$RUN_DIR/runner_summary.txt"
|
||||||
|
RUN_HASHES="$RUN_DIR/hashes.sha256"
|
||||||
|
OUTPUT_FILE="$RUN_DIR/s03_output.bin"
|
||||||
|
CSV_FILE="$RUN_DIR/s03_output.csv"
|
||||||
|
MODE_FILE="$RUN_DIR/s03h1_mode.txt"
|
||||||
|
VALIDATION_LOG="$RUN_DIR/validation.txt"
|
||||||
|
CSV_REPORT="$RUN_DIR/csv_export.txt"
|
||||||
|
LAUNCHER_SUMMARY="$RUN_DIR/launcher_summary.txt"
|
||||||
|
PROTECTED_BEFORE_RUN="$RUN_DIR/protected_baseline_before.sha256"
|
||||||
|
PROTECTED_AFTER_RUN="$RUN_DIR/protected_baseline_after.sha256"
|
||||||
|
INVARIANCE_REPORT="$RUN_DIR/protected_baseline_invariance.txt"
|
||||||
|
|
||||||
|
cp -- "$PROTECTED_BEFORE" "$PROTECTED_BEFORE_RUN"
|
||||||
|
{
|
||||||
|
printf "SCENARIO=S03H1\n"
|
||||||
|
printf "MODE=%s\n" "$MODE"
|
||||||
|
printf "CANDIDATE_CONFIG_SHA256=%s\n" "$EXPECTED_CANDIDATE_CONFIG_SHA256"
|
||||||
|
printf "S03_H1_INSTALLATION_AUTHORIZED=NO\n"
|
||||||
|
} >"$MODE_FILE"
|
||||||
|
|
||||||
|
sha256sum -- \
|
||||||
|
"$MODE_FILE" \
|
||||||
|
"${BASH_SOURCE[0]}" \
|
||||||
|
"$PATCHER" \
|
||||||
|
"$VALIDATOR" \
|
||||||
|
"$CONFIG_VERIFIER" \
|
||||||
|
"$CSV_EXPORTER" \
|
||||||
|
"$LIVE_PARSER_S03" \
|
||||||
|
"$RUN_LOG" \
|
||||||
|
"$RUNNER_SUMMARY" \
|
||||||
|
"$OUTPUT_FILE" \
|
||||||
|
"$PROTECTED_BEFORE_RUN" \
|
||||||
|
"${PROTECTED_PATHS[@]}" \
|
||||||
|
>>"$RUN_HASHES"
|
||||||
|
|
||||||
|
S03_BASELINE_PARSER="$LIVE_PARSER_S03" \
|
||||||
|
timeout 30s "$VALIDATOR" "$MODE" "$RUN_DIR" 2>&1 | tee "$VALIDATION_LOG"
|
||||||
|
VALIDATION_CODES=("${PIPESTATUS[@]}")
|
||||||
|
VALIDATOR_RC="${VALIDATION_CODES[0]}"
|
||||||
|
VALIDATION_TEE_RC="${VALIDATION_CODES[1]}"
|
||||||
|
|
||||||
|
"$CSV_EXPORTER" "$OUTPUT_FILE" "$CSV_FILE" >"$CSV_REPORT" 2>&1
|
||||||
|
CSV_RC=$?
|
||||||
|
|
||||||
|
write_protected_hashes "$PROTECTED_AFTER_RUN"
|
||||||
|
if cmp -s -- "$PROTECTED_BEFORE_RUN" "$PROTECTED_AFTER_RUN"; then
|
||||||
|
PROTECTED_BASELINE_INVARIANCE="PASS"
|
||||||
|
else
|
||||||
|
PROTECTED_BASELINE_INVARIANCE="FAIL"
|
||||||
|
fi
|
||||||
|
{
|
||||||
|
printf "PROTECTED_BASELINE_INVARIANCE=%s\n" "$PROTECTED_BASELINE_INVARIANCE"
|
||||||
|
printf "CURRENT_OPERATIONAL_BASELINE=S03_R3_INSTALLED\n"
|
||||||
|
printf "S03_H1_INSTALLATION_AUTHORIZED=NO\n"
|
||||||
|
} >"$INVARIANCE_REPORT"
|
||||||
|
|
||||||
|
for evidence_file in \
|
||||||
|
"$VALIDATION_LOG" \
|
||||||
|
"$CSV_REPORT" \
|
||||||
|
"$PROTECTED_AFTER_RUN" \
|
||||||
|
"$INVARIANCE_REPORT"
|
||||||
|
do
|
||||||
|
if [ -f "$evidence_file" ]; then
|
||||||
|
sha256sum -- "$evidence_file" >>"$RUN_HASHES"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ -f "$CSV_FILE" ]; then
|
||||||
|
sha256sum -- "$CSV_FILE" >>"$RUN_HASHES"
|
||||||
|
fi
|
||||||
|
|
||||||
|
classify_s03h1_run \
|
||||||
|
"$VALIDATOR_RC" \
|
||||||
|
"$VALIDATION_TEE_RC" \
|
||||||
|
"$VALIDATION_LOG" \
|
||||||
|
"$CSV_RC" \
|
||||||
|
"$PROTECTED_BASELINE_INVARIANCE"
|
||||||
|
|
||||||
|
{
|
||||||
|
printf "============================================================\n"
|
||||||
|
printf "RIEPILOGO LAUNCHER S03-H1 CANDIDATO\n"
|
||||||
|
printf "============================================================\n"
|
||||||
|
printf "SCENARIO=S03H1\n"
|
||||||
|
printf "MODE=%s\n" "$MODE"
|
||||||
|
printf "DURATION=%s\n" "$duration"
|
||||||
|
printf "RUN_DIR=%s\n" "$RUN_DIR"
|
||||||
|
printf "RUNNER_RC=%s\n" "$RUNNER_RC"
|
||||||
|
printf "VALIDATOR_RC=%s\n" "$VALIDATOR_RC"
|
||||||
|
printf "CSV_EXPORT_RC=%s\n" "$CSV_RC"
|
||||||
|
printf "CSV_STATUS=%s\n" "$( [ "$CSV_RC" -eq 0 ] && printf PASS || printf FAIL )"
|
||||||
|
printf "MODE_STATUS=%s\n" "$PARSED_MODE_STATUS"
|
||||||
|
printf "PROFILE_CONFIG_STATUS=%s\n" "$PARSED_PROFILE_CONFIG_STATUS"
|
||||||
|
printf "OBSERVABILITY_STATUS=%s\n" "$PARSED_OBSERVABILITY_STATUS"
|
||||||
|
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=NO\n"
|
||||||
|
printf "PROTECTED_BASELINE_INVARIANCE=%s\n" "$PROTECTED_BASELINE_INVARIANCE"
|
||||||
|
printf "BLOCK_REASON=%s\n" "$BLOCK_REASON"
|
||||||
|
printf "FINAL_RESULT=%s\n" "$FINAL_RESULT"
|
||||||
|
printf "FINAL_RC=%s\n" "$FINAL_RC"
|
||||||
|
printf "S03_H1_INSTALLATION_AUTHORIZED=NO\n"
|
||||||
|
printf "CURRENT_OPERATIONAL_BASELINE=S03_R3_INSTALLED\n"
|
||||||
|
printf "PERFORMANCE_MEASUREMENT_AUTHORIZED=NO\n"
|
||||||
|
printf "S04_AUTHORIZED=NO\n"
|
||||||
|
printf "MD00_AUTHORIZED=NO\n"
|
||||||
|
} | tee "$LAUNCHER_SUMMARY"
|
||||||
|
SUMMARY_CODES=("${PIPESTATUS[@]}")
|
||||||
|
if [ "${SUMMARY_CODES[1]}" -ne 0 ]; then
|
||||||
|
FINAL_RC=69
|
||||||
|
else
|
||||||
|
sha256sum -- "$LAUNCHER_SUMMARY" >>"$RUN_HASHES"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "RUN_DIR=%s\n" "$RUN_DIR"
|
||||||
|
printf "RISULTATO_FINALE=%s\n" "$FINAL_RESULT"
|
||||||
|
printf "FINAL_RC=%s\n" "$FINAL_RC"
|
||||||
|
|
||||||
|
rm -rf -- "$WORK_ROOT"
|
||||||
|
trap - EXIT HUP INT TERM
|
||||||
|
return "$FINAL_RC"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "${S03H1_LAUNCHER_LIB_ONLY:-0}" = "1" ]; then
|
||||||
|
if [ "${BASH_SOURCE[0]}" != "$0" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
printf "ERRORE: S03H1_LAUNCHER_LIB_ONLY=1 e' ammesso solo con source.\n" >&2
|
||||||
|
exit 3
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$#" in
|
||||||
|
1)
|
||||||
|
case "$1" in
|
||||||
|
-h|--help)
|
||||||
|
print_usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
print_usage >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
3)
|
||||||
|
if [ "$1" != "S03H1" ] && [ "$1" != "s03h1" ]; then
|
||||||
|
print_usage >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
if ! validate_duration "$2"; then
|
||||||
|
printf "ERRORE: durata non valida: %s\n" "$2" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
case "$3" in
|
||||||
|
TEST|DIAGNOSTIC) ;;
|
||||||
|
*)
|
||||||
|
printf "ERRORE: MODE non riconosciuto: %s\n" "$3" >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
run_s03h1 "$2" "$3"
|
||||||
|
exit $?
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
print_usage >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
Executable
+669
@@ -0,0 +1,669 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -u
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
LAUNCHER_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
|
||||||
|
INSTALLED_SUITE="$(cd -- "$LAUNCHER_DIR/.." && pwd -P)"
|
||||||
|
WORK_ROOT=""
|
||||||
|
|
||||||
|
print_usage() {
|
||||||
|
printf 'Uso:\n'
|
||||||
|
printf ' %s S03H3 <durata-secondi> MINIMAL\n' "$0"
|
||||||
|
printf ' %s S03H3 <durata-secondi> TEST\n' "$0"
|
||||||
|
printf ' %s S03H3 <durata-secondi> DIAGNOSTIC\n' "$0"
|
||||||
|
}
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
local code="$1"
|
||||||
|
local reason="$2"
|
||||||
|
printf 'S03_H3_LAUNCHER_STATUS=FAIL\n' >&2
|
||||||
|
printf 'BLOCK_REASON=%s\n' "$reason" >&2
|
||||||
|
exit "$code"
|
||||||
|
}
|
||||||
|
|
||||||
|
is_positive_decimal() {
|
||||||
|
local value="$1"
|
||||||
|
[[ "$value" =~ ^[0-9]+$ ]] && [[ "$value" =~ [1-9] ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_hash() {
|
||||||
|
local file="$1"
|
||||||
|
local expected="$2"
|
||||||
|
local label="$3"
|
||||||
|
local actual
|
||||||
|
if [ ! -f "$file" ]; then
|
||||||
|
printf 'HASH_CHECK=%s STATUS=MISSING FILE=%s\n' "$label" "$file" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
actual="$(sha256sum -- "$file" | awk '{print $1}')" || return 1
|
||||||
|
printf 'HASH_CHECK=%s EXPECTED=%s ACTUAL=%s FILE=%s\n' \
|
||||||
|
"$label" "$expected" "$actual" "$file"
|
||||||
|
[ "$actual" = "$expected" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly -a HISTORICAL_RELATIVE_PATHS=(
|
||||||
|
"launcher/marte_benchmark_launcher.sh"
|
||||||
|
"configurations/generated/S00/smoke_s0_core.marte"
|
||||||
|
"configurations/generated/S01/from_patcher/smoke_s1_timing_from_s00.marte"
|
||||||
|
"configurations/generated/S02/from_patcher/smoke_s2_binary_recording_from_s01.marte"
|
||||||
|
"configurations/generated/S03/from_patcher/smoke_s3_semantic_sentinels_from_s02.marte"
|
||||||
|
"patchers/configuration/build_s01_from_s00.sh"
|
||||||
|
"patchers/configuration/build_s02_from_s01.sh"
|
||||||
|
"patchers/configuration/build_s03_from_s02.sh"
|
||||||
|
"scenarios/S02_binary_recording/validate.sh"
|
||||||
|
"scenarios/S03_semantic_sentinels/validate.sh"
|
||||||
|
"scenarios/S03_semantic_sentinels/parse_s03_binary.py"
|
||||||
|
"common/marte_runner.sh"
|
||||||
|
"common/paths.sh"
|
||||||
|
"common/environment.sh"
|
||||||
|
"launcher/marte_benchmark_launcher_s03h1.sh"
|
||||||
|
"patchers/configuration/build_s03h1_from_s02.sh"
|
||||||
|
"scenarios/S03H1_execution_profiles/validate.sh"
|
||||||
|
"scenarios/S03H1_execution_profiles/verify_s03h1_config.py"
|
||||||
|
"scenarios/S03H1_execution_profiles/export_s03_csv.py"
|
||||||
|
"configurations/generated/S03H1/from_patcher/smoke_s03h1_execution_profiles_test_from_s02.marte"
|
||||||
|
"configurations/generated/S03H1/from_patcher/smoke_s03h1_execution_profiles_diagnostic_from_s02.marte"
|
||||||
|
)
|
||||||
|
|
||||||
|
readonly -a HISTORICAL_EXPECTED_HASHES=(
|
||||||
|
"7ef0419826c85c0364aad2403db4b8340cd815e9d9ce17edfbe5da8e6fbf2683"
|
||||||
|
"49a9b48595aab88cd8fd11d1e58ace4ab11d7d0a649e9b143bdc25c8866253d5"
|
||||||
|
"1513e1ca72eba56d53079ac7328908f12ddc72772456e2d75bcbacb6465d2427"
|
||||||
|
"8ecc8ba55e46e9f6fb8f304404d4070ff4c2ea5b9c783a69113bc08b457859d1"
|
||||||
|
"0f8916735ff67a9be2b167b52f147687fe131a063f410a81bfbf3bf9ff65f1e4"
|
||||||
|
"a8cced1ea1711806863606e27c3ba52a3e72794dbe8c36c253570709ce3f7ccb"
|
||||||
|
"8ac51d09f6f7984af3522e373bab59e2553775c418f69a53ccb93d8d1b893391"
|
||||||
|
"96c778ba6a15353fd969b19960706d7c0ca810c0c6fd61a14b5f88960e4e2b7a"
|
||||||
|
"7cd29b216b5edc3c72750a3326aebe5a9fdfb3b7522f1d7a6e8b0a1a97b3d60a"
|
||||||
|
"95caf207c4d29037c4973d756ff5a7004a3360aad9656d068948e222a4ba0c98"
|
||||||
|
"91c4d66770197e1986ed91eb6a4870e7da7df5a522ffdf4329b6d9250f238307"
|
||||||
|
"9e4f1a6b0dabc244fd0726fd18bf07e86b29a9fc6a76d54fcaf61c79f13c9633"
|
||||||
|
"468d92c3eb048b7137ea52a768f459d2d1f26f83f5a5c174d3333d032c9583c6"
|
||||||
|
"b1faa567e480c326c72107b886f387f108907900804621337524f1f856f056ac"
|
||||||
|
"f420afdff1f0a96026d14820662a4257c0da4924a491fe00182f838414e06152"
|
||||||
|
"5db5f71db4ab8f007b2e78230c2506bed4c62a8e502fb1c08ca04eb14b645b82"
|
||||||
|
"748f403a045f9dbed64910de67e75ba5529c02ab5894417a866225518c10b5e5"
|
||||||
|
"2f1c41b186bd2e79a9fb51fab0461a7a0dce104bf0852c0ec1ade2c55a017443"
|
||||||
|
"b413ad113e188141891b61b930a607890b8468051e8a61cb0f0454c519a51fb7"
|
||||||
|
"d037561b32760fbd0e2aec9f1eefc5efda27b1918eca4742c89092a8a2f7e92e"
|
||||||
|
"cd999ff249452298d650a22c8fe5b0b03bf48c0735f4630befdec8209cbb13a3"
|
||||||
|
)
|
||||||
|
|
||||||
|
readonly -a S03H3_ADD_RELATIVE_PATHS=(
|
||||||
|
"launcher/marte_benchmark_launcher_s03h3.sh"
|
||||||
|
"patchers/configuration/build_s03h3_minimal_from_s03h1_test.sh"
|
||||||
|
"scenarios/S03H3_execution_profiles/validate.sh"
|
||||||
|
"scenarios/S03H3_execution_profiles/verify_s03h3_minimal_structure.py"
|
||||||
|
"configurations/generated/S03H3/from_patcher/smoke_s03h3_execution_profiles_minimal_from_s03h1_test.marte"
|
||||||
|
)
|
||||||
|
|
||||||
|
readonly EXPECTED_PATCHER_SHA256="b3ba3c195b33a028e7ae21ba92b90a070a5e3526b455f9e3dbcebe023af05e2e"
|
||||||
|
readonly EXPECTED_VALIDATOR_SHA256="8574636315340c785f41dca37eaac097cd3b59958e7fd1160444b9c21768f2d5"
|
||||||
|
readonly EXPECTED_MINIMAL_VERIFIER_SHA256="c8d2d4880ed9cb0e8f23427617e989f5f70e82a990a49489f2863a7b3fc2cb95"
|
||||||
|
readonly EXPECTED_MINIMAL_CONFIG_SHA256="2ee67c48d748e79ec7fdbc748bc4371eb02590d7522b41990d5cb2a3649796ec"
|
||||||
|
readonly EXPECTED_TEST_CONFIG_SHA256="d037561b32760fbd0e2aec9f1eefc5efda27b1918eca4742c89092a8a2f7e92e"
|
||||||
|
readonly EXPECTED_DIAGNOSTIC_CONFIG_SHA256="cd999ff249452298d650a22c8fe5b0b03bf48c0735f4630befdec8209cbb13a3"
|
||||||
|
|
||||||
|
resolve_suite() {
|
||||||
|
if [ -n "${MARTE_BENCHMARK_SUITE_ROOT:-}" ]; then
|
||||||
|
[[ "$MARTE_BENCHMARK_SUITE_ROOT" = /* ]] || \
|
||||||
|
fail 50 "TEST_OVERRIDE_NOT_ABSOLUTE"
|
||||||
|
[ -d "$MARTE_BENCHMARK_SUITE_ROOT" ] || \
|
||||||
|
fail 50 "TEST_OVERRIDE_ROOT_MISSING"
|
||||||
|
SUITE="$(cd -- "$MARTE_BENCHMARK_SUITE_ROOT" && pwd -P)"
|
||||||
|
[ -n "$SUITE" ] && [ "$SUITE" != "/" ] || \
|
||||||
|
fail 50 "TEST_OVERRIDE_ROOT_UNSAFE"
|
||||||
|
if [ "$SUITE" != "$INSTALLED_SUITE" ]; then
|
||||||
|
[ "${S03H3_TEST_ONLY_OVERRIDE:-NO}" = "YES" ] || \
|
||||||
|
fail 50 "TEST_OVERRIDE_NOT_ACKNOWLEDGED"
|
||||||
|
fi
|
||||||
|
elif [ "${S03H3_TEST_ONLY_OVERRIDE:-NO}" = "YES" ]; then
|
||||||
|
fail 50 "TEST_OVERRIDE_ROOT_NOT_PROVIDED"
|
||||||
|
else
|
||||||
|
SUITE="$INSTALLED_SUITE"
|
||||||
|
fi
|
||||||
|
readonly SUITE
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_historical_baseline() {
|
||||||
|
local index=0
|
||||||
|
while [ "$index" -lt "${#HISTORICAL_RELATIVE_PATHS[@]}" ]; do
|
||||||
|
verify_hash \
|
||||||
|
"$SUITE/${HISTORICAL_RELATIVE_PATHS[$index]}" \
|
||||||
|
"${HISTORICAL_EXPECTED_HASHES[$index]}" \
|
||||||
|
"HISTORICAL_${index}" || return 1
|
||||||
|
index=$((index + 1))
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_candidate_components() {
|
||||||
|
verify_hash "$PATCHER" "$EXPECTED_PATCHER_SHA256" "S03H3_PATCHER" || return 1
|
||||||
|
verify_hash "$VALIDATOR" "$EXPECTED_VALIDATOR_SHA256" "S03H3_VALIDATOR" || return 1
|
||||||
|
verify_hash "$MINIMAL_VERIFIER" "$EXPECTED_MINIMAL_VERIFIER_SHA256" "S03H3_MINIMAL_VERIFIER" || return 1
|
||||||
|
verify_hash "$MINIMAL_CONFIG" "$EXPECTED_MINIMAL_CONFIG_SHA256" "S03H3_MINIMAL_CONFIG" || return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
build_protected_paths() {
|
||||||
|
PROTECTED_PATHS=()
|
||||||
|
local relative
|
||||||
|
for relative in "${HISTORICAL_RELATIVE_PATHS[@]}"; do
|
||||||
|
PROTECTED_PATHS+=("$SUITE/$relative")
|
||||||
|
done
|
||||||
|
for relative in "${S03H3_ADD_RELATIVE_PATHS[@]}"; do
|
||||||
|
PROTECTED_PATHS+=("$SUITE/$relative")
|
||||||
|
done
|
||||||
|
PROTECTED_PATHS+=("$SUITE/launcher/marte_benchmark_menu.sh")
|
||||||
|
}
|
||||||
|
|
||||||
|
write_protected_snapshot() {
|
||||||
|
local destination="$1"
|
||||||
|
[ "${#PROTECTED_PATHS[@]}" -eq 27 ] || return 1
|
||||||
|
sha256sum -- "${PROTECTED_PATHS[@]}" >"$destination"
|
||||||
|
}
|
||||||
|
|
||||||
|
write_protected_path_list() {
|
||||||
|
local destination="$1"
|
||||||
|
printf '%s\n' "${PROTECTED_PATHS[@]}" >"$destination"
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_contract_field() {
|
||||||
|
local field="$1"
|
||||||
|
local file="$2"
|
||||||
|
local count
|
||||||
|
PARSED_FIELD_VALUE=""
|
||||||
|
PARSED_FIELD_ERROR=""
|
||||||
|
count="$(grep -Ec "^${field}=" "$file" || true)"
|
||||||
|
if [ "$count" -eq 0 ]; then
|
||||||
|
PARSED_FIELD_ERROR="MISSING"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [ "$count" -ne 1 ]; then
|
||||||
|
PARSED_FIELD_ERROR="DUPLICATED"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
PARSED_FIELD_VALUE="$(sed -n "s/^${field}=//p" "$file")"
|
||||||
|
[ -n "$PARSED_FIELD_VALUE" ] || {
|
||||||
|
PARSED_FIELD_ERROR="MALFORMED"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
classify_s03h3_run() {
|
||||||
|
local validator_rc="$1"
|
||||||
|
local validation_tee_rc="$2"
|
||||||
|
local validation_file="$3"
|
||||||
|
local csv_rc="$4"
|
||||||
|
local invariance_status="$5"
|
||||||
|
local dependency_status="$6"
|
||||||
|
local requested_mode="$7"
|
||||||
|
local field
|
||||||
|
|
||||||
|
FINAL_RC=22
|
||||||
|
FINAL_RESULT="INCONCLUSIVE_S03H3_CONTRACT"
|
||||||
|
BLOCK_REASON="NOT_EVALUATED"
|
||||||
|
PARSED_MODE_STATUS="NOT_EVALUATED"
|
||||||
|
PARSED_PROFILE_CONFIG_STATUS="NOT_EVALUATED"
|
||||||
|
PARSED_PROFILE_RUNTIME_STATUS="NOT_EVALUATED"
|
||||||
|
PARSED_OBSERVABILITY_STATUS="NOT_EVALUATED"
|
||||||
|
PARSED_FUNCTIONAL_STATUS="NOT_EVALUATED"
|
||||||
|
PARSED_SEMANTIC_STATUS="NOT_EVALUATED"
|
||||||
|
PARSED_TIMING_STATUS="NOT_EVALUATED"
|
||||||
|
PARSED_MEASUREMENT_ELIGIBILITY="NOT_EVALUATED"
|
||||||
|
PARSED_COMPLETE_SAMPLE_COUNT="NOT_EVALUATED"
|
||||||
|
|
||||||
|
if [ "$dependency_status" != "PASS" ]; then
|
||||||
|
FINAL_RC=51
|
||||||
|
FINAL_RESULT="FAIL_DEPENDENCY_INTEGRITY"
|
||||||
|
BLOCK_REASON="DEPENDENCY_INTEGRITY_NOT_PASS"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [ "$validation_tee_rc" -ne 0 ]; then
|
||||||
|
FINAL_RC=67
|
||||||
|
FINAL_RESULT="FAIL_VALIDATION_LOG"
|
||||||
|
BLOCK_REASON="VALIDATION_LOG_NOT_WRITTEN"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
case "$validator_rc" in
|
||||||
|
0|10|11|20|21) ;;
|
||||||
|
*)
|
||||||
|
FINAL_RC=68
|
||||||
|
FINAL_RESULT="FAIL_VALIDATOR_EXIT"
|
||||||
|
BLOCK_REASON="UNRECOGNIZED_VALIDATOR_RC_${validator_rc}"
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
if [ "$csv_rc" -ne 0 ]; then
|
||||||
|
FINAL_RC=70
|
||||||
|
FINAL_RESULT="FAIL_DERIVED_CSV_EXPORT"
|
||||||
|
BLOCK_REASON="CSV_EXPORT_RC_${csv_rc}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [ "$invariance_status" != "PASS" ]; then
|
||||||
|
FINAL_RC=71
|
||||||
|
FINAL_RESULT="FAIL_PROTECTED_BASELINE_CHANGED"
|
||||||
|
BLOCK_REASON="PROTECTED_BASELINE_INVARIANCE_${invariance_status}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
CONTRACT_PARSE_ERROR="NONE"
|
||||||
|
for field in \
|
||||||
|
MODE \
|
||||||
|
MODE_STATUS \
|
||||||
|
PROFILE_CONFIG_STATUS \
|
||||||
|
PROFILE_RUNTIME_STATUS \
|
||||||
|
OBSERVABILITY_STATUS \
|
||||||
|
OBSERVABILITY_REASON \
|
||||||
|
FUNCTIONAL_STATUS \
|
||||||
|
SEMANTIC_STATUS \
|
||||||
|
TIMING_STATUS \
|
||||||
|
MEASUREMENT_ELIGIBILITY \
|
||||||
|
COMPLETE_SAMPLE_COUNT \
|
||||||
|
VALIDATION_RESULT
|
||||||
|
do
|
||||||
|
if parse_contract_field "$field" "$validation_file"; then
|
||||||
|
case "$field" in
|
||||||
|
MODE) PARSED_MODE="$PARSED_FIELD_VALUE" ;;
|
||||||
|
MODE_STATUS) PARSED_MODE_STATUS="$PARSED_FIELD_VALUE" ;;
|
||||||
|
PROFILE_CONFIG_STATUS) PARSED_PROFILE_CONFIG_STATUS="$PARSED_FIELD_VALUE" ;;
|
||||||
|
PROFILE_RUNTIME_STATUS) PARSED_PROFILE_RUNTIME_STATUS="$PARSED_FIELD_VALUE" ;;
|
||||||
|
OBSERVABILITY_STATUS) PARSED_OBSERVABILITY_STATUS="$PARSED_FIELD_VALUE" ;;
|
||||||
|
OBSERVABILITY_REASON) PARSED_OBSERVABILITY_REASON="$PARSED_FIELD_VALUE" ;;
|
||||||
|
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_MEASUREMENT_ELIGIBILITY="$PARSED_FIELD_VALUE" ;;
|
||||||
|
COMPLETE_SAMPLE_COUNT) PARSED_COMPLETE_SAMPLE_COUNT="$PARSED_FIELD_VALUE" ;;
|
||||||
|
VALIDATION_RESULT) PARSED_VALIDATION_RESULT="$PARSED_FIELD_VALUE" ;;
|
||||||
|
esac
|
||||||
|
elif [ "$CONTRACT_PARSE_ERROR" = "NONE" ]; then
|
||||||
|
CONTRACT_PARSE_ERROR="${field}_${PARSED_FIELD_ERROR}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$CONTRACT_PARSE_ERROR" = "NONE" ]; then
|
||||||
|
[ "$PARSED_MODE" = "$requested_mode" ] || CONTRACT_PARSE_ERROR="MODE_MISMATCH"
|
||||||
|
for field in \
|
||||||
|
"$PARSED_MODE_STATUS" \
|
||||||
|
"$PARSED_PROFILE_CONFIG_STATUS" \
|
||||||
|
"$PARSED_PROFILE_RUNTIME_STATUS" \
|
||||||
|
"$PARSED_OBSERVABILITY_STATUS" \
|
||||||
|
"$PARSED_FUNCTIONAL_STATUS" \
|
||||||
|
"$PARSED_SEMANTIC_STATUS"
|
||||||
|
do
|
||||||
|
case "$field" in
|
||||||
|
PASS|FAIL|NOT_DEMONSTRATED) ;;
|
||||||
|
*) CONTRACT_PARSE_ERROR="STATUS_VOCABULARY_INVALID"; break ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
if [ "$CONTRACT_PARSE_ERROR" = "NONE" ]; then
|
||||||
|
[[ "$PARSED_OBSERVABILITY_REASON" =~ ^[A-Z][A-Z0-9_]*$ ]] || \
|
||||||
|
CONTRACT_PARSE_ERROR="OBSERVABILITY_REASON_MALFORMED"
|
||||||
|
[[ "$PARSED_TIMING_STATUS" =~ ^(NOT_VALID_|UNASSESSED_)[A-Z0-9_]+$ ]] || \
|
||||||
|
CONTRACT_PARSE_ERROR="TIMING_STATUS_UNRECOGNIZED"
|
||||||
|
[ "$PARSED_MEASUREMENT_ELIGIBILITY" = "NO" ] || \
|
||||||
|
CONTRACT_PARSE_ERROR="ELIGIBILITY_CONTRACT_VIOLATION"
|
||||||
|
[[ "$PARSED_COMPLETE_SAMPLE_COUNT" =~ ^[0-9]+$ ]] || \
|
||||||
|
CONTRACT_PARSE_ERROR="COMPLETE_SAMPLE_COUNT_MALFORMED"
|
||||||
|
[[ "$PARSED_VALIDATION_RESULT" =~ ^[A-Z][A-Z0-9_]*$ ]] || \
|
||||||
|
CONTRACT_PARSE_ERROR="VALIDATION_RESULT_MALFORMED"
|
||||||
|
if [ "$PARSED_OBSERVABILITY_STATUS" = "PASS" ]; then
|
||||||
|
[ "$PARSED_OBSERVABILITY_REASON" = "NONE" ] || \
|
||||||
|
CONTRACT_PARSE_ERROR="OBSERVABILITY_REASON_CONFLICT"
|
||||||
|
else
|
||||||
|
[ "$PARSED_OBSERVABILITY_REASON" != "NONE" ] || \
|
||||||
|
CONTRACT_PARSE_ERROR="OBSERVABILITY_REASON_MISSING"
|
||||||
|
fi
|
||||||
|
case "$validator_rc:$PARSED_VALIDATION_RESULT" in
|
||||||
|
0:PASS_CLEAN_SHUTDOWN|\
|
||||||
|
10:PASS_KNOWN_SHUTDOWN_ANOMALY|\
|
||||||
|
11:PASS_UNCLASSIFIED_SHUTDOWN_ANOMALY|\
|
||||||
|
20:FUNCTIONAL_OR_SEMANTIC_NOT_DEMONSTRATED|\
|
||||||
|
21:FAIL_REQUIRED_INPUT)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
CONTRACT_PARSE_ERROR="VALIDATION_RESULT_RC_CONFLICT"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$requested_mode" = "MINIMAL" ]; then
|
||||||
|
for field in \
|
||||||
|
CANONICAL_STRUCTURAL_COMPLETENESS_STATUS \
|
||||||
|
MINIMAL_RUNTIME_CONFIG_STATUS
|
||||||
|
do
|
||||||
|
if parse_contract_field "$field" "$validation_file"; then
|
||||||
|
[ "$PARSED_FIELD_VALUE" = "PASS" ] || \
|
||||||
|
CONTRACT_PARSE_ERROR="${field}_NOT_PASS"
|
||||||
|
else
|
||||||
|
CONTRACT_PARSE_ERROR="${field}_${PARSED_FIELD_ERROR}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$CONTRACT_PARSE_ERROR" != "NONE" ]; then
|
||||||
|
FINAL_RC=22
|
||||||
|
FINAL_RESULT="INCONCLUSIVE_S03H3_CONTRACT"
|
||||||
|
BLOCK_REASON="$CONTRACT_PARSE_ERROR"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$validator_rc" in
|
||||||
|
11|20|21)
|
||||||
|
FINAL_RC=20
|
||||||
|
FINAL_RESULT="S03H3_VALIDATION_INCONCLUSIVE"
|
||||||
|
BLOCK_REASON="VALIDATOR_RC_${validator_rc}"
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
for field in \
|
||||||
|
"$PARSED_MODE_STATUS" \
|
||||||
|
"$PARSED_PROFILE_CONFIG_STATUS" \
|
||||||
|
"$PARSED_PROFILE_RUNTIME_STATUS" \
|
||||||
|
"$PARSED_OBSERVABILITY_STATUS" \
|
||||||
|
"$PARSED_FUNCTIONAL_STATUS" \
|
||||||
|
"$PARSED_SEMANTIC_STATUS"
|
||||||
|
do
|
||||||
|
if [ "$field" != "PASS" ]; then
|
||||||
|
FINAL_RC=25
|
||||||
|
FINAL_RESULT="S03H3_CONTRACT_STATUS_NOT_PASS"
|
||||||
|
BLOCK_REASON="MANDATORY_STATUS_NOT_PASS"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
case "$PARSED_TIMING_STATUS" in
|
||||||
|
NOT_VALID_*)
|
||||||
|
FINAL_RC=14
|
||||||
|
FINAL_RESULT="FUNCTIONAL_AND_SEMANTIC_PASS_TIMING_NOT_VALID"
|
||||||
|
BLOCK_REASON="$PARSED_TIMING_STATUS"
|
||||||
|
;;
|
||||||
|
UNASSESSED_*)
|
||||||
|
FINAL_RC=15
|
||||||
|
FINAL_RESULT="FUNCTIONAL_AND_SEMANTIC_PASS_TIMING_UNASSESSED"
|
||||||
|
BLOCK_REASON="$PARSED_TIMING_STATUS"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
FINAL_RC=22
|
||||||
|
FINAL_RESULT="INCONCLUSIVE_S03H3_CONTRACT"
|
||||||
|
BLOCK_REASON="TIMING_STATUS_UNRECOGNIZED"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
run_s03h3() {
|
||||||
|
local duration="$1"
|
||||||
|
MODE="$2"
|
||||||
|
local expected_selected_hash
|
||||||
|
local patcher_log
|
||||||
|
local protected_before
|
||||||
|
local capture
|
||||||
|
local run_dir
|
||||||
|
local validation_log
|
||||||
|
local csv_report
|
||||||
|
local launcher_summary
|
||||||
|
local protected_after
|
||||||
|
local invariance_report
|
||||||
|
local protected_path_list
|
||||||
|
|
||||||
|
resolve_suite
|
||||||
|
[ -d "$SUITE" ] || return 50
|
||||||
|
|
||||||
|
PATCHER="$SUITE/patchers/configuration/build_s03h3_minimal_from_s03h1_test.sh"
|
||||||
|
VALIDATOR="$SUITE/scenarios/S03H3_execution_profiles/validate.sh"
|
||||||
|
MINIMAL_VERIFIER="$SUITE/scenarios/S03H3_execution_profiles/verify_s03h3_minimal_structure.py"
|
||||||
|
MINIMAL_CONFIG="$SUITE/configurations/generated/S03H3/from_patcher/smoke_s03h3_execution_profiles_minimal_from_s03h1_test.marte"
|
||||||
|
TEST_CONFIG="$SUITE/configurations/generated/S03H1/from_patcher/smoke_s03h1_execution_profiles_test_from_s02.marte"
|
||||||
|
DIAGNOSTIC_CONFIG="$SUITE/configurations/generated/S03H1/from_patcher/smoke_s03h1_execution_profiles_diagnostic_from_s02.marte"
|
||||||
|
RUNNER="$SUITE/common/marte_runner.sh"
|
||||||
|
LIVE_PATHS="$SUITE/common/paths.sh"
|
||||||
|
CSV_EXPORTER="$SUITE/scenarios/S03H1_execution_profiles/export_s03_csv.py"
|
||||||
|
PARSER="$SUITE/scenarios/S03_semantic_sentinels/parse_s03_binary.py"
|
||||||
|
|
||||||
|
case "$MODE" in
|
||||||
|
MINIMAL)
|
||||||
|
SELECTED_CONFIG="$MINIMAL_CONFIG"
|
||||||
|
expected_selected_hash="$EXPECTED_MINIMAL_CONFIG_SHA256"
|
||||||
|
;;
|
||||||
|
TEST)
|
||||||
|
SELECTED_CONFIG="$TEST_CONFIG"
|
||||||
|
expected_selected_hash="$EXPECTED_TEST_CONFIG_SHA256"
|
||||||
|
;;
|
||||||
|
DIAGNOSTIC)
|
||||||
|
SELECTED_CONFIG="$DIAGNOSTIC_CONFIG"
|
||||||
|
expected_selected_hash="$EXPECTED_DIAGNOSTIC_CONFIG_SHA256"
|
||||||
|
;;
|
||||||
|
*) return 2 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
verify_historical_baseline || return 52
|
||||||
|
verify_candidate_components || return 51
|
||||||
|
verify_hash "$SELECTED_CONFIG" "$expected_selected_hash" "SELECTED_${MODE}_CONFIG" || return 51
|
||||||
|
build_protected_paths
|
||||||
|
local protected_path
|
||||||
|
for protected_path in "${PROTECTED_PATHS[@]}"; do
|
||||||
|
[ -f "$protected_path" ] || return 51
|
||||||
|
done
|
||||||
|
|
||||||
|
WORK_ROOT="$(mktemp -d "${TMPDIR:-/tmp}/s03h3_launcher.XXXXXX")" || return 53
|
||||||
|
trap 'rm -rf -- "$WORK_ROOT"' EXIT HUP INT TERM
|
||||||
|
patcher_log="$WORK_ROOT/patcher.log"
|
||||||
|
protected_before="$WORK_ROOT/protected_before.sha256"
|
||||||
|
capture="$WORK_ROOT/runner_capture.log"
|
||||||
|
|
||||||
|
"$PATCHER" >"$patcher_log" 2>&1
|
||||||
|
PATCHER_RC=$?
|
||||||
|
[ "$PATCHER_RC" -eq 0 ] || return 54
|
||||||
|
verify_hash "$MINIMAL_CONFIG" "$EXPECTED_MINIMAL_CONFIG_SHA256" "MINIMAL_REGENERATION" || return 55
|
||||||
|
python3 "$MINIMAL_VERIFIER" CANONICAL "$TEST_CONFIG" "$MINIMAL_CONFIG" >/dev/null 2>&1 || return 55
|
||||||
|
write_protected_snapshot "$protected_before" || return 56
|
||||||
|
|
||||||
|
[ -f "$LIVE_PATHS" ] || return 57
|
||||||
|
# shellcheck source=/dev/null
|
||||||
|
source "$LIVE_PATHS" || return 57
|
||||||
|
CONSTANT_GAM_LIB_DIR="$MARTE2_COMPONENTS_ROOT/Build/$MARTE_TARGET/Components/GAMs/ConstantGAM"
|
||||||
|
CONSTANT_GAM_LIB="$CONSTANT_GAM_LIB_DIR/ConstantGAM.so"
|
||||||
|
[ -f "$CONSTANT_GAM_LIB" ] || return 58
|
||||||
|
case ":${LD_LIBRARY_PATH-}:" in
|
||||||
|
*":${CONSTANT_GAM_LIB_DIR}:"*) ;;
|
||||||
|
*) LD_LIBRARY_PATH="${CONSTANT_GAM_LIB_DIR}${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}" ;;
|
||||||
|
esac
|
||||||
|
export LD_LIBRARY_PATH
|
||||||
|
|
||||||
|
printf '============================================================\n'
|
||||||
|
printf 'S03-H3 EXECUTION PROFILES\n'
|
||||||
|
printf '============================================================\n'
|
||||||
|
printf 'MODE=%s\n' "$MODE"
|
||||||
|
printf 'DURATION=%s\n' "$duration"
|
||||||
|
printf 'DEPENDENCY_INTEGRITY_STATUS=PASS\n'
|
||||||
|
|
||||||
|
"$RUNNER" "S03H3_${MODE}_launcher" "$SELECTED_CONFIG" "State1" "$duration" \
|
||||||
|
2>&1 | tee "$capture"
|
||||||
|
RUNNER_CODES=("${PIPESTATUS[@]}")
|
||||||
|
RUNNER_RC="${RUNNER_CODES[0]}"
|
||||||
|
CAPTURE_TEE_RC="${RUNNER_CODES[1]}"
|
||||||
|
[ "$RUNNER_RC" -eq 0 ] || return 60
|
||||||
|
[ "$CAPTURE_TEE_RC" -eq 0 ] || return 61
|
||||||
|
|
||||||
|
run_dir="$(sed -n 's/^RUN_DIR=//p' "$capture" | tail -n 1)"
|
||||||
|
case "$run_dir" in
|
||||||
|
"$SUITE"/runs/*_S03H3_${MODE}_launcher) ;;
|
||||||
|
*) return 62 ;;
|
||||||
|
esac
|
||||||
|
[ -d "$run_dir" ] || return 62
|
||||||
|
|
||||||
|
RUN_LOG="$run_dir/run.log"
|
||||||
|
RUN_CONFIG="$run_dir/configuration.marte"
|
||||||
|
RUNNER_SUMMARY="$run_dir/runner_summary.txt"
|
||||||
|
RUN_HASHES="$run_dir/hashes.sha256"
|
||||||
|
OUTPUT_FILE="$run_dir/s03_output.bin"
|
||||||
|
CSV_FILE="$run_dir/s03_output.csv"
|
||||||
|
MODE_FILE="$run_dir/s03h3_mode.txt"
|
||||||
|
validation_log="$run_dir/validation.txt"
|
||||||
|
csv_report="$run_dir/csv_export.txt"
|
||||||
|
launcher_summary="$run_dir/launcher_summary.txt"
|
||||||
|
PROTECTED_BEFORE_RUN="$run_dir/protected_baseline_before.sha256"
|
||||||
|
protected_after="$run_dir/protected_baseline_after.sha256"
|
||||||
|
invariance_report="$run_dir/protected_baseline_invariance.txt"
|
||||||
|
protected_path_list="$run_dir/protected_successor_paths.txt"
|
||||||
|
|
||||||
|
for protected_path in "$RUN_LOG" "$RUN_CONFIG" "$RUNNER_SUMMARY" "$RUN_HASHES" "$OUTPUT_FILE"; do
|
||||||
|
[ -f "$protected_path" ] || return 63
|
||||||
|
done
|
||||||
|
|
||||||
|
cp -- "$protected_before" "$PROTECTED_BEFORE_RUN" || return 64
|
||||||
|
write_protected_path_list "$protected_path_list" || return 64
|
||||||
|
{
|
||||||
|
printf 'SCENARIO=S03H3\n'
|
||||||
|
printf 'MODE=%s\n' "$MODE"
|
||||||
|
printf 'SELECTED_CONFIG_SHA256=%s\n' "$expected_selected_hash"
|
||||||
|
} >"$MODE_FILE" || return 64
|
||||||
|
|
||||||
|
sha256sum -- \
|
||||||
|
"$MODE_FILE" \
|
||||||
|
"${BASH_SOURCE[0]}" \
|
||||||
|
"$PATCHER" \
|
||||||
|
"$VALIDATOR" \
|
||||||
|
"$MINIMAL_VERIFIER" \
|
||||||
|
"$CSV_EXPORTER" \
|
||||||
|
"$PARSER" \
|
||||||
|
"$RUN_LOG" \
|
||||||
|
"$RUNNER_SUMMARY" \
|
||||||
|
"$OUTPUT_FILE" \
|
||||||
|
"$PROTECTED_BEFORE_RUN" \
|
||||||
|
"$protected_path_list" \
|
||||||
|
"${PROTECTED_PATHS[@]}" \
|
||||||
|
>>"$RUN_HASHES" || return 64
|
||||||
|
|
||||||
|
timeout 30s "$VALIDATOR" "$MODE" "$run_dir" 2>&1 | tee "$validation_log"
|
||||||
|
VALIDATION_CODES=("${PIPESTATUS[@]}")
|
||||||
|
VALIDATOR_RC="${VALIDATION_CODES[0]}"
|
||||||
|
VALIDATION_TEE_RC="${VALIDATION_CODES[1]}"
|
||||||
|
|
||||||
|
"$CSV_EXPORTER" "$OUTPUT_FILE" "$CSV_FILE" >"$csv_report" 2>&1
|
||||||
|
CSV_EXPORT_RC=$?
|
||||||
|
if [ "$CSV_EXPORT_RC" -eq 0 ]; then
|
||||||
|
CSV_EXPORT_STATUS="PASS"
|
||||||
|
else
|
||||||
|
CSV_EXPORT_STATUS="FAIL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if write_protected_snapshot "$protected_after" && \
|
||||||
|
cmp -s -- "$PROTECTED_BEFORE_RUN" "$protected_after"; then
|
||||||
|
PROTECTED_BASELINE_INVARIANCE="PASS"
|
||||||
|
else
|
||||||
|
PROTECTED_BASELINE_INVARIANCE="FAIL"
|
||||||
|
fi
|
||||||
|
{
|
||||||
|
printf 'PROTECTED_BASELINE_INVARIANCE=%s\n' "$PROTECTED_BASELINE_INVARIANCE"
|
||||||
|
printf 'PROTECTED_SUCCESSOR_BASELINE_COUNT=27\n'
|
||||||
|
} >"$invariance_report"
|
||||||
|
|
||||||
|
for protected_path in "$validation_log" "$csv_report" "$protected_after" "$invariance_report"; do
|
||||||
|
[ -f "$protected_path" ] && sha256sum -- "$protected_path" >>"$RUN_HASHES"
|
||||||
|
done
|
||||||
|
[ -f "$CSV_FILE" ] && sha256sum -- "$CSV_FILE" >>"$RUN_HASHES"
|
||||||
|
|
||||||
|
classify_s03h3_run \
|
||||||
|
"$VALIDATOR_RC" \
|
||||||
|
"$VALIDATION_TEE_RC" \
|
||||||
|
"$validation_log" \
|
||||||
|
"$CSV_EXPORT_RC" \
|
||||||
|
"$PROTECTED_BASELINE_INVARIANCE" \
|
||||||
|
"PASS" \
|
||||||
|
"$MODE"
|
||||||
|
|
||||||
|
{
|
||||||
|
printf '============================================================\n'
|
||||||
|
printf 'RIEPILOGO LAUNCHER S03-H3\n'
|
||||||
|
printf '============================================================\n'
|
||||||
|
printf 'SCENARIO=S03H3\n'
|
||||||
|
printf 'MODE=%s\n' "$MODE"
|
||||||
|
printf 'DURATION=%s\n' "$duration"
|
||||||
|
printf 'RUN_DIR=%s\n' "$run_dir"
|
||||||
|
printf 'RUNNER_RC=%s\n' "$RUNNER_RC"
|
||||||
|
printf 'VALIDATOR_RC=%s\n' "$VALIDATOR_RC"
|
||||||
|
printf 'CSV_EXPORT_RC=%s\n' "$CSV_EXPORT_RC"
|
||||||
|
printf 'DEPENDENCY_INTEGRITY_STATUS=PASS\n'
|
||||||
|
printf 'PROTECTED_BASELINE_INVARIANCE=%s\n' "$PROTECTED_BASELINE_INVARIANCE"
|
||||||
|
printf 'CSV_EXPORT_STATUS=%s\n' "$CSV_EXPORT_STATUS"
|
||||||
|
printf 'MODE_STATUS=%s\n' "$PARSED_MODE_STATUS"
|
||||||
|
printf 'PROFILE_CONFIG_STATUS=%s\n' "$PARSED_PROFILE_CONFIG_STATUS"
|
||||||
|
printf 'PROFILE_RUNTIME_STATUS=%s\n' "$PARSED_PROFILE_RUNTIME_STATUS"
|
||||||
|
printf 'OBSERVABILITY_STATUS=%s\n' "$PARSED_OBSERVABILITY_STATUS"
|
||||||
|
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=NO\n'
|
||||||
|
printf 'BLOCK_REASON=%s\n' "$BLOCK_REASON"
|
||||||
|
printf 'FINAL_RESULT=%s\n' "$FINAL_RESULT"
|
||||||
|
printf 'FINAL_RC=%s\n' "$FINAL_RC"
|
||||||
|
printf 'PERFORMANCE_MEASUREMENT_AUTHORIZED=NO\n'
|
||||||
|
printf 'S04_AUTHORIZED=NO\n'
|
||||||
|
printf 'MD00_AUTHORIZED=NO\n'
|
||||||
|
} | tee "$launcher_summary"
|
||||||
|
SUMMARY_CODES=("${PIPESTATUS[@]}")
|
||||||
|
if [ "${SUMMARY_CODES[1]}" -ne 0 ]; then
|
||||||
|
FINAL_RC=69
|
||||||
|
FINAL_RESULT="FAIL_LAUNCHER_SUMMARY"
|
||||||
|
BLOCK_REASON="LAUNCHER_SUMMARY_NOT_WRITTEN"
|
||||||
|
else
|
||||||
|
sha256sum -- "$launcher_summary" >>"$RUN_HASHES"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf 'RUN_DIR=%s\n' "$run_dir"
|
||||||
|
printf 'FINAL_RESULT=%s\n' "$FINAL_RESULT"
|
||||||
|
printf 'FINAL_RC=%s\n' "$FINAL_RC"
|
||||||
|
|
||||||
|
rm -rf -- "$WORK_ROOT"
|
||||||
|
WORK_ROOT=""
|
||||||
|
trap - EXIT HUP INT TERM
|
||||||
|
return "$FINAL_RC"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "${S03H3_LAUNCHER_LIB_ONLY:-0}" = "1" ]; then
|
||||||
|
if [ "${BASH_SOURCE[0]}" != "$0" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
printf 'S03H3_LAUNCHER_LIB_ONLY=1 richiede source.\n' >&2
|
||||||
|
exit 3
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$#" in
|
||||||
|
1)
|
||||||
|
case "$1" in
|
||||||
|
-h|--help)
|
||||||
|
print_usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
print_usage >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
3)
|
||||||
|
[ "$1" = "S03H3" ] || {
|
||||||
|
print_usage >&2
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
is_positive_decimal "$2" || {
|
||||||
|
printf 'Durata non valida: %s\n' "$2" >&2
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
case "$3" in
|
||||||
|
MINIMAL|TEST|DIAGNOSTIC) ;;
|
||||||
|
*)
|
||||||
|
printf 'Profilo non riconosciuto: %s\n' "$3" >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
run_s03h3 "$2" "$3"
|
||||||
|
exit $?
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
print_usage >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
Executable
+512
@@ -0,0 +1,512 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -u
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
readonly DEFAULT_DURATION_SECONDS="8"
|
||||||
|
readonly TEST_OVERRIDE_ACK_VALUE="YES"
|
||||||
|
|
||||||
|
CAPTURE=""
|
||||||
|
STATUS_DIR=""
|
||||||
|
LAUNCH_ACTIVE="NO"
|
||||||
|
INTERRUPT_PENDING="NO"
|
||||||
|
|
||||||
|
SELECTED_SCENARIO=""
|
||||||
|
DISPLAY_SCENARIO=""
|
||||||
|
SELECTED_PROFILE="N/A"
|
||||||
|
SELECTED_DURATION=""
|
||||||
|
|
||||||
|
LAST_LAUNCHER_RC="NOT_AVAILABLE"
|
||||||
|
LAST_RUN_DIR="NOT_AVAILABLE"
|
||||||
|
LAST_RUN_DIR_STATUS="NOT_AVAILABLE"
|
||||||
|
|
||||||
|
cleanup_temporary_files() {
|
||||||
|
if [ -n "$CAPTURE" ]; then
|
||||||
|
rm -f -- "$CAPTURE"
|
||||||
|
CAPTURE=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$STATUS_DIR" ]; then
|
||||||
|
rm -f -- \
|
||||||
|
"$STATUS_DIR/launcher_rc" \
|
||||||
|
"$STATUS_DIR/tee_rc"
|
||||||
|
rmdir -- "$STATUS_DIR" 2>/dev/null || true
|
||||||
|
STATUS_DIR=""
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
fatal_wrapper_error() {
|
||||||
|
local exit_code="$1"
|
||||||
|
local status="$2"
|
||||||
|
local message="$3"
|
||||||
|
|
||||||
|
printf 'ERRORE S03-H3: %s\n' "$message" >&2
|
||||||
|
if [ "$exit_code" -eq 70 ]; then
|
||||||
|
printf 'S03_H3_STARTUP_STATUS=%s\n' "$status" >&2
|
||||||
|
else
|
||||||
|
printf 'S03_H3_MENU_LIFECYCLE_STATUS=%s\n' "$status" >&2
|
||||||
|
fi
|
||||||
|
exit "$exit_code"
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_int() {
|
||||||
|
if [ "$LAUNCH_ACTIVE" = "YES" ]; then
|
||||||
|
INTERRUPT_PENDING="YES"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '\nInterruzione richiesta: nessun nuovo benchmark verra avviato.\n' >&2
|
||||||
|
printf 'LAUNCHER_EXECUTED=NO\n' >&2
|
||||||
|
exit 130
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_hup() {
|
||||||
|
printf '\nS03-H3 terminato da SIGHUP.\n' >&2
|
||||||
|
exit 129
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_term() {
|
||||||
|
printf '\nS03-H3 terminato da SIGTERM.\n' >&2
|
||||||
|
exit 143
|
||||||
|
}
|
||||||
|
|
||||||
|
trap cleanup_temporary_files EXIT
|
||||||
|
trap handle_hup HUP
|
||||||
|
trap handle_int INT
|
||||||
|
trap handle_term TERM
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
|
||||||
|
if [ -z "$SCRIPT_DIR" ]; then
|
||||||
|
fatal_wrapper_error 70 "FAIL_SUITE_ROOT" \
|
||||||
|
"impossibile determinare la directory del menu"
|
||||||
|
fi
|
||||||
|
|
||||||
|
INSTALLED_SUITE="$(cd -- "$SCRIPT_DIR/.." && pwd -P)"
|
||||||
|
if [ -z "$INSTALLED_SUITE" ]; then
|
||||||
|
fatal_wrapper_error 70 "FAIL_SUITE_ROOT" \
|
||||||
|
"impossibile determinare la radice della suite"
|
||||||
|
fi
|
||||||
|
|
||||||
|
readonly -a COMPLETE_OVERRIDE_PATHS=(
|
||||||
|
"launcher/marte_benchmark_launcher.sh"
|
||||||
|
"configurations/generated/S00/smoke_s0_core.marte"
|
||||||
|
"configurations/generated/S01/from_patcher/smoke_s1_timing_from_s00.marte"
|
||||||
|
"configurations/generated/S02/from_patcher/smoke_s2_binary_recording_from_s01.marte"
|
||||||
|
"configurations/generated/S03/from_patcher/smoke_s3_semantic_sentinels_from_s02.marte"
|
||||||
|
"patchers/configuration/build_s01_from_s00.sh"
|
||||||
|
"patchers/configuration/build_s02_from_s01.sh"
|
||||||
|
"patchers/configuration/build_s03_from_s02.sh"
|
||||||
|
"scenarios/S02_binary_recording/validate.sh"
|
||||||
|
"scenarios/S03_semantic_sentinels/validate.sh"
|
||||||
|
"scenarios/S03_semantic_sentinels/parse_s03_binary.py"
|
||||||
|
"common/marte_runner.sh"
|
||||||
|
"common/paths.sh"
|
||||||
|
"common/environment.sh"
|
||||||
|
"launcher/marte_benchmark_launcher_s03h1.sh"
|
||||||
|
"patchers/configuration/build_s03h1_from_s02.sh"
|
||||||
|
"scenarios/S03H1_execution_profiles/validate.sh"
|
||||||
|
"scenarios/S03H1_execution_profiles/verify_s03h1_config.py"
|
||||||
|
"scenarios/S03H1_execution_profiles/export_s03_csv.py"
|
||||||
|
"configurations/generated/S03H1/from_patcher/smoke_s03h1_execution_profiles_test_from_s02.marte"
|
||||||
|
"configurations/generated/S03H1/from_patcher/smoke_s03h1_execution_profiles_diagnostic_from_s02.marte"
|
||||||
|
"launcher/marte_benchmark_launcher_s03h3.sh"
|
||||||
|
"patchers/configuration/build_s03h3_minimal_from_s03h1_test.sh"
|
||||||
|
"scenarios/S03H3_execution_profiles/validate.sh"
|
||||||
|
"scenarios/S03H3_execution_profiles/verify_s03h3_minimal_structure.py"
|
||||||
|
"configurations/generated/S03H3/from_patcher/smoke_s03h3_execution_profiles_minimal_from_s03h1_test.marte"
|
||||||
|
"launcher/marte_benchmark_menu.sh"
|
||||||
|
)
|
||||||
|
|
||||||
|
verify_complete_override_root() {
|
||||||
|
local relative_path
|
||||||
|
local missing_count=0
|
||||||
|
|
||||||
|
for relative_path in "${COMPLETE_OVERRIDE_PATHS[@]}"; do
|
||||||
|
if [ ! -f "$SUITE/$relative_path" ]; then
|
||||||
|
printf 'ERRORE S03-H3: fixture incompleta, manca %s\n' \
|
||||||
|
"$relative_path" >&2
|
||||||
|
missing_count=$((missing_count + 1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
[ "$missing_count" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
OVERRIDE_ACTIVE="NO"
|
||||||
|
if [ -n "${MARTE_BENCHMARK_SUITE_ROOT:-}" ]; then
|
||||||
|
if [ "${S03H3_TEST_ONLY_OVERRIDE:-NO}" != "$TEST_OVERRIDE_ACK_VALUE" ]; then
|
||||||
|
fatal_wrapper_error 70 "FAIL_TEST_OVERRIDE_NOT_ACKNOWLEDGED" \
|
||||||
|
"MARTE_BENCHMARK_SUITE_ROOT richiede S03H3_TEST_ONLY_OVERRIDE=YES"
|
||||||
|
fi
|
||||||
|
if [[ "$MARTE_BENCHMARK_SUITE_ROOT" != /* ]]; then
|
||||||
|
fatal_wrapper_error 70 "FAIL_TEST_OVERRIDE_NOT_ABSOLUTE" \
|
||||||
|
"la radice di override deve essere un percorso assoluto"
|
||||||
|
fi
|
||||||
|
if [ ! -d "$MARTE_BENCHMARK_SUITE_ROOT" ]; then
|
||||||
|
fatal_wrapper_error 70 "FAIL_TEST_OVERRIDE_ROOT" \
|
||||||
|
"la radice di override non esiste"
|
||||||
|
fi
|
||||||
|
|
||||||
|
SUITE="$(cd -- "$MARTE_BENCHMARK_SUITE_ROOT" && pwd -P)"
|
||||||
|
if [ -z "$SUITE" ] || [ "$SUITE" = "/" ]; then
|
||||||
|
fatal_wrapper_error 70 "FAIL_TEST_OVERRIDE_ROOT" \
|
||||||
|
"la radice di override non e sicura"
|
||||||
|
fi
|
||||||
|
OVERRIDE_ACTIVE="YES"
|
||||||
|
|
||||||
|
if ! verify_complete_override_root; then
|
||||||
|
fatal_wrapper_error 70 "FAIL_INCOMPLETE_TEST_SUITE" \
|
||||||
|
"l'override e ammesso soltanto per una suite completa di 27 elementi"
|
||||||
|
fi
|
||||||
|
elif [ "${S03H3_TEST_ONLY_OVERRIDE:-NO}" = "$TEST_OVERRIDE_ACK_VALUE" ]; then
|
||||||
|
fatal_wrapper_error 70 "FAIL_TEST_OVERRIDE_ROOT_MISSING" \
|
||||||
|
"S03H3_TEST_ONLY_OVERRIDE=YES richiede MARTE_BENCHMARK_SUITE_ROOT"
|
||||||
|
else
|
||||||
|
SUITE="$INSTALLED_SUITE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
readonly SUITE
|
||||||
|
readonly OVERRIDE_ACTIVE
|
||||||
|
|
||||||
|
STANDARD_LAUNCHER="$SUITE/launcher/marte_benchmark_launcher.sh"
|
||||||
|
S03H3_LAUNCHER="$SUITE/launcher/marte_benchmark_launcher_s03h3.sh"
|
||||||
|
readonly STANDARD_LAUNCHER
|
||||||
|
readonly S03H3_LAUNCHER
|
||||||
|
|
||||||
|
if [ ! -x "$STANDARD_LAUNCHER" ]; then
|
||||||
|
fatal_wrapper_error 70 "FAIL_REQUIRED_LAUNCHER" \
|
||||||
|
"launcher standard assente o non eseguibile: $STANDARD_LAUNCHER"
|
||||||
|
fi
|
||||||
|
if [ ! -x "$S03H3_LAUNCHER" ]; then
|
||||||
|
fatal_wrapper_error 70 "FAIL_REQUIRED_LAUNCHER" \
|
||||||
|
"launcher S03-H3 assente o non eseguibile: $S03H3_LAUNCHER"
|
||||||
|
fi
|
||||||
|
|
||||||
|
export MARTE_BENCHMARK_SUITE_ROOT="$SUITE"
|
||||||
|
|
||||||
|
is_positive_decimal() {
|
||||||
|
local value="$1"
|
||||||
|
|
||||||
|
[[ "$value" =~ ^[0-9]+$ ]] && [[ "$value" =~ [1-9] ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
normalize_decimal() {
|
||||||
|
local value="$1"
|
||||||
|
|
||||||
|
while [ "${#value}" -gt 1 ] && [ "${value:0:1}" = "0" ]; do
|
||||||
|
value="${value#0}"
|
||||||
|
done
|
||||||
|
printf '%s' "$value"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_main_menu() {
|
||||||
|
printf '\n============================================================\n'
|
||||||
|
printf 'MARTe2 Benchmark Suite — menu S03-H3\n'
|
||||||
|
printf '============================================================\n'
|
||||||
|
printf '1) S01\n'
|
||||||
|
printf '2) S02\n'
|
||||||
|
printf '3) S03\n'
|
||||||
|
printf '4) S03-H3\n'
|
||||||
|
printf '0) Exit\n'
|
||||||
|
printf 'Selection: '
|
||||||
|
}
|
||||||
|
|
||||||
|
read_duration() {
|
||||||
|
local value
|
||||||
|
|
||||||
|
printf 'Simulation duration [seconds] (default: %s): ' \
|
||||||
|
"$DEFAULT_DURATION_SECONDS"
|
||||||
|
if ! IFS= read -r value; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [ -z "$value" ]; then
|
||||||
|
SELECTED_DURATION="$DEFAULT_DURATION_SECONDS"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if ! is_positive_decimal "$value"; then
|
||||||
|
printf 'Durata non valida: usare solo un intero decimale positivo.\n' >&2
|
||||||
|
printf 'LAUNCHER_EXECUTED=NO\n'
|
||||||
|
return 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
SELECTED_DURATION="$(normalize_decimal "$value")"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
read_s03h3_profile() {
|
||||||
|
local value
|
||||||
|
|
||||||
|
printf '1) MINIMAL\n'
|
||||||
|
printf '2) TEST\n'
|
||||||
|
printf '3) DIAGNOSTIC\n'
|
||||||
|
printf 'Profile: '
|
||||||
|
if ! IFS= read -r value; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$value" in
|
||||||
|
1)
|
||||||
|
SELECTED_PROFILE="MINIMAL"
|
||||||
|
;;
|
||||||
|
2)
|
||||||
|
SELECTED_PROFILE="TEST"
|
||||||
|
;;
|
||||||
|
3)
|
||||||
|
SELECTED_PROFILE="DIAGNOSTIC"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf 'Profilo non valido. Nessun launcher eseguito.\n' >&2
|
||||||
|
printf 'LAUNCHER_EXECUTED=NO\n'
|
||||||
|
return 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
confirm_execution() {
|
||||||
|
local answer
|
||||||
|
|
||||||
|
printf '\nScenario: %s\n' "$DISPLAY_SCENARIO"
|
||||||
|
printf 'Profile: %s\n' "$SELECTED_PROFILE"
|
||||||
|
printf 'Duration: %s s\n\n' "$SELECTED_DURATION"
|
||||||
|
printf 'Start execution? [y/N]: '
|
||||||
|
if ! IFS= read -r answer; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$answer" in
|
||||||
|
y|Y)
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf 'Esecuzione annullata.\n'
|
||||||
|
printf 'LAUNCHER_EXECUTED=NO\n'
|
||||||
|
return 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate_launcher() {
|
||||||
|
case "$SELECTED_SCENARIO" in
|
||||||
|
S01)
|
||||||
|
"$STANDARD_LAUNCHER" S01 "$SELECTED_DURATION"
|
||||||
|
;;
|
||||||
|
S02)
|
||||||
|
"$STANDARD_LAUNCHER" S02 "$SELECTED_DURATION"
|
||||||
|
;;
|
||||||
|
S03)
|
||||||
|
"$STANDARD_LAUNCHER" S03 "$SELECTED_DURATION"
|
||||||
|
;;
|
||||||
|
S03H3)
|
||||||
|
"$S03H3_LAUNCHER" S03H3 "$SELECTED_DURATION" "$SELECTED_PROFILE"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
return 125
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
read_recorded_status() {
|
||||||
|
local status_file="$1"
|
||||||
|
local fallback="$2"
|
||||||
|
local value=""
|
||||||
|
|
||||||
|
if [ -s "$status_file" ]; then
|
||||||
|
IFS= read -r value <"$status_file" || value=""
|
||||||
|
fi
|
||||||
|
if [[ "$value" =~ ^[0-9]+$ ]]; then
|
||||||
|
printf '%s' "$value"
|
||||||
|
else
|
||||||
|
printf '%s' "$fallback"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
observe_run_dir() {
|
||||||
|
local observed=""
|
||||||
|
local observed_resolved=""
|
||||||
|
local observed_parent=""
|
||||||
|
local observed_name=""
|
||||||
|
|
||||||
|
observed="$(sed -n 's/^RUN_DIR=//p' "$CAPTURE" | tail -n 1)"
|
||||||
|
if [ -z "$observed" ]; then
|
||||||
|
LAST_RUN_DIR="NOT_AVAILABLE"
|
||||||
|
LAST_RUN_DIR_STATUS="NOT_AVAILABLE"
|
||||||
|
elif [[ "$observed" != /* ]]; then
|
||||||
|
LAST_RUN_DIR="$observed"
|
||||||
|
LAST_RUN_DIR_STATUS="REPORTED_BUT_INVALID"
|
||||||
|
elif [ ! -d "$observed" ]; then
|
||||||
|
LAST_RUN_DIR="$observed"
|
||||||
|
LAST_RUN_DIR_STATUS="REPORTED_BUT_NOT_FOUND"
|
||||||
|
elif [ "$SELECTED_SCENARIO" = "S03H3" ]; then
|
||||||
|
observed_resolved="$(cd -- "$observed" && pwd -P)" || observed_resolved=""
|
||||||
|
observed_parent="$(dirname -- "$observed_resolved")"
|
||||||
|
observed_name="$(basename -- "$observed_resolved")"
|
||||||
|
if [ "$observed_parent" = "$SUITE/runs" ] &&
|
||||||
|
[[ "$observed_name" = *_S03H3_${SELECTED_PROFILE}_launcher ]]; then
|
||||||
|
LAST_RUN_DIR="$observed_resolved"
|
||||||
|
LAST_RUN_DIR_STATUS="FOUND"
|
||||||
|
else
|
||||||
|
LAST_RUN_DIR="$observed"
|
||||||
|
LAST_RUN_DIR_STATUS="REPORTED_BUT_INVALID"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
LAST_RUN_DIR="$observed"
|
||||||
|
LAST_RUN_DIR_STATUS="FOUND"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
print_execution_summary() {
|
||||||
|
printf '\n============================================================\n'
|
||||||
|
printf 'Riepilogo esecuzione S03-H3\n'
|
||||||
|
printf '============================================================\n'
|
||||||
|
printf 'Scenario: %s\n' "$DISPLAY_SCENARIO"
|
||||||
|
printf 'Profile: %s\n' "$SELECTED_PROFILE"
|
||||||
|
printf 'Duration: %s s\n' "$SELECTED_DURATION"
|
||||||
|
printf 'Launcher RC: %s\n' "$LAST_LAUNCHER_RC"
|
||||||
|
printf 'RUN_DIR: %s\n' "$LAST_RUN_DIR"
|
||||||
|
printf 'RUN_DIR status: %s\n' "$LAST_RUN_DIR_STATUS"
|
||||||
|
printf 'LAST_LAUNCHER_RC=%s\n' "$LAST_LAUNCHER_RC"
|
||||||
|
printf 'RUN_DIR_STATUS=%s\n' "$LAST_RUN_DIR_STATUS"
|
||||||
|
printf 'RUN_DIR=%s\n' "$LAST_RUN_DIR"
|
||||||
|
printf 'MENU_RECLASSIFIES_LAUNCHER_RESULT=NO\n'
|
||||||
|
}
|
||||||
|
|
||||||
|
invoke_selected_launcher() {
|
||||||
|
local -a pipeline_status
|
||||||
|
local launcher_rc
|
||||||
|
local tee_rc
|
||||||
|
|
||||||
|
cleanup_temporary_files
|
||||||
|
CAPTURE="$(mktemp "${TMPDIR:-/tmp}/marte_benchmark_menu.capture.XXXXXX")" ||
|
||||||
|
fatal_wrapper_error 71 "FAIL_CAPTURE_CREATION" \
|
||||||
|
"impossibile creare il file temporaneo di cattura"
|
||||||
|
STATUS_DIR="$(mktemp -d "${TMPDIR:-/tmp}/marte_benchmark_menu.status.XXXXXX")" || {
|
||||||
|
cleanup_temporary_files
|
||||||
|
fatal_wrapper_error 71 "FAIL_CAPTURE_CREATION" \
|
||||||
|
"impossibile creare lo stato temporaneo della cattura"
|
||||||
|
}
|
||||||
|
|
||||||
|
INTERRUPT_PENDING="NO"
|
||||||
|
LAUNCH_ACTIVE="YES"
|
||||||
|
(
|
||||||
|
delegate_launcher
|
||||||
|
launcher_rc=$?
|
||||||
|
printf '%s\n' "$launcher_rc" >"$STATUS_DIR/launcher_rc"
|
||||||
|
exit "$launcher_rc"
|
||||||
|
) 2>&1 | (
|
||||||
|
tee "$CAPTURE"
|
||||||
|
tee_rc=$?
|
||||||
|
printf '%s\n' "$tee_rc" >"$STATUS_DIR/tee_rc"
|
||||||
|
exit "$tee_rc"
|
||||||
|
)
|
||||||
|
pipeline_status=("${PIPESTATUS[@]}")
|
||||||
|
LAUNCH_ACTIVE="NO"
|
||||||
|
|
||||||
|
launcher_rc="$(read_recorded_status \
|
||||||
|
"$STATUS_DIR/launcher_rc" "${pipeline_status[0]:-125}")"
|
||||||
|
tee_rc="$(read_recorded_status \
|
||||||
|
"$STATUS_DIR/tee_rc" "${pipeline_status[1]:-125}")"
|
||||||
|
LAST_LAUNCHER_RC="$launcher_rc"
|
||||||
|
observe_run_dir
|
||||||
|
print_execution_summary
|
||||||
|
|
||||||
|
if [ "$INTERRUPT_PENDING" = "YES" ]; then
|
||||||
|
printf 'S03_H3_MENU_LIFECYCLE_STATUS=INTERRUPTED\n' >&2
|
||||||
|
printf 'LAUNCHER_RC_RECLASSIFIED=NO\n' >&2
|
||||||
|
cleanup_temporary_files
|
||||||
|
exit 130
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$tee_rc" -ne 0 ]; then
|
||||||
|
printf 'CAPTURE_TEE_STATUS=FAIL\n' >&2
|
||||||
|
printf 'CAPTURE_TEE_RC=%s\n' "$tee_rc" >&2
|
||||||
|
printf 'S03_H3_MENU_LIFECYCLE_STATUS=FAIL_CAPTURE_TEE\n' >&2
|
||||||
|
cleanup_temporary_files
|
||||||
|
exit 72
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf 'CAPTURE_TEE_STATUS=PASS\n'
|
||||||
|
printf 'S03_H3_MENU_LIFECYCLE_STATUS=CONTINUE\n'
|
||||||
|
cleanup_temporary_files
|
||||||
|
}
|
||||||
|
|
||||||
|
printf 'S03_H3_STARTUP_STATUS=PASS\n'
|
||||||
|
printf 'S03_H3_SUITE_ROOT=%s\n' "$SUITE"
|
||||||
|
printf 'S03_H3_TEST_OVERRIDE_ACTIVE=%s\n' "$OVERRIDE_ACTIVE"
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
print_main_menu
|
||||||
|
if ! IFS= read -r menu_choice; then
|
||||||
|
printf '\nEOF: uscita pulita dal menu.\n'
|
||||||
|
printf 'S03_H3_MENU_LIFECYCLE_STATUS=EXIT_EOF\n'
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
SELECTED_PROFILE="N/A"
|
||||||
|
case "$menu_choice" in
|
||||||
|
0)
|
||||||
|
printf 'Uscita dal menu S03-H3.\n'
|
||||||
|
printf 'S03_H3_MENU_LIFECYCLE_STATUS=EXIT_USER\n'
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
1)
|
||||||
|
SELECTED_SCENARIO="S01"
|
||||||
|
DISPLAY_SCENARIO="S01"
|
||||||
|
;;
|
||||||
|
2)
|
||||||
|
SELECTED_SCENARIO="S02"
|
||||||
|
DISPLAY_SCENARIO="S02"
|
||||||
|
;;
|
||||||
|
3)
|
||||||
|
SELECTED_SCENARIO="S03"
|
||||||
|
DISPLAY_SCENARIO="S03"
|
||||||
|
;;
|
||||||
|
4)
|
||||||
|
SELECTED_SCENARIO="S03H3"
|
||||||
|
DISPLAY_SCENARIO="S03-H3"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf 'Selezione non valida. Nessun launcher eseguito.\n' >&2
|
||||||
|
printf 'LAUNCHER_EXECUTED=NO\n'
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
read_duration
|
||||||
|
duration_status=$?
|
||||||
|
if [ "$duration_status" -eq 1 ]; then
|
||||||
|
printf '\nEOF prima dell esecuzione: azione annullata.\n'
|
||||||
|
printf 'LAUNCHER_EXECUTED=NO\n'
|
||||||
|
printf 'S03_H3_MENU_LIFECYCLE_STATUS=EXIT_EOF\n'
|
||||||
|
exit 0
|
||||||
|
elif [ "$duration_status" -ne 0 ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$SELECTED_SCENARIO" = "S03H3" ]; then
|
||||||
|
read_s03h3_profile
|
||||||
|
profile_status=$?
|
||||||
|
if [ "$profile_status" -eq 1 ]; then
|
||||||
|
printf '\nEOF prima dell esecuzione: azione annullata.\n'
|
||||||
|
printf 'LAUNCHER_EXECUTED=NO\n'
|
||||||
|
printf 'S03_H3_MENU_LIFECYCLE_STATUS=EXIT_EOF\n'
|
||||||
|
exit 0
|
||||||
|
elif [ "$profile_status" -ne 0 ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
confirm_execution
|
||||||
|
confirmation_status=$?
|
||||||
|
if [ "$confirmation_status" -eq 1 ]; then
|
||||||
|
printf '\nEOF prima della conferma: azione annullata.\n'
|
||||||
|
printf 'LAUNCHER_EXECUTED=NO\n'
|
||||||
|
printf 'S03_H3_MENU_LIFECYCLE_STATUS=EXIT_EOF\n'
|
||||||
|
exit 0
|
||||||
|
elif [ "$confirmation_status" -ne 0 ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf 'LAUNCHER_EXECUTED=YES\n'
|
||||||
|
invoke_selected_launcher
|
||||||
|
done
|
||||||
Executable
+149
@@ -0,0 +1,149 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
SUITE="/home/dariodf/Scrivania/MARTE/marte-benchmark-suite"
|
||||||
|
|
||||||
|
DEFAULT_SOURCE="$SUITE/configurations/generated/S00/smoke_s0_core.marte"
|
||||||
|
DEFAULT_OUTPUT="$SUITE/configurations/generated/S01/from_patcher/smoke_s1_timing_from_s00.marte"
|
||||||
|
|
||||||
|
SOURCE="${1:-$DEFAULT_SOURCE}"
|
||||||
|
OUTPUT="${2:-$DEFAULT_OUTPUT}"
|
||||||
|
|
||||||
|
EXPECTED_SOURCE_SHA256="49a9b48595aab88cd8fd11d1e58ace4ab11d7d0a649e9b143bdc25c8866253d5"
|
||||||
|
EXPECTED_OUTPUT_SHA256="1513e1ca72eba56d53079ac7328908f12ddc72772456e2d75bcbacb6465d2427"
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
code="$1"
|
||||||
|
shift
|
||||||
|
printf "ERRORE: %s\n" "$*" >&2
|
||||||
|
exit "$code"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ ! -f "$SOURCE" ]; then
|
||||||
|
fail 2 "configurazione sorgente non trovata: $SOURCE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
SOURCE_SHA256="$(sha256sum "$SOURCE" | awk '{print $1}')"
|
||||||
|
|
||||||
|
if [ "$SOURCE_SHA256" != "$EXPECTED_SOURCE_SHA256" ]; then
|
||||||
|
fail 3 "hash della configurazione sorgente non riconosciuto: $SOURCE_SHA256"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if grep -q 'State1_Thread1_CycleTime' "$SOURCE"; then
|
||||||
|
fail 4 "la configurazione sorgente contiene già il segnale S01"
|
||||||
|
fi
|
||||||
|
|
||||||
|
OUTPUT_DIR="$(dirname "$OUTPUT")"
|
||||||
|
mkdir -p "$OUTPUT_DIR"
|
||||||
|
|
||||||
|
if [ -e "$OUTPUT" ]; then
|
||||||
|
if [ ! -f "$OUTPUT" ]; then
|
||||||
|
fail 5 "il percorso di output esiste ma non è un file regolare: $OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
OUTPUT_SHA256="$(sha256sum "$OUTPUT" | awk '{print $1}')"
|
||||||
|
|
||||||
|
if [ "$OUTPUT_SHA256" = "$EXPECTED_OUTPUT_SHA256" ]; then
|
||||||
|
printf "RISULTATO GIÀ PRESENTE E CORRETTO\n"
|
||||||
|
printf "Output: %s\n" "$OUTPUT"
|
||||||
|
printf "SHA-256: %s\n" "$OUTPUT_SHA256"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
fail 6 "il file di output esiste ma ha un contenuto inatteso: $OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
TMP="${OUTPUT}.tmp.$$"
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
if [ -f "$TMP" ]; then
|
||||||
|
rm -f "$TMP"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
trap cleanup EXIT HUP INT TERM
|
||||||
|
|
||||||
|
set +e
|
||||||
|
awk '
|
||||||
|
BEGIN {
|
||||||
|
inGamDisplay = 0
|
||||||
|
inInputSignals = 0
|
||||||
|
inOutputSignals = 0
|
||||||
|
inputInsertions = 0
|
||||||
|
outputInsertions = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
if ($0 ~ /^ \+GAMDisplay[[:space:]]*=[[:space:]]*\{[[:space:]]*$/) {
|
||||||
|
inGamDisplay = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inGamDisplay &&
|
||||||
|
$0 ~ /^ InputSignals[[:space:]]*=[[:space:]]*\{[[:space:]]*$/) {
|
||||||
|
inInputSignals = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inGamDisplay &&
|
||||||
|
$0 ~ /^ OutputSignals[[:space:]]*=[[:space:]]*\{[[:space:]]*$/) {
|
||||||
|
inOutputSignals = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inInputSignals &&
|
||||||
|
$0 ~ /^ \}[[:space:]]*$/) {
|
||||||
|
print " State1_Thread1_CycleTime = {"
|
||||||
|
print " Alias = State1.Thread1_CycleTime"
|
||||||
|
print " DataSource = Timings"
|
||||||
|
print " Type = uint32"
|
||||||
|
print " }"
|
||||||
|
inputInsertions++
|
||||||
|
inInputSignals = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inOutputSignals &&
|
||||||
|
$0 ~ /^ \}[[:space:]]*$/) {
|
||||||
|
print " State1_Thread1_CycleTime = {"
|
||||||
|
print " DataSource = Display"
|
||||||
|
print " Type = uint32"
|
||||||
|
print " }"
|
||||||
|
print " } "
|
||||||
|
outputInsertions++
|
||||||
|
inOutputSignals = 0
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
print
|
||||||
|
|
||||||
|
if (inGamDisplay &&
|
||||||
|
$0 ~ /^ \}[[:space:]]*$/) {
|
||||||
|
inGamDisplay = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
END {
|
||||||
|
if (inputInsertions != 1 || outputInsertions != 1) {
|
||||||
|
exit 42
|
||||||
|
}
|
||||||
|
}
|
||||||
|
' "$SOURCE" > "$TMP"
|
||||||
|
|
||||||
|
AWK_RC=$?
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ "$AWK_RC" -ne 0 ]; then
|
||||||
|
fail 7 "trasformazione non applicata in modo univoco; codice awk: $AWK_RC"
|
||||||
|
fi
|
||||||
|
|
||||||
|
GENERATED_SHA256="$(sha256sum "$TMP" | awk '{print $1}')"
|
||||||
|
|
||||||
|
if [ "$GENERATED_SHA256" != "$EXPECTED_OUTPUT_SHA256" ]; then
|
||||||
|
fail 8 "output generato differente dalla S01 manuale: $GENERATED_SHA256"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mv "$TMP" "$OUTPUT"
|
||||||
|
trap - EXIT HUP INT TERM
|
||||||
|
|
||||||
|
printf "PATCH S00 -> S01 COMPLETATA\n"
|
||||||
|
printf "Sorgente: %s\n" "$SOURCE"
|
||||||
|
printf "Output: %s\n" "$OUTPUT"
|
||||||
|
printf "SHA-256 sorgente: %s\n" "$SOURCE_SHA256"
|
||||||
|
printf "SHA-256 output: %s\n" "$GENERATED_SHA256"
|
||||||
Executable
+224
@@ -0,0 +1,224 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -u
|
||||||
|
|
||||||
|
SUITE="/home/dariodf/Scrivania/MARTE/marte-benchmark-suite"
|
||||||
|
|
||||||
|
SOURCE_CONFIG="$SUITE/configurations/generated/S01/from_patcher/smoke_s1_timing_from_s00.marte"
|
||||||
|
OUTPUT_DIR="$SUITE/configurations/generated/S02/from_patcher"
|
||||||
|
OUTPUT_CONFIG="$OUTPUT_DIR/smoke_s2_binary_recording_from_s01.marte"
|
||||||
|
|
||||||
|
EXPECTED_SOURCE_SHA256="1513e1ca72eba56d53079ac7328908f12ddc72772456e2d75bcbacb6465d2427"
|
||||||
|
|
||||||
|
if [ ! -f "$SOURCE_CONFIG" ]; then
|
||||||
|
printf "SOURCE_STATUS=NOT_FOUND\n"
|
||||||
|
printf "SOURCE_CONFIG=%s\n" "$SOURCE_CONFIG"
|
||||||
|
exit 20
|
||||||
|
fi
|
||||||
|
|
||||||
|
ACTUAL_SOURCE_SHA256="$(sha256sum -- "$SOURCE_CONFIG" | awk '{print $1}')"
|
||||||
|
|
||||||
|
printf "SOURCE_CONFIG=%s\n" "$SOURCE_CONFIG"
|
||||||
|
printf "EXPECTED_SOURCE_SHA256=%s\n" "$EXPECTED_SOURCE_SHA256"
|
||||||
|
printf "ACTUAL_SOURCE_SHA256=%s\n" "$ACTUAL_SOURCE_SHA256"
|
||||||
|
|
||||||
|
if [ "$ACTUAL_SOURCE_SHA256" != "$EXPECTED_SOURCE_SHA256" ]; then
|
||||||
|
printf "SOURCE_HASH_STATUS=MISMATCH\n"
|
||||||
|
exit 21
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "SOURCE_HASH_STATUS=MATCH\n"
|
||||||
|
|
||||||
|
mkdir -p -- "$OUTPUT_DIR"
|
||||||
|
|
||||||
|
TEMP_CONFIG="$(mktemp "$OUTPUT_DIR/.s02_candidate_XXXXXX.marte")"
|
||||||
|
|
||||||
|
if [ -z "$TEMP_CONFIG" ]; then
|
||||||
|
printf "TEMPORARY_FILE_STATUS=FAIL\n"
|
||||||
|
exit 22
|
||||||
|
fi
|
||||||
|
|
||||||
|
trap 'rm -f -- "$TEMP_CONFIG"' EXIT
|
||||||
|
|
||||||
|
python3 - "$SOURCE_CONFIG" "$TEMP_CONFIG" <<'PY'
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
source = Path(sys.argv[1])
|
||||||
|
destination = Path(sys.argv[2])
|
||||||
|
|
||||||
|
text = source.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
for forbidden in (
|
||||||
|
"+IOGAM_Writer =",
|
||||||
|
"+FileWriter =",
|
||||||
|
"__MARTE_RUN_DIR__",
|
||||||
|
):
|
||||||
|
if forbidden in text:
|
||||||
|
print("SOURCE_ALREADY_CONTAINS_S02_CONTENT=" + forbidden)
|
||||||
|
sys.exit(30)
|
||||||
|
|
||||||
|
writer_gam = """ +IOGAM_Writer = {
|
||||||
|
Class = IOGAM
|
||||||
|
InputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
State1_Thread1_CycleTime = {
|
||||||
|
Alias = State1.Thread1_CycleTime
|
||||||
|
DataSource = Timings
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputSignals = {
|
||||||
|
Counter = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
State1_Thread1_CycleTime = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
file_writer = """ +FileWriter = {
|
||||||
|
Class = FileDataSource::FileWriter
|
||||||
|
NumberOfBuffers = 100
|
||||||
|
CPUMask = 0x1
|
||||||
|
StackSize = 10000000
|
||||||
|
Filename = "__MARTE_RUN_DIR__/s02_output.bin"
|
||||||
|
Overwrite = "yes"
|
||||||
|
FileFormat = "binary"
|
||||||
|
StoreOnTrigger = 0
|
||||||
|
RefreshContent = 0
|
||||||
|
Signals = {
|
||||||
|
Counter = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
Time = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
State1_Thread1_CycleTime = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
patched, functions_count = re.subn(
|
||||||
|
r"(?m)^ }\n \+Data = \{\n",
|
||||||
|
writer_gam + " }\n +Data = {\n",
|
||||||
|
text,
|
||||||
|
count=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
patched, data_count = re.subn(
|
||||||
|
r"(?m)^ }\n \+States = \{\n",
|
||||||
|
file_writer + " }\n +States = {\n",
|
||||||
|
patched,
|
||||||
|
count=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
patched, thread_count = re.subn(
|
||||||
|
r"Functions = \{GAMTimer GAMDisplay\}",
|
||||||
|
"Functions = {GAMTimer GAMDisplay IOGAM_Writer}",
|
||||||
|
patched,
|
||||||
|
count=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
print("FUNCTIONS_TRANSFORM_COUNT=" + str(functions_count))
|
||||||
|
print("DATA_TRANSFORM_COUNT=" + str(data_count))
|
||||||
|
print("THREAD_TRANSFORM_COUNT=" + str(thread_count))
|
||||||
|
|
||||||
|
if (functions_count, data_count, thread_count) != (1, 1, 1):
|
||||||
|
print("TRANSFORM_STATUS=FAIL")
|
||||||
|
sys.exit(31)
|
||||||
|
|
||||||
|
checks = {
|
||||||
|
"IOGAM_WRITER_COUNT": patched.count("+IOGAM_Writer ="),
|
||||||
|
"FILE_WRITER_COUNT": patched.count("+FileWriter ="),
|
||||||
|
"FILE_WRITER_CLASS_COUNT": patched.count("Class = FileDataSource::FileWriter"),
|
||||||
|
"PLAIN_FILE_WRITER_CLASS_COUNT": patched.count("Class = FileWriter"),
|
||||||
|
"FILEWRITER_OUTPUT_COUNT": patched.count("DataSource = FileWriter"),
|
||||||
|
"RUN_DIR_PLACEHOLDER_COUNT": patched.count("__MARTE_RUN_DIR__"),
|
||||||
|
"BINARY_FORMAT_COUNT": patched.count('FileFormat = "binary"'),
|
||||||
|
"OVERWRITE_YES_COUNT": patched.count('Overwrite = "yes"'),
|
||||||
|
"CONTINUOUS_MODE_COUNT": patched.count("StoreOnTrigger = 0"),
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, value in checks.items():
|
||||||
|
print(name + "=" + str(value))
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
"IOGAM_WRITER_COUNT": 1,
|
||||||
|
"FILE_WRITER_COUNT": 1,
|
||||||
|
"FILE_WRITER_CLASS_COUNT": 1,
|
||||||
|
"PLAIN_FILE_WRITER_CLASS_COUNT": 0,
|
||||||
|
"FILEWRITER_OUTPUT_COUNT": 3,
|
||||||
|
"RUN_DIR_PLACEHOLDER_COUNT": 1,
|
||||||
|
"BINARY_FORMAT_COUNT": 1,
|
||||||
|
"OVERWRITE_YES_COUNT": 1,
|
||||||
|
"CONTINUOUS_MODE_COUNT": 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
if checks != expected:
|
||||||
|
print("STRUCTURAL_CHECK_STATUS=FAIL")
|
||||||
|
sys.exit(32)
|
||||||
|
|
||||||
|
required_thread = "Functions = {GAMTimer GAMDisplay IOGAM_Writer}"
|
||||||
|
|
||||||
|
if patched.count(required_thread) != 1:
|
||||||
|
print("THREAD_FUNCTION_LIST_STATUS=FAIL")
|
||||||
|
sys.exit(33)
|
||||||
|
|
||||||
|
destination.write_text(patched, encoding="utf-8")
|
||||||
|
|
||||||
|
print("STRUCTURAL_CHECK_STATUS=PASS")
|
||||||
|
print("TRANSFORM_STATUS=PASS")
|
||||||
|
PY
|
||||||
|
|
||||||
|
PYTHON_RC=$?
|
||||||
|
|
||||||
|
if [ "$PYTHON_RC" -ne 0 ]; then
|
||||||
|
printf "PYTHON_TRANSFORM_EXIT_CODE=%s\n" "$PYTHON_RC"
|
||||||
|
exit 23
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$OUTPUT_CONFIG" ]; then
|
||||||
|
if cmp -s -- "$TEMP_CONFIG" "$OUTPUT_CONFIG"; then
|
||||||
|
printf "OUTPUT_STATUS=ALREADY_VALID\n"
|
||||||
|
printf "OUTPUT_CONFIG=%s\n" "$OUTPUT_CONFIG"
|
||||||
|
printf "OUTPUT_SHA256=%s\n" \
|
||||||
|
"$(sha256sum -- "$OUTPUT_CONFIG" | awk '{print $1}')"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "OUTPUT_STATUS=EXISTS_BUT_DIFFERS\n"
|
||||||
|
printf "OUTPUT_CONFIG=%s\n" "$OUTPUT_CONFIG"
|
||||||
|
exit 24
|
||||||
|
fi
|
||||||
|
|
||||||
|
chmod 0644 "$TEMP_CONFIG"
|
||||||
|
|
||||||
|
if ! mv -- "$TEMP_CONFIG" "$OUTPUT_CONFIG"; then
|
||||||
|
printf "OUTPUT_STATUS=PUBLISH_FAILED\n"
|
||||||
|
exit 25
|
||||||
|
fi
|
||||||
|
|
||||||
|
trap - EXIT
|
||||||
|
|
||||||
|
printf "OUTPUT_STATUS=CREATED\n"
|
||||||
|
printf "OUTPUT_CONFIG=%s\n" "$OUTPUT_CONFIG"
|
||||||
|
printf "OUTPUT_SHA256=%s\n" \
|
||||||
|
"$(sha256sum -- "$OUTPUT_CONFIG" | awk '{print $1}')"
|
||||||
Executable
+317
@@ -0,0 +1,317 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -u
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(
|
||||||
|
cd "$(dirname "${BASH_SOURCE[0]}")" &&
|
||||||
|
pwd
|
||||||
|
)"
|
||||||
|
SUITE="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||||
|
|
||||||
|
DEFAULT_SOURCE="$SUITE/configurations/generated/S02/from_patcher/smoke_s2_binary_recording_from_s01.marte"
|
||||||
|
DEFAULT_OUTPUT="$SUITE/configurations/generated/S03/from_patcher/smoke_s3_semantic_sentinels_from_s02.marte"
|
||||||
|
|
||||||
|
SOURCE_CONFIG="${1:-$DEFAULT_SOURCE}"
|
||||||
|
OUTPUT_CONFIG="${2:-$DEFAULT_OUTPUT}"
|
||||||
|
|
||||||
|
EXPECTED_SOURCE_SHA256="8ecc8ba55e46e9f6fb8f304404d4070ff4c2ea5b9c783a69113bc08b457859d1"
|
||||||
|
EXPECTED_OUTPUT_SHA256="0f8916735ff67a9be2b167b52f147687fe131a063f410a81bfbf3bf9ff65f1e4"
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
code="$1"
|
||||||
|
shift
|
||||||
|
printf "S03_BUILD_STATUS=FAIL\n" >&2
|
||||||
|
printf "S03_BUILD_ERROR=%s\n" "$*" >&2
|
||||||
|
exit "$code"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ ! -f "$SOURCE_CONFIG" ]; then
|
||||||
|
fail 20 "SOURCE_NOT_FOUND:$SOURCE_CONFIG"
|
||||||
|
fi
|
||||||
|
|
||||||
|
SOURCE_SHA256="$(sha256sum -- "$SOURCE_CONFIG" | awk '{print $1}')"
|
||||||
|
|
||||||
|
printf "SOURCE_CONFIG=%s\n" "$SOURCE_CONFIG"
|
||||||
|
printf "EXPECTED_SOURCE_SHA256=%s\n" "$EXPECTED_SOURCE_SHA256"
|
||||||
|
printf "ACTUAL_SOURCE_SHA256=%s\n" "$SOURCE_SHA256"
|
||||||
|
|
||||||
|
if [ "$SOURCE_SHA256" != "$EXPECTED_SOURCE_SHA256" ]; then
|
||||||
|
fail 21 "SOURCE_HASH_MISMATCH:$SOURCE_SHA256"
|
||||||
|
fi
|
||||||
|
|
||||||
|
OUTPUT_DIR="$(dirname "$OUTPUT_CONFIG")"
|
||||||
|
if ! mkdir -p -- "$OUTPUT_DIR"; then
|
||||||
|
fail 22 "OUTPUT_DIRECTORY_CREATE_FAILED:$OUTPUT_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -e "$OUTPUT_CONFIG" ] && [ ! -f "$OUTPUT_CONFIG" ]; then
|
||||||
|
fail 23 "OUTPUT_EXISTS_NOT_REGULAR_FILE:$OUTPUT_CONFIG"
|
||||||
|
fi
|
||||||
|
|
||||||
|
TEMP_CONFIG="$(mktemp "$OUTPUT_DIR/.s03_candidate_XXXXXX.marte")" ||
|
||||||
|
fail 24 "TEMPORARY_FILE_CREATE_FAILED:$OUTPUT_DIR"
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
rm -f -- "$TEMP_CONFIG"
|
||||||
|
}
|
||||||
|
trap cleanup EXIT HUP INT TERM
|
||||||
|
|
||||||
|
PYTHONHASHSEED=0 python3 - "$SOURCE_CONFIG" "$TEMP_CONFIG" <<'PY_S03_PATCHER'
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
source = Path(sys.argv[1])
|
||||||
|
destination = Path(sys.argv[2])
|
||||||
|
text = source.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def require_count(haystack, needle, expected, label):
|
||||||
|
observed = haystack.count(needle)
|
||||||
|
print(f"{label}_COUNT={observed}")
|
||||||
|
if observed != expected:
|
||||||
|
raise RuntimeError(f"{label}_COUNT_EXPECTED_{expected}_OBSERVED_{observed}")
|
||||||
|
|
||||||
|
|
||||||
|
def replace_once(haystack, old, new, label):
|
||||||
|
require_count(haystack, old, 1, label)
|
||||||
|
return haystack.replace(old, new, 1)
|
||||||
|
|
||||||
|
|
||||||
|
for forbidden in (
|
||||||
|
"+SentinelProducer =",
|
||||||
|
"SentinelScalarA",
|
||||||
|
"SentinelScalarB",
|
||||||
|
"SentinelVector",
|
||||||
|
"s03_output.bin",
|
||||||
|
):
|
||||||
|
if forbidden in text:
|
||||||
|
raise RuntimeError("SOURCE_ALREADY_CONTAINS_S03_CONTENT:" + forbidden)
|
||||||
|
|
||||||
|
constant_gam = """ +SentinelProducer = {
|
||||||
|
Class = ConstantGAM
|
||||||
|
OutputSignals = {
|
||||||
|
SentinelScalarA = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
Default = 324508639
|
||||||
|
}
|
||||||
|
SentinelScalarB = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
Default = 610839776
|
||||||
|
}
|
||||||
|
SentinelVector = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfDimensions = 1
|
||||||
|
NumberOfElements = 3
|
||||||
|
Default = {16909060 286397204 555885348}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
sentinel_signals = """ SentinelScalarA = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelScalarB = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelVector = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfDimensions = 1
|
||||||
|
NumberOfElements = 3
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
filewriter_signals = """ SentinelScalarA = {
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelScalarB = {
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelVector = {
|
||||||
|
Type = uint32
|
||||||
|
NumberOfDimensions = 1
|
||||||
|
NumberOfElements = 3
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
text = replace_once(
|
||||||
|
text,
|
||||||
|
" +GAMDisplay = {\n",
|
||||||
|
constant_gam + " +GAMDisplay = {\n",
|
||||||
|
"SENTINEL_PRODUCER_ANCHOR",
|
||||||
|
)
|
||||||
|
|
||||||
|
writer_start = text.index(" +IOGAM_Writer = {\n")
|
||||||
|
writer_end = text.index(" }\n +Data = {\n", writer_start)
|
||||||
|
writer = text[writer_start:writer_end]
|
||||||
|
|
||||||
|
writer = replace_once(
|
||||||
|
writer,
|
||||||
|
""" State1_Thread1_CycleTime = {
|
||||||
|
Alias = State1.Thread1_CycleTime
|
||||||
|
DataSource = Timings
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputSignals = {
|
||||||
|
""",
|
||||||
|
""" State1_Thread1_CycleTime = {
|
||||||
|
Alias = State1.Thread1_CycleTime
|
||||||
|
DataSource = Timings
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
""" + sentinel_signals + """ }
|
||||||
|
OutputSignals = {
|
||||||
|
""",
|
||||||
|
"WRITER_INPUT_ANCHOR",
|
||||||
|
)
|
||||||
|
|
||||||
|
writer_output_signals = sentinel_signals.replace("DataSource = DDB1", "DataSource = FileWriter")
|
||||||
|
writer = replace_once(
|
||||||
|
writer,
|
||||||
|
""" State1_Thread1_CycleTime = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
""" State1_Thread1_CycleTime = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
""" + writer_output_signals + """ }
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"WRITER_OUTPUT_ANCHOR",
|
||||||
|
)
|
||||||
|
|
||||||
|
text = text[:writer_start] + writer + text[writer_end:]
|
||||||
|
|
||||||
|
filewriter_start = text.index(" +FileWriter = {\n")
|
||||||
|
filewriter_end = text.index(" }\n +States = {\n", filewriter_start)
|
||||||
|
filewriter = text[filewriter_start:filewriter_end]
|
||||||
|
|
||||||
|
filewriter = replace_once(
|
||||||
|
filewriter,
|
||||||
|
' Filename = "__MARTE_RUN_DIR__/s02_output.bin"\n',
|
||||||
|
' Filename = "__MARTE_RUN_DIR__/s03_output.bin"\n',
|
||||||
|
"OUTPUT_FILENAME_ANCHOR",
|
||||||
|
)
|
||||||
|
|
||||||
|
filewriter = replace_once(
|
||||||
|
filewriter,
|
||||||
|
""" State1_Thread1_CycleTime = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
""" State1_Thread1_CycleTime = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
""" + filewriter_signals + """ }
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"FILEWRITER_SIGNAL_ANCHOR",
|
||||||
|
)
|
||||||
|
|
||||||
|
text = text[:filewriter_start] + filewriter + text[filewriter_end:]
|
||||||
|
|
||||||
|
text = replace_once(
|
||||||
|
text,
|
||||||
|
"Functions = {GAMTimer GAMDisplay IOGAM_Writer}",
|
||||||
|
"Functions = {GAMTimer SentinelProducer GAMDisplay IOGAM_Writer}",
|
||||||
|
"THREAD_FUNCTION_LIST_ANCHOR",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Canonicalise the historical trailing blank line so the generated candidate
|
||||||
|
# is byte-stable across copies and archive extraction tools.
|
||||||
|
text = text.rstrip("\n") + "\n"
|
||||||
|
|
||||||
|
checks = {
|
||||||
|
"SENTINEL_PRODUCER": text.count("+SentinelProducer ="),
|
||||||
|
"CONSTANT_GAM_CLASS": text.count("Class = ConstantGAM"),
|
||||||
|
"SENTINEL_SCALAR_A_DECLARATIONS": text.count("SentinelScalarA ="),
|
||||||
|
"SENTINEL_SCALAR_B_DECLARATIONS": text.count("SentinelScalarB ="),
|
||||||
|
"SENTINEL_VECTOR_DECLARATIONS": text.count("SentinelVector ="),
|
||||||
|
"VECTOR_DIMENSION_DECLARATIONS": text.count("NumberOfDimensions = 1"),
|
||||||
|
"VECTOR_CARDINALITY_DECLARATIONS": text.count("NumberOfElements = 3"),
|
||||||
|
"S03_OUTPUT_FILENAME": text.count("__MARTE_RUN_DIR__/s03_output.bin"),
|
||||||
|
"S02_OUTPUT_FILENAME": text.count("s02_output.bin"),
|
||||||
|
"RUN_DIR_PLACEHOLDER": text.count("__MARTE_RUN_DIR__"),
|
||||||
|
"FILEWRITER_CLASS": text.count("Class = FileDataSource::FileWriter"),
|
||||||
|
"THREAD_FUNCTION_LIST": text.count(
|
||||||
|
"Functions = {GAMTimer SentinelProducer GAMDisplay IOGAM_Writer}"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
"SENTINEL_PRODUCER": 1,
|
||||||
|
"CONSTANT_GAM_CLASS": 1,
|
||||||
|
"SENTINEL_SCALAR_A_DECLARATIONS": 4,
|
||||||
|
"SENTINEL_SCALAR_B_DECLARATIONS": 4,
|
||||||
|
"SENTINEL_VECTOR_DECLARATIONS": 4,
|
||||||
|
"VECTOR_DIMENSION_DECLARATIONS": 4,
|
||||||
|
"VECTOR_CARDINALITY_DECLARATIONS": 4,
|
||||||
|
"S03_OUTPUT_FILENAME": 1,
|
||||||
|
"S02_OUTPUT_FILENAME": 0,
|
||||||
|
"RUN_DIR_PLACEHOLDER": 1,
|
||||||
|
"FILEWRITER_CLASS": 1,
|
||||||
|
"THREAD_FUNCTION_LIST": 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
for name in sorted(checks):
|
||||||
|
print(f"{name}_COUNT={checks[name]}")
|
||||||
|
|
||||||
|
if checks != expected:
|
||||||
|
raise RuntimeError(f"STRUCTURAL_CHECK_MISMATCH:{checks!r}")
|
||||||
|
|
||||||
|
destination.write_text(text, encoding="utf-8")
|
||||||
|
print("TRANSFORM_STATUS=PASS")
|
||||||
|
print("STRUCTURAL_CHECK_STATUS=PASS")
|
||||||
|
PY_S03_PATCHER
|
||||||
|
|
||||||
|
PYTHON_RC=$?
|
||||||
|
if [ "$PYTHON_RC" -ne 0 ]; then
|
||||||
|
fail 25 "TRANSFORM_FAILED_RC_$PYTHON_RC"
|
||||||
|
fi
|
||||||
|
|
||||||
|
GENERATED_SHA256="$(sha256sum -- "$TEMP_CONFIG" | awk '{print $1}')"
|
||||||
|
printf "GENERATED_SHA256=%s\n" "$GENERATED_SHA256"
|
||||||
|
|
||||||
|
if [ "$GENERATED_SHA256" != "$EXPECTED_OUTPUT_SHA256" ]; then
|
||||||
|
fail 26 "OUTPUT_HASH_MISMATCH:$GENERATED_SHA256"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$OUTPUT_CONFIG" ]; then
|
||||||
|
if cmp -s -- "$TEMP_CONFIG" "$OUTPUT_CONFIG"; then
|
||||||
|
printf "S03_BUILD_STATUS=ALREADY_VALID\n"
|
||||||
|
printf "OUTPUT_CONFIG=%s\n" "$OUTPUT_CONFIG"
|
||||||
|
printf "OUTPUT_SHA256=%s\n" "$GENERATED_SHA256"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fail 27 "OUTPUT_EXISTS_BUT_DIFFERS:$OUTPUT_CONFIG"
|
||||||
|
fi
|
||||||
|
|
||||||
|
chmod 0644 "$TEMP_CONFIG" || fail 28 "OUTPUT_CHMOD_FAILED:$TEMP_CONFIG"
|
||||||
|
if ! mv -- "$TEMP_CONFIG" "$OUTPUT_CONFIG"; then
|
||||||
|
fail 29 "ATOMIC_PUBLISH_FAILED:$OUTPUT_CONFIG"
|
||||||
|
fi
|
||||||
|
trap - EXIT HUP INT TERM
|
||||||
|
|
||||||
|
printf "S03_BUILD_STATUS=CREATED\n"
|
||||||
|
printf "OUTPUT_CONFIG=%s\n" "$OUTPUT_CONFIG"
|
||||||
|
printf "OUTPUT_SHA256=%s\n" "$GENERATED_SHA256"
|
||||||
+458
@@ -0,0 +1,458 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -u
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(
|
||||||
|
cd "$(dirname "${BASH_SOURCE[0]}")" &&
|
||||||
|
pwd
|
||||||
|
)"
|
||||||
|
PACKAGE_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||||
|
|
||||||
|
DEFAULT_SOURCE="$PACKAGE_ROOT/baseline/smoke_s2_binary_recording_from_s01.marte"
|
||||||
|
DEFAULT_OUTPUT_ROOT="$PACKAGE_ROOT/configurations/generated/S03H1/from_patcher"
|
||||||
|
|
||||||
|
EXPECTED_SOURCE_SHA256="8ecc8ba55e46e9f6fb8f304404d4070ff4c2ea5b9c783a69113bc08b457859d1"
|
||||||
|
EXPECTED_TEST_SHA256="d037561b32760fbd0e2aec9f1eefc5efda27b1918eca4742c89092a8a2f7e92e"
|
||||||
|
EXPECTED_DIAGNOSTIC_SHA256="cd999ff249452298d650a22c8fe5b0b03bf48c0735f4630befdec8209cbb13a3"
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
code="$1"
|
||||||
|
shift
|
||||||
|
printf "S03_H1_BUILD_STATUS=FAIL\n" >&2
|
||||||
|
printf "S03_H1_BUILD_ERROR=%s\n" "$*" >&2
|
||||||
|
exit "$code"
|
||||||
|
}
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
printf "Uso:\n" >&2
|
||||||
|
printf " %s TEST|DIAGNOSTIC\n" "$0" >&2
|
||||||
|
printf " %s <source-S02> <output-config> TEST|DIAGNOSTIC\n" "$0" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$#" in
|
||||||
|
1)
|
||||||
|
SOURCE_CONFIG="$DEFAULT_SOURCE"
|
||||||
|
MODE="$1"
|
||||||
|
case "$MODE" in
|
||||||
|
TEST)
|
||||||
|
OUTPUT_CONFIG="$DEFAULT_OUTPUT_ROOT/smoke_s03h1_execution_profiles_test_from_s02.marte"
|
||||||
|
;;
|
||||||
|
DIAGNOSTIC)
|
||||||
|
OUTPUT_CONFIG="$DEFAULT_OUTPUT_ROOT/smoke_s03h1_execution_profiles_diagnostic_from_s02.marte"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
usage
|
||||||
|
fail 20 "UNKNOWN_MODE:$MODE"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
3)
|
||||||
|
SOURCE_CONFIG="$1"
|
||||||
|
OUTPUT_CONFIG="$2"
|
||||||
|
MODE="$3"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
usage
|
||||||
|
fail 20 "INVALID_ARGUMENT_COUNT:$#"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "$MODE" in
|
||||||
|
TEST)
|
||||||
|
EXPECTED_OUTPUT_SHA256="$EXPECTED_TEST_SHA256"
|
||||||
|
DISPLAY_CLASS="GAMDataSource"
|
||||||
|
;;
|
||||||
|
DIAGNOSTIC)
|
||||||
|
EXPECTED_OUTPUT_SHA256="$EXPECTED_DIAGNOSTIC_SHA256"
|
||||||
|
DISPLAY_CLASS="LoggerDataSource"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
usage
|
||||||
|
fail 20 "UNKNOWN_MODE:$MODE"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ ! -f "$SOURCE_CONFIG" ]; then
|
||||||
|
fail 21 "SOURCE_NOT_FOUND:$SOURCE_CONFIG"
|
||||||
|
fi
|
||||||
|
|
||||||
|
SOURCE_SHA256="$(sha256sum -- "$SOURCE_CONFIG" | awk '{print $1}')"
|
||||||
|
printf "MODE=%s\n" "$MODE"
|
||||||
|
printf "SOURCE_CONFIG=%s\n" "$SOURCE_CONFIG"
|
||||||
|
printf "EXPECTED_SOURCE_SHA256=%s\n" "$EXPECTED_SOURCE_SHA256"
|
||||||
|
printf "ACTUAL_SOURCE_SHA256=%s\n" "$SOURCE_SHA256"
|
||||||
|
|
||||||
|
if [ "$SOURCE_SHA256" != "$EXPECTED_SOURCE_SHA256" ]; then
|
||||||
|
fail 22 "SOURCE_HASH_MISMATCH:$SOURCE_SHA256"
|
||||||
|
fi
|
||||||
|
|
||||||
|
OUTPUT_DIR="$(dirname "$OUTPUT_CONFIG")"
|
||||||
|
if ! mkdir -p -- "$OUTPUT_DIR"; then
|
||||||
|
fail 23 "OUTPUT_DIRECTORY_CREATE_FAILED:$OUTPUT_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -e "$OUTPUT_CONFIG" ] && [ ! -f "$OUTPUT_CONFIG" ]; then
|
||||||
|
fail 24 "OUTPUT_EXISTS_NOT_REGULAR_FILE:$OUTPUT_CONFIG"
|
||||||
|
fi
|
||||||
|
|
||||||
|
TEMP_CONFIG="$(mktemp "$OUTPUT_DIR/.s03h1_candidate_XXXXXX.marte")" ||
|
||||||
|
fail 25 "TEMPORARY_FILE_CREATE_FAILED:$OUTPUT_DIR"
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
rm -f -- "$TEMP_CONFIG"
|
||||||
|
}
|
||||||
|
trap cleanup EXIT HUP INT TERM
|
||||||
|
|
||||||
|
PYTHONHASHSEED=0 python3 - \
|
||||||
|
"$SOURCE_CONFIG" \
|
||||||
|
"$TEMP_CONFIG" \
|
||||||
|
"$MODE" \
|
||||||
|
"$DISPLAY_CLASS" <<'PY_S03H1_PATCHER'
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
source = Path(sys.argv[1])
|
||||||
|
destination = Path(sys.argv[2])
|
||||||
|
mode = sys.argv[3]
|
||||||
|
display_class = sys.argv[4]
|
||||||
|
text = source.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def require_count(haystack, needle, expected, label):
|
||||||
|
observed = haystack.count(needle)
|
||||||
|
print(f"{label}_COUNT={observed}")
|
||||||
|
if observed != expected:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"{label}_COUNT_EXPECTED_{expected}_OBSERVED_{observed}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def replace_once(haystack, old, new, label):
|
||||||
|
require_count(haystack, old, 1, label)
|
||||||
|
return haystack.replace(old, new, 1)
|
||||||
|
|
||||||
|
|
||||||
|
for forbidden in (
|
||||||
|
"+SentinelProducer =",
|
||||||
|
"SentinelScalarA",
|
||||||
|
"SentinelScalarB",
|
||||||
|
"SentinelVector",
|
||||||
|
"s03_output.bin",
|
||||||
|
):
|
||||||
|
if forbidden in text:
|
||||||
|
raise RuntimeError("SOURCE_ALREADY_CONTAINS_S03_CONTENT:" + forbidden)
|
||||||
|
|
||||||
|
if mode not in {"TEST", "DIAGNOSTIC"}:
|
||||||
|
raise RuntimeError("UNKNOWN_MODE:" + mode)
|
||||||
|
if display_class not in {"GAMDataSource", "LoggerDataSource"}:
|
||||||
|
raise RuntimeError("UNKNOWN_DISPLAY_CLASS:" + display_class)
|
||||||
|
|
||||||
|
constant_gam = """ +SentinelProducer = {
|
||||||
|
Class = ConstantGAM
|
||||||
|
OutputSignals = {
|
||||||
|
SentinelScalarA = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
Default = 324508639
|
||||||
|
}
|
||||||
|
SentinelScalarB = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
Default = 610839776
|
||||||
|
}
|
||||||
|
SentinelVector = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfDimensions = 1
|
||||||
|
NumberOfElements = 3
|
||||||
|
Default = {16909060 286397204 555885348}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
gam_display = f""" +GAMDisplay = {{
|
||||||
|
Class = IOGAM
|
||||||
|
InputSignals = {{
|
||||||
|
Counter = {{
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}}
|
||||||
|
Time = {{
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
}}
|
||||||
|
State1_Thread1_CycleTime = {{
|
||||||
|
Alias = State1.Thread1_CycleTime
|
||||||
|
DataSource = Timings
|
||||||
|
Type = uint32
|
||||||
|
}}
|
||||||
|
SentinelScalarA = {{
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}}
|
||||||
|
SentinelScalarB = {{
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}}
|
||||||
|
SentinelVector = {{
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfDimensions = 1
|
||||||
|
NumberOfElements = 3
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
OutputSignals = {{
|
||||||
|
Counter = {{
|
||||||
|
DataSource = Display
|
||||||
|
Type = uint32
|
||||||
|
}}
|
||||||
|
Time = {{
|
||||||
|
DataSource = Display
|
||||||
|
Type = uint32
|
||||||
|
}}
|
||||||
|
State1_Thread1_CycleTime = {{
|
||||||
|
DataSource = Display
|
||||||
|
Type = uint32
|
||||||
|
}}
|
||||||
|
SentinelScalarA = {{
|
||||||
|
DataSource = Display
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}}
|
||||||
|
SentinelScalarB = {{
|
||||||
|
DataSource = Display
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}}
|
||||||
|
SentinelVector = {{
|
||||||
|
DataSource = Display
|
||||||
|
Type = uint32
|
||||||
|
NumberOfDimensions = 1
|
||||||
|
NumberOfElements = 3
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
"""
|
||||||
|
|
||||||
|
sentinel_signals = """ SentinelScalarA = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelScalarB = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelVector = {
|
||||||
|
DataSource = DDB1
|
||||||
|
Type = uint32
|
||||||
|
NumberOfDimensions = 1
|
||||||
|
NumberOfElements = 3
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
filewriter_signals = """ SentinelScalarA = {
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelScalarB = {
|
||||||
|
Type = uint32
|
||||||
|
NumberOfElements = 1
|
||||||
|
}
|
||||||
|
SentinelVector = {
|
||||||
|
Type = uint32
|
||||||
|
NumberOfDimensions = 1
|
||||||
|
NumberOfElements = 3
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
require_count(text, " +GAMDisplay = {\n", 1, "GAMDISPLAY_START_ANCHOR")
|
||||||
|
require_count(text, " +IOGAM_Writer = {\n", 1, "IOGAM_WRITER_START_ANCHOR")
|
||||||
|
display_start = text.index(" +GAMDisplay = {\n")
|
||||||
|
writer_start = text.index(" +IOGAM_Writer = {\n", display_start)
|
||||||
|
text = text[:display_start] + constant_gam + gam_display + text[writer_start:]
|
||||||
|
|
||||||
|
writer_start = text.index(" +IOGAM_Writer = {\n")
|
||||||
|
writer_end = text.index(" }\n +Data = {\n", writer_start)
|
||||||
|
writer = text[writer_start:writer_end]
|
||||||
|
|
||||||
|
writer = replace_once(
|
||||||
|
writer,
|
||||||
|
""" State1_Thread1_CycleTime = {
|
||||||
|
Alias = State1.Thread1_CycleTime
|
||||||
|
DataSource = Timings
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputSignals = {
|
||||||
|
""",
|
||||||
|
""" State1_Thread1_CycleTime = {
|
||||||
|
Alias = State1.Thread1_CycleTime
|
||||||
|
DataSource = Timings
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
""" + sentinel_signals + """ }
|
||||||
|
OutputSignals = {
|
||||||
|
""",
|
||||||
|
"WRITER_INPUT_ANCHOR",
|
||||||
|
)
|
||||||
|
|
||||||
|
writer_output_signals = sentinel_signals.replace(
|
||||||
|
"DataSource = DDB1", "DataSource = FileWriter"
|
||||||
|
)
|
||||||
|
writer = replace_once(
|
||||||
|
writer,
|
||||||
|
""" State1_Thread1_CycleTime = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
""" State1_Thread1_CycleTime = {
|
||||||
|
DataSource = FileWriter
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
""" + writer_output_signals + """ }
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"WRITER_OUTPUT_ANCHOR",
|
||||||
|
)
|
||||||
|
text = text[:writer_start] + writer + text[writer_end:]
|
||||||
|
|
||||||
|
text = replace_once(
|
||||||
|
text,
|
||||||
|
""" +Display = {
|
||||||
|
Class = LoggerDataSource
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
f""" +Display = {{
|
||||||
|
Class = {display_class}
|
||||||
|
}}
|
||||||
|
""",
|
||||||
|
"DISPLAY_DATASOURCE_ANCHOR",
|
||||||
|
)
|
||||||
|
|
||||||
|
filewriter_start = text.index(" +FileWriter = {\n")
|
||||||
|
filewriter_end = text.index(" }\n +States = {\n", filewriter_start)
|
||||||
|
filewriter = text[filewriter_start:filewriter_end]
|
||||||
|
filewriter = replace_once(
|
||||||
|
filewriter,
|
||||||
|
' Filename = "__MARTE_RUN_DIR__/s02_output.bin"\n',
|
||||||
|
' Filename = "__MARTE_RUN_DIR__/s03_output.bin"\n',
|
||||||
|
"OUTPUT_FILENAME_ANCHOR",
|
||||||
|
)
|
||||||
|
filewriter = replace_once(
|
||||||
|
filewriter,
|
||||||
|
""" State1_Thread1_CycleTime = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
""" State1_Thread1_CycleTime = {
|
||||||
|
Type = uint32
|
||||||
|
}
|
||||||
|
""" + filewriter_signals + """ }
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"FILEWRITER_SIGNAL_ANCHOR",
|
||||||
|
)
|
||||||
|
text = text[:filewriter_start] + filewriter + text[filewriter_end:]
|
||||||
|
|
||||||
|
text = replace_once(
|
||||||
|
text,
|
||||||
|
"Functions = {GAMTimer GAMDisplay IOGAM_Writer}",
|
||||||
|
"Functions = {GAMTimer SentinelProducer GAMDisplay IOGAM_Writer}",
|
||||||
|
"THREAD_FUNCTION_LIST_ANCHOR",
|
||||||
|
)
|
||||||
|
|
||||||
|
text = text.rstrip("\n") + "\n"
|
||||||
|
|
||||||
|
checks = {
|
||||||
|
"SENTINEL_PRODUCER": text.count("+SentinelProducer ="),
|
||||||
|
"CONSTANT_GAM_CLASS": text.count("Class = ConstantGAM"),
|
||||||
|
"GAMDISPLAY_OBJECT": text.count("+GAMDisplay ="),
|
||||||
|
"SENTINEL_SCALAR_A_DECLARATIONS": text.count("SentinelScalarA ="),
|
||||||
|
"SENTINEL_SCALAR_B_DECLARATIONS": text.count("SentinelScalarB ="),
|
||||||
|
"SENTINEL_VECTOR_DECLARATIONS": text.count("SentinelVector ="),
|
||||||
|
"VECTOR_DIMENSION_DECLARATIONS": text.count("NumberOfDimensions = 1"),
|
||||||
|
"VECTOR_CARDINALITY_DECLARATIONS": text.count("NumberOfElements = 3"),
|
||||||
|
"S03_OUTPUT_FILENAME": text.count("__MARTE_RUN_DIR__/s03_output.bin"),
|
||||||
|
"S02_OUTPUT_FILENAME": text.count("s02_output.bin"),
|
||||||
|
"RUN_DIR_PLACEHOLDER": text.count("__MARTE_RUN_DIR__"),
|
||||||
|
"FILEWRITER_CLASS": text.count("Class = FileDataSource::FileWriter"),
|
||||||
|
"THREAD_FUNCTION_LIST": text.count(
|
||||||
|
"Functions = {GAMTimer SentinelProducer GAMDisplay IOGAM_Writer}"
|
||||||
|
),
|
||||||
|
"DISPLAY_DATASOURCE_BLOCK": text.count(
|
||||||
|
f" +Display = {{\n Class = {display_class}\n }}\n"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
expected = {
|
||||||
|
"SENTINEL_PRODUCER": 1,
|
||||||
|
"CONSTANT_GAM_CLASS": 1,
|
||||||
|
"GAMDISPLAY_OBJECT": 1,
|
||||||
|
"SENTINEL_SCALAR_A_DECLARATIONS": 6,
|
||||||
|
"SENTINEL_SCALAR_B_DECLARATIONS": 6,
|
||||||
|
"SENTINEL_VECTOR_DECLARATIONS": 6,
|
||||||
|
"VECTOR_DIMENSION_DECLARATIONS": 6,
|
||||||
|
"VECTOR_CARDINALITY_DECLARATIONS": 6,
|
||||||
|
"S03_OUTPUT_FILENAME": 1,
|
||||||
|
"S02_OUTPUT_FILENAME": 0,
|
||||||
|
"RUN_DIR_PLACEHOLDER": 1,
|
||||||
|
"FILEWRITER_CLASS": 1,
|
||||||
|
"THREAD_FUNCTION_LIST": 1,
|
||||||
|
"DISPLAY_DATASOURCE_BLOCK": 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
for name in sorted(checks):
|
||||||
|
print(f"{name}_COUNT={checks[name]}")
|
||||||
|
if checks != expected:
|
||||||
|
raise RuntimeError(f"STRUCTURAL_CHECK_MISMATCH:{checks!r}")
|
||||||
|
|
||||||
|
destination.write_text(text, encoding="utf-8")
|
||||||
|
print("TRANSFORM_STATUS=PASS")
|
||||||
|
print("STRUCTURAL_CHECK_STATUS=PASS")
|
||||||
|
PY_S03H1_PATCHER
|
||||||
|
PYTHON_RC=$?
|
||||||
|
|
||||||
|
if [ "$PYTHON_RC" -ne 0 ]; then
|
||||||
|
fail 26 "TRANSFORM_FAILED_RC_$PYTHON_RC"
|
||||||
|
fi
|
||||||
|
|
||||||
|
GENERATED_SHA256="$(sha256sum -- "$TEMP_CONFIG" | awk '{print $1}')"
|
||||||
|
printf "GENERATED_SHA256=%s\n" "$GENERATED_SHA256"
|
||||||
|
printf "EXPECTED_OUTPUT_SHA256=%s\n" "$EXPECTED_OUTPUT_SHA256"
|
||||||
|
|
||||||
|
if [ "$GENERATED_SHA256" != "$EXPECTED_OUTPUT_SHA256" ]; then
|
||||||
|
fail 27 "OUTPUT_HASH_MISMATCH:$GENERATED_SHA256"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$OUTPUT_CONFIG" ]; then
|
||||||
|
if cmp -s -- "$TEMP_CONFIG" "$OUTPUT_CONFIG"; then
|
||||||
|
printf "S03_H1_BUILD_STATUS=ALREADY_VALID\n"
|
||||||
|
printf "MODE=%s\n" "$MODE"
|
||||||
|
printf "OUTPUT_CONFIG=%s\n" "$OUTPUT_CONFIG"
|
||||||
|
printf "OUTPUT_SHA256=%s\n" "$GENERATED_SHA256"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fail 28 "OUTPUT_EXISTS_BUT_DIFFERS:$OUTPUT_CONFIG"
|
||||||
|
fi
|
||||||
|
|
||||||
|
chmod 0644 "$TEMP_CONFIG" || fail 29 "OUTPUT_CHMOD_FAILED:$TEMP_CONFIG"
|
||||||
|
if ! mv -- "$TEMP_CONFIG" "$OUTPUT_CONFIG"; then
|
||||||
|
fail 30 "ATOMIC_PUBLISH_FAILED:$OUTPUT_CONFIG"
|
||||||
|
fi
|
||||||
|
trap - EXIT HUP INT TERM
|
||||||
|
|
||||||
|
printf "S03_H1_BUILD_STATUS=CREATED\n"
|
||||||
|
printf "MODE=%s\n" "$MODE"
|
||||||
|
printf "OUTPUT_CONFIG=%s\n" "$OUTPUT_CONFIG"
|
||||||
|
printf "OUTPUT_SHA256=%s\n" "$GENERATED_SHA256"
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -u
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
PATCHER_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
|
||||||
|
SUITE="$(cd -- "$PATCHER_DIR/../.." && pwd -P)"
|
||||||
|
|
||||||
|
PARENT="$SUITE/configurations/generated/S03H1/from_patcher/smoke_s03h1_execution_profiles_test_from_s02.marte"
|
||||||
|
OUTPUT_DIR="$SUITE/configurations/generated/S03H3/from_patcher"
|
||||||
|
OUTPUT="$OUTPUT_DIR/smoke_s03h3_execution_profiles_minimal_from_s03h1_test.marte"
|
||||||
|
VERIFIER="$SUITE/scenarios/S03H3_execution_profiles/verify_s03h3_minimal_structure.py"
|
||||||
|
EXPECTED_PARENT_SHA256="d037561b32760fbd0e2aec9f1eefc5efda27b1918eca4742c89092a8a2f7e92e"
|
||||||
|
|
||||||
|
TEMP_OUTPUT=""
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
if [ -n "$TEMP_OUTPUT" ]; then
|
||||||
|
rm -f -- "$TEMP_OUTPUT"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
trap cleanup EXIT HUP INT TERM
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
local code="$1"
|
||||||
|
local reason="$2"
|
||||||
|
printf 'PATCHER_STATUS=FAIL\n' >&2
|
||||||
|
printf 'PATCHER_ERROR=%s\n' "$reason" >&2
|
||||||
|
printf 'SOURCE_MODIFIED_IN_PLACE=NO\n' >&2
|
||||||
|
exit "$code"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$#" -ne 0 ]; then
|
||||||
|
printf 'Uso: %s\n' "$0" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$PARENT" ]; then
|
||||||
|
fail 10 "CANONICAL_TEST_PARENT_MISSING"
|
||||||
|
fi
|
||||||
|
if [ ! -f "$VERIFIER" ]; then
|
||||||
|
fail 11 "MINIMAL_VERIFIER_MISSING"
|
||||||
|
fi
|
||||||
|
|
||||||
|
PARENT_SHA256_BEFORE="$(sha256sum -- "$PARENT" | awk '{print $1}')" || \
|
||||||
|
fail 12 "PARENT_HASH_UNAVAILABLE"
|
||||||
|
if [ "$PARENT_SHA256_BEFORE" != "$EXPECTED_PARENT_SHA256" ]; then
|
||||||
|
fail 13 "CANONICAL_TEST_PARENT_SHA256_MISMATCH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! mkdir -p -- "$OUTPUT_DIR"; then
|
||||||
|
fail 14 "OUTPUT_DIRECTORY_CREATION_FAILED"
|
||||||
|
fi
|
||||||
|
TEMP_OUTPUT="$(mktemp "$OUTPUT_DIR/.s03h3_minimal.XXXXXX")" || \
|
||||||
|
fail 15 "TEMPORARY_OUTPUT_CREATION_FAILED"
|
||||||
|
|
||||||
|
if ! python3 - "$PARENT" "$TEMP_OUTPUT" <<'PY'
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
parent = Path(sys.argv[1])
|
||||||
|
target = Path(sys.argv[2])
|
||||||
|
text = parent.read_bytes().decode("utf-8")
|
||||||
|
|
||||||
|
gamdisplay_start = " +GAMDisplay = {\n"
|
||||||
|
writer_start = " +IOGAM_Writer = {\n"
|
||||||
|
display_block = (
|
||||||
|
" +Display = {\n"
|
||||||
|
" Class = GAMDataSource\n"
|
||||||
|
" }\n"
|
||||||
|
)
|
||||||
|
old_functions = (
|
||||||
|
" Functions = "
|
||||||
|
"{GAMTimer SentinelProducer GAMDisplay IOGAM_Writer}"
|
||||||
|
)
|
||||||
|
new_functions = (
|
||||||
|
" Functions = "
|
||||||
|
"{GAMTimer SentinelProducer IOGAM_Writer}"
|
||||||
|
)
|
||||||
|
|
||||||
|
checks = {
|
||||||
|
"GAMDISPLAY_ANCHOR": text.count(gamdisplay_start),
|
||||||
|
"WRITER_ANCHOR": text.count(writer_start),
|
||||||
|
"DISPLAY_BLOCK": text.count(display_block),
|
||||||
|
"FUNCTIONS_ANCHOR": text.count(old_functions),
|
||||||
|
"MINIMAL_FUNCTIONS_PREEXISTING": text.count(new_functions),
|
||||||
|
}
|
||||||
|
if checks != {
|
||||||
|
"GAMDISPLAY_ANCHOR": 1,
|
||||||
|
"WRITER_ANCHOR": 1,
|
||||||
|
"DISPLAY_BLOCK": 1,
|
||||||
|
"FUNCTIONS_ANCHOR": 1,
|
||||||
|
"MINIMAL_FUNCTIONS_PREEXISTING": 0,
|
||||||
|
}:
|
||||||
|
for name, value in checks.items():
|
||||||
|
print(f"{name}_COUNT={value}", file=sys.stderr)
|
||||||
|
raise SystemExit(20)
|
||||||
|
|
||||||
|
start = text.index(gamdisplay_start)
|
||||||
|
end = text.index(writer_start, start)
|
||||||
|
if end <= start:
|
||||||
|
raise SystemExit(21)
|
||||||
|
|
||||||
|
result = text[:start] + text[end:]
|
||||||
|
result = result.replace(display_block, "", 1)
|
||||||
|
result = result.replace(old_functions, new_functions, 1)
|
||||||
|
target.write_bytes(result.encode("utf-8"))
|
||||||
|
PY
|
||||||
|
then
|
||||||
|
fail 16 "STRUCTURAL_TRANSFORMATION_FAILED"
|
||||||
|
fi
|
||||||
|
|
||||||
|
PARENT_SHA256_AFTER="$(sha256sum -- "$PARENT" | awk '{print $1}')" || \
|
||||||
|
fail 17 "PARENT_POST_HASH_UNAVAILABLE"
|
||||||
|
if [ "$PARENT_SHA256_AFTER" != "$PARENT_SHA256_BEFORE" ]; then
|
||||||
|
fail 18 "SOURCE_MODIFIED_IN_PLACE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! python3 "$VERIFIER" CANONICAL "$PARENT" "$TEMP_OUTPUT"; then
|
||||||
|
fail 19 "CANONICAL_STRUCTURAL_COMPLETENESS_FAILED"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -e "$OUTPUT" ]; then
|
||||||
|
if [ ! -f "$OUTPUT" ]; then
|
||||||
|
fail 20 "OUTPUT_EXISTS_NOT_REGULAR_FILE"
|
||||||
|
fi
|
||||||
|
if ! cmp -s -- "$TEMP_OUTPUT" "$OUTPUT"; then
|
||||||
|
fail 21 "EXISTING_OUTPUT_DIFFERS_FROM_DETERMINISTIC_RESULT"
|
||||||
|
fi
|
||||||
|
if ! python3 "$VERIFIER" CANONICAL "$PARENT" "$OUTPUT" >/dev/null; then
|
||||||
|
fail 22 "EXISTING_OUTPUT_COMPLETENESS_FAILED"
|
||||||
|
fi
|
||||||
|
printf 'PATCHER_RESULT=ALREADY_VALID\n'
|
||||||
|
else
|
||||||
|
chmod 0644 -- "$TEMP_OUTPUT" || fail 23 "OUTPUT_MODE_SET_FAILED"
|
||||||
|
mv -- "$TEMP_OUTPUT" "$OUTPUT" || fail 24 "OUTPUT_PUBLICATION_FAILED"
|
||||||
|
TEMP_OUTPUT=""
|
||||||
|
if ! python3 "$VERIFIER" CANONICAL "$PARENT" "$OUTPUT" >/dev/null; then
|
||||||
|
fail 25 "PUBLISHED_OUTPUT_COMPLETENESS_FAILED"
|
||||||
|
fi
|
||||||
|
printf 'PATCHER_RESULT=CREATED\n'
|
||||||
|
fi
|
||||||
|
|
||||||
|
OUTPUT_SHA256="$(sha256sum -- "$OUTPUT" | awk '{print $1}')" || \
|
||||||
|
fail 26 "OUTPUT_HASH_UNAVAILABLE"
|
||||||
|
printf 'PATCHER_STATUS=PASS\n'
|
||||||
|
printf 'PATCHER_DETERMINISM=PASS\n'
|
||||||
|
printf 'PATCHER_PARENT_HASH_MATCH=PASS\n'
|
||||||
|
printf 'CANONICAL_STRUCTURAL_COMPLETENESS_STATUS=PASS\n'
|
||||||
|
printf 'SOURCE_MODIFIED_IN_PLACE=NO\n'
|
||||||
|
printf 'MINIMAL_CONFIG=%s\n' "$OUTPUT"
|
||||||
|
printf 'MINIMAL_CONFIG_SHA256=%s\n' "$OUTPUT_SHA256"
|
||||||
Executable
+115
@@ -0,0 +1,115 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -u
|
||||||
|
|
||||||
|
if [ "$#" -ne 1 ]; then
|
||||||
|
printf "Uso: %s <run.log>\n" "$0" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
RUN_LOG="$1"
|
||||||
|
|
||||||
|
if [ ! -f "$RUN_LOG" ]; then
|
||||||
|
printf "LOG ASSENTE: %s\n" "$RUN_LOG" >&2
|
||||||
|
exit 3
|
||||||
|
fi
|
||||||
|
|
||||||
|
START_LINES="$(
|
||||||
|
grep -Ec \
|
||||||
|
'^\[Information - RealTimeLoader\.cpp:[0-9]+\]: Started application in state State1[[:space:]]*$' \
|
||||||
|
"$RUN_LOG" || true
|
||||||
|
)"
|
||||||
|
|
||||||
|
COUNTER_SAMPLES="$(
|
||||||
|
grep -Ec \
|
||||||
|
'^\[Information - LoggerBroker\.cpp:[0-9]+\]: Counter \[0:0\]:[0-9]+[[:space:]]*$' \
|
||||||
|
"$RUN_LOG" || true
|
||||||
|
)"
|
||||||
|
|
||||||
|
CYCLE_TIME_SAMPLES="$(
|
||||||
|
grep -Ec \
|
||||||
|
'^\[Information - LoggerBroker\.cpp:[0-9]+\]: State1_Thread1_CycleTime \[0:0\]:[0-9]+[[:space:]]*$' \
|
||||||
|
"$RUN_LOG" || true
|
||||||
|
)"
|
||||||
|
|
||||||
|
SIGINT_LINES="$(
|
||||||
|
grep -Ec \
|
||||||
|
'^\[Information - Bootstrap\.cpp:[0-9]+\]: Application recieved SIGINT\.[[:space:]]*$' \
|
||||||
|
"$RUN_LOG" || true
|
||||||
|
)"
|
||||||
|
|
||||||
|
STOP_OK_LINES="$(
|
||||||
|
grep -Ec \
|
||||||
|
'^\[Information - Bootstrap\.cpp:[0-9]+\]: Application successfully stopped\.[[:space:]]*$' \
|
||||||
|
"$RUN_LOG" || true
|
||||||
|
)"
|
||||||
|
|
||||||
|
FATAL_ERROR_LINES="$(
|
||||||
|
grep -Ec '^\[FatalError - ' "$RUN_LOG" || true
|
||||||
|
)"
|
||||||
|
|
||||||
|
ERROR_LINES="$(
|
||||||
|
grep -Ec '^\[Error - ' "$RUN_LOG" || true
|
||||||
|
)"
|
||||||
|
|
||||||
|
NO_ERROR_LINES="$(
|
||||||
|
grep -Ec '^\[NoError - ' "$RUN_LOG" || true
|
||||||
|
)"
|
||||||
|
|
||||||
|
DOUBLE_STOP_LINES="$(
|
||||||
|
grep -Fc \
|
||||||
|
'Could not stop the RealTimeApplication. Was it ever started?' \
|
||||||
|
"$RUN_LOG" || true
|
||||||
|
)"
|
||||||
|
|
||||||
|
LAST_COUNTER="$(
|
||||||
|
grep -E \
|
||||||
|
'^\[Information - LoggerBroker\.cpp:[0-9]+\]: Counter \[0:0\]:[0-9]+[[:space:]]*$' \
|
||||||
|
"$RUN_LOG" |
|
||||||
|
tail -n 1 |
|
||||||
|
awk -F: '{gsub(/[[:space:]]/, "", $NF); print $NF}'
|
||||||
|
)"
|
||||||
|
|
||||||
|
printf "============================================================\n"
|
||||||
|
printf "VALIDAZIONE PRECISA S01\n"
|
||||||
|
printf "============================================================\n"
|
||||||
|
printf "Log: %s\n" "$RUN_LOG"
|
||||||
|
printf "Avvii di State1: %s\n" "$START_LINES"
|
||||||
|
printf "Campioni Counter reali: %s\n" "$COUNTER_SAMPLES"
|
||||||
|
printf "Ultimo Counter: %s\n" "${LAST_COUNTER:-non disponibile}"
|
||||||
|
printf "Campioni CycleTime reali: %s\n" "$CYCLE_TIME_SAMPLES"
|
||||||
|
printf "SIGINT ricevuti: %s\n" "$SIGINT_LINES"
|
||||||
|
printf "Stop riusciti: %s\n" "$STOP_OK_LINES"
|
||||||
|
printf "Righe FatalError reali: %s\n" "$FATAL_ERROR_LINES"
|
||||||
|
printf "Righe Error reali: %s\n" "$ERROR_LINES"
|
||||||
|
printf "Righe NoError: %s\n" "$NO_ERROR_LINES"
|
||||||
|
printf "Anomalie doppio arresto: %s\n" "$DOUBLE_STOP_LINES"
|
||||||
|
|
||||||
|
FUNCTIONAL_OK=0
|
||||||
|
|
||||||
|
if [ "$START_LINES" -ge 1 ] &&
|
||||||
|
[ "$COUNTER_SAMPLES" -ge 50 ] &&
|
||||||
|
[ "$CYCLE_TIME_SAMPLES" -ge 50 ]; then
|
||||||
|
FUNCTIONAL_OK=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "\n============================================================\n"
|
||||||
|
printf "CLASSIFICAZIONE\n"
|
||||||
|
printf "============================================================\n"
|
||||||
|
|
||||||
|
if [ "$FUNCTIONAL_OK" -eq 1 ]; then
|
||||||
|
printf "[VERIFICATO] Funzionamento S01 e produzione dei segnali.\n"
|
||||||
|
else
|
||||||
|
printf "[NON DIMOSTRATO] Funzionamento S01 non sufficientemente provato.\n"
|
||||||
|
exit 20
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$SIGINT_LINES" -ge 1 ] &&
|
||||||
|
[ "$STOP_OK_LINES" -ge 1 ] &&
|
||||||
|
[ "$FATAL_ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$ERROR_LINES" -eq 0 ]; then
|
||||||
|
printf "[VERIFICATO] Shutdown privo di Error e FatalError.\n"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "[DA VERIFICARE] Funzionalità riuscita, ma shutdown con anomalia.\n"
|
||||||
|
exit 10
|
||||||
Executable
+722
@@ -0,0 +1,722 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -u
|
||||||
|
|
||||||
|
if [ "$#" -ne 1 ]; then
|
||||||
|
printf "Uso: %s <directory-run|run.log>\n" "$0" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
INPUT_PATH="$1"
|
||||||
|
|
||||||
|
if [ -d "$INPUT_PATH" ]; then
|
||||||
|
RUN_DIR="$(cd "$INPUT_PATH" >/dev/null 2>&1 && pwd)"
|
||||||
|
RUN_LOG="$RUN_DIR/run.log"
|
||||||
|
elif [ -f "$INPUT_PATH" ]; then
|
||||||
|
RUN_LOG="$(cd "$(dirname "$INPUT_PATH")" >/dev/null 2>&1 && pwd)/$(basename "$INPUT_PATH")"
|
||||||
|
RUN_DIR="$(dirname "$RUN_LOG")"
|
||||||
|
else
|
||||||
|
printf "[NON DIMOSTRATO] Percorso di validazione non trovato: %s\n" "$INPUT_PATH" >&2
|
||||||
|
exit 21
|
||||||
|
fi
|
||||||
|
|
||||||
|
RUN_CONFIG="$RUN_DIR/configuration.marte"
|
||||||
|
OUTPUT_FILE="$RUN_DIR/s02_output.bin"
|
||||||
|
RUNNER_SUMMARY="$RUN_DIR/runner_summary.txt"
|
||||||
|
|
||||||
|
for required_file in "$RUN_LOG" "$RUN_CONFIG" "$OUTPUT_FILE"; do
|
||||||
|
if [ ! -f "$required_file" ]; then
|
||||||
|
printf "[NON DIMOSTRATO] File richiesto assente: %s\n" "$required_file" >&2
|
||||||
|
exit 21
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
count_lines() {
|
||||||
|
pattern="$1"
|
||||||
|
file="$2"
|
||||||
|
grep -Ec "$pattern" "$file" 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
START_LINES="$(count_lines '^\[Information - RealTimeLoader\.cpp:[0-9]+\]: Started application in state State1[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
APPLICATION_START_LINES="$(count_lines '^\[Information - MARTeApp\.cpp:[0-9]+\]: Application starting[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
FILE_OPEN_LINES="$(count_lines '^\[Information - FileWriter\.cpp:[0-9]+\]: Going to open file with name ' "$RUN_LOG")"
|
||||||
|
SIGINT_LINES="$(count_lines '^\[Information - Bootstrap\.cpp:[0-9]+\]: Application recieved SIGINT\.[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
STOP_OK_LINES="$(count_lines '^\[Information - Bootstrap\.cpp:[0-9]+\]: Application successfully stopped\.[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
TERMINATED_LINES="$(count_lines '^\[NoError - MARTeApp\.cpp:[0-9]+\]: Application terminated[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
|
||||||
|
STARTUP_ERROR_LINES="$(count_lines 'Failed dlopen|Failed CreateByName|Failed to Initialise object|Failed to initialise the ObjectRegistryDatabase|Could not Initialise the loader' "$RUN_LOG")"
|
||||||
|
FATAL_ERROR_LINES="$(count_lines '^\[FatalError ' "$RUN_LOG")"
|
||||||
|
OS_ERROR_LINES="$(count_lines '^\[OSError ' "$RUN_LOG")"
|
||||||
|
ERROR_LINES="$(count_lines '^\[Error ' "$RUN_LOG")"
|
||||||
|
INITIALISATION_ERROR_LINES="$(count_lines '^\[InitialisationEr ' "$RUN_LOG")"
|
||||||
|
NO_ERROR_LINES="$(count_lines '^\[NoError ' "$RUN_LOG")"
|
||||||
|
WARNING_LINES="$(count_lines '^\[Warning ' "$RUN_LOG")"
|
||||||
|
PRIORITY_CLIP_LINES="$(count_lines '^\[Warning - Threads\.cpp:[0-9]+\]: Requested a thread priority that is higher than ' "$RUN_LOG")"
|
||||||
|
PRIORITY_FAIL_LINES="$(count_lines '^\[Warning - Threads\.cpp:[0-9]+\]: Failed to change the thread priority' "$RUN_LOG")"
|
||||||
|
UNCLASSIFIED_WARNING_LINES=$((WARNING_LINES - PRIORITY_CLIP_LINES - PRIORITY_FAIL_LINES))
|
||||||
|
|
||||||
|
if [ "$UNCLASSIFIED_WARNING_LINES" -lt 0 ]; then
|
||||||
|
UNCLASSIFIED_WARNING_LINES=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
DOUBLE_STOP_LINES="$(count_lines '^\[FatalError - RealTimeApplication\.cpp:[0-9]+\]: Could not stop the RealTimeApplication\. Was it ever started\?[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
ASYNC_EVENTSEM_CLOSE_LINES="$(count_lines '^\[FatalError - MemoryMapAsyncOutputBroker\.cpp:[0-9]+\]: Could not Close the EventSem\.[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
PTHREAD_MUTEX_DESTROY_LINES="$(count_lines '^\[OSError - EventSem\.cpp:[0-9]+\]: Error: pthread_mutex_destroy\(\)[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
|
||||||
|
UNCLASSIFIED_FATAL_LINES=$((FATAL_ERROR_LINES - DOUBLE_STOP_LINES - ASYNC_EVENTSEM_CLOSE_LINES))
|
||||||
|
UNCLASSIFIED_OS_ERROR_LINES=$((OS_ERROR_LINES - PTHREAD_MUTEX_DESTROY_LINES))
|
||||||
|
|
||||||
|
if [ "$UNCLASSIFIED_FATAL_LINES" -lt 0 ]; then
|
||||||
|
UNCLASSIFIED_FATAL_LINES=0
|
||||||
|
fi
|
||||||
|
if [ "$UNCLASSIFIED_OS_ERROR_LINES" -lt 0 ]; then
|
||||||
|
UNCLASSIFIED_OS_ERROR_LINES=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
PLACEHOLDER_COUNT="$(grep -o '__MARTE_RUN_DIR__' "$RUN_CONFIG" 2>/dev/null | wc -l)"
|
||||||
|
NAMESPACED_CLASS_COUNT="$(count_lines '^[[:space:]]*Class = FileDataSource::FileWriter[[:space:]]*$' "$RUN_CONFIG")"
|
||||||
|
PLAIN_CLASS_COUNT="$(count_lines '^[[:space:]]*Class = FileWriter[[:space:]]*$' "$RUN_CONFIG")"
|
||||||
|
EXPECTED_FILENAME="$RUN_DIR/s02_output.bin"
|
||||||
|
FILENAME_MATCH_LINES="$(
|
||||||
|
python3 - "$RUN_CONFIG" "$EXPECTED_FILENAME" <<'PYCONFIG'
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
config_path = Path(sys.argv[1])
|
||||||
|
expected = f'Filename = "{sys.argv[2]}"'
|
||||||
|
count = sum(
|
||||||
|
1
|
||||||
|
for line in config_path.read_text(encoding="utf-8").splitlines()
|
||||||
|
if line.strip() == expected
|
||||||
|
)
|
||||||
|
print(count)
|
||||||
|
PYCONFIG
|
||||||
|
)"
|
||||||
|
|
||||||
|
MARTE_EXIT_CODE="NOT_AVAILABLE"
|
||||||
|
TEE_EXIT_CODE="NOT_AVAILABLE"
|
||||||
|
if [ -f "$RUNNER_SUMMARY" ]; then
|
||||||
|
value="$(sed -n 's/^Exit code MARTe:[[:space:]]*//p' "$RUNNER_SUMMARY" | tail -n 1)"
|
||||||
|
if [ -n "$value" ]; then
|
||||||
|
MARTE_EXIT_CODE="$value"
|
||||||
|
fi
|
||||||
|
value="$(sed -n 's/^Exit code tee:[[:space:]]*//p' "$RUNNER_SUMMARY" | tail -n 1)"
|
||||||
|
if [ -n "$value" ]; then
|
||||||
|
TEE_EXIT_CODE="$value"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$MARTE_EXIT_CODE" in
|
||||||
|
124)
|
||||||
|
MARTE_EXIT_CLASS="TIMEOUT_EXIT_124"
|
||||||
|
;;
|
||||||
|
137)
|
||||||
|
MARTE_EXIT_CLASS="EXIT_137_SIGKILL"
|
||||||
|
;;
|
||||||
|
0)
|
||||||
|
MARTE_EXIT_CLASS="EXIT_0"
|
||||||
|
;;
|
||||||
|
NOT_AVAILABLE)
|
||||||
|
MARTE_EXIT_CLASS="NOT_AVAILABLE"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
MARTE_EXIT_CLASS="OTHER_EXIT_CODE"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CONFIG_REPORT="$(mktemp "${TMPDIR:-/tmp}/s02_validator_config_XXXXXX.log")"
|
||||||
|
BINARY_REPORT="$(mktemp "${TMPDIR:-/tmp}/s02_validator_binary_XXXXXX.log")"
|
||||||
|
trap 'rm -f -- "$CONFIG_REPORT" "$BINARY_REPORT"' EXIT
|
||||||
|
|
||||||
|
python3 - "$RUN_CONFIG" >"$CONFIG_REPORT" 2>&1 <<'PYCONFIGOBS'
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from decimal import Decimal, InvalidOperation
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
class Node:
|
||||||
|
def __init__(self, name):
|
||||||
|
self.name = name.lstrip("+$")
|
||||||
|
self.properties = {}
|
||||||
|
|
||||||
|
|
||||||
|
def sanitise(text):
|
||||||
|
"""Remove comments while preserving strings, braces and line boundaries."""
|
||||||
|
output = []
|
||||||
|
index = 0
|
||||||
|
quote = None
|
||||||
|
block_comment = False
|
||||||
|
while index < len(text):
|
||||||
|
char = text[index]
|
||||||
|
next_char = text[index + 1] if index + 1 < len(text) else ""
|
||||||
|
if block_comment:
|
||||||
|
if char == "*" and next_char == "/":
|
||||||
|
block_comment = False
|
||||||
|
output.extend(" ")
|
||||||
|
index += 2
|
||||||
|
else:
|
||||||
|
output.append("\n" if char == "\n" else " ")
|
||||||
|
index += 1
|
||||||
|
continue
|
||||||
|
if quote:
|
||||||
|
output.append(char)
|
||||||
|
if char == "\\" and index + 1 < len(text):
|
||||||
|
output.append(text[index + 1])
|
||||||
|
index += 2
|
||||||
|
continue
|
||||||
|
if char == quote:
|
||||||
|
quote = None
|
||||||
|
index += 1
|
||||||
|
continue
|
||||||
|
if char in {'"', "'"}:
|
||||||
|
quote = char
|
||||||
|
output.append(char)
|
||||||
|
index += 1
|
||||||
|
continue
|
||||||
|
if char == "/" and next_char == "*":
|
||||||
|
block_comment = True
|
||||||
|
output.extend(" ")
|
||||||
|
index += 2
|
||||||
|
continue
|
||||||
|
if char == "/" and next_char == "/":
|
||||||
|
while index < len(text) and text[index] != "\n":
|
||||||
|
output.append(" ")
|
||||||
|
index += 1
|
||||||
|
continue
|
||||||
|
if char == "#":
|
||||||
|
while index < len(text) and text[index] != "\n":
|
||||||
|
output.append(" ")
|
||||||
|
index += 1
|
||||||
|
continue
|
||||||
|
output.append(char)
|
||||||
|
index += 1
|
||||||
|
return "".join(output)
|
||||||
|
|
||||||
|
|
||||||
|
def braces_outside_strings(line):
|
||||||
|
result = []
|
||||||
|
quote = None
|
||||||
|
index = 0
|
||||||
|
while index < len(line):
|
||||||
|
char = line[index]
|
||||||
|
if quote:
|
||||||
|
if char == "\\" and index + 1 < len(line):
|
||||||
|
index += 2
|
||||||
|
continue
|
||||||
|
if char == quote:
|
||||||
|
quote = None
|
||||||
|
elif char in {'"', "'"}:
|
||||||
|
quote = char
|
||||||
|
elif char in "{}":
|
||||||
|
result.append(char)
|
||||||
|
index += 1
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
text = Path(sys.argv[1]).read_text(encoding="utf-8")
|
||||||
|
clean = sanitise(text)
|
||||||
|
nodes = []
|
||||||
|
stack = []
|
||||||
|
object_open = re.compile(r"^\s*([+$]?[A-Za-z_][A-Za-z0-9_.:-]*)\s*=\s*\{")
|
||||||
|
assignment = re.compile(r"^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*?)\s*$")
|
||||||
|
|
||||||
|
for line in clean.splitlines():
|
||||||
|
match = object_open.match(line)
|
||||||
|
if match:
|
||||||
|
node = Node(match.group(1))
|
||||||
|
nodes.append(node)
|
||||||
|
stack.append(node)
|
||||||
|
elif stack:
|
||||||
|
match = assignment.match(line)
|
||||||
|
if match and not match.group(2).startswith("{"):
|
||||||
|
stack[-1].properties[match.group(1)] = match.group(2).strip()
|
||||||
|
|
||||||
|
opens_and_closes = braces_outside_strings(line)
|
||||||
|
opening_already_consumed = bool(match and object_open.match(line))
|
||||||
|
if opening_already_consumed:
|
||||||
|
removed = False
|
||||||
|
adjusted = []
|
||||||
|
for brace in opens_and_closes:
|
||||||
|
if brace == "{" and not removed:
|
||||||
|
removed = True
|
||||||
|
continue
|
||||||
|
adjusted.append(brace)
|
||||||
|
opens_and_closes = adjusted
|
||||||
|
for brace in opens_and_closes:
|
||||||
|
if brace == "{":
|
||||||
|
stack.append(Node("<anonymous>"))
|
||||||
|
elif stack:
|
||||||
|
stack.pop()
|
||||||
|
|
||||||
|
|
||||||
|
def report_objects(prefix, classes, property_name):
|
||||||
|
matches = [node for node in nodes if node.properties.get("Class") in classes]
|
||||||
|
names = ",".join(node.name for node in matches) or "NOT_AVAILABLE_OBJECT_NOT_FOUND"
|
||||||
|
affinities = []
|
||||||
|
for node in matches:
|
||||||
|
value = node.properties.get(property_name, "NOT_EXPLICITLY_CONFIGURED")
|
||||||
|
affinities.append(f"{node.name}={value}")
|
||||||
|
affinity = ",".join(affinities) or "NOT_AVAILABLE_OBJECT_NOT_FOUND"
|
||||||
|
print(f"{prefix}_OBJECT_COUNT={len(matches)}")
|
||||||
|
print(f"{prefix}_OBJECT_NAMES={names}")
|
||||||
|
print(f"{prefix}_AFFINITY={affinity}")
|
||||||
|
|
||||||
|
|
||||||
|
report_objects("REALTIME_THREAD", {"RealTimeThread"}, "CPUs")
|
||||||
|
report_objects("FILE_WRITER", {"FileDataSource::FileWriter", "FileWriter"}, "CPUMask")
|
||||||
|
report_objects("LINUX_TIMER", {"LinuxTimer"}, "CPUMask")
|
||||||
|
|
||||||
|
frequency_values = []
|
||||||
|
for node in nodes:
|
||||||
|
raw = node.properties.get("Frequency")
|
||||||
|
if raw is None:
|
||||||
|
continue
|
||||||
|
raw = raw.strip().strip('"').strip("'")
|
||||||
|
try:
|
||||||
|
value = Decimal(raw)
|
||||||
|
except InvalidOperation:
|
||||||
|
continue
|
||||||
|
if value > 0:
|
||||||
|
frequency_values.append(value)
|
||||||
|
|
||||||
|
unique_frequencies = sorted(set(frequency_values))
|
||||||
|
if len(unique_frequencies) == 1:
|
||||||
|
frequency = unique_frequencies[0]
|
||||||
|
period = Decimal(1_000_000) / frequency
|
||||||
|
period_text = str(int(period)) if period == period.to_integral_value() else format(period, ".6f").rstrip("0").rstrip(".")
|
||||||
|
frequency_text = format(frequency, "f").rstrip("0").rstrip(".") if "." in format(frequency, "f") else format(frequency, "f")
|
||||||
|
print(f"DT_NOMINAL_PERIOD_US={period_text}")
|
||||||
|
print(f"DT_NOMINAL_SOURCE=CONFIG_FREQUENCY_{frequency_text}_HZ")
|
||||||
|
elif not unique_frequencies:
|
||||||
|
print("DT_NOMINAL_PERIOD_US=NOT_AVAILABLE")
|
||||||
|
print("DT_NOMINAL_SOURCE=NOT_AVAILABLE_NO_POSITIVE_FREQUENCY")
|
||||||
|
else:
|
||||||
|
print("DT_NOMINAL_PERIOD_US=NOT_AVAILABLE")
|
||||||
|
print("DT_NOMINAL_SOURCE=NOT_AVAILABLE_MULTIPLE_FREQUENCIES")
|
||||||
|
|
||||||
|
print("CONFIG_OBSERVABILITY_STATUS=PASS")
|
||||||
|
PYCONFIGOBS
|
||||||
|
|
||||||
|
CONFIG_RC=$?
|
||||||
|
|
||||||
|
config_value() {
|
||||||
|
key="$1"
|
||||||
|
sed -n "s/^${key}=//p" "$CONFIG_REPORT" | tail -n 1
|
||||||
|
}
|
||||||
|
|
||||||
|
CONFIG_OBSERVABILITY_STATUS="$(config_value CONFIG_OBSERVABILITY_STATUS)"
|
||||||
|
REALTIME_THREAD_OBJECT_COUNT="$(config_value REALTIME_THREAD_OBJECT_COUNT)"
|
||||||
|
REALTIME_THREAD_OBJECT_NAMES="$(config_value REALTIME_THREAD_OBJECT_NAMES)"
|
||||||
|
REALTIME_THREAD_AFFINITY="$(config_value REALTIME_THREAD_AFFINITY)"
|
||||||
|
FILE_WRITER_OBJECT_COUNT="$(config_value FILE_WRITER_OBJECT_COUNT)"
|
||||||
|
FILE_WRITER_OBJECT_NAMES="$(config_value FILE_WRITER_OBJECT_NAMES)"
|
||||||
|
FILE_WRITER_AFFINITY="$(config_value FILE_WRITER_AFFINITY)"
|
||||||
|
LINUX_TIMER_OBJECT_COUNT="$(config_value LINUX_TIMER_OBJECT_COUNT)"
|
||||||
|
LINUX_TIMER_OBJECT_NAMES="$(config_value LINUX_TIMER_OBJECT_NAMES)"
|
||||||
|
LINUX_TIMER_AFFINITY="$(config_value LINUX_TIMER_AFFINITY)"
|
||||||
|
DT_NOMINAL_PERIOD_US="$(config_value DT_NOMINAL_PERIOD_US)"
|
||||||
|
DT_NOMINAL_SOURCE="$(config_value DT_NOMINAL_SOURCE)"
|
||||||
|
|
||||||
|
python3 - "$OUTPUT_FILE" "${DT_NOMINAL_PERIOD_US:-NOT_AVAILABLE}" >"$BINARY_REPORT" 2>&1 <<'PY'
|
||||||
|
from collections import Counter
|
||||||
|
from decimal import Decimal, InvalidOperation
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
path = Path(sys.argv[1])
|
||||||
|
nominal_period_raw = sys.argv[2]
|
||||||
|
data = path.read_bytes()
|
||||||
|
|
||||||
|
expected_names = [
|
||||||
|
"Counter",
|
||||||
|
"Time",
|
||||||
|
"State1_Thread1_CycleTime",
|
||||||
|
]
|
||||||
|
expected_type_hex = "0408"
|
||||||
|
expected_signals = len(expected_names)
|
||||||
|
signal_header_bytes = 2 + 32 + 4
|
||||||
|
|
||||||
|
print(f"FILE_SIZE_BYTES={len(data)}")
|
||||||
|
|
||||||
|
if len(data) < 4:
|
||||||
|
print("BINARY_STATUS=FAIL_HEADER_TOO_SMALL")
|
||||||
|
sys.exit(31)
|
||||||
|
|
||||||
|
number_of_signals = struct.unpack_from("<I", data, 0)[0]
|
||||||
|
print(f"NUMBER_OF_SIGNALS={number_of_signals}")
|
||||||
|
|
||||||
|
if number_of_signals != expected_signals:
|
||||||
|
print("BINARY_STATUS=FAIL_SIGNAL_COUNT")
|
||||||
|
sys.exit(32)
|
||||||
|
|
||||||
|
offset = 4
|
||||||
|
names = []
|
||||||
|
type_hex_values = []
|
||||||
|
elements = []
|
||||||
|
|
||||||
|
for index in range(number_of_signals):
|
||||||
|
if offset + signal_header_bytes > len(data):
|
||||||
|
print(f"TRUNCATED_SIGNAL_HEADER_INDEX={index}")
|
||||||
|
print("BINARY_STATUS=FAIL_TRUNCATED_SIGNAL_HEADER")
|
||||||
|
sys.exit(33)
|
||||||
|
|
||||||
|
type_bytes = data[offset:offset + 2]
|
||||||
|
offset += 2
|
||||||
|
|
||||||
|
raw_name = data[offset:offset + 32]
|
||||||
|
offset += 32
|
||||||
|
|
||||||
|
number_of_elements = struct.unpack_from("<I", data, offset)[0]
|
||||||
|
offset += 4
|
||||||
|
|
||||||
|
name = raw_name.split(b"\x00", 1)[0].decode("ascii", errors="replace")
|
||||||
|
names.append(name)
|
||||||
|
type_hex_values.append(type_bytes.hex())
|
||||||
|
elements.append(number_of_elements)
|
||||||
|
|
||||||
|
print(f"SIGNAL_{index}_TYPE_HEX={type_bytes.hex()}")
|
||||||
|
print(f"SIGNAL_{index}_NAME={name}")
|
||||||
|
print(f"SIGNAL_{index}_NUMBER_OF_ELEMENTS={number_of_elements}")
|
||||||
|
|
||||||
|
print("SIGNAL_NAMES=" + ",".join(names))
|
||||||
|
|
||||||
|
if names != expected_names:
|
||||||
|
print("BINARY_STATUS=FAIL_SIGNAL_NAMES")
|
||||||
|
sys.exit(34)
|
||||||
|
|
||||||
|
if any(value != expected_type_hex for value in type_hex_values):
|
||||||
|
print("BINARY_STATUS=FAIL_SIGNAL_TYPES")
|
||||||
|
sys.exit(35)
|
||||||
|
|
||||||
|
if any(value != 1 for value in elements):
|
||||||
|
print("BINARY_STATUS=FAIL_NUMBER_OF_ELEMENTS")
|
||||||
|
sys.exit(36)
|
||||||
|
|
||||||
|
header_bytes = offset
|
||||||
|
sample_bytes = expected_signals * 4
|
||||||
|
payload_bytes = len(data) - header_bytes
|
||||||
|
remainder_bytes = payload_bytes % sample_bytes
|
||||||
|
sample_count = payload_bytes // sample_bytes
|
||||||
|
|
||||||
|
print(f"HEADER_BYTES={header_bytes}")
|
||||||
|
print(f"SAMPLE_BYTES={sample_bytes}")
|
||||||
|
print(f"PAYLOAD_BYTES={payload_bytes}")
|
||||||
|
print(f"PAYLOAD_REMAINDER_BYTES={remainder_bytes}")
|
||||||
|
print(f"COMPLETE_SAMPLE_COUNT={sample_count}")
|
||||||
|
|
||||||
|
if remainder_bytes != 0:
|
||||||
|
print("BINARY_STATUS=FAIL_PAYLOAD_REMAINDER")
|
||||||
|
sys.exit(37)
|
||||||
|
|
||||||
|
records = [
|
||||||
|
struct.unpack_from("<III", data, header_bytes + index * sample_bytes)
|
||||||
|
for index in range(sample_count)
|
||||||
|
]
|
||||||
|
|
||||||
|
counters = [record[0] for record in records]
|
||||||
|
times = [record[1] for record in records]
|
||||||
|
cycle_times = [record[2] for record in records]
|
||||||
|
|
||||||
|
dt_values = [current - previous for previous, current in zip(times, times[1:])]
|
||||||
|
dt_histogram = Counter(dt_values)
|
||||||
|
distinct_dt_values = sorted(dt_histogram)
|
||||||
|
leading_zero_cycle_time_samples = 0
|
||||||
|
for value in cycle_times:
|
||||||
|
if value != 0:
|
||||||
|
break
|
||||||
|
leading_zero_cycle_time_samples += 1
|
||||||
|
|
||||||
|
print(f"DT_INTERVAL_COUNT={len(dt_values)}")
|
||||||
|
print("DT_DISTINCT_VALUES=" + (",".join(str(value) for value in distinct_dt_values) or "NOT_AVAILABLE"))
|
||||||
|
print(
|
||||||
|
"DT_HISTOGRAM="
|
||||||
|
+ (",".join(f"{value}:{dt_histogram[value]}" for value in distinct_dt_values) or "NOT_AVAILABLE")
|
||||||
|
)
|
||||||
|
print(f"DT_MIN={min(dt_values) if dt_values else 'NOT_AVAILABLE'}")
|
||||||
|
print(f"DT_MAX={max(dt_values) if dt_values else 'NOT_AVAILABLE'}")
|
||||||
|
print(f"LEADING_ZERO_CYCLE_TIME_SAMPLES={leading_zero_cycle_time_samples}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
nominal_period = Decimal(nominal_period_raw)
|
||||||
|
except InvalidOperation:
|
||||||
|
nominal_period = None
|
||||||
|
|
||||||
|
if nominal_period is not None and dt_values:
|
||||||
|
anomaly_indices = [
|
||||||
|
index for index, value in enumerate(dt_values)
|
||||||
|
if Decimal(value) != nominal_period
|
||||||
|
]
|
||||||
|
print(f"DT_ANOMALY_COUNT={len(anomaly_indices)}")
|
||||||
|
print("DT_ANOMALY_INDICES=" + (",".join(str(index) for index in anomaly_indices) or "NONE"))
|
||||||
|
if anomaly_indices:
|
||||||
|
first_index = anomaly_indices[0]
|
||||||
|
print(f"DT_FIRST_ANOMALY_BETWEEN_RECORDS={first_index}_AND_{first_index + 1}")
|
||||||
|
print(f"DT_FIRST_ANOMALY_COUNTER_PAIR={counters[first_index]}_AND_{counters[first_index + 1]}")
|
||||||
|
print(f"DT_FIRST_ANOMALY_VALUE={dt_values[first_index]}")
|
||||||
|
else:
|
||||||
|
print("DT_FIRST_ANOMALY_BETWEEN_RECORDS=NONE")
|
||||||
|
print("DT_FIRST_ANOMALY_COUNTER_PAIR=NONE")
|
||||||
|
print("DT_FIRST_ANOMALY_VALUE=NONE")
|
||||||
|
else:
|
||||||
|
print("DT_ANOMALY_COUNT=NOT_AVAILABLE")
|
||||||
|
print("DT_ANOMALY_INDICES=NOT_AVAILABLE")
|
||||||
|
print("DT_FIRST_ANOMALY_BETWEEN_RECORDS=NOT_AVAILABLE")
|
||||||
|
print("DT_FIRST_ANOMALY_COUNTER_PAIR=NOT_AVAILABLE")
|
||||||
|
print("DT_FIRST_ANOMALY_VALUE=NOT_AVAILABLE")
|
||||||
|
|
||||||
|
if sample_count < 50:
|
||||||
|
print("BINARY_STATUS=FAIL_INSUFFICIENT_SAMPLES")
|
||||||
|
sys.exit(38)
|
||||||
|
|
||||||
|
counter_gap_count = sum(
|
||||||
|
1 for previous, current in zip(counters, counters[1:])
|
||||||
|
if current != previous + 1
|
||||||
|
)
|
||||||
|
time_decrease_count = sum(
|
||||||
|
1 for previous, current in zip(times, times[1:])
|
||||||
|
if current < previous
|
||||||
|
)
|
||||||
|
nonzero_cycle_times = [value for value in cycle_times if value > 0]
|
||||||
|
|
||||||
|
print(f"COUNTER_FIRST={counters[0]}")
|
||||||
|
print(f"COUNTER_LAST={counters[-1]}")
|
||||||
|
print(f"COUNTER_GAP_COUNT={counter_gap_count}")
|
||||||
|
print(f"TIME_FIRST={times[0]}")
|
||||||
|
print(f"TIME_LAST={times[-1]}")
|
||||||
|
print(f"TIME_DECREASE_COUNT={time_decrease_count}")
|
||||||
|
print(f"NONZERO_CYCLE_TIME_SAMPLES={len(nonzero_cycle_times)}")
|
||||||
|
|
||||||
|
if nonzero_cycle_times:
|
||||||
|
print(f"CYCLE_TIME_MIN={min(nonzero_cycle_times)}")
|
||||||
|
print(f"CYCLE_TIME_MAX={max(nonzero_cycle_times)}")
|
||||||
|
print(f"CYCLE_TIME_MEAN={sum(nonzero_cycle_times) / len(nonzero_cycle_times):.3f}")
|
||||||
|
else:
|
||||||
|
print("CYCLE_TIME_MIN=NOT_AVAILABLE")
|
||||||
|
print("CYCLE_TIME_MAX=NOT_AVAILABLE")
|
||||||
|
print("CYCLE_TIME_MEAN=NOT_AVAILABLE")
|
||||||
|
|
||||||
|
if counters[0] != 1 or counter_gap_count != 0:
|
||||||
|
print("BINARY_STATUS=FAIL_COUNTER_SEQUENCE")
|
||||||
|
sys.exit(39)
|
||||||
|
|
||||||
|
if time_decrease_count != 0:
|
||||||
|
print("BINARY_STATUS=FAIL_TIME_MONOTONICITY")
|
||||||
|
sys.exit(40)
|
||||||
|
|
||||||
|
if len(nonzero_cycle_times) == 0:
|
||||||
|
print("BINARY_STATUS=FAIL_NO_CYCLE_TIME")
|
||||||
|
sys.exit(41)
|
||||||
|
|
||||||
|
print("BINARY_STATUS=PASS")
|
||||||
|
PY
|
||||||
|
|
||||||
|
BINARY_RC=$?
|
||||||
|
|
||||||
|
binary_value() {
|
||||||
|
key="$1"
|
||||||
|
sed -n "s/^${key}=//p" "$BINARY_REPORT" | tail -n 1
|
||||||
|
}
|
||||||
|
|
||||||
|
BINARY_STATUS="$(binary_value BINARY_STATUS)"
|
||||||
|
FILE_SIZE_BYTES="$(binary_value FILE_SIZE_BYTES)"
|
||||||
|
NUMBER_OF_SIGNALS="$(binary_value NUMBER_OF_SIGNALS)"
|
||||||
|
SIGNAL_NAMES="$(binary_value SIGNAL_NAMES)"
|
||||||
|
HEADER_BYTES="$(binary_value HEADER_BYTES)"
|
||||||
|
SAMPLE_BYTES="$(binary_value SAMPLE_BYTES)"
|
||||||
|
PAYLOAD_BYTES="$(binary_value PAYLOAD_BYTES)"
|
||||||
|
PAYLOAD_REMAINDER_BYTES="$(binary_value PAYLOAD_REMAINDER_BYTES)"
|
||||||
|
COMPLETE_SAMPLE_COUNT="$(binary_value COMPLETE_SAMPLE_COUNT)"
|
||||||
|
COUNTER_FIRST="$(binary_value COUNTER_FIRST)"
|
||||||
|
COUNTER_LAST="$(binary_value COUNTER_LAST)"
|
||||||
|
COUNTER_GAP_COUNT="$(binary_value COUNTER_GAP_COUNT)"
|
||||||
|
TIME_FIRST="$(binary_value TIME_FIRST)"
|
||||||
|
TIME_LAST="$(binary_value TIME_LAST)"
|
||||||
|
TIME_DECREASE_COUNT="$(binary_value TIME_DECREASE_COUNT)"
|
||||||
|
NONZERO_CYCLE_TIME_SAMPLES="$(binary_value NONZERO_CYCLE_TIME_SAMPLES)"
|
||||||
|
CYCLE_TIME_MIN="$(binary_value CYCLE_TIME_MIN)"
|
||||||
|
CYCLE_TIME_MAX="$(binary_value CYCLE_TIME_MAX)"
|
||||||
|
CYCLE_TIME_MEAN="$(binary_value CYCLE_TIME_MEAN)"
|
||||||
|
DT_INTERVAL_COUNT="$(binary_value DT_INTERVAL_COUNT)"
|
||||||
|
DT_DISTINCT_VALUES="$(binary_value DT_DISTINCT_VALUES)"
|
||||||
|
DT_HISTOGRAM="$(binary_value DT_HISTOGRAM)"
|
||||||
|
DT_MIN="$(binary_value DT_MIN)"
|
||||||
|
DT_MAX="$(binary_value DT_MAX)"
|
||||||
|
DT_ANOMALY_COUNT="$(binary_value DT_ANOMALY_COUNT)"
|
||||||
|
DT_ANOMALY_INDICES="$(binary_value DT_ANOMALY_INDICES)"
|
||||||
|
DT_FIRST_ANOMALY_BETWEEN_RECORDS="$(binary_value DT_FIRST_ANOMALY_BETWEEN_RECORDS)"
|
||||||
|
DT_FIRST_ANOMALY_COUNTER_PAIR="$(binary_value DT_FIRST_ANOMALY_COUNTER_PAIR)"
|
||||||
|
DT_FIRST_ANOMALY_VALUE="$(binary_value DT_FIRST_ANOMALY_VALUE)"
|
||||||
|
LEADING_ZERO_CYCLE_TIME_SAMPLES="$(binary_value LEADING_ZERO_CYCLE_TIME_SAMPLES)"
|
||||||
|
|
||||||
|
affinity_display() {
|
||||||
|
object_count="$1"
|
||||||
|
affinity_mapping="$2"
|
||||||
|
if [ "$object_count" = "1" ]; then
|
||||||
|
printf "%s" "${affinity_mapping#*=}"
|
||||||
|
else
|
||||||
|
printf "%s" "$affinity_mapping"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
REALTIME_THREAD_AFFINITY_DISPLAY="$(affinity_display "${REALTIME_THREAD_OBJECT_COUNT:-0}" "${REALTIME_THREAD_AFFINITY:-NOT_AVAILABLE}")"
|
||||||
|
FILE_WRITER_AFFINITY_DISPLAY="$(affinity_display "${FILE_WRITER_OBJECT_COUNT:-0}" "${FILE_WRITER_AFFINITY:-NOT_AVAILABLE}")"
|
||||||
|
LINUX_TIMER_AFFINITY_DISPLAY="$(affinity_display "${LINUX_TIMER_OBJECT_COUNT:-0}" "${LINUX_TIMER_AFFINITY:-NOT_AVAILABLE}")"
|
||||||
|
|
||||||
|
printf "============================================================\n"
|
||||||
|
printf "VALIDAZIONE PRECISA S02\n"
|
||||||
|
printf "============================================================\n"
|
||||||
|
printf "Run directory: %s\n" "$RUN_DIR"
|
||||||
|
printf "Log: %s\n" "$RUN_LOG"
|
||||||
|
printf "Configurazione: %s\n" "$RUN_CONFIG"
|
||||||
|
printf "File binario: %s\n" "$OUTPUT_FILE"
|
||||||
|
printf "Avvii State1: %s\n" "$START_LINES"
|
||||||
|
printf "Application starting: %s\n" "$APPLICATION_START_LINES"
|
||||||
|
printf "Aperture FileWriter: %s\n" "$FILE_OPEN_LINES"
|
||||||
|
printf "Placeholder residui: %s\n" "$PLACEHOLDER_COUNT"
|
||||||
|
printf "Classe qualificata FileWriter: %s\n" "$NAMESPACED_CLASS_COUNT"
|
||||||
|
printf "Classe semplice FileWriter: %s\n" "$PLAIN_CLASS_COUNT"
|
||||||
|
printf "Filename corretti: %s\n" "$FILENAME_MATCH_LINES"
|
||||||
|
printf "Dimensione file: %s byte\n" "${FILE_SIZE_BYTES:-NOT_AVAILABLE}"
|
||||||
|
printf "Segnali binari: %s\n" "${NUMBER_OF_SIGNALS:-NOT_AVAILABLE}"
|
||||||
|
printf "Nomi segnali: %s\n" "${SIGNAL_NAMES:-NOT_AVAILABLE}"
|
||||||
|
printf "Header: %s byte\n" "${HEADER_BYTES:-NOT_AVAILABLE}"
|
||||||
|
printf "Record: %s byte\n" "${SAMPLE_BYTES:-NOT_AVAILABLE}"
|
||||||
|
printf "Payload: %s byte\n" "${PAYLOAD_BYTES:-NOT_AVAILABLE}"
|
||||||
|
printf "Residuo payload: %s byte\n" "${PAYLOAD_REMAINDER_BYTES:-NOT_AVAILABLE}"
|
||||||
|
printf "Campioni completi: %s\n" "${COMPLETE_SAMPLE_COUNT:-NOT_AVAILABLE}"
|
||||||
|
printf "Counter iniziale: %s\n" "${COUNTER_FIRST:-NOT_AVAILABLE}"
|
||||||
|
printf "Counter finale: %s\n" "${COUNTER_LAST:-NOT_AVAILABLE}"
|
||||||
|
printf "Salti Counter: %s\n" "${COUNTER_GAP_COUNT:-NOT_AVAILABLE}"
|
||||||
|
printf "Time iniziale: %s\n" "${TIME_FIRST:-NOT_AVAILABLE}"
|
||||||
|
printf "Time finale: %s\n" "${TIME_LAST:-NOT_AVAILABLE}"
|
||||||
|
printf "Regressioni Time: %s\n" "${TIME_DECREASE_COUNT:-NOT_AVAILABLE}"
|
||||||
|
printf "CycleTime non nulli: %s\n" "${NONZERO_CYCLE_TIME_SAMPLES:-NOT_AVAILABLE}"
|
||||||
|
printf "CycleTime minimo: %s\n" "${CYCLE_TIME_MIN:-NOT_AVAILABLE}"
|
||||||
|
printf "CycleTime massimo: %s\n" "${CYCLE_TIME_MAX:-NOT_AVAILABLE}"
|
||||||
|
printf "CycleTime medio: %s\n" "${CYCLE_TIME_MEAN:-NOT_AVAILABLE}"
|
||||||
|
printf "Stato parser binario: %s\n" "${BINARY_STATUS:-NOT_AVAILABLE}"
|
||||||
|
printf "Exit code MARTe: %s\n" "$MARTE_EXIT_CODE"
|
||||||
|
printf "Exit code tee: %s\n" "$TEE_EXIT_CODE"
|
||||||
|
printf "SIGINT ricevuti: %s\n" "$SIGINT_LINES"
|
||||||
|
printf "Stop riusciti: %s\n" "$STOP_OK_LINES"
|
||||||
|
printf "Application terminated: %s\n" "$TERMINATED_LINES"
|
||||||
|
printf "Errori startup: %s\n" "$STARTUP_ERROR_LINES"
|
||||||
|
printf "FatalError reali: %s\n" "$FATAL_ERROR_LINES"
|
||||||
|
printf "OSError reali: %s\n" "$OS_ERROR_LINES"
|
||||||
|
printf "Error reali: %s\n" "$ERROR_LINES"
|
||||||
|
printf "InitialisationError reali: %s\n" "$INITIALISATION_ERROR_LINES"
|
||||||
|
printf "NoError: %s\n" "$NO_ERROR_LINES"
|
||||||
|
printf "Doppio arresto: %s\n" "$DOUBLE_STOP_LINES"
|
||||||
|
printf "Close EventSem asincrono: %s\n" "$ASYNC_EVENTSEM_CLOSE_LINES"
|
||||||
|
printf "pthread_mutex_destroy: %s\n" "$PTHREAD_MUTEX_DESTROY_LINES"
|
||||||
|
printf "FatalError non classificati: %s\n" "$UNCLASSIFIED_FATAL_LINES"
|
||||||
|
printf "OSError non classificati: %s\n" "$UNCLASSIFIED_OS_ERROR_LINES"
|
||||||
|
|
||||||
|
printf "\n--- INTERVALLI TEMPORALI (osservativo) ---\n"
|
||||||
|
printf "Periodo nominale: %s us\n" "${DT_NOMINAL_PERIOD_US:-NOT_AVAILABLE}"
|
||||||
|
printf "Fonte periodo nominale: %s\n" "${DT_NOMINAL_SOURCE:-NOT_AVAILABLE}"
|
||||||
|
printf "Intervalli dt: %s\n" "${DT_INTERVAL_COUNT:-NOT_AVAILABLE}"
|
||||||
|
printf "Valori dt distinti: %s\n" "${DT_DISTINCT_VALUES:-NOT_AVAILABLE}"
|
||||||
|
printf "Istogramma dt: %s\n" "${DT_HISTOGRAM:-NOT_AVAILABLE}"
|
||||||
|
printf "dt minimo: %s\n" "${DT_MIN:-NOT_AVAILABLE}"
|
||||||
|
printf "dt massimo: %s\n" "${DT_MAX:-NOT_AVAILABLE}"
|
||||||
|
printf "Intervalli dt anomali: %s\n" "${DT_ANOMALY_COUNT:-NOT_AVAILABLE}"
|
||||||
|
printf "Indici dt anomali: %s\n" "${DT_ANOMALY_INDICES:-NOT_AVAILABLE}"
|
||||||
|
printf "Primo dt anomalo tra record: %s\n" "${DT_FIRST_ANOMALY_BETWEEN_RECORDS:-NOT_AVAILABLE}"
|
||||||
|
printf "Primo dt anomalo Counter: %s\n" "${DT_FIRST_ANOMALY_COUNTER_PAIR:-NOT_AVAILABLE}"
|
||||||
|
printf "Primo dt anomalo valore: %s\n" "${DT_FIRST_ANOMALY_VALUE:-NOT_AVAILABLE}"
|
||||||
|
printf "CycleTime nulli iniziali: %s\n" "${LEADING_ZERO_CYCLE_TIME_SAMPLES:-NOT_AVAILABLE}"
|
||||||
|
|
||||||
|
printf "\n--- AFFINITA' DICHIARATE IN CONFIGURAZIONE ---\n"
|
||||||
|
REALTIME_THREAD_LABEL="RealTimeThread (${REALTIME_THREAD_OBJECT_NAMES:-NOT_AVAILABLE}) CPUs:"
|
||||||
|
FILE_WRITER_LABEL="FileWriter (${FILE_WRITER_OBJECT_NAMES:-NOT_AVAILABLE}) CPUMask:"
|
||||||
|
LINUX_TIMER_LABEL="LinuxTimer (${LINUX_TIMER_OBJECT_NAMES:-NOT_AVAILABLE}) CPUMask:"
|
||||||
|
printf "%-40s %s (rc=%s)\n" "Stato parser configurazione:" "${CONFIG_OBSERVABILITY_STATUS:-NOT_AVAILABLE}" "$CONFIG_RC"
|
||||||
|
printf "%-40s %s\n" "$REALTIME_THREAD_LABEL" "${REALTIME_THREAD_AFFINITY_DISPLAY:-NOT_AVAILABLE}"
|
||||||
|
printf "%-40s %s\n" "$FILE_WRITER_LABEL" "${FILE_WRITER_AFFINITY_DISPLAY:-NOT_AVAILABLE}"
|
||||||
|
printf "%-40s %s\n" "$LINUX_TIMER_LABEL" "${LINUX_TIMER_AFFINITY_DISPLAY:-NOT_AVAILABLE}"
|
||||||
|
|
||||||
|
printf "\n--- PRIORITA' E TERMINAZIONE ---\n"
|
||||||
|
printf "Warning totali: %s\n" "$WARNING_LINES"
|
||||||
|
printf "Warning clipping priorita': %s\n" "$PRIORITY_CLIP_LINES"
|
||||||
|
printf "Warning priorita' non applic.: %s\n" "$PRIORITY_FAIL_LINES"
|
||||||
|
printf "Warning non classificati: %s\n" "$UNCLASSIFIED_WARNING_LINES"
|
||||||
|
printf "Classe exit code: %s\n" "$MARTE_EXIT_CLASS"
|
||||||
|
|
||||||
|
FUNCTIONAL_OK=0
|
||||||
|
|
||||||
|
if [ "$START_LINES" -ge 1 ] &&
|
||||||
|
[ "$APPLICATION_START_LINES" -ge 1 ] &&
|
||||||
|
[ "$FILE_OPEN_LINES" -ge 1 ] &&
|
||||||
|
[ "$STARTUP_ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$PLACEHOLDER_COUNT" -eq 0 ] &&
|
||||||
|
[ "$NAMESPACED_CLASS_COUNT" -eq 1 ] &&
|
||||||
|
[ "$PLAIN_CLASS_COUNT" -eq 0 ] &&
|
||||||
|
[ "$FILENAME_MATCH_LINES" -eq 1 ] &&
|
||||||
|
[ "$BINARY_RC" -eq 0 ]; then
|
||||||
|
FUNCTIONAL_OK=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$FUNCTIONAL_OK" -eq 1 ]; then
|
||||||
|
FUNCTIONAL_STATUS="PASS"
|
||||||
|
else
|
||||||
|
FUNCTIONAL_STATUS="NOT_DEMONSTRATED"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$MARTE_EXIT_CLASS" = "EXIT_137_SIGKILL" ]; then
|
||||||
|
TIMING_STATUS="NOT_VALID_EXIT_137_SIGKILL"
|
||||||
|
elif [ "$PRIORITY_FAIL_LINES" -ge 1 ]; then
|
||||||
|
TIMING_STATUS="NOT_VALID_PRIORITY_NOT_APPLIED"
|
||||||
|
else
|
||||||
|
TIMING_STATUS="UNASSESSED_DT_SEMANTICS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "\nFUNCTIONAL_STATUS=%s\n" "$FUNCTIONAL_STATUS"
|
||||||
|
printf "TIMING_STATUS=%s\n" "$TIMING_STATUS"
|
||||||
|
case "$FUNCTIONAL_STATUS:$TIMING_STATUS" in
|
||||||
|
PASS:NOT_VALID_*)
|
||||||
|
printf "FUNCTIONAL_PASS_TIMING_NOT_VALID\n"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
printf "\n============================================================\n"
|
||||||
|
printf "CLASSIFICAZIONE\n"
|
||||||
|
printf "============================================================\n"
|
||||||
|
|
||||||
|
if [ "$FUNCTIONAL_OK" -ne 1 ]; then
|
||||||
|
printf "[NON DIMOSTRATO] Funzionamento S02 e registrazione binaria non sufficientemente provati.\n"
|
||||||
|
printf "[DA VERIFICARE] Dettaglio parser binario:\n"
|
||||||
|
cat -- "$BINARY_REPORT"
|
||||||
|
exit 20
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "[VERIFICATO] Funzionamento S02 e registrazione binaria dimostrati.\n"
|
||||||
|
|
||||||
|
if [ "$SIGINT_LINES" -ge 1 ] &&
|
||||||
|
[ "$STOP_OK_LINES" -ge 1 ] &&
|
||||||
|
[ "$TERMINATED_LINES" -ge 1 ] &&
|
||||||
|
[ "$FATAL_ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$OS_ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$INITIALISATION_ERROR_LINES" -eq 0 ]; then
|
||||||
|
printf "[VERIFICATO] Shutdown privo di Error, OSError e FatalError.\n"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
KNOWN_SHUTDOWN_TOTAL=$((DOUBLE_STOP_LINES + ASYNC_EVENTSEM_CLOSE_LINES + PTHREAD_MUTEX_DESTROY_LINES))
|
||||||
|
|
||||||
|
if [ "$SIGINT_LINES" -ge 1 ] &&
|
||||||
|
[ "$STOP_OK_LINES" -ge 1 ] &&
|
||||||
|
[ "$TERMINATED_LINES" -ge 1 ] &&
|
||||||
|
[ "$KNOWN_SHUTDOWN_TOTAL" -ge 1 ] &&
|
||||||
|
[ "$UNCLASSIFIED_FATAL_LINES" -eq 0 ] &&
|
||||||
|
[ "$UNCLASSIFIED_OS_ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$INITIALISATION_ERROR_LINES" -eq 0 ]; then
|
||||||
|
printf "[DA VERIFICARE] Funzionalità riuscita con sole anomalie di shutdown già classificate.\n"
|
||||||
|
exit 10
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "[DA VERIFICARE] Funzionalità riuscita, ma sono presenti anomalie di shutdown non classificate.\n"
|
||||||
|
exit 11
|
||||||
+185
@@ -0,0 +1,185 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Export the approved S03 binary record layout to a derived CSV artifact."""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import csv
|
||||||
|
import hashlib
|
||||||
|
import os
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
UINT32_TYPE_HEX = "0408"
|
||||||
|
SIGNAL_HEADER_BYTES = 38
|
||||||
|
EXPECTED_SIGNALS = (
|
||||||
|
("Counter", 1),
|
||||||
|
("Time", 1),
|
||||||
|
("State1_Thread1_CycleTime", 1),
|
||||||
|
("SentinelScalarA", 1),
|
||||||
|
("SentinelScalarB", 1),
|
||||||
|
("SentinelVector", 3),
|
||||||
|
)
|
||||||
|
EXPECTED_HEADER_BYTES = 4 + len(EXPECTED_SIGNALS) * SIGNAL_HEADER_BYTES
|
||||||
|
EXPECTED_RECORD_BYTES = 32
|
||||||
|
CSV_COLUMNS = (
|
||||||
|
"Counter",
|
||||||
|
"Time",
|
||||||
|
"CycleTime",
|
||||||
|
"SentinelScalarA",
|
||||||
|
"SentinelScalarB",
|
||||||
|
"SentinelVector0",
|
||||||
|
"SentinelVector1",
|
||||||
|
"SentinelVector2",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ExportError(Exception):
|
||||||
|
"""A fail-closed binary or publication error."""
|
||||||
|
|
||||||
|
|
||||||
|
def decode_name(raw):
|
||||||
|
try:
|
||||||
|
return raw.split(b"\x00", 1)[0].decode("ascii")
|
||||||
|
except UnicodeDecodeError as exc:
|
||||||
|
raise ExportError("NON_ASCII_SIGNAL_NAME") from exc
|
||||||
|
|
||||||
|
|
||||||
|
def read_records(binary_path):
|
||||||
|
try:
|
||||||
|
data = binary_path.read_bytes()
|
||||||
|
except OSError as exc:
|
||||||
|
raise ExportError(f"BINARY_READ_FAILED:{exc}") from exc
|
||||||
|
|
||||||
|
if len(data) < EXPECTED_HEADER_BYTES:
|
||||||
|
raise ExportError(
|
||||||
|
f"HEADER_TOO_SMALL:EXPECTED_{EXPECTED_HEADER_BYTES}:OBSERVED_{len(data)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
signal_count = struct.unpack_from("<I", data, 0)[0]
|
||||||
|
if signal_count != len(EXPECTED_SIGNALS):
|
||||||
|
raise ExportError(
|
||||||
|
f"SIGNAL_COUNT_MISMATCH:EXPECTED_{len(EXPECTED_SIGNALS)}:OBSERVED_{signal_count}"
|
||||||
|
)
|
||||||
|
|
||||||
|
offset = 4
|
||||||
|
observed = []
|
||||||
|
for _ in range(signal_count):
|
||||||
|
type_hex = data[offset : offset + 2].hex()
|
||||||
|
offset += 2
|
||||||
|
name = decode_name(data[offset : offset + 32])
|
||||||
|
offset += 32
|
||||||
|
elements = struct.unpack_from("<I", data, offset)[0]
|
||||||
|
offset += 4
|
||||||
|
observed.append((name, type_hex, elements))
|
||||||
|
|
||||||
|
expected = tuple(
|
||||||
|
(name, UINT32_TYPE_HEX, elements) for name, elements in EXPECTED_SIGNALS
|
||||||
|
)
|
||||||
|
if tuple(observed) != expected:
|
||||||
|
raise ExportError(
|
||||||
|
"HEADER_CONTRACT_MISMATCH:"
|
||||||
|
f"EXPECTED_{expected!r}:OBSERVED_{tuple(observed)!r}"
|
||||||
|
)
|
||||||
|
if offset != EXPECTED_HEADER_BYTES:
|
||||||
|
raise ExportError(
|
||||||
|
f"HEADER_SIZE_MISMATCH:EXPECTED_{EXPECTED_HEADER_BYTES}:OBSERVED_{offset}"
|
||||||
|
)
|
||||||
|
|
||||||
|
payload = data[offset:]
|
||||||
|
remainder = len(payload) % EXPECTED_RECORD_BYTES
|
||||||
|
if remainder != 0:
|
||||||
|
raise ExportError(
|
||||||
|
f"PAYLOAD_ALIGNMENT_ERROR:REMAINDER_{remainder}:RECORD_{EXPECTED_RECORD_BYTES}"
|
||||||
|
)
|
||||||
|
if not payload:
|
||||||
|
raise ExportError("NO_COMPLETE_RECORDS")
|
||||||
|
|
||||||
|
records = [
|
||||||
|
struct.unpack_from("<8I", payload, record_offset)
|
||||||
|
for record_offset in range(0, len(payload), EXPECTED_RECORD_BYTES)
|
||||||
|
]
|
||||||
|
return data, records
|
||||||
|
|
||||||
|
|
||||||
|
def write_csv_atomic(output_path, records):
|
||||||
|
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
if output_path.exists() and not output_path.is_file():
|
||||||
|
raise ExportError(f"OUTPUT_NOT_REGULAR_FILE:{output_path}")
|
||||||
|
|
||||||
|
descriptor, temporary_name = tempfile.mkstemp(
|
||||||
|
prefix=f".{output_path.name}.",
|
||||||
|
suffix=".tmp",
|
||||||
|
dir=output_path.parent,
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
temporary_path = Path(temporary_name)
|
||||||
|
try:
|
||||||
|
with os.fdopen(descriptor, "w", encoding="utf-8", newline="") as stream:
|
||||||
|
writer = csv.writer(stream, lineterminator="\n")
|
||||||
|
writer.writerow(CSV_COLUMNS)
|
||||||
|
writer.writerows(records)
|
||||||
|
stream.flush()
|
||||||
|
os.fsync(stream.fileno())
|
||||||
|
|
||||||
|
if output_path.exists():
|
||||||
|
if temporary_path.read_bytes() == output_path.read_bytes():
|
||||||
|
temporary_path.unlink()
|
||||||
|
return "ALREADY_VALID"
|
||||||
|
raise ExportError(f"OUTPUT_EXISTS_BUT_DIFFERS:{output_path}")
|
||||||
|
|
||||||
|
os.chmod(temporary_path, 0o644)
|
||||||
|
os.replace(temporary_path, output_path)
|
||||||
|
return "CREATED"
|
||||||
|
finally:
|
||||||
|
if temporary_path.exists():
|
||||||
|
temporary_path.unlink()
|
||||||
|
|
||||||
|
|
||||||
|
def sha256_bytes(data):
|
||||||
|
return hashlib.sha256(data).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description=(
|
||||||
|
"Create a human-readable CSV from the S03 FileWriter binary. "
|
||||||
|
"The binary remains the primary evidence."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
parser.add_argument("binary", type=Path)
|
||||||
|
parser.add_argument("csv_output", type=Path, nargs="?")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
output_path = args.csv_output
|
||||||
|
if output_path is None:
|
||||||
|
output_path = args.binary.with_suffix(".csv")
|
||||||
|
|
||||||
|
try:
|
||||||
|
binary_data, records = read_records(args.binary)
|
||||||
|
publication = write_csv_atomic(output_path, records)
|
||||||
|
csv_data = output_path.read_bytes()
|
||||||
|
except ExportError as exc:
|
||||||
|
print("CSV_EXPORT_STATUS=FAIL")
|
||||||
|
print(f"CSV_EXPORT_ERROR={exc}")
|
||||||
|
return 40
|
||||||
|
except OSError as exc:
|
||||||
|
print("CSV_EXPORT_STATUS=FAIL")
|
||||||
|
print(f"CSV_EXPORT_ERROR=OS_ERROR:{exc}")
|
||||||
|
return 41
|
||||||
|
|
||||||
|
print("PRIMARY_EVIDENCE=s03_output.bin")
|
||||||
|
print("DERIVED_ARTIFACT=s03_output.csv")
|
||||||
|
print(f"BINARY_PATH={args.binary}")
|
||||||
|
print(f"BINARY_SHA256={sha256_bytes(binary_data)}")
|
||||||
|
print(f"CSV_PATH={output_path}")
|
||||||
|
print(f"CSV_SHA256={sha256_bytes(csv_data)}")
|
||||||
|
print(f"CSV_RECORD_COUNT={len(records)}")
|
||||||
|
print(f"CSV_PUBLICATION={publication}")
|
||||||
|
print("CSV_EXPORT_STATUS=PASS")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
+414
@@ -0,0 +1,414 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -u
|
||||||
|
|
||||||
|
MINIMUM_SAMPLES="50"
|
||||||
|
EXPECTED_BASELINE_PARSER_SHA256="91c4d66770197e1986ed91eb6a4870e7da7df5a522ffdf4329b6d9250f238307"
|
||||||
|
EXPECTED_TEST_CONFIG_SHA256="d037561b32760fbd0e2aec9f1eefc5efda27b1918eca4742c89092a8a2f7e92e"
|
||||||
|
EXPECTED_DIAGNOSTIC_CONFIG_SHA256="cd999ff249452298d650a22c8fe5b0b03bf48c0735f4630befdec8209cbb13a3"
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PACKAGE_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||||
|
PARSER="${S03_BASELINE_PARSER:-$PACKAGE_ROOT/baseline/parse_s03_binary.py}"
|
||||||
|
CONFIG_VERIFIER="$SCRIPT_DIR/verify_s03h1_config.py"
|
||||||
|
|
||||||
|
MODE="NOT_PROVIDED"
|
||||||
|
MODE_STATUS="NOT_DEMONSTRATED"
|
||||||
|
PROFILE_CONFIG_STATUS="NOT_DEMONSTRATED"
|
||||||
|
OBSERVABILITY_STATUS="NOT_DEMONSTRATED"
|
||||||
|
FUNCTIONAL_STATUS="NOT_DEMONSTRATED"
|
||||||
|
SEMANTIC_STATUS="NOT_DEMONSTRATED"
|
||||||
|
TIMING_STATUS="NOT_EVALUATED"
|
||||||
|
MEASUREMENT_ELIGIBILITY="NO"
|
||||||
|
|
||||||
|
emit_contract() {
|
||||||
|
printf "MODE=%s\n" "$MODE"
|
||||||
|
printf "MODE_STATUS=%s\n" "$MODE_STATUS"
|
||||||
|
printf "PROFILE_CONFIG_STATUS=%s\n" "$PROFILE_CONFIG_STATUS"
|
||||||
|
printf "OBSERVABILITY_STATUS=%s\n" "$OBSERVABILITY_STATUS"
|
||||||
|
printf "FUNCTIONAL_STATUS=%s\n" "$FUNCTIONAL_STATUS"
|
||||||
|
printf "SEMANTIC_STATUS=%s\n" "$SEMANTIC_STATUS"
|
||||||
|
printf "TIMING_STATUS=%s\n" "$TIMING_STATUS"
|
||||||
|
printf "MEASUREMENT_ELIGIBILITY=%s\n" "$MEASUREMENT_ELIGIBILITY"
|
||||||
|
}
|
||||||
|
|
||||||
|
fail_early() {
|
||||||
|
code="$1"
|
||||||
|
shift
|
||||||
|
printf "[NON DIMOSTRATO] %s\n" "$*" >&2
|
||||||
|
emit_contract
|
||||||
|
printf "VALIDATION_RESULT=FAIL_REQUIRED_INPUT\n"
|
||||||
|
exit "$code"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$#" -ne 2 ]; then
|
||||||
|
printf "Uso: %s TEST|DIAGNOSTIC <directory-run|run.log>\n" "$0" >&2
|
||||||
|
emit_contract
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
MODE="$1"
|
||||||
|
case "$MODE" in
|
||||||
|
TEST)
|
||||||
|
EXPECTED_PROFILE_CONFIG_SHA256="$EXPECTED_TEST_CONFIG_SHA256"
|
||||||
|
;;
|
||||||
|
DIAGNOSTIC)
|
||||||
|
EXPECTED_PROFILE_CONFIG_SHA256="$EXPECTED_DIAGNOSTIC_CONFIG_SHA256"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
MODE_STATUS="FAIL"
|
||||||
|
PROFILE_CONFIG_STATUS="FAIL"
|
||||||
|
OBSERVABILITY_STATUS="FAIL"
|
||||||
|
printf "UNKNOWN_MODE=%s\n" "$MODE" >&2
|
||||||
|
emit_contract
|
||||||
|
printf "VALIDATION_RESULT=FAIL_UNKNOWN_MODE\n"
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
INPUT_PATH="$2"
|
||||||
|
if [ -d "$INPUT_PATH" ]; then
|
||||||
|
RUN_DIR="$(cd "$INPUT_PATH" && pwd)"
|
||||||
|
RUN_LOG="$RUN_DIR/run.log"
|
||||||
|
elif [ -f "$INPUT_PATH" ]; then
|
||||||
|
RUN_LOG="$(cd "$(dirname "$INPUT_PATH")" && pwd)/$(basename "$INPUT_PATH")"
|
||||||
|
RUN_DIR="$(dirname "$RUN_LOG")"
|
||||||
|
else
|
||||||
|
fail_early 21 "Percorso di validazione non trovato: $INPUT_PATH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
RUN_CONFIG="$RUN_DIR/configuration.marte"
|
||||||
|
OUTPUT_FILE="$RUN_DIR/s03_output.bin"
|
||||||
|
RUNNER_SUMMARY="$RUN_DIR/runner_summary.txt"
|
||||||
|
RUN_HASHES="$RUN_DIR/hashes.sha256"
|
||||||
|
MODE_FILE="$RUN_DIR/s03h1_mode.txt"
|
||||||
|
|
||||||
|
if [ ! -f "$PARSER" ]; then
|
||||||
|
fail_early 21 "Parser baseline S03 assente: $PARSER"
|
||||||
|
fi
|
||||||
|
PARSER_SHA256="$(sha256sum -- "$PARSER" | awk '{print $1}')"
|
||||||
|
if [ "$PARSER_SHA256" != "$EXPECTED_BASELINE_PARSER_SHA256" ]; then
|
||||||
|
fail_early 21 "Parser baseline S03 con hash inatteso: $PARSER_SHA256"
|
||||||
|
fi
|
||||||
|
if [ ! -x "$CONFIG_VERIFIER" ]; then
|
||||||
|
fail_early 21 "Verificatore configurazione assente o non eseguibile: $CONFIG_VERIFIER"
|
||||||
|
fi
|
||||||
|
|
||||||
|
for required_file in \
|
||||||
|
"$RUN_LOG" \
|
||||||
|
"$RUN_CONFIG" \
|
||||||
|
"$OUTPUT_FILE" \
|
||||||
|
"$RUNNER_SUMMARY" \
|
||||||
|
"$RUN_HASHES" \
|
||||||
|
"$MODE_FILE"
|
||||||
|
do
|
||||||
|
if [ ! -f "$required_file" ]; then
|
||||||
|
fail_early 21 "File richiesto assente: $required_file"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ ! -s "$RUN_HASHES" ]; then
|
||||||
|
fail_early 21 "Manifest hash assente o vuoto: $RUN_HASHES"
|
||||||
|
fi
|
||||||
|
|
||||||
|
count_lines() {
|
||||||
|
pattern="$1"
|
||||||
|
file="$2"
|
||||||
|
grep -Ec "$pattern" "$file" || true
|
||||||
|
}
|
||||||
|
|
||||||
|
report_value() {
|
||||||
|
key="$1"
|
||||||
|
file="$2"
|
||||||
|
sed -n "s/^${key}=//p" "$file" | tail -n 1
|
||||||
|
}
|
||||||
|
|
||||||
|
MODE_DECLARATION_COUNT="$(count_lines "^MODE=${MODE}$" "$MODE_FILE")"
|
||||||
|
SCENARIO_DECLARATION_COUNT="$(count_lines '^SCENARIO=S03H1$' "$MODE_FILE")"
|
||||||
|
CONFIG_HASH_DECLARATION_COUNT="$(
|
||||||
|
count_lines "^CANDIDATE_CONFIG_SHA256=${EXPECTED_PROFILE_CONFIG_SHA256}$" "$MODE_FILE"
|
||||||
|
)"
|
||||||
|
INSTALLATION_GATE_DECLARATION_COUNT="$(
|
||||||
|
count_lines '^S03_H1_INSTALLATION_AUTHORIZED=NO$' "$MODE_FILE"
|
||||||
|
)"
|
||||||
|
if [ "$MODE_DECLARATION_COUNT" -eq 1 ] &&
|
||||||
|
[ "$SCENARIO_DECLARATION_COUNT" -eq 1 ] &&
|
||||||
|
[ "$CONFIG_HASH_DECLARATION_COUNT" -eq 1 ] &&
|
||||||
|
[ "$INSTALLATION_GATE_DECLARATION_COUNT" -eq 1 ]; then
|
||||||
|
MODE_STATUS="PASS"
|
||||||
|
else
|
||||||
|
MODE_STATUS="FAIL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
START_LINES="$(count_lines '^\[Information - RealTimeLoader\.cpp:[0-9]+\]: Started application in state State1[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
APPLICATION_START_LINES="$(count_lines '^\[Information - MARTeApp\.cpp:[0-9]+\]: Application starting[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
FILE_OPEN_LINES="$(count_lines '^\[Information - FileWriter\.cpp:[0-9]+\]: Going to open file with name ' "$RUN_LOG")"
|
||||||
|
SIGINT_LINES="$(count_lines '^\[Information - Bootstrap\.cpp:[0-9]+\]: Application recieved SIGINT\.[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
STOP_OK_LINES="$(count_lines '^\[Information - Bootstrap\.cpp:[0-9]+\]: Application successfully stopped\.[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
TERMINATED_LINES="$(count_lines '^\[NoError - MARTeApp\.cpp:[0-9]+\]: Application terminated[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
|
||||||
|
STARTUP_ERROR_LINES="$(count_lines 'Failed dlopen|Failed CreateByName|Failed to Initialise object|Failed to initialise the ObjectRegistryDatabase|Could not Initialise the loader' "$RUN_LOG")"
|
||||||
|
FATAL_ERROR_LINES="$(count_lines '^\[FatalError ' "$RUN_LOG")"
|
||||||
|
OS_ERROR_LINES="$(count_lines '^\[OSError ' "$RUN_LOG")"
|
||||||
|
ERROR_LINES="$(count_lines '^\[Error ' "$RUN_LOG")"
|
||||||
|
INITIALISATION_ERROR_LINES="$(count_lines '^\[InitialisationEr ' "$RUN_LOG")"
|
||||||
|
WARNING_LINES="$(count_lines '^\[Warning ' "$RUN_LOG")"
|
||||||
|
|
||||||
|
PRIORITY_CLIP_LINES="$(count_lines '^\[Warning - Threads\.cpp:[0-9]+\]: Requested a thread priority that is higher than ' "$RUN_LOG")"
|
||||||
|
PRIORITY_FAIL_LINES="$(count_lines '^\[Warning - Threads\.cpp:[0-9]+\]: Failed to change the thread priority' "$RUN_LOG")"
|
||||||
|
LINUX_TIMER_DEFAULT_WARNING_LINES="$(count_lines '^\[Warning - LinuxTimer\.cpp:[0-9]+\]: (ExecutionMode|CPUMask|StackSize) not specified using: ' "$RUN_LOG")"
|
||||||
|
CONFIG_DB_NODE_WARNING_LINES="$(count_lines '^\[Warning - MARTeApp\.cpp:[0-9]+\]: \[ConfigurationDatabaseNode\] - instances: [0-9]+[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
|
||||||
|
UNCLASSIFIED_WARNING_LINES=$((
|
||||||
|
WARNING_LINES -
|
||||||
|
PRIORITY_CLIP_LINES -
|
||||||
|
PRIORITY_FAIL_LINES -
|
||||||
|
LINUX_TIMER_DEFAULT_WARNING_LINES -
|
||||||
|
CONFIG_DB_NODE_WARNING_LINES
|
||||||
|
))
|
||||||
|
if [ "$UNCLASSIFIED_WARNING_LINES" -lt 0 ]; then
|
||||||
|
UNCLASSIFIED_WARNING_LINES=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
DOUBLE_STOP_LINES="$(count_lines '^\[FatalError - RealTimeApplication\.cpp:[0-9]+\]: Could not stop the RealTimeApplication\. Was it ever started\?[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
ASYNC_EVENTSEM_CLOSE_LINES="$(count_lines '^\[FatalError - MemoryMapAsyncOutputBroker\.cpp:[0-9]+\]: Could not Close the EventSem\.[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
PTHREAD_MUTEX_DESTROY_LINES="$(count_lines '^\[OSError - EventSem\.cpp:[0-9]+\]: Error: pthread_mutex_destroy\(\)[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
|
||||||
|
UNCLASSIFIED_FATAL_LINES=$((FATAL_ERROR_LINES - DOUBLE_STOP_LINES - ASYNC_EVENTSEM_CLOSE_LINES))
|
||||||
|
UNCLASSIFIED_OS_ERROR_LINES=$((OS_ERROR_LINES - PTHREAD_MUTEX_DESTROY_LINES))
|
||||||
|
if [ "$UNCLASSIFIED_FATAL_LINES" -lt 0 ]; then
|
||||||
|
UNCLASSIFIED_FATAL_LINES=0
|
||||||
|
fi
|
||||||
|
if [ "$UNCLASSIFIED_OS_ERROR_LINES" -lt 0 ]; then
|
||||||
|
UNCLASSIFIED_OS_ERROR_LINES=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
LOGGER_SIGNAL_LINES="$(count_lines '^\[Information - LoggerBroker\.cpp:[0-9]+\]: (Counter|Time|State1_Thread1_CycleTime|SentinelScalarA|SentinelScalarB|SentinelVector) \[[0-9]+:[0-9]+\]:' "$RUN_LOG")"
|
||||||
|
LOGGER_COUNTER_LINES="$(count_lines '^\[Information - LoggerBroker\.cpp:[0-9]+\]: Counter \[0:0\]:' "$RUN_LOG")"
|
||||||
|
LOGGER_TIME_LINES="$(count_lines '^\[Information - LoggerBroker\.cpp:[0-9]+\]: Time \[0:0\]:' "$RUN_LOG")"
|
||||||
|
LOGGER_CYCLE_TIME_LINES="$(count_lines '^\[Information - LoggerBroker\.cpp:[0-9]+\]: State1_Thread1_CycleTime \[0:0\]:' "$RUN_LOG")"
|
||||||
|
LOGGER_SCALAR_A_LINES="$(count_lines '^\[Information - LoggerBroker\.cpp:[0-9]+\]: SentinelScalarA \[0:0\]:' "$RUN_LOG")"
|
||||||
|
LOGGER_SCALAR_B_LINES="$(count_lines '^\[Information - LoggerBroker\.cpp:[0-9]+\]: SentinelScalarB \[0:0\]:' "$RUN_LOG")"
|
||||||
|
LOGGER_VECTOR_LINES="$(count_lines '^\[Information - LoggerBroker\.cpp:[0-9]+\]: SentinelVector \[0:2\]:' "$RUN_LOG")"
|
||||||
|
|
||||||
|
case "$MODE" in
|
||||||
|
TEST)
|
||||||
|
if [ "$LOGGER_SIGNAL_LINES" -eq 0 ] &&
|
||||||
|
[ "$LOGGER_COUNTER_LINES" -eq 0 ] &&
|
||||||
|
[ "$LOGGER_TIME_LINES" -eq 0 ] &&
|
||||||
|
[ "$LOGGER_CYCLE_TIME_LINES" -eq 0 ] &&
|
||||||
|
[ "$LOGGER_SCALAR_A_LINES" -eq 0 ] &&
|
||||||
|
[ "$LOGGER_SCALAR_B_LINES" -eq 0 ] &&
|
||||||
|
[ "$LOGGER_VECTOR_LINES" -eq 0 ]; then
|
||||||
|
OBSERVABILITY_STATUS="PASS"
|
||||||
|
else
|
||||||
|
OBSERVABILITY_STATUS="FAIL"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
DIAGNOSTIC)
|
||||||
|
if [ "$LOGGER_COUNTER_LINES" -ge 1 ] &&
|
||||||
|
[ "$LOGGER_TIME_LINES" -ge 1 ] &&
|
||||||
|
[ "$LOGGER_CYCLE_TIME_LINES" -ge 1 ] &&
|
||||||
|
[ "$LOGGER_SCALAR_A_LINES" -ge 1 ] &&
|
||||||
|
[ "$LOGGER_SCALAR_B_LINES" -ge 1 ] &&
|
||||||
|
[ "$LOGGER_VECTOR_LINES" -ge 1 ]; then
|
||||||
|
OBSERVABILITY_STATUS="PASS"
|
||||||
|
else
|
||||||
|
OBSERVABILITY_STATUS="FAIL"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CONFIG_REPORT="$(mktemp "${TMPDIR:-/tmp}/s03h1_validator_config_XXXXXX.log")" || exit 22
|
||||||
|
BINARY_REPORT="$(mktemp "${TMPDIR:-/tmp}/s03h1_validator_binary_XXXXXX.log")" || exit 22
|
||||||
|
HASH_REPORT="$(mktemp "${TMPDIR:-/tmp}/s03h1_validator_hashes_XXXXXX.log")" || exit 22
|
||||||
|
trap 'rm -f -- "$CONFIG_REPORT" "$BINARY_REPORT" "$HASH_REPORT"' EXIT HUP INT TERM
|
||||||
|
|
||||||
|
EXPECTED_FILENAME="$RUN_DIR/s03_output.bin"
|
||||||
|
PYTHONHASHSEED=0 "$CONFIG_VERIFIER" \
|
||||||
|
"$MODE" \
|
||||||
|
"$RUN_CONFIG" \
|
||||||
|
"$EXPECTED_FILENAME" \
|
||||||
|
>"$CONFIG_REPORT" 2>&1
|
||||||
|
CONFIG_RC=$?
|
||||||
|
PROFILE_CONFIG_STATUS="$(
|
||||||
|
report_value CONFIG_PROFILE_VERIFICATION_STATUS "$CONFIG_REPORT"
|
||||||
|
)"
|
||||||
|
if [ -z "$PROFILE_CONFIG_STATUS" ]; then
|
||||||
|
PROFILE_CONFIG_STATUS="FAIL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
PYTHONHASHSEED=0 python3 "$PARSER" "$OUTPUT_FILE" --min-samples "$MINIMUM_SAMPLES" \
|
||||||
|
>"$BINARY_REPORT" 2>&1
|
||||||
|
PARSER_RC=$?
|
||||||
|
|
||||||
|
sha256sum -c --strict "$RUN_HASHES" >"$HASH_REPORT" 2>&1
|
||||||
|
HASH_RC=$?
|
||||||
|
|
||||||
|
FUNCTIONAL_BINARY_STATUS="$(report_value FUNCTIONAL_BINARY_STATUS "$BINARY_REPORT")"
|
||||||
|
SEMANTIC_BINARY_STATUS="$(report_value SEMANTIC_BINARY_STATUS "$BINARY_REPORT")"
|
||||||
|
BINARY_STATUS="$(report_value BINARY_STATUS "$BINARY_REPORT")"
|
||||||
|
FIRST_ERROR_CODE="$(report_value FIRST_ERROR_CODE "$BINARY_REPORT")"
|
||||||
|
PROFILE_ERROR_CODE="$(report_value PROFILE_ERROR_CODE "$CONFIG_REPORT")"
|
||||||
|
COMPLETE_SAMPLE_COUNT="$(report_value COMPLETE_SAMPLE_COUNT "$BINARY_REPORT")"
|
||||||
|
HEADER_BYTES="$(report_value OBSERVED_HEADER_BYTES "$BINARY_REPORT")"
|
||||||
|
RECORD_BYTES="$(report_value OBSERVED_RECORD_BYTES_FROM_HEADER "$BINARY_REPORT")"
|
||||||
|
PAYLOAD_BYTES="$(report_value PAYLOAD_BYTES "$BINARY_REPORT")"
|
||||||
|
PAYLOAD_REMAINDER_BYTES="$(report_value PAYLOAD_REMAINDER_BYTES "$BINARY_REPORT")"
|
||||||
|
|
||||||
|
MARTE_EXIT_CODE="$(sed -n 's/^Exit code MARTe:[[:space:]]*//p' "$RUNNER_SUMMARY" | tail -n 1)"
|
||||||
|
TEE_EXIT_CODE="$(sed -n 's/^Exit code tee:[[:space:]]*//p' "$RUNNER_SUMMARY" | tail -n 1)"
|
||||||
|
if [ -z "$MARTE_EXIT_CODE" ]; then
|
||||||
|
MARTE_EXIT_CODE="NOT_AVAILABLE"
|
||||||
|
fi
|
||||||
|
if [ -z "$TEE_EXIT_CODE" ]; then
|
||||||
|
TEE_EXIT_CODE="NOT_AVAILABLE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$MARTE_EXIT_CODE" in
|
||||||
|
137)
|
||||||
|
TIMING_STATUS="NOT_VALID_EXIT_137_SIGKILL"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [ "$PRIORITY_FAIL_LINES" -ge 1 ]; then
|
||||||
|
TIMING_STATUS="NOT_VALID_PRIORITY_NOT_APPLIED"
|
||||||
|
else
|
||||||
|
TIMING_STATUS="UNASSESSED_DT_SEMANTICS"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
FUNCTIONAL_OK=0
|
||||||
|
if [ "$START_LINES" -ge 1 ] &&
|
||||||
|
[ "$APPLICATION_START_LINES" -ge 1 ] &&
|
||||||
|
[ "$FILE_OPEN_LINES" -ge 1 ] &&
|
||||||
|
[ "$STARTUP_ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$MODE_STATUS" = "PASS" ] &&
|
||||||
|
[ "$CONFIG_RC" -eq 0 ] &&
|
||||||
|
[ "$PROFILE_CONFIG_STATUS" = "PASS" ] &&
|
||||||
|
[ "$OBSERVABILITY_STATUS" = "PASS" ] &&
|
||||||
|
[ "$FUNCTIONAL_BINARY_STATUS" = "PASS" ] &&
|
||||||
|
[ "$HASH_RC" -eq 0 ] &&
|
||||||
|
[ "$TEE_EXIT_CODE" = "0" ] &&
|
||||||
|
[ "$UNCLASSIFIED_FATAL_LINES" -eq 0 ] &&
|
||||||
|
[ "$UNCLASSIFIED_OS_ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$INITIALISATION_ERROR_LINES" -eq 0 ]; then
|
||||||
|
FUNCTIONAL_OK=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$FUNCTIONAL_OK" -eq 1 ]; then
|
||||||
|
FUNCTIONAL_STATUS="PASS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$MODE_STATUS" = "PASS" ] &&
|
||||||
|
[ "$PROFILE_CONFIG_STATUS" = "PASS" ] &&
|
||||||
|
[ "$SEMANTIC_BINARY_STATUS" = "PASS" ]; then
|
||||||
|
SEMANTIC_STATUS="PASS"
|
||||||
|
elif [ "$SEMANTIC_BINARY_STATUS" = "FAIL" ]; then
|
||||||
|
SEMANTIC_STATUS="FAIL"
|
||||||
|
else
|
||||||
|
SEMANTIC_STATUS="NOT_DEMONSTRATED"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "============================================================\n"
|
||||||
|
printf "VALIDAZIONE S03-H1 - EXECUTION PROFILES\n"
|
||||||
|
printf "============================================================\n"
|
||||||
|
printf "Mode: %s\n" "$MODE"
|
||||||
|
printf "Run directory: %s\n" "$RUN_DIR"
|
||||||
|
printf "Configurazione: %s\n" "$RUN_CONFIG"
|
||||||
|
printf "File binario: %s\n" "$OUTPUT_FILE"
|
||||||
|
printf "Manifest hash: %s\n" "$RUN_HASHES"
|
||||||
|
printf "Parser baseline SHA-256: %s\n" "$PARSER_SHA256"
|
||||||
|
printf "Mode file: %s\n" "$MODE_FILE"
|
||||||
|
printf "Mode declaration count: %s\n" "$MODE_DECLARATION_COUNT"
|
||||||
|
printf "Scenario declaration count: %s\n" "$SCENARIO_DECLARATION_COUNT"
|
||||||
|
printf "Config hash declaration count: %s\n" "$CONFIG_HASH_DECLARATION_COUNT"
|
||||||
|
printf "Installation gate count: %s\n" "$INSTALLATION_GATE_DECLARATION_COUNT"
|
||||||
|
printf "Configurazione profilo: %s (rc=%s)\n" "$PROFILE_CONFIG_STATUS" "$CONFIG_RC"
|
||||||
|
printf "Errore profilo: %s\n" "${PROFILE_ERROR_CODE:-NOT_AVAILABLE}"
|
||||||
|
printf "Osservabilita' profilo: %s\n" "$OBSERVABILITY_STATUS"
|
||||||
|
printf "Logger signal lines: %s\n" "$LOGGER_SIGNAL_LINES"
|
||||||
|
printf "Logger Counter lines: %s\n" "$LOGGER_COUNTER_LINES"
|
||||||
|
printf "Logger Time lines: %s\n" "$LOGGER_TIME_LINES"
|
||||||
|
printf "Logger CycleTime lines: %s\n" "$LOGGER_CYCLE_TIME_LINES"
|
||||||
|
printf "Logger ScalarA lines: %s\n" "$LOGGER_SCALAR_A_LINES"
|
||||||
|
printf "Logger ScalarB lines: %s\n" "$LOGGER_SCALAR_B_LINES"
|
||||||
|
printf "Logger Vector[3] lines: %s\n" "$LOGGER_VECTOR_LINES"
|
||||||
|
printf "Verifica manifest hash: %s (rc=%s)\n" "$( [ "$HASH_RC" -eq 0 ] && printf PASS || printf FAIL )" "$HASH_RC"
|
||||||
|
printf "Parser binario: %s (rc=%s)\n" "${BINARY_STATUS:-NOT_AVAILABLE}" "$PARSER_RC"
|
||||||
|
printf "Primo errore parser: %s\n" "${FIRST_ERROR_CODE:-NOT_AVAILABLE}"
|
||||||
|
printf "Header osservato: %s byte\n" "${HEADER_BYTES:-NOT_AVAILABLE}"
|
||||||
|
printf "Record da header: %s byte\n" "${RECORD_BYTES:-NOT_AVAILABLE}"
|
||||||
|
printf "Payload: %s byte\n" "${PAYLOAD_BYTES:-NOT_AVAILABLE}"
|
||||||
|
printf "Residuo payload: %s byte\n" "${PAYLOAD_REMAINDER_BYTES:-NOT_AVAILABLE}"
|
||||||
|
printf "Campioni completi: %s\n" "${COMPLETE_SAMPLE_COUNT:-NOT_AVAILABLE}"
|
||||||
|
printf "Avvii State1: %s\n" "$START_LINES"
|
||||||
|
printf "Application starting: %s\n" "$APPLICATION_START_LINES"
|
||||||
|
printf "Aperture FileWriter: %s\n" "$FILE_OPEN_LINES"
|
||||||
|
printf "Exit code MARTe: %s\n" "$MARTE_EXIT_CODE"
|
||||||
|
printf "Exit code tee: %s\n" "$TEE_EXIT_CODE"
|
||||||
|
printf "Warning priorita' non applic.: %s\n" "$PRIORITY_FAIL_LINES"
|
||||||
|
printf "Warning non classificati: %s\n" "$UNCLASSIFIED_WARNING_LINES"
|
||||||
|
printf "FatalError non classificati: %s\n" "$UNCLASSIFIED_FATAL_LINES"
|
||||||
|
printf "OSError non classificati: %s\n" "$UNCLASSIFIED_OS_ERROR_LINES"
|
||||||
|
printf "Error non classificati: %s\n" "$ERROR_LINES"
|
||||||
|
printf "InitialisationError: %s\n" "$INITIALISATION_ERROR_LINES"
|
||||||
|
printf "UNCLASSIFIED_WARNING_LINES=%s\n" "$UNCLASSIFIED_WARNING_LINES"
|
||||||
|
printf "LOGGER_SIGNAL_LINES=%s\n" "$LOGGER_SIGNAL_LINES"
|
||||||
|
printf "LOGGER_COUNTER_LINES=%s\n" "$LOGGER_COUNTER_LINES"
|
||||||
|
printf "LOGGER_TIME_LINES=%s\n" "$LOGGER_TIME_LINES"
|
||||||
|
printf "LOGGER_CYCLE_TIME_LINES=%s\n" "$LOGGER_CYCLE_TIME_LINES"
|
||||||
|
printf "LOGGER_SCALAR_A_LINES=%s\n" "$LOGGER_SCALAR_A_LINES"
|
||||||
|
printf "LOGGER_SCALAR_B_LINES=%s\n" "$LOGGER_SCALAR_B_LINES"
|
||||||
|
printf "LOGGER_VECTOR_LINES=%s\n" "$LOGGER_VECTOR_LINES"
|
||||||
|
|
||||||
|
printf "\n--- DETTAGLIO CONFIGURAZIONE PROFILE-AWARE ---\n"
|
||||||
|
cat -- "$CONFIG_REPORT"
|
||||||
|
printf "\n--- DETTAGLIO PARSER BINARIO BASELINE ---\n"
|
||||||
|
cat -- "$BINARY_REPORT"
|
||||||
|
printf "\n--- VERIFICA HASH ---\n"
|
||||||
|
cat -- "$HASH_REPORT"
|
||||||
|
|
||||||
|
printf "\n--- CONTRATTO S03-H1 ---\n"
|
||||||
|
emit_contract
|
||||||
|
|
||||||
|
if [ "$FUNCTIONAL_STATUS" != "PASS" ]; then
|
||||||
|
printf "VALIDATION_RESULT=FUNCTIONAL_NOT_DEMONSTRATED\n"
|
||||||
|
exit 20
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$SEMANTIC_STATUS" != "PASS" ]; then
|
||||||
|
printf "VALIDATION_RESULT=SEMANTIC_VALIDATION_FAILED\n"
|
||||||
|
exit 20
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$SIGINT_LINES" -ge 1 ] &&
|
||||||
|
[ "$STOP_OK_LINES" -ge 1 ] &&
|
||||||
|
[ "$TERMINATED_LINES" -ge 1 ] &&
|
||||||
|
[ "$FATAL_ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$OS_ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$INITIALISATION_ERROR_LINES" -eq 0 ]; then
|
||||||
|
printf "VALIDATION_RESULT=PASS_CLEAN_SHUTDOWN\n"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
KNOWN_SHUTDOWN_TOTAL=$((
|
||||||
|
DOUBLE_STOP_LINES +
|
||||||
|
ASYNC_EVENTSEM_CLOSE_LINES +
|
||||||
|
PTHREAD_MUTEX_DESTROY_LINES
|
||||||
|
))
|
||||||
|
if [ "$SIGINT_LINES" -ge 1 ] &&
|
||||||
|
[ "$STOP_OK_LINES" -ge 1 ] &&
|
||||||
|
[ "$TERMINATED_LINES" -ge 1 ] &&
|
||||||
|
[ "$KNOWN_SHUTDOWN_TOTAL" -ge 1 ] &&
|
||||||
|
[ "$UNCLASSIFIED_FATAL_LINES" -eq 0 ] &&
|
||||||
|
[ "$UNCLASSIFIED_OS_ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$INITIALISATION_ERROR_LINES" -eq 0 ]; then
|
||||||
|
printf "VALIDATION_RESULT=PASS_KNOWN_SHUTDOWN_ANOMALY\n"
|
||||||
|
exit 10
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "VALIDATION_RESULT=PASS_UNCLASSIFIED_SHUTDOWN_ANOMALY\n"
|
||||||
|
exit 11
|
||||||
+267
@@ -0,0 +1,267 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Fail-closed, profile-aware verifier for S03-H1 runtime configurations."""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import hashlib
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
EXPECTED_PROFILE_HASHES = {
|
||||||
|
"TEST": "d037561b32760fbd0e2aec9f1eefc5efda27b1918eca4742c89092a8a2f7e92e",
|
||||||
|
"DIAGNOSTIC": "cd999ff249452298d650a22c8fe5b0b03bf48c0735f4630befdec8209cbb13a3",
|
||||||
|
}
|
||||||
|
EXPECTED_DISPLAY_CLASSES = {
|
||||||
|
"TEST": "GAMDataSource",
|
||||||
|
"DIAGNOSTIC": "LoggerDataSource",
|
||||||
|
}
|
||||||
|
EXPECTED_GAMDISPLAY_BLOCK_SHA256 = (
|
||||||
|
"13b14b504dac43df5febf230cd069c5093d951726382b1d5dee8edf43d6814d0"
|
||||||
|
)
|
||||||
|
EXPECTED_IOGAM_WRITER_BLOCK_SHA256 = (
|
||||||
|
"b3d54ad2fae08e6640bfa0be39ead9841906b4573a3b407e5ecf21340b5c5717"
|
||||||
|
)
|
||||||
|
EXPECTED_FILEWRITER_BLOCK_SHA256 = (
|
||||||
|
"0bb949b9d72fa758bdfd8b2039336bc1fda071ecf038304402032de63f4fc455"
|
||||||
|
)
|
||||||
|
PLACEHOLDER_LINE = ' Filename = "__MARTE_RUN_DIR__/s03_output.bin"'
|
||||||
|
|
||||||
|
|
||||||
|
def digest(text):
|
||||||
|
return hashlib.sha256(text.encode("utf-8")).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def extract_block(text, start_marker, end_marker):
|
||||||
|
if text.count(start_marker) != 1:
|
||||||
|
raise ValueError(f"START_MARKER_COUNT:{start_marker!r}:{text.count(start_marker)}")
|
||||||
|
start = text.index(start_marker)
|
||||||
|
try:
|
||||||
|
end = text.index(end_marker, start)
|
||||||
|
except ValueError as exc:
|
||||||
|
raise ValueError(f"END_MARKER_MISSING:{end_marker!r}") from exc
|
||||||
|
return text[start:end]
|
||||||
|
|
||||||
|
|
||||||
|
class Verification:
|
||||||
|
def __init__(self):
|
||||||
|
self.checks = {}
|
||||||
|
self.first_error = "NONE"
|
||||||
|
|
||||||
|
def check(self, name, condition, error_code):
|
||||||
|
self.checks[name] = "PASS" if condition else "FAIL"
|
||||||
|
if not condition and self.first_error == "NONE":
|
||||||
|
self.first_error = error_code
|
||||||
|
|
||||||
|
def emit(self):
|
||||||
|
for name in sorted(self.checks):
|
||||||
|
print(f"{name}={self.checks[name]}")
|
||||||
|
print(f"PROFILE_ERROR_CODE={self.first_error}")
|
||||||
|
|
||||||
|
|
||||||
|
def verify(mode, config_path, expected_filename):
|
||||||
|
report = Verification()
|
||||||
|
try:
|
||||||
|
text = config_path.read_text(encoding="utf-8")
|
||||||
|
except OSError as exc:
|
||||||
|
print("CONFIG_READ_STATUS=FAIL")
|
||||||
|
print(f"CONFIG_READ_ERROR={exc}")
|
||||||
|
print("PROFILE_ERROR_CODE=CONFIG_READ_FAILED")
|
||||||
|
print("CONFIG_PROFILE_VERIFICATION_STATUS=FAIL")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
expected_line = f' Filename = "{expected_filename}"'
|
||||||
|
filename_count = sum(1 for line in text.splitlines() if line == expected_line)
|
||||||
|
placeholder_count = text.count("__MARTE_RUN_DIR__")
|
||||||
|
|
||||||
|
canonical = text
|
||||||
|
if filename_count == 1:
|
||||||
|
canonical = text.replace(expected_line, PLACEHOLDER_LINE, 1)
|
||||||
|
|
||||||
|
canonical_hash = digest(canonical)
|
||||||
|
expected_profile_hash = EXPECTED_PROFILE_HASHES[mode]
|
||||||
|
expected_display_class = EXPECTED_DISPLAY_CLASSES[mode]
|
||||||
|
|
||||||
|
print(f"VERIFIED_MODE={mode}")
|
||||||
|
print(f"EXPECTED_FILENAME={expected_filename}")
|
||||||
|
print(f"EXPECTED_FILENAME_COUNT={filename_count}")
|
||||||
|
print(f"PLACEHOLDER_COUNT={placeholder_count}")
|
||||||
|
print(f"CANONICAL_CONFIG_SHA256={canonical_hash}")
|
||||||
|
print(f"EXPECTED_PROFILE_CONFIG_SHA256={expected_profile_hash}")
|
||||||
|
|
||||||
|
report.check(
|
||||||
|
"RUNTIME_FILENAME_STATUS",
|
||||||
|
filename_count == 1 and placeholder_count == 0,
|
||||||
|
"RUNTIME_FILENAME_MISMATCH",
|
||||||
|
)
|
||||||
|
report.check(
|
||||||
|
"GAMDISPLAY_OBJECT_STATUS",
|
||||||
|
text.count("+GAMDisplay =") == 1,
|
||||||
|
"GAMDISPLAY_OBJECT_COUNT_MISMATCH",
|
||||||
|
)
|
||||||
|
report.check(
|
||||||
|
"THREAD_ORDER_STATUS",
|
||||||
|
text.count(
|
||||||
|
"Functions = {GAMTimer SentinelProducer GAMDisplay IOGAM_Writer}"
|
||||||
|
)
|
||||||
|
== 1,
|
||||||
|
"THREAD_ORDER_MISMATCH",
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
gamdisplay = extract_block(
|
||||||
|
canonical,
|
||||||
|
" +GAMDisplay = {\n",
|
||||||
|
" +IOGAM_Writer = {\n",
|
||||||
|
)
|
||||||
|
except ValueError as exc:
|
||||||
|
print(f"GAMDISPLAY_EXTRACTION_ERROR={exc}")
|
||||||
|
gamdisplay = ""
|
||||||
|
|
||||||
|
display_checks = {
|
||||||
|
"GAMDISPLAY_CLASS_COUNT": gamdisplay.count("Class = IOGAM") == 1,
|
||||||
|
"GAMDISPLAY_COUNTER_COUNT": gamdisplay.count(
|
||||||
|
" Counter = {\n"
|
||||||
|
)
|
||||||
|
== 2,
|
||||||
|
"GAMDISPLAY_TIME_COUNT": gamdisplay.count(" Time = {\n") == 2,
|
||||||
|
"GAMDISPLAY_CYCLETIME_COUNT": gamdisplay.count(
|
||||||
|
"State1_Thread1_CycleTime ="
|
||||||
|
)
|
||||||
|
== 2,
|
||||||
|
"GAMDISPLAY_SCALAR_A_COUNT": gamdisplay.count("SentinelScalarA =") == 2,
|
||||||
|
"GAMDISPLAY_SCALAR_B_COUNT": gamdisplay.count("SentinelScalarB =") == 2,
|
||||||
|
"GAMDISPLAY_VECTOR_COUNT": gamdisplay.count("SentinelVector =") == 2,
|
||||||
|
"GAMDISPLAY_VECTOR_DIMENSION_COUNT": gamdisplay.count(
|
||||||
|
"NumberOfDimensions = 1"
|
||||||
|
)
|
||||||
|
== 2,
|
||||||
|
"GAMDISPLAY_VECTOR_ELEMENTS_COUNT": gamdisplay.count(
|
||||||
|
"NumberOfElements = 3"
|
||||||
|
)
|
||||||
|
== 2,
|
||||||
|
"GAMDISPLAY_OUTPUT_DATASOURCE_COUNT": gamdisplay.count(
|
||||||
|
"DataSource = Display"
|
||||||
|
)
|
||||||
|
== 6,
|
||||||
|
}
|
||||||
|
for name, passed in display_checks.items():
|
||||||
|
report.check(name, passed, f"{name}_MISMATCH")
|
||||||
|
|
||||||
|
gamdisplay_hash = digest(gamdisplay)
|
||||||
|
print(f"GAMDISPLAY_BLOCK_SHA256={gamdisplay_hash}")
|
||||||
|
print(
|
||||||
|
"EXPECTED_GAMDISPLAY_BLOCK_SHA256="
|
||||||
|
f"{EXPECTED_GAMDISPLAY_BLOCK_SHA256}"
|
||||||
|
)
|
||||||
|
report.check(
|
||||||
|
"GAMDISPLAY_BLOCK_STATUS",
|
||||||
|
gamdisplay_hash == EXPECTED_GAMDISPLAY_BLOCK_SHA256,
|
||||||
|
"GAMDISPLAY_BLOCK_HASH_MISMATCH",
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
writer = extract_block(
|
||||||
|
canonical,
|
||||||
|
" +IOGAM_Writer = {\n",
|
||||||
|
" }\n +Data = {\n",
|
||||||
|
)
|
||||||
|
except ValueError as exc:
|
||||||
|
print(f"IOGAM_WRITER_EXTRACTION_ERROR={exc}")
|
||||||
|
writer = ""
|
||||||
|
writer_hash = digest(writer)
|
||||||
|
print(f"IOGAM_WRITER_BLOCK_SHA256={writer_hash}")
|
||||||
|
print(
|
||||||
|
"EXPECTED_IOGAM_WRITER_BLOCK_SHA256="
|
||||||
|
f"{EXPECTED_IOGAM_WRITER_BLOCK_SHA256}"
|
||||||
|
)
|
||||||
|
report.check(
|
||||||
|
"IOGAM_WRITER_INVARIANT_STATUS",
|
||||||
|
writer_hash == EXPECTED_IOGAM_WRITER_BLOCK_SHA256,
|
||||||
|
"IOGAM_WRITER_BLOCK_HASH_MISMATCH",
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
filewriter = extract_block(
|
||||||
|
canonical,
|
||||||
|
" +FileWriter = {\n",
|
||||||
|
" }\n +States = {\n",
|
||||||
|
)
|
||||||
|
except ValueError as exc:
|
||||||
|
print(f"FILEWRITER_EXTRACTION_ERROR={exc}")
|
||||||
|
filewriter = ""
|
||||||
|
filewriter_hash = digest(filewriter)
|
||||||
|
print(f"FILEWRITER_BLOCK_SHA256={filewriter_hash}")
|
||||||
|
print(
|
||||||
|
"EXPECTED_FILEWRITER_BLOCK_SHA256="
|
||||||
|
f"{EXPECTED_FILEWRITER_BLOCK_SHA256}"
|
||||||
|
)
|
||||||
|
report.check(
|
||||||
|
"FILEWRITER_INVARIANT_STATUS",
|
||||||
|
filewriter_hash == EXPECTED_FILEWRITER_BLOCK_SHA256,
|
||||||
|
"FILEWRITER_BLOCK_HASH_MISMATCH",
|
||||||
|
)
|
||||||
|
|
||||||
|
structural_expectations = {
|
||||||
|
"CONSTANT_GAM_COUNT": (text.count("Class = ConstantGAM"), 1),
|
||||||
|
"SENTINEL_SCALAR_A_DECLARATION_COUNT": (
|
||||||
|
text.count("SentinelScalarA ="),
|
||||||
|
6,
|
||||||
|
),
|
||||||
|
"SENTINEL_SCALAR_B_DECLARATION_COUNT": (
|
||||||
|
text.count("SentinelScalarB ="),
|
||||||
|
6,
|
||||||
|
),
|
||||||
|
"SENTINEL_VECTOR_DECLARATION_COUNT": (
|
||||||
|
text.count("SentinelVector ="),
|
||||||
|
6,
|
||||||
|
),
|
||||||
|
"VECTOR_DIMENSION_COUNT": (text.count("NumberOfDimensions = 1"), 6),
|
||||||
|
"VECTOR_CARDINALITY_COUNT": (text.count("NumberOfElements = 3"), 6),
|
||||||
|
"FILEWRITER_CLASS_COUNT": (
|
||||||
|
text.count("Class = FileDataSource::FileWriter"),
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
"PLAIN_FILEWRITER_CLASS_COUNT": (text.count("Class = FileWriter"), 0),
|
||||||
|
}
|
||||||
|
for name, (observed, expected) in structural_expectations.items():
|
||||||
|
print(f"{name}={observed}")
|
||||||
|
print(f"EXPECTED_{name}={expected}")
|
||||||
|
report.check(
|
||||||
|
f"{name}_STATUS",
|
||||||
|
observed == expected,
|
||||||
|
f"{name}_MISMATCH",
|
||||||
|
)
|
||||||
|
|
||||||
|
expected_display_block = (
|
||||||
|
" +Display = {\n"
|
||||||
|
f" Class = {expected_display_class}\n"
|
||||||
|
" }\n"
|
||||||
|
)
|
||||||
|
report.check(
|
||||||
|
"DISPLAY_DATASOURCE_CLASS_STATUS",
|
||||||
|
text.count(expected_display_block) == 1,
|
||||||
|
"DISPLAY_DATASOURCE_CLASS_MISMATCH",
|
||||||
|
)
|
||||||
|
report.check(
|
||||||
|
"PROFILE_CANONICAL_HASH_STATUS",
|
||||||
|
canonical_hash == expected_profile_hash,
|
||||||
|
"PROFILE_CANONICAL_HASH_MISMATCH",
|
||||||
|
)
|
||||||
|
|
||||||
|
report.emit()
|
||||||
|
passed = all(value == "PASS" for value in report.checks.values())
|
||||||
|
print(f"CONFIG_PROFILE_VERIFICATION_STATUS={'PASS' if passed else 'FAIL'}")
|
||||||
|
return 0 if passed else 1
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("mode", choices=sorted(EXPECTED_PROFILE_HASHES))
|
||||||
|
parser.add_argument("configuration", type=Path)
|
||||||
|
parser.add_argument("expected_filename")
|
||||||
|
args = parser.parse_args()
|
||||||
|
return verify(args.mode, args.configuration, args.expected_filename)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
+508
@@ -0,0 +1,508 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -u
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
readonly MINIMUM_SAMPLES="50"
|
||||||
|
readonly EXPECTED_PARSER_SHA256="91c4d66770197e1986ed91eb6a4870e7da7df5a522ffdf4329b6d9250f238307"
|
||||||
|
readonly EXPECTED_H1_VERIFIER_SHA256="2f1c41b186bd2e79a9fb51fab0461a7a0dce104bf0852c0ec1ade2c55a017443"
|
||||||
|
readonly EXPECTED_TEST_CONFIG_SHA256="d037561b32760fbd0e2aec9f1eefc5efda27b1918eca4742c89092a8a2f7e92e"
|
||||||
|
readonly EXPECTED_DIAGNOSTIC_CONFIG_SHA256="cd999ff249452298d650a22c8fe5b0b03bf48c0735f4630befdec8209cbb13a3"
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
|
||||||
|
SUITE="$(cd -- "$SCRIPT_DIR/../.." && pwd -P)"
|
||||||
|
PARSER="$SUITE/scenarios/S03_semantic_sentinels/parse_s03_binary.py"
|
||||||
|
H1_VERIFIER="$SUITE/scenarios/S03H1_execution_profiles/verify_s03h1_config.py"
|
||||||
|
MINIMAL_VERIFIER="$SCRIPT_DIR/verify_s03h3_minimal_structure.py"
|
||||||
|
TEST_CONFIG="$SUITE/configurations/generated/S03H1/from_patcher/smoke_s03h1_execution_profiles_test_from_s02.marte"
|
||||||
|
DIAGNOSTIC_CONFIG="$SUITE/configurations/generated/S03H1/from_patcher/smoke_s03h1_execution_profiles_diagnostic_from_s02.marte"
|
||||||
|
MINIMAL_CONFIG="$SUITE/configurations/generated/S03H3/from_patcher/smoke_s03h3_execution_profiles_minimal_from_s03h1_test.marte"
|
||||||
|
|
||||||
|
MODE="NOT_PROVIDED"
|
||||||
|
MODE_STATUS="NOT_DEMONSTRATED"
|
||||||
|
PROFILE_CONFIG_STATUS="NOT_DEMONSTRATED"
|
||||||
|
PROFILE_RUNTIME_STATUS="NOT_DEMONSTRATED"
|
||||||
|
OBSERVABILITY_STATUS="NOT_DEMONSTRATED"
|
||||||
|
OBSERVABILITY_REASON="NOT_EVALUATED"
|
||||||
|
FUNCTIONAL_STATUS="NOT_DEMONSTRATED"
|
||||||
|
SEMANTIC_STATUS="NOT_DEMONSTRATED"
|
||||||
|
TIMING_STATUS="NOT_EVALUATED"
|
||||||
|
MEASUREMENT_ELIGIBILITY="NO"
|
||||||
|
COMPLETE_SAMPLE_COUNT="NOT_DEMONSTRATED"
|
||||||
|
|
||||||
|
CONFIG_REPORT=""
|
||||||
|
RUNTIME_CONFIG_REPORT=""
|
||||||
|
BINARY_REPORT=""
|
||||||
|
HASH_REPORT=""
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
rm -f -- \
|
||||||
|
"${CONFIG_REPORT:-}" \
|
||||||
|
"${RUNTIME_CONFIG_REPORT:-}" \
|
||||||
|
"${BINARY_REPORT:-}" \
|
||||||
|
"${HASH_REPORT:-}" 2>/dev/null || true
|
||||||
|
}
|
||||||
|
trap cleanup EXIT HUP INT TERM
|
||||||
|
|
||||||
|
emit_contract() {
|
||||||
|
printf 'MODE=%s\n' "$MODE"
|
||||||
|
printf 'MODE_STATUS=%s\n' "$MODE_STATUS"
|
||||||
|
printf 'PROFILE_CONFIG_STATUS=%s\n' "$PROFILE_CONFIG_STATUS"
|
||||||
|
printf 'PROFILE_RUNTIME_STATUS=%s\n' "$PROFILE_RUNTIME_STATUS"
|
||||||
|
printf 'OBSERVABILITY_STATUS=%s\n' "$OBSERVABILITY_STATUS"
|
||||||
|
printf 'OBSERVABILITY_REASON=%s\n' "$OBSERVABILITY_REASON"
|
||||||
|
printf 'FUNCTIONAL_STATUS=%s\n' "$FUNCTIONAL_STATUS"
|
||||||
|
printf 'SEMANTIC_STATUS=%s\n' "$SEMANTIC_STATUS"
|
||||||
|
printf 'TIMING_STATUS=%s\n' "$TIMING_STATUS"
|
||||||
|
printf 'MEASUREMENT_ELIGIBILITY=%s\n' "$MEASUREMENT_ELIGIBILITY"
|
||||||
|
printf 'COMPLETE_SAMPLE_COUNT=%s\n' "$COMPLETE_SAMPLE_COUNT"
|
||||||
|
}
|
||||||
|
|
||||||
|
fail_early() {
|
||||||
|
local code="$1"
|
||||||
|
local reason="$2"
|
||||||
|
printf '[NON DIMOSTRATO] %s\n' "$reason" >&2
|
||||||
|
OBSERVABILITY_REASON="$reason"
|
||||||
|
emit_contract
|
||||||
|
printf 'VALIDATION_RESULT=FAIL_REQUIRED_INPUT\n'
|
||||||
|
exit "$code"
|
||||||
|
}
|
||||||
|
|
||||||
|
count_lines() {
|
||||||
|
local pattern="$1"
|
||||||
|
local file="$2"
|
||||||
|
grep -Ec "$pattern" "$file" || true
|
||||||
|
}
|
||||||
|
|
||||||
|
report_value_exact() {
|
||||||
|
local key="$1"
|
||||||
|
local file="$2"
|
||||||
|
local count
|
||||||
|
count="$(grep -Ec "^${key}=" "$file" || true)"
|
||||||
|
if [ "$count" -ne 1 ]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
sed -n "s/^${key}=//p" "$file"
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_identity() {
|
||||||
|
local file="$1"
|
||||||
|
local expected="$2"
|
||||||
|
[ -f "$file" ] || return 1
|
||||||
|
[ "$(sha256sum -- "$file" | awk '{print $1}')" = "$expected" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$#" -ne 2 ]; then
|
||||||
|
printf 'Uso: %s MINIMAL|TEST|DIAGNOSTIC <directory-run|run.log>\n' "$0" >&2
|
||||||
|
emit_contract
|
||||||
|
printf 'VALIDATION_RESULT=FAIL_INVALID_USAGE\n'
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
MODE="$1"
|
||||||
|
case "$MODE" in
|
||||||
|
MINIMAL)
|
||||||
|
SELECTED_CONFIG="$MINIMAL_CONFIG"
|
||||||
|
;;
|
||||||
|
TEST)
|
||||||
|
SELECTED_CONFIG="$TEST_CONFIG"
|
||||||
|
EXPECTED_SELECTED_CONFIG_SHA256="$EXPECTED_TEST_CONFIG_SHA256"
|
||||||
|
;;
|
||||||
|
DIAGNOSTIC)
|
||||||
|
SELECTED_CONFIG="$DIAGNOSTIC_CONFIG"
|
||||||
|
EXPECTED_SELECTED_CONFIG_SHA256="$EXPECTED_DIAGNOSTIC_CONFIG_SHA256"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
MODE_STATUS="FAIL"
|
||||||
|
PROFILE_CONFIG_STATUS="FAIL"
|
||||||
|
PROFILE_RUNTIME_STATUS="FAIL"
|
||||||
|
OBSERVABILITY_STATUS="FAIL"
|
||||||
|
OBSERVABILITY_REASON="UNKNOWN_MODE"
|
||||||
|
emit_contract
|
||||||
|
printf 'VALIDATION_RESULT=FAIL_UNKNOWN_MODE\n'
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
INPUT_PATH="$2"
|
||||||
|
if [ -d "$INPUT_PATH" ]; then
|
||||||
|
RUN_DIR="$(cd -- "$INPUT_PATH" && pwd -P)"
|
||||||
|
RUN_LOG="$RUN_DIR/run.log"
|
||||||
|
elif [ -f "$INPUT_PATH" ]; then
|
||||||
|
RUN_LOG="$(cd -- "$(dirname -- "$INPUT_PATH")" && pwd -P)/$(basename -- "$INPUT_PATH")"
|
||||||
|
RUN_DIR="$(dirname -- "$RUN_LOG")"
|
||||||
|
else
|
||||||
|
fail_early 21 "INPUT_PATH_NOT_FOUND"
|
||||||
|
fi
|
||||||
|
|
||||||
|
RUN_CONFIG="$RUN_DIR/configuration.marte"
|
||||||
|
OUTPUT_FILE="$RUN_DIR/s03_output.bin"
|
||||||
|
RUNNER_SUMMARY="$RUN_DIR/runner_summary.txt"
|
||||||
|
RUN_HASHES="$RUN_DIR/hashes.sha256"
|
||||||
|
MODE_FILE="$RUN_DIR/s03h3_mode.txt"
|
||||||
|
|
||||||
|
verify_identity "$PARSER" "$EXPECTED_PARSER_SHA256" || \
|
||||||
|
fail_early 21 "PARSER_IDENTITY_NOT_DEMONSTRATED"
|
||||||
|
verify_identity "$H1_VERIFIER" "$EXPECTED_H1_VERIFIER_SHA256" || \
|
||||||
|
fail_early 21 "H1_VERIFIER_IDENTITY_NOT_DEMONSTRATED"
|
||||||
|
[ -x "$MINIMAL_VERIFIER" ] || fail_early 21 "MINIMAL_VERIFIER_NOT_EXECUTABLE"
|
||||||
|
|
||||||
|
for required_file in \
|
||||||
|
"$RUN_LOG" \
|
||||||
|
"$RUN_CONFIG" \
|
||||||
|
"$OUTPUT_FILE" \
|
||||||
|
"$RUNNER_SUMMARY" \
|
||||||
|
"$RUN_HASHES" \
|
||||||
|
"$MODE_FILE" \
|
||||||
|
"$SELECTED_CONFIG"
|
||||||
|
do
|
||||||
|
[ -f "$required_file" ] || fail_early 21 "REQUIRED_FILE_MISSING"
|
||||||
|
done
|
||||||
|
[ -s "$RUN_LOG" ] || fail_early 21 "RUN_LOG_EMPTY"
|
||||||
|
[ -s "$RUN_HASHES" ] || fail_early 21 "RUN_HASH_MANIFEST_EMPTY"
|
||||||
|
|
||||||
|
SELECTED_CONFIG_SHA256="$(sha256sum -- "$SELECTED_CONFIG" | awk '{print $1}')"
|
||||||
|
if [ "$MODE" = "MINIMAL" ]; then
|
||||||
|
EXPECTED_SELECTED_CONFIG_SHA256="$SELECTED_CONFIG_SHA256"
|
||||||
|
fi
|
||||||
|
|
||||||
|
CANONICAL_CONFIG_IDENTITY_STATUS="PASS"
|
||||||
|
if [ "$SELECTED_CONFIG_SHA256" != "$EXPECTED_SELECTED_CONFIG_SHA256" ]; then
|
||||||
|
CANONICAL_CONFIG_IDENTITY_STATUS="FAIL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
MODE_FILE_CONTENT_STATUS="PASS"
|
||||||
|
MODE_DECLARATION_COUNT=0
|
||||||
|
SCENARIO_DECLARATION_COUNT=0
|
||||||
|
CONFIG_HASH_DECLARATION_COUNT=0
|
||||||
|
while IFS= read -r metadata_line || [ -n "$metadata_line" ]; do
|
||||||
|
case "$metadata_line" in
|
||||||
|
'')
|
||||||
|
;;
|
||||||
|
SCENARIO=S03H3)
|
||||||
|
SCENARIO_DECLARATION_COUNT=$((SCENARIO_DECLARATION_COUNT + 1))
|
||||||
|
;;
|
||||||
|
MODE=MINIMAL|MODE=TEST|MODE=DIAGNOSTIC)
|
||||||
|
MODE_DECLARATION_COUNT=$((MODE_DECLARATION_COUNT + 1))
|
||||||
|
[ "${metadata_line#MODE=}" = "$MODE" ] || MODE_FILE_CONTENT_STATUS="FAIL"
|
||||||
|
;;
|
||||||
|
SELECTED_CONFIG_SHA256=*)
|
||||||
|
CONFIG_HASH_DECLARATION_COUNT=$((CONFIG_HASH_DECLARATION_COUNT + 1))
|
||||||
|
declared_config_sha256="${metadata_line#SELECTED_CONFIG_SHA256=}"
|
||||||
|
if [[ ! "$declared_config_sha256" =~ ^[0-9a-f]{64}$ ]] ||
|
||||||
|
[ "$declared_config_sha256" != "$EXPECTED_SELECTED_CONFIG_SHA256" ] ||
|
||||||
|
[ "$declared_config_sha256" != "$SELECTED_CONFIG_SHA256" ]; then
|
||||||
|
MODE_FILE_CONTENT_STATUS="FAIL"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
MODE_FILE_CONTENT_STATUS="FAIL"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done <"$MODE_FILE"
|
||||||
|
|
||||||
|
if [ "$MODE_FILE_CONTENT_STATUS" = "PASS" ] &&
|
||||||
|
[ "$CANONICAL_CONFIG_IDENTITY_STATUS" = "PASS" ] &&
|
||||||
|
[ "$MODE_DECLARATION_COUNT" -eq 1 ] &&
|
||||||
|
[ "$SCENARIO_DECLARATION_COUNT" -eq 1 ] &&
|
||||||
|
[ "$CONFIG_HASH_DECLARATION_COUNT" -eq 1 ]; then
|
||||||
|
MODE_STATUS="PASS"
|
||||||
|
else
|
||||||
|
MODE_STATUS="FAIL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
CONFIG_REPORT="$(mktemp "${TMPDIR:-/tmp}/s03h3_config.XXXXXX")" || \
|
||||||
|
fail_early 21 "CONFIG_REPORT_CREATION_FAILED"
|
||||||
|
RUNTIME_CONFIG_REPORT="$(mktemp "${TMPDIR:-/tmp}/s03h3_runtime.XXXXXX")" || \
|
||||||
|
fail_early 21 "RUNTIME_REPORT_CREATION_FAILED"
|
||||||
|
BINARY_REPORT="$(mktemp "${TMPDIR:-/tmp}/s03h3_binary.XXXXXX")" || \
|
||||||
|
fail_early 21 "BINARY_REPORT_CREATION_FAILED"
|
||||||
|
HASH_REPORT="$(mktemp "${TMPDIR:-/tmp}/s03h3_hashes.XXXXXX")" || \
|
||||||
|
fail_early 21 "HASH_REPORT_CREATION_FAILED"
|
||||||
|
|
||||||
|
EXPECTED_FILENAME="$RUN_DIR/s03_output.bin"
|
||||||
|
CONFIG_RC=1
|
||||||
|
RUNTIME_CONFIG_RC=1
|
||||||
|
CANONICAL_STRUCTURAL_COMPLETENESS_STATUS="NOT_APPLICABLE"
|
||||||
|
MINIMAL_RUNTIME_CONFIG_STATUS="NOT_APPLICABLE"
|
||||||
|
if [ "$MODE" = "MINIMAL" ]; then
|
||||||
|
PYTHONHASHSEED=0 python3 "$MINIMAL_VERIFIER" \
|
||||||
|
CANONICAL "$TEST_CONFIG" "$MINIMAL_CONFIG" \
|
||||||
|
>"$CONFIG_REPORT" 2>&1
|
||||||
|
CONFIG_RC=$?
|
||||||
|
PYTHONHASHSEED=0 python3 "$MINIMAL_VERIFIER" \
|
||||||
|
RUNTIME "$MINIMAL_CONFIG" "$RUN_CONFIG" "$RUN_DIR" \
|
||||||
|
>"$RUNTIME_CONFIG_REPORT" 2>&1
|
||||||
|
RUNTIME_CONFIG_RC=$?
|
||||||
|
CANONICAL_STRUCTURAL_COMPLETENESS_STATUS="$(
|
||||||
|
report_value_exact CANONICAL_STRUCTURAL_COMPLETENESS_STATUS "$CONFIG_REPORT" || printf FAIL
|
||||||
|
)"
|
||||||
|
MINIMAL_RUNTIME_CONFIG_STATUS="$(
|
||||||
|
report_value_exact MINIMAL_RUNTIME_CONFIG_STATUS "$RUNTIME_CONFIG_REPORT" || printf FAIL
|
||||||
|
)"
|
||||||
|
if [ "$CONFIG_RC" -eq 0 ] &&
|
||||||
|
[ "$RUNTIME_CONFIG_RC" -eq 0 ] &&
|
||||||
|
[ "$CANONICAL_STRUCTURAL_COMPLETENESS_STATUS" = "PASS" ] &&
|
||||||
|
[ "$MINIMAL_RUNTIME_CONFIG_STATUS" = "PASS" ]; then
|
||||||
|
PROFILE_CONFIG_STATUS="PASS"
|
||||||
|
else
|
||||||
|
PROFILE_CONFIG_STATUS="FAIL"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
PYTHONHASHSEED=0 python3 "$H1_VERIFIER" \
|
||||||
|
"$MODE" "$RUN_CONFIG" "$EXPECTED_FILENAME" \
|
||||||
|
>"$CONFIG_REPORT" 2>&1
|
||||||
|
CONFIG_RC=$?
|
||||||
|
RUNTIME_CONFIG_RC=0
|
||||||
|
PROFILE_CONFIG_STATUS="$(
|
||||||
|
report_value_exact CONFIG_PROFILE_VERIFICATION_STATUS "$CONFIG_REPORT" || printf FAIL
|
||||||
|
)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
GAMTIMER_RUNTIME_LINES="$(count_lines '^\[Information - RealTimeApplicationConfigurationBuilder\.cpp:[0-9]+\]: Resolving for function GAMTimer \[idx: 0\][[:space:]]*$' "$RUN_LOG")"
|
||||||
|
SENTINEL_RUNTIME_LINES="$(count_lines '^\[Information - RealTimeApplicationConfigurationBuilder\.cpp:[0-9]+\]: Resolving for function SentinelProducer \[idx: 1\][[:space:]]*$' "$RUN_LOG")"
|
||||||
|
GAMDISPLAY_IDX2_LINES="$(count_lines '^\[Information - RealTimeApplicationConfigurationBuilder\.cpp:[0-9]+\]: Resolving for function GAMDisplay \[idx: 2\][[:space:]]*$' "$RUN_LOG")"
|
||||||
|
IOGAM_IDX2_LINES="$(count_lines '^\[Information - RealTimeApplicationConfigurationBuilder\.cpp:[0-9]+\]: Resolving for function IOGAM_Writer \[idx: 2\][[:space:]]*$' "$RUN_LOG")"
|
||||||
|
IOGAM_IDX3_LINES="$(count_lines '^\[Information - RealTimeApplicationConfigurationBuilder\.cpp:[0-9]+\]: Resolving for function IOGAM_Writer \[idx: 3\][[:space:]]*$' "$RUN_LOG")"
|
||||||
|
FUNCTION_RESOLUTION_LINES="$(count_lines '^\[Information - RealTimeApplicationConfigurationBuilder\.cpp:[0-9]+\]: Resolving for function .* \[idx: [0-9]+\][[:space:]]*$' "$RUN_LOG")"
|
||||||
|
GAMTIMER_OBJECT_RESOLUTION_LINES="$(count_lines '^\[Information - RealTimeApplicationConfigurationBuilder\.cpp:[0-9]+\]: Resolving GAMTimer[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
SENTINEL_OBJECT_RESOLUTION_LINES="$(count_lines '^\[Information - RealTimeApplicationConfigurationBuilder\.cpp:[0-9]+\]: Resolving SentinelProducer[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
GAMDISPLAY_OBJECT_RESOLUTION_LINES="$(count_lines '^\[Information - RealTimeApplicationConfigurationBuilder\.cpp:[0-9]+\]: Resolving GAMDisplay[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
IOGAM_OBJECT_RESOLUTION_LINES="$(count_lines '^\[Information - RealTimeApplicationConfigurationBuilder\.cpp:[0-9]+\]: Resolving IOGAM_Writer[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
|
||||||
|
case "$MODE" in
|
||||||
|
MINIMAL)
|
||||||
|
if [ "$GAMTIMER_RUNTIME_LINES" -eq 1 ] &&
|
||||||
|
[ "$SENTINEL_RUNTIME_LINES" -eq 1 ] &&
|
||||||
|
[ "$GAMDISPLAY_IDX2_LINES" -eq 0 ] &&
|
||||||
|
[ "$IOGAM_IDX2_LINES" -eq 1 ] &&
|
||||||
|
[ "$IOGAM_IDX3_LINES" -eq 0 ] &&
|
||||||
|
[ "$GAMTIMER_OBJECT_RESOLUTION_LINES" -eq 1 ] &&
|
||||||
|
[ "$SENTINEL_OBJECT_RESOLUTION_LINES" -eq 1 ] &&
|
||||||
|
[ "$GAMDISPLAY_OBJECT_RESOLUTION_LINES" -eq 0 ] &&
|
||||||
|
[ "$IOGAM_OBJECT_RESOLUTION_LINES" -eq 1 ] &&
|
||||||
|
[ "$FUNCTION_RESOLUTION_LINES" -eq 3 ]; then
|
||||||
|
PROFILE_RUNTIME_STATUS="PASS"
|
||||||
|
else
|
||||||
|
PROFILE_RUNTIME_STATUS="FAIL"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
TEST|DIAGNOSTIC)
|
||||||
|
if [ "$GAMTIMER_RUNTIME_LINES" -eq 1 ] &&
|
||||||
|
[ "$SENTINEL_RUNTIME_LINES" -eq 1 ] &&
|
||||||
|
[ "$GAMDISPLAY_IDX2_LINES" -eq 1 ] &&
|
||||||
|
[ "$IOGAM_IDX2_LINES" -eq 0 ] &&
|
||||||
|
[ "$IOGAM_IDX3_LINES" -eq 1 ] &&
|
||||||
|
[ "$GAMTIMER_OBJECT_RESOLUTION_LINES" -eq 1 ] &&
|
||||||
|
[ "$SENTINEL_OBJECT_RESOLUTION_LINES" -eq 1 ] &&
|
||||||
|
[ "$GAMDISPLAY_OBJECT_RESOLUTION_LINES" -eq 1 ] &&
|
||||||
|
[ "$IOGAM_OBJECT_RESOLUTION_LINES" -eq 1 ] &&
|
||||||
|
[ "$FUNCTION_RESOLUTION_LINES" -eq 4 ]; then
|
||||||
|
PROFILE_RUNTIME_STATUS="PASS"
|
||||||
|
else
|
||||||
|
PROFILE_RUNTIME_STATUS="FAIL"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
PYTHONHASHSEED=0 python3 "$PARSER" "$OUTPUT_FILE" --min-samples "$MINIMUM_SAMPLES" \
|
||||||
|
>"$BINARY_REPORT" 2>&1
|
||||||
|
PARSER_RC=$?
|
||||||
|
sha256sum -c --strict "$RUN_HASHES" >"$HASH_REPORT" 2>&1
|
||||||
|
HASH_RC=$?
|
||||||
|
|
||||||
|
FUNCTIONAL_BINARY_STATUS="$(report_value_exact FUNCTIONAL_BINARY_STATUS "$BINARY_REPORT" || printf FAIL)"
|
||||||
|
SEMANTIC_BINARY_STATUS="$(report_value_exact SEMANTIC_BINARY_STATUS "$BINARY_REPORT" || printf FAIL)"
|
||||||
|
BINARY_STATUS="$(report_value_exact BINARY_STATUS "$BINARY_REPORT" || printf FAIL)"
|
||||||
|
PARSER_PAYLOAD_ALIGNMENT_STATUS="$(report_value_exact PAYLOAD_ALIGNMENT_STATUS "$BINARY_REPORT" || printf FAIL)"
|
||||||
|
COMPLETE_SAMPLE_COUNT="$(report_value_exact COMPLETE_SAMPLE_COUNT "$BINARY_REPORT" || printf NOT_DEMONSTRATED)"
|
||||||
|
|
||||||
|
COMPLETE_SAMPLE_COUNT_STATUS="FAIL"
|
||||||
|
case "$COMPLETE_SAMPLE_COUNT" in
|
||||||
|
''|*[!0-9]*) ;;
|
||||||
|
*)
|
||||||
|
if [ "$PARSER_RC" -eq 0 ] &&
|
||||||
|
[ "$FUNCTIONAL_BINARY_STATUS" = "PASS" ] &&
|
||||||
|
[ "$SEMANTIC_BINARY_STATUS" = "PASS" ] &&
|
||||||
|
[ "$BINARY_STATUS" = "PASS" ] &&
|
||||||
|
[ "$PARSER_PAYLOAD_ALIGNMENT_STATUS" = "PASS" ]; then
|
||||||
|
COMPLETE_SAMPLE_COUNT_STATUS="PASS"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
LOGGER_SIGNAL_LINES="$(count_lines '^\[Information - LoggerBroker\.cpp:[0-9]+\]: (Counter|Time|State1_Thread1_CycleTime|SentinelScalarA|SentinelScalarB|SentinelVector) \[[0-9]+:[0-9]+\]:' "$RUN_LOG")"
|
||||||
|
LOGGER_COUNTER_LINES="$(count_lines '^\[Information - LoggerBroker\.cpp:[0-9]+\]: Counter \[0:0\]:' "$RUN_LOG")"
|
||||||
|
LOGGER_TIME_LINES="$(count_lines '^\[Information - LoggerBroker\.cpp:[0-9]+\]: Time \[0:0\]:' "$RUN_LOG")"
|
||||||
|
LOGGER_CYCLE_TIME_LINES="$(count_lines '^\[Information - LoggerBroker\.cpp:[0-9]+\]: State1_Thread1_CycleTime \[0:0\]:' "$RUN_LOG")"
|
||||||
|
LOGGER_SCALAR_A_LINES="$(count_lines '^\[Information - LoggerBroker\.cpp:[0-9]+\]: SentinelScalarA \[0:0\]:' "$RUN_LOG")"
|
||||||
|
LOGGER_SCALAR_B_LINES="$(count_lines '^\[Information - LoggerBroker\.cpp:[0-9]+\]: SentinelScalarB \[0:0\]:' "$RUN_LOG")"
|
||||||
|
LOGGER_VECTOR_LINES="$(count_lines '^\[Information - LoggerBroker\.cpp:[0-9]+\]: SentinelVector \[0:2\]:' "$RUN_LOG")"
|
||||||
|
|
||||||
|
if [ "$COMPLETE_SAMPLE_COUNT_STATUS" != "PASS" ]; then
|
||||||
|
OBSERVABILITY_STATUS="NOT_DEMONSTRATED"
|
||||||
|
OBSERVABILITY_REASON="COMPLETE_SAMPLE_COUNT_NOT_AUTHORITATIVE"
|
||||||
|
elif [ "$MODE" = "MINIMAL" ] || [ "$MODE" = "TEST" ]; then
|
||||||
|
if [ "$LOGGER_SIGNAL_LINES" -eq 0 ] &&
|
||||||
|
[ "$LOGGER_COUNTER_LINES" -eq 0 ] &&
|
||||||
|
[ "$LOGGER_TIME_LINES" -eq 0 ] &&
|
||||||
|
[ "$LOGGER_CYCLE_TIME_LINES" -eq 0 ] &&
|
||||||
|
[ "$LOGGER_SCALAR_A_LINES" -eq 0 ] &&
|
||||||
|
[ "$LOGGER_SCALAR_B_LINES" -eq 0 ] &&
|
||||||
|
[ "$LOGGER_VECTOR_LINES" -eq 0 ]; then
|
||||||
|
OBSERVABILITY_STATUS="PASS"
|
||||||
|
OBSERVABILITY_REASON="NONE"
|
||||||
|
else
|
||||||
|
OBSERVABILITY_STATUS="FAIL"
|
||||||
|
OBSERVABILITY_REASON="UNEXPECTED_LOGGER_SIGNAL_LINES"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ "$LOGGER_COUNTER_LINES" -eq "$COMPLETE_SAMPLE_COUNT" ] &&
|
||||||
|
[ "$LOGGER_TIME_LINES" -eq "$COMPLETE_SAMPLE_COUNT" ] &&
|
||||||
|
[ "$LOGGER_CYCLE_TIME_LINES" -eq "$COMPLETE_SAMPLE_COUNT" ] &&
|
||||||
|
[ "$LOGGER_SCALAR_A_LINES" -eq "$COMPLETE_SAMPLE_COUNT" ] &&
|
||||||
|
[ "$LOGGER_SCALAR_B_LINES" -eq "$COMPLETE_SAMPLE_COUNT" ] &&
|
||||||
|
[ "$LOGGER_VECTOR_LINES" -eq "$COMPLETE_SAMPLE_COUNT" ] &&
|
||||||
|
[ "$LOGGER_SIGNAL_LINES" -eq $((6 * COMPLETE_SAMPLE_COUNT)) ]; then
|
||||||
|
OBSERVABILITY_STATUS="PASS"
|
||||||
|
OBSERVABILITY_REASON="NONE"
|
||||||
|
elif [ "$LOGGER_COUNTER_LINES" -eq "$LOGGER_TIME_LINES" ] &&
|
||||||
|
[ "$LOGGER_COUNTER_LINES" -eq "$LOGGER_CYCLE_TIME_LINES" ] &&
|
||||||
|
[ "$LOGGER_COUNTER_LINES" -eq "$LOGGER_SCALAR_A_LINES" ] &&
|
||||||
|
[ "$LOGGER_COUNTER_LINES" -eq "$LOGGER_SCALAR_B_LINES" ] &&
|
||||||
|
[ "$LOGGER_COUNTER_LINES" -eq "$LOGGER_VECTOR_LINES" ]; then
|
||||||
|
OBSERVABILITY_STATUS="NOT_DEMONSTRATED"
|
||||||
|
OBSERVABILITY_REASON="SHUTDOWN_SKEW"
|
||||||
|
else
|
||||||
|
OBSERVABILITY_STATUS="FAIL"
|
||||||
|
OBSERVABILITY_REASON="LOGGER_BINARY_COUNT_MISMATCH"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
START_LINES="$(count_lines '^\[Information - RealTimeLoader\.cpp:[0-9]+\]: Started application in state State1[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
APPLICATION_START_LINES="$(count_lines '^\[Information - MARTeApp\.cpp:[0-9]+\]: Application starting[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
FILE_OPEN_LINES="$(count_lines '^\[Information - FileWriter\.cpp:[0-9]+\]: Going to open file with name ' "$RUN_LOG")"
|
||||||
|
SIGINT_LINES="$(count_lines '^\[Information - Bootstrap\.cpp:[0-9]+\]: Application recieved SIGINT\.[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
STOP_OK_LINES="$(count_lines '^\[Information - Bootstrap\.cpp:[0-9]+\]: Application successfully stopped\.[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
TERMINATED_LINES="$(count_lines '^\[NoError - MARTeApp\.cpp:[0-9]+\]: Application terminated[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
STARTUP_ERROR_LINES="$(count_lines 'Failed dlopen|Failed CreateByName|Failed to Initialise object|Failed to initialise the ObjectRegistryDatabase|Could not Initialise the loader' "$RUN_LOG")"
|
||||||
|
FATAL_ERROR_LINES="$(count_lines '^\[FatalError ' "$RUN_LOG")"
|
||||||
|
OS_ERROR_LINES="$(count_lines '^\[OSError ' "$RUN_LOG")"
|
||||||
|
ERROR_LINES="$(count_lines '^\[Error ' "$RUN_LOG")"
|
||||||
|
INITIALISATION_ERROR_LINES="$(count_lines '^\[InitialisationEr ' "$RUN_LOG")"
|
||||||
|
PRIORITY_FAIL_LINES="$(count_lines '^\[Warning - Threads\.cpp:[0-9]+\]: Failed to change the thread priority' "$RUN_LOG")"
|
||||||
|
DOUBLE_STOP_LINES="$(count_lines '^\[FatalError - RealTimeApplication\.cpp:[0-9]+\]: Could not stop the RealTimeApplication\. Was it ever started\?[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
ASYNC_CLOSE_LINES="$(count_lines '^\[FatalError - MemoryMapAsyncOutputBroker\.cpp:[0-9]+\]: Could not Close the EventSem\.[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
MUTEX_DESTROY_LINES="$(count_lines '^\[OSError - EventSem\.cpp:[0-9]+\]: Error: pthread_mutex_destroy\(\)[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
UNCLASSIFIED_FATAL_LINES=$((FATAL_ERROR_LINES - DOUBLE_STOP_LINES - ASYNC_CLOSE_LINES))
|
||||||
|
UNCLASSIFIED_OS_ERROR_LINES=$((OS_ERROR_LINES - MUTEX_DESTROY_LINES))
|
||||||
|
[ "$UNCLASSIFIED_FATAL_LINES" -ge 0 ] || UNCLASSIFIED_FATAL_LINES=0
|
||||||
|
[ "$UNCLASSIFIED_OS_ERROR_LINES" -ge 0 ] || UNCLASSIFIED_OS_ERROR_LINES=0
|
||||||
|
|
||||||
|
MARTE_EXIT_CODE="$(sed -n 's/^Exit code MARTe:[[:space:]]*//p' "$RUNNER_SUMMARY" | tail -n 1)"
|
||||||
|
TEE_EXIT_CODE="$(sed -n 's/^Exit code tee:[[:space:]]*//p' "$RUNNER_SUMMARY" | tail -n 1)"
|
||||||
|
[ -n "$MARTE_EXIT_CODE" ] || MARTE_EXIT_CODE="NOT_AVAILABLE"
|
||||||
|
[ -n "$TEE_EXIT_CODE" ] || TEE_EXIT_CODE="NOT_AVAILABLE"
|
||||||
|
case "$MARTE_EXIT_CODE" in
|
||||||
|
137) TIMING_STATUS="NOT_VALID_EXIT_137_SIGKILL" ;;
|
||||||
|
*)
|
||||||
|
if [ "$PRIORITY_FAIL_LINES" -ge 1 ]; then
|
||||||
|
TIMING_STATUS="NOT_VALID_PRIORITY_NOT_APPLIED"
|
||||||
|
else
|
||||||
|
TIMING_STATUS="UNASSESSED_DT_SEMANTICS"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ "$MODE_STATUS" = "PASS" ] &&
|
||||||
|
[ "$PROFILE_CONFIG_STATUS" = "PASS" ] &&
|
||||||
|
[ "$PROFILE_RUNTIME_STATUS" = "PASS" ] &&
|
||||||
|
[ "$OBSERVABILITY_STATUS" = "PASS" ] &&
|
||||||
|
[ "$FUNCTIONAL_BINARY_STATUS" = "PASS" ] &&
|
||||||
|
[ "$START_LINES" -eq 1 ] &&
|
||||||
|
[ "$APPLICATION_START_LINES" -eq 1 ] &&
|
||||||
|
[ "$FILE_OPEN_LINES" -eq 1 ] &&
|
||||||
|
[ "$STARTUP_ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$HASH_RC" -eq 0 ] &&
|
||||||
|
[ "$TEE_EXIT_CODE" = "0" ] &&
|
||||||
|
[ "$UNCLASSIFIED_FATAL_LINES" -eq 0 ] &&
|
||||||
|
[ "$UNCLASSIFIED_OS_ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$INITIALISATION_ERROR_LINES" -eq 0 ]; then
|
||||||
|
FUNCTIONAL_STATUS="PASS"
|
||||||
|
else
|
||||||
|
FUNCTIONAL_STATUS="NOT_DEMONSTRATED"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$MODE_STATUS" = "PASS" ] &&
|
||||||
|
[ "$PROFILE_CONFIG_STATUS" = "PASS" ] &&
|
||||||
|
[ "$SEMANTIC_BINARY_STATUS" = "PASS" ]; then
|
||||||
|
SEMANTIC_STATUS="PASS"
|
||||||
|
elif [ "$SEMANTIC_BINARY_STATUS" = "FAIL" ]; then
|
||||||
|
SEMANTIC_STATUS="FAIL"
|
||||||
|
else
|
||||||
|
SEMANTIC_STATUS="NOT_DEMONSTRATED"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '============================================================\n'
|
||||||
|
printf 'VALIDAZIONE S03-H3 - MINIMAL / TEST / DIAGNOSTIC\n'
|
||||||
|
printf '============================================================\n'
|
||||||
|
printf 'Run directory: %s\n' "$RUN_DIR"
|
||||||
|
printf 'CANONICAL_STRUCTURAL_COMPLETENESS_STATUS=%s\n' "$CANONICAL_STRUCTURAL_COMPLETENESS_STATUS"
|
||||||
|
printf 'MINIMAL_RUNTIME_CONFIG_STATUS=%s\n' "$MINIMAL_RUNTIME_CONFIG_STATUS"
|
||||||
|
printf 'FUNCTION_RESOLUTION_LINES=%s\n' "$FUNCTION_RESOLUTION_LINES"
|
||||||
|
printf 'LOGGER_SIGNAL_LINES=%s\n' "$LOGGER_SIGNAL_LINES"
|
||||||
|
printf 'LOGGER_COUNTER_LINES=%s\n' "$LOGGER_COUNTER_LINES"
|
||||||
|
printf 'LOGGER_TIME_LINES=%s\n' "$LOGGER_TIME_LINES"
|
||||||
|
printf 'LOGGER_CYCLE_TIME_LINES=%s\n' "$LOGGER_CYCLE_TIME_LINES"
|
||||||
|
printf 'LOGGER_SCALAR_A_LINES=%s\n' "$LOGGER_SCALAR_A_LINES"
|
||||||
|
printf 'LOGGER_SCALAR_B_LINES=%s\n' "$LOGGER_SCALAR_B_LINES"
|
||||||
|
printf 'LOGGER_VECTOR_LINES=%s\n' "$LOGGER_VECTOR_LINES"
|
||||||
|
printf 'PARSER_RC=%s\n' "$PARSER_RC"
|
||||||
|
printf 'HASH_VERIFICATION_STATUS=%s\n' "$( [ "$HASH_RC" -eq 0 ] && printf PASS || printf FAIL )"
|
||||||
|
|
||||||
|
printf '\n--- CONFIGURATION VERIFIER DETAIL ---\n'
|
||||||
|
if [ "$MODE" = "MINIMAL" ]; then
|
||||||
|
sed 's/^/MINIMAL_CANONICAL_VERIFIER_/' "$CONFIG_REPORT"
|
||||||
|
sed 's/^/MINIMAL_RUNTIME_VERIFIER_/' "$RUNTIME_CONFIG_REPORT"
|
||||||
|
else
|
||||||
|
cat -- "$CONFIG_REPORT"
|
||||||
|
fi
|
||||||
|
printf '\n--- BINARY PARSER DETAIL ---\n'
|
||||||
|
sed 's/^/BINARY_PARSER_/' "$BINARY_REPORT"
|
||||||
|
printf '\n--- HASH DETAIL ---\n'
|
||||||
|
cat -- "$HASH_REPORT"
|
||||||
|
|
||||||
|
printf '\n--- CONTRATTO S03-H3 ---\n'
|
||||||
|
emit_contract
|
||||||
|
|
||||||
|
if [ "$FUNCTIONAL_STATUS" != "PASS" ] || [ "$SEMANTIC_STATUS" != "PASS" ]; then
|
||||||
|
printf 'VALIDATION_RESULT=FUNCTIONAL_OR_SEMANTIC_NOT_DEMONSTRATED\n'
|
||||||
|
exit 20
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$SIGINT_LINES" -ge 1 ] &&
|
||||||
|
[ "$STOP_OK_LINES" -ge 1 ] &&
|
||||||
|
[ "$TERMINATED_LINES" -ge 1 ] &&
|
||||||
|
[ "$FATAL_ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$OS_ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$INITIALISATION_ERROR_LINES" -eq 0 ]; then
|
||||||
|
printf 'VALIDATION_RESULT=PASS_CLEAN_SHUTDOWN\n'
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
KNOWN_SHUTDOWN_TOTAL=$((DOUBLE_STOP_LINES + ASYNC_CLOSE_LINES + MUTEX_DESTROY_LINES))
|
||||||
|
if [ "$SIGINT_LINES" -ge 1 ] &&
|
||||||
|
[ "$STOP_OK_LINES" -ge 1 ] &&
|
||||||
|
[ "$TERMINATED_LINES" -ge 1 ] &&
|
||||||
|
[ "$KNOWN_SHUTDOWN_TOTAL" -ge 1 ] &&
|
||||||
|
[ "$UNCLASSIFIED_FATAL_LINES" -eq 0 ] &&
|
||||||
|
[ "$UNCLASSIFIED_OS_ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$INITIALISATION_ERROR_LINES" -eq 0 ]; then
|
||||||
|
printf 'VALIDATION_RESULT=PASS_KNOWN_SHUTDOWN_ANOMALY\n'
|
||||||
|
exit 10
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf 'VALIDATION_RESULT=PASS_UNCLASSIFIED_SHUTDOWN_ANOMALY\n'
|
||||||
|
exit 11
|
||||||
@@ -0,0 +1,331 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Fail-closed structural verifier for the S03-H3 MINIMAL profile."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import hashlib
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
EXPECTED_TEST_SHA256 = (
|
||||||
|
"d037561b32760fbd0e2aec9f1eefc5efda27b1918eca4742c89092a8a2f7e92e"
|
||||||
|
)
|
||||||
|
PLACEHOLDER = "__MARTE_RUN_DIR__"
|
||||||
|
TEST_FUNCTIONS = (
|
||||||
|
" Functions = "
|
||||||
|
"{GAMTimer SentinelProducer GAMDisplay IOGAM_Writer}"
|
||||||
|
)
|
||||||
|
MINIMAL_FUNCTIONS = (
|
||||||
|
" Functions = "
|
||||||
|
"{GAMTimer SentinelProducer IOGAM_Writer}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def sha256_bytes(data: bytes) -> str:
|
||||||
|
return hashlib.sha256(data).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def read_utf8(path: Path) -> tuple[bytes, str]:
|
||||||
|
data = path.read_bytes()
|
||||||
|
return data, data.decode("utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def object_matches(text: str, name: str) -> list[re.Match[str]]:
|
||||||
|
pattern = re.compile(
|
||||||
|
rf"(?m)^[ \t]*\+{re.escape(name)}[ \t]*=[ \t]*\{{[ \t]*(?:\r?\n|$)"
|
||||||
|
)
|
||||||
|
return list(pattern.finditer(text))
|
||||||
|
|
||||||
|
|
||||||
|
def object_count(text: str, name: str) -> int:
|
||||||
|
return len(object_matches(text, name))
|
||||||
|
|
||||||
|
|
||||||
|
def block_span(text: str, name: str) -> tuple[int, int]:
|
||||||
|
matches = object_matches(text, name)
|
||||||
|
if len(matches) != 1:
|
||||||
|
raise ValueError(f"{name.upper()}_ANCHOR_COUNT_{len(matches)}")
|
||||||
|
|
||||||
|
match = matches[0]
|
||||||
|
opening = text.find("{", match.start(), match.end())
|
||||||
|
if opening < 0:
|
||||||
|
raise ValueError(f"{name.upper()}_OPENING_BRACE_MISSING")
|
||||||
|
|
||||||
|
depth = 0
|
||||||
|
quoted = False
|
||||||
|
escaped = False
|
||||||
|
closing = -1
|
||||||
|
for index in range(opening, len(text)):
|
||||||
|
char = text[index]
|
||||||
|
if quoted:
|
||||||
|
if escaped:
|
||||||
|
escaped = False
|
||||||
|
elif char == "\\":
|
||||||
|
escaped = True
|
||||||
|
elif char == '"':
|
||||||
|
quoted = False
|
||||||
|
continue
|
||||||
|
if char == '"':
|
||||||
|
quoted = True
|
||||||
|
elif char == "{":
|
||||||
|
depth += 1
|
||||||
|
elif char == "}":
|
||||||
|
depth -= 1
|
||||||
|
if depth == 0:
|
||||||
|
closing = index + 1
|
||||||
|
break
|
||||||
|
if depth < 0:
|
||||||
|
raise ValueError(f"{name.upper()}_UNBALANCED_BRACE")
|
||||||
|
|
||||||
|
if closing < 0:
|
||||||
|
raise ValueError(f"{name.upper()}_CLOSING_BRACE_MISSING")
|
||||||
|
|
||||||
|
if text.startswith("\r\n", closing):
|
||||||
|
closing += 2
|
||||||
|
elif text.startswith("\n", closing):
|
||||||
|
closing += 1
|
||||||
|
return match.start(), closing
|
||||||
|
|
||||||
|
|
||||||
|
def derive_expected_minimal(canonical: str) -> str:
|
||||||
|
if canonical.count(TEST_FUNCTIONS) != 1:
|
||||||
|
raise ValueError(
|
||||||
|
f"FUNCTIONS_ANCHOR_COUNT_{canonical.count(TEST_FUNCTIONS)}"
|
||||||
|
)
|
||||||
|
if canonical.count(MINIMAL_FUNCTIONS) != 0:
|
||||||
|
raise ValueError("SOURCE_ALREADY_PARTIALLY_TRANSFORMED")
|
||||||
|
|
||||||
|
spans = [
|
||||||
|
block_span(canonical, "GAMDisplay"),
|
||||||
|
block_span(canonical, "Display"),
|
||||||
|
]
|
||||||
|
if spans[0][0] < spans[1][1] and spans[1][0] < spans[0][1]:
|
||||||
|
raise ValueError("AUTHORIZED_BLOCK_SPANS_OVERLAP")
|
||||||
|
|
||||||
|
transformed = canonical
|
||||||
|
for start, end in sorted(spans, reverse=True):
|
||||||
|
transformed = transformed[:start] + transformed[end:]
|
||||||
|
transformed = transformed.replace(TEST_FUNCTIONS, MINIMAL_FUNCTIONS, 1)
|
||||||
|
return transformed
|
||||||
|
|
||||||
|
|
||||||
|
class Report:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.values: list[tuple[str, str]] = []
|
||||||
|
self.failed = False
|
||||||
|
self.first_error = "NONE"
|
||||||
|
|
||||||
|
def value(self, name: str, value: object) -> None:
|
||||||
|
self.values.append((name, str(value)))
|
||||||
|
|
||||||
|
def status(self, name: str, passed: bool, error: str) -> None:
|
||||||
|
self.value(name, "PASS" if passed else "FAIL")
|
||||||
|
if not passed:
|
||||||
|
self.failed = True
|
||||||
|
if self.first_error == "NONE":
|
||||||
|
self.first_error = error
|
||||||
|
|
||||||
|
def emit(self) -> int:
|
||||||
|
for name, value in self.values:
|
||||||
|
print(f"{name}={value}")
|
||||||
|
print(f"MINIMAL_VERIFIER_ERROR={self.first_error}")
|
||||||
|
return 1 if self.failed else 0
|
||||||
|
|
||||||
|
|
||||||
|
def emit_canonical_failure(error: str) -> int:
|
||||||
|
report = Report()
|
||||||
|
report.value("VERIFICATION_MODE", "CANONICAL")
|
||||||
|
report.value("GAMDisplay_OBJECT_COUNT", 0)
|
||||||
|
report.value("Display_DATASOURCE_COUNT", 0)
|
||||||
|
report.value("GAMDisplay_THREAD_TOKEN_COUNT", 0)
|
||||||
|
report.value("GAMTimer_OBJECT_COUNT", 0)
|
||||||
|
report.value("SentinelProducer_OBJECT_COUNT", 0)
|
||||||
|
report.value("IOGAM_Writer_OBJECT_COUNT", 0)
|
||||||
|
report.value("FileWriter_OBJECT_COUNT", 0)
|
||||||
|
report.status("THREAD_FUNCTIONS_STATUS", False, error)
|
||||||
|
report.status("BINARY_PATH_STRUCTURE_STATUS", False, error)
|
||||||
|
report.status("CANONICAL_STRUCTURAL_COMPLETENESS_STATUS", False, error)
|
||||||
|
report.status("PROFILE_CONFIG_STATUS", False, error)
|
||||||
|
return report.emit()
|
||||||
|
|
||||||
|
|
||||||
|
def verify_canonical(canonical_path: Path, minimal_path: Path) -> int:
|
||||||
|
try:
|
||||||
|
canonical_bytes, canonical = read_utf8(canonical_path)
|
||||||
|
minimal_bytes, minimal = read_utf8(minimal_path)
|
||||||
|
except (OSError, UnicodeError) as exc:
|
||||||
|
return emit_canonical_failure(f"INPUT_READ_FAILED_{type(exc).__name__}")
|
||||||
|
|
||||||
|
canonical_hash = sha256_bytes(canonical_bytes)
|
||||||
|
try:
|
||||||
|
expected_minimal = derive_expected_minimal(canonical)
|
||||||
|
except ValueError as exc:
|
||||||
|
return emit_canonical_failure(str(exc))
|
||||||
|
|
||||||
|
expected_bytes = expected_minimal.encode("utf-8")
|
||||||
|
complete = minimal_bytes == expected_bytes
|
||||||
|
report = Report()
|
||||||
|
report.value("VERIFICATION_MODE", "CANONICAL")
|
||||||
|
report.value("CANONICAL_TEST_SHA256", canonical_hash)
|
||||||
|
report.value("EXPECTED_CANONICAL_TEST_SHA256", EXPECTED_TEST_SHA256)
|
||||||
|
report.value("MINIMAL_CONFIG_SHA256", sha256_bytes(minimal_bytes))
|
||||||
|
report.value("EXPECTED_MINIMAL_CONFIG_SHA256", sha256_bytes(expected_bytes))
|
||||||
|
|
||||||
|
counts = {
|
||||||
|
"GAMDisplay_OBJECT_COUNT": object_count(minimal, "GAMDisplay"),
|
||||||
|
"Display_DATASOURCE_COUNT": object_count(minimal, "Display"),
|
||||||
|
"GAMDisplay_THREAD_TOKEN_COUNT": len(
|
||||||
|
re.findall(r"\bGAMDisplay\b", minimal)
|
||||||
|
),
|
||||||
|
"GAMTimer_OBJECT_COUNT": object_count(minimal, "GAMTimer"),
|
||||||
|
"SentinelProducer_OBJECT_COUNT": object_count(
|
||||||
|
minimal, "SentinelProducer"
|
||||||
|
),
|
||||||
|
"IOGAM_Writer_OBJECT_COUNT": object_count(minimal, "IOGAM_Writer"),
|
||||||
|
"FileWriter_OBJECT_COUNT": object_count(minimal, "FileWriter"),
|
||||||
|
}
|
||||||
|
for name, value in counts.items():
|
||||||
|
report.value(name, value)
|
||||||
|
|
||||||
|
expected_counts = {
|
||||||
|
"GAMDisplay_OBJECT_COUNT": 0,
|
||||||
|
"Display_DATASOURCE_COUNT": 0,
|
||||||
|
"GAMDisplay_THREAD_TOKEN_COUNT": 0,
|
||||||
|
"GAMTimer_OBJECT_COUNT": 1,
|
||||||
|
"SentinelProducer_OBJECT_COUNT": 1,
|
||||||
|
"IOGAM_Writer_OBJECT_COUNT": 1,
|
||||||
|
"FileWriter_OBJECT_COUNT": 1,
|
||||||
|
}
|
||||||
|
counts_pass = counts == expected_counts
|
||||||
|
thread_pass = minimal.count(MINIMAL_FUNCTIONS) == 1
|
||||||
|
binary_pass = (
|
||||||
|
counts["IOGAM_Writer_OBJECT_COUNT"] == 1
|
||||||
|
and counts["FileWriter_OBJECT_COUNT"] == 1
|
||||||
|
and minimal.count('Filename = "__MARTE_RUN_DIR__/s03_output.bin"') == 1
|
||||||
|
and minimal.count('FileFormat = "binary"') == 1
|
||||||
|
and minimal.count("DataSource = FileWriter") == 6
|
||||||
|
)
|
||||||
|
parent_pass = canonical_hash == EXPECTED_TEST_SHA256
|
||||||
|
|
||||||
|
report.value("UNAUTHORIZED_ADDITION_COUNT", 0 if complete else 1)
|
||||||
|
report.status(
|
||||||
|
"CANONICAL_TEST_IDENTITY_STATUS",
|
||||||
|
parent_pass,
|
||||||
|
"CANONICAL_TEST_SHA256_MISMATCH",
|
||||||
|
)
|
||||||
|
report.status(
|
||||||
|
"AUTHORIZED_ABSENCE_AND_PRESENCE_STATUS",
|
||||||
|
counts_pass,
|
||||||
|
"OBJECT_OR_TOKEN_COUNT_MISMATCH",
|
||||||
|
)
|
||||||
|
report.status(
|
||||||
|
"THREAD_FUNCTIONS_STATUS", thread_pass, "THREAD_FUNCTIONS_MISMATCH"
|
||||||
|
)
|
||||||
|
report.status(
|
||||||
|
"BINARY_PATH_STRUCTURE_STATUS",
|
||||||
|
binary_pass,
|
||||||
|
"BINARY_PATH_STRUCTURE_MISMATCH",
|
||||||
|
)
|
||||||
|
report.status(
|
||||||
|
"CANONICAL_STRUCTURAL_COMPLETENESS_STATUS",
|
||||||
|
parent_pass and complete,
|
||||||
|
"UNAUTHORIZED_STRUCTURAL_DIFFERENCE",
|
||||||
|
)
|
||||||
|
report.status(
|
||||||
|
"PROFILE_CONFIG_STATUS",
|
||||||
|
parent_pass and complete and counts_pass and thread_pass and binary_pass,
|
||||||
|
"MINIMAL_PROFILE_CONFIG_NOT_PROVEN",
|
||||||
|
)
|
||||||
|
return report.emit()
|
||||||
|
|
||||||
|
|
||||||
|
def extract_runtime_filename(text: str) -> list[str]:
|
||||||
|
return re.findall(r'(?m)^[ \t]*Filename[ \t]*=[ \t]*"([^"]+)"[ \t]*$', text)
|
||||||
|
|
||||||
|
|
||||||
|
def verify_runtime(packaged_path: Path, runtime_path: Path, run_dir: Path) -> int:
|
||||||
|
report = Report()
|
||||||
|
report.value("VERIFICATION_MODE", "RUNTIME")
|
||||||
|
try:
|
||||||
|
packaged_bytes, packaged = read_utf8(packaged_path)
|
||||||
|
runtime_bytes, runtime = read_utf8(runtime_path)
|
||||||
|
except (OSError, UnicodeError) as exc:
|
||||||
|
report.status(
|
||||||
|
"MINIMAL_RUNTIME_CONFIG_STATUS",
|
||||||
|
False,
|
||||||
|
f"INPUT_READ_FAILED_{type(exc).__name__}",
|
||||||
|
)
|
||||||
|
return report.emit()
|
||||||
|
|
||||||
|
supplied = str(run_dir)
|
||||||
|
absolute = run_dir.is_absolute()
|
||||||
|
exists = run_dir.is_dir()
|
||||||
|
placeholder_count = packaged.count(PLACEHOLDER)
|
||||||
|
unresolved_count = runtime.count(PLACEHOLDER)
|
||||||
|
expected_runtime = packaged.replace(PLACEHOLDER, supplied)
|
||||||
|
exact = runtime_bytes == expected_runtime.encode("utf-8")
|
||||||
|
filenames = extract_runtime_filename(runtime)
|
||||||
|
expected_filename = os.path.join(supplied, "s03_output.bin")
|
||||||
|
filename_pass = filenames.count(expected_filename) == 1 and len(filenames) == 1
|
||||||
|
|
||||||
|
report.value("PACKAGED_MINIMAL_SHA256", sha256_bytes(packaged_bytes))
|
||||||
|
report.value("RUNTIME_CONFIG_SHA256", sha256_bytes(runtime_bytes))
|
||||||
|
report.value("PACKAGED_PLACEHOLDER_COUNT", placeholder_count)
|
||||||
|
report.value("RUNTIME_UNRESOLVED_PLACEHOLDER_COUNT", unresolved_count)
|
||||||
|
report.value("RUNTIME_FILENAME", filenames[0] if len(filenames) == 1 else "AMBIGUOUS")
|
||||||
|
report.value("EXPECTED_RUNTIME_FILENAME", expected_filename)
|
||||||
|
report.status("RUN_DIR_ABSOLUTE_STATUS", absolute, "RUN_DIR_NOT_ABSOLUTE")
|
||||||
|
report.status("RUN_DIR_EXISTS_STATUS", exists, "RUN_DIR_NOT_FOUND")
|
||||||
|
report.status(
|
||||||
|
"PACKAGED_PLACEHOLDER_STATUS",
|
||||||
|
placeholder_count == 1,
|
||||||
|
"PACKAGED_PLACEHOLDER_COUNT_MISMATCH",
|
||||||
|
)
|
||||||
|
report.status(
|
||||||
|
"RUNTIME_PLACEHOLDER_RESOLUTION_STATUS",
|
||||||
|
unresolved_count == 0,
|
||||||
|
"RUNTIME_PLACEHOLDER_UNRESOLVED",
|
||||||
|
)
|
||||||
|
report.status(
|
||||||
|
"RUNTIME_FILENAME_STATUS", filename_pass, "RUNTIME_FILENAME_OUTSIDE_RUN_DIR"
|
||||||
|
)
|
||||||
|
report.status(
|
||||||
|
"MINIMAL_RUNTIME_CONFIG_STATUS",
|
||||||
|
absolute
|
||||||
|
and exists
|
||||||
|
and placeholder_count == 1
|
||||||
|
and unresolved_count == 0
|
||||||
|
and filename_pass
|
||||||
|
and exact,
|
||||||
|
"RUNTIME_DIFF_EXCEEDS_AUTHORIZED_SUBSTITUTION",
|
||||||
|
)
|
||||||
|
return report.emit()
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
subparsers = parser.add_subparsers(dest="mode", required=True)
|
||||||
|
|
||||||
|
canonical = subparsers.add_parser("CANONICAL")
|
||||||
|
canonical.add_argument("canonical_test", type=Path)
|
||||||
|
canonical.add_argument("packaged_minimal", type=Path)
|
||||||
|
|
||||||
|
runtime = subparsers.add_parser("RUNTIME")
|
||||||
|
runtime.add_argument("packaged_minimal", type=Path)
|
||||||
|
runtime.add_argument("runtime_configuration", type=Path)
|
||||||
|
runtime.add_argument("run_dir", type=Path)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
if args.mode == "CANONICAL":
|
||||||
|
return verify_canonical(args.canonical_test, args.packaged_minimal)
|
||||||
|
return verify_runtime(
|
||||||
|
args.packaged_minimal, args.runtime_configuration, args.run_dir
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
+589
@@ -0,0 +1,589 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Fail-closed parser for the MARTe2 S03 FileWriter binary contract."""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
UINT32_TYPE_HEX = "0408"
|
||||||
|
UINT32_BYTES = 4
|
||||||
|
SIGNAL_HEADER_BYTES = 2 + 32 + 4
|
||||||
|
|
||||||
|
SENTINEL_SCALAR_A = 324508639 # 0x13579BDF
|
||||||
|
SENTINEL_SCALAR_B = 610839776 # 0x2468ACE0
|
||||||
|
SENTINEL_VECTOR = (16909060, 286397204, 555885348)
|
||||||
|
|
||||||
|
EXPECTED_SIGNALS = (
|
||||||
|
("Counter", UINT32_TYPE_HEX, 1),
|
||||||
|
("Time", UINT32_TYPE_HEX, 1),
|
||||||
|
("State1_Thread1_CycleTime", UINT32_TYPE_HEX, 1),
|
||||||
|
("SentinelScalarA", UINT32_TYPE_HEX, 1),
|
||||||
|
("SentinelScalarB", UINT32_TYPE_HEX, 1),
|
||||||
|
("SentinelVector", UINT32_TYPE_HEX, 3),
|
||||||
|
)
|
||||||
|
|
||||||
|
EXPECTED_OFFSETS = (0, 4, 8, 12, 16, 20)
|
||||||
|
EXPECTED_RECORD_BYTES = 32
|
||||||
|
EXPECTED_HEADER_BYTES = 4 + len(EXPECTED_SIGNALS) * SIGNAL_HEADER_BYTES
|
||||||
|
|
||||||
|
STATUS_ORDER = (
|
||||||
|
"HEADER_STATUS",
|
||||||
|
"RECORD_LAYOUT_STATUS",
|
||||||
|
"PAYLOAD_ALIGNMENT_STATUS",
|
||||||
|
"TRUNCATION_STATUS",
|
||||||
|
"SIGNAL_COUNT_STATUS",
|
||||||
|
"SIGNAL_NAMES_STATUS",
|
||||||
|
"SIGNAL_TYPES_STATUS",
|
||||||
|
"SIGNAL_ELEMENTS_STATUS",
|
||||||
|
"SIGNAL_ORDER_STATUS",
|
||||||
|
"COUNTER_STATUS",
|
||||||
|
"TIME_STATUS",
|
||||||
|
"CYCLE_TIME_STATUS",
|
||||||
|
"SENTINEL_SCALAR_A_STATUS",
|
||||||
|
"SENTINEL_SCALAR_B_STATUS",
|
||||||
|
"SENTINEL_VECTOR_STATUS",
|
||||||
|
"SENTINEL_SEQUENCE_STATUS",
|
||||||
|
"FUNCTIONAL_BINARY_STATUS",
|
||||||
|
"SEMANTIC_BINARY_STATUS",
|
||||||
|
"BINARY_STATUS",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def safe_value(value):
|
||||||
|
return str(value).replace("\r", "\\r").replace("\n", "\\n")
|
||||||
|
|
||||||
|
|
||||||
|
class Report:
|
||||||
|
def __init__(self):
|
||||||
|
self.status = {name: "NOT_EVALUATED" for name in STATUS_ORDER}
|
||||||
|
self.details = {}
|
||||||
|
self.first_error = {
|
||||||
|
"FIRST_ERROR_CODE": "NONE",
|
||||||
|
"EXPECTED": "NOT_APPLICABLE",
|
||||||
|
"OBSERVED": "NOT_APPLICABLE",
|
||||||
|
"RECORD_INDEX": "NOT_APPLICABLE",
|
||||||
|
"SIGNAL_NAME": "NOT_APPLICABLE",
|
||||||
|
"ELEMENT_INDEX": "NOT_APPLICABLE",
|
||||||
|
"BYTE_OFFSET": "NOT_APPLICABLE",
|
||||||
|
}
|
||||||
|
|
||||||
|
def set_error(
|
||||||
|
self,
|
||||||
|
code,
|
||||||
|
expected="NOT_APPLICABLE",
|
||||||
|
observed="NOT_APPLICABLE",
|
||||||
|
record_index="NOT_APPLICABLE",
|
||||||
|
signal_name="NOT_APPLICABLE",
|
||||||
|
element_index="NOT_APPLICABLE",
|
||||||
|
byte_offset="NOT_APPLICABLE",
|
||||||
|
):
|
||||||
|
if self.first_error["FIRST_ERROR_CODE"] != "NONE":
|
||||||
|
return
|
||||||
|
self.first_error.update(
|
||||||
|
{
|
||||||
|
"FIRST_ERROR_CODE": safe_value(code),
|
||||||
|
"EXPECTED": safe_value(expected),
|
||||||
|
"OBSERVED": safe_value(observed),
|
||||||
|
"RECORD_INDEX": safe_value(record_index),
|
||||||
|
"SIGNAL_NAME": safe_value(signal_name),
|
||||||
|
"ELEMENT_INDEX": safe_value(element_index),
|
||||||
|
"BYTE_OFFSET": safe_value(byte_offset),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def emit(self):
|
||||||
|
for key in STATUS_ORDER:
|
||||||
|
print(f"{key}={self.status[key]}")
|
||||||
|
for key in sorted(self.details):
|
||||||
|
print(f"{key}={safe_value(self.details[key])}")
|
||||||
|
for key in (
|
||||||
|
"FIRST_ERROR_CODE",
|
||||||
|
"EXPECTED",
|
||||||
|
"OBSERVED",
|
||||||
|
"RECORD_INDEX",
|
||||||
|
"SIGNAL_NAME",
|
||||||
|
"ELEMENT_INDEX",
|
||||||
|
"BYTE_OFFSET",
|
||||||
|
):
|
||||||
|
print(f"{key}={self.first_error[key]}")
|
||||||
|
|
||||||
|
|
||||||
|
def padded_name(raw):
|
||||||
|
try:
|
||||||
|
return raw.split(b"\x00", 1)[0].decode("ascii")
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
return raw.split(b"\x00", 1)[0].decode("ascii", errors="replace")
|
||||||
|
|
||||||
|
|
||||||
|
def finish_early(report, exit_code):
|
||||||
|
report.status["FUNCTIONAL_BINARY_STATUS"] = "FAIL"
|
||||||
|
report.status["SEMANTIC_BINARY_STATUS"] = "NOT_DEMONSTRATED"
|
||||||
|
report.status["BINARY_STATUS"] = "FAIL"
|
||||||
|
report.emit()
|
||||||
|
return exit_code
|
||||||
|
|
||||||
|
|
||||||
|
def parse_binary(path, min_samples):
|
||||||
|
report = Report()
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = path.read_bytes()
|
||||||
|
except OSError as exc:
|
||||||
|
report.status["HEADER_STATUS"] = "FAIL"
|
||||||
|
report.status["TRUNCATION_STATUS"] = "FAIL"
|
||||||
|
report.details["FILE_SIZE_BYTES"] = "NOT_AVAILABLE"
|
||||||
|
report.set_error("FILE_READ_ERROR", observed=exc)
|
||||||
|
return report, finish_early(report, 31), True
|
||||||
|
|
||||||
|
report.details["FILE_SIZE_BYTES"] = len(data)
|
||||||
|
report.details["EXPECTED_HEADER_BYTES"] = EXPECTED_HEADER_BYTES
|
||||||
|
report.details["EXPECTED_RECORD_BYTES"] = EXPECTED_RECORD_BYTES
|
||||||
|
report.details["EXPECTED_SIGNAL_COUNT"] = len(EXPECTED_SIGNALS)
|
||||||
|
|
||||||
|
if len(data) < 4:
|
||||||
|
report.status["HEADER_STATUS"] = "FAIL"
|
||||||
|
report.status["TRUNCATION_STATUS"] = "FAIL"
|
||||||
|
report.status["SIGNAL_COUNT_STATUS"] = "NOT_EVALUATED"
|
||||||
|
report.set_error(
|
||||||
|
"HEADER_TOO_SMALL",
|
||||||
|
expected="AT_LEAST_4_BYTES",
|
||||||
|
observed=f"{len(data)}_BYTES",
|
||||||
|
byte_offset=len(data),
|
||||||
|
)
|
||||||
|
return report, 31, False
|
||||||
|
|
||||||
|
signal_count = struct.unpack_from("<I", data, 0)[0]
|
||||||
|
report.details["OBSERVED_SIGNAL_COUNT"] = signal_count
|
||||||
|
|
||||||
|
if signal_count > 4096:
|
||||||
|
report.status["HEADER_STATUS"] = "FAIL"
|
||||||
|
report.status["TRUNCATION_STATUS"] = "FAIL"
|
||||||
|
report.status["SIGNAL_COUNT_STATUS"] = "FAIL"
|
||||||
|
report.set_error(
|
||||||
|
"SIGNAL_COUNT_UNREASONABLE",
|
||||||
|
expected=len(EXPECTED_SIGNALS),
|
||||||
|
observed=signal_count,
|
||||||
|
byte_offset=0,
|
||||||
|
)
|
||||||
|
return report, 32, False
|
||||||
|
|
||||||
|
if signal_count == len(EXPECTED_SIGNALS):
|
||||||
|
report.status["SIGNAL_COUNT_STATUS"] = "PASS"
|
||||||
|
else:
|
||||||
|
report.status["SIGNAL_COUNT_STATUS"] = "FAIL"
|
||||||
|
report.set_error(
|
||||||
|
"SIGNAL_COUNT_MISMATCH",
|
||||||
|
expected=len(EXPECTED_SIGNALS),
|
||||||
|
observed=signal_count,
|
||||||
|
byte_offset=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
offset = 4
|
||||||
|
observed = []
|
||||||
|
for index in range(signal_count):
|
||||||
|
if offset + SIGNAL_HEADER_BYTES > len(data):
|
||||||
|
report.status["HEADER_STATUS"] = "FAIL"
|
||||||
|
report.status["TRUNCATION_STATUS"] = "FAIL"
|
||||||
|
report.set_error(
|
||||||
|
"TRUNCATED_SIGNAL_HEADER",
|
||||||
|
expected=SIGNAL_HEADER_BYTES,
|
||||||
|
observed=max(0, len(data) - offset),
|
||||||
|
signal_name=f"SIGNAL_{index}",
|
||||||
|
byte_offset=offset,
|
||||||
|
)
|
||||||
|
report.details["OBSERVED_HEADER_BYTES"] = offset
|
||||||
|
return report, 33, False
|
||||||
|
|
||||||
|
type_offset = offset
|
||||||
|
type_hex = data[offset : offset + 2].hex()
|
||||||
|
offset += 2
|
||||||
|
name_offset = offset
|
||||||
|
name = padded_name(data[offset : offset + 32])
|
||||||
|
offset += 32
|
||||||
|
elements_offset = offset
|
||||||
|
elements = struct.unpack_from("<I", data, offset)[0]
|
||||||
|
offset += 4
|
||||||
|
|
||||||
|
observed.append(
|
||||||
|
{
|
||||||
|
"name": name,
|
||||||
|
"type_hex": type_hex,
|
||||||
|
"elements": elements,
|
||||||
|
"type_offset": type_offset,
|
||||||
|
"name_offset": name_offset,
|
||||||
|
"elements_offset": elements_offset,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
report.details[f"SIGNAL_{index}_NAME"] = name
|
||||||
|
report.details[f"SIGNAL_{index}_TYPE_HEX"] = type_hex
|
||||||
|
report.details[f"SIGNAL_{index}_NUMBER_OF_ELEMENTS"] = elements
|
||||||
|
|
||||||
|
report.status["HEADER_STATUS"] = "PASS"
|
||||||
|
report.details["OBSERVED_HEADER_BYTES"] = offset
|
||||||
|
header_bytes = offset
|
||||||
|
|
||||||
|
observed_names = [item["name"] for item in observed]
|
||||||
|
expected_names = [item[0] for item in EXPECTED_SIGNALS]
|
||||||
|
report.details["OBSERVED_SIGNAL_NAMES"] = ",".join(observed_names)
|
||||||
|
report.details["EXPECTED_SIGNAL_NAMES"] = ",".join(expected_names)
|
||||||
|
|
||||||
|
duplicates = sorted({name for name in observed_names if observed_names.count(name) > 1})
|
||||||
|
if duplicates:
|
||||||
|
report.status["SIGNAL_NAMES_STATUS"] = "FAIL"
|
||||||
|
report.status["SIGNAL_ORDER_STATUS"] = "FAIL"
|
||||||
|
report.set_error(
|
||||||
|
"DUPLICATE_SIGNAL_NAME",
|
||||||
|
expected="UNIQUE_NAMES",
|
||||||
|
observed=",".join(duplicates),
|
||||||
|
)
|
||||||
|
elif sorted(observed_names) == sorted(expected_names):
|
||||||
|
report.status["SIGNAL_NAMES_STATUS"] = "PASS"
|
||||||
|
if observed_names == expected_names:
|
||||||
|
report.status["SIGNAL_ORDER_STATUS"] = "PASS"
|
||||||
|
else:
|
||||||
|
report.status["SIGNAL_ORDER_STATUS"] = "FAIL"
|
||||||
|
first_index = next(
|
||||||
|
index
|
||||||
|
for index, pair in enumerate(zip(observed_names, expected_names))
|
||||||
|
if pair[0] != pair[1]
|
||||||
|
)
|
||||||
|
report.set_error(
|
||||||
|
"SIGNAL_ORDER_MISMATCH",
|
||||||
|
expected=expected_names[first_index],
|
||||||
|
observed=observed_names[first_index],
|
||||||
|
signal_name=observed_names[first_index],
|
||||||
|
byte_offset=observed[first_index]["name_offset"],
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
report.status["SIGNAL_NAMES_STATUS"] = "FAIL"
|
||||||
|
report.status["SIGNAL_ORDER_STATUS"] = "FAIL"
|
||||||
|
mismatch_index = 0
|
||||||
|
for mismatch_index in range(min(len(observed_names), len(expected_names))):
|
||||||
|
if observed_names[mismatch_index] != expected_names[mismatch_index]:
|
||||||
|
break
|
||||||
|
observed_name = (
|
||||||
|
observed_names[mismatch_index]
|
||||||
|
if mismatch_index < len(observed_names)
|
||||||
|
else "MISSING"
|
||||||
|
)
|
||||||
|
expected_name = (
|
||||||
|
expected_names[mismatch_index]
|
||||||
|
if mismatch_index < len(expected_names)
|
||||||
|
else "NO_ADDITIONAL_SIGNAL"
|
||||||
|
)
|
||||||
|
byte_offset = (
|
||||||
|
observed[mismatch_index]["name_offset"]
|
||||||
|
if mismatch_index < len(observed)
|
||||||
|
else header_bytes
|
||||||
|
)
|
||||||
|
report.set_error(
|
||||||
|
"SIGNAL_NAME_MISMATCH",
|
||||||
|
expected=expected_name,
|
||||||
|
observed=observed_name,
|
||||||
|
signal_name=observed_name,
|
||||||
|
byte_offset=byte_offset,
|
||||||
|
)
|
||||||
|
|
||||||
|
types_ok = len(observed) == len(EXPECTED_SIGNALS)
|
||||||
|
elements_ok = len(observed) == len(EXPECTED_SIGNALS)
|
||||||
|
observed_offsets = []
|
||||||
|
running_offset = 0
|
||||||
|
|
||||||
|
for index, item in enumerate(observed):
|
||||||
|
observed_offsets.append(running_offset)
|
||||||
|
width = UINT32_BYTES if item["type_hex"] == UINT32_TYPE_HEX else UINT32_BYTES
|
||||||
|
running_offset += width * item["elements"]
|
||||||
|
report.details[f"SIGNAL_{index}_OBSERVED_OFFSET"] = observed_offsets[-1]
|
||||||
|
if index < len(EXPECTED_OFFSETS):
|
||||||
|
report.details[f"SIGNAL_{index}_EXPECTED_OFFSET"] = EXPECTED_OFFSETS[index]
|
||||||
|
|
||||||
|
if index >= len(EXPECTED_SIGNALS):
|
||||||
|
types_ok = False
|
||||||
|
elements_ok = False
|
||||||
|
continue
|
||||||
|
|
||||||
|
expected_name, expected_type, expected_elements = EXPECTED_SIGNALS[index]
|
||||||
|
if item["type_hex"] != expected_type:
|
||||||
|
types_ok = False
|
||||||
|
report.set_error(
|
||||||
|
"SIGNAL_TYPE_MISMATCH",
|
||||||
|
expected=expected_type,
|
||||||
|
observed=item["type_hex"],
|
||||||
|
signal_name=expected_name,
|
||||||
|
byte_offset=item["type_offset"],
|
||||||
|
)
|
||||||
|
if item["elements"] != expected_elements:
|
||||||
|
elements_ok = False
|
||||||
|
report.set_error(
|
||||||
|
"SIGNAL_ELEMENTS_MISMATCH",
|
||||||
|
expected=expected_elements,
|
||||||
|
observed=item["elements"],
|
||||||
|
signal_name=expected_name,
|
||||||
|
byte_offset=item["elements_offset"],
|
||||||
|
)
|
||||||
|
|
||||||
|
report.status["SIGNAL_TYPES_STATUS"] = "PASS" if types_ok else "FAIL"
|
||||||
|
report.status["SIGNAL_ELEMENTS_STATUS"] = "PASS" if elements_ok else "FAIL"
|
||||||
|
report.details["OBSERVED_RECORD_BYTES_FROM_HEADER"] = running_offset
|
||||||
|
|
||||||
|
layout_ok = all(
|
||||||
|
report.status[name] == "PASS"
|
||||||
|
for name in (
|
||||||
|
"SIGNAL_COUNT_STATUS",
|
||||||
|
"SIGNAL_NAMES_STATUS",
|
||||||
|
"SIGNAL_TYPES_STATUS",
|
||||||
|
"SIGNAL_ELEMENTS_STATUS",
|
||||||
|
"SIGNAL_ORDER_STATUS",
|
||||||
|
)
|
||||||
|
) and observed_offsets == list(EXPECTED_OFFSETS)
|
||||||
|
|
||||||
|
report.status["RECORD_LAYOUT_STATUS"] = "PASS" if layout_ok else "FAIL"
|
||||||
|
if not layout_ok and report.first_error["FIRST_ERROR_CODE"] == "NONE":
|
||||||
|
report.set_error(
|
||||||
|
"RECORD_LAYOUT_MISMATCH",
|
||||||
|
expected=EXPECTED_RECORD_BYTES,
|
||||||
|
observed=running_offset,
|
||||||
|
)
|
||||||
|
|
||||||
|
payload_bytes = len(data) - header_bytes
|
||||||
|
remainder_bytes = payload_bytes % EXPECTED_RECORD_BYTES
|
||||||
|
sample_count = payload_bytes // EXPECTED_RECORD_BYTES
|
||||||
|
report.details["PAYLOAD_BYTES"] = payload_bytes
|
||||||
|
report.details["PAYLOAD_REMAINDER_BYTES"] = remainder_bytes
|
||||||
|
report.details["COMPLETE_SAMPLE_COUNT"] = sample_count
|
||||||
|
report.details["MINIMUM_SAMPLE_COUNT"] = min_samples
|
||||||
|
|
||||||
|
if remainder_bytes == 0:
|
||||||
|
report.status["PAYLOAD_ALIGNMENT_STATUS"] = "PASS"
|
||||||
|
report.status["TRUNCATION_STATUS"] = "PASS"
|
||||||
|
else:
|
||||||
|
report.status["PAYLOAD_ALIGNMENT_STATUS"] = "FAIL"
|
||||||
|
report.status["TRUNCATION_STATUS"] = "FAIL"
|
||||||
|
report.set_error(
|
||||||
|
"PAYLOAD_SIZE_NOT_MULTIPLE_OF_RECORD",
|
||||||
|
expected=f"MULTIPLE_OF_{EXPECTED_RECORD_BYTES}",
|
||||||
|
observed=f"REMAINDER_{remainder_bytes}",
|
||||||
|
byte_offset=header_bytes + sample_count * EXPECTED_RECORD_BYTES,
|
||||||
|
)
|
||||||
|
|
||||||
|
if sample_count < min_samples:
|
||||||
|
report.set_error(
|
||||||
|
"INSUFFICIENT_SAMPLES",
|
||||||
|
expected=f"AT_LEAST_{min_samples}",
|
||||||
|
observed=sample_count,
|
||||||
|
)
|
||||||
|
|
||||||
|
records = []
|
||||||
|
if remainder_bytes == 0:
|
||||||
|
for record_index in range(sample_count):
|
||||||
|
start = header_bytes + record_index * EXPECTED_RECORD_BYTES
|
||||||
|
records.append(struct.unpack_from("<8I", data, start))
|
||||||
|
|
||||||
|
counters = [record[0] for record in records]
|
||||||
|
times = [record[1] for record in records]
|
||||||
|
cycle_times = [record[2] for record in records]
|
||||||
|
|
||||||
|
counter_error = None
|
||||||
|
if counters:
|
||||||
|
if counters[0] != 1:
|
||||||
|
counter_error = (0, 1, counters[0])
|
||||||
|
else:
|
||||||
|
for index in range(1, len(counters)):
|
||||||
|
if counters[index] != counters[index - 1] + 1:
|
||||||
|
counter_error = (index, counters[index - 1] + 1, counters[index])
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
counter_error = ("NOT_APPLICABLE", "AT_LEAST_ONE_RECORD", "NO_RECORDS")
|
||||||
|
|
||||||
|
if counter_error is None:
|
||||||
|
report.status["COUNTER_STATUS"] = "PASS"
|
||||||
|
else:
|
||||||
|
report.status["COUNTER_STATUS"] = "FAIL"
|
||||||
|
record_index, expected_counter, observed_counter = counter_error
|
||||||
|
byte_offset = (
|
||||||
|
header_bytes + int(record_index) * EXPECTED_RECORD_BYTES
|
||||||
|
if isinstance(record_index, int)
|
||||||
|
else header_bytes
|
||||||
|
)
|
||||||
|
report.set_error(
|
||||||
|
"COUNTER_SEQUENCE_MISMATCH",
|
||||||
|
expected=expected_counter,
|
||||||
|
observed=observed_counter,
|
||||||
|
record_index=record_index,
|
||||||
|
signal_name="Counter",
|
||||||
|
element_index=0,
|
||||||
|
byte_offset=byte_offset,
|
||||||
|
)
|
||||||
|
|
||||||
|
time_error = None
|
||||||
|
for index in range(1, len(times)):
|
||||||
|
if times[index] < times[index - 1]:
|
||||||
|
time_error = (index, f">={times[index - 1]}", times[index])
|
||||||
|
break
|
||||||
|
if records and time_error is None:
|
||||||
|
report.status["TIME_STATUS"] = "PASS"
|
||||||
|
else:
|
||||||
|
report.status["TIME_STATUS"] = "FAIL"
|
||||||
|
if time_error is not None:
|
||||||
|
record_index, expected_time, observed_time = time_error
|
||||||
|
report.set_error(
|
||||||
|
"TIME_REGRESSION",
|
||||||
|
expected=expected_time,
|
||||||
|
observed=observed_time,
|
||||||
|
record_index=record_index,
|
||||||
|
signal_name="Time",
|
||||||
|
element_index=0,
|
||||||
|
byte_offset=header_bytes + record_index * EXPECTED_RECORD_BYTES + 4,
|
||||||
|
)
|
||||||
|
|
||||||
|
nonzero_cycle_times = [value for value in cycle_times if value > 0]
|
||||||
|
if records and nonzero_cycle_times:
|
||||||
|
report.status["CYCLE_TIME_STATUS"] = "PASS"
|
||||||
|
else:
|
||||||
|
report.status["CYCLE_TIME_STATUS"] = "FAIL"
|
||||||
|
report.set_error(
|
||||||
|
"NO_NONZERO_CYCLE_TIME",
|
||||||
|
expected="AT_LEAST_ONE_NONZERO_SAMPLE",
|
||||||
|
observed=len(nonzero_cycle_times),
|
||||||
|
signal_name="State1_Thread1_CycleTime",
|
||||||
|
byte_offset=header_bytes + 8,
|
||||||
|
)
|
||||||
|
|
||||||
|
sentinel_failures = {
|
||||||
|
"A": None,
|
||||||
|
"B": None,
|
||||||
|
"VECTOR": None,
|
||||||
|
}
|
||||||
|
|
||||||
|
for record_index, record in enumerate(records):
|
||||||
|
if sentinel_failures["A"] is None and record[3] != SENTINEL_SCALAR_A:
|
||||||
|
sentinel_failures["A"] = (record_index, 0, SENTINEL_SCALAR_A, record[3], 12)
|
||||||
|
if sentinel_failures["B"] is None and record[4] != SENTINEL_SCALAR_B:
|
||||||
|
sentinel_failures["B"] = (record_index, 0, SENTINEL_SCALAR_B, record[4], 16)
|
||||||
|
for element_index, expected_value in enumerate(SENTINEL_VECTOR):
|
||||||
|
observed_value = record[5 + element_index]
|
||||||
|
if sentinel_failures["VECTOR"] is None and observed_value != expected_value:
|
||||||
|
sentinel_failures["VECTOR"] = (
|
||||||
|
record_index,
|
||||||
|
element_index,
|
||||||
|
expected_value,
|
||||||
|
observed_value,
|
||||||
|
20 + element_index * UINT32_BYTES,
|
||||||
|
)
|
||||||
|
|
||||||
|
for key, status_name, signal_name in (
|
||||||
|
("A", "SENTINEL_SCALAR_A_STATUS", "SentinelScalarA"),
|
||||||
|
("B", "SENTINEL_SCALAR_B_STATUS", "SentinelScalarB"),
|
||||||
|
("VECTOR", "SENTINEL_VECTOR_STATUS", "SentinelVector"),
|
||||||
|
):
|
||||||
|
failure = sentinel_failures[key]
|
||||||
|
if records and failure is None:
|
||||||
|
report.status[status_name] = "PASS"
|
||||||
|
else:
|
||||||
|
report.status[status_name] = "FAIL"
|
||||||
|
if failure is not None:
|
||||||
|
record_index, element_index, expected_value, observed_value, field_offset = failure
|
||||||
|
code = {
|
||||||
|
"A": "SENTINEL_SCALAR_A_MISMATCH",
|
||||||
|
"B": "SENTINEL_SCALAR_B_MISMATCH",
|
||||||
|
"VECTOR": "SENTINEL_VECTOR_MISMATCH",
|
||||||
|
}[key]
|
||||||
|
report.set_error(
|
||||||
|
code,
|
||||||
|
expected=expected_value,
|
||||||
|
observed=observed_value,
|
||||||
|
record_index=record_index,
|
||||||
|
signal_name=signal_name,
|
||||||
|
element_index=element_index,
|
||||||
|
byte_offset=header_bytes
|
||||||
|
+ record_index * EXPECTED_RECORD_BYTES
|
||||||
|
+ field_offset,
|
||||||
|
)
|
||||||
|
|
||||||
|
sentinel_values_ok = all(
|
||||||
|
report.status[name] == "PASS"
|
||||||
|
for name in (
|
||||||
|
"SENTINEL_SCALAR_A_STATUS",
|
||||||
|
"SENTINEL_SCALAR_B_STATUS",
|
||||||
|
"SENTINEL_VECTOR_STATUS",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
report.status["SENTINEL_SEQUENCE_STATUS"] = (
|
||||||
|
"PASS" if sentinel_values_ok and records else "FAIL"
|
||||||
|
)
|
||||||
|
|
||||||
|
if counters:
|
||||||
|
report.details["COUNTER_FIRST"] = counters[0]
|
||||||
|
report.details["COUNTER_LAST"] = counters[-1]
|
||||||
|
if times:
|
||||||
|
report.details["TIME_FIRST"] = times[0]
|
||||||
|
report.details["TIME_LAST"] = times[-1]
|
||||||
|
report.details["NONZERO_CYCLE_TIME_SAMPLES"] = len(nonzero_cycle_times)
|
||||||
|
if nonzero_cycle_times:
|
||||||
|
report.details["CYCLE_TIME_MIN"] = min(nonzero_cycle_times)
|
||||||
|
report.details["CYCLE_TIME_MAX"] = max(nonzero_cycle_times)
|
||||||
|
|
||||||
|
base_header_ok = len(observed) >= 3 and all(
|
||||||
|
(
|
||||||
|
observed[index]["name"],
|
||||||
|
observed[index]["type_hex"],
|
||||||
|
observed[index]["elements"],
|
||||||
|
)
|
||||||
|
== EXPECTED_SIGNALS[index]
|
||||||
|
for index in range(3)
|
||||||
|
)
|
||||||
|
|
||||||
|
functional_ok = (
|
||||||
|
report.status["HEADER_STATUS"] == "PASS"
|
||||||
|
and base_header_ok
|
||||||
|
and report.status["PAYLOAD_ALIGNMENT_STATUS"] == "PASS"
|
||||||
|
and sample_count >= min_samples
|
||||||
|
and report.status["COUNTER_STATUS"] == "PASS"
|
||||||
|
and report.status["TIME_STATUS"] == "PASS"
|
||||||
|
and report.status["CYCLE_TIME_STATUS"] == "PASS"
|
||||||
|
)
|
||||||
|
|
||||||
|
semantic_ok = (
|
||||||
|
layout_ok
|
||||||
|
and report.status["PAYLOAD_ALIGNMENT_STATUS"] == "PASS"
|
||||||
|
and sample_count >= min_samples
|
||||||
|
and sentinel_values_ok
|
||||||
|
and report.status["SENTINEL_SEQUENCE_STATUS"] == "PASS"
|
||||||
|
)
|
||||||
|
|
||||||
|
report.status["FUNCTIONAL_BINARY_STATUS"] = "PASS" if functional_ok else "FAIL"
|
||||||
|
report.status["SEMANTIC_BINARY_STATUS"] = "PASS" if semantic_ok else "FAIL"
|
||||||
|
report.status["BINARY_STATUS"] = (
|
||||||
|
"PASS" if functional_ok and semantic_ok else "FAIL"
|
||||||
|
)
|
||||||
|
|
||||||
|
return report, 0 if report.status["BINARY_STATUS"] == "PASS" else 40, False
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Validate the S03 MARTe2 FileWriter binary contract."
|
||||||
|
)
|
||||||
|
parser.add_argument("binary", type=Path)
|
||||||
|
parser.add_argument("--min-samples", type=int, default=50)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.min_samples < 1:
|
||||||
|
parser.error("--min-samples must be at least 1")
|
||||||
|
|
||||||
|
report, exit_code, already_emitted = parse_binary(args.binary, args.min_samples)
|
||||||
|
if not already_emitted:
|
||||||
|
if report.status["FUNCTIONAL_BINARY_STATUS"] == "NOT_EVALUATED":
|
||||||
|
report.status["FUNCTIONAL_BINARY_STATUS"] = "FAIL"
|
||||||
|
if report.status["SEMANTIC_BINARY_STATUS"] == "NOT_EVALUATED":
|
||||||
|
report.status["SEMANTIC_BINARY_STATUS"] = "NOT_DEMONSTRATED"
|
||||||
|
if report.status["BINARY_STATUS"] == "NOT_EVALUATED":
|
||||||
|
report.status["BINARY_STATUS"] = "FAIL"
|
||||||
|
report.emit()
|
||||||
|
return exit_code
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
Executable
+347
@@ -0,0 +1,347 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -u
|
||||||
|
|
||||||
|
EXPECTED_S03_CONFIG_SHA256="0f8916735ff67a9be2b167b52f147687fe131a063f410a81bfbf3bf9ff65f1e4"
|
||||||
|
MINIMUM_SAMPLES="50"
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PARSER="$SCRIPT_DIR/parse_s03_binary.py"
|
||||||
|
|
||||||
|
FUNCTIONAL_STATUS="NOT_DEMONSTRATED"
|
||||||
|
SEMANTIC_STATUS="NOT_DEMONSTRATED"
|
||||||
|
TIMING_STATUS="NOT_EVALUATED"
|
||||||
|
MEASUREMENT_ELIGIBILITY="NO"
|
||||||
|
|
||||||
|
emit_contract() {
|
||||||
|
printf "FUNCTIONAL_STATUS=%s\n" "$FUNCTIONAL_STATUS"
|
||||||
|
printf "SEMANTIC_STATUS=%s\n" "$SEMANTIC_STATUS"
|
||||||
|
printf "TIMING_STATUS=%s\n" "$TIMING_STATUS"
|
||||||
|
printf "MEASUREMENT_ELIGIBILITY=%s\n" "$MEASUREMENT_ELIGIBILITY"
|
||||||
|
}
|
||||||
|
|
||||||
|
fail_early() {
|
||||||
|
code="$1"
|
||||||
|
shift
|
||||||
|
printf "[NON DIMOSTRATO] %s\n" "$*" >&2
|
||||||
|
emit_contract
|
||||||
|
printf "VALIDATION_RESULT=FAIL_REQUIRED_INPUT\n"
|
||||||
|
exit "$code"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$#" -ne 1 ]; then
|
||||||
|
printf "Uso: %s <directory-run|run.log>\n" "$0" >&2
|
||||||
|
emit_contract
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
INPUT_PATH="$1"
|
||||||
|
if [ -d "$INPUT_PATH" ]; then
|
||||||
|
RUN_DIR="$(cd "$INPUT_PATH" && pwd)"
|
||||||
|
RUN_LOG="$RUN_DIR/run.log"
|
||||||
|
elif [ -f "$INPUT_PATH" ]; then
|
||||||
|
RUN_LOG="$(cd "$(dirname "$INPUT_PATH")" && pwd)/$(basename "$INPUT_PATH")"
|
||||||
|
RUN_DIR="$(dirname "$RUN_LOG")"
|
||||||
|
else
|
||||||
|
fail_early 21 "Percorso di validazione non trovato: $INPUT_PATH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
RUN_CONFIG="$RUN_DIR/configuration.marte"
|
||||||
|
OUTPUT_FILE="$RUN_DIR/s03_output.bin"
|
||||||
|
RUNNER_SUMMARY="$RUN_DIR/runner_summary.txt"
|
||||||
|
RUN_HASHES="$RUN_DIR/hashes.sha256"
|
||||||
|
|
||||||
|
if [ ! -x "$PARSER" ]; then
|
||||||
|
fail_early 21 "Parser S03 assente o non eseguibile: $PARSER"
|
||||||
|
fi
|
||||||
|
|
||||||
|
for required_file in \
|
||||||
|
"$RUN_LOG" \
|
||||||
|
"$RUN_CONFIG" \
|
||||||
|
"$OUTPUT_FILE" \
|
||||||
|
"$RUNNER_SUMMARY" \
|
||||||
|
"$RUN_HASHES"
|
||||||
|
do
|
||||||
|
if [ ! -f "$required_file" ]; then
|
||||||
|
fail_early 21 "File richiesto assente: $required_file"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ ! -s "$RUN_HASHES" ]; then
|
||||||
|
fail_early 21 "Manifest hash assente o vuoto: $RUN_HASHES"
|
||||||
|
fi
|
||||||
|
|
||||||
|
count_lines() {
|
||||||
|
pattern="$1"
|
||||||
|
file="$2"
|
||||||
|
grep -Ec "$pattern" "$file" || true
|
||||||
|
}
|
||||||
|
|
||||||
|
START_LINES="$(count_lines '^\[Information - RealTimeLoader\.cpp:[0-9]+\]: Started application in state State1[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
APPLICATION_START_LINES="$(count_lines '^\[Information - MARTeApp\.cpp:[0-9]+\]: Application starting[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
FILE_OPEN_LINES="$(count_lines '^\[Information - FileWriter\.cpp:[0-9]+\]: Going to open file with name ' "$RUN_LOG")"
|
||||||
|
SIGINT_LINES="$(count_lines '^\[Information - Bootstrap\.cpp:[0-9]+\]: Application recieved SIGINT\.[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
STOP_OK_LINES="$(count_lines '^\[Information - Bootstrap\.cpp:[0-9]+\]: Application successfully stopped\.[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
TERMINATED_LINES="$(count_lines '^\[NoError - MARTeApp\.cpp:[0-9]+\]: Application terminated[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
|
||||||
|
STARTUP_ERROR_LINES="$(count_lines 'Failed dlopen|Failed CreateByName|Failed to Initialise object|Failed to initialise the ObjectRegistryDatabase|Could not Initialise the loader' "$RUN_LOG")"
|
||||||
|
FATAL_ERROR_LINES="$(count_lines '^\[FatalError ' "$RUN_LOG")"
|
||||||
|
OS_ERROR_LINES="$(count_lines '^\[OSError ' "$RUN_LOG")"
|
||||||
|
ERROR_LINES="$(count_lines '^\[Error ' "$RUN_LOG")"
|
||||||
|
INITIALISATION_ERROR_LINES="$(count_lines '^\[InitialisationEr ' "$RUN_LOG")"
|
||||||
|
WARNING_LINES="$(count_lines '^\[Warning ' "$RUN_LOG")"
|
||||||
|
|
||||||
|
PRIORITY_CLIP_LINES="$(count_lines '^\[Warning - Threads\.cpp:[0-9]+\]: Requested a thread priority that is higher than ' "$RUN_LOG")"
|
||||||
|
PRIORITY_FAIL_LINES="$(count_lines '^\[Warning - Threads\.cpp:[0-9]+\]: Failed to change the thread priority' "$RUN_LOG")"
|
||||||
|
LINUX_TIMER_DEFAULT_WARNING_LINES="$(count_lines '^\[Warning - LinuxTimer\.cpp:[0-9]+\]: (ExecutionMode|CPUMask|StackSize) not specified using: ' "$RUN_LOG")"
|
||||||
|
CONFIG_DB_NODE_WARNING_LINES="$(count_lines '^\[Warning - MARTeApp\.cpp:[0-9]+\]: \[ConfigurationDatabaseNode\] - instances: [0-9]+[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
|
||||||
|
UNCLASSIFIED_WARNING_LINES=$((
|
||||||
|
WARNING_LINES -
|
||||||
|
PRIORITY_CLIP_LINES -
|
||||||
|
PRIORITY_FAIL_LINES -
|
||||||
|
LINUX_TIMER_DEFAULT_WARNING_LINES -
|
||||||
|
CONFIG_DB_NODE_WARNING_LINES
|
||||||
|
))
|
||||||
|
if [ "$UNCLASSIFIED_WARNING_LINES" -lt 0 ]; then
|
||||||
|
UNCLASSIFIED_WARNING_LINES=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
DOUBLE_STOP_LINES="$(count_lines '^\[FatalError - RealTimeApplication\.cpp:[0-9]+\]: Could not stop the RealTimeApplication\. Was it ever started\?[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
ASYNC_EVENTSEM_CLOSE_LINES="$(count_lines '^\[FatalError - MemoryMapAsyncOutputBroker\.cpp:[0-9]+\]: Could not Close the EventSem\.[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
PTHREAD_MUTEX_DESTROY_LINES="$(count_lines '^\[OSError - EventSem\.cpp:[0-9]+\]: Error: pthread_mutex_destroy\(\)[[:space:]]*$' "$RUN_LOG")"
|
||||||
|
|
||||||
|
UNCLASSIFIED_FATAL_LINES=$((FATAL_ERROR_LINES - DOUBLE_STOP_LINES - ASYNC_EVENTSEM_CLOSE_LINES))
|
||||||
|
UNCLASSIFIED_OS_ERROR_LINES=$((OS_ERROR_LINES - PTHREAD_MUTEX_DESTROY_LINES))
|
||||||
|
if [ "$UNCLASSIFIED_FATAL_LINES" -lt 0 ]; then
|
||||||
|
UNCLASSIFIED_FATAL_LINES=0
|
||||||
|
fi
|
||||||
|
if [ "$UNCLASSIFIED_OS_ERROR_LINES" -lt 0 ]; then
|
||||||
|
UNCLASSIFIED_OS_ERROR_LINES=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
CONFIG_REPORT="$(mktemp "${TMPDIR:-/tmp}/s03_validator_config_XXXXXX.log")" || exit 22
|
||||||
|
BINARY_REPORT="$(mktemp "${TMPDIR:-/tmp}/s03_validator_binary_XXXXXX.log")" || exit 22
|
||||||
|
HASH_REPORT="$(mktemp "${TMPDIR:-/tmp}/s03_validator_hashes_XXXXXX.log")" || exit 22
|
||||||
|
trap 'rm -f -- "$CONFIG_REPORT" "$BINARY_REPORT" "$HASH_REPORT"' EXIT HUP INT TERM
|
||||||
|
|
||||||
|
EXPECTED_FILENAME="$RUN_DIR/s03_output.bin"
|
||||||
|
PYTHONHASHSEED=0 python3 - \
|
||||||
|
"$RUN_CONFIG" \
|
||||||
|
"$EXPECTED_FILENAME" \
|
||||||
|
"$EXPECTED_S03_CONFIG_SHA256" \
|
||||||
|
>"$CONFIG_REPORT" 2>&1 <<'PY_S03_CONFIG'
|
||||||
|
import hashlib
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
config_path = Path(sys.argv[1])
|
||||||
|
expected_filename = sys.argv[2]
|
||||||
|
expected_hash = sys.argv[3]
|
||||||
|
text = config_path.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
expected_line = f' Filename = "{expected_filename}"'
|
||||||
|
placeholder_line = ' Filename = "__MARTE_RUN_DIR__/s03_output.bin"'
|
||||||
|
filename_count = sum(1 for line in text.splitlines() if line == expected_line)
|
||||||
|
placeholder_count = text.count("__MARTE_RUN_DIR__")
|
||||||
|
|
||||||
|
canonical = text.replace(expected_line, placeholder_line, 1)
|
||||||
|
canonical_hash = hashlib.sha256(canonical.encode("utf-8")).hexdigest()
|
||||||
|
|
||||||
|
checks = {
|
||||||
|
"EXPECTED_FILENAME_COUNT": filename_count,
|
||||||
|
"PLACEHOLDER_COUNT": placeholder_count,
|
||||||
|
"FILEWRITER_CLASS_COUNT": text.count("Class = FileDataSource::FileWriter"),
|
||||||
|
"PLAIN_FILEWRITER_CLASS_COUNT": text.count("Class = FileWriter"),
|
||||||
|
"CONSTANT_GAM_COUNT": text.count("Class = ConstantGAM"),
|
||||||
|
"SENTINEL_SCALAR_A_DECLARATION_COUNT": text.count("SentinelScalarA ="),
|
||||||
|
"SENTINEL_SCALAR_B_DECLARATION_COUNT": text.count("SentinelScalarB ="),
|
||||||
|
"SENTINEL_VECTOR_DECLARATION_COUNT": text.count("SentinelVector ="),
|
||||||
|
"VECTOR_DIMENSION_COUNT": text.count("NumberOfDimensions = 1"),
|
||||||
|
"VECTOR_CARDINALITY_COUNT": text.count("NumberOfElements = 3"),
|
||||||
|
"THREAD_ORDER_COUNT": text.count(
|
||||||
|
"Functions = {GAMTimer SentinelProducer GAMDisplay IOGAM_Writer}"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
expected_checks = {
|
||||||
|
"EXPECTED_FILENAME_COUNT": 1,
|
||||||
|
"PLACEHOLDER_COUNT": 0,
|
||||||
|
"FILEWRITER_CLASS_COUNT": 1,
|
||||||
|
"PLAIN_FILEWRITER_CLASS_COUNT": 0,
|
||||||
|
"CONSTANT_GAM_COUNT": 1,
|
||||||
|
"SENTINEL_SCALAR_A_DECLARATION_COUNT": 4,
|
||||||
|
"SENTINEL_SCALAR_B_DECLARATION_COUNT": 4,
|
||||||
|
"SENTINEL_VECTOR_DECLARATION_COUNT": 4,
|
||||||
|
"VECTOR_DIMENSION_COUNT": 4,
|
||||||
|
"VECTOR_CARDINALITY_COUNT": 4,
|
||||||
|
"THREAD_ORDER_COUNT": 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
for key in sorted(checks):
|
||||||
|
print(f"{key}={checks[key]}")
|
||||||
|
print(f"CANONICAL_CONFIG_SHA256={canonical_hash}")
|
||||||
|
print(f"EXPECTED_CONFIG_SHA256={expected_hash}")
|
||||||
|
|
||||||
|
if checks == expected_checks and canonical_hash == expected_hash:
|
||||||
|
print("CONFIG_STATUS=PASS")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
print("CONFIG_STATUS=FAIL")
|
||||||
|
sys.exit(1)
|
||||||
|
PY_S03_CONFIG
|
||||||
|
CONFIG_RC=$?
|
||||||
|
|
||||||
|
PYTHONHASHSEED=0 "$PARSER" "$OUTPUT_FILE" --min-samples "$MINIMUM_SAMPLES" \
|
||||||
|
>"$BINARY_REPORT" 2>&1
|
||||||
|
PARSER_RC=$?
|
||||||
|
|
||||||
|
sha256sum -c --strict "$RUN_HASHES" >"$HASH_REPORT" 2>&1
|
||||||
|
HASH_RC=$?
|
||||||
|
|
||||||
|
report_value() {
|
||||||
|
key="$1"
|
||||||
|
file="$2"
|
||||||
|
sed -n "s/^${key}=//p" "$file" | tail -n 1
|
||||||
|
}
|
||||||
|
|
||||||
|
CONFIG_STATUS="$(report_value CONFIG_STATUS "$CONFIG_REPORT")"
|
||||||
|
FUNCTIONAL_BINARY_STATUS="$(report_value FUNCTIONAL_BINARY_STATUS "$BINARY_REPORT")"
|
||||||
|
SEMANTIC_BINARY_STATUS="$(report_value SEMANTIC_BINARY_STATUS "$BINARY_REPORT")"
|
||||||
|
BINARY_STATUS="$(report_value BINARY_STATUS "$BINARY_REPORT")"
|
||||||
|
FIRST_ERROR_CODE="$(report_value FIRST_ERROR_CODE "$BINARY_REPORT")"
|
||||||
|
COMPLETE_SAMPLE_COUNT="$(report_value COMPLETE_SAMPLE_COUNT "$BINARY_REPORT")"
|
||||||
|
HEADER_BYTES="$(report_value OBSERVED_HEADER_BYTES "$BINARY_REPORT")"
|
||||||
|
RECORD_BYTES="$(report_value OBSERVED_RECORD_BYTES_FROM_HEADER "$BINARY_REPORT")"
|
||||||
|
PAYLOAD_BYTES="$(report_value PAYLOAD_BYTES "$BINARY_REPORT")"
|
||||||
|
PAYLOAD_REMAINDER_BYTES="$(report_value PAYLOAD_REMAINDER_BYTES "$BINARY_REPORT")"
|
||||||
|
|
||||||
|
MARTE_EXIT_CODE="$(sed -n 's/^Exit code MARTe:[[:space:]]*//p' "$RUNNER_SUMMARY" | tail -n 1)"
|
||||||
|
TEE_EXIT_CODE="$(sed -n 's/^Exit code tee:[[:space:]]*//p' "$RUNNER_SUMMARY" | tail -n 1)"
|
||||||
|
if [ -z "$MARTE_EXIT_CODE" ]; then
|
||||||
|
MARTE_EXIT_CODE="NOT_AVAILABLE"
|
||||||
|
fi
|
||||||
|
if [ -z "$TEE_EXIT_CODE" ]; then
|
||||||
|
TEE_EXIT_CODE="NOT_AVAILABLE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$MARTE_EXIT_CODE" in
|
||||||
|
137)
|
||||||
|
TIMING_STATUS="NOT_VALID_EXIT_137_SIGKILL"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [ "$PRIORITY_FAIL_LINES" -ge 1 ]; then
|
||||||
|
TIMING_STATUS="NOT_VALID_PRIORITY_NOT_APPLIED"
|
||||||
|
else
|
||||||
|
TIMING_STATUS="UNASSESSED_DT_SEMANTICS"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
FUNCTIONAL_OK=0
|
||||||
|
if [ "$START_LINES" -ge 1 ] &&
|
||||||
|
[ "$APPLICATION_START_LINES" -ge 1 ] &&
|
||||||
|
[ "$FILE_OPEN_LINES" -ge 1 ] &&
|
||||||
|
[ "$STARTUP_ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$CONFIG_RC" -eq 0 ] &&
|
||||||
|
[ "$CONFIG_STATUS" = "PASS" ] &&
|
||||||
|
[ "$FUNCTIONAL_BINARY_STATUS" = "PASS" ] &&
|
||||||
|
[ "$HASH_RC" -eq 0 ] &&
|
||||||
|
[ "$TEE_EXIT_CODE" = "0" ] &&
|
||||||
|
[ "$UNCLASSIFIED_FATAL_LINES" -eq 0 ] &&
|
||||||
|
[ "$UNCLASSIFIED_OS_ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$INITIALISATION_ERROR_LINES" -eq 0 ]; then
|
||||||
|
FUNCTIONAL_OK=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$FUNCTIONAL_OK" -eq 1 ]; then
|
||||||
|
FUNCTIONAL_STATUS="PASS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$CONFIG_STATUS" = "PASS" ] && [ "$SEMANTIC_BINARY_STATUS" = "PASS" ]; then
|
||||||
|
SEMANTIC_STATUS="PASS"
|
||||||
|
elif [ "$SEMANTIC_BINARY_STATUS" = "FAIL" ]; then
|
||||||
|
SEMANTIC_STATUS="FAIL"
|
||||||
|
else
|
||||||
|
SEMANTIC_STATUS="NOT_DEMONSTRATED"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "============================================================\n"
|
||||||
|
printf "VALIDAZIONE S03 - SENTINELLE SEMANTICHE\n"
|
||||||
|
printf "============================================================\n"
|
||||||
|
printf "Run directory: %s\n" "$RUN_DIR"
|
||||||
|
printf "Configurazione: %s\n" "$RUN_CONFIG"
|
||||||
|
printf "File binario: %s\n" "$OUTPUT_FILE"
|
||||||
|
printf "Manifest hash: %s\n" "$RUN_HASHES"
|
||||||
|
printf "Configurazione canonica: %s (rc=%s)\n" "${CONFIG_STATUS:-NOT_AVAILABLE}" "$CONFIG_RC"
|
||||||
|
printf "Verifica manifest hash: %s (rc=%s)\n" "$( [ "$HASH_RC" -eq 0 ] && printf PASS || printf FAIL )" "$HASH_RC"
|
||||||
|
printf "Parser binario: %s (rc=%s)\n" "${BINARY_STATUS:-NOT_AVAILABLE}" "$PARSER_RC"
|
||||||
|
printf "Primo errore parser: %s\n" "${FIRST_ERROR_CODE:-NOT_AVAILABLE}"
|
||||||
|
printf "Header osservato: %s byte\n" "${HEADER_BYTES:-NOT_AVAILABLE}"
|
||||||
|
printf "Record da header: %s byte\n" "${RECORD_BYTES:-NOT_AVAILABLE}"
|
||||||
|
printf "Payload: %s byte\n" "${PAYLOAD_BYTES:-NOT_AVAILABLE}"
|
||||||
|
printf "Residuo payload: %s byte\n" "${PAYLOAD_REMAINDER_BYTES:-NOT_AVAILABLE}"
|
||||||
|
printf "Campioni completi: %s\n" "${COMPLETE_SAMPLE_COUNT:-NOT_AVAILABLE}"
|
||||||
|
printf "Avvii State1: %s\n" "$START_LINES"
|
||||||
|
printf "Application starting: %s\n" "$APPLICATION_START_LINES"
|
||||||
|
printf "Aperture FileWriter: %s\n" "$FILE_OPEN_LINES"
|
||||||
|
printf "Exit code MARTe: %s\n" "$MARTE_EXIT_CODE"
|
||||||
|
printf "Exit code tee: %s\n" "$TEE_EXIT_CODE"
|
||||||
|
printf "Warning priorita' non applic.: %s\n" "$PRIORITY_FAIL_LINES"
|
||||||
|
printf "Warning non classificati: %s\n" "$UNCLASSIFIED_WARNING_LINES"
|
||||||
|
printf "FatalError non classificati: %s\n" "$UNCLASSIFIED_FATAL_LINES"
|
||||||
|
printf "OSError non classificati: %s\n" "$UNCLASSIFIED_OS_ERROR_LINES"
|
||||||
|
printf "Error non classificati: %s\n" "$ERROR_LINES"
|
||||||
|
printf "InitialisationError: %s\n" "$INITIALISATION_ERROR_LINES"
|
||||||
|
|
||||||
|
printf "\n--- DETTAGLIO CONFIGURAZIONE ---\n"
|
||||||
|
cat -- "$CONFIG_REPORT"
|
||||||
|
printf "\n--- DETTAGLIO PARSER BINARIO ---\n"
|
||||||
|
cat -- "$BINARY_REPORT"
|
||||||
|
printf "\n--- VERIFICA HASH ---\n"
|
||||||
|
cat -- "$HASH_REPORT"
|
||||||
|
|
||||||
|
printf "\n--- CONTRATTO S03 ---\n"
|
||||||
|
emit_contract
|
||||||
|
|
||||||
|
if [ "$FUNCTIONAL_STATUS" != "PASS" ]; then
|
||||||
|
printf "VALIDATION_RESULT=FUNCTIONAL_NOT_DEMONSTRATED\n"
|
||||||
|
exit 20
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$SEMANTIC_STATUS" != "PASS" ]; then
|
||||||
|
printf "VALIDATION_RESULT=SEMANTIC_VALIDATION_FAILED\n"
|
||||||
|
exit 20
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$SIGINT_LINES" -ge 1 ] &&
|
||||||
|
[ "$STOP_OK_LINES" -ge 1 ] &&
|
||||||
|
[ "$TERMINATED_LINES" -ge 1 ] &&
|
||||||
|
[ "$FATAL_ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$OS_ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$INITIALISATION_ERROR_LINES" -eq 0 ]; then
|
||||||
|
printf "VALIDATION_RESULT=PASS_CLEAN_SHUTDOWN\n"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
KNOWN_SHUTDOWN_TOTAL=$((
|
||||||
|
DOUBLE_STOP_LINES +
|
||||||
|
ASYNC_EVENTSEM_CLOSE_LINES +
|
||||||
|
PTHREAD_MUTEX_DESTROY_LINES
|
||||||
|
))
|
||||||
|
if [ "$SIGINT_LINES" -ge 1 ] &&
|
||||||
|
[ "$STOP_OK_LINES" -ge 1 ] &&
|
||||||
|
[ "$TERMINATED_LINES" -ge 1 ] &&
|
||||||
|
[ "$KNOWN_SHUTDOWN_TOTAL" -ge 1 ] &&
|
||||||
|
[ "$UNCLASSIFIED_FATAL_LINES" -eq 0 ] &&
|
||||||
|
[ "$UNCLASSIFIED_OS_ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$ERROR_LINES" -eq 0 ] &&
|
||||||
|
[ "$INITIALISATION_ERROR_LINES" -eq 0 ]; then
|
||||||
|
printf "VALIDATION_RESULT=PASS_KNOWN_SHUTDOWN_ANOMALY\n"
|
||||||
|
exit 10
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "VALIDATION_RESULT=PASS_UNCLASSIFIED_SHUTDOWN_ANOMALY\n"
|
||||||
|
exit 11
|
||||||
Reference in New Issue
Block a user