dex-python-sdk 0.0.2__cp311-abi3-win_amd64.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.
- dex/__init__.py +146 -0
- dex/_grpc_errors.py +73 -0
- dex/_invocation_context.py +269 -0
- dex/_native.pyd +0 -0
- dex/_native.pyi +20 -0
- dex/_utils.py +18 -0
- dex/_value_hydrator.py +223 -0
- dex/_value_mapper.py +174 -0
- dex/_worker_dispatcher.py +451 -0
- dex/_worker_service.py +60 -0
- dex/attribute.py +87 -0
- dex/blob_cache.py +73 -0
- dex/channel.py +165 -0
- dex/client.py +715 -0
- dex/client_options.py +19 -0
- dex/codec.py +286 -0
- dex/command_request.py +120 -0
- dex/command_results.py +107 -0
- dex/communication.py +136 -0
- dex/communication_schema.py +54 -0
- dex/condition.py +74 -0
- dex/context.py +86 -0
- dex/data_attributes.py +70 -0
- dex/dexpb/__init__.py +1 -0
- dex/dexpb/dex_pb2.py +381 -0
- dex/dexpb/dex_pb2.pyi +1734 -0
- dex/dexpb/dex_pb2_grpc.py +1298 -0
- dex/errors.py +109 -0
- dex/flow.py +456 -0
- dex/flow_config.py +29 -0
- dex/flow_info.py +51 -0
- dex/flow_options.py +122 -0
- dex/object_encoder.py +799 -0
- dex/persistence.py +89 -0
- dex/persistence_options.py +12 -0
- dex/persistence_schema.py +51 -0
- dex/py.typed +1 -0
- dex/registry.py +204 -0
- dex/reset_workflow_type_and_options.py +67 -0
- dex/rpc.py +93 -0
- dex/runtime_errors.py +81 -0
- dex/search_attributes.py +184 -0
- dex/state_decision.py +153 -0
- dex/state_execution_locals.py +66 -0
- dex/state_movement.py +115 -0
- dex/state_schema.py +48 -0
- dex/step.py +194 -0
- dex/step_execution.py +42 -0
- dex/stop_workflow_options.py +18 -0
- dex/tests/__init__.py +80 -0
- dex/tests/dex-service-env/.env +7 -0
- dex/tests/dex-service-env/docker-compose-init.sh +44 -0
- dex/tests/dex-service-env/docker-compose.yml +97 -0
- dex/tests/dex-service-env/dynamicconfig/README.md +39 -0
- dex/tests/dex-service-env/dynamicconfig/development-sql.yaml +9 -0
- dex/tests/dex-service-env/dynamicconfig/docker.yaml +2 -0
- dex/tests/test_abnormal_exit_workflow.py +43 -0
- dex/tests/test_basic_workflow.py +70 -0
- dex/tests/test_conditional_complete.py +50 -0
- dex/tests/test_describe_workflow.py +40 -0
- dex/tests/test_empty_data_decodes_properly.py +74 -0
- dex/tests/test_internal_channel.py +28 -0
- dex/tests/test_internal_channel_with_no_prefix_channel.py +41 -0
- dex/tests/test_persistence_data_attributes.py +62 -0
- dex/tests/test_persistence_search_attributes.py +127 -0
- dex/tests/test_persistence_state_execution_locals.py +38 -0
- dex/tests/test_rpc.py +64 -0
- dex/tests/test_rpc_with_memo.py +195 -0
- dex/tests/test_rpc_with_memo_duplicate_java_tests.py +117 -0
- dex/tests/test_signal.py +51 -0
- dex/tests/test_skip_wait_until.py +76 -0
- dex/tests/test_state_failure_recovery.py +28 -0
- dex/tests/test_timer.py +35 -0
- dex/tests/test_wait_for_state_execution_completion.py +53 -0
- dex/tests/test_workflow_errors.py +87 -0
- dex/tests/test_workflow_state_options.py +118 -0
- dex/tests/test_workflow_state_options_override.py +44 -0
- dex/tests/worker_server.py +64 -0
- dex/tests/workflows/abnormal_exit_workflow.py +42 -0
- dex/tests/workflows/basic_workflow.py +62 -0
- dex/tests/workflows/conditional_complete_workflow.py +95 -0
- dex/tests/workflows/describe_workflow.py +46 -0
- dex/tests/workflows/empty_data_workflow.py +45 -0
- dex/tests/workflows/internal_channel_workflow.py +129 -0
- dex/tests/workflows/internal_channel_workflow_with_no_prefix_channel.py +100 -0
- dex/tests/workflows/java_duplicate_rpc_memo_workflow.py +276 -0
- dex/tests/workflows/persistence_data_attributes_workflow.py +98 -0
- dex/tests/workflows/persistence_search_attributes_workflow.py +159 -0
- dex/tests/workflows/persistence_state_execution_local_workflow.py +63 -0
- dex/tests/workflows/recovery_workflow.py +82 -0
- dex/tests/workflows/rpc_memo_workflow.py +231 -0
- dex/tests/workflows/rpc_workflow.py +117 -0
- dex/tests/workflows/state_options_override_workflow.py +93 -0
- dex/tests/workflows/state_options_workflow.py +84 -0
- dex/tests/workflows/timer_workflow.py +46 -0
- dex/tests/workflows/wait_for_state_with_state_execution_id_workflow.py +70 -0
- dex/tests/workflows/wait_for_state_with_wait_for_key_workflow.py +71 -0
- dex/tests/workflows/wait_internal_channel_workflow.py +47 -0
- dex/tests/workflows/wait_signal_workflow.py +147 -0
- dex/timer.py +21 -0
- dex/type_store.py +99 -0
- dex/unregistered_client.py +585 -0
- dex/utils/__init__.py +3 -0
- dex/utils/dex_typing.py +25 -0
- dex/utils/persistence_utils.py +32 -0
- dex/wait.py +49 -0
- dex/worker.py +121 -0
- dex/worker_options.py +22 -0
- dex/worker_service.py +432 -0
- dex/workflow.py +79 -0
- dex/workflow_context.py +44 -0
- dex/workflow_info.py +16 -0
- dex/workflow_options.py +74 -0
- dex/workflow_state.py +123 -0
- dex/workflow_state_options.py +154 -0
- dex_python_sdk-0.0.2.dist-info/METADATA +202 -0
- dex_python_sdk-0.0.2.dist-info/RECORD +121 -0
- dex_python_sdk-0.0.2.dist-info/WHEEL +4 -0
- dex_python_sdk-0.0.2.dist-info/licenses/LEGACY_NOTICES.md +61 -0
- dex_python_sdk-0.0.2.dist-info/licenses/LICENSE +192 -0
- dex_python_sdk-0.0.2.dist-info/sboms/dex-blob-cache-python.cyclonedx.json +2406 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Legacy Materials in this file remain under their original licenses.
|
|
2
|
+
# See LEGACY_NOTICES.md.
|
|
3
|
+
|
|
4
|
+
# Modifications Copyright (c) 2026 Super Durable, Inc.
|
|
5
|
+
#
|
|
6
|
+
# Modifications after the Legacy Cutoff are licensed under the
|
|
7
|
+
# Super Durable Source License 1.0.
|
|
8
|
+
# Legacy Materials remain under their original licenses.
|
|
9
|
+
# See LICENSE and LEGACY_NOTICES.md.
|
|
10
|
+
|
|
11
|
+
import inspect
|
|
12
|
+
import time
|
|
13
|
+
import unittest
|
|
14
|
+
|
|
15
|
+
from dex.client import Client
|
|
16
|
+
from dex.tests.worker_server import registry
|
|
17
|
+
from dex.tests.workflows.conditional_complete_workflow import (
|
|
18
|
+
ConditionalCompleteWorkflow,
|
|
19
|
+
test_signal_channel,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
class TestConditionalComplete(unittest.TestCase):
|
|
23
|
+
@classmethod
|
|
24
|
+
def setUpClass(cls):
|
|
25
|
+
cls.client = Client(registry)
|
|
26
|
+
|
|
27
|
+
def test_internal_channel_conditional_complete(self):
|
|
28
|
+
wf_id = f"{inspect.currentframe().f_code.co_name}-{time.time_ns()}"
|
|
29
|
+
do_test_conditional_workflow(self.client, wf_id, False)
|
|
30
|
+
|
|
31
|
+
def test_signal_channel_conditional_complete(self):
|
|
32
|
+
wf_id = f"{inspect.currentframe().f_code.co_name}-{time.time_ns()}"
|
|
33
|
+
do_test_conditional_workflow(self.client, wf_id, True)
|
|
34
|
+
|
|
35
|
+
def do_test_conditional_workflow(client: Client, wf_id: str, use_signal: bool):
|
|
36
|
+
client.start_workflow(ConditionalCompleteWorkflow, wf_id, 10, use_signal)
|
|
37
|
+
|
|
38
|
+
for x in range(3):
|
|
39
|
+
if use_signal:
|
|
40
|
+
client.signal_workflow(wf_id, test_signal_channel, 123)
|
|
41
|
+
else:
|
|
42
|
+
client.invoke_rpc(
|
|
43
|
+
wf_id, ConditionalCompleteWorkflow.test_rpc_publish_channel
|
|
44
|
+
)
|
|
45
|
+
if x == 0:
|
|
46
|
+
# wait for a second so that the workflow is in execute state
|
|
47
|
+
time.sleep(1)
|
|
48
|
+
|
|
49
|
+
res = client.wait_for_workflow_completion(wf_id)
|
|
50
|
+
assert res == 3
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Legacy Materials in this file remain under their original licenses.
|
|
2
|
+
# See LEGACY_NOTICES.md.
|
|
3
|
+
|
|
4
|
+
# Modifications Copyright (c) 2026 Super Durable, Inc.
|
|
5
|
+
#
|
|
6
|
+
# Modifications after the Legacy Cutoff are licensed under the
|
|
7
|
+
# Super Durable Source License 1.0.
|
|
8
|
+
# Legacy Materials remain under their original licenses.
|
|
9
|
+
# See LICENSE and LEGACY_NOTICES.md.
|
|
10
|
+
|
|
11
|
+
import inspect
|
|
12
|
+
import time
|
|
13
|
+
import unittest
|
|
14
|
+
|
|
15
|
+
from dex.client import Client
|
|
16
|
+
from dex.errors import WorkflowNotExistsError
|
|
17
|
+
from dex.dex_api.models import WorkflowStatus
|
|
18
|
+
from dex.tests.workflows.describe_workflow import DescribeWorkflow
|
|
19
|
+
from dex.tests.worker_server import registry
|
|
20
|
+
|
|
21
|
+
class TestDescribeWorkflow(unittest.TestCase):
|
|
22
|
+
@classmethod
|
|
23
|
+
def setUpClass(cls):
|
|
24
|
+
cls.client = Client(registry)
|
|
25
|
+
|
|
26
|
+
def test_describe_workflow(self):
|
|
27
|
+
wf_id = f"{inspect.currentframe().f_code.co_name}-{time.time_ns()}"
|
|
28
|
+
|
|
29
|
+
self.client.start_workflow(DescribeWorkflow, wf_id, 100)
|
|
30
|
+
workflow_info = self.client.describe_workflow(wf_id)
|
|
31
|
+
assert workflow_info.workflow_status == WorkflowStatus.RUNNING
|
|
32
|
+
|
|
33
|
+
# Stop the workflow
|
|
34
|
+
self.client.stop_workflow(wf_id)
|
|
35
|
+
|
|
36
|
+
def test_describe_workflow_when_workflow_not_exists(self):
|
|
37
|
+
wf_id = f"{inspect.currentframe().f_code.co_name}-{time.time_ns()}"
|
|
38
|
+
|
|
39
|
+
with self.assertRaises(WorkflowNotExistsError):
|
|
40
|
+
self.client.describe_workflow(wf_id)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Legacy Materials in this file remain under their original licenses.
|
|
2
|
+
# See LEGACY_NOTICES.md.
|
|
3
|
+
|
|
4
|
+
# Modifications Copyright (c) 2026 Super Durable, Inc.
|
|
5
|
+
#
|
|
6
|
+
# Modifications after the Legacy Cutoff are licensed under the
|
|
7
|
+
# Super Durable Source License 1.0.
|
|
8
|
+
# Legacy Materials remain under their original licenses.
|
|
9
|
+
# See LICENSE and LEGACY_NOTICES.md.
|
|
10
|
+
|
|
11
|
+
import inspect
|
|
12
|
+
import time
|
|
13
|
+
import unittest
|
|
14
|
+
|
|
15
|
+
import httpx
|
|
16
|
+
|
|
17
|
+
from dex.client import Client
|
|
18
|
+
from dex.tests.worker_server import registry
|
|
19
|
+
from dex.worker_service import WorkerService
|
|
20
|
+
|
|
21
|
+
class TestBinaryNullDecodesCorrectly(unittest.TestCase):
|
|
22
|
+
@classmethod
|
|
23
|
+
def setUpClass(cls):
|
|
24
|
+
cls.client = Client(registry)
|
|
25
|
+
|
|
26
|
+
def test_binary_null_input_decodes_correctly(self):
|
|
27
|
+
wf_id = f"{inspect.currentframe().f_code.co_name}-{time.time_ns()}"
|
|
28
|
+
|
|
29
|
+
response = httpx.post(
|
|
30
|
+
f"http://0.0.0.0:8802/{WorkerService.api_path_workflow_state_execute}",
|
|
31
|
+
json={
|
|
32
|
+
"DataObjects": [
|
|
33
|
+
{"key": "test-da", "value": {"encoding": "binary/null"}}
|
|
34
|
+
],
|
|
35
|
+
"commandResults": {
|
|
36
|
+
"interStateChannelResults": [],
|
|
37
|
+
"stateStartApiSucceeded": True,
|
|
38
|
+
},
|
|
39
|
+
"context": {
|
|
40
|
+
"attempt": 1,
|
|
41
|
+
"firstAttemptTimestamp": 1747935829,
|
|
42
|
+
"stateExecutionId": "State1-1",
|
|
43
|
+
"workflowId": wf_id,
|
|
44
|
+
"workflowRunId": "0196f734-d037-7432-bd63-e1136cd34dbd",
|
|
45
|
+
"workflowStartedTimestamp": 1747904155,
|
|
46
|
+
},
|
|
47
|
+
"stateInput": {"encoding": "binary/null"},
|
|
48
|
+
"stateLocals": [],
|
|
49
|
+
"workflowStateId": "State1",
|
|
50
|
+
"workflowType": "EmptyDataWorkflow",
|
|
51
|
+
},
|
|
52
|
+
)
|
|
53
|
+
assert response.is_success
|
|
54
|
+
response_json = response.json()
|
|
55
|
+
self.assertEqual(
|
|
56
|
+
response_json,
|
|
57
|
+
{
|
|
58
|
+
"publishToInterStateChannel": [],
|
|
59
|
+
"recordEvents": [],
|
|
60
|
+
"stateDecision": {
|
|
61
|
+
"nextStates": [
|
|
62
|
+
{
|
|
63
|
+
"stateId": "_SYS_GRACEFUL_COMPLETING_WORKFLOW",
|
|
64
|
+
"stateInput": {
|
|
65
|
+
"data": '"success"',
|
|
66
|
+
"encoding": "json/plain",
|
|
67
|
+
},
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
},
|
|
71
|
+
"upsertDataObjects": [],
|
|
72
|
+
"upsertStateLocals": [],
|
|
73
|
+
},
|
|
74
|
+
)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Legacy Materials in this file remain under their original licenses.
|
|
2
|
+
# See LEGACY_NOTICES.md.
|
|
3
|
+
|
|
4
|
+
# Modifications Copyright (c) 2026 Super Durable, Inc.
|
|
5
|
+
#
|
|
6
|
+
# Modifications after the Legacy Cutoff are licensed under the
|
|
7
|
+
# Super Durable Source License 1.0.
|
|
8
|
+
# Legacy Materials remain under their original licenses.
|
|
9
|
+
# See LICENSE and LEGACY_NOTICES.md.
|
|
10
|
+
|
|
11
|
+
import inspect
|
|
12
|
+
import time
|
|
13
|
+
import unittest
|
|
14
|
+
|
|
15
|
+
from dex.client import Client
|
|
16
|
+
from dex.tests.worker_server import registry
|
|
17
|
+
from dex.tests.workflows.internal_channel_workflow import InternalChannelWorkflow
|
|
18
|
+
|
|
19
|
+
class TestConditionalComplete(unittest.TestCase):
|
|
20
|
+
@classmethod
|
|
21
|
+
def setUpClass(cls):
|
|
22
|
+
cls.client = Client(registry)
|
|
23
|
+
|
|
24
|
+
def test_internal_channel_workflow(self):
|
|
25
|
+
wf_id = f"{inspect.currentframe().f_code.co_name}-{time.time_ns()}"
|
|
26
|
+
|
|
27
|
+
self.client.start_workflow(InternalChannelWorkflow, wf_id, 100, None)
|
|
28
|
+
self.client.wait_for_workflow_completion(wf_id, None)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Legacy Materials in this file remain under their original licenses.
|
|
2
|
+
# See LEGACY_NOTICES.md.
|
|
3
|
+
|
|
4
|
+
# Modifications Copyright (c) 2026 Super Durable, Inc.
|
|
5
|
+
#
|
|
6
|
+
# Modifications after the Legacy Cutoff are licensed under the
|
|
7
|
+
# Super Durable Source License 1.0.
|
|
8
|
+
# Legacy Materials remain under their original licenses.
|
|
9
|
+
# See LICENSE and LEGACY_NOTICES.md.
|
|
10
|
+
|
|
11
|
+
import inspect
|
|
12
|
+
import time
|
|
13
|
+
import unittest
|
|
14
|
+
|
|
15
|
+
from dex.client import Client
|
|
16
|
+
from dex.tests.worker_server import registry
|
|
17
|
+
from dex.tests.workflows.internal_channel_workflow_with_no_prefix_channel import (
|
|
18
|
+
InternalChannelWorkflowWithNoPrefixChannel,
|
|
19
|
+
test_non_prefix_channel_name_with_suffix,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
class TestInternalChannelWithNoPrefix(unittest.TestCase):
|
|
23
|
+
@classmethod
|
|
24
|
+
def setUpClass(cls):
|
|
25
|
+
cls.client = Client(registry)
|
|
26
|
+
|
|
27
|
+
def test_internal_channel_workflow_with_no_prefix_channel(self):
|
|
28
|
+
wf_id = f"{inspect.currentframe().f_code.co_name}-{time.time_ns()}"
|
|
29
|
+
|
|
30
|
+
self.client.start_workflow(
|
|
31
|
+
InternalChannelWorkflowWithNoPrefixChannel, wf_id, 5, None
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
with self.assertRaises(Exception) as context:
|
|
35
|
+
self.client.wait_for_workflow_completion(wf_id, None)
|
|
36
|
+
|
|
37
|
+
self.assertIn("FAILED", context.exception.workflow_status)
|
|
38
|
+
self.assertIn(
|
|
39
|
+
f"WorkerExecutionError: InternalChannel channel_name is not defined {test_non_prefix_channel_name_with_suffix}",
|
|
40
|
+
context.exception.error_message,
|
|
41
|
+
)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Legacy Materials in this file remain under their original licenses.
|
|
2
|
+
# See LEGACY_NOTICES.md.
|
|
3
|
+
|
|
4
|
+
# Modifications Copyright (c) 2026 Super Durable, Inc.
|
|
5
|
+
#
|
|
6
|
+
# Modifications after the Legacy Cutoff are licensed under the
|
|
7
|
+
# Super Durable Source License 1.0.
|
|
8
|
+
# Legacy Materials remain under their original licenses.
|
|
9
|
+
# See LICENSE and LEGACY_NOTICES.md.
|
|
10
|
+
|
|
11
|
+
import inspect
|
|
12
|
+
import time
|
|
13
|
+
import unittest
|
|
14
|
+
|
|
15
|
+
from dex.client import Client
|
|
16
|
+
from dex.tests.worker_server import registry
|
|
17
|
+
from dex.tests.workflows.persistence_data_attributes_workflow import (
|
|
18
|
+
PersistenceDataAttributesWorkflow,
|
|
19
|
+
initial_da_1,
|
|
20
|
+
initial_da_2,
|
|
21
|
+
initial_da_value_2,
|
|
22
|
+
initial_da_value_1,
|
|
23
|
+
test_da_set_key,
|
|
24
|
+
test_da_set_value,
|
|
25
|
+
expected_final_das,
|
|
26
|
+
)
|
|
27
|
+
from dex.workflow_options import WorkflowOptions
|
|
28
|
+
|
|
29
|
+
class TestPersistenceDataAttributes(unittest.TestCase):
|
|
30
|
+
@classmethod
|
|
31
|
+
def setUpClass(cls):
|
|
32
|
+
cls.client = Client(registry)
|
|
33
|
+
|
|
34
|
+
def test_persistence_data_attributes_workflow(self):
|
|
35
|
+
wf_id = f"{inspect.currentframe().f_code.co_name}-{time.time_ns()}"
|
|
36
|
+
|
|
37
|
+
start_options = WorkflowOptions(
|
|
38
|
+
initial_data_attributes={
|
|
39
|
+
initial_da_1: initial_da_value_1,
|
|
40
|
+
initial_da_2: initial_da_value_2,
|
|
41
|
+
},
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
wf_run_id = self.client.start_workflow(
|
|
45
|
+
PersistenceDataAttributesWorkflow, wf_id, 100, None, start_options
|
|
46
|
+
)
|
|
47
|
+
self.client.set_workflow_data_attributes(
|
|
48
|
+
PersistenceDataAttributesWorkflow,
|
|
49
|
+
wf_id,
|
|
50
|
+
wf_run_id,
|
|
51
|
+
{
|
|
52
|
+
test_da_set_key: test_da_set_value,
|
|
53
|
+
},
|
|
54
|
+
)
|
|
55
|
+
self.client.wait_for_workflow_completion(wf_id, None)
|
|
56
|
+
|
|
57
|
+
all_data_attributes = self.client.get_all_workflow_data_attributes(
|
|
58
|
+
PersistenceDataAttributesWorkflow, wf_id, wf_run_id
|
|
59
|
+
)
|
|
60
|
+
for k, v in expected_final_das.items():
|
|
61
|
+
assert k in all_data_attributes
|
|
62
|
+
assert all_data_attributes[k] == v
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Legacy Materials in this file remain under their original licenses.
|
|
2
|
+
# See LEGACY_NOTICES.md.
|
|
3
|
+
|
|
4
|
+
# Modifications Copyright (c) 2026 Super Durable, Inc.
|
|
5
|
+
#
|
|
6
|
+
# Modifications after the Legacy Cutoff are licensed under the
|
|
7
|
+
# Super Durable Source License 1.0.
|
|
8
|
+
# Legacy Materials remain under their original licenses.
|
|
9
|
+
# See LICENSE and LEGACY_NOTICES.md.
|
|
10
|
+
|
|
11
|
+
import inspect
|
|
12
|
+
import time
|
|
13
|
+
import unittest
|
|
14
|
+
|
|
15
|
+
from dex.client import Client
|
|
16
|
+
from dex.tests.worker_server import registry
|
|
17
|
+
from dex.tests.workflows.persistence_search_attributes_workflow import (
|
|
18
|
+
PersistenceSearchAttributesWorkflow,
|
|
19
|
+
sa_keyword_key,
|
|
20
|
+
sa_double_key,
|
|
21
|
+
sa_int_key,
|
|
22
|
+
sa_bool_key,
|
|
23
|
+
sa_datetime_key,
|
|
24
|
+
sa_keyword_array_key,
|
|
25
|
+
initial_sa_keyword,
|
|
26
|
+
initial_sa_double,
|
|
27
|
+
initial_sa_int,
|
|
28
|
+
initial_sa_bool,
|
|
29
|
+
initial_sa_datetime,
|
|
30
|
+
initial_sa_keyword_array,
|
|
31
|
+
SearchAttributeState1,
|
|
32
|
+
sa_keyword,
|
|
33
|
+
sa_double,
|
|
34
|
+
sa_bool,
|
|
35
|
+
sa_keyword_array,
|
|
36
|
+
sa_int,
|
|
37
|
+
final_sa_keyword,
|
|
38
|
+
final_sa_bool,
|
|
39
|
+
final_sa_int,
|
|
40
|
+
final_sa_keyword_array,
|
|
41
|
+
)
|
|
42
|
+
from dex.workflow_options import WorkflowOptions
|
|
43
|
+
|
|
44
|
+
class TestPersistenceSearchAttributes(unittest.TestCase):
|
|
45
|
+
@classmethod
|
|
46
|
+
def setUpClass(cls):
|
|
47
|
+
cls.client = Client(registry)
|
|
48
|
+
|
|
49
|
+
def test_persistence_search_attributes_workflow(self):
|
|
50
|
+
wf_id = f"{inspect.currentframe().f_code.co_name}-{time.time_ns()}"
|
|
51
|
+
|
|
52
|
+
wf_opts = WorkflowOptions(
|
|
53
|
+
initial_search_attributes={
|
|
54
|
+
sa_keyword_key: initial_sa_keyword,
|
|
55
|
+
sa_double_key: initial_sa_double,
|
|
56
|
+
sa_int_key: initial_sa_int,
|
|
57
|
+
sa_bool_key: initial_sa_bool,
|
|
58
|
+
sa_datetime_key: initial_sa_datetime,
|
|
59
|
+
sa_keyword_array_key: initial_sa_keyword_array,
|
|
60
|
+
}
|
|
61
|
+
)
|
|
62
|
+
wf_opts.add_wait_for_completion_state_ids(SearchAttributeState1)
|
|
63
|
+
self.client.start_workflow(
|
|
64
|
+
PersistenceSearchAttributesWorkflow, wf_id, 100, None, wf_opts
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
initial_returned_search_attributes = self.client.get_all_search_attributes(
|
|
68
|
+
PersistenceSearchAttributesWorkflow,
|
|
69
|
+
wf_id,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
initial_expected_search_attributes = dict()
|
|
73
|
+
initial_expected_search_attributes[sa_keyword_key] = initial_sa_keyword
|
|
74
|
+
initial_expected_search_attributes[sa_double_key] = initial_sa_double
|
|
75
|
+
initial_expected_search_attributes[sa_bool_key] = initial_sa_bool
|
|
76
|
+
initial_expected_search_attributes[sa_keyword_array_key] = (
|
|
77
|
+
initial_sa_keyword_array
|
|
78
|
+
)
|
|
79
|
+
initial_expected_search_attributes[sa_int_key] = initial_sa_int
|
|
80
|
+
initial_expected_search_attributes[sa_datetime_key] = (
|
|
81
|
+
"2024-11-10T00:00:01.731455544Z" # This is a bug. The dex-server always returns utc time. See https://github.com/superdurable/dex/issues/261
|
|
82
|
+
# "2024-11-09T18:00:01.731455544-06:00"
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
assert initial_expected_search_attributes == initial_returned_search_attributes
|
|
86
|
+
|
|
87
|
+
self.client.wait_for_state_execution_completion_with_state_execution_id(
|
|
88
|
+
SearchAttributeState1, wf_id
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
returned_search_attributes = self.client.get_all_search_attributes(
|
|
92
|
+
PersistenceSearchAttributesWorkflow,
|
|
93
|
+
wf_id,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
expected_search_attributes = dict()
|
|
97
|
+
expected_search_attributes[sa_keyword_key] = sa_keyword
|
|
98
|
+
expected_search_attributes[sa_double_key] = sa_double
|
|
99
|
+
expected_search_attributes[sa_bool_key] = sa_bool
|
|
100
|
+
expected_search_attributes[sa_keyword_array_key] = sa_keyword_array
|
|
101
|
+
expected_search_attributes[sa_int_key] = sa_int
|
|
102
|
+
expected_search_attributes[sa_datetime_key] = (
|
|
103
|
+
"2024-11-13T00:00:01.731455544Z" # This is a bug. The dex-server always returns utc time. See https://github.com/superdurable/dex/issues/261
|
|
104
|
+
# "2024-11-12T18:00:01.731455544-06:00"
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
assert expected_search_attributes == returned_search_attributes
|
|
108
|
+
|
|
109
|
+
self.client.wait_for_workflow_completion(wf_id)
|
|
110
|
+
|
|
111
|
+
final_expected_search_attributes = dict()
|
|
112
|
+
final_expected_search_attributes[sa_keyword_key] = final_sa_keyword
|
|
113
|
+
final_expected_search_attributes[sa_double_key] = sa_double
|
|
114
|
+
final_expected_search_attributes[sa_int_key] = final_sa_int
|
|
115
|
+
final_expected_search_attributes[sa_bool_key] = final_sa_bool
|
|
116
|
+
final_expected_search_attributes[sa_keyword_array_key] = final_sa_keyword_array
|
|
117
|
+
final_expected_search_attributes[sa_datetime_key] = (
|
|
118
|
+
"2024-12-14T00:00:01.731455544Z" # This is a bug. The dex-server always returns utc time. See https://github.com/superdurable/dex/issues/261
|
|
119
|
+
# "2024-12-13T18:00:01.731455544-06:00"
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
final_returned_search_attributes = self.client.get_all_search_attributes(
|
|
123
|
+
PersistenceSearchAttributesWorkflow,
|
|
124
|
+
wf_id,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
assert final_expected_search_attributes == final_returned_search_attributes
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Legacy Materials in this file remain under their original licenses.
|
|
2
|
+
# See LEGACY_NOTICES.md.
|
|
3
|
+
|
|
4
|
+
# Modifications Copyright (c) 2026 Super Durable, Inc.
|
|
5
|
+
#
|
|
6
|
+
# Modifications after the Legacy Cutoff are licensed under the
|
|
7
|
+
# Super Durable Source License 1.0.
|
|
8
|
+
# Legacy Materials remain under their original licenses.
|
|
9
|
+
# See LICENSE and LEGACY_NOTICES.md.
|
|
10
|
+
|
|
11
|
+
import inspect
|
|
12
|
+
import time
|
|
13
|
+
import unittest
|
|
14
|
+
|
|
15
|
+
from dex.client import Client
|
|
16
|
+
from dex.tests.worker_server import registry
|
|
17
|
+
from dex.tests.workflows.persistence_state_execution_local_workflow import (
|
|
18
|
+
PersistenceStateExecutionLocalWorkflow,
|
|
19
|
+
PERSISTENCE_LOCAL_VALUE,
|
|
20
|
+
)
|
|
21
|
+
from dex.workflow_options import WorkflowOptions
|
|
22
|
+
|
|
23
|
+
class TestPersistenceExecutionLocalRead(unittest.TestCase):
|
|
24
|
+
@classmethod
|
|
25
|
+
def setUpClass(cls):
|
|
26
|
+
cls.client = Client(registry)
|
|
27
|
+
|
|
28
|
+
def test_persistence_execution_local_workflow(self):
|
|
29
|
+
wf_id = f"{inspect.currentframe().f_code.co_name}-{time.time_ns()}"
|
|
30
|
+
start_options = WorkflowOptions()
|
|
31
|
+
self.client.start_workflow(
|
|
32
|
+
PersistenceStateExecutionLocalWorkflow, wf_id, 200, None, start_options
|
|
33
|
+
)
|
|
34
|
+
self.client.wait_for_workflow_completion(wf_id, None)
|
|
35
|
+
res = self.client.invoke_rpc(
|
|
36
|
+
wf_id, PersistenceStateExecutionLocalWorkflow.test_persistence_read
|
|
37
|
+
)
|
|
38
|
+
assert res == PERSISTENCE_LOCAL_VALUE
|
dex/tests/test_rpc.py
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Legacy Materials in this file remain under their original licenses.
|
|
2
|
+
# See LEGACY_NOTICES.md.
|
|
3
|
+
|
|
4
|
+
# Modifications Copyright (c) 2026 Super Durable, Inc.
|
|
5
|
+
#
|
|
6
|
+
# Modifications after the Legacy Cutoff are licensed under the
|
|
7
|
+
# Super Durable Source License 1.0.
|
|
8
|
+
# Legacy Materials remain under their original licenses.
|
|
9
|
+
# See LICENSE and LEGACY_NOTICES.md.
|
|
10
|
+
|
|
11
|
+
import inspect
|
|
12
|
+
import time
|
|
13
|
+
import unittest
|
|
14
|
+
|
|
15
|
+
from dex.client import Client
|
|
16
|
+
from dex.tests.worker_server import registry
|
|
17
|
+
from dex.tests.workflows.rpc_workflow import RPCWorkflow, Mydata
|
|
18
|
+
|
|
19
|
+
class TestRPCs(unittest.TestCase):
|
|
20
|
+
@classmethod
|
|
21
|
+
def setUpClass(cls):
|
|
22
|
+
cls.client = Client(registry)
|
|
23
|
+
|
|
24
|
+
def test_simple_rpc(self):
|
|
25
|
+
wf_id = f"{inspect.currentframe().f_code.co_name}-{time.time_ns()}"
|
|
26
|
+
self.client.start_workflow(RPCWorkflow, wf_id, 10)
|
|
27
|
+
|
|
28
|
+
input = Mydata("test", 100)
|
|
29
|
+
output = self.client.invoke_rpc(
|
|
30
|
+
wf_id, RPCWorkflow.test_rpc_input_type, input, Mydata
|
|
31
|
+
)
|
|
32
|
+
assert output == input
|
|
33
|
+
|
|
34
|
+
output = self.client.invoke_rpc(wf_id, RPCWorkflow.test_simple_rpc)
|
|
35
|
+
assert output == 123
|
|
36
|
+
wf = RPCWorkflow()
|
|
37
|
+
output = self.client.invoke_rpc(wf_id, wf.test_simple_rpc)
|
|
38
|
+
assert output == 123
|
|
39
|
+
|
|
40
|
+
def test_complicated_rpc(self):
|
|
41
|
+
wf_id = f"{inspect.currentframe().f_code.co_name}-{time.time_ns()}"
|
|
42
|
+
self.client.start_workflow(RPCWorkflow, wf_id, 10)
|
|
43
|
+
self.client.invoke_rpc(wf_id, RPCWorkflow.test_rpc_persistence_write, 100)
|
|
44
|
+
res = self.client.invoke_rpc(wf_id, RPCWorkflow.test_rpc_persistence_read)
|
|
45
|
+
assert res == 100
|
|
46
|
+
self.client.invoke_rpc(wf_id, RPCWorkflow.test_rpc_trigger_state, 200)
|
|
47
|
+
res = self.client.invoke_rpc(wf_id, RPCWorkflow.test_rpc_persistence_read)
|
|
48
|
+
assert res == 200
|
|
49
|
+
|
|
50
|
+
res1 = self.client.invoke_rpc(
|
|
51
|
+
wf_id, RPCWorkflow.test_rpc_publish_to_idle_channel, "input-1"
|
|
52
|
+
)
|
|
53
|
+
# Channel Size should be 1
|
|
54
|
+
assert res1 == 1
|
|
55
|
+
|
|
56
|
+
res2 = self.client.invoke_rpc(
|
|
57
|
+
wf_id, RPCWorkflow.test_rpc_publish_to_idle_channel, "input-2"
|
|
58
|
+
)
|
|
59
|
+
# Channel Size should be 2
|
|
60
|
+
assert res2 == 2
|
|
61
|
+
|
|
62
|
+
self.client.invoke_rpc(wf_id, RPCWorkflow.test_rpc_publish_channel)
|
|
63
|
+
result = self.client.wait_for_workflow_completion(wf_id, str)
|
|
64
|
+
assert result == "done"
|