@temporalio/core-bridge 1.13.0 → 1.13.2

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 (181) hide show
  1. package/Cargo.lock +239 -382
  2. package/Cargo.toml +11 -11
  3. package/lib/native.d.ts +10 -3
  4. package/package.json +3 -3
  5. package/releases/aarch64-apple-darwin/index.node +0 -0
  6. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  7. package/releases/x86_64-apple-darwin/index.node +0 -0
  8. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  9. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  10. package/sdk-core/.cargo/config.toml +71 -11
  11. package/sdk-core/.clippy.toml +1 -0
  12. package/sdk-core/.github/workflows/heavy.yml +2 -0
  13. package/sdk-core/.github/workflows/per-pr.yml +50 -18
  14. package/sdk-core/ARCHITECTURE.md +44 -48
  15. package/sdk-core/Cargo.toml +26 -7
  16. package/sdk-core/README.md +4 -0
  17. package/sdk-core/arch_docs/diagrams/TimerMachine_Coverage.puml +14 -0
  18. package/sdk-core/arch_docs/diagrams/initial_event_history.png +0 -0
  19. package/sdk-core/arch_docs/sdks_intro.md +299 -0
  20. package/sdk-core/client/Cargo.toml +8 -7
  21. package/sdk-core/client/src/callback_based.rs +1 -2
  22. package/sdk-core/client/src/lib.rs +485 -299
  23. package/sdk-core/client/src/metrics.rs +32 -8
  24. package/sdk-core/client/src/proxy.rs +124 -5
  25. package/sdk-core/client/src/raw.rs +598 -307
  26. package/sdk-core/client/src/replaceable.rs +253 -0
  27. package/sdk-core/client/src/retry.rs +9 -6
  28. package/sdk-core/client/src/worker_registry/mod.rs +19 -3
  29. package/sdk-core/client/src/workflow_handle/mod.rs +20 -17
  30. package/sdk-core/core/Cargo.toml +100 -31
  31. package/sdk-core/core/src/core_tests/activity_tasks.rs +55 -225
  32. package/sdk-core/core/src/core_tests/mod.rs +2 -8
  33. package/sdk-core/core/src/core_tests/queries.rs +3 -5
  34. package/sdk-core/core/src/core_tests/replay_flag.rs +3 -62
  35. package/sdk-core/core/src/core_tests/updates.rs +4 -5
  36. package/sdk-core/core/src/core_tests/workers.rs +4 -3
  37. package/sdk-core/core/src/core_tests/workflow_cancels.rs +10 -7
  38. package/sdk-core/core/src/core_tests/workflow_tasks.rs +28 -291
  39. package/sdk-core/core/src/ephemeral_server/mod.rs +15 -3
  40. package/sdk-core/core/src/internal_flags.rs +11 -1
  41. package/sdk-core/core/src/lib.rs +50 -36
  42. package/sdk-core/core/src/pollers/mod.rs +5 -5
  43. package/sdk-core/core/src/pollers/poll_buffer.rs +2 -2
  44. package/sdk-core/core/src/protosext/mod.rs +13 -5
  45. package/sdk-core/core/src/protosext/protocol_messages.rs +4 -11
  46. package/sdk-core/core/src/retry_logic.rs +256 -108
  47. package/sdk-core/core/src/telemetry/metrics.rs +1 -0
  48. package/sdk-core/core/src/telemetry/mod.rs +8 -2
  49. package/sdk-core/core/src/telemetry/prometheus_meter.rs +2 -2
  50. package/sdk-core/core/src/test_help/integ_helpers.rs +971 -0
  51. package/sdk-core/core/src/test_help/mod.rs +10 -1100
  52. package/sdk-core/core/src/test_help/unit_helpers.rs +218 -0
  53. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +42 -6
  54. package/sdk-core/core/src/worker/activities/local_activities.rs +19 -19
  55. package/sdk-core/core/src/worker/activities.rs +10 -3
  56. package/sdk-core/core/src/worker/client/mocks.rs +3 -3
  57. package/sdk-core/core/src/worker/client.rs +130 -93
  58. package/sdk-core/core/src/worker/heartbeat.rs +12 -13
  59. package/sdk-core/core/src/worker/mod.rs +31 -21
  60. package/sdk-core/core/src/worker/nexus.rs +14 -3
  61. package/sdk-core/core/src/worker/slot_provider.rs +9 -0
  62. package/sdk-core/core/src/worker/tuner.rs +159 -0
  63. package/sdk-core/core/src/worker/workflow/history_update.rs +3 -265
  64. package/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +1 -54
  65. package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +0 -82
  66. package/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +0 -67
  67. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +1 -192
  68. package/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +0 -43
  69. package/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +6 -554
  70. package/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +0 -71
  71. package/sdk-core/core/src/worker/workflow/machines/nexus_operation_state_machine.rs +102 -3
  72. package/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +10 -539
  73. package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +0 -139
  74. package/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +1 -119
  75. package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +6 -63
  76. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +9 -4
  77. package/sdk-core/core/src/worker/workflow/mod.rs +5 -1
  78. package/sdk-core/core/src/worker/workflow/workflow_stream.rs +8 -3
  79. package/sdk-core/core-api/Cargo.toml +4 -4
  80. package/sdk-core/core-api/src/envconfig.rs +153 -54
  81. package/sdk-core/core-api/src/lib.rs +68 -0
  82. package/sdk-core/core-api/src/telemetry/metrics.rs +2 -1
  83. package/sdk-core/core-api/src/telemetry.rs +13 -0
  84. package/sdk-core/core-c-bridge/Cargo.toml +13 -8
  85. package/sdk-core/core-c-bridge/include/temporal-sdk-core-c-bridge.h +184 -22
  86. package/sdk-core/core-c-bridge/src/client.rs +462 -184
  87. package/sdk-core/core-c-bridge/src/envconfig.rs +314 -0
  88. package/sdk-core/core-c-bridge/src/lib.rs +1 -0
  89. package/sdk-core/core-c-bridge/src/random.rs +4 -4
  90. package/sdk-core/core-c-bridge/src/runtime.rs +22 -23
  91. package/sdk-core/core-c-bridge/src/testing.rs +1 -4
  92. package/sdk-core/core-c-bridge/src/tests/context.rs +31 -31
  93. package/sdk-core/core-c-bridge/src/tests/mod.rs +32 -28
  94. package/sdk-core/core-c-bridge/src/tests/utils.rs +7 -7
  95. package/sdk-core/core-c-bridge/src/worker.rs +319 -66
  96. package/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +6 -1
  97. package/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dupe_transitions_fail.stderr +5 -5
  98. package/sdk-core/sdk/Cargo.toml +8 -2
  99. package/sdk-core/sdk/src/activity_context.rs +1 -1
  100. package/sdk-core/sdk/src/app_data.rs +1 -1
  101. package/sdk-core/sdk/src/interceptors.rs +1 -4
  102. package/sdk-core/sdk/src/lib.rs +1 -5
  103. package/sdk-core/sdk/src/workflow_context/options.rs +10 -1
  104. package/sdk-core/sdk/src/workflow_future.rs +1 -1
  105. package/sdk-core/sdk-core-protos/Cargo.toml +6 -6
  106. package/sdk-core/sdk-core-protos/build.rs +10 -23
  107. package/sdk-core/sdk-core-protos/protos/api_upstream/.github/workflows/create-release.yml +9 -1
  108. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv2.json +254 -5
  109. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv3.yaml +234 -5
  110. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/common/v1/message.proto +1 -1
  111. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/deployment/v1/message.proto +6 -0
  112. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/namespace/v1/message.proto +6 -2
  113. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +60 -2
  114. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +30 -6
  115. package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +2 -0
  116. package/sdk-core/{test-utils → sdk-core-protos}/src/canned_histories.rs +5 -5
  117. package/sdk-core/sdk-core-protos/src/history_builder.rs +2 -2
  118. package/sdk-core/sdk-core-protos/src/lib.rs +25 -9
  119. package/sdk-core/sdk-core-protos/src/test_utils.rs +89 -0
  120. package/sdk-core/sdk-core-protos/src/utilities.rs +14 -5
  121. package/sdk-core/tests/c_bridge_smoke_test.c +10 -0
  122. package/sdk-core/tests/cloud_tests.rs +10 -8
  123. package/sdk-core/tests/common/http_proxy.rs +134 -0
  124. package/sdk-core/{test-utils/src/lib.rs → tests/common/mod.rs} +214 -281
  125. package/sdk-core/{test-utils/src → tests/common}/workflows.rs +4 -3
  126. package/sdk-core/tests/fuzzy_workflow.rs +1 -1
  127. package/sdk-core/tests/global_metric_tests.rs +8 -7
  128. package/sdk-core/tests/heavy_tests.rs +7 -3
  129. package/sdk-core/tests/integ_tests/client_tests.rs +111 -24
  130. package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +14 -9
  131. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +4 -4
  132. package/sdk-core/tests/integ_tests/metrics_tests.rs +114 -14
  133. package/sdk-core/tests/integ_tests/pagination_tests.rs +273 -0
  134. package/sdk-core/tests/integ_tests/polling_tests.rs +311 -93
  135. package/sdk-core/tests/integ_tests/queries_tests.rs +4 -4
  136. package/sdk-core/tests/integ_tests/update_tests.rs +13 -7
  137. package/sdk-core/tests/integ_tests/visibility_tests.rs +26 -9
  138. package/sdk-core/tests/integ_tests/worker_tests.rs +668 -13
  139. package/sdk-core/tests/integ_tests/worker_versioning_tests.rs +40 -24
  140. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +244 -11
  141. package/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +1 -1
  142. package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +78 -2
  143. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +61 -2
  144. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +465 -7
  145. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +41 -2
  146. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +315 -3
  147. package/sdk-core/tests/integ_tests/workflow_tests/eager.rs +1 -1
  148. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +1990 -14
  149. package/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +65 -2
  150. package/sdk-core/tests/integ_tests/workflow_tests/nexus.rs +123 -23
  151. package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +525 -3
  152. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +65 -16
  153. package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +32 -23
  154. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +126 -5
  155. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +1 -2
  156. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +124 -8
  157. package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +62 -2
  158. package/sdk-core/tests/integ_tests/workflow_tests.rs +67 -8
  159. package/sdk-core/tests/main.rs +26 -17
  160. package/sdk-core/tests/manual_tests.rs +5 -1
  161. package/sdk-core/tests/runner.rs +22 -40
  162. package/sdk-core/tests/shared_tests/mod.rs +1 -1
  163. package/sdk-core/tests/shared_tests/priority.rs +1 -1
  164. package/sdk-core/{core/benches/workflow_replay.rs → tests/workflow_replay_bench.rs} +10 -5
  165. package/src/client.rs +97 -20
  166. package/src/helpers/callbacks.rs +4 -4
  167. package/src/helpers/errors.rs +7 -1
  168. package/src/helpers/handles.rs +1 -0
  169. package/src/helpers/try_from_js.rs +4 -3
  170. package/src/lib.rs +3 -2
  171. package/src/metrics.rs +3 -0
  172. package/src/runtime.rs +5 -2
  173. package/src/worker.rs +9 -12
  174. package/ts/native.ts +13 -3
  175. package/sdk-core/arch_docs/diagrams/workflow_internals.svg +0 -1
  176. package/sdk-core/core/src/core_tests/child_workflows.rs +0 -281
  177. package/sdk-core/core/src/core_tests/determinism.rs +0 -318
  178. package/sdk-core/core/src/core_tests/local_activities.rs +0 -1442
  179. package/sdk-core/test-utils/Cargo.toml +0 -38
  180. package/sdk-core/test-utils/src/histfetch.rs +0 -28
  181. package/sdk-core/test-utils/src/interceptors.rs +0 -46
