135 lines
5.3 KiB
Markdown
135 lines
5.3 KiB
Markdown
# MACHINE.md — Agent Context for ST Flow Test Harness
|
|
|
|
This file is structured for consumption by AI agents. It defines the canonical test
|
|
patterns, expected behaviours, and how to operate the harness programmatically.
|
|
|
|
## Repo Purpose
|
|
|
|
Canonical test harness for ST Advanced Routing flows. Provides:
|
|
- Deterministic fixture files with known content and expected transforms
|
|
- Automated test runner (SFTP upload → route execution → destination verify)
|
|
- Declarative flow specs (YAML) for idempotent deploy
|
|
- Pre-flight environment snapshot tooling
|
|
|
|
## Test Case Registry
|
|
|
|
Each entry defines: fixture file, expected output filename, transform type, verification method.
|
|
|
|
```json
|
|
[
|
|
{
|
|
"id": "compress-txt",
|
|
"fixture": "fixtures/test.txt",
|
|
"fixture_sha256": "see fixtures/CHECKSUMS",
|
|
"expected_output_filename": "test.txt.zip",
|
|
"transform": "Compress",
|
|
"verify_method": "filename_suffix",
|
|
"verify_params": {"suffix": ".zip", "size_relation": "larger"},
|
|
"notes": "ST Compress step appends .zip. Output size > input due to ZIP header overhead on small files."
|
|
},
|
|
{
|
|
"id": "pgp-encrypt-md",
|
|
"fixture": "fixtures/test.md",
|
|
"fixture_sha256": "see fixtures/CHECKSUMS",
|
|
"expected_output_filename": "test.md.pgp",
|
|
"transform": "PgpEncryption",
|
|
"verify_method": "filename_suffix_and_magic_bytes",
|
|
"verify_params": {
|
|
"suffix": ".pgp",
|
|
"magic_bytes_hex": "C1",
|
|
"magic_bytes_offset": 0
|
|
},
|
|
"notes": "ST PgpEncryption appends .pgp. Binary output starts with 0xC1 (OpenPGP packet tag). Cert must have accessLevel=PUBLIC and account ownership."
|
|
},
|
|
{
|
|
"id": "passthrough-csv",
|
|
"fixture": "fixtures/test.csv",
|
|
"fixture_sha256": "see fixtures/CHECKSUMS",
|
|
"expected_output_filename": "test.csv",
|
|
"transform": "None (pass-through)",
|
|
"verify_method": "exact_match",
|
|
"verify_params": {"filename_exact": true, "size_exact": true},
|
|
"notes": "No step matches .csv. File passes through to SendToPartner unchanged."
|
|
},
|
|
{
|
|
"id": "passthrough-pdf",
|
|
"fixture": "fixtures/test.pdf",
|
|
"fixture_sha256": "see fixtures/CHECKSUMS",
|
|
"expected_output_filename": "test.pdf",
|
|
"transform": "None (pass-through)",
|
|
"verify_method": "exact_match",
|
|
"verify_params": {"filename_exact": true, "size_exact": true},
|
|
"notes": "No step matches .pdf. File passes through to SendToPartner unchanged."
|
|
},
|
|
{
|
|
"id": "passthrough-jpg",
|
|
"fixture": "fixtures/test.jpg",
|
|
"fixture_sha256": "see fixtures/CHECKSUMS",
|
|
"expected_output_filename": "test.jpg",
|
|
"transform": "None (pass-through)",
|
|
"verify_method": "exact_match",
|
|
"verify_params": {"filename_exact": true, "size_exact": true},
|
|
"notes": "No step matches .jpg. File passes through to SendToPartner unchanged."
|
|
}
|
|
]
|
|
```
|
|
|
|
## Script Interface
|
|
|
|
### run_tests.py
|
|
|
|
```
|
|
python scripts/run_tests.py [--spec SPEC_YAML] [--env ENV_FILE] [--fixture FIXTURE] [--verbose]
|
|
```
|
|
|
|
- `--spec`: Path to flow spec YAML. Used to validate environment pre-flight.
|
|
- `--env`: Path to env file (default: `.env`).
|
|
- `--fixture`: Run only a single fixture (by id). Omit to run all.
|
|
- `--verbose`: Print step-by-step detail.
|
|
|
|
Exit codes: `0` = all pass, `1` = one or more fail, `2` = environment/config error.
|
|
|
|
Output format: JSON to stdout (machine-readable), human summary to stderr.
|
|
|
|
### st_env_snapshot.py
|
|
|
|
```
|
|
python scripts/st_env_snapshot.py --host HOST --port PORT --user USER --pass PASS [--output json|yaml]
|
|
```
|
|
|
|
Returns a structured snapshot of the live ST environment:
|
|
- `accounts`: list of accounts with type and status
|
|
- `partner_sites`: list of partner sites with name, type, and partner account
|
|
- `certificates`: list of certs with name, type, usage, account, accessLevel
|
|
- `applications`: list of AR applications
|
|
- `subscriptions`: list of active subscriptions with folder and linked application
|
|
|
|
Use this output to validate that all resources referenced in a flow spec exist before deploying.
|
|
|
|
### st_deploy.py
|
|
|
|
```
|
|
python scripts/st_deploy.py --spec SPEC_YAML --host HOST --port PORT --user USER --pass PASS [--dry-run]
|
|
```
|
|
|
|
Idempotent deploy from spec YAML:
|
|
- Creates objects that don't exist
|
|
- Skips objects that exist with matching config
|
|
- Updates objects that exist with different config (route PUT, step rebuild)
|
|
- `--dry-run`: print planned actions without executing
|
|
|
|
Exit codes: `0` = success, `1` = deploy error, `2` = validation error.
|
|
|
|
## Known Constraints
|
|
|
|
- **Route PUT drops step IDs**: When updating a route via PUT, omit all step `id` fields. Including them causes "Cannot attach a route step to another route" error.
|
|
- **conditionType is mandatory**: Every step must have explicit `conditionType: ALWAYS` or `EL`. Null causes NPE at runtime.
|
|
- **PGP cert must be PUBLIC**: Cert `accessLevel` must be `PUBLIC` and `account` must be a real account name. System-level or PRIVATE certs are invisible to the routing engine.
|
|
- **encryptKeyExpressionType**: Only `ALIAS` or `EXPRESSION_WILDCARD` are valid. `NAME` is rejected.
|
|
- **Routing latency**: Allow 15-30 seconds between upload and destination check. Use `ROUTING_TIMEOUT_SEC` env var.
|
|
- **Top-level Processed is insufficient**: Always verify at destination. A file with no matching step shows `Processed` at route level but was never transformed or delivered.
|
|
|
|
## Spec Format Reference
|
|
|
|
See `specs/schema.md` for full YAML spec format.
|