Skip to content

Commit 6e7015d

Browse files
Assert Python query task parity
Add Python client parity fixtures and assertions for polling, completing, and failing workflow query tasks.
1 parent 5f8c82b commit 6e7015d

4 files changed

Lines changed: 204 additions & 0 deletions

File tree

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
{
2+
"schema": "durable-workflow.polyglot.control-plane-request-fixture",
3+
"version": 1,
4+
"operation": "query-task.complete",
5+
"request": {
6+
"method": "POST",
7+
"path": "/worker/query-tasks/query-task-231/complete",
8+
"body": {
9+
"lease_owner": "polyglot-worker-231",
10+
"query_task_attempt": 1,
11+
"result": {
12+
"status": "ready",
13+
"open_items": 3
14+
},
15+
"result_envelope": {
16+
"codec": "json",
17+
"blob": "{\"status\":\"ready\",\"open_items\":3}"
18+
}
19+
}
20+
},
21+
"semantic_body": {
22+
"query_task_id": "query-task-231",
23+
"lease_owner": "polyglot-worker-231",
24+
"query_task_attempt": 1,
25+
"outcome": "completed"
26+
},
27+
"response_body": {
28+
"query_task_id": "query-task-231",
29+
"query_task_attempt": 1,
30+
"outcome": "completed"
31+
},
32+
"cli": {
33+
"argv": {
34+
"query-task-id": "query-task-231",
35+
"attempt": "1",
36+
"--lease-owner": "polyglot-worker-231",
37+
"--result": "{\"status\":\"ready\",\"open_items\":3}",
38+
"--json": true
39+
}
40+
},
41+
"sdk_python": {
42+
"method": "complete_query_task",
43+
"kwargs": {
44+
"query_task_id": "query-task-231",
45+
"lease_owner": "polyglot-worker-231",
46+
"query_task_attempt": 1,
47+
"result": {
48+
"status": "ready",
49+
"open_items": 3
50+
},
51+
"codec": "json",
52+
"workflow_id": "order-231",
53+
"run_id": "run-231",
54+
"query_name": "current_status"
55+
}
56+
}
57+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
{
2+
"schema": "durable-workflow.polyglot.control-plane-request-fixture",
3+
"version": 1,
4+
"operation": "query-task.fail",
5+
"request": {
6+
"method": "POST",
7+
"path": "/worker/query-tasks/query-task-231/fail",
8+
"body": {
9+
"lease_owner": "polyglot-worker-231",
10+
"query_task_attempt": 1,
11+
"failure": {
12+
"message": "unknown query current_status_v3",
13+
"reason": "rejected_unknown_query",
14+
"type": "QueryFailed",
15+
"stack_trace": "query handler not registered"
16+
}
17+
}
18+
},
19+
"semantic_body": {
20+
"query_task_id": "query-task-231",
21+
"lease_owner": "polyglot-worker-231",
22+
"query_task_attempt": 1,
23+
"reason": "rejected_unknown_query",
24+
"outcome": "failed"
25+
},
26+
"response_body": {
27+
"query_task_id": "query-task-231",
28+
"query_task_attempt": 1,
29+
"outcome": "failed"
30+
},
31+
"cli": {
32+
"argv": {
33+
"query-task-id": "query-task-231",
34+
"attempt": "1",
35+
"--lease-owner": "polyglot-worker-231",
36+
"--message": "unknown query current_status_v3",
37+
"--reason": "rejected_unknown_query",
38+
"--type": "QueryFailed",
39+
"--stack-trace": "query handler not registered",
40+
"--json": true
41+
}
42+
},
43+
"sdk_python": {
44+
"method": "fail_query_task",
45+
"kwargs": {
46+
"query_task_id": "query-task-231",
47+
"lease_owner": "polyglot-worker-231",
48+
"query_task_attempt": 1,
49+
"message": "unknown query current_status_v3",
50+
"reason": "rejected_unknown_query",
51+
"failure_type": "QueryFailed",
52+
"stack_trace": "query handler not registered"
53+
}
54+
}
55+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
{
2+
"schema": "durable-workflow.polyglot.control-plane-request-fixture",
3+
"version": 1,
4+
"operation": "query-task.poll",
5+
"request": {
6+
"method": "POST",
7+
"path": "/worker/query-tasks/poll",
8+
"body": {
9+
"worker_id": "polyglot-worker-231",
10+
"task_queue": "external-workflows"
11+
}
12+
},
13+
"semantic_body": {
14+
"worker_id": "polyglot-worker-231",
15+
"task_queue": "external-workflows",
16+
"query_task_id": "query-task-231",
17+
"workflow_id": "order-231",
18+
"run_id": "run-231",
19+
"query_name": "current_status",
20+
"query_task_attempt": 1
21+
},
22+
"response_body": {
23+
"task": {
24+
"query_task_id": "query-task-231",
25+
"workflow_id": "order-231",
26+
"run_id": "run-231",
27+
"query_name": "current_status",
28+
"query_task_attempt": 1,
29+
"lease_owner": "polyglot-worker-231",
30+
"input": {
31+
"codec": "json",
32+
"blob": "{\"include_line_items\":true}"
33+
}
34+
}
35+
},
36+
"cli": {
37+
"argv": {
38+
"worker-id": "polyglot-worker-231",
39+
"--task-queue": "external-workflows",
40+
"--json": true
41+
}
42+
},
43+
"sdk_python": {
44+
"method": "poll_query_task",
45+
"kwargs": {
46+
"worker_id": "polyglot-worker-231",
47+
"task_queue": "external-workflows"
48+
}
49+
}
50+
}

tests/test_client.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1971,6 +1971,48 @@ async def test_list_workers_rejects_non_object_response(self, client: Client) ->
19711971

19721972

19731973
class TestQueryTasks:
1974+
@pytest.mark.asyncio
1975+
async def test_poll_query_task_matches_polyglot_fixture(self, client: Client) -> None:
1976+
fixture_path = Path(__file__).parent / "fixtures" / "control-plane" / "query-task-poll-parity.json"
1977+
fixture = json.loads(fixture_path.read_text())
1978+
resp = _mock_response(200, fixture["response_body"])
1979+
1980+
with patch.object(client._http, "request", new_callable=AsyncMock, return_value=resp) as mock:
1981+
task = await client.poll_query_task(**fixture["sdk_python"]["kwargs"])
1982+
1983+
assert task == fixture["response_body"]["task"]
1984+
assert task["query_task_id"] == fixture["semantic_body"]["query_task_id"]
1985+
assert mock.call_args.args[:2] == (fixture["request"]["method"], f"/api{fixture['request']['path']}")
1986+
assert mock.call_args.kwargs["json"] == fixture["request"]["body"]
1987+
1988+
@pytest.mark.asyncio
1989+
async def test_complete_query_task_matches_polyglot_fixture(self, client: Client) -> None:
1990+
fixture_path = Path(__file__).parent / "fixtures" / "control-plane" / "query-task-complete-parity.json"
1991+
fixture = json.loads(fixture_path.read_text())
1992+
resp = _mock_response(200, fixture["response_body"])
1993+
1994+
with patch.object(client._http, "request", new_callable=AsyncMock, return_value=resp) as mock:
1995+
result = await client.complete_query_task(**fixture["sdk_python"]["kwargs"])
1996+
1997+
assert result == fixture["response_body"]
1998+
assert result["outcome"] == fixture["semantic_body"]["outcome"]
1999+
assert mock.call_args.args[:2] == (fixture["request"]["method"], f"/api{fixture['request']['path']}")
2000+
assert mock.call_args.kwargs["json"] == fixture["request"]["body"]
2001+
2002+
@pytest.mark.asyncio
2003+
async def test_fail_query_task_matches_polyglot_fixture(self, client: Client) -> None:
2004+
fixture_path = Path(__file__).parent / "fixtures" / "control-plane" / "query-task-fail-parity.json"
2005+
fixture = json.loads(fixture_path.read_text())
2006+
resp = _mock_response(200, fixture["response_body"])
2007+
2008+
with patch.object(client._http, "request", new_callable=AsyncMock, return_value=resp) as mock:
2009+
result = await client.fail_query_task(**fixture["sdk_python"]["kwargs"])
2010+
2011+
assert result == fixture["response_body"]
2012+
assert result["outcome"] == fixture["semantic_body"]["outcome"]
2013+
assert mock.call_args.args[:2] == (fixture["request"]["method"], f"/api{fixture['request']['path']}")
2014+
assert mock.call_args.kwargs["json"] == fixture["request"]["body"]
2015+
19742016
@pytest.mark.asyncio
19752017
async def test_poll_query_task_returns_task_payload(self, client: Client) -> None:
19762018
resp = _mock_response(200, {"task": {"query_task_id": "qt1"}})

0 commit comments

Comments
 (0)