@@ -7,13 +7,17 @@ import (
77
88 "github.com/google/uuid"
99 "github.com/stretchr/testify/require"
10+ commonpb "go.temporal.io/api/common/v1"
1011 computepb "go.temporal.io/api/compute/v1"
1112 deploymentpb "go.temporal.io/api/deployment/v1"
13+ "go.temporal.io/api/serviceerror"
1214 workflowservice "go.temporal.io/api/workflowservice/v1"
1315 computeprovider "go.temporal.io/auto-scaled-workers/wci/workflow/compute_provider"
1416 sdkclient "go.temporal.io/sdk/client"
1517 "go.temporal.io/sdk/worker"
1618 "go.temporal.io/sdk/workflow"
19+ "go.temporal.io/server/common/sdk"
20+ "google.golang.org/protobuf/proto"
1721 "google.golang.org/protobuf/types/known/fieldmaskpb"
1822)
1923
@@ -128,6 +132,297 @@ func TestWCIInstanceLifecycle(t *testing.T) {
128132 require .Error (t , err )
129133}
130134
135+ func TestWCIDuplicateDeploymentVersionAlreadyExists (t * testing.T ) {
136+ env := createWCITestEnv (t )
137+ ctx := env .Context ()
138+ cli := env .SdkClient ()
139+
140+ namespace := env .Namespace ().String ()
141+ deploymentName := uuid .NewString ()
142+ version := & deploymentpb.WorkerDeploymentVersion {
143+ DeploymentName : deploymentName ,
144+ BuildId : uuid .NewString (),
145+ }
146+
147+ // Create the parent Worker Deployment before creating a version.
148+ _ , err := cli .WorkflowService ().CreateWorkerDeployment (ctx ,
149+ & workflowservice.CreateWorkerDeploymentRequest {
150+ Namespace : namespace ,
151+ DeploymentName : deploymentName ,
152+ Identity : "test-identity" ,
153+ RequestId : uuid .NewString (),
154+ })
155+ require .NoError (t , err )
156+
157+ cc := testComputeConfig ()
158+
159+ // First create of the version succeeds.
160+ _ , err = cli .WorkflowService ().CreateWorkerDeploymentVersion (ctx ,
161+ & workflowservice.CreateWorkerDeploymentVersionRequest {
162+ Namespace : namespace ,
163+ DeploymentVersion : version ,
164+ Identity : "test-identity" ,
165+ ComputeConfig : cc ,
166+ RequestId : uuid .NewString (),
167+ })
168+ require .NoError (t , err )
169+
170+ // Second create of the same version with a different request_id must be
171+ // rejected as already existing.
172+ _ , err = cli .WorkflowService ().CreateWorkerDeploymentVersion (ctx ,
173+ & workflowservice.CreateWorkerDeploymentVersionRequest {
174+ Namespace : namespace ,
175+ DeploymentVersion : version ,
176+ Identity : "test-identity" ,
177+ ComputeConfig : cc ,
178+ RequestId : uuid .NewString (),
179+ })
180+ require .Error (t , err )
181+ var alreadyExists * serviceerror.AlreadyExists
182+ require .ErrorAs (t , err , & alreadyExists ,
183+ "duplicate version create should return an AlreadyExists error, got: %v" , err )
184+ }
185+
186+ func TestWCIDescribeVersionReturnsCorrectComputeConfig (t * testing.T ) {
187+ env := createWCITestEnv (t )
188+ ctx := env .Context ()
189+ cli := env .SdkClient ()
190+
191+ namespace := env .Namespace ().String ()
192+ deploymentName := uuid .NewString ()
193+ version := & deploymentpb.WorkerDeploymentVersion {
194+ DeploymentName : deploymentName ,
195+ BuildId : uuid .NewString (),
196+ }
197+
198+ // Create the parent Worker Deployment before creating a version.
199+ _ , err := cli .WorkflowService ().CreateWorkerDeployment (ctx ,
200+ & workflowservice.CreateWorkerDeploymentRequest {
201+ Namespace : namespace ,
202+ DeploymentName : deploymentName ,
203+ Identity : "test-identity" ,
204+ RequestId : uuid .NewString (),
205+ })
206+ require .NoError (t , err )
207+
208+ cc := testComputeConfig ()
209+ _ , err = cli .WorkflowService ().CreateWorkerDeploymentVersion (ctx ,
210+ & workflowservice.CreateWorkerDeploymentVersionRequest {
211+ Namespace : namespace ,
212+ DeploymentVersion : version ,
213+ Identity : "test-identity" ,
214+ ComputeConfig : cc ,
215+ RequestId : uuid .NewString (),
216+ })
217+ require .NoError (t , err )
218+
219+ // Describe the version and assert the stored compute config matches what we sent.
220+ descResp , err := cli .WorkflowService ().DescribeWorkerDeploymentVersion (ctx ,
221+ & workflowservice.DescribeWorkerDeploymentVersionRequest {
222+ Namespace : namespace ,
223+ DeploymentVersion : version ,
224+ })
225+ require .NoError (t , err )
226+
227+ got := descResp .GetWorkerDeploymentVersionInfo ().GetComputeConfig ()
228+ require .NotNil (t , got )
229+ require .True (t , proto .Equal (cc , got ),
230+ "described compute config does not match the create request:\n want: %v\n got: %v" , cc , got )
231+ }
232+
233+ func TestWCICreateVersionInvalidComputeConfig (t * testing.T ) {
234+ env := createWCITestEnv (t )
235+ ctx := env .Context ()
236+ cli := env .SdkClient ()
237+
238+ namespace := env .Namespace ().String ()
239+ deploymentName := uuid .NewString ()
240+ version := & deploymentpb.WorkerDeploymentVersion {
241+ DeploymentName : deploymentName ,
242+ BuildId : uuid .NewString (),
243+ }
244+
245+ // Create the parent Worker Deployment before creating a version.
246+ _ , err := cli .WorkflowService ().CreateWorkerDeployment (ctx ,
247+ & workflowservice.CreateWorkerDeploymentRequest {
248+ Namespace : namespace ,
249+ DeploymentName : deploymentName ,
250+ Identity : "test-identity" ,
251+ RequestId : uuid .NewString (),
252+ })
253+ require .NoError (t , err )
254+
255+ // Creating the version with the invalid compute config must be rejected.
256+ _ , err = cli .WorkflowService ().CreateWorkerDeploymentVersion (ctx ,
257+ & workflowservice.CreateWorkerDeploymentVersionRequest {
258+ Namespace : namespace ,
259+ DeploymentVersion : version ,
260+ Identity : "test-identity" ,
261+ ComputeConfig : invalidTestComputeConfig (),
262+ RequestId : uuid .NewString (),
263+ })
264+ require .Error (t , err )
265+ var invalidArg * serviceerror.InvalidArgument
266+ require .ErrorAs (t , err , & invalidArg ,
267+ "invalid compute config should return an InvalidArgument error, got: %v" , err )
268+
269+ // The rejected create must not have left a version behind.
270+ _ , err = cli .WorkflowService ().DescribeWorkerDeploymentVersion (ctx ,
271+ & workflowservice.DescribeWorkerDeploymentVersionRequest {
272+ Namespace : namespace ,
273+ DeploymentVersion : version ,
274+ })
275+ require .Error (t , err )
276+ }
277+
278+ func TestWCIUpdateVersionInvalidComputeConfig (t * testing.T ) {
279+ env := createWCITestEnv (t )
280+ ctx := env .Context ()
281+ cli := env .SdkClient ()
282+
283+ namespace := env .Namespace ().String ()
284+ deploymentName := uuid .NewString ()
285+ version := & deploymentpb.WorkerDeploymentVersion {
286+ DeploymentName : deploymentName ,
287+ BuildId : uuid .NewString (),
288+ }
289+
290+ // Create the parent Worker Deployment before creating a version.
291+ _ , err := cli .WorkflowService ().CreateWorkerDeployment (ctx ,
292+ & workflowservice.CreateWorkerDeploymentRequest {
293+ Namespace : namespace ,
294+ DeploymentName : deploymentName ,
295+ Identity : "test-identity" ,
296+ RequestId : uuid .NewString (),
297+ })
298+ require .NoError (t , err )
299+
300+ cc := testComputeConfig ()
301+ _ , err = cli .WorkflowService ().CreateWorkerDeploymentVersion (ctx ,
302+ & workflowservice.CreateWorkerDeploymentVersionRequest {
303+ Namespace : namespace ,
304+ DeploymentVersion : version ,
305+ Identity : "test-identity" ,
306+ ComputeConfig : cc ,
307+ RequestId : uuid .NewString (),
308+ })
309+ require .NoError (t , err )
310+
311+ // Updating the version with the invalid compute config should fail in provider ValidateConfig.
312+ _ , err = cli .WorkflowService ().UpdateWorkerDeploymentVersionComputeConfig (ctx ,
313+ & workflowservice.UpdateWorkerDeploymentVersionComputeConfigRequest {
314+ Namespace : namespace ,
315+ DeploymentVersion : version ,
316+ Identity : "test-identity" ,
317+ ComputeConfigScalingGroups : invalidTestScalingGroupUpdate (),
318+ RequestId : uuid .NewString (),
319+ })
320+ require .Error (t , err )
321+ var invalidArg * serviceerror.InvalidArgument
322+ require .ErrorAs (t , err , & invalidArg ,
323+ "invalid compute config should return an InvalidArgument error, got: %v" , err )
324+
325+ // Describe the version and assert the stored compute config matches original.
326+ descResp , err := cli .WorkflowService ().DescribeWorkerDeploymentVersion (ctx ,
327+ & workflowservice.DescribeWorkerDeploymentVersionRequest {
328+ Namespace : namespace ,
329+ DeploymentVersion : version ,
330+ })
331+ require .NoError (t , err )
332+
333+ got := descResp .GetWorkerDeploymentVersionInfo ().GetComputeConfig ()
334+ require .NotNil (t , got )
335+ require .True (t , proto .Equal (cc , got ),
336+ "described compute config does not match the create request:\n want: %v\n got: %v" , cc , got )
337+ }
338+
339+ func TestWCIUpdateAndRemoveVersionComputeConfig (t * testing.T ) {
340+ env := createWCITestEnv (t )
341+ ctx := env .Context ()
342+ cli := env .SdkClient ()
343+
344+ namespace := env .Namespace ().String ()
345+ deploymentName := uuid .NewString ()
346+ version := & deploymentpb.WorkerDeploymentVersion {
347+ DeploymentName : deploymentName ,
348+ BuildId : uuid .NewString (),
349+ }
350+
351+ // Create the parent deployment + a version with the baseline compute config
352+ _ , err := cli .WorkflowService ().CreateWorkerDeployment (ctx ,
353+ & workflowservice.CreateWorkerDeploymentRequest {
354+ Namespace : namespace ,
355+ DeploymentName : deploymentName ,
356+ Identity : "test-identity" ,
357+ RequestId : uuid .NewString (),
358+ })
359+ require .NoError (t , err )
360+
361+ _ , err = cli .WorkflowService ().CreateWorkerDeploymentVersion (ctx ,
362+ & workflowservice.CreateWorkerDeploymentVersionRequest {
363+ Namespace : namespace ,
364+ DeploymentVersion : version ,
365+ Identity : "test-identity" ,
366+ ComputeConfig : testComputeConfig (),
367+ RequestId : uuid .NewString (),
368+ })
369+ require .NoError (t , err )
370+
371+ // Update the default scaling group's scaler details with a valid no-sync
372+ // config
373+ updated := validUpdatedComputeConfig ()
374+ _ , err = cli .WorkflowService ().UpdateWorkerDeploymentVersionComputeConfig (ctx ,
375+ & workflowservice.UpdateWorkerDeploymentVersionComputeConfigRequest {
376+ Namespace : namespace ,
377+ DeploymentVersion : version ,
378+ Identity : "test-identity" ,
379+ RequestId : uuid .NewString (),
380+ ComputeConfigScalingGroups : map [string ]* computepb.ComputeConfigScalingGroupUpdate {
381+ "default" : {
382+ ScalingGroup : updated .GetScalingGroups ()["default" ],
383+ UpdateMask : & fieldmaskpb.FieldMask {
384+ Paths : []string {"scaler.details" },
385+ },
386+ },
387+ },
388+ })
389+ require .NoError (t , err )
390+
391+ // Describe and assert the update took effect.
392+ descResp , err := cli .WorkflowService ().DescribeWorkerDeploymentVersion (ctx ,
393+ & workflowservice.DescribeWorkerDeploymentVersionRequest {
394+ Namespace : namespace ,
395+ DeploymentVersion : version ,
396+ })
397+ require .NoError (t , err )
398+ got := descResp .GetWorkerDeploymentVersionInfo ().GetComputeConfig ()
399+ require .NotNil (t , got )
400+ require .True (t , proto .Equal (updated , got ),
401+ "described compute config does not match the update:\n want: %v\n got: %v" , updated , got )
402+
403+ // Remove the compute config for the default scaling group.
404+ _ , err = cli .WorkflowService ().UpdateWorkerDeploymentVersionComputeConfig (ctx ,
405+ & workflowservice.UpdateWorkerDeploymentVersionComputeConfigRequest {
406+ Namespace : namespace ,
407+ DeploymentVersion : version ,
408+ Identity : "test-identity" ,
409+ RequestId : uuid .NewString (),
410+ RemoveComputeConfigScalingGroups : []string {"default" },
411+ })
412+ require .NoError (t , err )
413+
414+ // Describe and assert the compute config no longer has the removed group.
415+ descResp , err = cli .WorkflowService ().DescribeWorkerDeploymentVersion (ctx ,
416+ & workflowservice.DescribeWorkerDeploymentVersionRequest {
417+ Namespace : namespace ,
418+ DeploymentVersion : version ,
419+ })
420+ require .NoError (t , err )
421+ require .Nil (t ,
422+ descResp .GetWorkerDeploymentVersionInfo ().GetComputeConfig ().GetScalingGroups ()["default" ],
423+ "default scaling group should have been removed from the compute config" )
424+ }
425+
131426// scaleUpWorkflow is a trivial workflow whose only purpose is to create a
132427// backlog on a versioned task queue and then complete once a worker comes up.
133428func scaleUpWorkflow (_ workflow.Context ) (string , error ) {
@@ -309,3 +604,60 @@ func testComputeConfig() *computepb.ComputeConfig {
309604 },
310605 }
311606}
607+
608+ // validUpdatedComputeConfig mirrors testComputeConfig but gives the no-sync
609+ // scaler a valid details payload.
610+ func validUpdatedComputeConfig () * computepb.ComputeConfig {
611+ return & computepb.ComputeConfig {
612+ ScalingGroups : map [string ]* computepb.ComputeConfigScalingGroup {
613+ "default" : {
614+ Provider : & computepb.ComputeProvider {
615+ Type : "test-invoke" ,
616+ },
617+ Scaler : & computepb.ComputeScaler {
618+ Type : "no-sync" ,
619+ Details : noSyncScalerDetails (),
620+ },
621+ },
622+ },
623+ }
624+ }
625+
626+ func noSyncScalerDetails () * commonpb.Payload {
627+ details := map [string ]string {
628+ "scale_up_backlog_threshold" : "5" ,
629+ "scale_up_cooloff_ms" : "500" ,
630+ "max_worker_lifetime_ms" : "300000" ,
631+ }
632+ payload , err := sdk .PreferProtoDataConverter .ToPayload (details )
633+ if err != nil {
634+ panic (err )
635+ }
636+ return payload
637+ }
638+
639+ func invalidTestComputeConfig () * computepb.ComputeConfig {
640+ return & computepb.ComputeConfig {
641+ ScalingGroups : map [string ]* computepb.ComputeConfigScalingGroup {
642+ "default" : {
643+ Provider : computeprovider .TestInvokeComputeProviderInvalidComputeProvider (),
644+ Scaler : & computepb.ComputeScaler {
645+ Type : "no-sync" ,
646+ },
647+ },
648+ },
649+ }
650+ }
651+
652+ func invalidTestScalingGroupUpdate () map [string ]* computepb.ComputeConfigScalingGroupUpdate {
653+ invalidComputeConfig := invalidTestComputeConfig ()
654+ invalidTestScalingGroupUpdate := & computepb.ComputeConfigScalingGroupUpdate {
655+ ScalingGroup : invalidComputeConfig .GetScalingGroups ()["default" ],
656+ UpdateMask : & fieldmaskpb.FieldMask {
657+ Paths : []string {"Provider" },
658+ },
659+ }
660+ return map [string ]* computepb.ComputeConfigScalingGroupUpdate {
661+ "default" : invalidTestScalingGroupUpdate ,
662+ }
663+ }
0 commit comments