mirror of
https://github.com/temporalio/temporal.git
synced 2026-08-30 18:41:49 -07:00
## What changed? - Applied testifylint, staticcheck, and gofix auto-fixes. - Exact commands that were run: ```sh .bin/golangci-lint-v2.9.0 run --allow-parallel-runners --concurrency 4 --fix --enable-only testifylint --build-tags disable_grpc_modules,test_dep --timeout 20m --config=.github/.golangci.yml .bin/golangci-lint-v2.9.0 run --allow-parallel-runners --concurrency 4 --fix --enable-only staticcheck --build-tags disable_grpc_modules,test_dep --timeout 20m --config=.github/.golangci.yml make fmt-gofix make goimports make fmt git diff --check ``` - No manual or AI changes were made; except where commented on. - Some fixes caused lint errors; those were reverted again. - Changes were all reviewed by me.
244 lines
6.8 KiB
Go
244 lines
6.8 KiB
Go
package chasm
|
|
|
|
import (
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/stretchr/testify/suite"
|
|
"go.uber.org/mock/gomock"
|
|
)
|
|
|
|
type fieldsIteratorSuite struct {
|
|
suite.Suite
|
|
*require.Assertions
|
|
|
|
controller *gomock.Controller
|
|
}
|
|
|
|
func TestFieldsIteratorSuite(t *testing.T) {
|
|
suite.Run(t, new(fieldsIteratorSuite))
|
|
}
|
|
|
|
func (s *fieldsIteratorSuite) SetupTest() {
|
|
s.initAssertions()
|
|
s.controller = gomock.NewController(s.T())
|
|
}
|
|
|
|
func (s *fieldsIteratorSuite) SetupSubTest() {
|
|
s.initAssertions()
|
|
}
|
|
|
|
func (s *fieldsIteratorSuite) initAssertions() {
|
|
// `s.Assertions` (as well as other test helpers which depends on `s.T()`) must be initialized on
|
|
// both test and subtest levels (but not suite level, where `s.T()` is `nil`).
|
|
//
|
|
// If these helpers are not reinitialized on subtest level, any failed `assert` in
|
|
// subtest will fail the entire test (not subtest) immediately without running other subtests.
|
|
|
|
s.Assertions = require.New(s.T())
|
|
}
|
|
|
|
func (s *fieldsIteratorSuite) TestGenericTypePrefix() {
|
|
tests := []struct {
|
|
name string
|
|
input any
|
|
expected string
|
|
}{
|
|
{
|
|
name: "Field type",
|
|
input: Field[string]{},
|
|
expected: chasmFieldTypePrefix,
|
|
},
|
|
{
|
|
name: "Map type",
|
|
input: Map[string, int]{},
|
|
expected: chasmMapTypePrefix,
|
|
},
|
|
{
|
|
name: "Non-generic type",
|
|
input: 0,
|
|
expected: "",
|
|
},
|
|
{
|
|
name: "Map type",
|
|
input: map[string]int{},
|
|
expected: "map[",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
s.Run(tt.name, func() {
|
|
typ := reflect.TypeOf(tt.input)
|
|
result := genericTypePrefix(typ)
|
|
s.Equal(tt.expected, result)
|
|
})
|
|
}
|
|
}
|
|
|
|
func (s *fieldsIteratorSuite) TestChasmFieldTypePrefix() {
|
|
fT := reflect.TypeFor[Field[any]]()
|
|
s.True(strings.HasPrefix(fT.String(), chasmFieldTypePrefix))
|
|
}
|
|
|
|
func (s *fieldsIteratorSuite) TestChasmMapTypePrefix() {
|
|
cT := reflect.TypeFor[Map[string, any]]()
|
|
s.True(strings.HasPrefix(cT.String(), chasmMapTypePrefix))
|
|
}
|
|
|
|
func (s *fieldsIteratorSuite) TestFieldsOf() {
|
|
type fieldPointer struct {
|
|
DataField *protoMessageType
|
|
InvalidField *Field[string]
|
|
}
|
|
|
|
type noDataField struct {
|
|
SubField Field[string]
|
|
SubMap Map[string, int]
|
|
}
|
|
|
|
type twoDataFields struct {
|
|
DataField *protoMessageType
|
|
AnotherDataField *protoMessageType
|
|
}
|
|
|
|
type unimplementedComponentOnly struct {
|
|
UnimplementedComponent
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
input any
|
|
expectedKinds []fieldKind
|
|
expectedNames []string
|
|
expectedTypes []string
|
|
expectedErrors []string
|
|
}{
|
|
{
|
|
name: "Valid component with one data field",
|
|
input: &struct {
|
|
UnimplementedComponent
|
|
DataField *protoMessageType
|
|
SubField Field[string]
|
|
SubMap Map[string, int]
|
|
ignored *struct{}
|
|
}{},
|
|
expectedKinds: []fieldKind{fieldKindData, fieldKindSubField, fieldKindSubMap},
|
|
expectedNames: []string{"DataField", "SubField", "SubMap"},
|
|
expectedTypes: []string{"*persistence.WorkflowExecutionState", "chasm.Field[string]", "chasm.Map[string,int]"},
|
|
expectedErrors: []string{"", "", ""},
|
|
},
|
|
{
|
|
name: "Component with no data field",
|
|
input: &noDataField{},
|
|
expectedKinds: []fieldKind{fieldKindSubField, fieldKindSubMap, fieldKindUnspecified},
|
|
expectedNames: []string{"SubField", "SubMap", ""},
|
|
expectedTypes: []string{"chasm.Field[string]", "chasm.Map[string,int]", ""},
|
|
expectedErrors: []string{"", "", "*chasm.noDataField: no data field (implements proto.Message) found"},
|
|
},
|
|
{
|
|
name: "Component with *Field",
|
|
input: &fieldPointer{},
|
|
expectedKinds: []fieldKind{fieldKindData, fieldKindUnspecified},
|
|
expectedNames: []string{"DataField", "InvalidField"},
|
|
expectedTypes: []string{"*persistence.WorkflowExecutionState", "*chasm.Field[string]"},
|
|
expectedErrors: []string{"", "*chasm.fieldPointer.InvalidField: CHASM fields must not be pointers"},
|
|
},
|
|
{
|
|
name: "Component with multiple data fields",
|
|
input: &twoDataFields{},
|
|
expectedKinds: []fieldKind{fieldKindData, fieldKindData},
|
|
expectedNames: []string{"DataField", "AnotherDataField"},
|
|
expectedTypes: []string{"*persistence.WorkflowExecutionState", "*persistence.WorkflowExecutionState"},
|
|
expectedErrors: []string{"", "*chasm.twoDataFields.AnotherDataField: only one data field DataField (implements proto.Message) allowed in component"},
|
|
},
|
|
{
|
|
name: "Component with UnimplementedComponent only",
|
|
input: &unimplementedComponentOnly{},
|
|
expectedKinds: []fieldKind{fieldKindUnspecified},
|
|
expectedNames: []string{""},
|
|
expectedTypes: []string{""},
|
|
expectedErrors: []string{"*chasm.unimplementedComponentOnly: no data field (implements proto.Message) found"},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
s.Run(tt.name, func() {
|
|
valueV := reflect.ValueOf(tt.input)
|
|
|
|
var actualKinds []fieldKind
|
|
var actualNames []string
|
|
var actualTypes []string
|
|
var actualErrors []string
|
|
|
|
for field := range fieldsOf(valueV) {
|
|
actualKinds = append(actualKinds, field.kind)
|
|
actualNames = append(actualNames, field.name)
|
|
if field.typ != nil {
|
|
actualTypes = append(actualTypes, field.typ.String())
|
|
} else {
|
|
actualTypes = append(actualTypes, "")
|
|
}
|
|
if field.err != nil {
|
|
actualErrors = append(actualErrors, field.err.Error())
|
|
} else {
|
|
actualErrors = append(actualErrors, "")
|
|
}
|
|
}
|
|
|
|
s.Equal(tt.expectedKinds, actualKinds)
|
|
s.Equal(tt.expectedNames, actualNames)
|
|
s.Equal(tt.expectedTypes, actualTypes)
|
|
s.Equal(tt.expectedErrors, actualErrors)
|
|
})
|
|
}
|
|
}
|
|
|
|
func (s *fieldsIteratorSuite) TestUnmanagedFieldsOf() {
|
|
type unmanagedFields struct {
|
|
UnimplementedComponent
|
|
|
|
DataField *protoMessageType
|
|
SomeField Field[string]
|
|
unmanaged struct{}
|
|
anotherPtr *struct{}
|
|
}
|
|
|
|
var result []string
|
|
for r := range unmanagedFieldsOf(reflect.TypeFor[unmanagedFields]()) {
|
|
result = append(result, r.name)
|
|
}
|
|
s.Len(result, 2)
|
|
s.ElementsMatch([]string{"unmanaged", "anotherPtr"}, result)
|
|
}
|
|
|
|
func (s *fieldsIteratorSuite) TestHasVisibilityField() {
|
|
type componentWithVisibility struct {
|
|
UnimplementedComponent
|
|
DataField *protoMessageType
|
|
Visibility Field[*Visibility]
|
|
}
|
|
|
|
type componentWithoutVisibility struct {
|
|
UnimplementedComponent
|
|
DataField *protoMessageType
|
|
SomeField Field[string]
|
|
}
|
|
|
|
s.Run("component with Visibility field", func() {
|
|
s.True(hasVisibilityField(reflect.TypeFor[componentWithVisibility]()))
|
|
s.True(hasVisibilityField(reflect.TypeFor[*componentWithVisibility]()))
|
|
})
|
|
|
|
s.Run("component without Visibility field", func() {
|
|
s.False(hasVisibilityField(reflect.TypeFor[componentWithoutVisibility]()))
|
|
s.False(hasVisibilityField(reflect.TypeFor[*componentWithoutVisibility]()))
|
|
})
|
|
|
|
s.Run("non-struct type", func() {
|
|
s.False(hasVisibilityField(reflect.TypeFor[string]()))
|
|
s.False(hasVisibilityField(reflect.TypeFor[int]()))
|
|
})
|
|
}
|