diff --git a/Makefile b/Makefile index a722efd313c..1276311c65a 100644 --- a/Makefile +++ b/Makefile @@ -62,7 +62,7 @@ $(BUILD)/proto-lint: $(BUILD)/gomod-lint: $(BUILD)/goversion-lint: $(BUILD)/fmt: $(BUILD)/codegen # formatting must occur only after all other go-file-modifications are done -# $(BUILD)/copyright +# $(BUILD)/copyright # $(BUILD)/copyright: $(BUILD)/codegen # must add copyright to generated code, sometimes needs re-formatting $(BUILD)/codegen: $(BUILD)/thrift $(BUILD)/protoc $(BUILD)/thrift: $(BUILD)/go_mod_check @@ -188,6 +188,9 @@ $(BIN)/mockgen: internal/tools/go.mod go.work $(BIN)/mockery: internal/tools/go.mod go.work $(call go_build_tool,github.com/vektra/mockery/v2,mockery) +$(BIN)/deep-copy: internal/tools/go.mod go.work + $(call go_build_tool,github.com/globusdigital/deep-copy) + $(BIN)/enumer: internal/tools/go.mod go.work $(call go_build_tool,github.com/dmarkham/enumer) @@ -549,7 +552,7 @@ bins: $(BINS) ## Build all binaries, and any fast codegen needed (does not refre tools: $(TOOLS) -go-generate: $(BIN)/mockgen $(BIN)/enumer $(BIN)/mockery $(BIN)/gowrap ## Run `go generate` to regen mocks, enums, etc +go-generate: $(BIN)/mockgen $(BIN)/enumer $(BIN)/mockery $(BIN)/gowrap $(BIN)/deep-copy ## Run `go generate` to regen mocks, enums, etc $Q echo "running go generate ./..., this takes a minute or more..." $Q # add our bins to PATH so `go generate` can find them $Q $(BIN_PATH) go generate $(if $(verbose),-v) ./... diff --git a/common/cache/domainCache.go b/common/cache/domainCache.go index 82097ef18c6..761968e76a7 100644 --- a/common/cache/domainCache.go +++ b/common/cache/domainCache.go @@ -761,7 +761,9 @@ func (entry *DomainCacheEntry) duplicate() *DomainCacheEntry { c := *clusterCfg result.replicationConfig.Clusters = append(result.replicationConfig.Clusters, &c) } - result.replicationConfig.ActiveClusters = entry.replicationConfig.ActiveClusters.DeepCopy() + if entry.replicationConfig.ActiveClusters != nil { + result.replicationConfig.ActiveClusters = entry.replicationConfig.ActiveClusters.DeepCopy() + } result.configVersion = entry.configVersion result.failoverVersion = entry.failoverVersion result.isGlobalDomain = entry.isGlobalDomain diff --git a/common/domain/handler.go b/common/domain/handler.go index e0cf5473e15..cad8556bba3 100644 --- a/common/domain/handler.go +++ b/common/domain/handler.go @@ -839,7 +839,10 @@ func (d *handlerImpl) FailoverDomain( isGlobalDomain := getResponse.IsGlobalDomain gracefulFailoverEndTime := getResponse.FailoverEndTime currentActiveCluster := replicationConfig.ActiveClusterName - currentActiveClusters := replicationConfig.ActiveClusters.DeepCopy() + var currentActiveClusters *types.ActiveClusters + if replicationConfig.ActiveClusters != nil { + currentActiveClusters = replicationConfig.ActiveClusters.DeepCopy() + } previousFailoverVersion := getResponse.PreviousFailoverVersion lastUpdatedTime := time.Unix(0, getResponse.LastUpdatedTime) diff --git a/common/persistence/data_manager_deepcopy.gen.go b/common/persistence/data_manager_deepcopy.gen.go new file mode 100644 index 00000000000..28d65f66883 --- /dev/null +++ b/common/persistence/data_manager_deepcopy.gen.go @@ -0,0 +1,55 @@ +// generated by deep-copy -pointer-receiver -o ./data_manager_deepcopy.gen.go -type GetDomainResponse -type ClusterReplicationConfig .; DO NOT EDIT. + +package persistence + +// DeepCopy generates a deep copy of *GetDomainResponse +func (o *GetDomainResponse) DeepCopy() *GetDomainResponse { + var cp GetDomainResponse = *o + if o.Info != nil { + cp.Info = new(DomainInfo) + *cp.Info = *o.Info + if o.Info.Data != nil { + cp.Info.Data = make(map[string]string, len(o.Info.Data)) + for k4, v4 := range o.Info.Data { + cp.Info.Data[k4] = v4 + } + } + } + if o.Config != nil { + cp.Config = new(DomainConfig) + *cp.Config = *o.Config + { + retV := o.Config.BadBinaries.DeepCopy() + cp.Config.BadBinaries = *retV + } + cp.Config.IsolationGroups = o.Config.IsolationGroups.DeepCopy() + cp.Config.AsyncWorkflowConfig = o.Config.AsyncWorkflowConfig.DeepCopy() + } + if o.ReplicationConfig != nil { + cp.ReplicationConfig = new(DomainReplicationConfig) + *cp.ReplicationConfig = *o.ReplicationConfig + if o.ReplicationConfig.Clusters != nil { + cp.ReplicationConfig.Clusters = make([]*ClusterReplicationConfig, len(o.ReplicationConfig.Clusters)) + copy(cp.ReplicationConfig.Clusters, o.ReplicationConfig.Clusters) + for i4 := range o.ReplicationConfig.Clusters { + if o.ReplicationConfig.Clusters[i4] != nil { + cp.ReplicationConfig.Clusters[i4] = o.ReplicationConfig.Clusters[i4].DeepCopy() + } + } + } + if o.ReplicationConfig.ActiveClusters != nil { + cp.ReplicationConfig.ActiveClusters = o.ReplicationConfig.ActiveClusters.DeepCopy() + } + } + if o.FailoverEndTime != nil { + cp.FailoverEndTime = new(int64) + *cp.FailoverEndTime = *o.FailoverEndTime + } + return &cp +} + +// DeepCopy generates a deep copy of *ClusterReplicationConfig +func (o *ClusterReplicationConfig) DeepCopy() *ClusterReplicationConfig { + var cp ClusterReplicationConfig = *o + return &cp +} diff --git a/common/persistence/data_manager_interfaces.go b/common/persistence/data_manager_interfaces.go index be1f1a2a971..61a6ca88a70 100644 --- a/common/persistence/data_manager_interfaces.go +++ b/common/persistence/data_manager_interfaces.go @@ -1159,6 +1159,8 @@ type ( ActiveClusters *types.ActiveClusters } + //go:generate deep-copy -pointer-receiver -o ./data_manager_deepcopy.gen.go -type ClusterReplicationConfig . + // ClusterReplicationConfig describes the cross DC cluster replication configuration ClusterReplicationConfig struct { ClusterName string @@ -1188,6 +1190,8 @@ type ( Name string } + //go:generate deep-copy -pointer-receiver -o ./data_manager_deepcopy.gen.go -type GetDomainResponse . + // GetDomainResponse is the response for GetDomain GetDomainResponse struct { Info *DomainInfo @@ -2072,91 +2076,6 @@ func (config *ClusterReplicationConfig) deserialize(input map[string]interface{} } // GetCopy return a copy of ClusterReplicationConfig -func (config *ClusterReplicationConfig) GetCopy() *ClusterReplicationConfig { - res := *config - return &res -} - -// DeepCopy returns a deep copy of GetDomainResponse -// todo (david.porter) delete this manual deepcopying since it's annoying to maintain and -// use codegen for generating them instead -func (r *GetDomainResponse) DeepCopy() *GetDomainResponse { - if r == nil { - return nil - } - - result := &GetDomainResponse{ - IsGlobalDomain: r.IsGlobalDomain, - ConfigVersion: r.ConfigVersion, - FailoverVersion: r.FailoverVersion, - FailoverNotificationVersion: r.FailoverNotificationVersion, - PreviousFailoverVersion: r.PreviousFailoverVersion, - LastUpdatedTime: r.LastUpdatedTime, - NotificationVersion: r.NotificationVersion, - } - - // Deep copy FailoverEndTime - if r.FailoverEndTime != nil { - failoverEndTime := *r.FailoverEndTime - result.FailoverEndTime = &failoverEndTime - } - // Deep copy DomainInfo - if r.Info != nil { - result.Info = &DomainInfo{ - ID: r.Info.ID, - Name: r.Info.Name, - Status: r.Info.Status, - Description: r.Info.Description, - OwnerEmail: r.Info.OwnerEmail, - } - if r.Info.Data != nil { - result.Info.Data = make(map[string]string, len(r.Info.Data)) - for k, v := range r.Info.Data { - result.Info.Data[k] = v - } - } - } - - // Deep copy DomainConfig - if r.Config != nil { - result.Config = &DomainConfig{ - Retention: r.Config.Retention, - EmitMetric: r.Config.EmitMetric, - HistoryArchivalStatus: r.Config.HistoryArchivalStatus, - HistoryArchivalURI: r.Config.HistoryArchivalURI, - VisibilityArchivalStatus: r.Config.VisibilityArchivalStatus, - VisibilityArchivalURI: r.Config.VisibilityArchivalURI, - } - // Deep copy BadBinaries - result.Config.BadBinaries = r.Config.BadBinaries.DeepCopy() - // Deep copy IsolationGroups - result.Config.IsolationGroups = r.Config.IsolationGroups.DeepCopy() - // Deep copy AsyncWorkflowConfig - result.Config.AsyncWorkflowConfig = r.Config.AsyncWorkflowConfig.DeepCopy() - } - - // Deep copy DomainReplicationConfig - if r.ReplicationConfig != nil { - result.ReplicationConfig = &DomainReplicationConfig{ - ActiveClusterName: r.ReplicationConfig.ActiveClusterName, - } - // Deep copy Clusters - if r.ReplicationConfig.Clusters != nil { - result.ReplicationConfig.Clusters = make([]*ClusterReplicationConfig, len(r.ReplicationConfig.Clusters)) - for i, cluster := range r.ReplicationConfig.Clusters { - if cluster != nil { - result.ReplicationConfig.Clusters[i] = cluster.GetCopy() - } - } - } - // Deep copy ActiveClusters - if r.ReplicationConfig.ActiveClusters != nil { - result.ReplicationConfig.ActiveClusters = r.ReplicationConfig.ActiveClusters.DeepCopy() - } - } - - return result -} // DBTimestampToUnixNano converts Milliseconds timestamp to UnixNano func DBTimestampToUnixNano(milliseconds int64) int64 { diff --git a/common/persistence/data_manager_interfaces_test.go b/common/persistence/data_manager_interfaces_test.go index 5b025efec29..95e271a5dcc 100644 --- a/common/persistence/data_manager_interfaces_test.go +++ b/common/persistence/data_manager_interfaces_test.go @@ -39,8 +39,9 @@ func TestClusterReplicationConfigGetCopy(t *testing.T) { config := &ClusterReplicationConfig{ ClusterName: "test", } - assert.Equal(t, config, config.GetCopy()) // deep equal - assert.Equal(t, true, config != config.GetCopy()) + configCopy := config.DeepCopy() + assert.Equal(t, config, configCopy) // deep equal + assert.Equal(t, true, config != configCopy) } func TestGetDomainResponseDeepCopy(t *testing.T) { @@ -115,6 +116,11 @@ func TestGetDomainResponseDeepCopy(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { + if tt.input == nil { + // Cannot call DeepCopy on nil with value receiver + tt.validate(t, tt.input, nil) + return + } copied := tt.input.DeepCopy() tt.validate(t, tt.input, copied) }) diff --git a/common/types/admin.go b/common/types/admin.go index 217a7e65af9..3e5dc455828 100644 --- a/common/types/admin.go +++ b/common/types/admin.go @@ -428,6 +428,8 @@ type GetDomainAsyncWorkflowConfiguratonResponse struct { Configuration *AsyncWorkflowConfiguration } +//go:generate deep-copy -o ./admin_deepcopy.gen.go -type AsyncWorkflowConfiguration . + type AsyncWorkflowConfiguration struct { Enabled bool PredefinedQueueName string @@ -435,17 +437,6 @@ type AsyncWorkflowConfiguration struct { QueueConfig *DataBlob } -func (c AsyncWorkflowConfiguration) DeepCopy() AsyncWorkflowConfiguration { - res := AsyncWorkflowConfiguration{ - Enabled: c.Enabled, - PredefinedQueueName: c.PredefinedQueueName, - QueueType: c.QueueType, - QueueConfig: c.QueueConfig.DeepCopy(), - } - - return res -} - // ByteSize returns an approximate size of the object in bytes func (c *AsyncWorkflowConfiguration) ByteSize() uint64 { if c == nil { diff --git a/common/types/admin_deepcopy.gen.go b/common/types/admin_deepcopy.gen.go new file mode 100644 index 00000000000..535cdb7409d --- /dev/null +++ b/common/types/admin_deepcopy.gen.go @@ -0,0 +1,12 @@ +// generated by deep-copy -o ./admin_deepcopy.gen.go -type AsyncWorkflowConfiguration .; DO NOT EDIT. + +package types + +// DeepCopy generates a deep copy of AsyncWorkflowConfiguration +func (o AsyncWorkflowConfiguration) DeepCopy() AsyncWorkflowConfiguration { + var cp AsyncWorkflowConfiguration = o + if o.QueueConfig != nil { + cp.QueueConfig = o.QueueConfig.DeepCopy() + } + return cp +} diff --git a/common/types/configStore.go b/common/types/configStore.go index 65e60c4e476..33d6bf26ec5 100644 --- a/common/types/configStore.go +++ b/common/types/configStore.go @@ -44,9 +44,13 @@ func (dcf *DynamicConfigFilter) Copy() *DynamicConfigFilter { if dcf == nil { return nil } + var valueCopy *DataBlob + if dcf.Value != nil { + valueCopy = dcf.Value.DeepCopy() + } return &DynamicConfigFilter{ Name: dcf.Name, - Value: dcf.Value.DeepCopy(), + Value: valueCopy, } } @@ -63,8 +67,12 @@ func (dcv *DynamicConfigValue) Copy() *DynamicConfigValue { } } + var valueCopy *DataBlob + if dcv.Value != nil { + valueCopy = dcv.Value.DeepCopy() + } return &DynamicConfigValue{ - Value: dcv.Value.DeepCopy(), + Value: valueCopy, Filters: newFilters, } } diff --git a/common/types/shared.go b/common/types/shared.go index 1ff35e137de..eab678f4e6e 100644 --- a/common/types/shared.go +++ b/common/types/shared.go @@ -392,32 +392,6 @@ func (b *BadBinaries) ByteSize() uint64 { } // DeepCopy returns a deep copy of BadBinaries -func (b *BadBinaries) DeepCopy() BadBinaries { - if b == nil { - return BadBinaries{} - } - result := BadBinaries{} - if b.Binaries != nil { - result.Binaries = make(map[string]*BadBinaryInfo, len(b.Binaries)) - for k, v := range b.Binaries { - if v != nil { - copyV := &BadBinaryInfo{ - Reason: v.Reason, - Operator: v.Operator, - } - if v.CreatedTimeNano != nil { - createdTime := *v.CreatedTimeNano - copyV.CreatedTimeNano = &createdTime - } - result.Binaries[k] = copyV - } else { - // Preserve nil entries in the map - result.Binaries[k] = nil - } - } - } - return result -} // BadBinaryInfo is an internal type (TBD...) type BadBinaryInfo struct { @@ -1010,23 +984,6 @@ func (v *DataBlob) GetData() (o []byte) { return } -func (v *DataBlob) DeepCopy() *DataBlob { - if v == nil { - return nil - } - - res := &DataBlob{ - EncodingType: v.EncodingType, - } - - if v.Data != nil { - res.Data = make([]byte, len(v.Data)) - copy(res.Data, v.Data) - } - - return res -} - // ByteSize returns the approximate memory used in bytes func (v *DataBlob) ByteSize() uint64 { if v == nil { @@ -1728,6 +1685,8 @@ func (v *DescribeDomainRequest) GetUUID() (o string) { return } +//go:generate deep-copy -pointer-receiver -o ./shared_deepcopy.gen.go -type DescribeDomainResponse -type BadBinaries -type DataBlob -type ActiveClusters . + // DescribeDomainResponse is an internal type (TBD...) type DescribeDomainResponse struct { DomainInfo *DomainInfo `json:"domainInfo,omitempty"` @@ -2723,27 +2682,6 @@ func (v ActiveClusterInfo) ByteSize() uint64 { return uint64(unsafe.Sizeof(v)) + uint64(len(v.ActiveClusterName)) } -func (v *ActiveClusters) DeepCopy() *ActiveClusters { - if v == nil { - return nil - } - result := &ActiveClusters{} - if v.AttributeScopes != nil { - result.AttributeScopes = make(map[string]ClusterAttributeScope, len(v.AttributeScopes)) - for scopeType, scope := range v.AttributeScopes { - copiedScope := ClusterAttributeScope{} - if scope.ClusterAttributes != nil { - copiedScope.ClusterAttributes = make(map[string]ActiveClusterInfo, len(scope.ClusterAttributes)) - for attrName, attrInfo := range scope.ClusterAttributes { - copiedScope.ClusterAttributes[attrName] = attrInfo - } - } - result.AttributeScopes[scopeType] = copiedScope - } - } - return result -} - type ClusterAttribute struct { Scope string `json:"scope,omitempty" yaml:"scope,omitempty"` Name string `json:"name,omitempty" yaml:"name,omitempty"` diff --git a/common/types/shared_deepcopy.gen.go b/common/types/shared_deepcopy.gen.go new file mode 100644 index 00000000000..08ddf12e9b1 --- /dev/null +++ b/common/types/shared_deepcopy.gen.go @@ -0,0 +1,125 @@ +// generated by deep-copy -pointer-receiver -o ./shared_deepcopy.gen.go -type DescribeDomainResponse -type BadBinaries -type DataBlob -type ActiveClusters .; DO NOT EDIT. + +package types + +// DeepCopy generates a deep copy of *DescribeDomainResponse +func (o *DescribeDomainResponse) DeepCopy() *DescribeDomainResponse { + var cp DescribeDomainResponse = *o + if o.DomainInfo != nil { + cp.DomainInfo = new(DomainInfo) + *cp.DomainInfo = *o.DomainInfo + if o.DomainInfo.Status != nil { + cp.DomainInfo.Status = new(DomainStatus) + *cp.DomainInfo.Status = *o.DomainInfo.Status + } + if o.DomainInfo.Data != nil { + cp.DomainInfo.Data = make(map[string]string, len(o.DomainInfo.Data)) + for k4, v4 := range o.DomainInfo.Data { + cp.DomainInfo.Data[k4] = v4 + } + } + } + if o.Configuration != nil { + cp.Configuration = new(DomainConfiguration) + *cp.Configuration = *o.Configuration + if o.Configuration.BadBinaries != nil { + cp.Configuration.BadBinaries = o.Configuration.BadBinaries.DeepCopy() + } + if o.Configuration.HistoryArchivalStatus != nil { + cp.Configuration.HistoryArchivalStatus = new(ArchivalStatus) + *cp.Configuration.HistoryArchivalStatus = *o.Configuration.HistoryArchivalStatus + } + if o.Configuration.VisibilityArchivalStatus != nil { + cp.Configuration.VisibilityArchivalStatus = new(ArchivalStatus) + *cp.Configuration.VisibilityArchivalStatus = *o.Configuration.VisibilityArchivalStatus + } + if o.Configuration.IsolationGroups != nil { + retV := o.Configuration.IsolationGroups.DeepCopy() + cp.Configuration.IsolationGroups = &retV + } + if o.Configuration.AsyncWorkflowConfig != nil { + retV := o.Configuration.AsyncWorkflowConfig.DeepCopy() + cp.Configuration.AsyncWorkflowConfig = &retV + } + } + if o.ReplicationConfiguration != nil { + cp.ReplicationConfiguration = new(DomainReplicationConfiguration) + *cp.ReplicationConfiguration = *o.ReplicationConfiguration + if o.ReplicationConfiguration.Clusters != nil { + cp.ReplicationConfiguration.Clusters = make([]*ClusterReplicationConfiguration, len(o.ReplicationConfiguration.Clusters)) + copy(cp.ReplicationConfiguration.Clusters, o.ReplicationConfiguration.Clusters) + for i4 := range o.ReplicationConfiguration.Clusters { + if o.ReplicationConfiguration.Clusters[i4] != nil { + cp.ReplicationConfiguration.Clusters[i4] = new(ClusterReplicationConfiguration) + *cp.ReplicationConfiguration.Clusters[i4] = *o.ReplicationConfiguration.Clusters[i4] + } + } + } + if o.ReplicationConfiguration.ActiveClusters != nil { + cp.ReplicationConfiguration.ActiveClusters = o.ReplicationConfiguration.ActiveClusters.DeepCopy() + } + } + if o.FailoverInfo != nil { + cp.FailoverInfo = new(FailoverInfo) + *cp.FailoverInfo = *o.FailoverInfo + if o.FailoverInfo.PendingShards != nil { + cp.FailoverInfo.PendingShards = make([]int32, len(o.FailoverInfo.PendingShards)) + copy(cp.FailoverInfo.PendingShards, o.FailoverInfo.PendingShards) + } + } + return &cp +} + +// DeepCopy generates a deep copy of *BadBinaries +func (o *BadBinaries) DeepCopy() *BadBinaries { + var cp BadBinaries = *o + if o.Binaries != nil { + cp.Binaries = make(map[string]*BadBinaryInfo, len(o.Binaries)) + for k2, v2 := range o.Binaries { + var cp_Binaries_v2 *BadBinaryInfo + if v2 != nil { + cp_Binaries_v2 = new(BadBinaryInfo) + *cp_Binaries_v2 = *v2 + if v2.CreatedTimeNano != nil { + cp_Binaries_v2.CreatedTimeNano = new(int64) + *cp_Binaries_v2.CreatedTimeNano = *v2.CreatedTimeNano + } + } + cp.Binaries[k2] = cp_Binaries_v2 + } + } + return &cp +} + +// DeepCopy generates a deep copy of *DataBlob +func (o *DataBlob) DeepCopy() *DataBlob { + var cp DataBlob = *o + if o.EncodingType != nil { + cp.EncodingType = new(EncodingType) + *cp.EncodingType = *o.EncodingType + } + if o.Data != nil { + cp.Data = make([]byte, len(o.Data)) + copy(cp.Data, o.Data) + } + return &cp +} + +// DeepCopy generates a deep copy of *ActiveClusters +func (o *ActiveClusters) DeepCopy() *ActiveClusters { + var cp ActiveClusters = *o + if o.AttributeScopes != nil { + cp.AttributeScopes = make(map[string]ClusterAttributeScope, len(o.AttributeScopes)) + for k2, v2 := range o.AttributeScopes { + var cp_AttributeScopes_v2 ClusterAttributeScope + if v2.ClusterAttributes != nil { + cp_AttributeScopes_v2.ClusterAttributes = make(map[string]ActiveClusterInfo, len(v2.ClusterAttributes)) + for k4, v4 := range v2.ClusterAttributes { + cp_AttributeScopes_v2.ClusterAttributes[k4] = v4 + } + } + cp.AttributeScopes[k2] = cp_AttributeScopes_v2 + } + } + return &cp +} diff --git a/common/types/shared_test.go b/common/types/shared_test.go index 7bdaf23567b..8d040e384df 100644 --- a/common/types/shared_test.go +++ b/common/types/shared_test.go @@ -62,9 +62,14 @@ func TestDataBlobDeepCopy(t *testing.T) { for _, tc := range tests { tc := tc t.Run(tc.name, func(t *testing.T) { + if tc.input == nil { + // Cannot call DeepCopy on nil with pointer receiver + return + } got := tc.input.DeepCopy() assert.Equal(t, tc.input, got) - if tc.input != nil && tc.input.Data != nil && identicalByteArray(tc.input.Data, got.Data) { + assert.True(t, tc.input != got, "DeepCopy should return a different pointer") + if tc.input.Data != nil && identicalByteArray(tc.input.Data, got.Data) { t.Error("expected DeepCopy to return a new data slice") } }) @@ -122,10 +127,18 @@ func TestActiveClustersConfigDeepCopy(t *testing.T) { for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { + if tc.input == nil { + // Cannot call DeepCopy on nil with pointer receiver + if tc.expect != nil { + t.Errorf("expected nil but got %+v", tc.expect) + } + return + } deepCopy := tc.input.DeepCopy() if diff := cmp.Diff(tc.expect, deepCopy); diff != "" { t.Errorf("DeepCopy() mismatch (-want +got):\n%s", diff) } + assert.True(t, tc.input != deepCopy, "DeepCopy should return a different pointer") }) } } @@ -150,6 +163,7 @@ func TestActiveClustersDeepCopyMutationIsolation(t *testing.T) { copied := original.DeepCopy() assert.Equal(t, original, copied) + assert.True(t, original != copied, "DeepCopy should return a different pointer") scope := original.AttributeScopes["region"] scope.ClusterAttributes["us-west-1"] = ActiveClusterInfo{ @@ -485,14 +499,14 @@ func TestBadBinariesDeepCopy(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - copied := tt.input.DeepCopy() - // Test for nil input if tt.input == nil { - assert.Empty(t, copied.Binaries) + // Cannot call DeepCopy on nil with value receiver return } + copied := tt.input.DeepCopy() + // Verify values are equal assert.Equal(t, tt.input.Binaries, copied.Binaries, "values should be equal") diff --git a/internal/tools/go.mod b/internal/tools/go.mod index 06016e100d8..7407cdb83fc 100644 --- a/internal/tools/go.mod +++ b/internal/tools/go.mod @@ -7,6 +7,7 @@ toolchain go1.23.4 require ( github.com/daixiang0/gci v0.12.0 github.com/dmarkham/enumer v1.5.8 + github.com/globusdigital/deep-copy v0.5.4 github.com/gogo/protobuf v1.3.2 github.com/hexdigest/gowrap v1.2.5 github.com/mgechev/revive v1.3.2 diff --git a/internal/tools/go.sum b/internal/tools/go.sum index a95619a6621..7bd18e80c75 100644 --- a/internal/tools/go.sum +++ b/internal/tools/go.sum @@ -386,6 +386,8 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/globusdigital/deep-copy v0.5.4 h1:W4CHb7ul8VpZN0uj529AvfFH9Rs14MjKSaJHKISxLY0= +github.com/globusdigital/deep-copy v0.5.4/go.mod h1:UDFAJxcRE6lzC16dS/njdFBd3TXL4yeYH47PWkJJgEM= github.com/go-critic/go-critic v0.6.3 h1:abibh5XYBTASawfTQ0rA7dVtQT+6KzpGqb/J+DxRDaw= github.com/go-critic/go-critic v0.6.3/go.mod h1:c6b3ZP1MQ7o6lPR7Rv3lEf7pYQUmAcx8ABHgdZCQt/k= github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= @@ -1664,6 +1666,7 @@ golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200107050322-53017a39ae36/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117215004-fe56e6335763/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= diff --git a/internal/tools/tools.go b/internal/tools/tools.go index aa8dfc8204b..29fe6035890 100644 --- a/internal/tools/tools.go +++ b/internal/tools/tools.go @@ -28,6 +28,8 @@ import ( _ "github.com/daixiang0/gci" // enumer for generating utility methods for const enums _ "github.com/dmarkham/enumer" + // deep-copy for generating DeepCopy methods + _ "github.com/globusdigital/deep-copy" // protobuf stuff _ "github.com/gogo/protobuf/protoc-gen-gofast" // gowrap for generating decorators for interface