azure-functions-durable 1.2.8__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 -711
- 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 -29
- 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 -333
- 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 -25
- 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.8.dist-info → azure_functions_durable-1.2.10.dist-info}/LICENSE +21 -21
- {azure_functions_durable-1.2.8.dist-info → azure_functions_durable-1.2.10.dist-info}/METADATA +58 -58
- azure_functions_durable-1.2.10.dist-info/RECORD +100 -0
- {azure_functions_durable-1.2.8.dist-info → azure_functions_durable-1.2.10.dist-info}/WHEEL +1 -1
- tests/models/test_DecoratorMetadata.py +135 -135
- tests/models/test_Decorators.py +107 -107
- tests/models/test_DurableOrchestrationBindings.py +68 -56
- tests/models/test_DurableOrchestrationClient.py +730 -612
- 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 -801
- 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.8.data/data/_manifest/bsi.json +0 -1
- azure_functions_durable-1.2.8.data/data/_manifest/manifest.cat +0 -0
- azure_functions_durable-1.2.8.data/data/_manifest/manifest.spdx.json +0 -12845
- azure_functions_durable-1.2.8.data/data/_manifest/manifest.spdx.json.sha256 +0 -1
- azure_functions_durable-1.2.8.dist-info/RECORD +0 -102
- {azure_functions_durable-1.2.8.dist-info → azure_functions_durable-1.2.10.dist-info}/top_level.txt +0 -0
|
@@ -1,176 +1,235 @@
|
|
|
1
|
-
from azure.durable_functions.models.ReplaySchema import ReplaySchema
|
|
2
|
-
import json
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
from azure.durable_functions.
|
|
7
|
-
from .
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
from
|
|
11
|
-
from azure.durable_functions.models.
|
|
12
|
-
from azure.durable_functions.models.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
context_builder.
|
|
47
|
-
context_builder.
|
|
48
|
-
context_builder.
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
context_builder.
|
|
55
|
-
context_builder.
|
|
56
|
-
context_builder.
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
expected_state
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
assert http_request
|
|
149
|
-
assert http_request['
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
expected_state
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
1
|
+
from azure.durable_functions.models.ReplaySchema import ReplaySchema
|
|
2
|
+
import json
|
|
3
|
+
import pytest
|
|
4
|
+
from typing import Dict
|
|
5
|
+
|
|
6
|
+
from azure.durable_functions.constants import HTTP_ACTION_NAME
|
|
7
|
+
from azure.durable_functions.models import DurableHttpRequest
|
|
8
|
+
from .orchestrator_test_utils import assert_orchestration_state_equals, \
|
|
9
|
+
get_orchestration_state_result, assert_valid_schema, assert_dict_are_equal
|
|
10
|
+
from tests.test_utils.ContextBuilder import ContextBuilder
|
|
11
|
+
from azure.durable_functions.models.OrchestratorState import OrchestratorState
|
|
12
|
+
from azure.durable_functions.models.actions.CallHttpAction import CallHttpAction
|
|
13
|
+
from azure.durable_functions.models.TokenSource import ManagedIdentityTokenSource
|
|
14
|
+
|
|
15
|
+
TEST_URI: str = \
|
|
16
|
+
'https://localhost:7071/we_just_need_a_uri_to_use_for_testing'
|
|
17
|
+
SIMPLE_RESULT: str = json.dumps({'name': 'simple'})
|
|
18
|
+
CONTENT = json.dumps({'name': 'some data', 'additional': 'data'})
|
|
19
|
+
HEADERS = {'header1': 'value1', 'header2': 'value2'}
|
|
20
|
+
TOKEN_SOURCE = ManagedIdentityTokenSource('https://management.core.windows.net/')
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def simple_get_generator_function(context):
|
|
24
|
+
url = TEST_URI
|
|
25
|
+
yield context.call_http("GET", url)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def complete_generator_function(context):
|
|
29
|
+
url = TEST_URI
|
|
30
|
+
|
|
31
|
+
yield context.call_http(method="POST", uri=url, content=json.loads(CONTENT),
|
|
32
|
+
headers=HEADERS, token_source=TOKEN_SOURCE)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def base_expected_state(output=None, replay_schema: ReplaySchema = ReplaySchema.V1) -> OrchestratorState:
|
|
36
|
+
return OrchestratorState(is_done=False, actions=[], output=output, replay_schema=replay_schema.value)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def add_http_action(state: OrchestratorState, request):
|
|
40
|
+
action = CallHttpAction(request)
|
|
41
|
+
state.actions.append([action])
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def add_completed_http_events(
|
|
45
|
+
context_builder: ContextBuilder, id_: int, result: str):
|
|
46
|
+
context_builder.add_task_scheduled_event(name=HTTP_ACTION_NAME, id_=id_)
|
|
47
|
+
context_builder.add_orchestrator_completed_event()
|
|
48
|
+
context_builder.add_orchestrator_started_event()
|
|
49
|
+
context_builder.add_task_completed_event(id_=id_, result=result)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def add_failed_http_events(
|
|
53
|
+
context_builder: ContextBuilder, id_: int, reason: str, details: str):
|
|
54
|
+
context_builder.add_task_scheduled_event(name=HTTP_ACTION_NAME, id_=id_)
|
|
55
|
+
context_builder.add_orchestrator_completed_event()
|
|
56
|
+
context_builder.add_orchestrator_started_event()
|
|
57
|
+
context_builder.add_task_failed_event(
|
|
58
|
+
id_=id_, reason=reason, details=details)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def get_request() -> DurableHttpRequest:
|
|
62
|
+
return DurableHttpRequest(method='GET', uri=TEST_URI)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def post_request() -> DurableHttpRequest:
|
|
66
|
+
return DurableHttpRequest(method="POST", uri=TEST_URI, content=json.dumps(CONTENT),
|
|
67
|
+
headers=HEADERS, token_source=TOKEN_SOURCE)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def test_initial_orchestration_state():
|
|
71
|
+
context_builder = ContextBuilder('test_simple_function')
|
|
72
|
+
|
|
73
|
+
result = get_orchestration_state_result(
|
|
74
|
+
context_builder, simple_get_generator_function)
|
|
75
|
+
|
|
76
|
+
expected_state = base_expected_state()
|
|
77
|
+
request = get_request()
|
|
78
|
+
add_http_action(expected_state, request)
|
|
79
|
+
expected = expected_state.to_json()
|
|
80
|
+
|
|
81
|
+
assert_valid_schema(result)
|
|
82
|
+
assert_orchestration_state_equals(expected, result)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def test_completed_state():
|
|
86
|
+
context_builder = ContextBuilder('test_simple_function')
|
|
87
|
+
add_completed_http_events(context_builder, 0, SIMPLE_RESULT)
|
|
88
|
+
|
|
89
|
+
result = get_orchestration_state_result(
|
|
90
|
+
context_builder, simple_get_generator_function)
|
|
91
|
+
|
|
92
|
+
expected_state = base_expected_state()
|
|
93
|
+
request = get_request()
|
|
94
|
+
add_http_action(expected_state, request)
|
|
95
|
+
expected_state._is_done = True
|
|
96
|
+
expected = expected_state.to_json()
|
|
97
|
+
|
|
98
|
+
assert_valid_schema(result)
|
|
99
|
+
assert_orchestration_state_equals(expected, result)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def test_failed_state():
|
|
103
|
+
failed_reason = 'Reasons'
|
|
104
|
+
failed_details = 'Stuff and Things'
|
|
105
|
+
context_builder = ContextBuilder('test_simple_function')
|
|
106
|
+
add_failed_http_events(
|
|
107
|
+
context_builder, 0, failed_reason, failed_details)
|
|
108
|
+
|
|
109
|
+
try:
|
|
110
|
+
result = get_orchestration_state_result(
|
|
111
|
+
context_builder, simple_get_generator_function)
|
|
112
|
+
# We expected an exception
|
|
113
|
+
assert False
|
|
114
|
+
except Exception as e:
|
|
115
|
+
error_label = "\n\n$OutOfProcData$:"
|
|
116
|
+
error_str = str(e)
|
|
117
|
+
|
|
118
|
+
expected_state = base_expected_state()
|
|
119
|
+
request = get_request()
|
|
120
|
+
add_http_action(expected_state, request)
|
|
121
|
+
|
|
122
|
+
error_msg = f'{failed_reason} \n {failed_details}'
|
|
123
|
+
expected_state._error = error_msg
|
|
124
|
+
state_str = expected_state.to_json_string()
|
|
125
|
+
|
|
126
|
+
expected_error_str = f"{error_msg}{error_label}{state_str}"
|
|
127
|
+
assert expected_error_str == error_str
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def test_initial_post_state():
|
|
131
|
+
context_builder = ContextBuilder('test_simple_function')
|
|
132
|
+
|
|
133
|
+
result = get_orchestration_state_result(
|
|
134
|
+
context_builder, complete_generator_function)
|
|
135
|
+
|
|
136
|
+
expected_state = base_expected_state()
|
|
137
|
+
request = post_request()
|
|
138
|
+
add_http_action(expected_state, request)
|
|
139
|
+
expected = expected_state.to_json()
|
|
140
|
+
|
|
141
|
+
# assert_valid_schema(result)
|
|
142
|
+
assert_orchestration_state_equals(expected, result)
|
|
143
|
+
validate_result_http_request(result)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def validate_result_http_request(result):
|
|
147
|
+
http_request = result['actions'][0][0]['httpRequest']
|
|
148
|
+
assert http_request is not None
|
|
149
|
+
assert http_request['method'] == 'POST'
|
|
150
|
+
assert http_request['uri'] == TEST_URI
|
|
151
|
+
content = http_request['content']
|
|
152
|
+
assert isinstance(content, str)
|
|
153
|
+
content = json.loads(content)
|
|
154
|
+
test_content = json.loads(CONTENT)
|
|
155
|
+
assert_dict_are_equal(test_content, content)
|
|
156
|
+
assert content['name'] == 'some data'
|
|
157
|
+
headers: Dict[str, str] = http_request['headers']
|
|
158
|
+
assert_dict_are_equal(HEADERS, headers)
|
|
159
|
+
assert http_request['tokenSource']['resource'] == TOKEN_SOURCE.resource
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def test_post_completed_state():
|
|
163
|
+
context_builder = ContextBuilder('test_simple_function')
|
|
164
|
+
add_completed_http_events(context_builder, 0, SIMPLE_RESULT)
|
|
165
|
+
|
|
166
|
+
result = get_orchestration_state_result(
|
|
167
|
+
context_builder, complete_generator_function)
|
|
168
|
+
|
|
169
|
+
expected_state = base_expected_state()
|
|
170
|
+
request = post_request()
|
|
171
|
+
add_http_action(expected_state, request)
|
|
172
|
+
expected_state._is_done = True
|
|
173
|
+
expected = expected_state.to_json()
|
|
174
|
+
|
|
175
|
+
# assert_valid_schema(result)
|
|
176
|
+
assert_orchestration_state_equals(expected, result)
|
|
177
|
+
validate_result_http_request(result)
|
|
178
|
+
|
|
179
|
+
@pytest.mark.parametrize("content, expected_content, is_raw_str", [
|
|
180
|
+
(None, None, False),
|
|
181
|
+
("string data", '"string data"', False),
|
|
182
|
+
('{"key": "value"}', '"{\\"key\\": \\"value\\"}"', False),
|
|
183
|
+
('["list", "content"]', '"[\\"list\\", \\"content\\"]"', False),
|
|
184
|
+
('[]', '"[]"', False),
|
|
185
|
+
('42', '"42"', False),
|
|
186
|
+
('true', '"true"', False),
|
|
187
|
+
# Cases that test actual behavior (not strictly adhering to Optional[str])
|
|
188
|
+
({"key": "value"}, '{"key": "value"}', False),
|
|
189
|
+
(["list", "content"], '["list", "content"]', False),
|
|
190
|
+
([], '[]', False),
|
|
191
|
+
(42, '42', False),
|
|
192
|
+
(True, 'true', False),
|
|
193
|
+
# Cases when is_raw_str is True
|
|
194
|
+
("string data", "string data", True),
|
|
195
|
+
('{"key": "value"}', '{"key": "value"}', True),
|
|
196
|
+
('[]', '[]', True),
|
|
197
|
+
])
|
|
198
|
+
def test_call_http_content_handling(content, expected_content, is_raw_str):
|
|
199
|
+
def orchestrator_function(context):
|
|
200
|
+
yield context.call_http("POST", TEST_URI, content, is_raw_str=is_raw_str)
|
|
201
|
+
|
|
202
|
+
context_builder = ContextBuilder('test_call_http_content_handling')
|
|
203
|
+
result = get_orchestration_state_result(context_builder, orchestrator_function)
|
|
204
|
+
|
|
205
|
+
assert len(result['actions']) == 1
|
|
206
|
+
http_action = result['actions'][0][0]['httpRequest']
|
|
207
|
+
|
|
208
|
+
assert http_action['method'] == "POST"
|
|
209
|
+
assert http_action['uri'] == TEST_URI
|
|
210
|
+
assert http_action['content'] == expected_content
|
|
211
|
+
|
|
212
|
+
# Test that call_http raises a TypeError when is_raw_str is True but content is not a string
|
|
213
|
+
def test_call_http_non_string_content_with_raw_str():
|
|
214
|
+
def orchestrator_function(context):
|
|
215
|
+
yield context.call_http("POST", TEST_URI, {"key": "value"}, is_raw_str=True)
|
|
216
|
+
|
|
217
|
+
context_builder = ContextBuilder('test_call_http_non_string_content_with_raw_str')
|
|
218
|
+
|
|
219
|
+
try:
|
|
220
|
+
result = get_orchestration_state_result(context_builder, orchestrator_function)
|
|
221
|
+
assert False
|
|
222
|
+
except Exception as e:
|
|
223
|
+
error_label = "\n\n$OutOfProcData$:"
|
|
224
|
+
error_str = str(e)
|
|
225
|
+
|
|
226
|
+
expected_state = base_expected_state()
|
|
227
|
+
error_msg = "Invalid use of 'is_raw_str' parameter: 'is_raw_str' is "\
|
|
228
|
+
"set to 'True' but 'content' is not an instance of type 'str'. "\
|
|
229
|
+
"Either set 'is_raw_str' to 'False', or ensure your 'content' "\
|
|
230
|
+
"is of type 'str'."
|
|
231
|
+
expected_state._error = error_msg
|
|
232
|
+
state_str = expected_state.to_json_string()
|
|
233
|
+
|
|
234
|
+
expected_error_str = f"{error_msg}{error_label}{state_str}"
|
|
235
|
+
assert expected_error_str == error_str
|
|
@@ -1,67 +1,67 @@
|
|
|
1
|
-
from azure.durable_functions.models.ReplaySchema import ReplaySchema
|
|
2
|
-
from .orchestrator_test_utils \
|
|
3
|
-
import assert_orchestration_state_equals, get_orchestration_state_result, assert_valid_schema
|
|
4
|
-
from tests.test_utils.ContextBuilder import ContextBuilder
|
|
5
|
-
from azure.durable_functions.models.OrchestratorState import OrchestratorState
|
|
6
|
-
from azure.durable_functions.models.actions.CallActivityAction \
|
|
7
|
-
import CallActivityAction
|
|
8
|
-
from azure.durable_functions.models.actions.ContinueAsNewAction \
|
|
9
|
-
import ContinueAsNewAction
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def generator_function(context):
|
|
13
|
-
yield context.call_activity("Hello", "Tokyo")
|
|
14
|
-
context.continue_as_new("Cause I can")
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def base_expected_state(output=None, replay_schema: ReplaySchema = ReplaySchema.V1) -> OrchestratorState:
|
|
18
|
-
return OrchestratorState(is_done=False, actions=[], output=output, replay_schema=replay_schema.value)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def add_hello_action(state: OrchestratorState, input_: str):
|
|
22
|
-
action = CallActivityAction(function_name='Hello', input_=input_)
|
|
23
|
-
state.actions.append([action])
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def add_continue_as_new_action(state: OrchestratorState, input_: str):
|
|
27
|
-
action = ContinueAsNewAction(input_=input_)
|
|
28
|
-
state.actions.append([action])
|
|
29
|
-
state._is_done = True
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def add_hello_completed_events(
|
|
33
|
-
context_builder: ContextBuilder, id_: int, result: str):
|
|
34
|
-
context_builder.add_task_scheduled_event(name='Hello', id_=id_)
|
|
35
|
-
context_builder.add_orchestrator_completed_event()
|
|
36
|
-
context_builder.add_orchestrator_started_event()
|
|
37
|
-
context_builder.add_task_completed_event(id_=id_, result=result)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def test_initial_orchestration_state():
|
|
41
|
-
context_builder = ContextBuilder('test_simple_function')
|
|
42
|
-
|
|
43
|
-
result = get_orchestration_state_result(
|
|
44
|
-
context_builder, generator_function)
|
|
45
|
-
|
|
46
|
-
expected_state = base_expected_state()
|
|
47
|
-
add_hello_action(expected_state, 'Tokyo')
|
|
48
|
-
expected = expected_state.to_json()
|
|
49
|
-
|
|
50
|
-
assert_valid_schema(result)
|
|
51
|
-
assert_orchestration_state_equals(expected, result)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def test_tokyo_state():
|
|
55
|
-
context_builder = ContextBuilder('test_simple_function')
|
|
56
|
-
add_hello_completed_events(context_builder, 0, "\"Hello Tokyo!\"")
|
|
57
|
-
|
|
58
|
-
result = get_orchestration_state_result(
|
|
59
|
-
context_builder, generator_function)
|
|
60
|
-
|
|
61
|
-
expected_state = base_expected_state()
|
|
62
|
-
add_hello_action(expected_state, 'Tokyo')
|
|
63
|
-
add_continue_as_new_action(expected_state, 'Cause I can')
|
|
64
|
-
expected = expected_state.to_json()
|
|
65
|
-
|
|
66
|
-
assert_valid_schema(result)
|
|
67
|
-
assert_orchestration_state_equals(expected, result)
|
|
1
|
+
from azure.durable_functions.models.ReplaySchema import ReplaySchema
|
|
2
|
+
from .orchestrator_test_utils \
|
|
3
|
+
import assert_orchestration_state_equals, get_orchestration_state_result, assert_valid_schema
|
|
4
|
+
from tests.test_utils.ContextBuilder import ContextBuilder
|
|
5
|
+
from azure.durable_functions.models.OrchestratorState import OrchestratorState
|
|
6
|
+
from azure.durable_functions.models.actions.CallActivityAction \
|
|
7
|
+
import CallActivityAction
|
|
8
|
+
from azure.durable_functions.models.actions.ContinueAsNewAction \
|
|
9
|
+
import ContinueAsNewAction
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def generator_function(context):
|
|
13
|
+
yield context.call_activity("Hello", "Tokyo")
|
|
14
|
+
context.continue_as_new("Cause I can")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def base_expected_state(output=None, replay_schema: ReplaySchema = ReplaySchema.V1) -> OrchestratorState:
|
|
18
|
+
return OrchestratorState(is_done=False, actions=[], output=output, replay_schema=replay_schema.value)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def add_hello_action(state: OrchestratorState, input_: str):
|
|
22
|
+
action = CallActivityAction(function_name='Hello', input_=input_)
|
|
23
|
+
state.actions.append([action])
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def add_continue_as_new_action(state: OrchestratorState, input_: str):
|
|
27
|
+
action = ContinueAsNewAction(input_=input_)
|
|
28
|
+
state.actions.append([action])
|
|
29
|
+
state._is_done = True
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def add_hello_completed_events(
|
|
33
|
+
context_builder: ContextBuilder, id_: int, result: str):
|
|
34
|
+
context_builder.add_task_scheduled_event(name='Hello', id_=id_)
|
|
35
|
+
context_builder.add_orchestrator_completed_event()
|
|
36
|
+
context_builder.add_orchestrator_started_event()
|
|
37
|
+
context_builder.add_task_completed_event(id_=id_, result=result)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_initial_orchestration_state():
|
|
41
|
+
context_builder = ContextBuilder('test_simple_function')
|
|
42
|
+
|
|
43
|
+
result = get_orchestration_state_result(
|
|
44
|
+
context_builder, generator_function)
|
|
45
|
+
|
|
46
|
+
expected_state = base_expected_state()
|
|
47
|
+
add_hello_action(expected_state, 'Tokyo')
|
|
48
|
+
expected = expected_state.to_json()
|
|
49
|
+
|
|
50
|
+
assert_valid_schema(result)
|
|
51
|
+
assert_orchestration_state_equals(expected, result)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_tokyo_state():
|
|
55
|
+
context_builder = ContextBuilder('test_simple_function')
|
|
56
|
+
add_hello_completed_events(context_builder, 0, "\"Hello Tokyo!\"")
|
|
57
|
+
|
|
58
|
+
result = get_orchestration_state_result(
|
|
59
|
+
context_builder, generator_function)
|
|
60
|
+
|
|
61
|
+
expected_state = base_expected_state()
|
|
62
|
+
add_hello_action(expected_state, 'Tokyo')
|
|
63
|
+
add_continue_as_new_action(expected_state, 'Cause I can')
|
|
64
|
+
expected = expected_state.to_json()
|
|
65
|
+
|
|
66
|
+
assert_valid_schema(result)
|
|
67
|
+
assert_orchestration_state_equals(expected, result)
|