Repository navigation
feat: accept x- extension keys in native documents and run the OMG PSSM 1.0 test suite #697
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
be2614e
4908150
3662fd7
f7460f7
57b325a
041fd96
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -64,3 +64,32 @@ | |
| flags: unittests | ||
| name: codecov-umbrella | ||
| verbose: true | ||
|
|
||
| pssm-drift: | ||
| # The XMI may not be stored or cached anywhere, see tests/uml/pssm/README.md. | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 15 | ||
| steps: | ||
| - uses: actions/checkout@v7 | ||
| - name: Set up Python | ||
| uses: actions/setup-python@v7 | ||
| with: | ||
| python-version: "3.15" | ||
| - name: Install uv | ||
| uses: astral-sh/setup-uv@v10.2.0 | ||
|
Check failure on line 79 in .github/workflows/python-package.yml
|
||
| with: | ||
| enable-cache: true | ||
| cache-suffix: "pssm-drift" | ||
| - name: Install the project | ||
| run: uv sync --all-extras --dev | ||
|
Check warning on line 84 in .github/workflows/python-package.yml
|
||
|
github-advanced-security[bot] marked this conversation as resolved.
Fixed
github-advanced-security[bot] marked this conversation as resolved.
Fixed
|
||
| - name: Download the PSSM test suite XMI | ||
| run: | | ||
| xmi_dir="$(mktemp -d)" | ||
| curl --fail --silent --show-error --location --retry 3 \ | ||
| --output "$xmi_dir/PSSM_TestSuite.xmi" \ | ||
| https://www.omg.org/spec/PSSM/20181101/PSSM_TestSuite.xmi | ||
|
Check warning on line 90 in .github/workflows/python-package.yml
|
||
|
github-advanced-security[bot] marked this conversation as resolved.
Fixed
|
||
| echo "PSSM_XMI=$xmi_dir/PSSM_TestSuite.xmi" >> "$GITHUB_ENV" | ||
| - name: Compare the committed cases with the converter output | ||
| env: | ||
| PSSM_REQUIRED: "1" | ||
| run: uv run pytest tests/uml/pssm/test_pssm_drift.py --timeout 300 | ||
|
Check warning on line 95 in .github/workflows/python-package.yml
|
||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not applied yet: PyYAML 6.0.3 publishes no cp315 wheels, so
github-advanced-security[bot] marked this conversation as resolved.
Fixed
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| # UML state machine cases based on PSSM | ||
|
|
||
| The cases in `cases/` are generated by `convert.py` from the test suite of the OMG | ||
| Precise Semantics of UML State Machines (PSSM) 1.0 specification: | ||
|
|
||
| - Source: <https://www.omg.org/spec/PSSM/20181101/PSSM_TestSuite.xmi> | ||
| - OMG document number: ptc/18-11-06 | ||
| - sha256: `c355b249c356774377a46b60345019d827af1ce417bde88e533aa5f39206ae07` | ||
|
|
||
| The PSSM specification and its test suite are copyright © Object Management Group, Inc. | ||
| and the organizations named in the specification's copyright notice. UML and OMG are | ||
| trademarks of the Object Management Group, used here only to name the source. | ||
|
|
||
| The repository holds the converter, the harness and the generated cases, never the XMI | ||
| itself: the specification's license does not allow posting copies of it on a network | ||
| computer, so the XMI is downloaded when needed and never committed, stored or cached. The | ||
| cases are *based on* PSSM; passing them is not a conformance claim. | ||
|
|
||
| ## Layout | ||
|
|
||
| - `convert.py`: XMI to native YAML, standard library XML parser, deterministic output. | ||
| - `cases/<Category>/<id>.yaml`: one generated case per PSSM test. Do not edit. | ||
| - `overlays/<id>.yaml`: hand-written patches the converter applies, for behaviors with logic | ||
| (counters, signals sent from inside the machine) and for CallEvent tests. `cases/` is | ||
| always exactly the converter output for the XMI plus these overlays. In the generated | ||
| statechart, an overlay's native actions run before its trace callback. | ||
| - `conftest.py`: the expected failures, per engine, with a reason code, and `LOWERED`: the | ||
| cases that pass only because the converter lowers a construct the library cannot spell | ||
| yet (for example, a junction flattened into guarded transitions). Those passes do not | ||
| show native support for the construct. Every case with a non-empty `requires` is in one | ||
| of the two. | ||
| - `test_pssm_cases.py`: runs every case on the sync and the async engine. | ||
| - `test_pssm_drift.py`: regenerates the cases and compares them with `cases/`. | ||
|
|
||
| ## Case format | ||
|
|
||
| Each case is a YAML mapping: | ||
|
|
||
| - `requires`: UML constructs the case uses that the native format cannot spell yet | ||
| (`choice`, `junction`, `join`, `fork`, `terminate`, `entry_point`, `exit_point`, | ||
| `defer`, `call_event`, `redefinition`, `do_activity_accept`). The statechart is the | ||
| closest loadable approximation. | ||
| - `expected_traces`: the accepted traces, taken from the suite's executable oracle. | ||
| - `stimulus`: what the tester does, in order, starting with `Start`: `{event, kwargs}` | ||
| sends a signal, `{call, kwargs}` calls an operation, `{trace}` is a token the tester | ||
| traces itself, `trace_result` formats the value a call returned. | ||
| - `behaviors`: the trace tokens each callback appends; `{name}` placeholders are filled | ||
| with the event data. `on_invoke_<state>` entries are doActivities; in them, | ||
| `{send: {event}}` sends an event to the machine and `{accept}` parks the doActivity until | ||
| its state is left. | ||
| - `statechart`: a native document, loaded untrusted with `statemachine.io.load`. | ||
|
|
||
| The converter lowers UML completion transitions to what the library has today: from a | ||
| composite state to `done.state.<id>`, from a state with a doActivity to | ||
| `done.invoke.<id>`, from a simple state to an eventless transition. | ||
|
|
||
| ## Running | ||
|
|
||
| ```bash | ||
| timeout 120 uv run pytest tests/uml/pssm -n 4 | ||
| ``` | ||
|
|
||
| ## Regenerating | ||
|
|
||
| Download the XMI to a git-ignored location (any directory outside the repository, or the | ||
| repository root, where `PSSM_TestSuite.xmi` is ignored), then: | ||
|
|
||
| ```bash | ||
| export PSSM_XMI=/path/to/PSSM_TestSuite.xmi | ||
| uv run python -m tests.uml.pssm.convert --out tests/uml/pssm/cases | ||
| uv run pytest tests/uml/pssm/test_pssm_drift.py | ||
| ``` | ||
|
|
||
| The converter checks the sha256 above before reading the file. Without `PSSM_XMI` the | ||
| drift test is skipped; `PSSM_REQUIRED=1` turns the skip into a failure, which is how the | ||
| `pssm-drift` CI job runs it. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| # Generated by tests/uml/pssm/convert.py from the OMG PSSM 1.0 test suite (ptc/18-11-06, https://www.omg.org/spec/PSSM/20181101/PSSM_TestSuite.xmi). Do not edit. | ||
| requires: [] | ||
| expected_traces: | ||
| - S1(entry) | ||
| stimulus: | ||
| - event: Start | ||
| behaviors: | ||
| pssm_S1_entry: | ||
| - S1(entry) | ||
| statechart: | ||
| name: Behavior_001 | ||
| states: | ||
| S1: | ||
| initial: true | ||
| enter: | ||
| - pssm_S1_entry | ||
| transitions: | ||
| - event: Start | ||
| target: FinalState1 | ||
| FinalState1: | ||
| final: true |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| # Generated by tests/uml/pssm/convert.py from the OMG PSSM 1.0 test suite (ptc/18-11-06, https://www.omg.org/spec/PSSM/20181101/PSSM_TestSuite.xmi). Do not edit. | ||
| requires: [] | ||
| expected_traces: | ||
| - S1(exit) | ||
| stimulus: | ||
| - event: Start | ||
| behaviors: | ||
| pssm_S1_exit: | ||
| - S1(exit) | ||
| statechart: | ||
| name: Behavior_002 | ||
| states: | ||
| S1: | ||
| initial: true | ||
| exit: | ||
| - pssm_S1_exit | ||
| transitions: | ||
| - event: Start | ||
| target: FinalState1 | ||
| FinalState1: | ||
| final: true |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| # Generated by tests/uml/pssm/convert.py from the OMG PSSM 1.0 test suite (ptc/18-11-06, https://www.omg.org/spec/PSSM/20181101/PSSM_TestSuite.xmi). Do not edit. | ||
| requires: | ||
| - do_activity_accept | ||
| expected_traces: | ||
| - S1(entry)::S1(doActivityPartI) | ||
| - S1(entry) | ||
| stimulus: | ||
| - event: Start | ||
| - event: AnotherSignal | ||
| behaviors: | ||
| pssm_S1_entry: | ||
| - S1(entry) | ||
| on_invoke_S1: | ||
| - S1(doActivityPartI) | ||
| - accept: Continue | ||
| pssm_T3_effect: | ||
| - T3(effect) | ||
| statechart: | ||
| name: Behavior_003-A | ||
| states: | ||
| wait: | ||
| initial: true | ||
| transitions: | ||
| - event: Start | ||
| target: S1 | ||
| S1: | ||
| enter: | ||
| - pssm_S1_entry | ||
| transitions: | ||
| - event: done.invoke.S1 | ||
| target: error | ||
| 'on': | ||
| - pssm_T3_effect | ||
| - event: AnotherSignal | ||
| target: FS1 | ||
| FS1: | ||
| final: true | ||
| error: | ||
| transitions: | ||
| - target: FS1 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| # Generated by tests/uml/pssm/convert.py from the OMG PSSM 1.0 test suite (ptc/18-11-06, https://www.omg.org/spec/PSSM/20181101/PSSM_TestSuite.xmi). Do not edit. | ||
| requires: | ||
| - do_activity_accept | ||
| expected_traces: | ||
| - S1(entry)::S1(doActivityPartI)::S1(doActivityPartII) | ||
| stimulus: | ||
| - event: Start | ||
| - event: Continue | ||
| behaviors: | ||
| pssm_S1_entry: | ||
| - S1(entry) | ||
| on_invoke_S1: | ||
| - S1(doActivityPartI) | ||
| - accept: Continue | ||
| statechart: | ||
| name: Behavior_003-B | ||
| states: | ||
| wait: | ||
| initial: true | ||
| transitions: | ||
| - event: Start | ||
| target: S1 | ||
| S1: | ||
| enter: | ||
| - pssm_S1_entry | ||
| transitions: | ||
| - event: done.invoke.S1 | ||
| target: FinalState1 | ||
| FinalState1: | ||
| final: true |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| # Generated by tests/uml/pssm/convert.py from the OMG PSSM 1.0 test suite (ptc/18-11-06, https://www.omg.org/spec/PSSM/20181101/PSSM_TestSuite.xmi). Do not edit. | ||
| requires: | ||
| - do_activity_accept | ||
| expected_traces: | ||
| - S1(entry)::S1(doActivityPartI)::T3(effect)::S1(doActivityPartII) | ||
| stimulus: | ||
| - event: Start | ||
| - event: AnotherSignal | ||
| - event: Continue | ||
| behaviors: | ||
| pssm_S1_entry: | ||
| - S1(entry) | ||
| on_invoke_S1: | ||
| - S1(doActivityPartI) | ||
| - accept: Continue | ||
| pssm_T3_effect: | ||
| - T3(effect) | ||
| statechart: | ||
| name: Behavior_004 | ||
| states: | ||
| wait: | ||
| initial: true | ||
| transitions: | ||
| - event: Start | ||
| target: S1 | ||
| S1: | ||
| enter: | ||
| - pssm_S1_entry | ||
| transitions: | ||
| - event: done.invoke.S1 | ||
| target: FS1 | ||
| - event: AnotherSignal | ||
| 'on': | ||
| - pssm_T3_effect | ||
| FS1: | ||
| final: true |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| # Generated by tests/uml/pssm/convert.py from the OMG PSSM 1.0 test suite (ptc/18-11-06, https://www.omg.org/spec/PSSM/20181101/PSSM_TestSuite.xmi). Do not edit. | ||
| requires: | ||
| - choice | ||
| expected_traces: | ||
| - T4(effect)::T4(effect)::T4(effect)::T4(effect) | ||
| stimulus: | ||
| - event: Start | ||
| behaviors: | ||
| pssm_T4_effect: | ||
| - T4(effect) | ||
| statechart: | ||
| name: Choice_001 | ||
| datamodel: | ||
| value: '0' | ||
| states: | ||
| Increment: | ||
| enter: | ||
| - assign: | ||
| location: value | ||
| expr: value + 1 | ||
| transitions: | ||
| - target: FS1 | ||
| cond: value == 5 | ||
| - target: Increment | ||
| cond: value < 5 | ||
| 'on': | ||
| - pssm_T4_effect | ||
| wait: | ||
| initial: true | ||
| transitions: | ||
| - event: Start | ||
| target: Increment | ||
| 'on': | ||
| - assign: | ||
| location: value | ||
| expr: '0' | ||
| FS1: | ||
| final: true |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| # Generated by tests/uml/pssm/convert.py from the OMG PSSM 1.0 test suite (ptc/18-11-06, https://www.omg.org/spec/PSSM/20181101/PSSM_TestSuite.xmi). Do not edit. | ||
| requires: | ||
| - choice | ||
| expected_traces: | ||
| - T3(effect) | ||
| - T4(effect) | ||
| - T5(effect) | ||
| stimulus: | ||
| - event: Start | ||
| behaviors: | ||
| pssm_T3_effect: | ||
| - T3(effect) | ||
| pssm_T4_effect: | ||
| - T4(effect) | ||
| pssm_T5_effect: | ||
| - T5(effect) | ||
| statechart: | ||
| name: Choice_002 | ||
| states: | ||
| wait: | ||
| initial: true | ||
| transitions: | ||
| - event: Start | ||
| target: S1 | ||
| cond: 'True' | ||
| 'on': | ||
| - pssm_T3_effect | ||
| - event: Start | ||
| target: S1 | ||
| cond: 'True' | ||
| 'on': | ||
| - pssm_T4_effect | ||
| - event: Start | ||
| target: S1 | ||
| 'on': | ||
| - pssm_T5_effect | ||
| FS1: | ||
| final: true | ||
| S1: | ||
| transitions: | ||
| - target: FS1 |
Uh oh!
There was an error while loading. Please reload this page.