@@ -1,4 +1,7 @@
1
- use crate::integ_tests::activity_functions::echo;
1
+ use crate::{
2
+ common::{CoreWfStarter, NAMESPACE},
3
+ integ_tests::activity_functions::echo,
4
+ };
2
5
  use futures_util::StreamExt;
3
6
  use std::{
4
7
  sync::{
@@ -15,8 +18,8 @@ use temporal_sdk_core_protos::{
15
18
  common::v1::WorkflowExecution, workflowservice::v1::ResetWorkflowExecutionRequest,
16
19
  },
17
20
  };
18
- use temporal_sdk_core_test_utils::{CoreWfStarter, NAMESPACE};
19
21
  use tokio::sync::Notify;
22
+ use tonic::IntoRequest;
20
23
 
21
24
  const POST_RESET_SIG: &str = "post-reset";
22
25
 
@@ -63,17 +66,20 @@ async fn reset_workflow() {
63
66
  notify.notified().await;
64
67
  // Do the reset
65
68
  client
66
- .reset_workflow_execution(ResetWorkflowExecutionRequest {
67
- namespace: NAMESPACE.to_owned(),
68
- workflow_execution: Some(WorkflowExecution {
69
- workflow_id: wf_name.to_owned(),
70
- run_id: run_id.clone(),
71
- }),
72
- // End of first WFT
73
- workflow_task_finish_event_id: 4,
74
- request_id: "test-req-id".to_owned(),
75
- ..Default::default()
76
- })
69
+ .reset_workflow_execution(
70
+ ResetWorkflowExecutionRequest {
71
+ namespace: NAMESPACE.to_owned(),
72
+ workflow_execution: Some(WorkflowExecution {
73
+ workflow_id: wf_name.to_owned(),
74
+ run_id: run_id.clone(),
75
+ }),
76
+ // End of first WFT
77
+ workflow_task_finish_event_id: 4,
78
+ request_id: "test-req-id".to_owned(),
79
+ ..Default::default()
80
+ }
81
+ .into_request(),
82
+ )
77
83
  .await
78
84
  .unwrap();
79
85
 
@@ -189,16 +195,19 @@ async fn reset_randomseed() {
189
195
  notify.notified().await;
190
196
  // Reset the workflow to be after first timer has fired
191
197
  client
192
- .reset_workflow_execution(ResetWorkflowExecutionRequest {
193
- namespace: NAMESPACE.to_owned(),
194
- workflow_execution: Some(WorkflowExecution {
195
- workflow_id: wf_name.to_owned(),
196
- run_id: run_id.clone(),
197
- }),
198
- workflow_task_finish_event_id: 14,
199
- request_id: "test-req-id".to_owned(),
200
- ..Default::default()
201
- })
198
+ .reset_workflow_execution(
199
+ ResetWorkflowExecutionRequest {
200
+ namespace: NAMESPACE.to_owned(),
201
+ workflow_execution: Some(WorkflowExecution {
202
+ workflow_id: wf_name.to_owned(),
203
+ run_id: run_id.clone(),
204
+ }),
205
+ workflow_task_finish_event_id: 14,
206
+ request_id: "test-req-id".to_owned(),
207
+ ..Default::default()
208
+ }
209
+ .into_request(),
210
+ )
202
211
  .await
203
212
  .unwrap();
204
213
 
@@ -1,12 +1,26 @@
1
- use std::collections::HashMap;
2
-
1
+ use crate::common::{ActivationAssertionsInterceptor, CoreWfStarter, build_fake_sdk};
3
2
  use futures_util::StreamExt;
3
+ use std::collections::HashMap;
4
4
  use temporal_client::{SignalWithStartOptions, WorkflowClientTrait, WorkflowOptions};
5
5
  use temporal_sdk::{
6
- ChildWorkflowOptions, Signal, SignalWorkflowOptions, WfContext, WorkflowResult,
6
+ CancellableFuture, ChildWorkflowOptions, Signal, SignalWorkflowOptions, WfContext,
7
+ WorkflowResult,
8
+ };
9
+ use temporal_sdk_core::test_help::MockPollCfg;
10
+ use temporal_sdk_core_protos::{
11
+ DEFAULT_WORKFLOW_TYPE, TestHistoryBuilder,
12
+ coresdk::{
13
+ IntoPayloadsExt,
14
+ workflow_activation::{
15
+ ResolveSignalExternalWorkflow, WorkflowActivationJob, workflow_activation_job,
16
+ },
17
+ },
18
+ temporal::api::{
19
+ command::v1::{Command, command},
20
+ common::v1::Payload,
21
+ enums::v1::{CommandType, EventType},
22
+ },
7
23
  };
8
- use temporal_sdk_core_protos::{coresdk::IntoPayloadsExt, temporal::api::common::v1::Payload};
9
- use temporal_sdk_core_test_utils::CoreWfStarter;
10
24
  use uuid::Uuid;
11
25
 
12
26
  const SIGNAME: &str = "signame";
@@ -162,3 +176,110 @@ async fn sends_signal_to_child() {
162
176
  .unwrap();
163
177
  worker.run_until_done().await.unwrap();
164
178
  }
179
+
180
+ async fn signal_sender_canned(ctx: WfContext) -> WorkflowResult<()> {
181
+ let mut dat = SignalWorkflowOptions::new("fake_wid", "fake_rid", SIGNAME, [b"hi!"]);
182
+ dat.with_header("tupac", b"shakur");
183
+ let res = ctx.signal_workflow(dat).await;
184
+ if res.is_err() {
185
+ Err(anyhow::anyhow!("Signal fail!"))
186
+ } else {
187
+ Ok(().into())
188
+ }
189
+ }
190
+
191
+ #[rstest::rstest]
192
+ #[case::succeeds(false)]
193
+ #[case::fails(true)]
194
+ #[tokio::test]
195
+ async fn sends_signal(#[case] fails: bool) {
196
+ let mut t = TestHistoryBuilder::default();
197
+ t.add_by_type(EventType::WorkflowExecutionStarted);
198
+ t.add_full_wf_task();
199
+ let id = t.add_signal_wf(SIGNAME, "fake_wid", "fake_rid");
200
+ if fails {
201
+ t.add_external_signal_failed(id);
202
+ } else {
203
+ t.add_external_signal_completed(id);
204
+ }
205
+ t.add_full_wf_task();
206
+ t.add_workflow_execution_completed();
207
+
208
+ let mut mock_cfg = MockPollCfg::from_hist_builder(t);
209
+ mock_cfg.completion_asserts_from_expectations(|mut asserts| {
210
+ asserts.then(move |wft| {
211
+ assert_matches!(wft.commands.as_slice(),
212
+ [Command { attributes: Some(
213
+ command::Attributes::SignalExternalWorkflowExecutionCommandAttributes(attrs)),..}] => {
214
+ assert_eq!(attrs.signal_name, SIGNAME);
215
+ assert_eq!(attrs.input.as_ref().unwrap().payloads[0], b"hi!".into());
216
+ assert_eq!(*attrs.header.as_ref().unwrap().fields.get("tupac").unwrap(),
217
+ b"shakur".into());
218
+ }
219
+ );
220
+ }).then(move |wft| {
221
+ let cmds = &wft.commands;
222
+ assert_eq!(cmds.len(), 1);
223
+ if fails {
224
+ assert_eq!(cmds[0].command_type(), CommandType::FailWorkflowExecution);
225
+ } else {
226
+ assert_eq!(
227
+ cmds[0].command_type(),
228
+ CommandType::CompleteWorkflowExecution
229
+ );
230
+ }
231
+ });
232
+ });
233
+
234
+ let mut worker = build_fake_sdk(mock_cfg);
235
+ worker.register_wf(DEFAULT_WORKFLOW_TYPE, signal_sender_canned);
236
+ worker.run().await.unwrap();
237
+ }
238
+
239
+ #[tokio::test]
240
+ async fn cancels_before_sending() {
241
+ let mut t = TestHistoryBuilder::default();
242
+ t.add_by_type(EventType::WorkflowExecutionStarted);
243
+ t.add_full_wf_task();
244
+ t.add_workflow_execution_completed();
245
+
246
+ let mut mock_cfg = MockPollCfg::from_hist_builder(t);
247
+ let mut aai = ActivationAssertionsInterceptor::default();
248
+ aai.skip_one().then(move |act| {
249
+ assert_matches!(
250
+ &act.jobs[0],
251
+ WorkflowActivationJob {
252
+ variant: Some(workflow_activation_job::Variant::ResolveSignalExternalWorkflow(
253
+ ResolveSignalExternalWorkflow {
254
+ failure: Some(c),
255
+ ..
256
+ }
257
+ ))
258
+ } => c.message == "Signal was cancelled before being sent"
259
+ );
260
+ });
261
+ mock_cfg.completion_asserts_from_expectations(|mut asserts| {
262
+ asserts.then(move |wft| {
263
+ assert_eq!(wft.commands.len(), 1);
264
+ assert_eq!(
265
+ wft.commands[0].command_type(),
266
+ CommandType::CompleteWorkflowExecution
267
+ );
268
+ });
269
+ });
270
+
271
+ let mut worker = build_fake_sdk(mock_cfg);
272
+ worker.set_worker_interceptor(aai);
273
+ worker.register_wf(DEFAULT_WORKFLOW_TYPE, |ctx: WfContext| async move {
274
+ let sig = ctx.signal_workflow(SignalWorkflowOptions::new(
275
+ "fake_wid",
276
+ "fake_rid",
277
+ SIGNAME,
278
+ [b"hi!"],
279
+ ));
280
+ sig.cancel(&ctx);
281
+ let _res = sig.await;
282
+ Ok(().into())
283
+ });
284
+ worker.run().await.unwrap();
285
+ }
@@ -1,4 +1,4 @@
1
- use crate::integ_tests::workflow_tests::timers::timer_wf;
1
+ use crate::{common::CoreWfStarter, integ_tests::workflow_tests::timers::timer_wf};
2
2
  use std::{
3
3
  sync::atomic::{AtomicBool, AtomicUsize, Ordering},
4
4
  time::Duration,
@@ -6,7 +6,6 @@ use std::{
6
6
  use temporal_client::WorkflowOptions;
7
7
  use temporal_sdk::{WfContext, WorkflowResult};
8
8
  use temporal_sdk_core_api::worker::PollerBehavior;
9
- use temporal_sdk_core_test_utils::CoreWfStarter;
10
9
  use tokio::sync::Barrier;
11
10
 
12
11
  #[tokio::test]
@@ -1,13 +1,20 @@
1
1
  use std::time::Duration;
2
2
 
3
- use temporal_sdk::{WfContext, WorkflowResult};
4
- use temporal_sdk_core_protos::coresdk::{
5
- workflow_commands::{CancelTimer, CompleteWorkflowExecution, StartTimer},
6
- workflow_completion::WorkflowActivationCompletion,
7
- };
8
- use temporal_sdk_core_test_utils::{
9
- CoreWfStarter, WorkerTestHelpers, drain_pollers_and_shutdown, init_core_and_create_wf,
10
- start_timer_cmd,
3
+ use crate::common::{CoreWfStarter, build_fake_sdk, init_core_and_create_wf};
4
+ use temporal_sdk::{CancellableFuture, WfContext, WorkflowResult};
5
+ use temporal_sdk_core::test_help::{MockPollCfg, WorkerTestHelpers, drain_pollers_and_shutdown};
6
+ use temporal_sdk_core_protos::{
7
+ DEFAULT_WORKFLOW_TYPE, TestHistoryBuilder, canned_histories,
8
+ coresdk::{
9
+ workflow_commands::{CancelTimer, CompleteWorkflowExecution, StartTimer},
10
+ workflow_completion::WorkflowActivationCompletion,
11
+ },
12
+ prost_dur,
13
+ temporal::api::{
14
+ enums::v1::{CommandType, EventType, WorkflowTaskFailedCause},
15
+ failure::v1::Failure,
16
+ },
17
+ test_utils::start_timer_cmd,
11
18
  };
12
19
 
13
20
  pub(crate) async fn timer_wf(command_sink: WfContext) -> WorkflowResult<()> {
@@ -121,3 +128,112 @@ async fn parallel_timers() {
121
128
  starter.start_with_worker(wf_name, &mut worker).await;
122
129
  worker.run_until_done().await.unwrap();
123
130
  }
131
+
132
+ async fn happy_timer(ctx: WfContext) -> WorkflowResult<()> {
133
+ ctx.timer(Duration::from_secs(5)).await;
134
+ Ok(().into())
135
+ }
136
+
137
+ #[tokio::test]
138
+ async fn test_fire_happy_path_inc() {
139
+ let t = canned_histories::single_timer("1");
140
+ let mut mock_cfg = MockPollCfg::from_hist_builder(t);
141
+ mock_cfg.completion_asserts_from_expectations(|mut asserts| {
142
+ asserts
143
+ .then(move |wft| {
144
+ assert_eq!(wft.commands.len(), 1);
145
+ assert_eq!(wft.commands[0].command_type(), CommandType::StartTimer);
146
+ })
147
+ .then(move |wft| {
148
+ assert_eq!(wft.commands.len(), 1);
149
+ assert_eq!(
150
+ wft.commands[0].command_type(),
151
+ CommandType::CompleteWorkflowExecution
152
+ );
153
+ });
154
+ });
155
+
156
+ let mut worker = build_fake_sdk(mock_cfg);
157
+ worker.register_wf(DEFAULT_WORKFLOW_TYPE, happy_timer);
158
+ worker.run().await.unwrap();
159
+ }
160
+
161
+ #[tokio::test]
162
+ async fn mismatched_timer_ids_errors() {
163
+ let t = canned_histories::single_timer("badid");
164
+ let mut mock_cfg = MockPollCfg::from_hist_builder(t);
165
+ mock_cfg.num_expected_fails = 1;
166
+ mock_cfg.expect_fail_wft_matcher = Box::new(move |_, cause, f| {
167
+ matches!(cause, WorkflowTaskFailedCause::NonDeterministicError)
168
+ && matches!(f, Some(Failure {message, .. })
169
+ if message.contains("Timer fired event did not have expected timer id 1"))
170
+ });
171
+ let mut worker = build_fake_sdk(mock_cfg);
172
+ worker.register_wf(DEFAULT_WORKFLOW_TYPE, |ctx: WfContext| async move {
173
+ ctx.timer(Duration::from_secs(5)).await;
174
+ Ok(().into())
175
+ });
176
+ worker.run().await.unwrap();
177
+ }
178
+
179
+ async fn cancel_timer(ctx: WfContext) -> WorkflowResult<()> {
180
+ let cancel_timer_fut = ctx.timer(Duration::from_secs(500));
181
+ ctx.timer(Duration::from_secs(5)).await;
182
+ // Cancel the first timer after having waited on the second
183
+ cancel_timer_fut.cancel(&ctx);
184
+ cancel_timer_fut.await;
185
+ Ok(().into())
186
+ }
187
+
188
+ #[tokio::test]
189
+ async fn incremental_cancellation() {
190
+ let t = canned_histories::cancel_timer("2", "1");
191
+ let mut mock_cfg = MockPollCfg::from_hist_builder(t);
192
+ mock_cfg.completion_asserts_from_expectations(|mut asserts| {
193
+ asserts
194
+ .then(move |wft| {
195
+ assert_eq!(wft.commands.len(), 2);
196
+ assert_eq!(wft.commands[0].command_type(), CommandType::StartTimer);
197
+ assert_eq!(wft.commands[1].command_type(), CommandType::StartTimer);
198
+ })
199
+ .then(move |wft| {
200
+ assert_eq!(wft.commands.len(), 2);
201
+ assert_eq!(wft.commands[0].command_type(), CommandType::CancelTimer);
202
+ assert_eq!(
203
+ wft.commands[1].command_type(),
204
+ CommandType::CompleteWorkflowExecution
205
+ );
206
+ });
207
+ });
208
+
209
+ let mut worker = build_fake_sdk(mock_cfg);
210
+ worker.register_wf(DEFAULT_WORKFLOW_TYPE, cancel_timer);
211
+ worker.run().await.unwrap();
212
+ }
213
+
214
+ #[tokio::test]
215
+ async fn cancel_before_sent_to_server() {
216
+ let mut t = TestHistoryBuilder::default();
217
+ t.add_by_type(EventType::WorkflowExecutionStarted);
218
+ t.add_full_wf_task();
219
+ t.add_workflow_execution_completed();
220
+ let mut mock_cfg = MockPollCfg::from_hist_builder(t);
221
+ mock_cfg.completion_asserts_from_expectations(|mut asserts| {
222
+ asserts.then(move |wft| {
223
+ assert_eq!(wft.commands.len(), 1);
224
+ assert_matches!(
225
+ wft.commands[0].command_type(),
226
+ CommandType::CompleteWorkflowExecution
227
+ );
228
+ });
229
+ });
230
+ let mut worker = build_fake_sdk(mock_cfg);
231
+ worker.register_wf(DEFAULT_WORKFLOW_TYPE, |ctx: WfContext| async move {
232
+ let cancel_timer_fut = ctx.timer(Duration::from_secs(500));
233
+ // Immediately cancel the timer
234
+ cancel_timer_fut.cancel(&ctx);
235
+ cancel_timer_fut.await;
236
+ Ok(().into())
237
+ });
238
+ worker.run().await.unwrap();
239
+ }
@@ -1,3 +1,4 @@
1
+ use crate::common::{CoreWfStarter, SEARCH_ATTR_INT, SEARCH_ATTR_TXT, build_fake_sdk};
1
2
  use assert_matches::assert_matches;
2
3
  use std::{collections::HashMap, time::Duration};
3
4
  use temporal_client::{
@@ -5,8 +6,16 @@ use temporal_client::{
5
6
  WorkflowOptions,
6
7
  };
7
8
  use temporal_sdk::{WfContext, WfExitValue, WorkflowResult};
8
- use temporal_sdk_core_protos::coresdk::{AsJsonPayloadExt, FromJsonPayloadExt};
9
- use temporal_sdk_core_test_utils::{CoreWfStarter, SEARCH_ATTR_INT, SEARCH_ATTR_TXT};
9
+ use temporal_sdk_core::test_help::MockPollCfg;
10
+ use temporal_sdk_core_protos::{
11
+ DEFAULT_WORKFLOW_TYPE, TestHistoryBuilder,
12
+ coresdk::{AsJsonPayloadExt, FromJsonPayloadExt},
13
+ temporal::api::{
14
+ command::v1::{Command, command},
15
+ common::v1::Payload,
16
+ enums::v1::EventType,
17
+ },
18
+ };
10
19
  use uuid::Uuid;
11
20
 
12
21
  async fn search_attr_updater(ctx: WfContext) -> WorkflowResult<()> {
@@ -87,3 +96,54 @@ async fn sends_upsert() {
87
96
  .unwrap();
88
97
  assert_matches!(res, WorkflowExecutionResult::Succeeded(_));
89
98
  }
99
+
100
+ #[tokio::test]
101
+ async fn upsert_search_attrs_from_workflow() {
102
+ let mut t = TestHistoryBuilder::default();
103
+ t.add_by_type(EventType::WorkflowExecutionStarted);
104
+ t.add_full_wf_task();
105
+ t.add_workflow_execution_completed();
106
+
107
+ let (k1, k2) = ("foo", "bar");
108
+
109
+ let mut mock_cfg = MockPollCfg::from_hist_builder(t);
110
+ mock_cfg.completion_asserts_from_expectations(|mut asserts| {
111
+ asserts.then(|wft| {
112
+ assert_matches!(
113
+ wft.commands.as_slice(),
114
+ [Command { attributes: Some(
115
+ command::Attributes::UpsertWorkflowSearchAttributesCommandAttributes(msg)
116
+ ), .. }, ..] => {
117
+ let fields = &msg.search_attributes.as_ref().unwrap().indexed_fields;
118
+ let payload1 = fields.get(k1).unwrap();
119
+ let payload2 = fields.get(k2).unwrap();
120
+ assert_eq!(payload1.data[0], 0x01);
121
+ assert_eq!(payload2.data[0], 0x02);
122
+ assert_eq!(fields.len(), 2);
123
+ }
124
+ );
125
+ });
126
+ });
127
+
128
+ let mut worker = build_fake_sdk(mock_cfg);
129
+ worker.register_wf(DEFAULT_WORKFLOW_TYPE, move |ctx: WfContext| async move {
130
+ ctx.upsert_search_attributes([
131
+ (
132
+ String::from(k1),
133
+ Payload {
134
+ data: vec![0x01],
135
+ ..Default::default()
136
+ },
137
+ ),
138
+ (
139
+ String::from(k2),
140
+ Payload {
141
+ data: vec![0x02],
142
+ ..Default::default()
143
+ },
144
+ ),
145
+ ]);
146
+ Ok(().into())
147
+ });
148
+ worker.run().await.unwrap();
149
+ }
@@ -18,7 +18,13 @@ mod stickyness;
18
18
  mod timers;
19
19
  mod upsert_search_attrs;
20
20
 
21
- use crate::integ_tests::{activity_functions::echo, metrics_tests};
21
+ use crate::{
22
+ common::{
23
+ CoreWfStarter, history_from_proto_binary, init_core_and_create_wf,
24
+ init_core_replay_preloaded, mock_sdk_cfg, prom_metrics,
25
+ },
26
+ integ_tests::{activity_functions::echo, metrics_tests},
27
+ };
22
28
  use assert_matches::assert_matches;
23
29
  use std::{
24
30
  collections::{HashMap, HashSet},
@@ -26,9 +32,13 @@ use std::{
26
32
  };
27
33
  use temporal_client::{WfClientExt, WorkflowClientTrait, WorkflowExecutionResult, WorkflowOptions};
28
34
  use temporal_sdk::{
29
- ActivityOptions, LocalActivityOptions, WfContext, interceptors::WorkerInterceptor,
35
+ ActivityOptions, LocalActivityOptions, TimerOptions, WfContext, interceptors::WorkerInterceptor,
36
+ };
37
+ use temporal_sdk_core::{
38
+ CoreRuntime,
39
+ replay::HistoryForReplay,
40
+ test_help::{MockPollCfg, WorkerTestHelpers, drain_pollers_and_shutdown},
30
41
  };
31
- use temporal_sdk_core::{CoreRuntime, replay::HistoryForReplay};
32
42
  use temporal_sdk_core_api::{
33
43
  errors::{PollError, WorkflowErrorType},
34
44
  worker::{
@@ -36,6 +46,7 @@ use temporal_sdk_core_api::{
36
46
  },
37
47
  };
38
48
  use temporal_sdk_core_protos::{
49
+ DEFAULT_WORKFLOW_TYPE, canned_histories,
39
50
  coresdk::{
40
51
  ActivityTaskCompletion, AsJsonPayloadExt, IntoCompletion,
41
52
  activity_result::ActivityExecutionResult,
@@ -45,14 +56,15 @@ use temporal_sdk_core_protos::{
45
56
  },
46
57
  workflow_completion::WorkflowActivationCompletion,
47
58
  },
59
+ prost_dur,
48
60
  temporal::api::{
49
- enums::v1::EventType, failure::v1::Failure, history::v1::history_event,
61
+ enums::v1::{CommandType, EventType},
62
+ failure::v1::Failure,
63
+ history::v1::history_event,
50
64
  query::v1::WorkflowQuery,
65
+ sdk::v1::UserMetadata,
51
66
  },
52
- };
53
- use temporal_sdk_core_test_utils::{
54
- CoreWfStarter, WorkerTestHelpers, drain_pollers_and_shutdown, history_from_proto_binary,
55
- init_core_and_create_wf, init_core_replay_preloaded, prom_metrics, schedule_activity_cmd,
67
+ test_utils::schedule_activity_cmd,
56
68
  };
57
69
  use tokio::{join, sync::Notify, time::sleep};
58
70
 
@@ -922,3 +934,50 @@ async fn history_out_of_order_on_restart() {
922
934
  .unwrap();
923
935
  assert_matches!(res, WorkflowExecutionResult::Failed(_));
924
936
  }
937
+
938
+ #[tokio::test]
939
+ async fn pass_timer_summary_to_metadata() {
940
+ let t = canned_histories::single_timer("1");
941
+ let mut mock_cfg = MockPollCfg::from_hist_builder(t);
942
+ let wf_id = mock_cfg.hists[0].wf_id.clone();
943
+ let wf_type = DEFAULT_WORKFLOW_TYPE;
944
+ let expected_user_metadata = Some(UserMetadata {
945
+ summary: Some(b"timer summary".into()),
946
+ details: None,
947
+ });
948
+ mock_cfg.completion_asserts_from_expectations(|mut asserts| {
949
+ asserts
950
+ .then(move |wft| {
951
+ assert_eq!(wft.commands.len(), 1);
952
+ assert_eq!(wft.commands[0].command_type(), CommandType::StartTimer);
953
+ assert_eq!(wft.commands[0].user_metadata, expected_user_metadata)
954
+ })
955
+ .then(move |wft| {
956
+ assert_eq!(wft.commands.len(), 1);
957
+ assert_eq!(
958
+ wft.commands[0].command_type(),
959
+ CommandType::CompleteWorkflowExecution
960
+ );
961
+ });
962
+ });
963
+
964
+ let mut worker = mock_sdk_cfg(mock_cfg, |_| {});
965
+ worker.register_wf(wf_type, |ctx: WfContext| async move {
966
+ ctx.timer(TimerOptions {
967
+ duration: Duration::from_secs(1),
968
+ summary: Some("timer summary".to_string()),
969
+ })
970
+ .await;
971
+ Ok(().into())
972
+ });
973
+ worker
974
+ .submit_wf(
975
+ wf_id.to_owned(),
976
+ wf_type.to_owned(),
977
+ vec![],
978
+ WorkflowOptions::default(),
979
+ )
980
+ .await
981
+ .unwrap();
982
+ worker.run_until_done().await.unwrap();
983
+ }
@@ -3,7 +3,9 @@
3
3
  #[macro_use]
4
4
  extern crate rstest;
5
5
  #[macro_use]
6
- extern crate temporal_sdk_core_test_utils;
6
+ extern crate assert_matches;
7
+
8
+ mod common;
7
9
 
8
10
  #[cfg(test)]
9
11
  mod shared_tests;
@@ -15,6 +17,7 @@ mod integ_tests {
15
17
  mod ephemeral_server_tests;
16
18
  mod heartbeat_tests;
17
19
  mod metrics_tests;
20
+ mod pagination_tests;
18
21
  mod polling_tests;
19
22
  mod queries_tests;
20
23
  mod update_tests;
@@ -23,6 +26,9 @@ mod integ_tests {
23
26
  mod worker_versioning_tests;
24
27
  mod workflow_tests;
25
28
 
29
+ use crate::common::{
30
+ CoreWfStarter, get_integ_server_options, get_integ_telem_options, rand_6_chars,
31
+ };
26
32
  use std::time::Duration;
27
33
  use temporal_client::{NamespacedClient, WorkflowService};
28
34
  use temporal_sdk_core::{CoreRuntime, init_worker};
@@ -32,9 +38,7 @@ mod integ_tests {
32
38
  operatorservice::v1::CreateNexusEndpointRequest,
33
39
  workflowservice::v1::ListNamespacesRequest,
34
40
  };
35
- use temporal_sdk_core_test_utils::{
36
- CoreWfStarter, get_integ_server_options, get_integ_telem_options, rand_6_chars,
37
- };
41
+ use tonic::IntoRequest;
38
42
 
39
43
  // Create a worker like a bridge would (unwraps aside)
40
44
  #[tokio::test]
@@ -61,27 +65,32 @@ mod integ_tests {
61
65
 
62
66
  // Do things with worker or client
63
67
  let _ = retrying_client
64
- .list_namespaces(ListNamespacesRequest::default())
68
+ .list_namespaces(ListNamespacesRequest::default().into_request())
65
69
  .await;
66
70
  }
67
71
 
68
72
  pub(crate) async fn mk_nexus_endpoint(starter: &mut CoreWfStarter) -> String {
69
73
  let client = starter.get_client().await;
70
74
  let endpoint = format!("mycoolendpoint-{}", rand_6_chars());
71
- let mut op_client = client.get_client().inner().operator_svc().clone();
75
+ let mut op_client = client.get_client().inner().operator_svc();
72
76
  op_client
73
- .create_nexus_endpoint(CreateNexusEndpointRequest {
74
- spec: Some(EndpointSpec {
75
- name: endpoint.to_owned(),
76
- description: None,
77
- target: Some(EndpointTarget {
78
- variant: Some(endpoint_target::Variant::Worker(endpoint_target::Worker {
79
- namespace: client.namespace().to_owned(),
80
- task_queue: starter.get_task_queue().to_owned(),
81
- })),
77
+ .create_nexus_endpoint(
78
+ CreateNexusEndpointRequest {
79
+ spec: Some(EndpointSpec {
80
+ name: endpoint.to_owned(),
81
+ description: None,
82
+ target: Some(EndpointTarget {
83
+ variant: Some(endpoint_target::Variant::Worker(
84
+ endpoint_target::Worker {
85
+ namespace: client.namespace(),
86
+ task_queue: starter.get_task_queue().to_owned(),
87
+ },
88
+ )),
89
+ }),
82
90
  }),
83
- }),
84
- })
91
+ }
92
+ .into_request(),
93
+ )
85
94
  .await
86
95
  .unwrap();
87
96
  // Endpoint creation can (as of server 1.25.2 at least) return before they are actually usable.
@@ -1,6 +1,11 @@
1
1
  //! These tests are expensive and meant to be run manually. Use them for things like perf and
2
2
  //! load testing.
3
3
 
4
+ // All non-main.rs tests ignore dead common code so that the linter doesn't complain about about it.
5
+ #[allow(dead_code)]
6
+ mod common;
7
+
8
+ use common::{CoreWfStarter, prom_metrics, rand_6_chars};
4
9
  use futures_util::{
5
10
  StreamExt,
6
11
  future::{AbortHandle, Abortable},
@@ -18,7 +23,6 @@ use temporal_sdk::{ActContext, ActivityOptions, WfContext};
18
23
  use temporal_sdk_core::CoreRuntime;
19
24
  use temporal_sdk_core_api::{telemetry::PrometheusExporterOptionsBuilder, worker::PollerBehavior};
20
25
  use temporal_sdk_core_protos::coresdk::AsJsonPayloadExt;
21
- use temporal_sdk_core_test_utils::{CoreWfStarter, prom_metrics, rand_6_chars};
22
26
  use tracing::info;
23
27
 
24
28
  #[tokio::test]