feat: project authoring contract choices
This commit is contained in:
@@ -0,0 +1,308 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from wf_api.authoring_contracts import (
|
||||
project_authoring_contract_inventory,
|
||||
schema_path_options,
|
||||
)
|
||||
|
||||
|
||||
def test_schema_path_options_is_parent_first_and_schema_derived() -> None:
|
||||
schema = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"request": {
|
||||
"title": "Request",
|
||||
"description": "The incoming request.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {"type": "string"},
|
||||
"metadata": {
|
||||
"type": "object",
|
||||
"additionalProperties": True,
|
||||
},
|
||||
},
|
||||
"required": ["id"],
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {"name": {"type": "string"}},
|
||||
},
|
||||
},
|
||||
"headers": {
|
||||
"type": "object",
|
||||
"additionalProperties": {"type": "string"},
|
||||
},
|
||||
},
|
||||
"required": ["request", "items"],
|
||||
}
|
||||
|
||||
options = schema_path_options(
|
||||
schema,
|
||||
root="input",
|
||||
uses=["step_input", "workflow_output"],
|
||||
)
|
||||
|
||||
assert options == [
|
||||
{
|
||||
"path": "input.request",
|
||||
"label": "Request",
|
||||
"origin": "workflow_input",
|
||||
"schema": {
|
||||
"title": "Request",
|
||||
"description": "The incoming request.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {"type": "string"},
|
||||
"metadata": {"type": "object", "additionalProperties": True},
|
||||
},
|
||||
"required": ["id"],
|
||||
},
|
||||
"required": True,
|
||||
"availability": "available",
|
||||
"uses": ["step_input", "workflow_output"],
|
||||
"description": "The incoming request.",
|
||||
},
|
||||
{
|
||||
"path": "input.request.id",
|
||||
"label": "Id",
|
||||
"origin": "workflow_input",
|
||||
"schema": {"type": "string"},
|
||||
"required": True,
|
||||
"availability": "available",
|
||||
"uses": ["step_input", "workflow_output"],
|
||||
},
|
||||
{
|
||||
"path": "input.request.metadata",
|
||||
"label": "Metadata",
|
||||
"origin": "workflow_input",
|
||||
"schema": {"type": "object", "additionalProperties": True},
|
||||
"required": False,
|
||||
"availability": "available",
|
||||
"uses": ["step_input", "workflow_output"],
|
||||
},
|
||||
{
|
||||
"path": "input.items",
|
||||
"label": "Items",
|
||||
"origin": "workflow_input",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {"name": {"type": "string"}},
|
||||
},
|
||||
},
|
||||
"required": True,
|
||||
"availability": "available",
|
||||
"uses": ["step_input", "workflow_output"],
|
||||
},
|
||||
{
|
||||
"path": "input.headers",
|
||||
"label": "Headers",
|
||||
"origin": "workflow_input",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {"type": "string"},
|
||||
},
|
||||
"required": False,
|
||||
"availability": "available",
|
||||
"uses": ["step_input", "workflow_output"],
|
||||
},
|
||||
]
|
||||
assert not any("*" in option["path"] for option in options)
|
||||
assert not any(option["path"].startswith("input.metadata.") for option in options)
|
||||
assert options[0] == {
|
||||
"path": "input.request",
|
||||
"label": "Request",
|
||||
"origin": "workflow_input",
|
||||
"schema": {
|
||||
"title": "Request",
|
||||
"description": "The incoming request.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {"type": "string"},
|
||||
"metadata": {"type": "object", "additionalProperties": True},
|
||||
},
|
||||
"required": ["id"],
|
||||
},
|
||||
"required": True,
|
||||
"availability": "available",
|
||||
"uses": ["step_input", "workflow_output"],
|
||||
"description": "The incoming request.",
|
||||
}
|
||||
|
||||
|
||||
def test_schema_path_options_resolves_local_definition_metadata() -> None:
|
||||
options = schema_path_options(
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {"snapshot": {"$ref": "#/$defs/Snapshot"}},
|
||||
"required": ["snapshot"],
|
||||
"$defs": {
|
||||
"Snapshot": {
|
||||
"title": "Saved Snapshot",
|
||||
"type": "object",
|
||||
"properties": {"version": {"type": "integer"}},
|
||||
"required": ["version"],
|
||||
}
|
||||
},
|
||||
},
|
||||
root="input",
|
||||
uses=["step_input"],
|
||||
)
|
||||
|
||||
assert options == [
|
||||
{
|
||||
"path": "input.snapshot",
|
||||
"label": "Saved Snapshot",
|
||||
"origin": "workflow_input",
|
||||
"schema": {
|
||||
"$ref": "#/$defs/Snapshot",
|
||||
"$defs": {
|
||||
"Snapshot": {
|
||||
"title": "Saved Snapshot",
|
||||
"type": "object",
|
||||
"properties": {"version": {"type": "integer"}},
|
||||
"required": ["version"],
|
||||
}
|
||||
},
|
||||
},
|
||||
"required": True,
|
||||
"availability": "available",
|
||||
"uses": ["step_input"],
|
||||
},
|
||||
{
|
||||
"path": "input.snapshot.version",
|
||||
"label": "Version",
|
||||
"origin": "workflow_input",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"$defs": {
|
||||
"Snapshot": {
|
||||
"title": "Saved Snapshot",
|
||||
"type": "object",
|
||||
"properties": {"version": {"type": "integer"}},
|
||||
"required": ["version"],
|
||||
}
|
||||
},
|
||||
},
|
||||
"required": True,
|
||||
"availability": "available",
|
||||
"uses": ["step_input"],
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def test_schema_path_options_returns_empty_schema_for_unconstrained_property() -> None:
|
||||
options = schema_path_options(
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {"value": {}},
|
||||
},
|
||||
root="state",
|
||||
uses=["state_target"],
|
||||
)
|
||||
|
||||
assert options == [
|
||||
{
|
||||
"path": "state.value",
|
||||
"label": "Value",
|
||||
"origin": "workflow_state",
|
||||
"schema": {},
|
||||
"required": False,
|
||||
"availability": "available",
|
||||
"uses": ["state_target"],
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
def test_project_authoring_contract_inventory_composes_pure_inputs() -> None:
|
||||
context_entry = {
|
||||
"path": "context.loop_item",
|
||||
"label": "Loop Item",
|
||||
"origin": "runtime_context",
|
||||
"schema": {"type": "string"},
|
||||
"required": False,
|
||||
"availability": "conditional",
|
||||
"uses": ["step_input"],
|
||||
"reason": "Only available inside the foreach body.",
|
||||
}
|
||||
step_input_target = {
|
||||
"path": "step.input.query",
|
||||
"label": "Query",
|
||||
"origin": "step_input",
|
||||
"schema": {"type": "string"},
|
||||
"required": True,
|
||||
"availability": "available",
|
||||
"uses": ["step_input"],
|
||||
}
|
||||
step_output_source = {
|
||||
"path": "step.output.answer",
|
||||
"label": "Answer",
|
||||
"origin": "step_output",
|
||||
"schema": {"type": "string"},
|
||||
"required": False,
|
||||
"availability": "available",
|
||||
"uses": ["step_output_source", "workflow_output"],
|
||||
}
|
||||
entry_step = {
|
||||
"step_id": "fetch",
|
||||
"label": "Fetch",
|
||||
}
|
||||
|
||||
inventory = project_authoring_contract_inventory(
|
||||
workspace_id="workspace-1",
|
||||
revision=4,
|
||||
selected_step_id="fetch",
|
||||
input_schema={
|
||||
"type": "object",
|
||||
"properties": {"request": {"type": "string"}},
|
||||
},
|
||||
state_schema={
|
||||
"type": "object",
|
||||
"properties": {"answer": {"type": "string"}},
|
||||
},
|
||||
output_schema={
|
||||
"type": "object",
|
||||
"properties": {"result": {"type": "string"}},
|
||||
},
|
||||
context_entries=[context_entry],
|
||||
step_input_targets=[step_input_target],
|
||||
step_output_sources=[step_output_source],
|
||||
entry_steps=[entry_step],
|
||||
workflow_outcomes=["ok", "error"],
|
||||
warnings=["selected step has conditional context"],
|
||||
)
|
||||
|
||||
assert inventory["workspace_id"] == "workspace-1"
|
||||
assert inventory["revision"] == 4
|
||||
assert inventory["selected_step_id"] == "fetch"
|
||||
assert inventory["readable_sources"] == [
|
||||
{
|
||||
"path": "input.request",
|
||||
"label": "Request",
|
||||
"origin": "workflow_input",
|
||||
"schema": {"type": "string"},
|
||||
"required": False,
|
||||
"availability": "available",
|
||||
"uses": ["step_input", "workflow_output"],
|
||||
},
|
||||
context_entry,
|
||||
{
|
||||
"path": "state.answer",
|
||||
"label": "Answer",
|
||||
"origin": "workflow_state",
|
||||
"schema": {"type": "string"},
|
||||
"required": False,
|
||||
"availability": "available",
|
||||
"uses": ["step_input", "step_output_source", "workflow_output"],
|
||||
},
|
||||
]
|
||||
assert inventory["step_input_targets"] == [step_input_target]
|
||||
assert inventory["step_output_sources"] == [step_output_source]
|
||||
assert inventory["state_targets"][0]["path"] == "state.answer"
|
||||
assert inventory["workflow_output_targets"][0]["path"] == "output.result"
|
||||
assert inventory["entry_steps"] == [entry_step]
|
||||
assert inventory["workflow_outcomes"] == ["ok", "error"]
|
||||
assert inventory["warnings"] == ["selected step has conditional context"]
|
||||
Reference in New Issue
Block a user