dex-python-sdk 0.0.1__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.
- dex/__init__.py +14 -0
- dex/client.py +568 -0
- dex/client_options.py +34 -0
- dex/command_request.py +130 -0
- dex/command_results.py +116 -0
- dex/communication.py +141 -0
- dex/communication_schema.py +68 -0
- dex/data_attributes.py +75 -0
- dex/dexpb/__init__.py +1 -0
- dex/dexpb/dex_pb2.py +305 -0
- dex/dexpb/dex_pb2.pyi +1273 -0
- dex/dexpb/dex_pb2_grpc.py +1126 -0
- dex/errors.py +132 -0
- dex/object_encoder.py +818 -0
- dex/persistence.py +94 -0
- dex/persistence_options.py +24 -0
- dex/persistence_schema.py +58 -0
- dex/py.typed +1 -0
- dex/registry.py +209 -0
- dex/reset_workflow_type_and_options.py +77 -0
- dex/rpc.py +100 -0
- dex/search_attributes.py +189 -0
- dex/state_decision.py +161 -0
- dex/state_execution_locals.py +71 -0
- dex/state_movement.py +123 -0
- dex/state_schema.py +54 -0
- dex/stop_workflow_options.py +23 -0
- dex/tests/__init__.py +84 -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 +87 -0
- dex/tests/dex-service-env/dynamicconfig/README.md +39 -0
- dex/tests/dex-service-env/dynamicconfig/development-sql.yaml +6 -0
- dex/tests/dex-service-env/dynamicconfig/docker.yaml +0 -0
- dex/tests/test_abnormal_exit_workflow.py +48 -0
- dex/tests/test_basic_workflow.py +75 -0
- dex/tests/test_conditional_complete.py +56 -0
- dex/tests/test_describe_workflow.py +45 -0
- dex/tests/test_empty_data_decodes_properly.py +79 -0
- dex/tests/test_internal_channel.py +33 -0
- dex/tests/test_internal_channel_with_no_prefix_channel.py +46 -0
- dex/tests/test_persistence_data_attributes.py +67 -0
- dex/tests/test_persistence_search_attributes.py +132 -0
- dex/tests/test_persistence_state_execution_locals.py +43 -0
- dex/tests/test_rpc.py +69 -0
- dex/tests/test_rpc_with_memo.py +200 -0
- dex/tests/test_rpc_with_memo_duplicate_java_tests.py +122 -0
- dex/tests/test_signal.py +56 -0
- dex/tests/test_skip_wait_until.py +85 -0
- dex/tests/test_state_failure_recovery.py +33 -0
- dex/tests/test_timer.py +40 -0
- dex/tests/test_wait_for_state_execution_completion.py +58 -0
- dex/tests/test_workflow_errors.py +92 -0
- dex/tests/test_workflow_state_options.py +123 -0
- dex/tests/test_workflow_state_options_override.py +49 -0
- dex/tests/worker_server.py +74 -0
- dex/tests/workflows/abnormal_exit_workflow.py +48 -0
- dex/tests/workflows/basic_workflow.py +69 -0
- dex/tests/workflows/conditional_complete_workflow.py +101 -0
- dex/tests/workflows/describe_workflow.py +52 -0
- dex/tests/workflows/empty_data_workflow.py +51 -0
- dex/tests/workflows/internal_channel_workflow.py +137 -0
- dex/tests/workflows/internal_channel_workflow_with_no_prefix_channel.py +108 -0
- dex/tests/workflows/java_duplicate_rpc_memo_workflow.py +285 -0
- dex/tests/workflows/persistence_data_attributes_workflow.py +104 -0
- dex/tests/workflows/persistence_search_attributes_workflow.py +167 -0
- dex/tests/workflows/persistence_state_execution_local_workflow.py +69 -0
- dex/tests/workflows/recovery_workflow.py +90 -0
- dex/tests/workflows/rpc_memo_workflow.py +238 -0
- dex/tests/workflows/rpc_workflow.py +125 -0
- dex/tests/workflows/state_options_override_workflow.py +100 -0
- dex/tests/workflows/state_options_workflow.py +92 -0
- dex/tests/workflows/timer_workflow.py +52 -0
- dex/tests/workflows/wait_for_state_with_state_execution_id_workflow.py +77 -0
- dex/tests/workflows/wait_for_state_with_wait_for_key_workflow.py +78 -0
- dex/tests/workflows/wait_internal_channel_workflow.py +53 -0
- dex/tests/workflows/wait_signal_workflow.py +154 -0
- dex/type_store.py +105 -0
- dex/unregistered_client.py +595 -0
- dex/utils/__init__.py +14 -0
- dex/utils/dex_typing.py +31 -0
- dex/utils/persistence_utils.py +37 -0
- dex/worker_service.py +441 -0
- dex/workflow.py +86 -0
- dex/workflow_context.py +50 -0
- dex/workflow_info.py +21 -0
- dex/workflow_options.py +79 -0
- dex/workflow_state.py +134 -0
- dex/workflow_state_options.py +160 -0
- dex_python_sdk-0.0.1.dist-info/METADATA +140 -0
- dex_python_sdk-0.0.1.dist-info/RECORD +93 -0
- dex_python_sdk-0.0.1.dist-info/WHEEL +4 -0
- dex_python_sdk-0.0.1.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Copyright (c) 2022-2026 Super Durable, Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import inspect
|
|
16
|
+
import time
|
|
17
|
+
import unittest
|
|
18
|
+
|
|
19
|
+
from dex.client import Client
|
|
20
|
+
from dex.tests.worker_server import registry
|
|
21
|
+
from dex.tests.workflows.persistence_data_attributes_workflow import (
|
|
22
|
+
PersistenceDataAttributesWorkflow,
|
|
23
|
+
initial_da_1,
|
|
24
|
+
initial_da_2,
|
|
25
|
+
initial_da_value_2,
|
|
26
|
+
initial_da_value_1,
|
|
27
|
+
test_da_set_key,
|
|
28
|
+
test_da_set_value,
|
|
29
|
+
expected_final_das,
|
|
30
|
+
)
|
|
31
|
+
from dex.workflow_options import WorkflowOptions
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class TestPersistenceDataAttributes(unittest.TestCase):
|
|
35
|
+
@classmethod
|
|
36
|
+
def setUpClass(cls):
|
|
37
|
+
cls.client = Client(registry)
|
|
38
|
+
|
|
39
|
+
def test_persistence_data_attributes_workflow(self):
|
|
40
|
+
wf_id = f"{inspect.currentframe().f_code.co_name}-{time.time_ns()}"
|
|
41
|
+
|
|
42
|
+
start_options = WorkflowOptions(
|
|
43
|
+
initial_data_attributes={
|
|
44
|
+
initial_da_1: initial_da_value_1,
|
|
45
|
+
initial_da_2: initial_da_value_2,
|
|
46
|
+
},
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
wf_run_id = self.client.start_workflow(
|
|
50
|
+
PersistenceDataAttributesWorkflow, wf_id, 100, None, start_options
|
|
51
|
+
)
|
|
52
|
+
self.client.set_workflow_data_attributes(
|
|
53
|
+
PersistenceDataAttributesWorkflow,
|
|
54
|
+
wf_id,
|
|
55
|
+
wf_run_id,
|
|
56
|
+
{
|
|
57
|
+
test_da_set_key: test_da_set_value,
|
|
58
|
+
},
|
|
59
|
+
)
|
|
60
|
+
self.client.wait_for_workflow_completion(wf_id, None)
|
|
61
|
+
|
|
62
|
+
all_data_attributes = self.client.get_all_workflow_data_attributes(
|
|
63
|
+
PersistenceDataAttributesWorkflow, wf_id, wf_run_id
|
|
64
|
+
)
|
|
65
|
+
for k, v in expected_final_das.items():
|
|
66
|
+
assert k in all_data_attributes
|
|
67
|
+
assert all_data_attributes[k] == v
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Copyright (c) 2022-2026 Super Durable, Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import inspect
|
|
16
|
+
import time
|
|
17
|
+
import unittest
|
|
18
|
+
|
|
19
|
+
from dex.client import Client
|
|
20
|
+
from dex.tests.worker_server import registry
|
|
21
|
+
from dex.tests.workflows.persistence_search_attributes_workflow import (
|
|
22
|
+
PersistenceSearchAttributesWorkflow,
|
|
23
|
+
sa_keyword_key,
|
|
24
|
+
sa_double_key,
|
|
25
|
+
sa_int_key,
|
|
26
|
+
sa_bool_key,
|
|
27
|
+
sa_datetime_key,
|
|
28
|
+
sa_keyword_array_key,
|
|
29
|
+
initial_sa_keyword,
|
|
30
|
+
initial_sa_double,
|
|
31
|
+
initial_sa_int,
|
|
32
|
+
initial_sa_bool,
|
|
33
|
+
initial_sa_datetime,
|
|
34
|
+
initial_sa_keyword_array,
|
|
35
|
+
SearchAttributeState1,
|
|
36
|
+
sa_keyword,
|
|
37
|
+
sa_double,
|
|
38
|
+
sa_bool,
|
|
39
|
+
sa_keyword_array,
|
|
40
|
+
sa_int,
|
|
41
|
+
final_sa_keyword,
|
|
42
|
+
final_sa_bool,
|
|
43
|
+
final_sa_int,
|
|
44
|
+
final_sa_keyword_array,
|
|
45
|
+
)
|
|
46
|
+
from dex.workflow_options import WorkflowOptions
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class TestPersistenceSearchAttributes(unittest.TestCase):
|
|
50
|
+
@classmethod
|
|
51
|
+
def setUpClass(cls):
|
|
52
|
+
cls.client = Client(registry)
|
|
53
|
+
|
|
54
|
+
def test_persistence_search_attributes_workflow(self):
|
|
55
|
+
wf_id = f"{inspect.currentframe().f_code.co_name}-{time.time_ns()}"
|
|
56
|
+
|
|
57
|
+
wf_opts = WorkflowOptions(
|
|
58
|
+
initial_search_attributes={
|
|
59
|
+
sa_keyword_key: initial_sa_keyword,
|
|
60
|
+
sa_double_key: initial_sa_double,
|
|
61
|
+
sa_int_key: initial_sa_int,
|
|
62
|
+
sa_bool_key: initial_sa_bool,
|
|
63
|
+
sa_datetime_key: initial_sa_datetime,
|
|
64
|
+
sa_keyword_array_key: initial_sa_keyword_array,
|
|
65
|
+
}
|
|
66
|
+
)
|
|
67
|
+
wf_opts.add_wait_for_completion_state_ids(SearchAttributeState1)
|
|
68
|
+
self.client.start_workflow(
|
|
69
|
+
PersistenceSearchAttributesWorkflow, wf_id, 100, None, wf_opts
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
initial_returned_search_attributes = self.client.get_all_search_attributes(
|
|
73
|
+
PersistenceSearchAttributesWorkflow,
|
|
74
|
+
wf_id,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
initial_expected_search_attributes = dict()
|
|
78
|
+
initial_expected_search_attributes[sa_keyword_key] = initial_sa_keyword
|
|
79
|
+
initial_expected_search_attributes[sa_double_key] = initial_sa_double
|
|
80
|
+
initial_expected_search_attributes[sa_bool_key] = initial_sa_bool
|
|
81
|
+
initial_expected_search_attributes[sa_keyword_array_key] = (
|
|
82
|
+
initial_sa_keyword_array
|
|
83
|
+
)
|
|
84
|
+
initial_expected_search_attributes[sa_int_key] = initial_sa_int
|
|
85
|
+
initial_expected_search_attributes[sa_datetime_key] = (
|
|
86
|
+
"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
|
|
87
|
+
# "2024-11-09T18:00:01.731455544-06:00"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
assert initial_expected_search_attributes == initial_returned_search_attributes
|
|
91
|
+
|
|
92
|
+
self.client.wait_for_state_execution_completion_with_state_execution_id(
|
|
93
|
+
SearchAttributeState1, wf_id
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
returned_search_attributes = self.client.get_all_search_attributes(
|
|
97
|
+
PersistenceSearchAttributesWorkflow,
|
|
98
|
+
wf_id,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
expected_search_attributes = dict()
|
|
102
|
+
expected_search_attributes[sa_keyword_key] = sa_keyword
|
|
103
|
+
expected_search_attributes[sa_double_key] = sa_double
|
|
104
|
+
expected_search_attributes[sa_bool_key] = sa_bool
|
|
105
|
+
expected_search_attributes[sa_keyword_array_key] = sa_keyword_array
|
|
106
|
+
expected_search_attributes[sa_int_key] = sa_int
|
|
107
|
+
expected_search_attributes[sa_datetime_key] = (
|
|
108
|
+
"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
|
|
109
|
+
# "2024-11-12T18:00:01.731455544-06:00"
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
assert expected_search_attributes == returned_search_attributes
|
|
113
|
+
|
|
114
|
+
self.client.wait_for_workflow_completion(wf_id)
|
|
115
|
+
|
|
116
|
+
final_expected_search_attributes = dict()
|
|
117
|
+
final_expected_search_attributes[sa_keyword_key] = final_sa_keyword
|
|
118
|
+
final_expected_search_attributes[sa_double_key] = sa_double
|
|
119
|
+
final_expected_search_attributes[sa_int_key] = final_sa_int
|
|
120
|
+
final_expected_search_attributes[sa_bool_key] = final_sa_bool
|
|
121
|
+
final_expected_search_attributes[sa_keyword_array_key] = final_sa_keyword_array
|
|
122
|
+
final_expected_search_attributes[sa_datetime_key] = (
|
|
123
|
+
"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
|
|
124
|
+
# "2024-12-13T18:00:01.731455544-06:00"
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
final_returned_search_attributes = self.client.get_all_search_attributes(
|
|
128
|
+
PersistenceSearchAttributesWorkflow,
|
|
129
|
+
wf_id,
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
assert final_expected_search_attributes == final_returned_search_attributes
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Copyright (c) 2022-2026 Super Durable, Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import inspect
|
|
16
|
+
import time
|
|
17
|
+
import unittest
|
|
18
|
+
|
|
19
|
+
from dex.client import Client
|
|
20
|
+
from dex.tests.worker_server import registry
|
|
21
|
+
from dex.tests.workflows.persistence_state_execution_local_workflow import (
|
|
22
|
+
PersistenceStateExecutionLocalWorkflow,
|
|
23
|
+
PERSISTENCE_LOCAL_VALUE,
|
|
24
|
+
)
|
|
25
|
+
from dex.workflow_options import WorkflowOptions
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class TestPersistenceExecutionLocalRead(unittest.TestCase):
|
|
29
|
+
@classmethod
|
|
30
|
+
def setUpClass(cls):
|
|
31
|
+
cls.client = Client(registry)
|
|
32
|
+
|
|
33
|
+
def test_persistence_execution_local_workflow(self):
|
|
34
|
+
wf_id = f"{inspect.currentframe().f_code.co_name}-{time.time_ns()}"
|
|
35
|
+
start_options = WorkflowOptions()
|
|
36
|
+
self.client.start_workflow(
|
|
37
|
+
PersistenceStateExecutionLocalWorkflow, wf_id, 200, None, start_options
|
|
38
|
+
)
|
|
39
|
+
self.client.wait_for_workflow_completion(wf_id, None)
|
|
40
|
+
res = self.client.invoke_rpc(
|
|
41
|
+
wf_id, PersistenceStateExecutionLocalWorkflow.test_persistence_read
|
|
42
|
+
)
|
|
43
|
+
assert res == PERSISTENCE_LOCAL_VALUE
|
dex/tests/test_rpc.py
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Copyright (c) 2022-2026 Super Durable, Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import inspect
|
|
16
|
+
import time
|
|
17
|
+
import unittest
|
|
18
|
+
|
|
19
|
+
from dex.client import Client
|
|
20
|
+
from dex.tests.worker_server import registry
|
|
21
|
+
from dex.tests.workflows.rpc_workflow import RPCWorkflow, Mydata
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class TestRPCs(unittest.TestCase):
|
|
25
|
+
@classmethod
|
|
26
|
+
def setUpClass(cls):
|
|
27
|
+
cls.client = Client(registry)
|
|
28
|
+
|
|
29
|
+
def test_simple_rpc(self):
|
|
30
|
+
wf_id = f"{inspect.currentframe().f_code.co_name}-{time.time_ns()}"
|
|
31
|
+
self.client.start_workflow(RPCWorkflow, wf_id, 10)
|
|
32
|
+
|
|
33
|
+
input = Mydata("test", 100)
|
|
34
|
+
output = self.client.invoke_rpc(
|
|
35
|
+
wf_id, RPCWorkflow.test_rpc_input_type, input, Mydata
|
|
36
|
+
)
|
|
37
|
+
assert output == input
|
|
38
|
+
|
|
39
|
+
output = self.client.invoke_rpc(wf_id, RPCWorkflow.test_simple_rpc)
|
|
40
|
+
assert output == 123
|
|
41
|
+
wf = RPCWorkflow()
|
|
42
|
+
output = self.client.invoke_rpc(wf_id, wf.test_simple_rpc)
|
|
43
|
+
assert output == 123
|
|
44
|
+
|
|
45
|
+
def test_complicated_rpc(self):
|
|
46
|
+
wf_id = f"{inspect.currentframe().f_code.co_name}-{time.time_ns()}"
|
|
47
|
+
self.client.start_workflow(RPCWorkflow, wf_id, 10)
|
|
48
|
+
self.client.invoke_rpc(wf_id, RPCWorkflow.test_rpc_persistence_write, 100)
|
|
49
|
+
res = self.client.invoke_rpc(wf_id, RPCWorkflow.test_rpc_persistence_read)
|
|
50
|
+
assert res == 100
|
|
51
|
+
self.client.invoke_rpc(wf_id, RPCWorkflow.test_rpc_trigger_state, 200)
|
|
52
|
+
res = self.client.invoke_rpc(wf_id, RPCWorkflow.test_rpc_persistence_read)
|
|
53
|
+
assert res == 200
|
|
54
|
+
|
|
55
|
+
res1 = self.client.invoke_rpc(
|
|
56
|
+
wf_id, RPCWorkflow.test_rpc_publish_to_idle_channel, "input-1"
|
|
57
|
+
)
|
|
58
|
+
# Channel Size should be 1
|
|
59
|
+
assert res1 == 1
|
|
60
|
+
|
|
61
|
+
res2 = self.client.invoke_rpc(
|
|
62
|
+
wf_id, RPCWorkflow.test_rpc_publish_to_idle_channel, "input-2"
|
|
63
|
+
)
|
|
64
|
+
# Channel Size should be 2
|
|
65
|
+
assert res2 == 2
|
|
66
|
+
|
|
67
|
+
self.client.invoke_rpc(wf_id, RPCWorkflow.test_rpc_publish_channel)
|
|
68
|
+
result = self.client.wait_for_workflow_completion(wf_id, str)
|
|
69
|
+
assert result == "done"
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# Copyright (c) 2022-2026 Super Durable, Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import inspect
|
|
16
|
+
import time
|
|
17
|
+
import unittest
|
|
18
|
+
|
|
19
|
+
from dex.client import Client
|
|
20
|
+
from dex.dex_api.models.workflow_stop_type import WorkflowStopType
|
|
21
|
+
from dex.stop_workflow_options import StopWorkflowOptions
|
|
22
|
+
from dex.tests import registry
|
|
23
|
+
from dex.tests.workflows.rpc_memo_workflow import (
|
|
24
|
+
RpcMemoWorkflow,
|
|
25
|
+
TEST_DATA_OBJECT_KEY,
|
|
26
|
+
TEST_SEARCH_ATTRIBUTE_INT,
|
|
27
|
+
TEST_SEARCH_ATTRIBUTE_KEY,
|
|
28
|
+
RPC_INPUT,
|
|
29
|
+
RPC_OUTPUT,
|
|
30
|
+
TEST_STR,
|
|
31
|
+
TEST_DELAY,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class TestRpcWithMemo(unittest.TestCase):
|
|
36
|
+
@classmethod
|
|
37
|
+
def setUpClass(cls):
|
|
38
|
+
cls.client = Client(registry)
|
|
39
|
+
|
|
40
|
+
def test_rpc_memo_workflow_func1(self):
|
|
41
|
+
wf_id = f"{inspect.currentframe().f_code.co_name}-{time.time_ns()}"
|
|
42
|
+
run_id = self.client.start_workflow(RpcMemoWorkflow, wf_id, 30, 999)
|
|
43
|
+
|
|
44
|
+
self.client.invoke_rpc(
|
|
45
|
+
wf_id, RpcMemoWorkflow.test_rpc_set_data_attribute, TEST_STR
|
|
46
|
+
)
|
|
47
|
+
value = self.client.invoke_rpc(
|
|
48
|
+
wf_id, RpcMemoWorkflow.test_rpc_get_data_attribute_strong_consistency
|
|
49
|
+
)
|
|
50
|
+
assert value == TEST_STR
|
|
51
|
+
time.sleep(TEST_DELAY)
|
|
52
|
+
value = self.client.invoke_rpc(
|
|
53
|
+
wf_id, RpcMemoWorkflow.test_rpc_get_data_attribute, None, str
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
self.client.invoke_rpc(wf_id, RpcMemoWorkflow.test_rpc_set_data_attribute, None)
|
|
57
|
+
value = self.client.invoke_rpc(
|
|
58
|
+
wf_id, RpcMemoWorkflow.test_rpc_get_data_attribute_strong_consistency
|
|
59
|
+
)
|
|
60
|
+
assert value is None
|
|
61
|
+
time.sleep(TEST_DELAY)
|
|
62
|
+
value = self.client.invoke_rpc(
|
|
63
|
+
wf_id, RpcMemoWorkflow.test_rpc_get_data_attribute
|
|
64
|
+
)
|
|
65
|
+
assert value is None
|
|
66
|
+
|
|
67
|
+
self.client.invoke_rpc(wf_id, RpcMemoWorkflow.test_rpc_set_keyword, TEST_STR)
|
|
68
|
+
value = self.client.invoke_rpc(
|
|
69
|
+
wf_id, RpcMemoWorkflow.test_rpc_get_keyword_strong_consistency
|
|
70
|
+
)
|
|
71
|
+
assert value == TEST_STR
|
|
72
|
+
time.sleep(TEST_DELAY)
|
|
73
|
+
value = self.client.invoke_rpc(wf_id, RpcMemoWorkflow.test_rpc_get_keyword)
|
|
74
|
+
assert value == TEST_STR
|
|
75
|
+
|
|
76
|
+
self.client.invoke_rpc(wf_id, RpcMemoWorkflow.test_rpc_set_keyword, None)
|
|
77
|
+
value = self.client.invoke_rpc(
|
|
78
|
+
wf_id, RpcMemoWorkflow.test_rpc_get_keyword_strong_consistency
|
|
79
|
+
)
|
|
80
|
+
assert value is None
|
|
81
|
+
time.sleep(TEST_DELAY)
|
|
82
|
+
value = self.client.invoke_rpc(wf_id, RpcMemoWorkflow.test_rpc_get_keyword)
|
|
83
|
+
assert value is None
|
|
84
|
+
|
|
85
|
+
rpc_output = self.client.invoke_rpc(
|
|
86
|
+
wf_id, RpcMemoWorkflow.test_rpc_func1, RPC_INPUT
|
|
87
|
+
)
|
|
88
|
+
assert RPC_OUTPUT == rpc_output
|
|
89
|
+
|
|
90
|
+
self.client.wait_for_workflow_completion(wf_id)
|
|
91
|
+
|
|
92
|
+
data_attributes = self.client.get_workflow_data_attributes(
|
|
93
|
+
RpcMemoWorkflow, wf_id, run_id, [TEST_DATA_OBJECT_KEY]
|
|
94
|
+
)
|
|
95
|
+
assert TEST_DATA_OBJECT_KEY in data_attributes
|
|
96
|
+
assert data_attributes[TEST_DATA_OBJECT_KEY] == RPC_INPUT
|
|
97
|
+
|
|
98
|
+
search_attributes = self.client.get_workflow_search_attributes(
|
|
99
|
+
RpcMemoWorkflow,
|
|
100
|
+
wf_id,
|
|
101
|
+
[TEST_SEARCH_ATTRIBUTE_KEY, TEST_SEARCH_ATTRIBUTE_INT],
|
|
102
|
+
run_id,
|
|
103
|
+
)
|
|
104
|
+
assert TEST_SEARCH_ATTRIBUTE_INT in search_attributes
|
|
105
|
+
assert TEST_SEARCH_ATTRIBUTE_KEY in search_attributes
|
|
106
|
+
assert search_attributes[TEST_SEARCH_ATTRIBUTE_INT] == RPC_OUTPUT
|
|
107
|
+
assert search_attributes[TEST_SEARCH_ATTRIBUTE_KEY] == RPC_INPUT
|
|
108
|
+
|
|
109
|
+
def test_rpc_memo_workflow_func0(self):
|
|
110
|
+
wf_id = f"{inspect.currentframe().f_code.co_name}-{time.time_ns()}"
|
|
111
|
+
run_id = self.client.start_workflow(RpcMemoWorkflow, wf_id, 30, 999)
|
|
112
|
+
|
|
113
|
+
rpc_output = self.client.invoke_rpc(
|
|
114
|
+
wf_id, RpcMemoWorkflow.test_rpc_func0, TEST_STR
|
|
115
|
+
)
|
|
116
|
+
assert RPC_OUTPUT == rpc_output
|
|
117
|
+
|
|
118
|
+
self.client.wait_for_workflow_completion(wf_id)
|
|
119
|
+
|
|
120
|
+
data_attributes = self.client.get_workflow_data_attributes(
|
|
121
|
+
RpcMemoWorkflow, wf_id, run_id, [TEST_DATA_OBJECT_KEY]
|
|
122
|
+
)
|
|
123
|
+
assert TEST_DATA_OBJECT_KEY in data_attributes
|
|
124
|
+
assert data_attributes[TEST_DATA_OBJECT_KEY] == TEST_STR
|
|
125
|
+
|
|
126
|
+
search_attributes = self.client.get_workflow_search_attributes(
|
|
127
|
+
RpcMemoWorkflow,
|
|
128
|
+
wf_id,
|
|
129
|
+
[TEST_SEARCH_ATTRIBUTE_KEY, TEST_SEARCH_ATTRIBUTE_INT],
|
|
130
|
+
run_id,
|
|
131
|
+
)
|
|
132
|
+
assert TEST_SEARCH_ATTRIBUTE_INT in search_attributes
|
|
133
|
+
assert TEST_SEARCH_ATTRIBUTE_KEY in search_attributes
|
|
134
|
+
assert search_attributes[TEST_SEARCH_ATTRIBUTE_INT] == RPC_OUTPUT
|
|
135
|
+
assert search_attributes[TEST_SEARCH_ATTRIBUTE_KEY] == TEST_STR
|
|
136
|
+
|
|
137
|
+
def test_rpc_memo_workflow_proc1(self):
|
|
138
|
+
wf_id = f"{inspect.currentframe().f_code.co_name}-{time.time_ns()}"
|
|
139
|
+
run_id = self.client.start_workflow(RpcMemoWorkflow, wf_id, 30, 999)
|
|
140
|
+
|
|
141
|
+
self.client.invoke_rpc(wf_id, RpcMemoWorkflow.test_rpc_proc1, RPC_INPUT)
|
|
142
|
+
self.client.wait_for_workflow_completion(wf_id)
|
|
143
|
+
|
|
144
|
+
data_attributes = self.client.get_workflow_data_attributes(
|
|
145
|
+
RpcMemoWorkflow, wf_id, run_id, [TEST_DATA_OBJECT_KEY]
|
|
146
|
+
)
|
|
147
|
+
assert TEST_DATA_OBJECT_KEY in data_attributes
|
|
148
|
+
assert data_attributes[TEST_DATA_OBJECT_KEY] == RPC_INPUT
|
|
149
|
+
|
|
150
|
+
search_attributes = self.client.get_workflow_search_attributes(
|
|
151
|
+
RpcMemoWorkflow,
|
|
152
|
+
wf_id,
|
|
153
|
+
[TEST_SEARCH_ATTRIBUTE_KEY, TEST_SEARCH_ATTRIBUTE_INT],
|
|
154
|
+
run_id,
|
|
155
|
+
)
|
|
156
|
+
assert TEST_SEARCH_ATTRIBUTE_INT in search_attributes
|
|
157
|
+
assert TEST_SEARCH_ATTRIBUTE_KEY in search_attributes
|
|
158
|
+
assert search_attributes[TEST_SEARCH_ATTRIBUTE_INT] == RPC_OUTPUT
|
|
159
|
+
assert search_attributes[TEST_SEARCH_ATTRIBUTE_KEY] == RPC_INPUT
|
|
160
|
+
|
|
161
|
+
def test_rpc_memo_workflow_proc0(self):
|
|
162
|
+
wf_id = f"{inspect.currentframe().f_code.co_name}-{time.time_ns()}"
|
|
163
|
+
run_id = self.client.start_workflow(RpcMemoWorkflow, wf_id, 30, 999)
|
|
164
|
+
|
|
165
|
+
self.client.invoke_rpc(wf_id, RpcMemoWorkflow.test_rpc_proc0)
|
|
166
|
+
self.client.wait_for_workflow_completion(wf_id)
|
|
167
|
+
|
|
168
|
+
data_attributes = self.client.get_workflow_data_attributes(
|
|
169
|
+
RpcMemoWorkflow, wf_id, run_id, [TEST_DATA_OBJECT_KEY]
|
|
170
|
+
)
|
|
171
|
+
assert TEST_DATA_OBJECT_KEY in data_attributes
|
|
172
|
+
assert data_attributes[TEST_DATA_OBJECT_KEY] == TEST_STR
|
|
173
|
+
|
|
174
|
+
search_attributes = self.client.get_workflow_search_attributes(
|
|
175
|
+
RpcMemoWorkflow,
|
|
176
|
+
wf_id,
|
|
177
|
+
[TEST_SEARCH_ATTRIBUTE_KEY, TEST_SEARCH_ATTRIBUTE_INT],
|
|
178
|
+
run_id,
|
|
179
|
+
)
|
|
180
|
+
assert TEST_SEARCH_ATTRIBUTE_INT in search_attributes
|
|
181
|
+
assert TEST_SEARCH_ATTRIBUTE_KEY in search_attributes
|
|
182
|
+
assert search_attributes[TEST_SEARCH_ATTRIBUTE_INT] == RPC_OUTPUT
|
|
183
|
+
assert search_attributes[TEST_SEARCH_ATTRIBUTE_KEY] == TEST_STR
|
|
184
|
+
|
|
185
|
+
def test_rpc_memo_workflow_func1_readonly(self):
|
|
186
|
+
wf_id = f"{inspect.currentframe().f_code.co_name}-{time.time_ns()}"
|
|
187
|
+
self.client.start_workflow(RpcMemoWorkflow, wf_id, 30, 999)
|
|
188
|
+
|
|
189
|
+
rpc_output = self.client.invoke_rpc(
|
|
190
|
+
wf_id, RpcMemoWorkflow.test_rpc_func1_readonly, RPC_INPUT
|
|
191
|
+
)
|
|
192
|
+
assert RPC_OUTPUT == rpc_output
|
|
193
|
+
|
|
194
|
+
self.client.stop_workflow(
|
|
195
|
+
wf_id,
|
|
196
|
+
StopWorkflowOptions(
|
|
197
|
+
workflow_stop_type=WorkflowStopType.FAIL,
|
|
198
|
+
reason=TEST_STR,
|
|
199
|
+
),
|
|
200
|
+
)
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Copyright (c) 2022-2026 Super Durable, Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import inspect
|
|
16
|
+
import time
|
|
17
|
+
import unittest
|
|
18
|
+
|
|
19
|
+
from dex.client import Client
|
|
20
|
+
from dex.tests.worker_server import registry
|
|
21
|
+
from dex.tests.workflows.java_duplicate_rpc_memo_workflow import (
|
|
22
|
+
JavaDuplicateRpcMemoWorkflow,
|
|
23
|
+
RpcMemoWorkflowState2,
|
|
24
|
+
TEST_DATA_OBJECT_KEY,
|
|
25
|
+
TEST_SEARCH_ATTRIBUTE_INT,
|
|
26
|
+
TEST_SEARCH_ATTRIBUTE_KEY,
|
|
27
|
+
RPC_INPUT,
|
|
28
|
+
RPC_OUTPUT,
|
|
29
|
+
TEST_STR,
|
|
30
|
+
TEST_DELAY,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class TestRpcWithMemo(unittest.TestCase):
|
|
35
|
+
@classmethod
|
|
36
|
+
def setUpClass(cls):
|
|
37
|
+
cls.client = Client(registry)
|
|
38
|
+
|
|
39
|
+
def test_rpc_memo_workflow_func1(self):
|
|
40
|
+
wf_id = f"{inspect.currentframe().f_code.co_name}-{time.time_ns()}"
|
|
41
|
+
run_id = self.client.start_workflow(
|
|
42
|
+
JavaDuplicateRpcMemoWorkflow, wf_id, 30, 999
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
self.client.invoke_rpc(
|
|
46
|
+
wf_id, JavaDuplicateRpcMemoWorkflow.test_rpc_set_data_attribute, TEST_STR
|
|
47
|
+
)
|
|
48
|
+
value = self.client.invoke_rpc(
|
|
49
|
+
wf_id,
|
|
50
|
+
JavaDuplicateRpcMemoWorkflow.test_rpc_get_data_attribute_strong_consistency,
|
|
51
|
+
)
|
|
52
|
+
assert value == TEST_STR
|
|
53
|
+
time.sleep(TEST_DELAY)
|
|
54
|
+
value = self.client.invoke_rpc(
|
|
55
|
+
wf_id, JavaDuplicateRpcMemoWorkflow.test_rpc_get_data_attribute, None, str
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
self.client.invoke_rpc(
|
|
59
|
+
wf_id, JavaDuplicateRpcMemoWorkflow.test_rpc_set_data_attribute, None
|
|
60
|
+
)
|
|
61
|
+
value = self.client.invoke_rpc(
|
|
62
|
+
wf_id,
|
|
63
|
+
JavaDuplicateRpcMemoWorkflow.test_rpc_get_data_attribute_strong_consistency,
|
|
64
|
+
)
|
|
65
|
+
assert value is None
|
|
66
|
+
time.sleep(TEST_DELAY)
|
|
67
|
+
value = self.client.invoke_rpc(
|
|
68
|
+
wf_id, JavaDuplicateRpcMemoWorkflow.test_rpc_get_data_attribute
|
|
69
|
+
)
|
|
70
|
+
assert value is None
|
|
71
|
+
|
|
72
|
+
self.client.invoke_rpc(
|
|
73
|
+
wf_id, JavaDuplicateRpcMemoWorkflow.test_rpc_set_keyword, TEST_STR
|
|
74
|
+
)
|
|
75
|
+
value = self.client.invoke_rpc(
|
|
76
|
+
wf_id, JavaDuplicateRpcMemoWorkflow.test_rpc_get_keyword_strong_consistency
|
|
77
|
+
)
|
|
78
|
+
assert value == TEST_STR
|
|
79
|
+
time.sleep(TEST_DELAY)
|
|
80
|
+
value = self.client.invoke_rpc(
|
|
81
|
+
wf_id, JavaDuplicateRpcMemoWorkflow.test_rpc_get_keyword
|
|
82
|
+
)
|
|
83
|
+
assert value == TEST_STR
|
|
84
|
+
|
|
85
|
+
self.client.invoke_rpc(
|
|
86
|
+
wf_id, JavaDuplicateRpcMemoWorkflow.test_rpc_set_keyword, None
|
|
87
|
+
)
|
|
88
|
+
value = self.client.invoke_rpc(
|
|
89
|
+
wf_id, JavaDuplicateRpcMemoWorkflow.test_rpc_get_keyword_strong_consistency
|
|
90
|
+
)
|
|
91
|
+
assert value is None
|
|
92
|
+
time.sleep(TEST_DELAY)
|
|
93
|
+
value = self.client.invoke_rpc(
|
|
94
|
+
wf_id, JavaDuplicateRpcMemoWorkflow.test_rpc_get_keyword
|
|
95
|
+
)
|
|
96
|
+
assert value is None
|
|
97
|
+
|
|
98
|
+
rpc_output = self.client.invoke_rpc(
|
|
99
|
+
wf_id, JavaDuplicateRpcMemoWorkflow.test_rpc_func1, RPC_INPUT
|
|
100
|
+
)
|
|
101
|
+
assert RPC_OUTPUT == rpc_output
|
|
102
|
+
|
|
103
|
+
output = self.client.wait_for_workflow_completion(wf_id, int)
|
|
104
|
+
RpcMemoWorkflowState2.reset_counter()
|
|
105
|
+
assert 2 == output
|
|
106
|
+
|
|
107
|
+
data_attributes = self.client.get_workflow_data_attributes(
|
|
108
|
+
JavaDuplicateRpcMemoWorkflow, wf_id, run_id, [TEST_DATA_OBJECT_KEY]
|
|
109
|
+
)
|
|
110
|
+
assert TEST_DATA_OBJECT_KEY in data_attributes
|
|
111
|
+
assert data_attributes[TEST_DATA_OBJECT_KEY] == RPC_INPUT
|
|
112
|
+
|
|
113
|
+
search_attributes = self.client.get_workflow_search_attributes(
|
|
114
|
+
JavaDuplicateRpcMemoWorkflow,
|
|
115
|
+
wf_id,
|
|
116
|
+
[TEST_SEARCH_ATTRIBUTE_KEY, TEST_SEARCH_ATTRIBUTE_INT],
|
|
117
|
+
run_id,
|
|
118
|
+
)
|
|
119
|
+
assert TEST_SEARCH_ATTRIBUTE_INT in search_attributes
|
|
120
|
+
assert TEST_SEARCH_ATTRIBUTE_KEY in search_attributes
|
|
121
|
+
assert search_attributes[TEST_SEARCH_ATTRIBUTE_INT] == RPC_OUTPUT
|
|
122
|
+
assert search_attributes[TEST_SEARCH_ATTRIBUTE_KEY] == RPC_INPUT
|
dex/tests/test_signal.py
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Copyright (c) 2022-2026 Super Durable, Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import inspect
|
|
16
|
+
import time
|
|
17
|
+
import unittest
|
|
18
|
+
|
|
19
|
+
from dex.client import Client
|
|
20
|
+
from dex.tests.worker_server import registry
|
|
21
|
+
from dex.tests.workflows.wait_signal_workflow import (
|
|
22
|
+
WaitSignalWorkflow,
|
|
23
|
+
test_channel_int,
|
|
24
|
+
test_channel_str,
|
|
25
|
+
test_channel_none,
|
|
26
|
+
test_channel1,
|
|
27
|
+
test_idle_channel_none,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class TestSignal(unittest.TestCase):
|
|
32
|
+
@classmethod
|
|
33
|
+
def setUpClass(cls):
|
|
34
|
+
cls.client = Client(registry)
|
|
35
|
+
|
|
36
|
+
def test_signal(self):
|
|
37
|
+
wf_id = f"{inspect.currentframe().f_code.co_name}-{time.time_ns()}"
|
|
38
|
+
self.client.start_workflow(WaitSignalWorkflow, wf_id, 10)
|
|
39
|
+
self.client.signal_workflow(wf_id, test_channel_int, 123)
|
|
40
|
+
self.client.signal_workflow(wf_id, test_channel_str, "abc")
|
|
41
|
+
self.client.signal_workflow(wf_id, test_channel_none)
|
|
42
|
+
|
|
43
|
+
self.client.signal_workflow(wf_id, test_channel1)
|
|
44
|
+
res = self.client.wait_for_workflow_completion(wf_id, str)
|
|
45
|
+
assert res == "abc"
|
|
46
|
+
|
|
47
|
+
def test_signal_channel_size(self):
|
|
48
|
+
wf_id = f"{inspect.currentframe().f_code.co_name}-{time.time_ns()}"
|
|
49
|
+
self.client.start_workflow(WaitSignalWorkflow, wf_id, 1)
|
|
50
|
+
self.client.signal_workflow(wf_id, test_idle_channel_none)
|
|
51
|
+
self.client.signal_workflow(wf_id, test_idle_channel_none)
|
|
52
|
+
self.client.signal_workflow(wf_id, test_idle_channel_none)
|
|
53
|
+
res = self.client.invoke_rpc(
|
|
54
|
+
wf_id, WaitSignalWorkflow.get_idle_signal_channel_size
|
|
55
|
+
)
|
|
56
|
+
assert res == 3
|