Skip to content

Commit acde42c

Browse files
authored
Accept search attributes for dev server (#562)
Fixes #558
1 parent 51f4b66 commit acde42c

File tree

2 files changed

+82
-1
lines changed

2 files changed

+82
-1
lines changed

temporalio/testing/_workflow.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ async def start_local(
9191
download_dest_dir: Optional[str] = None,
9292
ui: bool = False,
9393
runtime: Optional[temporalio.runtime.Runtime] = None,
94+
search_attributes: Sequence[temporalio.common.SearchAttributeKey] = (),
9495
dev_server_existing_path: Optional[str] = None,
9596
dev_server_database_filename: Optional[str] = None,
9697
dev_server_log_format: str = "pretty",
@@ -138,6 +139,8 @@ async def start_local(
138139
needed. If unset, this is the system's temporary directory.
139140
ui: If ``True``, will start a UI in the dev server.
140141
runtime: Specific runtime to use or default if unset.
142+
search_attributes: Search attributes to register with the dev
143+
server.
141144
dev_server_existing_path: Existing path to the CLI binary.
142145
If present, no download will be attempted to fetch the binary.
143146
dev_server_database_filename: Path to the Sqlite database to use
@@ -167,6 +170,14 @@ async def start_local(
167170
dev_server_log_level = "error"
168171
else:
169172
dev_server_log_level = "fatal"
173+
# Add search attributes
174+
if search_attributes:
175+
new_args = []
176+
for attr in search_attributes:
177+
new_args.append("--search-attribute")
178+
new_args.append(f"{attr.name}={attr._metadata_type}")
179+
new_args += dev_server_extra_args
180+
dev_server_extra_args = new_args
170181
# Start CLI dev server
171182
runtime = runtime or temporalio.runtime.Runtime.default()
172183
server = await temporalio.bridge.testing.EphemeralServer.start_dev_server(

tests/testing/test_workflow.py

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,17 @@
1212
Client,
1313
Interceptor,
1414
OutboundInterceptor,
15+
RPCError,
1516
StartWorkflowInput,
1617
WorkflowFailureError,
1718
WorkflowHandle,
1819
)
19-
from temporalio.common import RetryPolicy
20+
from temporalio.common import (
21+
RetryPolicy,
22+
SearchAttributeKey,
23+
SearchAttributePair,
24+
TypedSearchAttributes,
25+
)
2026
from temporalio.exceptions import (
2127
ActivityError,
2228
ApplicationError,
@@ -245,6 +251,70 @@ def assert_proper_error(err: Optional[BaseException]) -> None:
245251
assert_proper_error(err.value.cause)
246252

247253

254+
async def test_search_attributes_on_dev_server(
255+
client: Client, env: WorkflowEnvironment
256+
):
257+
if env.supports_time_skipping:
258+
pytest.skip("Only testing for local dev server")
259+
260+
# Search attributes
261+
sa_prefix = f"{uuid.uuid4()}_"
262+
text_attr = SearchAttributeKey.for_text(f"{sa_prefix}text")
263+
keyword_attr = SearchAttributeKey.for_keyword(f"{sa_prefix}keyword")
264+
keyword_list_attr = SearchAttributeKey.for_keyword_list(f"{sa_prefix}keyword_list")
265+
int_attr = SearchAttributeKey.for_int(f"{sa_prefix}int")
266+
float_attr = SearchAttributeKey.for_float(f"{sa_prefix}double")
267+
bool_attr = SearchAttributeKey.for_bool(f"{sa_prefix}bool")
268+
datetime_attr = SearchAttributeKey.for_datetime(f"{sa_prefix}datetime")
269+
attrs = TypedSearchAttributes(
270+
[
271+
SearchAttributePair(text_attr, "text1"),
272+
SearchAttributePair(keyword_attr, "keyword1"),
273+
SearchAttributePair(
274+
keyword_list_attr,
275+
["keywordlist1", "keywordlist2"],
276+
),
277+
SearchAttributePair(int_attr, 123),
278+
SearchAttributePair(float_attr, 456.78),
279+
SearchAttributePair(bool_attr, True),
280+
SearchAttributePair(
281+
datetime_attr, datetime(2001, 2, 3, 4, 5, 6, tzinfo=timezone.utc)
282+
),
283+
]
284+
)
285+
286+
# Confirm that we can't start a workflow on existing environment
287+
with pytest.raises(RPCError) as err:
288+
await client.start_workflow(
289+
"some-workflow",
290+
id=f"wf-{uuid.uuid4()}",
291+
task_queue=f"tq-{uuid.uuid4()}",
292+
search_attributes=attrs,
293+
)
294+
assert "no mapping defined" in str(err.value)
295+
296+
# But we can in a new environment with the attrs set
297+
async with await WorkflowEnvironment.start_local(
298+
search_attributes=[
299+
text_attr,
300+
keyword_attr,
301+
keyword_list_attr,
302+
int_attr,
303+
float_attr,
304+
bool_attr,
305+
datetime_attr,
306+
]
307+
) as env:
308+
handle = await env.client.start_workflow(
309+
"some-workflow",
310+
id=f"wf-{uuid.uuid4()}",
311+
task_queue=f"tq-{uuid.uuid4()}",
312+
search_attributes=attrs,
313+
)
314+
desc = await handle.describe()
315+
assert attrs == desc.typed_search_attributes
316+
317+
248318
def assert_timestamp_from_now(
249319
ts: Union[datetime, float], expected_from_now: float, max_delta: float = 30
250320
) -> None:

0 commit comments

Comments
 (0)