@@ -30,6 +30,7 @@ import (
3030 "google.golang.org/protobuf/proto"
3131 "google.golang.org/protobuf/types/known/durationpb"
3232 "google.golang.org/protobuf/types/known/fieldmaskpb"
33+ "google.golang.org/protobuf/types/known/timestamppb"
3334)
3435
3536type noopVersionMembershipCache struct {}
@@ -215,41 +216,6 @@ func TestMergeOptions_TimeSkippingConfig(t *testing.T) {
215216 }
216217}
217218
218- func TestMergeAndApply_TimeSkippingConfig (t * testing.T ) {
219- tscMask := & fieldmaskpb.FieldMask {Paths : []string {"time_skipping_config" }}
220- cfg := & workflowpb.TimeSkippingConfig {
221- Enabled : true ,
222- Bound : & workflowpb.TimeSkippingConfig_MaxSkippedDuration {MaxSkippedDuration : durationpb .New (time .Hour )},
223- }
224-
225- t .Run ("same config - no event written" , func (t * testing.T ) {
226- ctrl := gomock .NewController (t )
227- ms := historyi .NewMockMutableState (ctrl )
228- ms .EXPECT ().GetExecutionInfo ().Return (& persistencespb.WorkflowExecutionInfo {
229- TimeSkippingInfo : & persistencespb.TimeSkippingInfo {Config : cfg },
230- }).AnyTimes ()
231-
232- merged , hasChanges , err := MergeAndApply (ms , & workflowpb.WorkflowExecutionOptions {TimeSkippingConfig : cfg }, tscMask , "" )
233- require .NoError (t , err )
234- require .False (t , hasChanges )
235- require .True (t , proto .Equal (cfg , merged .GetTimeSkippingConfig ()))
236- })
237-
238- t .Run ("new config - event written with config" , func (t * testing.T ) {
239- ctrl := gomock .NewController (t )
240- ms := historyi .NewMockMutableState (ctrl )
241- ms .EXPECT ().GetExecutionInfo ().Return (& persistencespb.WorkflowExecutionInfo {}).AnyTimes ()
242- ms .EXPECT ().AddWorkflowExecutionOptionsUpdatedEvent (
243- nil , true , "" , nil , nil , "" , nil , cfg ,
244- ).Return (& historypb.HistoryEvent {}, nil )
245-
246- merged , hasChanges , err := MergeAndApply (ms , & workflowpb.WorkflowExecutionOptions {TimeSkippingConfig : cfg }, tscMask , "" )
247- require .NoError (t , err )
248- require .True (t , hasChanges )
249- require .True (t , proto .Equal (cfg , merged .GetTimeSkippingConfig ()))
250- })
251- }
252-
253219type (
254220 // updateWorkflowOptionsSuite contains tests for the UpdateWorkflowOptions API.
255221 updateWorkflowOptionsSuite struct {
@@ -372,3 +338,126 @@ func (s *updateWorkflowOptionsSuite) TestInvoke_Success() {
372338 s .NotNil (resp )
373339 proto .Equal (expectedOverrideOptions , resp .GetWorkflowExecutionOptions ())
374340}
341+
342+ func TestMergeAndApply_TimeSkippingConfig (t * testing.T ) {
343+ oneHour := durationpb .New (time .Hour )
344+ twoHours := durationpb .New (2 * time .Hour )
345+ thirtyMin := durationpb .New (30 * time .Minute )
346+ targetTime := timestamppb .New (time .Date (2026 , 1 , 1 , 0 , 0 , 0 , 0 , time .UTC ))
347+
348+ testCases := []struct {
349+ name string
350+ initialConfig * workflowpb.TimeSkippingConfig
351+ updateOptions * workflowpb.WorkflowExecutionOptions
352+ updateMask * fieldmaskpb.FieldMask
353+ expectedConfig * workflowpb.TimeSkippingConfig
354+ }{
355+ {
356+ name : "update max_skipped_duration preserves enabled and disable_propagation" ,
357+ initialConfig : & workflowpb.TimeSkippingConfig {
358+ Enabled : true ,
359+ DisablePropagation : true ,
360+ Bound : & workflowpb.TimeSkippingConfig_MaxSkippedDuration {
361+ MaxSkippedDuration : oneHour ,
362+ },
363+ },
364+ updateOptions : & workflowpb.WorkflowExecutionOptions {
365+ TimeSkippingConfig : & workflowpb.TimeSkippingConfig {
366+ Bound : & workflowpb.TimeSkippingConfig_MaxSkippedDuration {
367+ MaxSkippedDuration : twoHours ,
368+ },
369+ },
370+ },
371+ updateMask : & fieldmaskpb.FieldMask {Paths : []string {"time_skipping_config.max_skipped_duration" }},
372+ expectedConfig : & workflowpb.TimeSkippingConfig {
373+ Enabled : true ,
374+ DisablePropagation : true ,
375+ Bound : & workflowpb.TimeSkippingConfig_MaxSkippedDuration {
376+ MaxSkippedDuration : twoHours ,
377+ },
378+ },
379+ },
380+ {
381+ name : "change bound type to max_elapsed_duration preserves enabled" ,
382+ initialConfig : & workflowpb.TimeSkippingConfig {
383+ Enabled : true ,
384+ Bound : & workflowpb.TimeSkippingConfig_MaxSkippedDuration {
385+ MaxSkippedDuration : oneHour ,
386+ },
387+ },
388+ updateOptions : & workflowpb.WorkflowExecutionOptions {
389+ TimeSkippingConfig : & workflowpb.TimeSkippingConfig {
390+ Bound : & workflowpb.TimeSkippingConfig_MaxElapsedDuration {
391+ MaxElapsedDuration : thirtyMin ,
392+ },
393+ },
394+ },
395+ updateMask : & fieldmaskpb.FieldMask {Paths : []string {"time_skipping_config.max_elapsed_duration" }},
396+ expectedConfig : & workflowpb.TimeSkippingConfig {
397+ Enabled : true ,
398+ Bound : & workflowpb.TimeSkippingConfig_MaxElapsedDuration {
399+ MaxElapsedDuration : thirtyMin ,
400+ },
401+ },
402+ },
403+ {
404+ name : "enable from nil config" ,
405+ initialConfig : nil ,
406+ updateOptions : & workflowpb.WorkflowExecutionOptions {
407+ TimeSkippingConfig : & workflowpb.TimeSkippingConfig {Enabled : true },
408+ },
409+ updateMask : & fieldmaskpb.FieldMask {Paths : []string {"time_skipping_config.enabled" }},
410+ expectedConfig : & workflowpb.TimeSkippingConfig {Enabled : true },
411+ },
412+ {
413+ name : "disable from enabled config" ,
414+ initialConfig : & workflowpb.TimeSkippingConfig {Enabled : true },
415+ updateOptions : & workflowpb.WorkflowExecutionOptions {
416+ TimeSkippingConfig : & workflowpb.TimeSkippingConfig {Enabled : false },
417+ },
418+ updateMask : & fieldmaskpb.FieldMask {Paths : []string {"time_skipping_config.enabled" }},
419+ expectedConfig : & workflowpb.TimeSkippingConfig {Enabled : false },
420+ },
421+ {
422+ name : "change bound type to max_target_time preserves enabled" ,
423+ initialConfig : & workflowpb.TimeSkippingConfig {
424+ Enabled : true ,
425+ Bound : & workflowpb.TimeSkippingConfig_MaxSkippedDuration {
426+ MaxSkippedDuration : oneHour ,
427+ },
428+ },
429+ updateOptions : & workflowpb.WorkflowExecutionOptions {
430+ TimeSkippingConfig : & workflowpb.TimeSkippingConfig {
431+ Bound : & workflowpb.TimeSkippingConfig_MaxTargetTime {
432+ MaxTargetTime : targetTime ,
433+ },
434+ },
435+ },
436+ updateMask : & fieldmaskpb.FieldMask {Paths : []string {"time_skipping_config.max_target_time" }},
437+ expectedConfig : & workflowpb.TimeSkippingConfig {
438+ Enabled : true ,
439+ Bound : & workflowpb.TimeSkippingConfig_MaxTargetTime {
440+ MaxTargetTime : targetTime ,
441+ },
442+ },
443+ },
444+ }
445+
446+ for _ , tc := range testCases {
447+ t .Run (tc .name , func (t * testing.T ) {
448+ ctrl := gomock .NewController (t )
449+ ms := historyi .NewMockMutableState (ctrl )
450+ ms .EXPECT ().GetExecutionInfo ().Return (& persistencespb.WorkflowExecutionInfo {
451+ TimeSkippingInfo : & persistencespb.TimeSkippingInfo {
452+ Config : tc .initialConfig ,
453+ },
454+ }).AnyTimes ()
455+ ms .EXPECT ().AddWorkflowExecutionOptionsUpdatedEvent (nil , true , "" , nil , nil , "" , nil , gomock .Any ()).Return (& historypb.HistoryEvent {}, nil )
456+
457+ result , hasChanges , err := MergeAndApply (ms , tc .updateOptions , tc .updateMask , "" )
458+ require .NoError (t , err )
459+ require .True (t , hasChanges )
460+ require .True (t , proto .Equal (tc .expectedConfig , result .GetTimeSkippingConfig ()))
461+ })
462+ }
463+ }
0 commit comments