Skip to content

Commit 407ad57

Browse files
authored
Update unit testing for compatibility with worker (#550)
* Update unit testing for compatibility with worker
1 parent b0570f0 commit 407ad57

File tree

3 files changed

+28
-81
lines changed

3 files changed

+28
-81
lines changed

azure/durable_functions/entity.py

Lines changed: 15 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,52 +3,13 @@
33
from datetime import datetime
44
from typing import Callable, Any, List, Dict
55

6-
import azure.functions as func
7-
86

97
class InternalEntityException(Exception):
108
"""Framework-internal Exception class (for internal use only)."""
119

1210
pass
1311

1412

15-
class EntityHandler(Callable):
16-
"""Durable Entity Handler.
17-
18-
A callable class that wraps the user defined entity function for execution by the Python worker
19-
and also allows access to the original method for unit testing
20-
"""
21-
22-
def __init__(self, func: Callable[[DurableEntityContext], None]):
23-
"""
24-
Create a new entity handler for the user defined entity function.
25-
26-
Parameters
27-
----------
28-
func: Callable[[DurableEntityContext], None]
29-
The user defined entity function.
30-
"""
31-
self.entity_function = func
32-
33-
def __call__(self, context: func.EntityContext) -> str:
34-
"""
35-
Handle the execution of the user defined entity function.
36-
37-
Parameters
38-
----------
39-
context : func.EntityContext
40-
The DF entity context
41-
"""
42-
# It is not clear when the context JSON would be found
43-
# inside a "body"-key, but this pattern matches the
44-
# orchestrator implementation, so we keep it for safety.
45-
context_body = getattr(context, "body", None)
46-
if context_body is None:
47-
context_body = context
48-
ctx, batch = DurableEntityContext.from_json(context_body)
49-
return Entity(self.entity_function).handle(ctx, batch)
50-
51-
5213
class Entity:
5314
"""Durable Entity Class.
5415
@@ -131,10 +92,22 @@ def create(cls, fn: Callable[[DurableEntityContext], None]) -> Callable[[Any], s
13192
13293
Returns
13394
-------
134-
EntityHandler
135-
Entity Handler callable for the newly created entity client
95+
Callable[[Any], str]
96+
Handle function of the newly created entity client
13697
"""
137-
return EntityHandler(fn)
98+
def handle(context) -> str:
99+
# It is not clear when the context JSON would be found
100+
# inside a "body"-key, but this pattern matches the
101+
# orchestrator implementation, so we keep it for safety.
102+
context_body = getattr(context, "body", None)
103+
if context_body is None:
104+
context_body = context
105+
ctx, batch = DurableEntityContext.from_json(context_body)
106+
return Entity(fn).handle(ctx, batch)
107+
108+
handle.entity_function = fn
109+
110+
return handle
138111

139112
def _elapsed_milliseconds_since(self, start_time: datetime) -> int:
140113
"""Calculate the elapsed time, in milliseconds, from the start_time to the present.

azure/durable_functions/orchestrator.py

Lines changed: 12 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -11,41 +11,6 @@
1111
import azure.functions as func
1212

1313

14-
class OrchestrationHandler(Callable):
15-
"""Durable Orchestration Handler.
16-
17-
A callable class that wraps the user defined generator function for execution
18-
by the Python worker and also allows access to the original method for unit testing
19-
"""
20-
21-
def __init__(self, func: Callable[[DurableOrchestrationContext], Generator[Any, Any, Any]]):
22-
"""
23-
Create a new orchestrator handler for the user defined orchestrator function.
24-
25-
Parameters
26-
----------
27-
func: Callable[[DurableOrchestrationContext], Generator[Any, Any, Any]]
28-
The user defined orchestrator function.
29-
"""
30-
self.orchestrator_function = func
31-
32-
def __call__(self, context: func.OrchestrationContext) -> str:
33-
"""
34-
Handle the execution of the user defined orchestrator function.
35-
36-
Parameters
37-
----------
38-
context : func.OrchestrationContext
39-
The DF orchestration context
40-
"""
41-
context_body = getattr(context, "body", None)
42-
if context_body is None:
43-
context_body = context
44-
return Orchestrator(self.orchestrator_function).handle(
45-
DurableOrchestrationContext.from_json(context_body)
46-
)
47-
48-
4914
class Orchestrator:
5015
"""Durable Orchestration Class.
5116
@@ -93,7 +58,16 @@ def create(cls, fn: Callable[[DurableOrchestrationContext], Generator[Any, Any,
9358
9459
Returns
9560
-------
96-
OrchestrationHandler
97-
Orchestration handler callable class for the newly created orchestration client
61+
Callable[[Any], str]
62+
Handle function of the newly created orchestration client
9863
"""
99-
return OrchestrationHandler(fn)
64+
65+
def handle(context: func.OrchestrationContext) -> str:
66+
context_body = getattr(context, "body", None)
67+
if context_body is None:
68+
context_body = context
69+
return Orchestrator(fn).handle(DurableOrchestrationContext.from_json(context_body))
70+
71+
handle.orchestrator_function = fn
72+
73+
return handle

samples-v2/function_chaining/tests/test_my_orchestrator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def test_chaining_orchestrator(self, context):
3131
expected_activity_calls = [call('say_hello', 'Tokyo'),
3232
call('say_hello', 'Seattle'),
3333
call('say_hello', 'London')]
34-
34+
3535
self.assertEqual(context.call_activity.call_count, 3)
3636
self.assertEqual(context.call_activity.call_args_list, expected_activity_calls)
3737
self.assertEqual(values[3], ["Hello Tokyo!", "Hello Seattle!", "Hello London!"])

0 commit comments

Comments
 (0)