The sync_test directory contains an automated integration testing framework for the ORIAnnotations UI synchronization pipeline. It ensures that peer applications (like xStudio and OpenRV) correctly exchange state (playhead position, active clip, annotations) over the RabbitMQ network.
Instead of testing only the SyncManager library in isolation, this framework provides true end-to-end testing:
- App Spawner: Launches the actual application binaries (xStudio, OpenRV) in isolated subprocesses.
- Inspection Server (RPC): Injects a lightweight HTTP server (
inspector.py) into the running applications. This exposes a/stateendpoint to query the true logical state of the app directly from its native Python API (xstudio_hook.py,openrv_hook.py). - Playback Automation: Uses the existing
sync_recorder.player.SyncPlayerto stream a.jsonlrecording of OTIO sync events into the RabbitMQ exchange, simulating a remote master peer driving the session. - State Assertion: The Test Runner (
runner.py) continuously polls the/stateendpoint of all spawned apps and asserts that they match the expected synchronized state.
Tests are defined in a YAML configuration file (sync_tests.yaml at the project root).
Example sync_tests.yaml:
tests:
- name: "xstudio_vs_openrv_demo"
recording: "demo.jsonl"
apps:
- "xstudio"
- "openrv"You can run the full suite or a specific test using the run_tests.sh wrapper script. This script automatically configures the PYTHONPATH so the testing modules can be imported correctly.
# Run all tests using the default sync_tests.yaml
./run_tests.sh run
# Run a specific test
./run_tests.sh run --test xstudio_vs_openrv_demo
# Run with custom config
./run_tests.sh run --config my_tests.yaml
# Enable verbose logging
./run_tests.sh run -vTests with script_driven: true drive the first app in the apps list via a sequence of high-level commands rather than replaying a .jsonl recording. The other app(s) receive changes through the normal sync session. After all commands complete the runner waits for convergence and then asserts that both apps report the same state.
Commands can be supplied in two ways:
- Explicit commands in
sync_tests.yamlvia acommandskey — use this when you want full control over the sequence. - Derived from the recording — if no
commandskey is present, the runner parses the.jsonlfile and extractsadd_media/delete_media/set_selectioncommands automatically fromINSERT_CHILD,REMOVE_CHILD, andPLAYBACK_SETTINGSevents.
Add a media file to the first playlist in the driver app. The sync plugin broadcasts the insertion to all peers.
| Field | Type | Description |
|---|---|---|
action |
string | "add_media" |
url |
string | Path to media. Relative paths resolve from repo root. |
- action: "add_media"
url: "test_media/source/encoded_notc/car_ACES_sRGB.mov"Remove a media item from the driver app by name. The sync plugin broadcasts the removal to all peers.
| Field | Type | Description |
|---|---|---|
action |
string | "delete_media" |
name |
string | Clip name to remove. Matches file basename. |
- action: "delete_media"
name: "graphic_ACES_sRGB.mov"Set the active/viewed item in the driver app. Useful to verify selection sync or to put both apps in a known state before a subsequent assertion. For the first playlist, the aliases "Default Sequence", "Sequence", and "Default" also match regardless of the actual name.
| Field | Type | Description |
|---|---|---|
action |
string | "set_selection" |
name |
string | Name of the sequence or clip to make active. |
- action: "set_selection"
name: "car_ACES_sRGB.mov"Save the current session to a file. Used automatically by the runner at the end of each test to capture final app state for debugging — you generally do not need this in a commands list.
| Field | Type | Description |
|---|---|---|
action |
string | "save_session" |
filepath |
string | Absolute path to write the session file. |
- action: "save_session"
filepath: "/tmp/debug_session.xst"When apps are launched, their stdout and stderr are redirected to isolated log files to make debugging easy. Logs are grouped by test name in the top-level logs/ directory:
logs/
└── xstudio_vs_openrv_demo/
├── openrv_9001.log
├── xstudio_9000.log
└── xstudio_inspector_9000.log