Skip to content

Commit 940e3ff

Browse files
committed
Add WCI valid/invalid compute configs tests
This adds a test for duplicate worker deployment versions and then various test around creating and updating worker deployment versions with valid and invalid compute configs.
1 parent 9aff8cf commit 940e3ff

1 file changed

Lines changed: 352 additions & 0 deletions

File tree

tests/integration/wci_test.go

Lines changed: 352 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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:\nwant: %v\ngot: %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:\nwant: %v\ngot: %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:\nwant: %v\ngot: %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.
133428
func 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

Comments
 (0)