@@ -39,14 +39,13 @@ import (
39
39
"testing"
40
40
"time"
41
41
42
- "go.opentelemetry.io/otel/baggage"
43
-
44
42
"github.com/opentracing/opentracing-go"
45
43
"github.com/pborman/uuid"
46
44
"github.com/stretchr/testify/assert"
47
45
"github.com/stretchr/testify/require"
48
46
"github.com/stretchr/testify/suite"
49
47
"github.com/uber-go/tally/v4"
48
+ "go.opentelemetry.io/otel/baggage"
50
49
sdktrace "go.opentelemetry.io/otel/sdk/trace"
51
50
"go.opentelemetry.io/otel/sdk/trace/tracetest"
52
51
"go.opentelemetry.io/otel/trace"
@@ -3956,6 +3955,240 @@ func (ts *IntegrationTestSuite) TestUpdateSettingHandlerInHandler() {
3956
3955
ts .NoError (run .Get (ctx , nil ))
3957
3956
}
3958
3957
3958
+ func (ts * IntegrationTestSuite ) TestExecuteWorkflowWithUpdate () {
3959
+ ctx , cancel := context .WithTimeout (context .Background (), 30 * time .Second )
3960
+ defer cancel ()
3961
+
3962
+ startOptionsWithOperation := func (op client.WithStartWorkflowOperation ) client.StartWorkflowOptions {
3963
+ startOptions := ts .startWorkflowOptions ("test-update-with-start-" + uuid .New ())
3964
+ startOptions .EnableEagerStart = false // not allowed to use with update-with-start
3965
+ startOptions .WithStartOperation = op
3966
+ return startOptions
3967
+ }
3968
+
3969
+ ts .Run ("sends update-with-start (no running workflow)" , func () {
3970
+ updateOp := client .NewUpdateWithStartWorkflowOperation (
3971
+ client.UpdateWorkflowOptions {
3972
+ UpdateName : "update" ,
3973
+ Args : []any {1 },
3974
+ WaitForStage : client .WorkflowUpdateStageAccepted ,
3975
+ })
3976
+
3977
+ startOptions := startOptionsWithOperation (updateOp )
3978
+ run , err := ts .client .ExecuteWorkflow (ctx , startOptions , ts .workflows .UpdateEntityWorkflow )
3979
+ ts .NoError (err )
3980
+
3981
+ var updateResult int
3982
+ updHandle , err := updateOp .Get (ctx )
3983
+ ts .NoError (err )
3984
+ ts .NoError (updHandle .Get (ctx , & updateResult ))
3985
+ ts .Equal (1 , updateResult )
3986
+
3987
+ var workflowResult int
3988
+ ts .NoError (run .Get (ctx , & workflowResult ))
3989
+ ts .Equal (1 , workflowResult )
3990
+ })
3991
+
3992
+ ts .Run ("sends update-with-start (already running workflow)" , func () {
3993
+ startOptions := startOptionsWithOperation (nil )
3994
+ run1 , err := ts .client .ExecuteWorkflow (ctx , startOptions , ts .workflows .UpdateEntityWorkflow )
3995
+ ts .NoError (err )
3996
+
3997
+ updateOp := client .NewUpdateWithStartWorkflowOperation (
3998
+ client.UpdateWorkflowOptions {
3999
+ UpdateName : "update" ,
4000
+ Args : []any {1 },
4001
+ WaitForStage : client .WorkflowUpdateStageCompleted ,
4002
+ })
4003
+
4004
+ startOptions .WithStartOperation = updateOp
4005
+ startOptions .WorkflowIDConflictPolicy = enumspb .WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING
4006
+ run2 , err := ts .client .ExecuteWorkflow (ctx , startOptions , ts .workflows .UpdateEntityWorkflow )
4007
+ ts .NoError (err )
4008
+ ts .Equal (run1 .GetRunID (), run2 .GetRunID ())
4009
+
4010
+ var updateResult int
4011
+ updHandle , err := updateOp .Get (ctx )
4012
+ ts .NoError (err )
4013
+ ts .NoError (updHandle .Get (ctx , & updateResult ))
4014
+ ts .Equal (1 , updateResult )
4015
+ })
4016
+
4017
+ ts .Run ("sends update-with-start but update is rejected" , func () {
4018
+ updateOp := client .NewUpdateWithStartWorkflowOperation (
4019
+ client.UpdateWorkflowOptions {
4020
+ UpdateName : "update" ,
4021
+ Args : []any {- 1 }, // rejected update payload
4022
+ WaitForStage : client .WorkflowUpdateStageCompleted ,
4023
+ })
4024
+
4025
+ startOptions := startOptionsWithOperation (updateOp )
4026
+ run , err := ts .client .ExecuteWorkflow (ctx , startOptions , ts .workflows .UpdateEntityWorkflow )
4027
+ ts .NoError (err )
4028
+ ts .NotNil (run )
4029
+
4030
+ var updateResult int
4031
+ updHandle , err := updateOp .Get (ctx )
4032
+ ts .NoError (err )
4033
+ err = updHandle .Get (ctx , & updateResult )
4034
+ ts .ErrorContains (err , "addend must be non-negative" )
4035
+ })
4036
+
4037
+ ts .Run ("receives update result in separate goroutines" , func () {
4038
+ updateOp := client .NewUpdateWithStartWorkflowOperation (
4039
+ client.UpdateWorkflowOptions {
4040
+ UpdateName : "update" ,
4041
+ Args : []any {1 },
4042
+ WaitForStage : client .WorkflowUpdateStageAccepted ,
4043
+ })
4044
+
4045
+ done := make (chan struct {})
4046
+ defer func () { <- done }()
4047
+ go func () {
4048
+ var updateResult int
4049
+ updHandle , err := updateOp .Get (ctx )
4050
+ ts .NoError (err )
4051
+ ts .NoError (updHandle .Get (ctx , & updateResult ))
4052
+ ts .Equal (1 , updateResult )
4053
+ done <- struct {}{}
4054
+ }()
4055
+
4056
+ startOptions := startOptionsWithOperation (updateOp )
4057
+ _ , err := ts .client .ExecuteWorkflow (ctx , startOptions , ts .workflows .UpdateEntityWorkflow )
4058
+ ts .NoError (err )
4059
+
4060
+ var updateResult int
4061
+ updHandle , err := updateOp .Get (ctx )
4062
+ ts .NoError (err )
4063
+ ts .NoError (updHandle .Get (ctx , & updateResult ))
4064
+ ts .Equal (1 , updateResult )
4065
+ })
4066
+
4067
+ ts .Run ("fails when start request is invalid" , func () {
4068
+ updateOp := client .NewUpdateWithStartWorkflowOperation (
4069
+ client.UpdateWorkflowOptions {
4070
+ UpdateName : "update" ,
4071
+ WaitForStage : client .WorkflowUpdateStageCompleted ,
4072
+ })
4073
+
4074
+ startOptions := startOptionsWithOperation (updateOp )
4075
+ startOptions .CronSchedule = "invalid!"
4076
+ _ , err := ts .client .ExecuteWorkflow (ctx , startOptions , ts .workflows .UpdateEntityWorkflow )
4077
+ ts .Error (err )
4078
+ })
4079
+
4080
+ ts .Run ("fails when update operation is invalid" , func () {
4081
+ updateOp := client .NewUpdateWithStartWorkflowOperation (
4082
+ client.UpdateWorkflowOptions {
4083
+ // invalid
4084
+ })
4085
+
4086
+ startOptions := startOptionsWithOperation (updateOp )
4087
+ _ , err := ts .client .ExecuteWorkflow (ctx , startOptions , ts .workflows .UpdateEntityWorkflow )
4088
+ ts .ErrorContains (err , "invalid WithStartOperation: WaitForStage must be specified" )
4089
+
4090
+ updateOp = client .NewUpdateWithStartWorkflowOperation (
4091
+ client.UpdateWorkflowOptions {
4092
+ RunID : "invalid" ,
4093
+ WaitForStage : client .WorkflowUpdateStageCompleted ,
4094
+ })
4095
+
4096
+ startOptions = startOptionsWithOperation (updateOp )
4097
+ _ , err = ts .client .ExecuteWorkflow (ctx , startOptions , ts .workflows .UpdateEntityWorkflow )
4098
+ ts .ErrorContains (err , "invalid WithStartOperation: RunID cannot be set because the workflow might not be running" )
4099
+
4100
+ updateOp = client .NewUpdateWithStartWorkflowOperation (
4101
+ client.UpdateWorkflowOptions {
4102
+ FirstExecutionRunID : "invalid" ,
4103
+ WaitForStage : client .WorkflowUpdateStageCompleted ,
4104
+ })
4105
+
4106
+ startOptions = startOptionsWithOperation (updateOp )
4107
+ _ , err = ts .client .ExecuteWorkflow (ctx , startOptions , ts .workflows .UpdateEntityWorkflow )
4108
+ ts .ErrorContains (err , "invalid WithStartOperation: FirstExecutionRunID cannot be set because the workflow might not be running" )
4109
+
4110
+ updateOp = client .NewUpdateWithStartWorkflowOperation (
4111
+ client.UpdateWorkflowOptions {
4112
+ UpdateName : "" , // invalid
4113
+ WaitForStage : client .WorkflowUpdateStageCompleted ,
4114
+ })
4115
+
4116
+ startOptions = startOptionsWithOperation (updateOp )
4117
+ _ , err = ts .client .ExecuteWorkflow (ctx , startOptions , ts .workflows .UpdateEntityWorkflow )
4118
+ ts .ErrorContains (err , "invalid WithStartOperation: " ) // omitting server message intentionally
4119
+
4120
+ updateOp = client .NewUpdateWithStartWorkflowOperation (
4121
+ client.UpdateWorkflowOptions {
4122
+ WorkflowID : "different" , // does not match Start's
4123
+ UpdateName : "update" ,
4124
+ WaitForStage : client .WorkflowUpdateStageCompleted ,
4125
+ })
4126
+
4127
+ startOptions = startOptionsWithOperation (updateOp )
4128
+ _ , err = ts .client .ExecuteWorkflow (ctx , startOptions , ts .workflows .UpdateEntityWorkflow )
4129
+ ts .ErrorContains (err , "invalid WithStartOperation: " ) // omitting server message intentionally
4130
+ })
4131
+
4132
+ ts .Run ("fails when workflow is already running" , func () {
4133
+ startOptions := startOptionsWithOperation (nil )
4134
+ _ , err := ts .client .ExecuteWorkflow (ctx , startOptions , ts .workflows .UpdateEntityWorkflow )
4135
+ ts .NoError (err )
4136
+
4137
+ updateOp := client .NewUpdateWithStartWorkflowOperation (
4138
+ client.UpdateWorkflowOptions {
4139
+ UpdateName : "update" ,
4140
+ Args : []any {1 },
4141
+ WaitForStage : client .WorkflowUpdateStageCompleted ,
4142
+ })
4143
+
4144
+ startOptions .WithStartOperation = updateOp
4145
+ // NOTE that WorkflowExecutionErrorWhenAlreadyStarted (defaults to false) has no impact
4146
+ _ , err = ts .client .ExecuteWorkflow (ctx , startOptions , ts .workflows .UpdateEntityWorkflow )
4147
+ ts .ErrorContains (err , "Workflow execution is already running" )
4148
+ })
4149
+
4150
+ ts .Run ("fails when executed twice" , func () {
4151
+ updateOp := client .NewUpdateWithStartWorkflowOperation (
4152
+ client.UpdateWorkflowOptions {
4153
+ UpdateName : "update" ,
4154
+ Args : []any {1 },
4155
+ WaitForStage : client .WorkflowUpdateStageCompleted ,
4156
+ })
4157
+
4158
+ startOptions := startOptionsWithOperation (updateOp )
4159
+ _ , err := ts .client .ExecuteWorkflow (ctx , startOptions , ts .workflows .UpdateEntityWorkflow )
4160
+ ts .NoError (err )
4161
+
4162
+ _ , err = ts .client .ExecuteWorkflow (ctx , startOptions , ts .workflows .UpdateEntityWorkflow )
4163
+ ts .ErrorContains (err , "invalid WithStartOperation: was already executed" )
4164
+ })
4165
+
4166
+ ts .Run ("propagates context" , func () {
4167
+ updateOp := client .NewUpdateWithStartWorkflowOperation (
4168
+ client.UpdateWorkflowOptions {
4169
+ UpdateName : "update" ,
4170
+ Args : []any {1 },
4171
+ WaitForStage : client .WorkflowUpdateStageCompleted ,
4172
+ })
4173
+
4174
+ var propagatedValues []string
4175
+ ctx := context .Background ()
4176
+ // Propagate values using different context propagators.
4177
+ ctx = context .WithValue (ctx , contextKey (testContextKey1 ), "propagatedValue1" )
4178
+ ctx = context .WithValue (ctx , contextKey (testContextKey2 ), "propagatedValue2" )
4179
+ ctx = context .WithValue (ctx , contextKey (testContextKey3 ), "non-propagatedValue" )
4180
+ startOptions := startOptionsWithOperation (updateOp )
4181
+ err := ts .executeWorkflowWithContextAndOption (ctx , startOptions , ts .workflows .ContextPropagator , & propagatedValues , true )
4182
+ ts .NoError (err )
4183
+
4184
+ // One copy from workflow and one copy from activity * 2 for child workflow
4185
+ ts .EqualValues ([]string {
4186
+ "propagatedValue1" , "propagatedValue2" , "activity_propagatedValue1" , "activity_propagatedValue2" ,
4187
+ "child_propagatedValue1" , "child_propagatedValue2" , "child_activity_propagatedValue1" , "child_activity_propagatedValue2" ,
4188
+ }, propagatedValues )
4189
+ })
4190
+ }
4191
+
3959
4192
func (ts * IntegrationTestSuite ) TestSessionOnWorkerFailure () {
3960
4193
ctx , cancel := context .WithTimeout (context .Background (), 30 * time .Second )
3961
4194
defer cancel ()
0 commit comments