Skip to content

Commit 04d9ff5

Browse files
committed
WIP service interface / impl tests
1 parent 520aecf commit 04d9ff5

File tree

2 files changed

+83
-21
lines changed

2 files changed

+83
-21
lines changed

temporalio/workflow.py

+1
Original file line numberDiff line numberDiff line change
@@ -5178,6 +5178,7 @@ def __init__(
51785178
self._schedule_to_close_timeout = schedule_to_close_timeout
51795179

51805180
# TODO(dan): overloads: no-input, operation name, ret type
5181+
# TODO(dan): should it be an error to use a reference to a mathod on a class other than that supplied?
51815182
async def start_operation(
51825183
self,
51835184
operation: Union[

tests/worker/test_nexus.py

+82-21
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@
3636
# Service interface
3737
#
3838
class CallerReference(StrEnum):
39-
IMPLEMENTATION = "implementation"
39+
IMPLEMENTATION_WITHOUT_INTERFACE = "implementation-without-interface"
40+
IMPLEMENTATION_OF_INTERFACE = "implementation-of-interface"
4041
INTERFACE = "interface"
4142

4243

@@ -189,7 +190,7 @@ def __init__(
189190
) -> None:
190191
self.nexus_service = workflow.NexusClient(
191192
service={
192-
CallerReference.IMPLEMENTATION: MyServiceImpl,
193+
CallerReference.IMPLEMENTATION_OF_INTERFACE: MyServiceImpl,
193194
CallerReference.INTERFACE: MyServiceInterface,
194195
}[input.caller_reference],
195196
endpoint=make_nexus_endpoint_name(task_queue),
@@ -237,7 +238,7 @@ def _get_operation(
237238
(
238239
SyncResponse,
239240
OpDefinitionType.SHORTHAND,
240-
CallerReference.IMPLEMENTATION,
241+
CallerReference.IMPLEMENTATION_OF_INTERFACE,
241242
): MyServiceImpl.my_sync_operation,
242243
(
243244
SyncResponse,
@@ -247,7 +248,7 @@ def _get_operation(
247248
(
248249
SyncResponse,
249250
OpDefinitionType.LONGHAND,
250-
CallerReference.IMPLEMENTATION,
251+
CallerReference.IMPLEMENTATION_OF_INTERFACE,
251252
): MyServiceImpl.my_sync_or_async_operation,
252253
(
253254
SyncResponse,
@@ -257,7 +258,7 @@ def _get_operation(
257258
(
258259
AsyncResponse,
259260
OpDefinitionType.SHORTHAND,
260-
CallerReference.IMPLEMENTATION,
261+
CallerReference.IMPLEMENTATION_OF_INTERFACE,
261262
): MyServiceImpl.my_async_operation,
262263
(
263264
AsyncResponse,
@@ -267,7 +268,7 @@ def _get_operation(
267268
(
268269
AsyncResponse,
269270
OpDefinitionType.LONGHAND,
270-
CallerReference.IMPLEMENTATION,
271+
CallerReference.IMPLEMENTATION_OF_INTERFACE,
271272
): MyServiceImpl.my_sync_or_async_operation,
272273
(
273274
AsyncResponse,
@@ -297,7 +298,8 @@ def _get_operation(
297298
"op_definition_type", [OpDefinitionType.SHORTHAND, OpDefinitionType.LONGHAND]
298299
)
299300
@pytest.mark.parametrize(
300-
"caller_reference", [CallerReference.IMPLEMENTATION, CallerReference.INTERFACE]
301+
"caller_reference",
302+
[CallerReference.IMPLEMENTATION_OF_INTERFACE, CallerReference.INTERFACE],
301303
)
302304
async def test_sync_response(
303305
client: Client,
@@ -343,7 +345,8 @@ async def test_sync_response(
343345
"op_definition_type", [OpDefinitionType.SHORTHAND, OpDefinitionType.LONGHAND]
344346
)
345347
@pytest.mark.parametrize(
346-
"caller_reference", [CallerReference.IMPLEMENTATION, CallerReference.INTERFACE]
348+
"caller_reference",
349+
[CallerReference.IMPLEMENTATION_OF_INTERFACE, CallerReference.INTERFACE],
347350
)
348351
async def test_async_response(
349352
client: Client,
@@ -469,13 +472,31 @@ class MyServiceInterfaceWithNameOverride:
469472
my_op: nexusrpc.interface.Operation[None, str]
470473

471474

475+
@nexusrpc.handler.service
476+
class MyServiceImplInterfaceWithNeitherInterfaceNorNameOverride:
477+
@nexusrpc.handler.sync_operation
478+
async def my_op(
479+
self, input: None, options: nexusrpc.handler.StartOperationOptions
480+
) -> str:
481+
return self.__class__.__name__
482+
483+
472484
@nexusrpc.handler.service(interface=MyServiceInterfaceWithoutNameOverride)
473-
class MyServiceImplWithoutNameOverride:
485+
class MyServiceImplInterfaceWithoutNameOverride:
486+
@nexusrpc.handler.sync_operation
487+
async def my_op(
488+
self, input: None, options: nexusrpc.handler.StartOperationOptions
489+
) -> str:
490+
return self.__class__.__name__
491+
492+
493+
@nexusrpc.handler.service(interface=MyServiceInterfaceWithNameOverride)
494+
class MyServiceImplInterfaceWithNameOverride:
474495
@nexusrpc.handler.sync_operation
475496
async def my_op(
476497
self, input: None, options: nexusrpc.handler.StartOperationOptions
477498
) -> str:
478-
return "from service impl with interface"
499+
return self.__class__.__name__
479500

480501

481502
@nexusrpc.handler.service(name="my-service-impl-🌈")
@@ -484,7 +505,7 @@ class MyServiceImplWithNameOverride:
484505
async def my_op(
485506
self, input: None, options: nexusrpc.handler.StartOperationOptions
486507
) -> str:
487-
return "from service impl with name override"
508+
return self.__class__.__name__
488509

489510

490511
class NameOverride(StrEnum):
@@ -511,13 +532,17 @@ async def run(
511532
NameOverride.NO,
512533
): MyServiceInterfaceWithoutNameOverride,
513534
(
514-
CallerReference.IMPLEMENTATION,
535+
CallerReference.IMPLEMENTATION_OF_INTERFACE,
515536
NameOverride.YES,
516537
): MyServiceImplWithNameOverride,
517538
(
518-
CallerReference.IMPLEMENTATION,
539+
CallerReference.IMPLEMENTATION_OF_INTERFACE,
519540
NameOverride.NO,
520-
): MyServiceImplWithoutNameOverride,
541+
): MyServiceImplInterfaceWithoutNameOverride,
542+
(
543+
CallerReference.IMPLEMENTATION_WITHOUT_INTERFACE,
544+
NameOverride.NO,
545+
): MyServiceImplInterfaceWithNeitherInterfaceNorNameOverride,
521546
}[caller_reference, name_override]
522547
nexus_client = workflow.NexusClient(
523548
service=service_cls,
@@ -532,12 +557,27 @@ async def run(
532557

533558

534559
async def test_service_interface_and_implementation_names(client: Client):
560+
# Note that:
561+
# - The caller can specify the service & operation via a reference to either the
562+
# interface or implementation class.
563+
# - An interface class may optionally override its name.
564+
# - An implementation class may either override its name or specify an interface that
565+
# it is implementing.
566+
# - On registering a service implementation with a worker, the name by which the
567+
# service is addressed in requests is the interface name if the implementation
568+
# supplies one, or else the name override made by the impl class, or else the impl
569+
# class name.
570+
#
571+
# This test checks that the request is routed to the expected service under a variety
572+
# of the possible scenarios arising from the above.
535573
task_queue = str(uuid.uuid4())
536574
async with Worker(
537575
client,
538576
nexus_services=[
539-
MyServiceImplWithoutNameOverride(),
540577
MyServiceImplWithNameOverride(),
578+
MyServiceImplInterfaceWithNameOverride(),
579+
MyServiceImplInterfaceWithoutNameOverride(),
580+
MyServiceImplInterfaceWithNeitherInterfaceNorNameOverride(),
541581
],
542582
workflows=[MyServiceInterfaceAndImplCallerWorkflow],
543583
task_queue=task_queue,
@@ -551,7 +591,7 @@ async def test_service_interface_and_implementation_names(client: Client):
551591
id=str(uuid.uuid4()),
552592
task_queue=task_queue,
553593
)
554-
== "from service interface with name override"
594+
== "MyServiceImplInterfaceWithNameOverride"
555595
)
556596
assert (
557597
await client.execute_workflow(
@@ -560,25 +600,46 @@ async def test_service_interface_and_implementation_names(client: Client):
560600
id=str(uuid.uuid4()),
561601
task_queue=task_queue,
562602
)
563-
== "from service interface without name override"
603+
== "MyServiceImplInterfaceWithoutNameOverride"
604+
)
605+
assert (
606+
await client.execute_workflow(
607+
MyServiceInterfaceAndImplCallerWorkflow.run,
608+
args=(
609+
CallerReference.IMPLEMENTATION_OF_INTERFACE,
610+
NameOverride.YES,
611+
task_queue,
612+
),
613+
id=str(uuid.uuid4()),
614+
task_queue=task_queue,
615+
)
616+
== "MyServiceImplWithNameOverride"
564617
)
565618
assert (
566619
await client.execute_workflow(
567620
MyServiceInterfaceAndImplCallerWorkflow.run,
568-
args=(CallerReference.IMPLEMENTATION, NameOverride.YES, task_queue),
621+
args=(
622+
CallerReference.IMPLEMENTATION_OF_INTERFACE,
623+
NameOverride.NO,
624+
task_queue,
625+
),
569626
id=str(uuid.uuid4()),
570627
task_queue=task_queue,
571628
)
572-
== "from service impl with interface and name override"
629+
== "MyServiceImplInterfaceWithoutNameOverride"
573630
)
574631
assert (
575632
await client.execute_workflow(
576633
MyServiceInterfaceAndImplCallerWorkflow.run,
577-
args=(CallerReference.IMPLEMENTATION, NameOverride.NO, task_queue),
634+
args=(
635+
CallerReference.IMPLEMENTATION_WITHOUT_INTERFACE,
636+
NameOverride.NO,
637+
task_queue,
638+
),
578639
id=str(uuid.uuid4()),
579640
task_queue=task_queue,
580641
)
581-
== "from service impl with interface but without name override"
642+
== "MyServiceImplInterfaceWithNeitherInterfaceNorNameOverride"
582643
)
583644

584645

0 commit comments

Comments
 (0)