azure-functions-durable 1.2.9__py3-none-any.whl → 1.3.0__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.
Files changed (104) hide show
  1. azure/durable_functions/__init__.py +81 -81
  2. azure/durable_functions/constants.py +9 -9
  3. azure/durable_functions/decorators/__init__.py +3 -3
  4. azure/durable_functions/decorators/durable_app.py +260 -249
  5. azure/durable_functions/decorators/metadata.py +109 -109
  6. azure/durable_functions/entity.py +129 -125
  7. azure/durable_functions/models/DurableEntityContext.py +201 -201
  8. azure/durable_functions/models/DurableHttpRequest.py +58 -58
  9. azure/durable_functions/models/DurableOrchestrationBindings.py +66 -66
  10. azure/durable_functions/models/DurableOrchestrationClient.py +812 -781
  11. azure/durable_functions/models/DurableOrchestrationContext.py +761 -707
  12. azure/durable_functions/models/DurableOrchestrationStatus.py +156 -156
  13. azure/durable_functions/models/EntityStateResponse.py +23 -23
  14. azure/durable_functions/models/FunctionContext.py +7 -7
  15. azure/durable_functions/models/OrchestrationRuntimeStatus.py +32 -32
  16. azure/durable_functions/models/OrchestratorState.py +117 -116
  17. azure/durable_functions/models/PurgeHistoryResult.py +33 -33
  18. azure/durable_functions/models/ReplaySchema.py +9 -8
  19. azure/durable_functions/models/RetryOptions.py +69 -69
  20. azure/durable_functions/models/RpcManagementOptions.py +86 -86
  21. azure/durable_functions/models/Task.py +540 -426
  22. azure/durable_functions/models/TaskOrchestrationExecutor.py +352 -336
  23. azure/durable_functions/models/TokenSource.py +56 -56
  24. azure/durable_functions/models/__init__.py +26 -24
  25. azure/durable_functions/models/actions/Action.py +23 -23
  26. azure/durable_functions/models/actions/ActionType.py +18 -18
  27. azure/durable_functions/models/actions/CallActivityAction.py +41 -41
  28. azure/durable_functions/models/actions/CallActivityWithRetryAction.py +45 -45
  29. azure/durable_functions/models/actions/CallEntityAction.py +46 -46
  30. azure/durable_functions/models/actions/CallHttpAction.py +35 -35
  31. azure/durable_functions/models/actions/CallSubOrchestratorAction.py +40 -40
  32. azure/durable_functions/models/actions/CallSubOrchestratorWithRetryAction.py +44 -44
  33. azure/durable_functions/models/actions/CompoundAction.py +35 -35
  34. azure/durable_functions/models/actions/ContinueAsNewAction.py +36 -36
  35. azure/durable_functions/models/actions/CreateTimerAction.py +48 -48
  36. azure/durable_functions/models/actions/NoOpAction.py +35 -35
  37. azure/durable_functions/models/actions/SignalEntityAction.py +47 -47
  38. azure/durable_functions/models/actions/WaitForExternalEventAction.py +63 -63
  39. azure/durable_functions/models/actions/WhenAllAction.py +14 -14
  40. azure/durable_functions/models/actions/WhenAnyAction.py +14 -14
  41. azure/durable_functions/models/actions/__init__.py +24 -24
  42. azure/durable_functions/models/entities/EntityState.py +74 -74
  43. azure/durable_functions/models/entities/OperationResult.py +94 -76
  44. azure/durable_functions/models/entities/RequestMessage.py +53 -53
  45. azure/durable_functions/models/entities/ResponseMessage.py +48 -48
  46. azure/durable_functions/models/entities/Signal.py +62 -62
  47. azure/durable_functions/models/entities/__init__.py +17 -17
  48. azure/durable_functions/models/history/HistoryEvent.py +92 -92
  49. azure/durable_functions/models/history/HistoryEventType.py +27 -27
  50. azure/durable_functions/models/history/__init__.py +8 -8
  51. azure/durable_functions/models/utils/__init__.py +7 -7
  52. azure/durable_functions/models/utils/entity_utils.py +103 -91
  53. azure/durable_functions/models/utils/http_utils.py +80 -69
  54. azure/durable_functions/models/utils/json_utils.py +96 -56
  55. azure/durable_functions/orchestrator.py +73 -71
  56. azure/durable_functions/testing/OrchestratorGeneratorWrapper.py +42 -0
  57. azure/durable_functions/testing/__init__.py +6 -0
  58. {azure_functions_durable-1.2.9.dist-info → azure_functions_durable-1.3.0.dist-info}/LICENSE +21 -21
  59. {azure_functions_durable-1.2.9.dist-info → azure_functions_durable-1.3.0.dist-info}/METADATA +59 -58
  60. azure_functions_durable-1.3.0.dist-info/RECORD +103 -0
  61. {azure_functions_durable-1.2.9.dist-info → azure_functions_durable-1.3.0.dist-info}/WHEEL +1 -1
  62. tests/models/test_DecoratorMetadata.py +135 -135
  63. tests/models/test_Decorators.py +107 -107
  64. tests/models/test_DurableOrchestrationBindings.py +68 -68
  65. tests/models/test_DurableOrchestrationClient.py +730 -730
  66. tests/models/test_DurableOrchestrationContext.py +102 -102
  67. tests/models/test_DurableOrchestrationStatus.py +59 -59
  68. tests/models/test_OrchestrationState.py +28 -28
  69. tests/models/test_RpcManagementOptions.py +79 -79
  70. tests/models/test_TokenSource.py +10 -10
  71. tests/orchestrator/models/OrchestrationInstance.py +18 -18
  72. tests/orchestrator/orchestrator_test_utils.py +130 -130
  73. tests/orchestrator/schemas/OrchetrationStateSchema.py +66 -66
  74. tests/orchestrator/test_call_http.py +235 -176
  75. tests/orchestrator/test_continue_as_new.py +67 -67
  76. tests/orchestrator/test_create_timer.py +126 -126
  77. tests/orchestrator/test_entity.py +397 -395
  78. tests/orchestrator/test_external_event.py +53 -53
  79. tests/orchestrator/test_fan_out_fan_in.py +175 -175
  80. tests/orchestrator/test_is_replaying_flag.py +101 -101
  81. tests/orchestrator/test_retries.py +308 -308
  82. tests/orchestrator/test_sequential_orchestrator.py +841 -841
  83. tests/orchestrator/test_sequential_orchestrator_custom_status.py +119 -119
  84. tests/orchestrator/test_sequential_orchestrator_with_retry.py +465 -465
  85. tests/orchestrator/test_serialization.py +30 -30
  86. tests/orchestrator/test_sub_orchestrator.py +95 -95
  87. tests/orchestrator/test_sub_orchestrator_with_retry.py +129 -129
  88. tests/orchestrator/test_task_any.py +60 -60
  89. tests/tasks/tasks_test_utils.py +17 -17
  90. tests/tasks/test_long_timers.py +70 -0
  91. tests/tasks/test_new_uuid.py +34 -34
  92. tests/test_utils/ContextBuilder.py +174 -174
  93. tests/test_utils/EntityContextBuilder.py +56 -56
  94. tests/test_utils/constants.py +1 -1
  95. tests/test_utils/json_utils.py +30 -30
  96. tests/test_utils/testClasses.py +56 -56
  97. tests/utils/__init__.py +1 -0
  98. tests/utils/test_entity_utils.py +24 -0
  99. azure_functions_durable-1.2.9.data/data/_manifest/bsi.json +0 -1
  100. azure_functions_durable-1.2.9.data/data/_manifest/manifest.cat +0 -0
  101. azure_functions_durable-1.2.9.data/data/_manifest/manifest.spdx.json +0 -11985
  102. azure_functions_durable-1.2.9.data/data/_manifest/manifest.spdx.json.sha256 +0 -1
  103. azure_functions_durable-1.2.9.dist-info/RECORD +0 -102
  104. {azure_functions_durable-1.2.9.dist-info → azure_functions_durable-1.3.0.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