mirror of
https://github.com/hanzoai/tasks.git
synced 2026-10-04 02:04:03 +00:00
## What changed? <!-- Describe what has changed in this PR --> - Sorting version summaries in DescribeWorkerDeployment calls with the newest version coming at the top. ## Why? <!-- Tell your future self why have you made these changes --> - Correctness and better user functionality. ## How did you test it? <!-- How have you verified this change? Tested locally? Added a unit test? Checked in staging env? --> - Added a new functional test + modified an existing one. ## Potential risks <!-- Assuming the worst case, what can be broken when deploying this change to production? --> ## Documentation <!-- Have you made sure this change doesn't falsify anything currently stated in `docs/`? If significant new behavior is added, have you described that in `docs/`? --> ## Is hotfix candidate? <!-- Is this PR a hotfix candidate or does it require a notification to be sent to the broader community? (Yes/No) -->
1875 lines
73 KiB
Go
1875 lines
73 KiB
Go
// The MIT License
|
|
//
|
|
// Copyright (c) 2024 Temporal Technologies Inc. All rights reserved.
|
|
//
|
|
// Copyright (c) 2024 Uber Technologies, Inc.
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
// THE SOFTWARE.
|
|
|
|
package tests
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"slices"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/dgryski/go-farm"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/suite"
|
|
commonpb "go.temporal.io/api/common/v1"
|
|
deploymentpb "go.temporal.io/api/deployment/v1"
|
|
enumspb "go.temporal.io/api/enums/v1"
|
|
"go.temporal.io/api/serviceerror"
|
|
taskqueuepb "go.temporal.io/api/taskqueue/v1"
|
|
"go.temporal.io/api/workflowservice/v1"
|
|
"go.temporal.io/server/common/dynamicconfig"
|
|
"go.temporal.io/server/common/testing/testvars"
|
|
"go.temporal.io/server/common/worker_versioning"
|
|
"go.temporal.io/server/service/worker/workerdeployment"
|
|
"go.temporal.io/server/tests/testcore"
|
|
"google.golang.org/protobuf/types/known/timestamppb"
|
|
)
|
|
|
|
type (
|
|
WorkerDeploymentSuite struct {
|
|
testcore.FunctionalTestSuite
|
|
}
|
|
)
|
|
|
|
func TestWorkerDeploymentSuite(t *testing.T) {
|
|
t.Parallel()
|
|
suite.Run(t, new(WorkerDeploymentSuite))
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) SetupSuite() {
|
|
s.FunctionalTestSuite.SetupSuiteWithDefaultCluster(testcore.WithDynamicConfigOverrides(map[dynamicconfig.Key]any{
|
|
dynamicconfig.EnableDeploymentVersions.Key(): true,
|
|
dynamicconfig.FrontendEnableWorkerVersioningDataAPIs.Key(): true, // [wv-cleanup-pre-release]
|
|
dynamicconfig.FrontendEnableWorkerVersioningWorkflowAPIs.Key(): true, // [wv-cleanup-pre-release]
|
|
dynamicconfig.FrontendEnableWorkerVersioningRuleAPIs.Key(): true, // [wv-cleanup-pre-release]
|
|
dynamicconfig.FrontendEnableExecuteMultiOperation.Key(): true,
|
|
|
|
// Make sure we don't hit the rate limiter in tests
|
|
dynamicconfig.FrontendGlobalNamespaceNamespaceReplicationInducingAPIsRPS.Key(): 1000,
|
|
dynamicconfig.FrontendMaxNamespaceNamespaceReplicationInducingAPIsBurstRatioPerInstance.Key(): 1,
|
|
dynamicconfig.FrontendNamespaceReplicationInducingAPIsRPS.Key(): 1000,
|
|
|
|
// Make drainage happen sooner
|
|
dynamicconfig.VersionDrainageStatusRefreshInterval.Key(): testVersionDrainageRefreshInterval,
|
|
dynamicconfig.VersionDrainageStatusVisibilityGracePeriod.Key(): testVersionDrainageVisibilityGracePeriod,
|
|
}))
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) SetupTest() {
|
|
s.FunctionalTestSuite.SetupTest()
|
|
}
|
|
|
|
// pollFromDeployment calls PollWorkflowTaskQueue to start deployment related workflows
|
|
func (s *WorkerDeploymentSuite) pollFromDeployment(ctx context.Context, tv *testvars.TestVars) {
|
|
_, _ = s.FrontendClient().PollWorkflowTaskQueue(ctx, &workflowservice.PollWorkflowTaskQueueRequest{
|
|
Namespace: s.Namespace().String(),
|
|
TaskQueue: tv.TaskQueue(),
|
|
Identity: "random",
|
|
DeploymentOptions: tv.WorkerDeploymentOptions(true),
|
|
})
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) pollFromDeploymentExpectFail(ctx context.Context, tv *testvars.TestVars) {
|
|
_, err := s.FrontendClient().PollWorkflowTaskQueue(ctx, &workflowservice.PollWorkflowTaskQueueRequest{
|
|
Namespace: s.Namespace().String(),
|
|
TaskQueue: tv.TaskQueue(),
|
|
Identity: "random",
|
|
DeploymentOptions: tv.WorkerDeploymentOptions(true),
|
|
})
|
|
s.Error(err)
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) ensureCreateVersion(ctx context.Context, tv *testvars.TestVars) {
|
|
s.Eventually(func() bool {
|
|
respV, _ := s.FrontendClient().DescribeWorkerDeploymentVersion(ctx, &workflowservice.DescribeWorkerDeploymentVersionRequest{
|
|
Namespace: s.Namespace().String(),
|
|
Version: tv.DeploymentVersionString(),
|
|
})
|
|
return len(respV.GetWorkerDeploymentVersionInfo().GetTaskQueueInfos()) > 0
|
|
}, 5*time.Second, 100*time.Millisecond)
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) ensureCreateVersionInDeployment(
|
|
tv *testvars.TestVars,
|
|
) {
|
|
v := tv.DeploymentVersionString()
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
res, _ := s.FrontendClient().DescribeWorkerDeployment(ctx,
|
|
&workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
})
|
|
|
|
found := false
|
|
if res != nil {
|
|
for _, vs := range res.GetWorkerDeploymentInfo().GetVersionSummaries() {
|
|
if vs.GetVersion() == v {
|
|
found = true
|
|
}
|
|
}
|
|
}
|
|
a.True(found)
|
|
}, 5*time.Second, 100*time.Millisecond)
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) ensureCreateDeployment(
|
|
tv *testvars.TestVars,
|
|
) {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
res, _ := s.FrontendClient().DescribeWorkerDeployment(ctx,
|
|
&workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
})
|
|
a.NotNil(res)
|
|
}, 5*time.Second, 100*time.Millisecond)
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) startVersionWorkflow(ctx context.Context, tv *testvars.TestVars) {
|
|
go s.pollFromDeployment(ctx, tv)
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
resp, err := s.FrontendClient().DescribeWorkerDeploymentVersion(ctx, &workflowservice.DescribeWorkerDeploymentVersionRequest{
|
|
Namespace: s.Namespace().String(),
|
|
Version: tv.DeploymentVersionString(),
|
|
})
|
|
a.NoError(err)
|
|
a.Equal(tv.DeploymentVersionString(), resp.GetWorkerDeploymentVersionInfo().GetVersion())
|
|
}, time.Second*5, time.Millisecond*200)
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) TestForceCAN_NoOpenWFS() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
|
|
defer cancel()
|
|
tv := testvars.New(s)
|
|
|
|
// Start a version workflow
|
|
s.startVersionWorkflow(ctx, tv)
|
|
s.ensureCreateVersionInDeployment(tv)
|
|
|
|
// Set the version as current
|
|
_, err := s.FrontendClient().SetWorkerDeploymentCurrentVersion(ctx, &workflowservice.SetWorkerDeploymentCurrentVersionRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
Version: tv.DeploymentVersionString(),
|
|
})
|
|
s.NoError(err)
|
|
|
|
// ForceCAN
|
|
workflowID := worker_versioning.GenerateDeploymentWorkflowID(tv.DeploymentSeries())
|
|
workflowExecution := &commonpb.WorkflowExecution{
|
|
WorkflowId: workflowID,
|
|
}
|
|
|
|
err = s.SendSignal(s.Namespace().String(), workflowExecution, workerdeployment.ForceCANSignalName, nil, tv.ClientIdentity())
|
|
s.NoError(err)
|
|
|
|
// Verify if the state is intact even after a CAN
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
})
|
|
a.NoError(err)
|
|
a.Equal(tv.DeploymentVersionString(), resp.GetWorkerDeploymentInfo().GetRoutingConfig().GetCurrentVersion())
|
|
}, time.Second*10, time.Millisecond*1000)
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) TestDeploymentVersionLimits() {
|
|
// TODO (carly): check the error messages that poller receives in each case and make sense they are informative and appropriate (e.g. do not expose internal stuff)
|
|
|
|
s.OverrideDynamicConfig(dynamicconfig.MatchingMaxVersionsInDeployment, 1)
|
|
s.OverrideDynamicConfig(dynamicconfig.MatchingMaxTaskQueuesInDeploymentVersion, 1)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
|
defer cancel()
|
|
|
|
tv := testvars.New(s)
|
|
|
|
// First deployment version should be fine
|
|
go s.pollFromDeployment(ctx, tv)
|
|
s.ensureCreateVersionInDeployment(tv)
|
|
|
|
// pollers of second version in the same deployment should be rejected
|
|
s.pollFromDeploymentExpectFail(ctx, tv.WithBuildIDNumber(2))
|
|
|
|
// But first version of another deployment fine
|
|
tv2 := tv.WithDeploymentSeriesNumber(2)
|
|
go s.pollFromDeployment(ctx, tv2)
|
|
s.ensureCreateVersionInDeployment(tv2)
|
|
|
|
// pollers of the second TQ in the same deployment version should be rejected
|
|
s.pollFromDeploymentExpectFail(ctx, tv.WithTaskQueueNumber(2))
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) TestNamespaceDeploymentsLimit() {
|
|
// TODO (carly): check the error messages that poller receives in each case and make sense they are informative and appropriate (e.g. do not expose internal stuff)
|
|
s.T().Skip() // Need to separate this test so other tests do not create deployment in the same NS
|
|
|
|
s.OverrideDynamicConfig(dynamicconfig.MatchingMaxDeployments, 1)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
|
defer cancel()
|
|
|
|
tv := testvars.New(s)
|
|
|
|
// First deployment version should be fine
|
|
go s.pollFromDeployment(ctx, tv)
|
|
s.ensureCreateVersionInDeployment(tv)
|
|
|
|
// pollers of the second deployment version should be rejected
|
|
s.pollFromDeploymentExpectFail(ctx, tv.WithDeploymentSeriesNumber(2))
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) TestDescribeWorkerDeployment_TwoVersions_Sorted() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
|
defer cancel()
|
|
tv := testvars.New(s)
|
|
|
|
// Starting two versions of the deployment
|
|
firstVersion := tv.WithBuildIDNumber(1)
|
|
secondVersion := tv.WithBuildIDNumber(2)
|
|
|
|
go s.pollFromDeployment(ctx, firstVersion)
|
|
|
|
// waiting for 1ms to start the second version later.
|
|
startTime := time.Now()
|
|
waitTime := 1 * time.Millisecond
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
a.Greater(time.Since(startTime), waitTime)
|
|
}, 10*time.Second, 1000*time.Millisecond)
|
|
|
|
go s.pollFromDeployment(ctx, secondVersion)
|
|
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
})
|
|
a.NoError(err)
|
|
a.NotNil(resp.GetWorkerDeploymentInfo())
|
|
a.Equal(tv.DeploymentSeries(), resp.GetWorkerDeploymentInfo().GetName())
|
|
|
|
a.NotNil(resp.GetWorkerDeploymentInfo().GetVersionSummaries())
|
|
a.Equal(2, len(resp.GetWorkerDeploymentInfo().GetVersionSummaries()))
|
|
|
|
if len(resp.GetWorkerDeploymentInfo().GetVersionSummaries()) < 2 {
|
|
return
|
|
}
|
|
// Verify that the version summaries are non-nil and sorted.
|
|
versionSummaries := resp.GetWorkerDeploymentInfo().GetVersionSummaries()
|
|
|
|
a.NotNil(versionSummaries[0].GetVersion())
|
|
a.NotNil(versionSummaries[1].GetVersion())
|
|
a.Equal(versionSummaries[0].GetVersion(), secondVersion.DeploymentVersionString())
|
|
a.Equal(versionSummaries[1].GetVersion(), firstVersion.DeploymentVersionString())
|
|
|
|
a.NotNil(resp.GetWorkerDeploymentInfo().GetVersionSummaries()[0].GetCreateTime())
|
|
a.NotNil(resp.GetWorkerDeploymentInfo().GetVersionSummaries()[1].GetCreateTime())
|
|
|
|
a.NotNil(resp.GetWorkerDeploymentInfo().GetCreateTime())
|
|
}, time.Second*10, time.Millisecond*1000)
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) TestDescribeWorkerDeployment_MultipleVersions_Sorted() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
|
defer cancel()
|
|
tv := testvars.New(s)
|
|
|
|
numVersions := 10
|
|
|
|
for i := 0; i < numVersions; i++ {
|
|
go s.pollFromDeployment(ctx, tv.WithBuildIDNumber(i))
|
|
|
|
// waiting for 1ms to start the next version later.
|
|
startTime := time.Now()
|
|
waitTime := 1 * time.Millisecond
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
a.Greater(time.Since(startTime), waitTime)
|
|
}, 10*time.Second, 1000*time.Millisecond)
|
|
}
|
|
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
})
|
|
a.NoError(err)
|
|
|
|
a.NotNil(resp.GetWorkerDeploymentInfo().GetVersionSummaries())
|
|
a.Equal(numVersions, len(resp.GetWorkerDeploymentInfo().GetVersionSummaries()))
|
|
|
|
if len(resp.GetWorkerDeploymentInfo().GetVersionSummaries()) < numVersions {
|
|
return
|
|
}
|
|
|
|
// Verify that the version summaries are sorted.
|
|
versionSummaries := resp.GetWorkerDeploymentInfo().GetVersionSummaries()
|
|
for i := 0; i < numVersions-1; i++ {
|
|
a.Less(versionSummaries[i+1].GetCreateTime().AsTime(), versionSummaries[i].GetCreateTime().AsTime())
|
|
}
|
|
}, time.Second*10, time.Millisecond*1000)
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) TestDescribeWorkerDeployment_SetCurrentVersion() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
|
defer cancel()
|
|
tv := testvars.New(s)
|
|
|
|
firstVersion := tv.WithBuildIDNumber(1)
|
|
secondVersion := tv.WithBuildIDNumber(2)
|
|
|
|
go s.pollFromDeployment(ctx, firstVersion)
|
|
|
|
// No current deployment version set.
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
})
|
|
a.NoError(err)
|
|
a.Equal(worker_versioning.UnversionedVersionId, resp.GetWorkerDeploymentInfo().GetRoutingConfig().GetCurrentVersion())
|
|
}, time.Second*10, time.Millisecond*1000)
|
|
|
|
// Set first version as current version
|
|
s.setCurrentVersion(ctx, firstVersion, worker_versioning.UnversionedVersionId, true, "")
|
|
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
})
|
|
a.NoError(err)
|
|
a.Equal(firstVersion.DeploymentVersionString(), resp.GetWorkerDeploymentInfo().GetRoutingConfig().GetCurrentVersion())
|
|
a.Equal(tv.ClientIdentity(), resp.GetWorkerDeploymentInfo().GetLastModifierIdentity())
|
|
}, time.Second*10, time.Millisecond*1000)
|
|
|
|
// Set a new second version and set it as the current version
|
|
go s.pollFromDeployment(ctx, secondVersion)
|
|
s.setCurrentVersion(ctx, secondVersion, firstVersion.DeploymentVersionString(), true, "")
|
|
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
})
|
|
a.NoError(err)
|
|
a.Equal(secondVersion.DeploymentVersionString(), resp.GetWorkerDeploymentInfo().GetRoutingConfig().GetCurrentVersion())
|
|
firstSummary := slices.IndexFunc(resp.GetWorkerDeploymentInfo().GetVersionSummaries(),
|
|
func(summary *deploymentpb.WorkerDeploymentInfo_WorkerDeploymentVersionSummary) bool {
|
|
return summary.GetVersion() == firstVersion.DeploymentVersionString()
|
|
})
|
|
a.Greater(firstSummary, -1)
|
|
a.Equal(enumspb.VERSION_DRAINAGE_STATUS_DRAINING, resp.GetWorkerDeploymentInfo().GetVersionSummaries()[firstSummary].GetDrainageStatus())
|
|
}, time.Second*10, time.Millisecond*1000)
|
|
}
|
|
|
|
// Testing Concurrent stale updates don't break workflow state and are caught in the update handler
|
|
func (s *WorkerDeploymentSuite) TestSetCurrentVersion_ConcurrentUpdates_NonIdempotentRequests() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
|
defer cancel()
|
|
tv := testvars.New(s)
|
|
|
|
go s.pollFromDeployment(ctx, tv)
|
|
|
|
var cT []byte
|
|
// No current deployment version set.
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
})
|
|
a.NoError(err)
|
|
a.Equal(worker_versioning.UnversionedVersionId, resp.GetWorkerDeploymentInfo().GetRoutingConfig().GetCurrentVersion())
|
|
cT = resp.GetConflictToken()
|
|
}, time.Second*10, time.Millisecond*1000)
|
|
s.ensureCreateVersionInDeployment(tv)
|
|
|
|
// Simulate two concurrent updates with the same updateID but with different identities.
|
|
var wg sync.WaitGroup
|
|
wg.Add(2)
|
|
|
|
var err1, err2 error
|
|
|
|
go func() {
|
|
defer wg.Done()
|
|
_, err1 = s.FrontendClient().SetWorkerDeploymentCurrentVersion(ctx, &workflowservice.SetWorkerDeploymentCurrentVersionRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
Version: tv.DeploymentVersionString(),
|
|
ConflictToken: cT,
|
|
Identity: tv.ClientIdentity(),
|
|
})
|
|
}()
|
|
|
|
// To allow the first go-routine to start before the second one.
|
|
//nolint:forbidigo
|
|
time.Sleep(1 * time.Millisecond)
|
|
|
|
go func() {
|
|
defer wg.Done()
|
|
_, err2 = s.FrontendClient().SetWorkerDeploymentCurrentVersion(ctx, &workflowservice.SetWorkerDeploymentCurrentVersionRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
Version: tv.DeploymentVersionString(),
|
|
ConflictToken: cT,
|
|
Identity: tv.Any().String(), // note: different identity
|
|
})
|
|
}()
|
|
|
|
wg.Wait()
|
|
|
|
s.NoError(err1)
|
|
// Since the first update completed successfully, the second update will be rejected inside the update handler due to a conflict token mismatch. This happens
|
|
// since the first update changes the conflict token of the worker-deployment workflow.
|
|
s.Error(err2)
|
|
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
})
|
|
a.NoError(err)
|
|
a.Equal(tv.DeploymentVersionString(), resp.GetWorkerDeploymentInfo().GetRoutingConfig().GetCurrentVersion())
|
|
a.Equal(tv.ClientIdentity(), resp.GetWorkerDeploymentInfo().GetLastModifierIdentity())
|
|
}, time.Second*10, time.Millisecond*1000)
|
|
|
|
}
|
|
|
|
// Testing Concurrent identical updates are being de-duped.
|
|
func (s *WorkerDeploymentSuite) TestSetCurrentVersion_ConcurrentUpdates_IdempotentRequests() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
|
defer cancel()
|
|
tv := testvars.New(s)
|
|
|
|
go s.pollFromDeployment(ctx, tv)
|
|
|
|
var cT []byte
|
|
// No current deployment version set.
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
})
|
|
a.NoError(err)
|
|
a.Equal(worker_versioning.UnversionedVersionId, resp.GetWorkerDeploymentInfo().GetRoutingConfig().GetCurrentVersion())
|
|
cT = resp.GetConflictToken()
|
|
}, time.Second*10, time.Millisecond*1000)
|
|
s.ensureCreateVersionInDeployment(tv)
|
|
|
|
// Simulate two concurrent identical updates.
|
|
var wg sync.WaitGroup
|
|
wg.Add(2)
|
|
|
|
var err1, err2 error
|
|
var resp1, resp2 *workflowservice.SetWorkerDeploymentCurrentVersionResponse
|
|
go func() {
|
|
defer wg.Done()
|
|
resp1, err1 = s.FrontendClient().SetWorkerDeploymentCurrentVersion(ctx, &workflowservice.SetWorkerDeploymentCurrentVersionRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
Version: tv.DeploymentVersionString(),
|
|
Identity: tv.ClientIdentity(),
|
|
ConflictToken: cT,
|
|
})
|
|
}()
|
|
|
|
// To allow the first go-routine to start before the second one.
|
|
//nolint:forbidigo
|
|
time.Sleep(2 * time.Millisecond)
|
|
|
|
go func() {
|
|
defer wg.Done()
|
|
resp2, err2 = s.FrontendClient().SetWorkerDeploymentCurrentVersion(ctx, &workflowservice.SetWorkerDeploymentCurrentVersionRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
Version: tv.DeploymentVersionString(),
|
|
Identity: tv.ClientIdentity(),
|
|
ConflictToken: []byte{}, // note: different conflict token
|
|
})
|
|
}()
|
|
|
|
wg.Wait()
|
|
|
|
s.NoError(err1)
|
|
s.NoError(err2)
|
|
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
})
|
|
a.NoError(err)
|
|
a.Equal(tv.DeploymentVersionString(), resp.GetWorkerDeploymentInfo().GetRoutingConfig().GetCurrentVersion())
|
|
a.Equal(tv.ClientIdentity(), resp.GetWorkerDeploymentInfo().GetLastModifierIdentity()) // note: the last modifier identity should be the one from the first update
|
|
}, time.Second*10, time.Millisecond*1000)
|
|
|
|
// Since both the updates are accepted, the response objects will be different.
|
|
|
|
// Since the first update completes successfully, the previous version will be __unversioned__
|
|
s.Equal(worker_versioning.UnversionedVersionId, resp1.GetPreviousVersion())
|
|
// Since the second update was de-duped in the update handler, the previous version will be the current version which is the version from the first update
|
|
s.Equal(tv.DeploymentVersionString(), resp2.GetPreviousVersion())
|
|
|
|
// The conflict token should be the same as the one set from the first update
|
|
s.Equal(resp1.GetConflictToken(), resp2.GetConflictToken())
|
|
}
|
|
|
|
// Testing Concurrent stale updates don't break workflow state and are caught in the update handler
|
|
func (s *WorkerDeploymentSuite) TestSetRampingVersion_ConcurrentUpdates_NonIdempotentRequests() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
|
defer cancel()
|
|
tv := testvars.New(s)
|
|
|
|
go s.pollFromDeployment(ctx, tv)
|
|
|
|
var cT []byte
|
|
// No ramping deployment version set.
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
})
|
|
a.NoError(err)
|
|
a.Equal("", resp.GetWorkerDeploymentInfo().GetRoutingConfig().GetRampingVersion())
|
|
cT = resp.GetConflictToken()
|
|
}, time.Second*10, time.Millisecond*1000)
|
|
s.ensureCreateVersionInDeployment(tv)
|
|
|
|
// Simulate two concurrent updates with the same updateID but with different identities.
|
|
var wg sync.WaitGroup
|
|
wg.Add(2)
|
|
|
|
var err1, err2 error
|
|
|
|
go func() {
|
|
defer wg.Done()
|
|
_, err1 = s.FrontendClient().SetWorkerDeploymentRampingVersion(ctx, &workflowservice.SetWorkerDeploymentRampingVersionRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
Version: tv.DeploymentVersionString(),
|
|
Percentage: 5,
|
|
ConflictToken: cT,
|
|
Identity: tv.ClientIdentity(),
|
|
})
|
|
}()
|
|
|
|
// To allow the first go-routine to start before the second one.
|
|
//nolint:forbidigo
|
|
time.Sleep(2 * time.Millisecond)
|
|
|
|
go func() {
|
|
defer wg.Done()
|
|
_, err2 = s.FrontendClient().SetWorkerDeploymentRampingVersion(ctx, &workflowservice.SetWorkerDeploymentRampingVersionRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
Version: tv.DeploymentVersionString(),
|
|
Percentage: 5,
|
|
ConflictToken: cT,
|
|
Identity: tv.Any().String(), // note: different identity
|
|
})
|
|
}()
|
|
|
|
wg.Wait()
|
|
|
|
s.NoError(err1)
|
|
// Since the first update completed successfully, the second update will be rejected inside the update handler due to a conflict token mismatch. This happens
|
|
// since the first update changes the conflict token of the worker-deployment workflow.
|
|
s.Error(err2)
|
|
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
})
|
|
a.NoError(err)
|
|
a.Equal(tv.DeploymentVersionString(), resp.GetWorkerDeploymentInfo().GetRoutingConfig().GetRampingVersion())
|
|
a.Equal(tv.ClientIdentity(), resp.GetWorkerDeploymentInfo().GetLastModifierIdentity())
|
|
}, time.Second*10, time.Millisecond*1000)
|
|
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) TestSetRampingVersion_ConcurrentUpdates_IdempotentRequests() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
|
defer cancel()
|
|
tv := testvars.New(s)
|
|
|
|
go s.pollFromDeployment(ctx, tv)
|
|
|
|
var cT []byte
|
|
// No ramping deployment version set.
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
})
|
|
a.NoError(err)
|
|
a.Equal("", resp.GetWorkerDeploymentInfo().GetRoutingConfig().GetRampingVersion())
|
|
cT = resp.GetConflictToken()
|
|
}, time.Second*10, time.Millisecond*1000)
|
|
s.ensureCreateVersionInDeployment(tv)
|
|
|
|
// Simulate two concurrent identical updates.
|
|
var wg sync.WaitGroup
|
|
wg.Add(2)
|
|
|
|
var err1, err2 error
|
|
var resp1, resp2 *workflowservice.SetWorkerDeploymentRampingVersionResponse
|
|
go func() {
|
|
defer wg.Done()
|
|
resp1, err1 = s.FrontendClient().SetWorkerDeploymentRampingVersion(ctx, &workflowservice.SetWorkerDeploymentRampingVersionRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
Version: tv.DeploymentVersionString(),
|
|
Identity: tv.ClientIdentity(),
|
|
ConflictToken: cT,
|
|
})
|
|
}()
|
|
|
|
// To allow the first go-routine to start before the second one.
|
|
//nolint:forbidigo
|
|
time.Sleep(2 * time.Millisecond)
|
|
|
|
go func() {
|
|
defer wg.Done()
|
|
resp2, err2 = s.FrontendClient().SetWorkerDeploymentRampingVersion(ctx, &workflowservice.SetWorkerDeploymentRampingVersionRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
Version: tv.DeploymentVersionString(),
|
|
Identity: tv.ClientIdentity(),
|
|
ConflictToken: []byte{}, // note: different conflict token
|
|
})
|
|
}()
|
|
|
|
wg.Wait()
|
|
|
|
s.NoError(err1)
|
|
s.NoError(err2)
|
|
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
})
|
|
a.NoError(err)
|
|
a.Equal(tv.DeploymentVersionString(), resp.GetWorkerDeploymentInfo().GetRoutingConfig().GetRampingVersion())
|
|
a.Equal(tv.ClientIdentity(), resp.GetWorkerDeploymentInfo().GetLastModifierIdentity()) // note: the last modifier identity should be the one from the first update
|
|
}, time.Second*10, time.Millisecond*1000)
|
|
|
|
// Since the first update completes successfully, the previous version will be ""
|
|
s.Equal("", resp1.GetPreviousVersion())
|
|
// Since the second update was de-duped in the update handler, the previous version will be the current ramping version which is the version from the first update
|
|
s.Equal(tv.DeploymentVersionString(), resp2.GetPreviousVersion())
|
|
|
|
// The conflict token should be the same as the one set from the first update
|
|
s.Equal(resp1.GetConflictToken(), resp2.GetConflictToken())
|
|
}
|
|
|
|
// Testing ConflictToken
|
|
func (s *WorkerDeploymentSuite) TestConflictToken_Describe_SetCurrent_SetRamping() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
|
defer cancel()
|
|
tv := testvars.New(s)
|
|
|
|
firstVersion := tv.WithBuildIDNumber(1)
|
|
secondVersion := tv.WithBuildIDNumber(2)
|
|
|
|
// Start deployment version workflow + worker-deployment workflow.
|
|
go s.pollFromDeployment(ctx, firstVersion)
|
|
go s.pollFromDeployment(ctx, secondVersion)
|
|
|
|
var cT []byte
|
|
// No current deployment version set.
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
})
|
|
a.NoError(err)
|
|
a.Equal(worker_versioning.UnversionedVersionId, resp.GetWorkerDeploymentInfo().GetRoutingConfig().GetCurrentVersion())
|
|
cT = resp.GetConflictToken()
|
|
}, time.Second*10, time.Millisecond*1000)
|
|
|
|
s.ensureCreateVersionInDeployment(firstVersion)
|
|
// Set first version as current version
|
|
_, err := s.FrontendClient().SetWorkerDeploymentCurrentVersion(ctx, &workflowservice.SetWorkerDeploymentCurrentVersionRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
Version: firstVersion.DeploymentVersionString(),
|
|
ConflictToken: cT,
|
|
})
|
|
s.Nil(err)
|
|
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
})
|
|
a.NoError(err)
|
|
a.Equal(firstVersion.DeploymentVersionString(), resp.GetWorkerDeploymentInfo().GetRoutingConfig().GetCurrentVersion())
|
|
cT = resp.GetConflictToken()
|
|
}, time.Second*10, time.Millisecond*1000)
|
|
|
|
// Set a new second version and set it as the current version
|
|
go s.pollFromDeployment(ctx, secondVersion)
|
|
_, _ = s.FrontendClient().SetWorkerDeploymentRampingVersion(ctx, &workflowservice.SetWorkerDeploymentRampingVersionRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
Version: secondVersion.DeploymentVersionString(),
|
|
Percentage: 5,
|
|
ConflictToken: cT,
|
|
IgnoreMissingTaskQueues: true, // here until we have 'has version started' safeguard in place
|
|
})
|
|
s.Nil(err)
|
|
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
})
|
|
a.NoError(err)
|
|
a.Equal(secondVersion.DeploymentVersionString(), resp.GetWorkerDeploymentInfo().GetRoutingConfig().GetRampingVersion())
|
|
}, time.Second*10, time.Millisecond*1000)
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) TestConflictToken_SetCurrent_SetRamping_Wrong() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
|
defer cancel()
|
|
tv := testvars.New(s)
|
|
|
|
firstVersion := tv.WithBuildIDNumber(1)
|
|
|
|
// Start deployment version workflow + worker-deployment workflow.
|
|
go s.pollFromDeployment(ctx, firstVersion)
|
|
|
|
cTWrong, _ := time.Now().MarshalBinary() // wrong token
|
|
// Wait until deployment exists
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
})
|
|
a.NoError(err)
|
|
a.Equal(worker_versioning.UnversionedVersionId, resp.GetWorkerDeploymentInfo().GetRoutingConfig().GetCurrentVersion())
|
|
}, time.Second*10, time.Millisecond*1000)
|
|
|
|
// Set first version as current version with wrong token
|
|
_, err := s.FrontendClient().SetWorkerDeploymentCurrentVersion(ctx, &workflowservice.SetWorkerDeploymentCurrentVersionRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
Version: firstVersion.DeploymentVersionString(),
|
|
ConflictToken: cTWrong,
|
|
})
|
|
s.NotNil(err)
|
|
|
|
// Set first version as ramping version with wrong token
|
|
_, err = s.FrontendClient().SetWorkerDeploymentRampingVersion(ctx, &workflowservice.SetWorkerDeploymentRampingVersionRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
Version: firstVersion.DeploymentVersionString(),
|
|
Percentage: 5,
|
|
ConflictToken: cTWrong,
|
|
})
|
|
s.NotNil(err)
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) TestSetCurrent_NoDeploymentVersion() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
|
defer cancel()
|
|
tv := testvars.New(s)
|
|
|
|
// Setting version as current version should error since there is no created deployment version
|
|
_, err := s.FrontendClient().SetWorkerDeploymentCurrentVersion(ctx, &workflowservice.SetWorkerDeploymentCurrentVersionRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentVersion().GetDeploymentName(),
|
|
Version: tv.DeploymentVersionString(),
|
|
IgnoreMissingTaskQueues: true,
|
|
})
|
|
s.Error(err)
|
|
s.Contains(err.Error(), "workflow not found for ID")
|
|
}
|
|
func (s *WorkerDeploymentSuite) TestSetCurrentVersion_Idempotent() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
|
defer cancel()
|
|
tv := testvars.New(s)
|
|
|
|
firstVersion := tv.WithBuildIDNumber(1)
|
|
|
|
s.startVersionWorkflow(ctx, firstVersion)
|
|
|
|
// Set first version as current version
|
|
s.setCurrentVersion(ctx, firstVersion, worker_versioning.UnversionedVersionId, true, "")
|
|
|
|
// Set first version as current version again
|
|
s.setCurrentVersion(ctx, firstVersion, firstVersion.DeploymentVersionString(), true, "")
|
|
}
|
|
|
|
// Testing ListWorkerDeployments
|
|
|
|
func (s *WorkerDeploymentSuite) TestListWorkerDeployments_OneVersion_OneDeployment() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
|
defer cancel()
|
|
tv := testvars.New(s)
|
|
|
|
s.startVersionWorkflow(ctx, tv)
|
|
|
|
expectedDeploymentSummaries := s.buildWorkerDeploymentSummary(
|
|
tv.DeploymentSeries(),
|
|
timestamppb.Now(),
|
|
&deploymentpb.RoutingConfig{
|
|
CurrentVersion: worker_versioning.UnversionedVersionId, // default current version is __unversioned__
|
|
},
|
|
)
|
|
|
|
s.startAndValidateWorkerDeployments(ctx, &workflowservice.ListWorkerDeploymentsRequest{
|
|
Namespace: s.Namespace().String(),
|
|
}, []*workflowservice.ListWorkerDeploymentsResponse_WorkerDeploymentSummary{expectedDeploymentSummaries})
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) TestListWorkerDeployments_TwoVersions_SameDeployment_OneCurrent_NoRamping() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
|
defer cancel()
|
|
tv := testvars.New(s)
|
|
|
|
firstVersion := tv.WithBuildIDNumber(1)
|
|
secondVersion := tv.WithBuildIDNumber(2)
|
|
|
|
routingInfo := &deploymentpb.RoutingConfig{
|
|
CurrentVersion: firstVersion.DeploymentVersionString(),
|
|
CurrentVersionChangedTime: timestamppb.Now(),
|
|
}
|
|
|
|
s.startVersionWorkflow(ctx, firstVersion)
|
|
s.startVersionWorkflow(ctx, secondVersion)
|
|
|
|
s.setCurrentVersion(ctx, firstVersion, worker_versioning.UnversionedVersionId, true, "")
|
|
expectedDeploymentSummary := s.buildWorkerDeploymentSummary(
|
|
tv.DeploymentSeries(),
|
|
timestamppb.Now(),
|
|
routingInfo,
|
|
)
|
|
|
|
s.startAndValidateWorkerDeployments(ctx, &workflowservice.ListWorkerDeploymentsRequest{
|
|
Namespace: s.Namespace().String(),
|
|
}, []*workflowservice.ListWorkerDeploymentsResponse_WorkerDeploymentSummary{
|
|
expectedDeploymentSummary,
|
|
})
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) TestListWorkerDeployments_TwoVersions_SameDeployment_OneCurrent_OneRamping() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
|
defer cancel()
|
|
tv := testvars.New(s)
|
|
|
|
currentVersionVars := tv.WithBuildIDNumber(1)
|
|
rampingVersionVars := tv.WithBuildIDNumber(2)
|
|
|
|
routingInfo := &deploymentpb.RoutingConfig{
|
|
CurrentVersion: currentVersionVars.DeploymentVersionString(),
|
|
CurrentVersionChangedTime: timestamppb.Now(),
|
|
RampingVersion: rampingVersionVars.DeploymentVersionString(),
|
|
RampingVersionPercentage: 50,
|
|
RampingVersionChangedTime: timestamppb.Now(),
|
|
}
|
|
|
|
s.startVersionWorkflow(ctx, currentVersionVars)
|
|
s.startVersionWorkflow(ctx, rampingVersionVars)
|
|
|
|
s.setCurrentVersion(ctx, currentVersionVars, worker_versioning.UnversionedVersionId, true, "") // starts first version's version workflow + set it to current
|
|
s.setAndVerifyRampingVersion(ctx, rampingVersionVars, false, 50, true, "", &workflowservice.SetWorkerDeploymentRampingVersionResponse{
|
|
PreviousVersion: "",
|
|
PreviousPercentage: 0,
|
|
}) // starts second version's version workflow + set it to ramping
|
|
|
|
expectedDeploymentSummary := s.buildWorkerDeploymentSummary(
|
|
tv.DeploymentSeries(),
|
|
timestamppb.Now(),
|
|
routingInfo,
|
|
)
|
|
|
|
s.startAndValidateWorkerDeployments(ctx, &workflowservice.ListWorkerDeploymentsRequest{
|
|
Namespace: s.Namespace().String(),
|
|
}, []*workflowservice.ListWorkerDeploymentsResponse_WorkerDeploymentSummary{
|
|
expectedDeploymentSummary,
|
|
})
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) TestListWorkerDeployments_RampingVersionPercentageChange_RampingChangedTime() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
|
defer cancel()
|
|
tv := testvars.New(s)
|
|
|
|
s.startVersionWorkflow(ctx, tv)
|
|
s.setAndVerifyRampingVersion(ctx, tv, false, 50, true, "", nil) // set version as ramping
|
|
rampingVersionChangedTime := timestamppb.Now()
|
|
|
|
routingInfo := &deploymentpb.RoutingConfig{
|
|
CurrentVersion: worker_versioning.UnversionedVersionId,
|
|
CurrentVersionChangedTime: nil,
|
|
RampingVersion: tv.DeploymentVersionString(),
|
|
RampingVersionPercentage: 50,
|
|
RampingVersionChangedTime: rampingVersionChangedTime,
|
|
}
|
|
|
|
// to simulate time passing before the next ramping version update
|
|
//nolint:forbidigo
|
|
time.Sleep(2 * time.Second)
|
|
|
|
// modify ramping version percentage
|
|
s.setAndVerifyRampingVersion(ctx, tv, false, 75, true, "", &workflowservice.SetWorkerDeploymentRampingVersionResponse{
|
|
PreviousVersion: tv.DeploymentVersionString(),
|
|
PreviousPercentage: 50,
|
|
})
|
|
|
|
// only the ramping version percentage should be updated, not the ramping version update time
|
|
// since we are not changing the ramping version
|
|
routingInfo.RampingVersionPercentage = 75
|
|
|
|
expectedDeploymentSummary := s.buildWorkerDeploymentSummary(
|
|
tv.DeploymentSeries(),
|
|
rampingVersionChangedTime,
|
|
routingInfo,
|
|
)
|
|
|
|
s.startAndValidateWorkerDeployments(ctx, &workflowservice.ListWorkerDeploymentsRequest{
|
|
Namespace: s.Namespace().String(),
|
|
}, []*workflowservice.ListWorkerDeploymentsResponse_WorkerDeploymentSummary{
|
|
expectedDeploymentSummary,
|
|
})
|
|
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) TestListWorkerDeployments_MultipleVersions_MultipleDeployments_OnePage() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
|
defer cancel()
|
|
tv := testvars.New(s)
|
|
|
|
expectedDeploymentSummaries := s.createVersionsInDeployments(ctx, tv, 2)
|
|
|
|
s.startAndValidateWorkerDeployments(ctx, &workflowservice.ListWorkerDeploymentsRequest{
|
|
Namespace: s.Namespace().String(),
|
|
}, expectedDeploymentSummaries)
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) TestListWorkerDeployments_MultipleVersions_MultipleDeployments_MultiplePages() {
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer cancel()
|
|
tv := testvars.New(s)
|
|
|
|
expectedDeploymentSummaries := s.createVersionsInDeployments(ctx, tv, 5)
|
|
|
|
s.startAndValidateWorkerDeployments(ctx, &workflowservice.ListWorkerDeploymentsRequest{
|
|
Namespace: s.Namespace().String(),
|
|
PageSize: 1,
|
|
}, expectedDeploymentSummaries)
|
|
}
|
|
|
|
// Testing SetWorkerDeploymentRampingVersion
|
|
func (s *WorkerDeploymentSuite) TestSetWorkerDeploymentRampingVersion_Ramping_With_Current() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
|
defer cancel()
|
|
tv := testvars.New(s)
|
|
|
|
rampingVersionVars := tv.WithBuildIDNumber(1)
|
|
currentVersionVars := tv.WithBuildIDNumber(2)
|
|
|
|
s.startVersionWorkflow(ctx, rampingVersionVars)
|
|
s.startVersionWorkflow(ctx, currentVersionVars)
|
|
|
|
// set version as ramping
|
|
s.setAndVerifyRampingVersion(ctx, rampingVersionVars, false, 50, true, "", &workflowservice.SetWorkerDeploymentRampingVersionResponse{
|
|
PreviousVersion: "",
|
|
PreviousPercentage: 0,
|
|
})
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
})
|
|
s.NoError(err)
|
|
s.verifyDescribeWorkerDeployment(resp, &workflowservice.DescribeWorkerDeploymentResponse{
|
|
WorkerDeploymentInfo: &deploymentpb.WorkerDeploymentInfo{
|
|
Name: tv.DeploymentSeries(),
|
|
RoutingConfig: &deploymentpb.RoutingConfig{
|
|
RampingVersion: rampingVersionVars.DeploymentVersionString(),
|
|
RampingVersionPercentage: 50,
|
|
RampingVersionChangedTime: timestamppb.Now(),
|
|
CurrentVersion: worker_versioning.UnversionedVersionId,
|
|
CurrentVersionChangedTime: nil,
|
|
},
|
|
LastModifierIdentity: tv.ClientIdentity(),
|
|
},
|
|
})
|
|
|
|
// set current version
|
|
s.setCurrentVersion(ctx, currentVersionVars, worker_versioning.UnversionedVersionId, true, "")
|
|
|
|
// fresh DescribeWorkerDeployment call
|
|
resp, err = s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
})
|
|
s.NoError(err)
|
|
s.verifyDescribeWorkerDeployment(resp, &workflowservice.DescribeWorkerDeploymentResponse{
|
|
WorkerDeploymentInfo: &deploymentpb.WorkerDeploymentInfo{
|
|
Name: tv.DeploymentSeries(),
|
|
RoutingConfig: &deploymentpb.RoutingConfig{
|
|
RampingVersion: rampingVersionVars.DeploymentVersionString(),
|
|
RampingVersionPercentage: 50,
|
|
RampingVersionChangedTime: timestamppb.Now(),
|
|
CurrentVersion: currentVersionVars.DeploymentVersionString(),
|
|
CurrentVersionChangedTime: timestamppb.Now(),
|
|
},
|
|
LastModifierIdentity: tv.ClientIdentity(),
|
|
},
|
|
})
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) TestSetWorkerDeploymentRampingVersion_DuplicateRamp() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
|
defer cancel()
|
|
rampingVersionVars := testvars.New(s).WithBuildIDNumber(1)
|
|
|
|
s.startVersionWorkflow(ctx, rampingVersionVars)
|
|
|
|
// set version as ramping
|
|
s.setAndVerifyRampingVersion(ctx, rampingVersionVars, false, 50, true, "", &workflowservice.SetWorkerDeploymentRampingVersionResponse{
|
|
PreviousVersion: "",
|
|
PreviousPercentage: 0,
|
|
})
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: rampingVersionVars.DeploymentSeries(),
|
|
})
|
|
s.NoError(err)
|
|
s.verifyDescribeWorkerDeployment(resp, &workflowservice.DescribeWorkerDeploymentResponse{
|
|
WorkerDeploymentInfo: &deploymentpb.WorkerDeploymentInfo{
|
|
Name: rampingVersionVars.DeploymentSeries(),
|
|
RoutingConfig: &deploymentpb.RoutingConfig{
|
|
RampingVersion: rampingVersionVars.DeploymentVersionString(),
|
|
RampingVersionPercentage: 50,
|
|
RampingVersionChangedTime: timestamppb.Now(),
|
|
CurrentVersion: worker_versioning.UnversionedVersionId,
|
|
CurrentVersionChangedTime: nil,
|
|
},
|
|
LastModifierIdentity: rampingVersionVars.ClientIdentity(),
|
|
},
|
|
})
|
|
|
|
// setting version as ramping again
|
|
s.setAndVerifyRampingVersion(ctx, rampingVersionVars, false, 50, true, "", &workflowservice.SetWorkerDeploymentRampingVersionResponse{
|
|
PreviousVersion: rampingVersionVars.DeploymentVersionString(),
|
|
PreviousPercentage: 50,
|
|
})
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) TestSetWorkerDeploymentRampingVersion_Invalid_SetCurrent_To_Ramping() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
|
defer cancel()
|
|
|
|
currentVersionVars := testvars.New(s).WithBuildIDNumber(1)
|
|
s.startVersionWorkflow(ctx, currentVersionVars)
|
|
s.setCurrentVersion(ctx, currentVersionVars, worker_versioning.UnversionedVersionId, true, "")
|
|
|
|
expectedError := fmt.Errorf("Ramping version %s is already current", currentVersionVars.DeploymentVersionString())
|
|
s.setAndVerifyRampingVersion(ctx, currentVersionVars, false, 50, true, expectedError.Error(), nil) // setting current version to ramping should fails
|
|
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: currentVersionVars.DeploymentSeries(),
|
|
})
|
|
s.NoError(err)
|
|
s.verifyDescribeWorkerDeployment(resp, &workflowservice.DescribeWorkerDeploymentResponse{
|
|
WorkerDeploymentInfo: &deploymentpb.WorkerDeploymentInfo{
|
|
Name: currentVersionVars.DeploymentSeries(),
|
|
RoutingConfig: &deploymentpb.RoutingConfig{
|
|
RampingVersion: "", // no ramping info should be set
|
|
RampingVersionPercentage: 0, // no ramping info should be set
|
|
RampingVersionChangedTime: nil, // no ramping info should be set
|
|
CurrentVersion: currentVersionVars.DeploymentVersionString(),
|
|
CurrentVersionChangedTime: timestamppb.Now(),
|
|
},
|
|
LastModifierIdentity: currentVersionVars.ClientIdentity(),
|
|
},
|
|
})
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) TestSetWorkerDeploymentRampingVersion_ModifyExistingRampVersionPercentage() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
|
defer cancel()
|
|
tv := testvars.New(s)
|
|
|
|
rampingVersionVars := tv.WithBuildIDNumber(1)
|
|
s.startVersionWorkflow(ctx, rampingVersionVars)
|
|
|
|
s.setAndVerifyRampingVersion(ctx, rampingVersionVars, false, 50, true, "", nil) // set version as ramping
|
|
|
|
// modify ramping version percentage
|
|
s.setAndVerifyRampingVersion(ctx, rampingVersionVars, false, 75, true, "", &workflowservice.SetWorkerDeploymentRampingVersionResponse{
|
|
PreviousVersion: rampingVersionVars.DeploymentVersionString(),
|
|
PreviousPercentage: 50,
|
|
})
|
|
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) TestSetWorkerDeploymentRampingVersion_WithCurrent_Unset_Ramp() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
|
defer cancel()
|
|
tv := testvars.New(s)
|
|
|
|
rampingVersionVars := tv.WithBuildIDNumber(1)
|
|
currentVersionVars := tv.WithBuildIDNumber(2)
|
|
|
|
s.startVersionWorkflow(ctx, rampingVersionVars)
|
|
s.startVersionWorkflow(ctx, currentVersionVars)
|
|
|
|
s.setAndVerifyRampingVersion(ctx, rampingVersionVars, false, 50, true, "", nil) // set version as ramping
|
|
s.setCurrentVersion(ctx, currentVersionVars, worker_versioning.UnversionedVersionId, true, "") // set version as curent
|
|
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
})
|
|
s.NoError(err)
|
|
s.verifyDescribeWorkerDeployment(resp, &workflowservice.DescribeWorkerDeploymentResponse{
|
|
WorkerDeploymentInfo: &deploymentpb.WorkerDeploymentInfo{
|
|
Name: tv.DeploymentSeries(),
|
|
RoutingConfig: &deploymentpb.RoutingConfig{
|
|
RampingVersion: rampingVersionVars.DeploymentVersionString(),
|
|
RampingVersionPercentage: 50,
|
|
RampingVersionChangedTime: timestamppb.Now(),
|
|
CurrentVersion: currentVersionVars.DeploymentVersionString(),
|
|
CurrentVersionChangedTime: timestamppb.Now(),
|
|
},
|
|
LastModifierIdentity: tv.ClientIdentity(),
|
|
},
|
|
})
|
|
|
|
// unset ramping version
|
|
s.setAndVerifyRampingVersion(ctx, rampingVersionVars, true, 0, true, "", &workflowservice.SetWorkerDeploymentRampingVersionResponse{
|
|
PreviousVersion: rampingVersionVars.DeploymentVersionString(),
|
|
PreviousPercentage: 50,
|
|
})
|
|
|
|
resp, err = s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
})
|
|
s.NoError(err)
|
|
s.verifyDescribeWorkerDeployment(resp, &workflowservice.DescribeWorkerDeploymentResponse{
|
|
WorkerDeploymentInfo: &deploymentpb.WorkerDeploymentInfo{
|
|
Name: tv.DeploymentSeries(),
|
|
RoutingConfig: &deploymentpb.RoutingConfig{
|
|
RampingVersion: "",
|
|
RampingVersionPercentage: 0,
|
|
RampingVersionChangedTime: nil,
|
|
CurrentVersion: currentVersionVars.DeploymentVersionString(),
|
|
CurrentVersionChangedTime: timestamppb.Now(),
|
|
},
|
|
LastModifierIdentity: tv.ClientIdentity(),
|
|
},
|
|
})
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) TestSetWorkerDeploymentRampingVersion_SetRampingAsCurrent() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
|
defer cancel()
|
|
tv := testvars.New(s)
|
|
|
|
rampingVersionVars := tv.WithBuildIDNumber(1)
|
|
s.startVersionWorkflow(ctx, rampingVersionVars)
|
|
|
|
s.setAndVerifyRampingVersion(ctx, rampingVersionVars, false, 50, true, "", nil)
|
|
// set ramping version as current
|
|
s.setCurrentVersion(ctx, rampingVersionVars, worker_versioning.UnversionedVersionId, true, "")
|
|
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
})
|
|
s.NoError(err)
|
|
s.verifyDescribeWorkerDeployment(resp, &workflowservice.DescribeWorkerDeploymentResponse{
|
|
WorkerDeploymentInfo: &deploymentpb.WorkerDeploymentInfo{
|
|
Name: tv.DeploymentSeries(),
|
|
RoutingConfig: &deploymentpb.RoutingConfig{
|
|
RampingVersion: "", // no ramping info should be set
|
|
RampingVersionPercentage: 0, // no ramping info should be set
|
|
RampingVersionChangedTime: timestamppb.Now(), // ramping version got updated to ""
|
|
CurrentVersion: rampingVersionVars.DeploymentVersionString(),
|
|
CurrentVersionChangedTime: timestamppb.Now(),
|
|
},
|
|
LastModifierIdentity: tv.ClientIdentity(),
|
|
},
|
|
})
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) TestSetWorkerDeploymentRampingVersion_NoCurrent_Unset_Ramp() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
|
defer cancel()
|
|
tv := testvars.New(s)
|
|
|
|
rampingVersionVars := tv.WithBuildIDNumber(1)
|
|
s.startVersionWorkflow(ctx, rampingVersionVars)
|
|
|
|
s.setAndVerifyRampingVersion(ctx, rampingVersionVars, false, 50, true, "", nil)
|
|
s.setAndVerifyRampingVersion(ctx, rampingVersionVars, true, 0, true, "", &workflowservice.SetWorkerDeploymentRampingVersionResponse{
|
|
PreviousVersion: rampingVersionVars.DeploymentVersionString(),
|
|
PreviousPercentage: 50,
|
|
})
|
|
}
|
|
|
|
// Should see that the current version of the task queues becomes unversioned
|
|
func (s *WorkerDeploymentSuite) TestSetCurrentVersion_Unversioned_NoRamp() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
|
defer cancel()
|
|
tv := testvars.New(s)
|
|
currentVars := tv.WithBuildIDNumber(1)
|
|
go s.pollFromDeployment(ctx, currentVars)
|
|
s.ensureCreateVersionInDeployment(currentVars)
|
|
|
|
// check that the current version's task queues have current version unversioned to start
|
|
s.verifyTaskQueueVersioningInfo(ctx, currentVars.TaskQueue(), worker_versioning.UnversionedVersionId, "", 0)
|
|
|
|
// set current and check that the current version's task queues have new current version
|
|
|
|
s.setCurrentVersion(ctx, currentVars, worker_versioning.UnversionedVersionId, true, "")
|
|
s.verifyTaskQueueVersioningInfo(ctx, currentVars.TaskQueue(), currentVars.DeploymentVersionString(), "", 0)
|
|
|
|
// set current unversioned and check that the current version's task queues have current version unversioned again
|
|
s.setCurrentVersionUnversionedOption(ctx, currentVars, true, currentVars.DeploymentVersionString(), true, "")
|
|
s.verifyTaskQueueVersioningInfo(ctx, currentVars.TaskQueue(), worker_versioning.UnversionedVersionId, "", 0)
|
|
|
|
// check that deployment has current version == __unversioned__
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
})
|
|
s.Nil(err)
|
|
s.Equal(worker_versioning.UnversionedVersionId, resp.GetWorkerDeploymentInfo().GetRoutingConfig().GetCurrentVersion())
|
|
}
|
|
|
|
// Should see that the current version of the task queue becomes unversioned, and the unversioned ramping version of the task queue is removed
|
|
func (s *WorkerDeploymentSuite) TestSetCurrentVersion_Unversioned_PromoteUnversionedRamp() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*60)
|
|
defer cancel()
|
|
tv := testvars.New(s)
|
|
currentVars := tv.WithBuildIDNumber(1)
|
|
|
|
go s.pollFromDeployment(ctx, currentVars)
|
|
s.ensureCreateVersionInDeployment(currentVars)
|
|
|
|
// make the current version versioned, so that we can set ramp to unversioned
|
|
s.setCurrentVersion(ctx, currentVars, worker_versioning.UnversionedVersionId, true, "")
|
|
// set ramp to unversioned
|
|
s.setAndVerifyRampingVersionUnversionedOption(ctx, tv, true, false, 75, true, "", nil)
|
|
// check that the current version's task queues have ramping version == __unversioned__
|
|
s.verifyTaskQueueVersioningInfo(ctx, currentVars.TaskQueue(), currentVars.DeploymentVersionString(), worker_versioning.UnversionedVersionId, 75)
|
|
|
|
// set current to unversioned
|
|
s.setCurrentVersionUnversionedOption(ctx, tv, true, currentVars.DeploymentVersionString(), true, "")
|
|
|
|
// check that the current version's task queues have ramping version == "" and current version == "__unversioned__"
|
|
s.verifyTaskQueueVersioningInfo(ctx, currentVars.TaskQueue(), worker_versioning.UnversionedVersionId, "", 0)
|
|
}
|
|
|
|
// Should see it fail because unversioned is already current
|
|
func (s *WorkerDeploymentSuite) TestSetWorkerDeploymentRampingVersion_Unversioned_UnversionedCurrent() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
|
defer cancel()
|
|
tv := testvars.New(s)
|
|
rampingVars := tv.WithBuildIDNumber(1)
|
|
s.startVersionWorkflow(ctx, rampingVars)
|
|
s.setAndVerifyRampingVersionUnversionedOption(ctx, rampingVars, true, false, 50, true, "Ramping version __unversioned__ is already current", nil)
|
|
}
|
|
|
|
// Should see that the ramping version of the task queues in the current version is unversioned
|
|
func (s *WorkerDeploymentSuite) TestSetWorkerDeploymentRampingVersion_Unversioned_VersionedCurrent() {
|
|
s.T().Skip("skipping this test since it's flaking on Cassandra. TODO (Shivam): Fix this.")
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
|
defer cancel()
|
|
tv := testvars.New(s)
|
|
currentVars := tv.WithBuildIDNumber(1)
|
|
s.pollFromDeployment(ctx, currentVars)
|
|
s.ensureCreateVersionInDeployment(currentVars)
|
|
|
|
// check that the current version's task queues have ramping version == ""
|
|
s.setCurrentVersion(ctx, currentVars, worker_versioning.UnversionedVersionId, true, "")
|
|
s.verifyTaskQueueVersioningInfo(ctx, currentVars.TaskQueue(), currentVars.DeploymentVersionString(), "", 0)
|
|
|
|
// set ramp to unversioned
|
|
s.setAndVerifyRampingVersionUnversionedOption(ctx, tv, true, false, 75, true, "", nil)
|
|
|
|
// check that deployment has ramping version == __unversioned__
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentSeries(),
|
|
})
|
|
s.Nil(err)
|
|
s.Equal(worker_versioning.UnversionedVersionId, resp.GetWorkerDeploymentInfo().GetRoutingConfig().GetRampingVersion())
|
|
|
|
// check that the current version's task queues have ramping version == __unversioned__
|
|
s.verifyTaskQueueVersioningInfo(ctx, currentVars.TaskQueue(), currentVars.DeploymentVersionString(), worker_versioning.UnversionedVersionId, 75)
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) TestTwoPollers_EnsureCreateVersion() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
|
defer func() {
|
|
cancel()
|
|
}()
|
|
tv := testvars.New(s)
|
|
tv1 := tv.WithBuildIDNumber(1)
|
|
tv2 := tv.WithBuildIDNumber(2)
|
|
|
|
go s.pollFromDeployment(ctx, tv1)
|
|
go s.pollFromDeployment(ctx, tv2)
|
|
s.ensureCreateVersion(ctx, tv1)
|
|
s.ensureCreateVersion(ctx, tv2)
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) verifyTaskQueueVersioningInfo(ctx context.Context, tq *taskqueuepb.TaskQueue, expectedCurrentVersion, expectedRampingVersion string, expectedPercentage float32) {
|
|
tqDesc, err := s.FrontendClient().DescribeTaskQueue(ctx, &workflowservice.DescribeTaskQueueRequest{
|
|
Namespace: s.Namespace().String(),
|
|
TaskQueue: tq,
|
|
})
|
|
s.Nil(err)
|
|
s.Equal(expectedCurrentVersion, tqDesc.GetVersioningInfo().GetCurrentVersion())
|
|
s.Equal(expectedRampingVersion, tqDesc.GetVersioningInfo().GetRampingVersion())
|
|
s.Equal(expectedPercentage, tqDesc.GetVersioningInfo().GetRampingVersionPercentage())
|
|
}
|
|
|
|
// Test that rolling back to a drained version works
|
|
func (s *WorkerDeploymentSuite) TestSetRampingVersion_AfterDrained() {
|
|
s.OverrideDynamicConfig(dynamicconfig.PollerHistoryTTL, 500*time.Millisecond)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
|
|
defer cancel()
|
|
tv1 := testvars.New(s).WithBuildIDNumber(1)
|
|
tv2 := testvars.New(s).WithBuildIDNumber(2)
|
|
|
|
// Start deployment workflow 1 and wait for the deployment version to exist
|
|
s.startVersionWorkflow(ctx, tv1)
|
|
|
|
// Set v1 as current version
|
|
s.setCurrentVersion(ctx, tv1, worker_versioning.UnversionedVersionId, true, "")
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv1.DeploymentSeries(),
|
|
})
|
|
a.NoError(err)
|
|
a.Equal(tv1.DeploymentVersionString(), resp.GetWorkerDeploymentInfo().GetRoutingConfig().GetCurrentVersion())
|
|
a.Equal(tv1.ClientIdentity(), resp.GetWorkerDeploymentInfo().GetLastModifierIdentity())
|
|
}, time.Second*10, time.Millisecond*1000)
|
|
|
|
// Start deployment workflow 2 and set v2 to current so that v1 can start draining
|
|
s.startVersionWorkflow(ctx, tv2)
|
|
s.setCurrentVersion(ctx, tv2, tv1.DeploymentVersionString(), true, "")
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv2.DeploymentSeries(),
|
|
})
|
|
a.NoError(err)
|
|
a.Equal(tv2.DeploymentVersionString(), resp.GetWorkerDeploymentInfo().GetRoutingConfig().GetCurrentVersion())
|
|
a.Equal(tv2.ClientIdentity(), resp.GetWorkerDeploymentInfo().GetLastModifierIdentity())
|
|
}, time.Second*10, time.Millisecond*1000)
|
|
|
|
// wait for v1 to be drained
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
resp, err := s.FrontendClient().DescribeWorkerDeploymentVersion(ctx, &workflowservice.DescribeWorkerDeploymentVersionRequest{
|
|
Namespace: s.Namespace().String(),
|
|
Version: tv1.DeploymentVersionString(),
|
|
})
|
|
a.NoError(err)
|
|
a.Equal(enumspb.VERSION_DRAINAGE_STATUS_DRAINED, resp.GetWorkerDeploymentVersionInfo().GetDrainageInfo().GetStatus())
|
|
}, time.Second*10, time.Millisecond*1000)
|
|
|
|
// start ramping traffic back to v1
|
|
s.setAndVerifyRampingVersion(ctx, tv1, false, 10, false, "", &workflowservice.SetWorkerDeploymentRampingVersionResponse{
|
|
ConflictToken: nil,
|
|
PreviousVersion: "",
|
|
PreviousPercentage: 0,
|
|
})
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) TestDeleteWorkerDeployment_ValidDelete() {
|
|
s.OverrideDynamicConfig(dynamicconfig.PollerHistoryTTL, 500*time.Millisecond)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
|
|
defer cancel()
|
|
tv1 := testvars.New(s).WithBuildIDNumber(1)
|
|
|
|
// Start deployment workflow 1 and wait for the deployment version to exist
|
|
s.startVersionWorkflow(ctx, tv1)
|
|
|
|
// Signal the first version to be drained. Only do this in tests.
|
|
versionWorkflowID := worker_versioning.GenerateVersionWorkflowID(tv1.DeploymentSeries(), tv1.BuildID())
|
|
workflowExecution := &commonpb.WorkflowExecution{
|
|
WorkflowId: versionWorkflowID,
|
|
}
|
|
input := &deploymentpb.VersionDrainageInfo{
|
|
Status: enumspb.VERSION_DRAINAGE_STATUS_DRAINED,
|
|
LastChangedTime: timestamppb.New(time.Now()),
|
|
LastCheckedTime: timestamppb.New(time.Now()),
|
|
}
|
|
marshaledData, err := input.Marshal()
|
|
s.NoError(err)
|
|
signalPayload := &commonpb.Payloads{
|
|
Payloads: []*commonpb.Payload{
|
|
{
|
|
Metadata: map[string][]byte{
|
|
"encoding": []byte("binary/protobuf"),
|
|
},
|
|
Data: marshaledData,
|
|
},
|
|
},
|
|
}
|
|
|
|
err = s.SendSignal(s.Namespace().String(), workflowExecution, workerdeployment.SyncDrainageSignalName, signalPayload, tv1.ClientIdentity())
|
|
s.Nil(err)
|
|
|
|
// Wait for pollers going away
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
resp, err := s.FrontendClient().DescribeTaskQueue(ctx, &workflowservice.DescribeTaskQueueRequest{
|
|
Namespace: s.Namespace().String(),
|
|
TaskQueue: tv1.TaskQueue(),
|
|
TaskQueueType: enumspb.TASK_QUEUE_TYPE_WORKFLOW,
|
|
})
|
|
assert.NoError(t, err)
|
|
assert.Empty(t, resp.Pollers)
|
|
}, 5*time.Second, time.Second)
|
|
|
|
// delete succeeds
|
|
s.tryDeleteVersion(ctx, tv1, true)
|
|
|
|
// deployment version does not exist in the deployment list
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv1.DeploymentSeries(),
|
|
})
|
|
a.NoError(err)
|
|
if resp != nil {
|
|
for _, vs := range resp.GetWorkerDeploymentInfo().GetVersionSummaries() {
|
|
a.NotEqual(tv1.DeploymentVersionString(), vs.Version)
|
|
}
|
|
}
|
|
}, time.Second*5, time.Millisecond*200)
|
|
|
|
// Deleting the worker deployment should succeed since there are no associated versions left
|
|
_, err = s.FrontendClient().DeleteWorkerDeployment(ctx, &workflowservice.DeleteWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv1.DeploymentSeries(),
|
|
Identity: tv1.ClientIdentity(),
|
|
})
|
|
s.Nil(err)
|
|
|
|
// Describe Worker Deployment should give not found
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
_, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv1.DeploymentSeries(),
|
|
})
|
|
a.Error(err)
|
|
var nfe *serviceerror.NotFound
|
|
a.True(errors.As(err, &nfe))
|
|
}, time.Second*5, time.Millisecond*200)
|
|
|
|
// ListDeployments should not show the closed/deleted Worker Deployment
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
listResp, err := s.FrontendClient().ListWorkerDeployments(ctx, &workflowservice.ListWorkerDeploymentsRequest{
|
|
Namespace: s.Namespace().String(),
|
|
})
|
|
a.Nil(err)
|
|
for _, dInfo := range listResp.GetWorkerDeployments() {
|
|
a.NotEqual(tv1.DeploymentSeries(), dInfo.GetName())
|
|
}
|
|
}, time.Second*5, time.Millisecond*200)
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) TestDeleteWorkerDeployment_Idempotent() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
|
|
defer cancel()
|
|
tv1 := testvars.New(s).WithBuildIDNumber(1)
|
|
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
_, err := s.FrontendClient().DeleteWorkerDeployment(ctx, &workflowservice.DeleteWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv1.DeploymentSeries(),
|
|
Identity: tv1.ClientIdentity(),
|
|
})
|
|
a.NoError(err)
|
|
}, time.Second*5, time.Millisecond*200)
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) TestDeleteWorkerDeployment_InvalidDelete() {
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
|
|
defer cancel()
|
|
tv1 := testvars.New(s).WithBuildIDNumber(1)
|
|
|
|
// Start deployment workflow 1 and wait for the deployment version and deployment workflow to exist
|
|
go s.pollFromDeployment(ctx, tv1)
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
resp, err := s.FrontendClient().DescribeWorkerDeploymentVersion(ctx, &workflowservice.DescribeWorkerDeploymentVersionRequest{
|
|
Namespace: s.Namespace().String(),
|
|
Version: tv1.DeploymentVersionString(),
|
|
})
|
|
a.NoError(err)
|
|
a.Equal(tv1.DeploymentVersionString(), resp.GetWorkerDeploymentVersionInfo().GetVersion())
|
|
}, time.Second*5, time.Millisecond*200)
|
|
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
resp, err := s.FrontendClient().DescribeWorkerDeployment(ctx, &workflowservice.DescribeWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv1.DeploymentSeries(),
|
|
})
|
|
a.NoError(err)
|
|
if a.NotEmpty(resp.GetWorkerDeploymentInfo().GetVersionSummaries()) {
|
|
a.Equal(tv1.DeploymentVersionString(), resp.GetWorkerDeploymentInfo().GetVersionSummaries()[0].Version)
|
|
}
|
|
}, time.Second*5, time.Millisecond*200)
|
|
|
|
// Delete the worker deployment should fail since there are versions associated with it
|
|
_, err := s.FrontendClient().DeleteWorkerDeployment(ctx, &workflowservice.DeleteWorkerDeploymentRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv1.DeploymentSeries(),
|
|
Identity: tv1.ClientIdentity(),
|
|
})
|
|
s.Error(err)
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) tryDeleteVersion(
|
|
ctx context.Context,
|
|
tv *testvars.TestVars,
|
|
expectSuccess bool,
|
|
) {
|
|
_, err := s.FrontendClient().DeleteWorkerDeploymentVersion(ctx, &workflowservice.DeleteWorkerDeploymentVersionRequest{
|
|
Namespace: s.Namespace().String(),
|
|
Version: tv.DeploymentVersionString(),
|
|
})
|
|
if expectSuccess {
|
|
s.Nil(err)
|
|
} else {
|
|
s.Error(err)
|
|
}
|
|
}
|
|
|
|
// todo: add validations for VersionSummaries
|
|
func (s *WorkerDeploymentSuite) verifyDescribeWorkerDeployment(
|
|
actualResp *workflowservice.DescribeWorkerDeploymentResponse,
|
|
expectedResp *workflowservice.DescribeWorkerDeploymentResponse,
|
|
) {
|
|
// relaxed timestamp constraint since the tests make sync calls, which could theoretically take seconds.
|
|
maxDurationBetweenTimeStamps := 2 * time.Second
|
|
|
|
s.True((actualResp == nil) == (expectedResp == nil))
|
|
s.True((actualResp.GetWorkerDeploymentInfo() == nil) == (expectedResp.GetWorkerDeploymentInfo() == nil))
|
|
s.True((actualResp.GetWorkerDeploymentInfo().GetRoutingConfig() == nil) == (expectedResp.GetWorkerDeploymentInfo().GetRoutingConfig() == nil))
|
|
s.Equal(expectedResp.GetWorkerDeploymentInfo().GetName(), actualResp.GetWorkerDeploymentInfo().GetName())
|
|
s.True(expectedResp.GetWorkerDeploymentInfo().GetCreateTime().AsTime().Sub(actualResp.GetWorkerDeploymentInfo().GetCreateTime().AsTime()) < maxDurationBetweenTimeStamps)
|
|
s.Equal(expectedResp.GetWorkerDeploymentInfo().GetLastModifierIdentity(), actualResp.GetWorkerDeploymentInfo().GetLastModifierIdentity())
|
|
|
|
actualRoutingInfo := actualResp.GetWorkerDeploymentInfo().GetRoutingConfig()
|
|
expectedRoutingInfo := expectedResp.GetWorkerDeploymentInfo().GetRoutingConfig()
|
|
|
|
s.Equal(expectedRoutingInfo.GetRampingVersion(), actualRoutingInfo.GetRampingVersion())
|
|
s.Equal(expectedRoutingInfo.GetRampingVersionPercentage(), actualRoutingInfo.GetRampingVersionPercentage())
|
|
s.True(expectedRoutingInfo.GetRampingVersionChangedTime().AsTime().Sub(actualRoutingInfo.GetRampingVersionChangedTime().AsTime()) < maxDurationBetweenTimeStamps)
|
|
|
|
s.Equal(expectedRoutingInfo.GetCurrentVersion(), actualRoutingInfo.GetCurrentVersion())
|
|
s.True(expectedRoutingInfo.GetCurrentVersionChangedTime().AsTime().Sub(actualRoutingInfo.GetCurrentVersionChangedTime().AsTime()) < maxDurationBetweenTimeStamps)
|
|
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) setAndVerifyRampingVersion(
|
|
ctx context.Context,
|
|
tv *testvars.TestVars,
|
|
unset bool,
|
|
percentage int,
|
|
ignoreMissingTaskQueues bool,
|
|
expectedError string,
|
|
expectedResp *workflowservice.SetWorkerDeploymentRampingVersionResponse,
|
|
) {
|
|
s.setAndVerifyRampingVersionUnversionedOption(ctx, tv, false, unset, percentage, ignoreMissingTaskQueues, expectedError, expectedResp)
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) setAndVerifyRampingVersionUnversionedOption(
|
|
ctx context.Context,
|
|
tv *testvars.TestVars,
|
|
unversioned bool,
|
|
unset bool,
|
|
percentage int,
|
|
ignoreMissingTaskQueues bool,
|
|
expectedError string,
|
|
expectedResp *workflowservice.SetWorkerDeploymentRampingVersionResponse,
|
|
) {
|
|
version := tv.DeploymentVersionString()
|
|
if unversioned {
|
|
version = worker_versioning.UnversionedVersionId
|
|
}
|
|
if unset {
|
|
version = ""
|
|
percentage = 0
|
|
}
|
|
if !unversioned && !unset {
|
|
s.ensureCreateVersionInDeployment(tv)
|
|
} else {
|
|
s.ensureCreateDeployment(tv)
|
|
}
|
|
resp, err := s.FrontendClient().SetWorkerDeploymentRampingVersion(ctx, &workflowservice.SetWorkerDeploymentRampingVersionRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentVersion().GetDeploymentName(),
|
|
Version: version,
|
|
Percentage: float32(percentage),
|
|
Identity: tv.ClientIdentity(),
|
|
IgnoreMissingTaskQueues: ignoreMissingTaskQueues,
|
|
})
|
|
if expectedError != "" {
|
|
s.Error(err)
|
|
s.Contains(err.Error(), expectedError)
|
|
return
|
|
}
|
|
s.NoError(err)
|
|
s.Equal(expectedResp.GetPreviousVersion(), resp.GetPreviousVersion())
|
|
s.Equal(expectedResp.GetPreviousPercentage(), resp.GetPreviousPercentage())
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) setCurrentVersion(ctx context.Context, tv *testvars.TestVars, previousCurrent string, ignoreMissingTaskQueues bool, expectedError string) {
|
|
s.setCurrentVersionUnversionedOption(ctx, tv, false, previousCurrent, ignoreMissingTaskQueues, expectedError)
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) setCurrentVersionUnversionedOption(ctx context.Context, tv *testvars.TestVars, unversioned bool, previousCurrent string, ignoreMissingTaskQueues bool, expectedError string) {
|
|
version := tv.DeploymentVersionString()
|
|
if unversioned {
|
|
version = worker_versioning.UnversionedVersionId
|
|
s.ensureCreateDeployment(tv)
|
|
} else {
|
|
s.ensureCreateVersionInDeployment(tv)
|
|
}
|
|
|
|
resp, err := s.FrontendClient().SetWorkerDeploymentCurrentVersion(ctx, &workflowservice.SetWorkerDeploymentCurrentVersionRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentName: tv.DeploymentVersion().GetDeploymentName(),
|
|
Version: version,
|
|
IgnoreMissingTaskQueues: ignoreMissingTaskQueues,
|
|
Identity: tv.ClientIdentity(),
|
|
})
|
|
if expectedError != "" {
|
|
s.Error(err)
|
|
s.Contains(err.Error(), expectedError)
|
|
return
|
|
}
|
|
s.NoError(err)
|
|
s.NotNil(resp.PreviousVersion)
|
|
s.Equal(previousCurrent, resp.PreviousVersion)
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) createVersionsInDeployments(ctx context.Context, tv *testvars.TestVars, n int) []*workflowservice.ListWorkerDeploymentsResponse_WorkerDeploymentSummary {
|
|
var expectedDeploymentSummaries []*workflowservice.ListWorkerDeploymentsResponse_WorkerDeploymentSummary
|
|
|
|
for i := 0; i < n; i++ {
|
|
deployment := tv.WithDeploymentSeriesNumber(i)
|
|
version := deployment.WithBuildIDNumber(i)
|
|
|
|
s.startVersionWorkflow(ctx, version)
|
|
s.setCurrentVersion(ctx, version, worker_versioning.UnversionedVersionId, true, "")
|
|
|
|
expectedDeployment := s.buildWorkerDeploymentSummary(
|
|
deployment.DeploymentSeries(),
|
|
timestamppb.Now(),
|
|
&deploymentpb.RoutingConfig{
|
|
CurrentVersion: version.DeploymentVersionString(),
|
|
CurrentVersionChangedTime: timestamppb.Now(),
|
|
},
|
|
)
|
|
expectedDeploymentSummaries = append(expectedDeploymentSummaries, expectedDeployment)
|
|
}
|
|
|
|
return expectedDeploymentSummaries
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) verifyWorkerDeploymentSummary(
|
|
expectedSummary *workflowservice.ListWorkerDeploymentsResponse_WorkerDeploymentSummary,
|
|
actualSummary *workflowservice.ListWorkerDeploymentsResponse_WorkerDeploymentSummary,
|
|
) bool {
|
|
maxDurationBetweenTimeStamps := 5 * time.Second
|
|
if expectedSummary.Name != actualSummary.Name {
|
|
s.Logger.Info("Name mismatch")
|
|
return false
|
|
}
|
|
if expectedSummary.CreateTime.AsTime().Sub(actualSummary.CreateTime.AsTime()) > maxDurationBetweenTimeStamps {
|
|
s.Logger.Info("Create time mismatch")
|
|
return false
|
|
}
|
|
|
|
// Current version checks
|
|
if expectedSummary.RoutingConfig.GetCurrentVersion() != actualSummary.RoutingConfig.GetCurrentVersion() {
|
|
s.Logger.Info("Current version mismatch")
|
|
return false
|
|
}
|
|
if expectedSummary.RoutingConfig.GetCurrentVersionChangedTime().AsTime().Sub(actualSummary.RoutingConfig.GetCurrentVersionChangedTime().AsTime()) > maxDurationBetweenTimeStamps {
|
|
s.Logger.Info("Current version update time mismatch")
|
|
return false
|
|
}
|
|
|
|
// Ramping version checks
|
|
if expectedSummary.RoutingConfig.GetRampingVersion() != actualSummary.RoutingConfig.GetRampingVersion() {
|
|
s.Logger.Info("Ramping version mismatch")
|
|
return false
|
|
}
|
|
if expectedSummary.RoutingConfig.GetRampingVersionPercentage() != actualSummary.RoutingConfig.GetRampingVersionPercentage() {
|
|
s.Logger.Info("Ramping version percentage mismatch")
|
|
return false
|
|
}
|
|
if expectedSummary.RoutingConfig.GetRampingVersionChangedTime().AsTime().Sub(actualSummary.RoutingConfig.GetRampingVersionChangedTime().AsTime()) > maxDurationBetweenTimeStamps {
|
|
s.Logger.Info("Ramping version update time mismatch")
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) listWorkerDeployments(ctx context.Context, request *workflowservice.ListWorkerDeploymentsRequest) ([]*workflowservice.ListWorkerDeploymentsResponse_WorkerDeploymentSummary, error) {
|
|
var resp *workflowservice.ListWorkerDeploymentsResponse
|
|
var err error
|
|
var deploymentSummaries []*workflowservice.ListWorkerDeploymentsResponse_WorkerDeploymentSummary
|
|
for resp == nil || len(resp.NextPageToken) > 0 {
|
|
resp, err = s.FrontendClient().ListWorkerDeployments(ctx, request)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
deploymentSummaries = append(deploymentSummaries, resp.GetWorkerDeployments()...)
|
|
request.NextPageToken = resp.NextPageToken
|
|
}
|
|
return deploymentSummaries, nil
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) startAndValidateWorkerDeployments(
|
|
ctx context.Context,
|
|
request *workflowservice.ListWorkerDeploymentsRequest,
|
|
expectedDeploymentSummaries []*workflowservice.ListWorkerDeploymentsResponse_WorkerDeploymentSummary,
|
|
) {
|
|
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := assert.New(t)
|
|
|
|
actualDeploymentSummaries, err := s.listWorkerDeployments(ctx, request)
|
|
a.NoError(err)
|
|
if len(actualDeploymentSummaries) < len(expectedDeploymentSummaries) {
|
|
return
|
|
}
|
|
|
|
for _, expectedDeploymentSummary := range expectedDeploymentSummaries {
|
|
deploymentSummaryValidated := false
|
|
for _, actualDeploymentSummary := range actualDeploymentSummaries {
|
|
deploymentSummaryValidated = deploymentSummaryValidated ||
|
|
s.verifyWorkerDeploymentSummary(expectedDeploymentSummary, actualDeploymentSummary)
|
|
}
|
|
a.True(deploymentSummaryValidated)
|
|
}
|
|
}, time.Second*10, time.Millisecond*1000)
|
|
}
|
|
|
|
func (s *WorkerDeploymentSuite) buildWorkerDeploymentSummary(
|
|
deploymentName string, createTime *timestamppb.Timestamp,
|
|
routingConfig *deploymentpb.RoutingConfig,
|
|
) *workflowservice.ListWorkerDeploymentsResponse_WorkerDeploymentSummary {
|
|
return &workflowservice.ListWorkerDeploymentsResponse_WorkerDeploymentSummary{
|
|
Name: deploymentName,
|
|
CreateTime: createTime,
|
|
RoutingConfig: routingConfig,
|
|
}
|
|
}
|
|
|
|
// Name is used by testvars. We use a shortened test name in variables so that physical task queue IDs
|
|
// do not grow larger than DB column limit (currently as low as 272 chars).
|
|
func (s *WorkerDeploymentSuite) Name() string {
|
|
fullName := s.T().Name()
|
|
if len(fullName) <= 30 {
|
|
return fullName
|
|
}
|
|
short := fmt.Sprintf("%s-%08x",
|
|
fullName[len(fullName)-21:],
|
|
farm.Fingerprint32([]byte(fullName)),
|
|
)
|
|
return strings.Replace(short, ".", "|", -1)
|
|
}
|