azure-functions-durable 1.2.9__py3-none-any.whl → 1.2.10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- azure/durable_functions/__init__.py +81 -81
- azure/durable_functions/constants.py +9 -9
- azure/durable_functions/decorators/__init__.py +3 -3
- azure/durable_functions/decorators/durable_app.py +249 -249
- azure/durable_functions/decorators/metadata.py +109 -109
- azure/durable_functions/entity.py +125 -125
- azure/durable_functions/models/DurableEntityContext.py +201 -201
- azure/durable_functions/models/DurableHttpRequest.py +58 -58
- azure/durable_functions/models/DurableOrchestrationBindings.py +66 -66
- azure/durable_functions/models/DurableOrchestrationClient.py +781 -781
- azure/durable_functions/models/DurableOrchestrationContext.py +722 -707
- azure/durable_functions/models/DurableOrchestrationStatus.py +156 -156
- azure/durable_functions/models/EntityStateResponse.py +23 -23
- azure/durable_functions/models/FunctionContext.py +7 -7
- azure/durable_functions/models/OrchestrationRuntimeStatus.py +32 -32
- azure/durable_functions/models/OrchestratorState.py +117 -116
- azure/durable_functions/models/PurgeHistoryResult.py +33 -33
- azure/durable_functions/models/ReplaySchema.py +8 -8
- azure/durable_functions/models/RetryOptions.py +69 -69
- azure/durable_functions/models/RpcManagementOptions.py +86 -86
- azure/durable_functions/models/Task.py +426 -426
- azure/durable_functions/models/TaskOrchestrationExecutor.py +346 -336
- azure/durable_functions/models/TokenSource.py +56 -56
- azure/durable_functions/models/__init__.py +24 -24
- azure/durable_functions/models/actions/Action.py +23 -23
- azure/durable_functions/models/actions/ActionType.py +18 -18
- azure/durable_functions/models/actions/CallActivityAction.py +41 -41
- azure/durable_functions/models/actions/CallActivityWithRetryAction.py +45 -45
- azure/durable_functions/models/actions/CallEntityAction.py +46 -46
- azure/durable_functions/models/actions/CallHttpAction.py +35 -35
- azure/durable_functions/models/actions/CallSubOrchestratorAction.py +40 -40
- azure/durable_functions/models/actions/CallSubOrchestratorWithRetryAction.py +44 -44
- azure/durable_functions/models/actions/CompoundAction.py +35 -35
- azure/durable_functions/models/actions/ContinueAsNewAction.py +36 -36
- azure/durable_functions/models/actions/CreateTimerAction.py +48 -48
- azure/durable_functions/models/actions/NoOpAction.py +35 -35
- azure/durable_functions/models/actions/SignalEntityAction.py +47 -47
- azure/durable_functions/models/actions/WaitForExternalEventAction.py +63 -63
- azure/durable_functions/models/actions/WhenAllAction.py +14 -14
- azure/durable_functions/models/actions/WhenAnyAction.py +14 -14
- azure/durable_functions/models/actions/__init__.py +24 -24
- azure/durable_functions/models/entities/EntityState.py +74 -74
- azure/durable_functions/models/entities/OperationResult.py +76 -76
- azure/durable_functions/models/entities/RequestMessage.py +53 -53
- azure/durable_functions/models/entities/ResponseMessage.py +48 -48
- azure/durable_functions/models/entities/Signal.py +62 -62
- azure/durable_functions/models/entities/__init__.py +17 -17
- azure/durable_functions/models/history/HistoryEvent.py +92 -92
- azure/durable_functions/models/history/HistoryEventType.py +27 -27
- azure/durable_functions/models/history/__init__.py +8 -8
- azure/durable_functions/models/utils/__init__.py +7 -7
- azure/durable_functions/models/utils/entity_utils.py +103 -91
- azure/durable_functions/models/utils/http_utils.py +69 -69
- azure/durable_functions/models/utils/json_utils.py +56 -56
- azure/durable_functions/orchestrator.py +71 -71
- {azure_functions_durable-1.2.9.dist-info → azure_functions_durable-1.2.10.dist-info}/LICENSE +21 -21
- {azure_functions_durable-1.2.9.dist-info → azure_functions_durable-1.2.10.dist-info}/METADATA +58 -58
- azure_functions_durable-1.2.10.dist-info/RECORD +100 -0
- tests/models/test_DecoratorMetadata.py +135 -135
- tests/models/test_Decorators.py +107 -107
- tests/models/test_DurableOrchestrationBindings.py +68 -68
- tests/models/test_DurableOrchestrationClient.py +730 -730
- tests/models/test_DurableOrchestrationContext.py +102 -102
- tests/models/test_DurableOrchestrationStatus.py +59 -59
- tests/models/test_OrchestrationState.py +28 -28
- tests/models/test_RpcManagementOptions.py +79 -79
- tests/models/test_TokenSource.py +10 -10
- tests/orchestrator/models/OrchestrationInstance.py +18 -18
- tests/orchestrator/orchestrator_test_utils.py +130 -130
- tests/orchestrator/schemas/OrchetrationStateSchema.py +66 -66
- tests/orchestrator/test_call_http.py +235 -176
- tests/orchestrator/test_continue_as_new.py +67 -67
- tests/orchestrator/test_create_timer.py +126 -126
- tests/orchestrator/test_entity.py +395 -395
- tests/orchestrator/test_external_event.py +53 -53
- tests/orchestrator/test_fan_out_fan_in.py +175 -175
- tests/orchestrator/test_is_replaying_flag.py +101 -101
- tests/orchestrator/test_retries.py +308 -308
- tests/orchestrator/test_sequential_orchestrator.py +841 -841
- tests/orchestrator/test_sequential_orchestrator_custom_status.py +119 -119
- tests/orchestrator/test_sequential_orchestrator_with_retry.py +465 -465
- tests/orchestrator/test_serialization.py +30 -30
- tests/orchestrator/test_sub_orchestrator.py +95 -95
- tests/orchestrator/test_sub_orchestrator_with_retry.py +129 -129
- tests/orchestrator/test_task_any.py +60 -60
- tests/tasks/tasks_test_utils.py +17 -17
- tests/tasks/test_new_uuid.py +34 -34
- tests/test_utils/ContextBuilder.py +174 -174
- tests/test_utils/EntityContextBuilder.py +56 -56
- tests/test_utils/constants.py +1 -1
- tests/test_utils/json_utils.py +30 -30
- tests/test_utils/testClasses.py +56 -56
- tests/utils/__init__.py +1 -0
- tests/utils/test_entity_utils.py +24 -0
- azure_functions_durable-1.2.9.data/data/_manifest/bsi.json +0 -1
- azure_functions_durable-1.2.9.data/data/_manifest/manifest.cat +0 -0
- azure_functions_durable-1.2.9.data/data/_manifest/manifest.spdx.json +0 -11985
- azure_functions_durable-1.2.9.data/data/_manifest/manifest.spdx.json.sha256 +0 -1
- azure_functions_durable-1.2.9.dist-info/RECORD +0 -102
- {azure_functions_durable-1.2.9.dist-info → azure_functions_durable-1.2.10.dist-info}/WHEEL +0 -0
- {azure_functions_durable-1.2.9.dist-info → azure_functions_durable-1.2.10.dist-info}/top_level.txt +0 -0
|
@@ -1,54 +1,54 @@
|
|
|
1
|
-
from datetime import datetime
|
|
2
|
-
from tests.orchestrator.test_fan_out_fan_in import add_completed_event, add_failed_event, base_expected_state, add_multi_actions
|
|
3
|
-
from tests.orchestrator.orchestrator_test_utils import assert_orchestration_state_equals, get_orchestration_state_result
|
|
4
|
-
from tests.test_utils.ContextBuilder import ContextBuilder
|
|
5
|
-
from azure.durable_functions.models.actions.WaitForExternalEventAction import WaitForExternalEventAction
|
|
6
|
-
|
|
7
|
-
def generator_function(context):
|
|
8
|
-
result = yield context.wait_for_external_event("A")
|
|
9
|
-
return result
|
|
10
|
-
|
|
11
|
-
def generator_function_multiple(context):
|
|
12
|
-
result = yield context.wait_for_external_event("B")
|
|
13
|
-
result = yield context.wait_for_external_event("A")
|
|
14
|
-
return result
|
|
15
|
-
|
|
16
|
-
def test_continue_when_no_payload():
|
|
17
|
-
context_builder = ContextBuilder()
|
|
18
|
-
result = get_orchestration_state_result(
|
|
19
|
-
context_builder, generator_function)
|
|
20
|
-
|
|
21
|
-
expected_state = base_expected_state()
|
|
22
|
-
expected_state.actions.append([WaitForExternalEventAction("A")])
|
|
23
|
-
expected = expected_state.to_json()
|
|
24
|
-
assert_orchestration_state_equals(expected, result)
|
|
25
|
-
|
|
26
|
-
def test_succeeds_on_payload():
|
|
27
|
-
timestamp = datetime.now()
|
|
28
|
-
json_input = '{"test":"somecontent"}'
|
|
29
|
-
context_builder = ContextBuilder()
|
|
30
|
-
context_builder.add_event_raised_event("A", input_=json_input, timestamp=timestamp, id_=-1)
|
|
31
|
-
result = get_orchestration_state_result(
|
|
32
|
-
context_builder, generator_function)
|
|
33
|
-
|
|
34
|
-
expected_state = base_expected_state({"test":"somecontent"})
|
|
35
|
-
expected_state.actions.append([WaitForExternalEventAction("A")])
|
|
36
|
-
expected_state._is_done = True
|
|
37
|
-
expected = expected_state.to_json()
|
|
38
|
-
assert_orchestration_state_equals(expected, result)
|
|
39
|
-
|
|
40
|
-
def test_succeeds_on_out_of_order_payload():
|
|
41
|
-
timestamp = datetime.now()
|
|
42
|
-
json_input = '{"test":"somecontent"}'
|
|
43
|
-
context_builder = ContextBuilder()
|
|
44
|
-
context_builder.add_event_raised_event("B", input_=json_input, timestamp=timestamp, id_=-1)
|
|
45
|
-
context_builder.add_event_raised_event("A", input_=json_input, timestamp=timestamp, id_=-1)
|
|
46
|
-
result = get_orchestration_state_result(
|
|
47
|
-
context_builder, generator_function_multiple)
|
|
48
|
-
|
|
49
|
-
expected_state = base_expected_state({"test":"somecontent"})
|
|
50
|
-
expected_state.actions.append([WaitForExternalEventAction("A")])
|
|
51
|
-
expected_state.actions.append([WaitForExternalEventAction("B")])
|
|
52
|
-
expected_state._is_done = True
|
|
53
|
-
expected = expected_state.to_json()
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from tests.orchestrator.test_fan_out_fan_in import add_completed_event, add_failed_event, base_expected_state, add_multi_actions
|
|
3
|
+
from tests.orchestrator.orchestrator_test_utils import assert_orchestration_state_equals, get_orchestration_state_result
|
|
4
|
+
from tests.test_utils.ContextBuilder import ContextBuilder
|
|
5
|
+
from azure.durable_functions.models.actions.WaitForExternalEventAction import WaitForExternalEventAction
|
|
6
|
+
|
|
7
|
+
def generator_function(context):
|
|
8
|
+
result = yield context.wait_for_external_event("A")
|
|
9
|
+
return result
|
|
10
|
+
|
|
11
|
+
def generator_function_multiple(context):
|
|
12
|
+
result = yield context.wait_for_external_event("B")
|
|
13
|
+
result = yield context.wait_for_external_event("A")
|
|
14
|
+
return result
|
|
15
|
+
|
|
16
|
+
def test_continue_when_no_payload():
|
|
17
|
+
context_builder = ContextBuilder()
|
|
18
|
+
result = get_orchestration_state_result(
|
|
19
|
+
context_builder, generator_function)
|
|
20
|
+
|
|
21
|
+
expected_state = base_expected_state()
|
|
22
|
+
expected_state.actions.append([WaitForExternalEventAction("A")])
|
|
23
|
+
expected = expected_state.to_json()
|
|
24
|
+
assert_orchestration_state_equals(expected, result)
|
|
25
|
+
|
|
26
|
+
def test_succeeds_on_payload():
|
|
27
|
+
timestamp = datetime.now()
|
|
28
|
+
json_input = '{"test":"somecontent"}'
|
|
29
|
+
context_builder = ContextBuilder()
|
|
30
|
+
context_builder.add_event_raised_event("A", input_=json_input, timestamp=timestamp, id_=-1)
|
|
31
|
+
result = get_orchestration_state_result(
|
|
32
|
+
context_builder, generator_function)
|
|
33
|
+
|
|
34
|
+
expected_state = base_expected_state({"test":"somecontent"})
|
|
35
|
+
expected_state.actions.append([WaitForExternalEventAction("A")])
|
|
36
|
+
expected_state._is_done = True
|
|
37
|
+
expected = expected_state.to_json()
|
|
38
|
+
assert_orchestration_state_equals(expected, result)
|
|
39
|
+
|
|
40
|
+
def test_succeeds_on_out_of_order_payload():
|
|
41
|
+
timestamp = datetime.now()
|
|
42
|
+
json_input = '{"test":"somecontent"}'
|
|
43
|
+
context_builder = ContextBuilder()
|
|
44
|
+
context_builder.add_event_raised_event("B", input_=json_input, timestamp=timestamp, id_=-1)
|
|
45
|
+
context_builder.add_event_raised_event("A", input_=json_input, timestamp=timestamp, id_=-1)
|
|
46
|
+
result = get_orchestration_state_result(
|
|
47
|
+
context_builder, generator_function_multiple)
|
|
48
|
+
|
|
49
|
+
expected_state = base_expected_state({"test":"somecontent"})
|
|
50
|
+
expected_state.actions.append([WaitForExternalEventAction("A")])
|
|
51
|
+
expected_state.actions.append([WaitForExternalEventAction("B")])
|
|
52
|
+
expected_state._is_done = True
|
|
53
|
+
expected = expected_state.to_json()
|
|
54
54
|
assert_orchestration_state_equals(expected, result)
|
|
@@ -1,175 +1,175 @@
|
|
|
1
|
-
from azure.durable_functions.models.ReplaySchema import ReplaySchema
|
|
2
|
-
import json
|
|
3
|
-
|
|
4
|
-
from azure.durable_functions.models import OrchestratorState
|
|
5
|
-
from azure.durable_functions.models.actions import CallActivityAction
|
|
6
|
-
from .orchestrator_test_utils import get_orchestration_state_result, \
|
|
7
|
-
assert_orchestration_state_equals, assert_valid_schema
|
|
8
|
-
from tests.test_utils.ContextBuilder import ContextBuilder
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def generator_function(context):
|
|
12
|
-
activity_count = yield context.call_activity("GetActivityCount")
|
|
13
|
-
tasks = []
|
|
14
|
-
for i in range(activity_count):
|
|
15
|
-
current_task = context.call_activity("ParrotValue", str(i))
|
|
16
|
-
tasks.append(current_task)
|
|
17
|
-
values = yield context.task_all(tasks)
|
|
18
|
-
results = yield context.call_activity("ShowMeTheSum", values)
|
|
19
|
-
return results
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def base_expected_state(output=None, error=None, replay_schema: ReplaySchema = ReplaySchema.V1) -> OrchestratorState:
|
|
23
|
-
return OrchestratorState(is_done=False, actions=[], output=output, replay_schema=replay_schema)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def add_completed_event(
|
|
27
|
-
context_builder: ContextBuilder, id_: int, name: str, result):
|
|
28
|
-
context_builder.add_task_scheduled_event(name=name, id_=id_)
|
|
29
|
-
context_builder.add_orchestrator_completed_event()
|
|
30
|
-
context_builder.add_orchestrator_started_event()
|
|
31
|
-
context_builder.add_task_completed_event(id_=id_, result=json.dumps(result))
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def add_failed_event(
|
|
35
|
-
context_builder: ContextBuilder, id_: int, name: str, reason: str, details: str):
|
|
36
|
-
context_builder.add_task_scheduled_event(name=name, id_=id_)
|
|
37
|
-
context_builder.add_orchestrator_completed_event()
|
|
38
|
-
context_builder.add_orchestrator_started_event()
|
|
39
|
-
context_builder.add_task_failed_event(
|
|
40
|
-
id_=id_, reason=reason, details=details)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
def add_completed_task_set_events(
|
|
44
|
-
context_builder: ContextBuilder, start_id: int, name: str, volume: int,
|
|
45
|
-
failed_index: int = -1, failed_reason: str = '', failed_details: str = ''):
|
|
46
|
-
for i in range(volume):
|
|
47
|
-
if i != failed_index:
|
|
48
|
-
add_completed_event(context_builder, start_id + i, name, i)
|
|
49
|
-
else:
|
|
50
|
-
add_failed_event(context_builder, start_id + i, name, failed_reason, failed_details)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
def add_single_action(state: OrchestratorState, function_name: str, input_):
|
|
54
|
-
action = CallActivityAction(function_name=function_name, input_=input_)
|
|
55
|
-
state.actions.append([action])
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def add_multi_actions(state: OrchestratorState, function_name: str, volume: int):
|
|
59
|
-
actions = []
|
|
60
|
-
for i in range(volume):
|
|
61
|
-
action = CallActivityAction(function_name=function_name, input_=json.dumps(i))
|
|
62
|
-
actions.append(action)
|
|
63
|
-
state.actions.append(actions)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
def test_initial_call():
|
|
67
|
-
context_builder = ContextBuilder('test_fan_out_fan_in_function')
|
|
68
|
-
|
|
69
|
-
result = get_orchestration_state_result(
|
|
70
|
-
context_builder, generator_function)
|
|
71
|
-
|
|
72
|
-
expected_state = base_expected_state()
|
|
73
|
-
add_single_action(expected_state, function_name='GetActivityCount', input_=None)
|
|
74
|
-
expected = expected_state.to_json()
|
|
75
|
-
|
|
76
|
-
assert_valid_schema(result)
|
|
77
|
-
assert_orchestration_state_equals(expected, result)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
def test_get_activity_count_success():
|
|
81
|
-
activity_count = 5
|
|
82
|
-
context_builder = ContextBuilder('test_fan_out_fan_in_function')
|
|
83
|
-
add_completed_event(context_builder, 0, 'GetActivityCount', activity_count)
|
|
84
|
-
|
|
85
|
-
result = get_orchestration_state_result(
|
|
86
|
-
context_builder, generator_function)
|
|
87
|
-
|
|
88
|
-
expected_state = base_expected_state()
|
|
89
|
-
add_single_action(expected_state, function_name='GetActivityCount', input_=None)
|
|
90
|
-
add_multi_actions(expected_state, function_name='ParrotValue', volume=activity_count)
|
|
91
|
-
expected = expected_state.to_json()
|
|
92
|
-
|
|
93
|
-
assert_valid_schema(result)
|
|
94
|
-
assert_orchestration_state_equals(expected, result)
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
def test_parrot_value_success():
|
|
98
|
-
activity_count = 5
|
|
99
|
-
context_builder = ContextBuilder('test_fan_out_fan_in_function')
|
|
100
|
-
add_completed_event(context_builder, 0, 'GetActivityCount', activity_count)
|
|
101
|
-
add_completed_task_set_events(context_builder, 1, 'ParrotValue', activity_count)
|
|
102
|
-
|
|
103
|
-
result = get_orchestration_state_result(
|
|
104
|
-
context_builder, generator_function)
|
|
105
|
-
|
|
106
|
-
expected_state = base_expected_state()
|
|
107
|
-
add_single_action(expected_state, function_name='GetActivityCount', input_=None)
|
|
108
|
-
add_multi_actions(expected_state, function_name='ParrotValue', volume=activity_count)
|
|
109
|
-
results = []
|
|
110
|
-
for i in range(activity_count):
|
|
111
|
-
results.append(i)
|
|
112
|
-
add_single_action(expected_state, function_name='ShowMeTheSum', input_=results)
|
|
113
|
-
expected = expected_state.to_json()
|
|
114
|
-
|
|
115
|
-
assert_valid_schema(result)
|
|
116
|
-
assert_orchestration_state_equals(expected, result)
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
def test_show_me_the_sum_success():
|
|
120
|
-
activity_count = 5
|
|
121
|
-
sum_ = 0
|
|
122
|
-
for i in range(activity_count):
|
|
123
|
-
sum_ += i
|
|
124
|
-
sum_results = f"Well that's nice {sum_}!"
|
|
125
|
-
context_builder = ContextBuilder('test_fan_out_fan_in_function')
|
|
126
|
-
add_completed_event(context_builder, 0, 'GetActivityCount', activity_count)
|
|
127
|
-
add_completed_task_set_events(context_builder, 1, 'ParrotValue', activity_count)
|
|
128
|
-
add_completed_event(
|
|
129
|
-
context_builder, activity_count + 1, 'ShowMeTheSum', sum_results)
|
|
130
|
-
|
|
131
|
-
result = get_orchestration_state_result(
|
|
132
|
-
context_builder, generator_function)
|
|
133
|
-
|
|
134
|
-
expected_state = base_expected_state(sum_results)
|
|
135
|
-
add_single_action(expected_state, function_name='GetActivityCount', input_=None)
|
|
136
|
-
add_multi_actions(expected_state, function_name='ParrotValue', volume=activity_count)
|
|
137
|
-
results = []
|
|
138
|
-
for i in range(activity_count):
|
|
139
|
-
results.append(i)
|
|
140
|
-
add_single_action(expected_state, function_name='ShowMeTheSum', input_=results)
|
|
141
|
-
expected_state._is_done = True
|
|
142
|
-
expected = expected_state.to_json()
|
|
143
|
-
|
|
144
|
-
assert_valid_schema(result)
|
|
145
|
-
assert_orchestration_state_equals(expected, result)
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
def test_failed_parrot_value():
|
|
149
|
-
failed_reason = 'Reasons'
|
|
150
|
-
failed_details = 'Stuff and Things'
|
|
151
|
-
activity_count = 5
|
|
152
|
-
context_builder = ContextBuilder('test_fan_out_fan_in_function')
|
|
153
|
-
add_completed_event(context_builder, 0, 'GetActivityCount', activity_count)
|
|
154
|
-
add_completed_task_set_events(context_builder, 1, 'ParrotValue', activity_count,
|
|
155
|
-
2, failed_reason, failed_details)
|
|
156
|
-
|
|
157
|
-
try:
|
|
158
|
-
result = get_orchestration_state_result(
|
|
159
|
-
context_builder, generator_function)
|
|
160
|
-
# we expected an exception
|
|
161
|
-
assert False
|
|
162
|
-
except Exception as e:
|
|
163
|
-
error_label = "\n\n$OutOfProcData$:"
|
|
164
|
-
error_str = str(e)
|
|
165
|
-
|
|
166
|
-
expected_state = base_expected_state(error=f'{failed_reason} \n {failed_details}')
|
|
167
|
-
add_single_action(expected_state, function_name='GetActivityCount', input_=None)
|
|
168
|
-
add_multi_actions(expected_state, function_name='ParrotValue', volume=activity_count)
|
|
169
|
-
|
|
170
|
-
error_msg = f'{failed_reason} \n {failed_details}'
|
|
171
|
-
expected_state._error = error_msg
|
|
172
|
-
state_str = expected_state.to_json_string()
|
|
173
|
-
|
|
174
|
-
expected_error_str = f"{error_msg}{error_label}{state_str}"
|
|
175
|
-
assert expected_error_str == error_str
|
|
1
|
+
from azure.durable_functions.models.ReplaySchema import ReplaySchema
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
from azure.durable_functions.models import OrchestratorState
|
|
5
|
+
from azure.durable_functions.models.actions import CallActivityAction
|
|
6
|
+
from .orchestrator_test_utils import get_orchestration_state_result, \
|
|
7
|
+
assert_orchestration_state_equals, assert_valid_schema
|
|
8
|
+
from tests.test_utils.ContextBuilder import ContextBuilder
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def generator_function(context):
|
|
12
|
+
activity_count = yield context.call_activity("GetActivityCount")
|
|
13
|
+
tasks = []
|
|
14
|
+
for i in range(activity_count):
|
|
15
|
+
current_task = context.call_activity("ParrotValue", str(i))
|
|
16
|
+
tasks.append(current_task)
|
|
17
|
+
values = yield context.task_all(tasks)
|
|
18
|
+
results = yield context.call_activity("ShowMeTheSum", values)
|
|
19
|
+
return results
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def base_expected_state(output=None, error=None, replay_schema: ReplaySchema = ReplaySchema.V1) -> OrchestratorState:
|
|
23
|
+
return OrchestratorState(is_done=False, actions=[], output=output, replay_schema=replay_schema)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def add_completed_event(
|
|
27
|
+
context_builder: ContextBuilder, id_: int, name: str, result):
|
|
28
|
+
context_builder.add_task_scheduled_event(name=name, id_=id_)
|
|
29
|
+
context_builder.add_orchestrator_completed_event()
|
|
30
|
+
context_builder.add_orchestrator_started_event()
|
|
31
|
+
context_builder.add_task_completed_event(id_=id_, result=json.dumps(result))
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def add_failed_event(
|
|
35
|
+
context_builder: ContextBuilder, id_: int, name: str, reason: str, details: str):
|
|
36
|
+
context_builder.add_task_scheduled_event(name=name, id_=id_)
|
|
37
|
+
context_builder.add_orchestrator_completed_event()
|
|
38
|
+
context_builder.add_orchestrator_started_event()
|
|
39
|
+
context_builder.add_task_failed_event(
|
|
40
|
+
id_=id_, reason=reason, details=details)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def add_completed_task_set_events(
|
|
44
|
+
context_builder: ContextBuilder, start_id: int, name: str, volume: int,
|
|
45
|
+
failed_index: int = -1, failed_reason: str = '', failed_details: str = ''):
|
|
46
|
+
for i in range(volume):
|
|
47
|
+
if i != failed_index:
|
|
48
|
+
add_completed_event(context_builder, start_id + i, name, i)
|
|
49
|
+
else:
|
|
50
|
+
add_failed_event(context_builder, start_id + i, name, failed_reason, failed_details)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def add_single_action(state: OrchestratorState, function_name: str, input_):
|
|
54
|
+
action = CallActivityAction(function_name=function_name, input_=input_)
|
|
55
|
+
state.actions.append([action])
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def add_multi_actions(state: OrchestratorState, function_name: str, volume: int):
|
|
59
|
+
actions = []
|
|
60
|
+
for i in range(volume):
|
|
61
|
+
action = CallActivityAction(function_name=function_name, input_=json.dumps(i))
|
|
62
|
+
actions.append(action)
|
|
63
|
+
state.actions.append(actions)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_initial_call():
|
|
67
|
+
context_builder = ContextBuilder('test_fan_out_fan_in_function')
|
|
68
|
+
|
|
69
|
+
result = get_orchestration_state_result(
|
|
70
|
+
context_builder, generator_function)
|
|
71
|
+
|
|
72
|
+
expected_state = base_expected_state()
|
|
73
|
+
add_single_action(expected_state, function_name='GetActivityCount', input_=None)
|
|
74
|
+
expected = expected_state.to_json()
|
|
75
|
+
|
|
76
|
+
assert_valid_schema(result)
|
|
77
|
+
assert_orchestration_state_equals(expected, result)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def test_get_activity_count_success():
|
|
81
|
+
activity_count = 5
|
|
82
|
+
context_builder = ContextBuilder('test_fan_out_fan_in_function')
|
|
83
|
+
add_completed_event(context_builder, 0, 'GetActivityCount', activity_count)
|
|
84
|
+
|
|
85
|
+
result = get_orchestration_state_result(
|
|
86
|
+
context_builder, generator_function)
|
|
87
|
+
|
|
88
|
+
expected_state = base_expected_state()
|
|
89
|
+
add_single_action(expected_state, function_name='GetActivityCount', input_=None)
|
|
90
|
+
add_multi_actions(expected_state, function_name='ParrotValue', volume=activity_count)
|
|
91
|
+
expected = expected_state.to_json()
|
|
92
|
+
|
|
93
|
+
assert_valid_schema(result)
|
|
94
|
+
assert_orchestration_state_equals(expected, result)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def test_parrot_value_success():
|
|
98
|
+
activity_count = 5
|
|
99
|
+
context_builder = ContextBuilder('test_fan_out_fan_in_function')
|
|
100
|
+
add_completed_event(context_builder, 0, 'GetActivityCount', activity_count)
|
|
101
|
+
add_completed_task_set_events(context_builder, 1, 'ParrotValue', activity_count)
|
|
102
|
+
|
|
103
|
+
result = get_orchestration_state_result(
|
|
104
|
+
context_builder, generator_function)
|
|
105
|
+
|
|
106
|
+
expected_state = base_expected_state()
|
|
107
|
+
add_single_action(expected_state, function_name='GetActivityCount', input_=None)
|
|
108
|
+
add_multi_actions(expected_state, function_name='ParrotValue', volume=activity_count)
|
|
109
|
+
results = []
|
|
110
|
+
for i in range(activity_count):
|
|
111
|
+
results.append(i)
|
|
112
|
+
add_single_action(expected_state, function_name='ShowMeTheSum', input_=results)
|
|
113
|
+
expected = expected_state.to_json()
|
|
114
|
+
|
|
115
|
+
assert_valid_schema(result)
|
|
116
|
+
assert_orchestration_state_equals(expected, result)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def test_show_me_the_sum_success():
|
|
120
|
+
activity_count = 5
|
|
121
|
+
sum_ = 0
|
|
122
|
+
for i in range(activity_count):
|
|
123
|
+
sum_ += i
|
|
124
|
+
sum_results = f"Well that's nice {sum_}!"
|
|
125
|
+
context_builder = ContextBuilder('test_fan_out_fan_in_function')
|
|
126
|
+
add_completed_event(context_builder, 0, 'GetActivityCount', activity_count)
|
|
127
|
+
add_completed_task_set_events(context_builder, 1, 'ParrotValue', activity_count)
|
|
128
|
+
add_completed_event(
|
|
129
|
+
context_builder, activity_count + 1, 'ShowMeTheSum', sum_results)
|
|
130
|
+
|
|
131
|
+
result = get_orchestration_state_result(
|
|
132
|
+
context_builder, generator_function)
|
|
133
|
+
|
|
134
|
+
expected_state = base_expected_state(sum_results)
|
|
135
|
+
add_single_action(expected_state, function_name='GetActivityCount', input_=None)
|
|
136
|
+
add_multi_actions(expected_state, function_name='ParrotValue', volume=activity_count)
|
|
137
|
+
results = []
|
|
138
|
+
for i in range(activity_count):
|
|
139
|
+
results.append(i)
|
|
140
|
+
add_single_action(expected_state, function_name='ShowMeTheSum', input_=results)
|
|
141
|
+
expected_state._is_done = True
|
|
142
|
+
expected = expected_state.to_json()
|
|
143
|
+
|
|
144
|
+
assert_valid_schema(result)
|
|
145
|
+
assert_orchestration_state_equals(expected, result)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def test_failed_parrot_value():
|
|
149
|
+
failed_reason = 'Reasons'
|
|
150
|
+
failed_details = 'Stuff and Things'
|
|
151
|
+
activity_count = 5
|
|
152
|
+
context_builder = ContextBuilder('test_fan_out_fan_in_function')
|
|
153
|
+
add_completed_event(context_builder, 0, 'GetActivityCount', activity_count)
|
|
154
|
+
add_completed_task_set_events(context_builder, 1, 'ParrotValue', activity_count,
|
|
155
|
+
2, failed_reason, failed_details)
|
|
156
|
+
|
|
157
|
+
try:
|
|
158
|
+
result = get_orchestration_state_result(
|
|
159
|
+
context_builder, generator_function)
|
|
160
|
+
# we expected an exception
|
|
161
|
+
assert False
|
|
162
|
+
except Exception as e:
|
|
163
|
+
error_label = "\n\n$OutOfProcData$:"
|
|
164
|
+
error_str = str(e)
|
|
165
|
+
|
|
166
|
+
expected_state = base_expected_state(error=f'{failed_reason} \n {failed_details}')
|
|
167
|
+
add_single_action(expected_state, function_name='GetActivityCount', input_=None)
|
|
168
|
+
add_multi_actions(expected_state, function_name='ParrotValue', volume=activity_count)
|
|
169
|
+
|
|
170
|
+
error_msg = f'{failed_reason} \n {failed_details}'
|
|
171
|
+
expected_state._error = error_msg
|
|
172
|
+
state_str = expected_state.to_json_string()
|
|
173
|
+
|
|
174
|
+
expected_error_str = f"{error_msg}{error_label}{state_str}"
|
|
175
|
+
assert expected_error_str == error_str
|