diff --git a/cmd/go.mod b/cmd/go.mod index 8f723d80..5fe68f73 100644 --- a/cmd/go.mod +++ b/cmd/go.mod @@ -36,7 +36,7 @@ require ( github.com/dlclark/regexp2 v1.11.4 // indirect github.com/dop251/goja v0.0.0-20241024094426-79f3a7efcdbd // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect - github.com/evanw/esbuild v0.24.0 // indirect + github.com/evanw/esbuild v0.24.2 // indirect github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect github.com/golang/snappy v0.0.4 // indirect @@ -81,8 +81,8 @@ require ( golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb // indirect - google.golang.org/protobuf v1.36.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20241223144023-3abc09e42ca8 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 // indirect + google.golang.org/protobuf v1.36.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/cmd/go.sum b/cmd/go.sum index 3cda7ef5..309e37e9 100644 --- a/cmd/go.sum +++ b/cmd/go.sum @@ -37,8 +37,8 @@ github.com/dop251/goja v0.0.0-20241024094426-79f3a7efcdbd h1:QMSNEh9uQkDjyPwu/J5 github.com/dop251/goja v0.0.0-20241024094426-79f3a7efcdbd/go.mod h1:MxLav0peU43GgvwVgNbLAj1s/bSGboKkhuULvq/7hx4= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= -github.com/evanw/esbuild v0.24.0 h1:GZ78naTLp7FKr+K7eNuM/SLs5maeiHYRPsTg6kmdsSE= -github.com/evanw/esbuild v0.24.0/go.mod h1:D2vIQZqV/vIf/VRHtViaUtViZmG7o+kKmlBfVQuRi48= +github.com/evanw/esbuild v0.24.2 h1:PQExybVBrjHjN6/JJiShRGIXh1hWVm6NepVnhZhrt0A= +github.com/evanw/esbuild v0.24.2/go.mod h1:D2vIQZqV/vIf/VRHtViaUtViZmG7o+kKmlBfVQuRi48= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= @@ -212,12 +212,12 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb h1:B7GIB7sr443wZ/EAEl7VZjmh1V6qzkt5V+RYcUYtS1U= -google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb/go.mod h1:E5//3O5ZIG2l71Xnt+P/CYUY8Bxs8E7WMoZ9tlcMbAY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb h1:3oy2tynMOP1QbTC0MsNNAV+Se8M2Bd0A5+x1QHyw+pI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA= -google.golang.org/protobuf v1.36.0 h1:mjIs9gYtt56AzC4ZaffQuh88TZurBGhIJMBZGSxNerQ= -google.golang.org/protobuf v1.36.0/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/genproto/googleapis/api v0.0.0-20241223144023-3abc09e42ca8 h1:st3LcW/BPi75W4q1jJTEor/QWwbNlPlDG0JTn6XhZu0= +google.golang.org/genproto/googleapis/api v0.0.0-20241223144023-3abc09e42ca8/go.mod h1:klhJGKFyG8Tn50enBn7gizg4nXGXJ+jqEREdCWaPcV4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 h1:TqExAhdPaB60Ux47Cn0oLV07rGnxZzIsaRhQaqS666A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA= +google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= +google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/cmd/pkg/cli/apply_test.go b/cmd/pkg/cli/apply_test.go index 6e119db6..27c136af 100644 --- a/cmd/pkg/cli/apply_test.go +++ b/cmd/pkg/cli/apply_test.go @@ -122,7 +122,7 @@ func TestApplyCommand_Execute(t *testing.T) { scrt := &secret.Secret{ Name: faker.UUIDHyphenated(), - Data: faker.Word(), + Data: faker.UUIDHyphenated(), } data, err := json.Marshal(scrt) @@ -164,7 +164,7 @@ func TestApplyCommand_Execute(t *testing.T) { scrt := &secret.Secret{ Name: faker.UUIDHyphenated(), - Data: faker.Word(), + Data: faker.UUIDHyphenated(), } _, err := secretStore.Store(ctx, scrt) @@ -209,7 +209,7 @@ func TestApplyCommand_Execute(t *testing.T) { chrt := &chart.Chart{ ID: uuid.Must(uuid.NewV7()), - Name: faker.Word(), + Name: faker.UUIDHyphenated(), } data, err := json.Marshal(chrt) @@ -251,7 +251,7 @@ func TestApplyCommand_Execute(t *testing.T) { chrt := &chart.Chart{ ID: uuid.Must(uuid.NewV7()), - Name: faker.Word(), + Name: faker.UUIDHyphenated(), } _, err := chartStore.Store(ctx, chrt) diff --git a/cmd/pkg/cli/delete_test.go b/cmd/pkg/cli/delete_test.go index 2b3381eb..44848cba 100644 --- a/cmd/pkg/cli/delete_test.go +++ b/cmd/pkg/cli/delete_test.go @@ -73,7 +73,7 @@ func TestDeleteCommand_Execute(t *testing.T) { scrt := &secret.Secret{ Name: faker.UUIDHyphenated(), - Data: faker.Word(), + Data: faker.UUIDHyphenated(), } data, err := json.Marshal(scrt) @@ -114,7 +114,7 @@ func TestDeleteCommand_Execute(t *testing.T) { chrt := &chart.Chart{ ID: uuid.Must(uuid.NewV7()), - Name: faker.Word(), + Name: faker.UUIDHyphenated(), } data, err := json.Marshal(chrt) diff --git a/cmd/pkg/cli/get_test.go b/cmd/pkg/cli/get_test.go index d2293af6..407c90ca 100644 --- a/cmd/pkg/cli/get_test.go +++ b/cmd/pkg/cli/get_test.go @@ -55,7 +55,7 @@ func TestGetCommand_Execute(t *testing.T) { scrt := &secret.Secret{ Name: faker.UUIDHyphenated(), - Data: faker.Word(), + Data: faker.UUIDHyphenated(), } _, err := secretStore.Store(ctx, scrt) @@ -84,7 +84,7 @@ func TestGetCommand_Execute(t *testing.T) { chrt := &chart.Chart{ ID: uuid.Must(uuid.NewV7()), - Name: faker.Word(), + Name: faker.UUIDHyphenated(), } _, err := chartStore.Store(ctx, chrt) diff --git a/cmd/pkg/cli/start_test.go b/cmd/pkg/cli/start_test.go index aea55e66..33abb7e8 100644 --- a/cmd/pkg/cli/start_test.go +++ b/cmd/pkg/cli/start_test.go @@ -189,7 +189,7 @@ func TestStartCommand_Execute(t *testing.T) { scrt := &secret.Secret{ ID: uuid.Must(uuid.NewV7()), Namespace: resource.DefaultNamespace, - Data: faker.Word(), + Data: faker.UUIDHyphenated(), } data, _ := json.Marshal(scrt) @@ -236,7 +236,7 @@ func TestStartCommand_Execute(t *testing.T) { chrt := &chart.Chart{ ID: uuid.Must(uuid.NewV7()), Namespace: resource.DefaultNamespace, - Name: faker.Word(), + Name: faker.UUIDHyphenated(), } data, _ := json.Marshal(chrt) diff --git a/driver/mongo/pkg/chart/store.go b/driver/mongo/pkg/chart/store.go index 83b149ce..92eeee53 100644 --- a/driver/mongo/pkg/chart/store.go +++ b/driver/mongo/pkg/chart/store.go @@ -2,6 +2,8 @@ package chart import ( "context" + "github.com/go-playground/validator/v10" + "github.com/siyul-park/uniflow/pkg/encoding" "github.com/gofrs/uuid" "github.com/pkg/errors" @@ -17,6 +19,7 @@ import ( // Store manages storage and retrieval of Spec objects in a MongoDB collection. type Store struct { collection *mongo.Collection + validate *validator.Validate } // Stream represents a MongoDB change stream for tracking Spec changes. @@ -39,7 +42,10 @@ var _ chart.Stream = (*Stream)(nil) // NewStore creates a new Store with the specified MongoDB collection. func NewStore(collection *mongo.Collection) *Store { - return &Store{collection: collection} + return &Store{ + collection: collection, + validate: validator.New(validator.WithRequiredStructEnabled()), + } } // Index ensures the collection has the required indexes and updates them if necessary. @@ -120,6 +126,10 @@ func (s *Store) Store(ctx context.Context, charts ...*chart.Chart) (int, error) chrt.SetNamespace(resource.DefaultNamespace) } + if err := s.validate.Struct(chrt); err != nil { + return 0, errors.WithMessage(encoding.ErrUnsupportedValue, err.Error()) + } + docs = append(docs, chrt) } @@ -140,6 +150,11 @@ func (s *Store) Swap(ctx context.Context, charts ...*chart.Chart) (int, error) { if chrt.GetID() == uuid.Nil { chrt.SetID(uuid.Must(uuid.NewV7())) } + + if err := s.validate.Struct(chrt); err != nil { + return 0, errors.WithMessage(encoding.ErrUnsupportedValue, err.Error()) + } + ids[i] = chrt.GetID() } diff --git a/driver/mongo/pkg/chart/store_test.go b/driver/mongo/pkg/chart/store_test.go index 9565d9d3..dc28801d 100644 --- a/driver/mongo/pkg/chart/store_test.go +++ b/driver/mongo/pkg/chart/store_test.go @@ -2,13 +2,13 @@ package chart import ( "context" + "github.com/siyul-park/uniflow/pkg/spec" "testing" "github.com/go-faker/faker/v4" "github.com/gofrs/uuid" "github.com/siyul-park/uniflow/driver/mongo/pkg/server" "github.com/siyul-park/uniflow/pkg/chart" - "github.com/siyul-park/uniflow/pkg/resource" "github.com/stretchr/testify/assert" "go.mongodb.org/mongo-driver/v2/mongo" "go.mongodb.org/mongo-driver/v2/mongo/options" @@ -59,8 +59,7 @@ func TestStore_Watch(t *testing.T) { }() chrt := &chart.Chart{ - ID: uuid.Must(uuid.NewV7()), - Namespace: resource.DefaultNamespace, + ID: uuid.Must(uuid.NewV7()), } _, _ = st.Store(ctx, chrt) @@ -110,6 +109,14 @@ func TestStore_Store(t *testing.T) { chrt1 := &chart.Chart{ ID: uuid.Must(uuid.NewV7()), + Specs: []*spec.Unstructured{ + { + Meta: spec.Meta{ + ID: uuid.Must(uuid.NewV7()), + Kind: faker.UUIDHyphenated(), + }, + }, + }, } chrt2 := &chart.Chart{ ID: uuid.Must(uuid.NewV7()), diff --git a/driver/mongo/pkg/secret/store.go b/driver/mongo/pkg/secret/store.go index 967cecf9..42b77606 100644 --- a/driver/mongo/pkg/secret/store.go +++ b/driver/mongo/pkg/secret/store.go @@ -2,6 +2,8 @@ package secret import ( "context" + "github.com/go-playground/validator/v10" + "github.com/siyul-park/uniflow/pkg/encoding" "github.com/gofrs/uuid" "github.com/pkg/errors" @@ -16,6 +18,7 @@ import ( // Store manages storage and retrieval of Spec objects in a MongoDB collection. type Store struct { collection *mongo.Collection + validate *validator.Validate } // Stream represents a MongoDB change stream for tracking Spec changes. @@ -38,7 +41,10 @@ var _ secret.Stream = (*Stream)(nil) // NewStore creates a new Store with the specified MongoDB collection. func NewStore(collection *mongo.Collection) *Store { - return &Store{collection: collection} + return &Store{ + collection: collection, + validate: validator.New(validator.WithRequiredStructEnabled()), + } } // Index ensures the collection has the required indexes and updates them if necessary. @@ -119,6 +125,10 @@ func (s *Store) Store(ctx context.Context, secrets ...*secret.Secret) (int, erro scrt.SetNamespace(resource.DefaultNamespace) } + if err := s.validate.Struct(scrt); err != nil { + return 0, errors.WithMessage(encoding.ErrUnsupportedValue, err.Error()) + } + docs = append(docs, scrt) } @@ -139,6 +149,11 @@ func (s *Store) Swap(ctx context.Context, secrets ...*secret.Secret) (int, error if scrt.GetID() == uuid.Nil { scrt.SetID(uuid.Must(uuid.NewV7())) } + + if err := s.validate.Struct(scrt); err != nil { + return 0, errors.WithMessage(encoding.ErrUnsupportedValue, err.Error()) + } + ids[i] = scrt.GetID() } diff --git a/driver/mongo/pkg/secret/store_test.go b/driver/mongo/pkg/secret/store_test.go index d5abea34..6a7acfb6 100644 --- a/driver/mongo/pkg/secret/store_test.go +++ b/driver/mongo/pkg/secret/store_test.go @@ -7,7 +7,6 @@ import ( "github.com/go-faker/faker/v4" "github.com/gofrs/uuid" "github.com/siyul-park/uniflow/driver/mongo/pkg/server" - "github.com/siyul-park/uniflow/pkg/resource" "github.com/siyul-park/uniflow/pkg/secret" "github.com/stretchr/testify/assert" "go.mongodb.org/mongo-driver/v2/mongo" @@ -59,8 +58,8 @@ func TestStore_Watch(t *testing.T) { }() scrt := &secret.Secret{ - ID: uuid.Must(uuid.NewV7()), - Namespace: resource.DefaultNamespace, + ID: uuid.Must(uuid.NewV7()), + Data: faker.UUIDHyphenated(), } _, _ = st.Store(ctx, scrt) @@ -81,10 +80,12 @@ func TestStore_Load(t *testing.T) { st := NewStore(c.Database(faker.UUIDHyphenated()).Collection(faker.UUIDHyphenated())) scrt1 := &secret.Secret{ - ID: uuid.Must(uuid.NewV7()), + ID: uuid.Must(uuid.NewV7()), + Data: faker.UUIDHyphenated(), } scrt2 := &secret.Secret{ - ID: uuid.Must(uuid.NewV7()), + ID: uuid.Must(uuid.NewV7()), + Data: faker.UUIDHyphenated(), } count, err := st.Store(ctx, scrt1, scrt2) @@ -109,10 +110,12 @@ func TestStore_Store(t *testing.T) { st := NewStore(c.Database(faker.UUIDHyphenated()).Collection(faker.UUIDHyphenated())) scrt1 := &secret.Secret{ - ID: uuid.Must(uuid.NewV7()), + ID: uuid.Must(uuid.NewV7()), + Data: faker.UUIDHyphenated(), } scrt2 := &secret.Secret{ - ID: uuid.Must(uuid.NewV7()), + ID: uuid.Must(uuid.NewV7()), + Data: faker.UUIDHyphenated(), } count, err := st.Store(ctx, scrt1, scrt2) @@ -137,10 +140,12 @@ func TestStore_Swap(t *testing.T) { st := NewStore(c.Database(faker.UUIDHyphenated()).Collection(faker.UUIDHyphenated())) scrt1 := &secret.Secret{ - ID: uuid.Must(uuid.NewV7()), + ID: uuid.Must(uuid.NewV7()), + Data: faker.UUIDHyphenated(), } scrt2 := &secret.Secret{ - ID: uuid.Must(uuid.NewV7()), + ID: uuid.Must(uuid.NewV7()), + Data: faker.UUIDHyphenated(), } count, err := st.Store(ctx, scrt1, scrt2) @@ -169,10 +174,12 @@ func TestMemStore_Delete(t *testing.T) { st := NewStore(c.Database(faker.UUIDHyphenated()).Collection(faker.UUIDHyphenated())) scrt1 := &secret.Secret{ - ID: uuid.Must(uuid.NewV7()), + ID: uuid.Must(uuid.NewV7()), + Data: faker.UUIDHyphenated(), } scrt2 := &secret.Secret{ - ID: uuid.Must(uuid.NewV7()), + ID: uuid.Must(uuid.NewV7()), + Data: faker.UUIDHyphenated(), } count, err := st.Store(ctx, scrt1, scrt2) diff --git a/driver/mongo/pkg/spec/store.go b/driver/mongo/pkg/spec/store.go index fbdd84e3..b21f917c 100644 --- a/driver/mongo/pkg/spec/store.go +++ b/driver/mongo/pkg/spec/store.go @@ -2,6 +2,8 @@ package spec import ( "context" + "github.com/go-playground/validator/v10" + "github.com/siyul-park/uniflow/pkg/encoding" "github.com/gofrs/uuid" "github.com/pkg/errors" @@ -17,6 +19,7 @@ import ( // Store manages storage and retrieval of Spec objects in a MongoDB collection. type Store struct { collection *mongo.Collection + validate *validator.Validate } // Stream represents a MongoDB change stream for tracking Spec changes. @@ -39,7 +42,10 @@ var _ spec.Stream = (*Stream)(nil) // NewStore creates a new Store with the specified MongoDB collection. func NewStore(collection *mongo.Collection) *Store { - return &Store{collection: collection} + return &Store{ + collection: collection, + validate: validator.New(validator.WithRequiredStructEnabled()), + } } // Index ensures the collection has the required indexes and updates them if necessary. @@ -123,6 +129,10 @@ func (s *Store) Store(ctx context.Context, specs ...spec.Spec) (int, error) { sp.SetNamespace(resource.DefaultNamespace) } + if err := s.validate.Struct(sp); err != nil { + return 0, errors.WithMessage(encoding.ErrUnsupportedValue, err.Error()) + } + doc, err := types.Marshal(sp) if err != nil { return 0, err @@ -153,6 +163,11 @@ func (s *Store) Swap(ctx context.Context, specs ...spec.Spec) (int, error) { if sp.GetID() == uuid.Nil { sp.SetID(uuid.Must(uuid.NewV7())) } + + if err := s.validate.Struct(sp); err != nil { + return 0, errors.WithMessage(encoding.ErrUnsupportedValue, err.Error()) + } + ids[i] = sp.GetID() } diff --git a/driver/mongo/pkg/spec/store_test.go b/driver/mongo/pkg/spec/store_test.go index efa95ddd..c2b36ec2 100644 --- a/driver/mongo/pkg/spec/store_test.go +++ b/driver/mongo/pkg/spec/store_test.go @@ -7,7 +7,6 @@ import ( "github.com/go-faker/faker/v4" "github.com/gofrs/uuid" "github.com/siyul-park/uniflow/driver/mongo/pkg/server" - "github.com/siyul-park/uniflow/pkg/resource" "github.com/siyul-park/uniflow/pkg/spec" "github.com/stretchr/testify/assert" "go.mongodb.org/mongo-driver/v2/mongo" @@ -61,9 +60,8 @@ func TestStore_Watch(t *testing.T) { }() meta := &spec.Meta{ - ID: uuid.Must(uuid.NewV7()), - Kind: kind, - Namespace: resource.DefaultNamespace, + ID: uuid.Must(uuid.NewV7()), + Kind: kind, } _, _ = st.Store(ctx, meta) diff --git a/ext/go.mod b/ext/go.mod index 9c1bbd9f..283ff320 100644 --- a/ext/go.mod +++ b/ext/go.mod @@ -6,7 +6,7 @@ require ( github.com/andybalholm/brotli v1.1.1 github.com/dop251/goja v0.0.0-20241024094426-79f3a7efcdbd github.com/evanphx/json-patch/v5 v5.9.0 - github.com/evanw/esbuild v0.24.0 + github.com/evanw/esbuild v0.24.2 github.com/go-faker/faker/v4 v4.5.0 github.com/gofrs/uuid v4.4.0+incompatible github.com/google/cel-go v0.22.1 @@ -37,7 +37,7 @@ require ( golang.org/x/net v0.33.0 golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb // indirect - google.golang.org/protobuf v1.36.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20241223144023-3abc09e42ca8 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 // indirect + google.golang.org/protobuf v1.36.1 // indirect ) diff --git a/ext/go.sum b/ext/go.sum index 042e0878..bf2fb1fb 100644 --- a/ext/go.sum +++ b/ext/go.sum @@ -21,8 +21,8 @@ github.com/dop251/goja v0.0.0-20241024094426-79f3a7efcdbd h1:QMSNEh9uQkDjyPwu/J5 github.com/dop251/goja v0.0.0-20241024094426-79f3a7efcdbd/go.mod h1:MxLav0peU43GgvwVgNbLAj1s/bSGboKkhuULvq/7hx4= github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= -github.com/evanw/esbuild v0.24.0 h1:GZ78naTLp7FKr+K7eNuM/SLs5maeiHYRPsTg6kmdsSE= -github.com/evanw/esbuild v0.24.0/go.mod h1:D2vIQZqV/vIf/VRHtViaUtViZmG7o+kKmlBfVQuRi48= +github.com/evanw/esbuild v0.24.2 h1:PQExybVBrjHjN6/JJiShRGIXh1hWVm6NepVnhZhrt0A= +github.com/evanw/esbuild v0.24.2/go.mod h1:D2vIQZqV/vIf/VRHtViaUtViZmG7o+kKmlBfVQuRi48= github.com/go-faker/faker/v4 v4.5.0 h1:ARzAY2XoOL9tOUK+KSecUQzyXQsUaZHefjyF8x6YFHc= github.com/go-faker/faker/v4 v4.5.0/go.mod h1:p3oq1GRjG2PZ7yqeFFfQI20Xm61DoBDlCA8RiSyZ48M= github.com/go-sourcemap/sourcemap v2.1.4+incompatible h1:a+iTbH5auLKxaNwQFg0B+TCYl6lbukKPc7b5x0n1s6Q= @@ -86,12 +86,12 @@ golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb h1:B7GIB7sr443wZ/EAEl7VZjmh1V6qzkt5V+RYcUYtS1U= -google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb/go.mod h1:E5//3O5ZIG2l71Xnt+P/CYUY8Bxs8E7WMoZ9tlcMbAY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb h1:3oy2tynMOP1QbTC0MsNNAV+Se8M2Bd0A5+x1QHyw+pI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA= -google.golang.org/protobuf v1.36.0 h1:mjIs9gYtt56AzC4ZaffQuh88TZurBGhIJMBZGSxNerQ= -google.golang.org/protobuf v1.36.0/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/genproto/googleapis/api v0.0.0-20241223144023-3abc09e42ca8 h1:st3LcW/BPi75W4q1jJTEor/QWwbNlPlDG0JTn6XhZu0= +google.golang.org/genproto/googleapis/api v0.0.0-20241223144023-3abc09e42ca8/go.mod h1:klhJGKFyG8Tn50enBn7gizg4nXGXJ+jqEREdCWaPcV4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 h1:TqExAhdPaB60Ux47Cn0oLV07rGnxZzIsaRhQaqS666A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA= +google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= +google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/ext/pkg/control/block.go b/ext/pkg/control/block.go index cac91e24..bfeb7d9d 100644 --- a/ext/pkg/control/block.go +++ b/ext/pkg/control/block.go @@ -11,7 +11,7 @@ import ( // BlockNodeSpec defines the specification for creating a BlockNode. type BlockNodeSpec struct { spec.Meta `map:",inline"` - Specs []spec.Spec `map:"specs"` + Specs []*spec.Unstructured `map:"specs"` Inbounds map[string][]spec.Port `map:"inbounds,omitempty"` Outbounds map[string][]spec.Port `map:"outbounds,omitempty"` } @@ -20,9 +20,13 @@ const KindBlock = "block" // NewBlockNodeCodec creates a new codec for BlockNodeSpec. func NewBlockNodeCodec(s *scheme.Scheme) scheme.Codec { - return scheme.CodecWithType(func(sp *BlockNodeSpec) (node.Node, error) { - symbols := make([]*symbol.Symbol, 0, len(sp.Specs)) - for i, sp := range sp.Specs { + return scheme.CodecWithType(func(root *BlockNodeSpec) (node.Node, error) { + symbols := make([]*symbol.Symbol, 0, len(root.Specs)) + for i, sp := range root.Specs { + if sp.GetNamespace() == "" { + sp.SetNamespace(fmt.Sprintf("%s/%s", root.GetNamespace(), root.GetID())) + } + sp, err := s.Decode(sp) if err != nil { for _, sb := range symbols { @@ -51,12 +55,12 @@ func NewBlockNodeCodec(s *scheme.Scheme) scheme.Codec { cluster := symbol.NewCluster(symbols) - for name, ports := range sp.Inbounds { + for name, ports := range root.Inbounds { for _, port := range ports { cluster.Inbound(name, port) } } - for name, ports := range sp.Outbounds { + for name, ports := range root.Outbounds { for _, port := range ports { cluster.Outbound(name, port) } diff --git a/ext/pkg/control/block_test.go b/ext/pkg/control/block_test.go index 737669e3..317164a9 100644 --- a/ext/pkg/control/block_test.go +++ b/ext/pkg/control/block_test.go @@ -23,14 +23,14 @@ func TestBlockNodeCodec_Compile(t *testing.T) { codec := NewBlockNodeCodec(s) sp := &BlockNodeSpec{ - Specs: []spec.Spec{ - &spec.Unstructured{ + Specs: []*spec.Unstructured{ + { Meta: spec.Meta{ ID: uuid.Must(uuid.NewV7()), Kind: kind, }, }, - &spec.Unstructured{ + { Meta: spec.Meta{ ID: uuid.Must(uuid.NewV7()), Kind: kind, diff --git a/ext/pkg/control/if.go b/ext/pkg/control/if.go index 1a4de802..36d1e075 100644 --- a/ext/pkg/control/if.go +++ b/ext/pkg/control/if.go @@ -17,7 +17,7 @@ import ( // IfNodeSpec defines the specifications for creating an IfNode. type IfNodeSpec struct { spec.Meta `map:",inline"` - When string `map:"when"` + When string `map:"when" validate:"required"` Timeout time.Duration `map:"timeout,omitempty"` } diff --git a/ext/pkg/control/merge.go b/ext/pkg/control/merge.go index 15c809c0..ea00a85d 100644 --- a/ext/pkg/control/merge.go +++ b/ext/pkg/control/merge.go @@ -36,7 +36,7 @@ func NewMergeNode() *MergeNode { } func (n *MergeNode) action(_ *process.Process, inPcks []*packet.Packet) (*packet.Packet, *packet.Packet) { - outPck := packet.Merge(inPcks) + outPck := packet.Join(inPcks...) if _, ok := outPck.Payload().(types.Error); ok { return nil, outPck diff --git a/ext/pkg/control/reduce.go b/ext/pkg/control/reduce.go index e88375c8..ceec017e 100644 --- a/ext/pkg/control/reduce.go +++ b/ext/pkg/control/reduce.go @@ -17,7 +17,7 @@ import ( // ReduceNodeSpec defines the specifications for creating a ReduceNode. type ReduceNodeSpec struct { spec.Meta `map:",inline"` - Action string `map:"action"` + Action string `map:"action" validate:"required"` Init any `map:"init,omitempty"` Timeout time.Duration `map:"timeout,omitempty"` } diff --git a/ext/pkg/control/retry.go b/ext/pkg/control/retry.go index dc8a0df0..09f6ef03 100644 --- a/ext/pkg/control/retry.go +++ b/ext/pkg/control/retry.go @@ -14,7 +14,7 @@ import ( // RetryNodeSpec defines the configuration for RetryNode. type RetryNodeSpec struct { spec.Meta `map:",inline"` - Threshold int `map:"threshold"` + Threshold int `map:"threshold,omitempty"` } // RetryNode attempts to process packets up to a specified retry limit. diff --git a/ext/pkg/control/retry_test.go b/ext/pkg/control/retry_test.go index edf3eb90..41e0d1fb 100644 --- a/ext/pkg/control/retry_test.go +++ b/ext/pkg/control/retry_test.go @@ -68,7 +68,7 @@ func TestRetryNode_SendAndReceive(t *testing.T) { inWriter := in.Open(proc) - inPayload := types.NewString(faker.Word()) + inPayload := types.NewString(faker.UUIDHyphenated()) inPck := packet.New(inPayload) inWriter.Write(inPck) @@ -101,7 +101,7 @@ func BenchmarkRetryNode_SendAndReceive(b *testing.B) { inWriter := in.Open(proc) - inPayload := types.NewString(faker.Word()) + inPayload := types.NewString(faker.UUIDHyphenated()) inPck := packet.New(inPayload) b.ResetTimer() diff --git a/ext/pkg/control/snippet.go b/ext/pkg/control/snippet.go index 599f52a6..fd57ef27 100644 --- a/ext/pkg/control/snippet.go +++ b/ext/pkg/control/snippet.go @@ -16,8 +16,8 @@ import ( // SnippetNodeSpec defines the specifications for creating a SnippetNode. type SnippetNodeSpec struct { spec.Meta `map:",inline"` - Language string `map:"language,omitempty"` - Code string `map:"code"` + Language string `map:"language" validate:"required"` + Code string `map:"code" validate:"required"` Timeout time.Duration `map:"timeout,omitempty"` } diff --git a/ext/pkg/control/snippet_test.go b/ext/pkg/control/snippet_test.go index 7e8fd955..841bb747 100644 --- a/ext/pkg/control/snippet_test.go +++ b/ext/pkg/control/snippet_test.go @@ -56,7 +56,7 @@ func TestSnippetNode_SendAndReceive(t *testing.T) { inWriter := in.Open(proc) - inPayload := types.NewString(faker.Word()) + inPayload := types.NewString(faker.UUIDHyphenated()) inPck := packet.New(inPayload) inWriter.Write(inPck) diff --git a/ext/pkg/control/split_test.go b/ext/pkg/control/split_test.go index abbd87b0..cfe177f7 100644 --- a/ext/pkg/control/split_test.go +++ b/ext/pkg/control/split_test.go @@ -60,7 +60,7 @@ func TestSplitNode_SendAndReceive(t *testing.T) { inPayload := types.NewSlice() for range outs { - inPayload = inPayload.Append(types.NewString(faker.Word())) + inPayload = inPayload.Append(types.NewString(faker.UUIDHyphenated())) } inPck := packet.New(inPayload) @@ -109,7 +109,7 @@ func BenchmarkSplitNode_SendAndReceive(b *testing.B) { inPayload := types.NewSlice() for range outs { - inPayload = inPayload.Append(types.NewString(faker.Word())) + inPayload = inPayload.Append(types.NewString(faker.UUIDHyphenated())) } inPck := packet.New(inPayload) diff --git a/ext/pkg/control/step.go b/ext/pkg/control/step.go index 6a004721..98afa16e 100644 --- a/ext/pkg/control/step.go +++ b/ext/pkg/control/step.go @@ -1,6 +1,7 @@ package control import ( + "fmt" "github.com/siyul-park/uniflow/pkg/node" "github.com/siyul-park/uniflow/pkg/scheme" "github.com/siyul-park/uniflow/pkg/spec" @@ -10,16 +11,20 @@ import ( // StepNodeSpec defines the specification for creating a StepNode. type StepNodeSpec struct { spec.Meta `map:",inline"` - Specs []spec.Spec `map:"specs"` + Specs []*spec.Unstructured `map:"specs"` } const KindStep = "step" // NewStepNodeCodec creates a new codec for StepNodeSpec. func NewStepNodeCodec(s *scheme.Scheme) scheme.Codec { - return scheme.CodecWithType(func(sp *StepNodeSpec) (node.Node, error) { - symbols := make([]*symbol.Symbol, 0, len(sp.Specs)) - for _, sp := range sp.Specs { + return scheme.CodecWithType(func(root *StepNodeSpec) (node.Node, error) { + symbols := make([]*symbol.Symbol, 0, len(root.Specs)) + for _, sp := range root.Specs { + if sp.GetNamespace() == "" { + sp.SetNamespace(fmt.Sprintf("%s/%s", root.GetNamespace(), root.GetID())) + } + sp, err := s.Decode(sp) if err != nil { for _, sb := range symbols { diff --git a/ext/pkg/control/step_test.go b/ext/pkg/control/step_test.go index 69a4cda8..8756a4a5 100644 --- a/ext/pkg/control/step_test.go +++ b/ext/pkg/control/step_test.go @@ -23,14 +23,14 @@ func TestStepNodeCodec_Compile(t *testing.T) { codec := NewStepNodeCodec(s) sp := &StepNodeSpec{ - Specs: []spec.Spec{ - &spec.Unstructured{ + Specs: []*spec.Unstructured{ + { Meta: spec.Meta{ ID: uuid.Must(uuid.NewV7()), Kind: kind, }, }, - &spec.Unstructured{ + { Meta: spec.Meta{ ID: uuid.Must(uuid.NewV7()), Kind: kind, diff --git a/ext/pkg/control/switch.go b/ext/pkg/control/switch.go index 1bc27751..78710d6e 100644 --- a/ext/pkg/control/switch.go +++ b/ext/pkg/control/switch.go @@ -18,14 +18,14 @@ import ( // SwitchNodeSpec holds specifications for creating a SwitchNode. type SwitchNodeSpec struct { spec.Meta `map:",inline"` - Matches []Condition `map:"matches"` + Matches []Condition `map:"matches" validate:"required"` Timeout time.Duration `map:"timeout,omitempty"` } // Condition represents a condition for directing packets to specific ports. type Condition struct { - When string `map:"when"` - Port string `map:"port"` + When string `map:"when" validate:"required"` + Port string `map:"port" validate:"required"` } // SwitchNode directs packets to different ports based on specified conditions. diff --git a/ext/pkg/control/wait.go b/ext/pkg/control/wait.go index 84165899..679863fd 100644 --- a/ext/pkg/control/wait.go +++ b/ext/pkg/control/wait.go @@ -12,7 +12,7 @@ import ( // WaitNodeSpec defines the configuration for WaitNode. type WaitNodeSpec struct { spec.Meta `map:",inline"` - Interval time.Duration `map:"interval"` + Interval time.Duration `map:"interval" validate:"required"` } // WaitNode adds a delay to packet processing, using a specified interval. diff --git a/ext/pkg/control/wait_test.go b/ext/pkg/control/wait_test.go index 8ebec6f5..134e04ce 100644 --- a/ext/pkg/control/wait_test.go +++ b/ext/pkg/control/wait_test.go @@ -47,7 +47,7 @@ func TestWaitNode_SendAndReceive(t *testing.T) { inWriter := in.Open(proc) - inPayload := types.NewString(faker.Word()) + inPayload := types.NewString(faker.UUIDHyphenated()) inPck := packet.New(inPayload) inWriter.Write(inPck) diff --git a/ext/pkg/io/sql.go b/ext/pkg/io/sql.go index 6856a336..d215e590 100644 --- a/ext/pkg/io/sql.go +++ b/ext/pkg/io/sql.go @@ -18,8 +18,8 @@ import ( // SQLNodeSpec defines the specifications for creating a SQLNode. type SQLNodeSpec struct { spec.Meta `map:",inline"` - Driver string `map:"driver"` - Source string `map:"source"` + Driver string `map:"driver" validate:"required"` + Source string `map:"source" validate:"required"` Isolation sql.IsolationLevel `map:"isolation,omitempty"` } diff --git a/ext/pkg/language/cel/compiler_test.go b/ext/pkg/language/cel/compiler_test.go index 37d72df9..6d62209f 100644 --- a/ext/pkg/language/cel/compiler_test.go +++ b/ext/pkg/language/cel/compiler_test.go @@ -22,7 +22,7 @@ func TestProgram_Run(t *testing.T) { c := NewCompiler() p, _ := c.Compile("self") - args := []any{faker.Word()} + args := []any{faker.UUIDHyphenated()} res, err := p.Run(ctx, args) assert.NoError(t, err) diff --git a/ext/pkg/language/javascript/compiler_test.go b/ext/pkg/language/javascript/compiler_test.go index a1f4650e..6400a72c 100644 --- a/ext/pkg/language/javascript/compiler_test.go +++ b/ext/pkg/language/javascript/compiler_test.go @@ -26,7 +26,7 @@ func TestProgram_Run(t *testing.T) { return args; }`) - args := []any{faker.Word()} + args := []any{faker.UUIDHyphenated()} res, err := p.Run(ctx, args) assert.NoError(t, err) diff --git a/ext/pkg/language/module_test.go b/ext/pkg/language/module_test.go index 4d3dfc00..9578dbc2 100644 --- a/ext/pkg/language/module_test.go +++ b/ext/pkg/language/module_test.go @@ -9,7 +9,7 @@ import ( ) func TestModule_StoreAndLoad(t *testing.T) { - lang := faker.Word() + lang := faker.UUIDHyphenated() c := CompileFunc(func(s string) (Program, error) { return RunFunc(func(_ context.Context, _ []any) ([]any, error) { return nil, nil diff --git a/ext/pkg/language/typescript/compiler_test.go b/ext/pkg/language/typescript/compiler_test.go index eb3bfce1..7d9207cb 100644 --- a/ext/pkg/language/typescript/compiler_test.go +++ b/ext/pkg/language/typescript/compiler_test.go @@ -26,7 +26,7 @@ func TestProgram_Run(t *testing.T) { return args; }`) - args := []any{faker.Word()} + args := []any{faker.UUIDHyphenated()} res, err := p.Run(ctx, args) assert.NoError(t, err) diff --git a/ext/pkg/mime/negotiation_test.go b/ext/pkg/mime/negotiation_test.go index 1b65ccc1..d12d6e27 100644 --- a/ext/pkg/mime/negotiation_test.go +++ b/ext/pkg/mime/negotiation_test.go @@ -44,7 +44,7 @@ func TestNegotiate(t *testing.T) { { when: "", - offers: []string{faker.Word(), faker.Word(), faker.Word()}, + offers: []string{faker.UUIDHyphenated(), faker.UUIDHyphenated(), faker.UUIDHyphenated()}, expect: "", }, { diff --git a/ext/pkg/network/gateway.go b/ext/pkg/network/gateway.go index cac01b7b..ae81d9b9 100644 --- a/ext/pkg/network/gateway.go +++ b/ext/pkg/network/gateway.go @@ -20,7 +20,7 @@ import ( // GatewayNodeSpec defines the specifications for creating a GatewayNode. type GatewayNodeSpec struct { spec.Meta `map:",inline"` - Protocol string `map:"protocol"` + Protocol string `map:"protocol" validate:"required"` Timeout time.Duration `map:"timeout,omitempty"` Buffer int `map:"buffer,omitempty"` } diff --git a/ext/pkg/network/http.go b/ext/pkg/network/http.go index 68e98568..9d273a3b 100644 --- a/ext/pkg/network/http.go +++ b/ext/pkg/network/http.go @@ -22,7 +22,7 @@ import ( // HTTPNodeSpec defines the specifications for creating an HTTPNode. type HTTPNodeSpec struct { spec.Meta `map:",inline"` - URL string `map:"url"` + URL string `map:"url" validate:"required,url"` Timeout time.Duration `map:"timeout,omitempty"` } diff --git a/ext/pkg/network/listener.go b/ext/pkg/network/listener.go index c685eea1..00b5f28d 100644 --- a/ext/pkg/network/listener.go +++ b/ext/pkg/network/listener.go @@ -26,9 +26,9 @@ import ( // ListenNodeSpec defines the specifications for creating a ListenNode. type ListenNodeSpec struct { spec.Meta `map:",inline"` - Protocol string `map:"protocol"` - Host string `map:"host,omitempty"` - Port int `map:"port"` + Protocol string `map:"protocol" validate:"required"` + Host string `map:"host,omitempty" validate:"hostname|ip"` + Port int `map:"port" validate:"required"` Cert string `map:"cert,omitempty"` Key string `map:"key,omitempty"` } diff --git a/ext/pkg/network/proxy.go b/ext/pkg/network/proxy.go index ee66016d..b10d8712 100644 --- a/ext/pkg/network/proxy.go +++ b/ext/pkg/network/proxy.go @@ -25,7 +25,7 @@ import ( // ProxyNodeSpec defines the specifications for creating a ProxyNode. type ProxyNodeSpec struct { spec.Meta `map:",inline"` - URLs []string `map:"urls"` + URLs []string `map:"urls" validate:"required,dive,url"` } // ProxyNode represents a Node for handling HTTP proxy. diff --git a/ext/pkg/network/router.go b/ext/pkg/network/router.go index 36accafa..12c0ffcb 100644 --- a/ext/pkg/network/router.go +++ b/ext/pkg/network/router.go @@ -18,14 +18,14 @@ import ( // RouteNodeSpec defines the specification for configuring a RouteNode. type RouteNodeSpec struct { spec.Meta `map:",inline"` - Routes []Route `map:"routes"` + Routes []Route `map:"routes" validate:"required"` } // Route represents a routing configuration with a specific HTTP method, path, and port. type Route struct { - Method string `map:"method"` - Path string `map:"path"` - Port string `map:"port"` + Method string `map:"method" validate:"required"` + Path string `map:"path" validate:"required"` + Port string `map:"port" validate:"required"` } // RouteNode represents a node for routing based on HTTP method, path, and port. diff --git a/ext/pkg/network/websocket.go b/ext/pkg/network/websocket.go index a396f822..5214dec1 100644 --- a/ext/pkg/network/websocket.go +++ b/ext/pkg/network/websocket.go @@ -23,7 +23,7 @@ import ( // WebSocketNodeSpec defines the specifications for creating a WebSocketNode. type WebSocketNodeSpec struct { spec.Meta `map:",inline"` - URL string `map:"url"` + URL string `map:"url" validate:"required,url"` Timeout time.Duration `map:"timeout,omitempty"` } diff --git a/ext/pkg/system/builder_test.go b/ext/pkg/system/builder_test.go index 5a70c666..c0766a67 100644 --- a/ext/pkg/system/builder_test.go +++ b/ext/pkg/system/builder_test.go @@ -165,7 +165,7 @@ func TestSchemeRegister_Syscall(t *testing.T) { register := AddToScheme() err := register.SetSyscall(opcode, func() error { - return errors.New(faker.Word()) + return errors.New(faker.UUIDHyphenated()) }) assert.NoError(t, err) @@ -209,7 +209,7 @@ func TestSchemeRegister_Syscall(t *testing.T) { register := AddToScheme() err := register.SetSyscall(opcode, func(arg string) (string, error) { - return "", errors.New(faker.Word()) + return "", errors.New(faker.UUIDHyphenated()) }) assert.NoError(t, err) @@ -255,7 +255,7 @@ func TestSchemeRegister_Syscall(t *testing.T) { register := AddToScheme() err := register.SetSyscall(opcode, func(_ context.Context, arg string) (string, error) { - return "", errors.New(faker.Word()) + return "", errors.New(faker.UUIDHyphenated()) }) assert.NoError(t, err) @@ -302,7 +302,7 @@ func TestSchemeRegister_Syscall(t *testing.T) { register := AddToScheme() err := register.SetSyscall(opcode, func(arg1, arg2 string) (string, string, error) { - return "", "", errors.New(faker.Word()) + return "", "", errors.New(faker.UUIDHyphenated()) }) assert.NoError(t, err) diff --git a/ext/pkg/system/resource_test.go b/ext/pkg/system/resource_test.go index 40ab9c6b..c4f651d9 100644 --- a/ext/pkg/system/resource_test.go +++ b/ext/pkg/system/resource_test.go @@ -31,7 +31,7 @@ func TestCreateResource(t *testing.T) { meta := &resource.Meta{ ID: uuid.Must(uuid.NewV7()), - Name: faker.Word(), + Name: faker.UUIDHyphenated(), } res, err := fn(ctx, []resource.Resource{meta}) @@ -48,7 +48,7 @@ func TestReadResource(t *testing.T) { meta := &resource.Meta{ ID: uuid.Must(uuid.NewV7()), - Name: faker.Word(), + Name: faker.UUIDHyphenated(), } _, err := st.Store(ctx, meta) @@ -68,7 +68,7 @@ func TestUpdateResource(t *testing.T) { meta := &resource.Meta{ ID: uuid.Must(uuid.NewV7()), - Name: faker.Word(), + Name: faker.UUIDHyphenated(), } _, err := st.Store(ctx, meta) @@ -88,7 +88,7 @@ func TestDeleteResource(t *testing.T) { meta := &resource.Meta{ ID: uuid.Must(uuid.NewV7()), - Name: faker.Word(), + Name: faker.UUIDHyphenated(), } _, err := st.Store(ctx, meta) diff --git a/ext/pkg/system/signal.go b/ext/pkg/system/signal.go index 4bd35564..e4d8908a 100644 --- a/ext/pkg/system/signal.go +++ b/ext/pkg/system/signal.go @@ -17,7 +17,7 @@ import ( // SignalNodeSpec defines the specifications for creating a SignalNode. type SignalNodeSpec struct { spec.Meta `map:",inline"` - Topic string `map:"topic"` + Topic string `map:"topic" validate:"required"` } // SignalNode listens to a signal channel and forwards signals as packets. diff --git a/ext/pkg/system/syscall.go b/ext/pkg/system/syscall.go index ec61f299..6acb20df 100644 --- a/ext/pkg/system/syscall.go +++ b/ext/pkg/system/syscall.go @@ -14,7 +14,7 @@ import ( // SyscallNodeSpec specifies the creation parameters for a SyscallNode. type SyscallNodeSpec struct { spec.Meta `map:",inline"` - OPCode string `map:"opcode"` + OPCode string `map:"opcode" validate:"required"` } // SyscallNode executes synchronized function. diff --git a/go.mod b/go.mod index 73c49f1d..70faf445 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.23.4 require ( github.com/benbjohnson/immutable v0.4.3 github.com/go-faker/faker/v4 v4.5.0 + github.com/go-playground/validator/v10 v10.23.0 github.com/gofrs/uuid v4.4.0+incompatible github.com/iancoleman/strcase v0.3.0 github.com/pkg/errors v0.9.1 @@ -15,9 +16,16 @@ require ( require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/gabriel-vasile/mimetype v1.4.7 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect github.com/kr/pretty v0.3.1 // indirect + github.com/leodido/go-urn v1.4.0 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/net v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 00240c63..ca36d6dc 100644 --- a/go.sum +++ b/go.sum @@ -3,8 +3,18 @@ github.com/benbjohnson/immutable v0.4.3/go.mod h1:qJIKKSmdqz1tVzNtst1DZzvaqOU1on github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gabriel-vasile/mimetype v1.4.7 h1:SKFKl7kD0RiPdbht0s7hFtjl489WcQ1VyPW8ZzUMYCA= +github.com/gabriel-vasile/mimetype v1.4.7/go.mod h1:GDlAgAyIRT27BhFl53XNAFtfjzOkLaF35JdEG0P7LtU= github.com/go-faker/faker/v4 v4.5.0 h1:ARzAY2XoOL9tOUK+KSecUQzyXQsUaZHefjyF8x6YFHc= github.com/go-faker/faker/v4 v4.5.0/go.mod h1:p3oq1GRjG2PZ7yqeFFfQI20Xm61DoBDlCA8RiSyZ48M= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o= +github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= @@ -16,6 +26,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -28,8 +40,14 @@ github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc= github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo= golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/pkg/chart/chart.go b/pkg/chart/chart.go index e573ca1e..72619d36 100644 --- a/pkg/chart/chart.go +++ b/pkg/chart/chart.go @@ -1,6 +1,7 @@ package chart import ( + "fmt" "github.com/gofrs/uuid" "github.com/pkg/errors" "github.com/siyul-park/uniflow/pkg/encoding" @@ -13,11 +14,11 @@ import ( // Chart defines the structure that combines multiple nodes into a cluster node. type Chart struct { - ID uuid.UUID `json:"id,omitempty" bson:"_id,omitempty" yaml:"id,omitempty" map:"id,omitempty"` - Namespace string `json:"namespace,omitempty" bson:"namespace,omitempty" yaml:"namespace,omitempty" map:"namespace,omitempty"` + ID uuid.UUID `json:"id" bson:"_id" yaml:"id" map:"id" validate:"required"` + Namespace string `json:"namespace" bson:"namespace" yaml:"namespace" map:"namespace" validate:"required"` Name string `json:"name,omitempty" bson:"name,omitempty" yaml:"name,omitempty" map:"name,omitempty"` Annotations map[string]string `json:"annotations,omitempty" bson:"annotations,omitempty" yaml:"annotations,omitempty" map:"annotations,omitempty"` - Specs []spec.Spec `json:"specs,omitempty" bson:"specs,omitempty" yaml:"specs,omitempty" map:"specs,omitempty"` + Specs []*spec.Unstructured `json:"specs" bson:"specs" yaml:"specs" map:"specs"` Inbounds map[string][]spec.Port `json:"inbounds,omitempty" bson:"inbounds,omitempty" yaml:"inbounds,omitempty" map:"inbounds,omitempty"` Outbounds map[string][]spec.Port `json:"outbounds,omitempty" bson:"outbounds,omitempty" yaml:"outbounds,omitempty" map:"outbounds,omitempty"` Env map[string][]spec.Value `json:"env,omitempty" bson:"env,omitempty" yaml:"env,omitempty" map:"env,omitempty"` @@ -103,8 +104,8 @@ func (c *Chart) Bind(secrets ...*secret.Secret) error { } // Build constructs a specs based on the given spec. -func (c *Chart) Build(sp spec.Spec) ([]spec.Spec, error) { - doc, err := types.Marshal(sp) +func (c *Chart) Build(root spec.Spec) ([]spec.Spec, error) { + doc, err := types.Marshal(root) if err != nil { return nil, err } @@ -127,16 +128,14 @@ func (c *Chart) Build(sp spec.Spec) ([]spec.Spec, error) { specs := make([]spec.Spec, 0, len(c.Specs)) for _, sp := range c.Specs { - unstructured := &spec.Unstructured{} - if err := spec.Convert(sp, unstructured); err != nil { - return nil, err + if sp.GetNamespace() == "" { + sp.SetNamespace(fmt.Sprintf("%s/%s", root.GetNamespace(), root.GetID())) } - if len(env) > 0 { - unstructured.SetEnv(env) + sp.SetEnv(env) } - specs = append(specs, unstructured) + specs = append(specs, sp) } return specs, nil } @@ -182,12 +181,12 @@ func (c *Chart) SetAnnotations(val map[string]string) { } // GetSpecs returns the chart's specs. -func (c *Chart) GetSpecs() []spec.Spec { +func (c *Chart) GetSpecs() []*spec.Unstructured { return c.Specs } // SetSpecs sets the chart's specs. -func (c *Chart) SetSpecs(val []spec.Spec) { +func (c *Chart) SetSpecs(val []*spec.Unstructured) { c.Specs = val } diff --git a/pkg/chart/chart_test.go b/pkg/chart/chart_test.go index b7e82316..076ed11f 100644 --- a/pkg/chart/chart_test.go +++ b/pkg/chart/chart_test.go @@ -15,6 +15,7 @@ func TestChart_IsBound(t *testing.T) { t.Run("NoSecrets", func(t *testing.T) { chrt := &Chart{ ID: uuid.Must(uuid.NewV7()), + Env: map[string][]spec.Value{ "FOO": { { @@ -36,6 +37,7 @@ func TestChart_IsBound(t *testing.T) { } chrt := &Chart{ ID: uuid.Must(uuid.NewV7()), + Env: map[string][]spec.Value{ "FOO": { { @@ -98,8 +100,8 @@ func TestChart_Build(t *testing.T) { chrt := &Chart{ ID: uuid.Must(uuid.NewV7()), Name: faker.UUIDHyphenated(), - Specs: []spec.Spec{ - &spec.Unstructured{ + Specs: []*spec.Unstructured{ + { Meta: spec.Meta{ ID: uuid.Must(uuid.NewV7()), Kind: faker.UUIDHyphenated(), @@ -123,8 +125,8 @@ func TestChart_Build(t *testing.T) { chrt := &Chart{ ID: uuid.Must(uuid.NewV7()), Name: faker.UUIDHyphenated(), - Specs: []spec.Spec{ - &spec.Unstructured{ + Specs: []*spec.Unstructured{ + { Meta: spec.Meta{ ID: uuid.Must(uuid.NewV7()), Kind: faker.UUIDHyphenated(), @@ -182,8 +184,8 @@ func TestChart_SetAnnotations(t *testing.T) { func TestChart_SetSpecs(t *testing.T) { chrt := New() - specs := []spec.Spec{ - &spec.Unstructured{ + specs := []*spec.Unstructured{ + { Meta: spec.Meta{ ID: uuid.Must(uuid.NewV7()), Kind: "test", diff --git a/pkg/chart/linker.go b/pkg/chart/linker.go index 9ffc98da..4917ea1d 100644 --- a/pkg/chart/linker.go +++ b/pkg/chart/linker.go @@ -39,8 +39,8 @@ func (l *Linker) Link(chrt *Chart) error { return nil } - codec = scheme.CodecFunc(func(sp spec.Spec) (node.Node, error) { - specs, err := chrt.Build(sp) + codec = scheme.CodecFunc(func(root spec.Spec) (node.Node, error) { + specs, err := chrt.Build(root) if err != nil { return nil, err } diff --git a/pkg/chart/linker_test.go b/pkg/chart/linker_test.go index 75a4b12a..fa3f49a8 100644 --- a/pkg/chart/linker_test.go +++ b/pkg/chart/linker_test.go @@ -29,17 +29,19 @@ func TestLinker_Link(t *testing.T) { ID: uuid.Must(uuid.NewV7()), Namespace: resource.DefaultNamespace, Name: faker.UUIDHyphenated(), - Specs: []spec.Spec{ - &spec.Meta{ - Kind: kind, - Name: "dummy", + Specs: []*spec.Unstructured{ + { + Meta: spec.Meta{ + Kind: kind, + Name: "dummy", + }, }, }, Env: map[string][]spec.Value{ "key1": { { ID: scrt.GetID(), - Data: faker.Word(), + Data: faker.UUIDHyphenated(), }, }, "key2": { @@ -81,7 +83,6 @@ func TestLinker_Unlink(t *testing.T) { ID: uuid.Must(uuid.NewV7()), Namespace: resource.DefaultNamespace, Name: faker.UUIDHyphenated(), - Specs: []spec.Spec{}, } l.Link(chrt) diff --git a/pkg/chart/loader_test.go b/pkg/chart/loader_test.go index 47f2ef2a..d3a08e23 100644 --- a/pkg/chart/loader_test.go +++ b/pkg/chart/loader_test.go @@ -28,17 +28,21 @@ func TestLoader_Load(t *testing.T) { SecretStore: secretStore, }) - scrt := &secret.Secret{ID: uuid.Must(uuid.NewV7())} + scrt := &secret.Secret{ + ID: uuid.Must(uuid.NewV7()), + Data: faker.UUIDHyphenated(), + } + chrt1 := &Chart{ ID: uuid.Must(uuid.NewV7()), Namespace: resource.DefaultNamespace, Name: faker.UUIDHyphenated(), - Specs: []spec.Spec{}, + Env: map[string][]spec.Value{ "key": { { ID: scrt.GetID(), - Data: faker.Word(), + Data: faker.UUIDHyphenated(), }, }, }, @@ -47,11 +51,13 @@ func TestLoader_Load(t *testing.T) { ID: uuid.Must(uuid.NewV7()), Namespace: resource.DefaultNamespace, Name: faker.UUIDHyphenated(), - Specs: []spec.Spec{ - &spec.Meta{ - Kind: chrt1.GetName(), - Namespace: resource.DefaultNamespace, - Name: faker.UUIDHyphenated(), + Specs: []*spec.Unstructured{ + { + Meta: spec.Meta{ + Kind: chrt1.GetName(), + Namespace: resource.DefaultNamespace, + Name: faker.UUIDHyphenated(), + }, }, }, } diff --git a/pkg/chart/table_test.go b/pkg/chart/table_test.go index be35218b..c08d0349 100644 --- a/pkg/chart/table_test.go +++ b/pkg/chart/table_test.go @@ -18,17 +18,18 @@ func TestTable_Insert(t *testing.T) { ID: uuid.Must(uuid.NewV7()), Namespace: resource.DefaultNamespace, Name: faker.UUIDHyphenated(), - Specs: []spec.Spec{}, } chrt2 := &Chart{ ID: uuid.Must(uuid.NewV7()), Namespace: resource.DefaultNamespace, Name: faker.UUIDHyphenated(), - Specs: []spec.Spec{ - &spec.Meta{ - Kind: chrt1.GetName(), - Namespace: resource.DefaultNamespace, - Name: faker.UUIDHyphenated(), + Specs: []*spec.Unstructured{ + { + Meta: spec.Meta{ + Kind: chrt1.GetName(), + Namespace: resource.DefaultNamespace, + Name: faker.UUIDHyphenated(), + }, }, }, } @@ -50,11 +51,13 @@ func TestTable_Free(t *testing.T) { ID: uuid.Must(uuid.NewV7()), Namespace: resource.DefaultNamespace, Name: faker.UUIDHyphenated(), - Specs: []spec.Spec{ - &spec.Meta{ - Kind: faker.UUIDHyphenated(), - Namespace: resource.DefaultNamespace, - Name: faker.UUIDHyphenated(), + Specs: []*spec.Unstructured{ + { + Meta: spec.Meta{ + Kind: faker.UUIDHyphenated(), + Namespace: resource.DefaultNamespace, + Name: faker.UUIDHyphenated(), + }, }, }, } @@ -75,11 +78,13 @@ func TestTable_Lookup(t *testing.T) { ID: uuid.Must(uuid.NewV7()), Namespace: resource.DefaultNamespace, Name: faker.UUIDHyphenated(), - Specs: []spec.Spec{ - &spec.Meta{ - Kind: faker.UUIDHyphenated(), - Namespace: resource.DefaultNamespace, - Name: faker.UUIDHyphenated(), + Specs: []*spec.Unstructured{ + { + Meta: spec.Meta{ + Kind: faker.UUIDHyphenated(), + Namespace: resource.DefaultNamespace, + Name: faker.UUIDHyphenated(), + }, }, }, } @@ -97,17 +102,18 @@ func TestTable_Links(t *testing.T) { ID: uuid.Must(uuid.NewV7()), Namespace: resource.DefaultNamespace, Name: faker.UUIDHyphenated(), - Specs: []spec.Spec{}, } chrt2 := &Chart{ ID: uuid.Must(uuid.NewV7()), Namespace: resource.DefaultNamespace, Name: faker.UUIDHyphenated(), - Specs: []spec.Spec{ - &spec.Meta{ - Kind: chrt1.GetName(), - Namespace: resource.DefaultNamespace, - Name: faker.UUIDHyphenated(), + Specs: []*spec.Unstructured{ + { + Meta: spec.Meta{ + Kind: chrt1.GetName(), + Namespace: resource.DefaultNamespace, + Name: faker.UUIDHyphenated(), + }, }, }, } @@ -130,11 +136,13 @@ func TestTable_Keys(t *testing.T) { ID: uuid.Must(uuid.NewV7()), Namespace: resource.DefaultNamespace, Name: faker.UUIDHyphenated(), - Specs: []spec.Spec{ - &spec.Meta{ - Kind: faker.UUIDHyphenated(), - Namespace: resource.DefaultNamespace, - Name: faker.UUIDHyphenated(), + Specs: []*spec.Unstructured{ + { + Meta: spec.Meta{ + Kind: faker.UUIDHyphenated(), + Namespace: resource.DefaultNamespace, + Name: faker.UUIDHyphenated(), + }, }, }, } @@ -169,17 +177,18 @@ func TestTable_Hook(t *testing.T) { ID: uuid.Must(uuid.NewV7()), Namespace: resource.DefaultNamespace, Name: faker.UUIDHyphenated(), - Specs: []spec.Spec{}, } chrt2 := &Chart{ ID: uuid.Must(uuid.NewV7()), Namespace: resource.DefaultNamespace, Name: faker.UUIDHyphenated(), - Specs: []spec.Spec{ - &spec.Meta{ - Kind: chrt1.GetName(), - Namespace: resource.DefaultNamespace, - Name: faker.UUIDHyphenated(), + Specs: []*spec.Unstructured{ + { + Meta: spec.Meta{ + Kind: chrt1.GetName(), + Namespace: resource.DefaultNamespace, + Name: faker.UUIDHyphenated(), + }, }, }, } diff --git a/pkg/node/port_test.go b/pkg/node/port_test.go index 3bd73a9e..402da17c 100644 --- a/pkg/node/port_test.go +++ b/pkg/node/port_test.go @@ -1,9 +1,9 @@ package node import ( + "github.com/go-faker/faker/v4" "testing" - "github.com/go-faker/faker/v4" "github.com/stretchr/testify/assert" ) diff --git a/pkg/packet/packet.go b/pkg/packet/packet.go index d912e75d..9749d4ca 100644 --- a/pkg/packet/packet.go +++ b/pkg/packet/packet.go @@ -17,8 +17,8 @@ var None = New(nil) // ErrDroppedPacket is an error indicating a dropped packet. var ErrDroppedPacket = errors.New("dropped packet") -// Merge combines multiple packets into one, handling errors and payloads. -func Merge(pcks []*Packet) *Packet { +// Join combines multiple packets into one, handling errors and payloads. +func Join(pcks ...*Packet) *Packet { var errs []error var payloads []types.Value diff --git a/pkg/packet/packet_test.go b/pkg/packet/packet_test.go index d416fe14..f3b2b331 100644 --- a/pkg/packet/packet_test.go +++ b/pkg/packet/packet_test.go @@ -12,27 +12,27 @@ func TestNew(t *testing.T) { assert.NotNil(t, pck) } -func TestMerge(t *testing.T) { +func TestJoin(t *testing.T) { t.Run("None", func(t *testing.T) { - res := Merge([]*Packet{None, None}) + res := Join(None, None) assert.Equal(t, None, res) }) t.Run("Zero", func(t *testing.T) { - res := Merge([]*Packet{}) + res := Join() assert.Equal(t, None, res) }) t.Run("One", func(t *testing.T) { pck := New(nil) - res := Merge([]*Packet{pck}) + res := Join(pck) assert.Equal(t, pck, res) }) t.Run("Many", func(t *testing.T) { pck1 := New(nil) pck2 := New(nil) - res := Merge([]*Packet{pck1, pck2}) + res := Join(pck1, pck2) assert.Equal(t, types.NewSlice(nil, nil), res.Payload()) }) } diff --git a/pkg/packet/tracer.go b/pkg/packet/tracer.go index 4f24cd20..8f0958e0 100644 --- a/pkg/packet/tracer.go +++ b/pkg/packet/tracer.go @@ -165,7 +165,7 @@ func (t *Tracer) receive(pck *Packet) { if sources, ok := t.sources[pck]; ok { delete(t.sources, pck) - merged := Merge(receives) + join := Join(receives...) for _, source := range sources { targets := t.targets[source] receives := t.receives[source] @@ -179,7 +179,7 @@ func (t *Tracer) receive(pck *Packet) { } if targets[i] == pck { - receives[i+offset] = merged + receives[i+offset] = join targets = append(targets[:i], targets[i+1:]...) break } @@ -206,8 +206,8 @@ func (t *Tracer) receive(pck *Packet) { break } - merged := Merge(receives) - reader.Receive(merged) + join := Join(receives...) + reader.Receive(join) delete(t.reader, read) delete(t.receives, read) @@ -233,13 +233,13 @@ func (t *Tracer) handle(pck *Packet) { } if hooks := t.hooks[pck]; len(hooks) > 0 { - merged := Merge(receives) + join := Join(receives...) delete(t.hooks, pck) delete(t.receives, pck) t.mu.Unlock() - hooks.Handle(merged) + hooks.Handle(join) t.mu.Lock() } } diff --git a/pkg/packet/writer.go b/pkg/packet/writer.go index 72024e9e..43b27329 100644 --- a/pkg/packet/writer.go +++ b/pkg/packet/writer.go @@ -223,7 +223,7 @@ func (w *Writer) receive(pck *Packet, reader *Reader) bool { w.receives = w.receives[1:] - pck := Merge(receives) + pck := Join(receives...) w.inbounds.Handle(pck) w.in <- pck } diff --git a/pkg/resource/resource.go b/pkg/resource/resource.go index 40b62a5b..ea162878 100644 --- a/pkg/resource/resource.go +++ b/pkg/resource/resource.go @@ -1,6 +1,8 @@ package resource -import "github.com/gofrs/uuid" +import ( + "github.com/gofrs/uuid" +) // Resource represents a common interface for objects with metadata. type Resource interface { @@ -25,9 +27,9 @@ type Resource interface { // Meta contains metadata for resources. type Meta struct { // ID is the unique identifier of the resource. - ID uuid.UUID `json:"id,omitempty" bson:"_id,omitempty" yaml:"id,omitempty" map:"id,omitempty"` + ID uuid.UUID `json:"id" bson:"_id" yaml:"id" map:"id" validate:"required"` // Namespace groups resources logically. - Namespace string `json:"namespace,omitempty" bson:"namespace,omitempty" yaml:"namespace,omitempty" map:"namespace,omitempty"` + Namespace string `json:"namespace" bson:"namespace" yaml:"namespace" map:"namespace" validate:"required"` // Name is the human-readable name of the resource. Name string `json:"name,omitempty" bson:"name,omitempty" yaml:"name,omitempty" map:"name,omitempty"` // Annotations hold additional metadata. diff --git a/pkg/resource/resource_test.go b/pkg/resource/resource_test.go index 618c254b..13c82305 100644 --- a/pkg/resource/resource_test.go +++ b/pkg/resource/resource_test.go @@ -12,7 +12,7 @@ func TestMeta_GetSet(t *testing.T) { meta := &Meta{ ID: uuid.Must(uuid.NewV7()), Namespace: "default", - Name: faker.Word(), + Name: faker.UUIDHyphenated(), Annotations: map[string]string{"key": "value"}, } diff --git a/pkg/resource/store.go b/pkg/resource/store.go index 47e28f23..709d4dca 100644 --- a/pkg/resource/store.go +++ b/pkg/resource/store.go @@ -2,6 +2,8 @@ package resource import ( "context" + "github.com/go-playground/validator/v10" + "github.com/siyul-park/uniflow/pkg/encoding" "sync" "github.com/gofrs/uuid" @@ -52,6 +54,7 @@ type store[T Resource] struct { namespaces map[string]map[string]uuid.UUID streams []*stream examples [][]T + validate *validator.Validate mu sync.RWMutex } @@ -68,9 +71,7 @@ const ( EventDelete = "delete" ) -var ( - ErrDuplicatedKey = errors.New("duplicated key") // ErrDuplicatedKey indicates a duplicated key error. -) +var ErrDuplicatedKey = errors.New("duplicated key") // ErrDuplicatedKey indicates a duplicated key error. var _ Store[Resource] = (*store[Resource])(nil) var _ Stream = (*stream)(nil) @@ -80,6 +81,7 @@ func NewStore[T Resource]() Store[T] { return &store[T]{ data: make(map[uuid.UUID]T), namespaces: make(map[string]map[string]uuid.UUID), + validate: validator.New(validator.WithRequiredStructEnabled()), } } @@ -146,6 +148,10 @@ func (s *store[T]) Store(_ context.Context, resources ...T) (int, error) { res.SetNamespace(DefaultNamespace) } + if err := s.validate.Struct(res); err != nil { + return 0, errors.WithMessage(encoding.ErrUnsupportedValue, err.Error()) + } + if res.GetName() != "" && s.lookup(res.GetNamespace(), res.GetName()) != uuid.Nil { return 0, errors.WithStack(ErrDuplicatedKey) } @@ -174,6 +180,10 @@ func (s *store[T]) Swap(_ context.Context, resources ...T) (int, error) { if res.GetID() == uuid.Nil { res.SetID(s.lookup(res.GetNamespace(), res.GetName())) } + + if err := s.validate.Struct(res); err != nil { + return 0, errors.WithMessage(encoding.ErrUnsupportedValue, err.Error()) + } } for i := 0; i < len(resources); i++ { diff --git a/pkg/runtime/runtime_test.go b/pkg/runtime/runtime_test.go index bd131488..976f1281 100644 --- a/pkg/runtime/runtime_test.go +++ b/pkg/runtime/runtime_test.go @@ -164,7 +164,7 @@ func TestRuntime_Reconcile(t *testing.T) { scrt := &secret.Secret{ ID: uuid.Must(uuid.NewV7()), - Data: faker.Word(), + Data: faker.UUIDHyphenated(), } meta := &spec.Meta{ ID: uuid.Must(uuid.NewV7()), @@ -363,7 +363,7 @@ func BenchmarkRuntime_Reconcile(b *testing.B) { for i := 0; i < b.N; i++ { scrt := &secret.Secret{ ID: uuid.Must(uuid.NewV7()), - Data: faker.Word(), + Data: faker.UUIDHyphenated(), } meta := &spec.Meta{ ID: uuid.Must(uuid.NewV7()), diff --git a/pkg/scheme/scheme.go b/pkg/scheme/scheme.go index 6ffc88f5..e777dac1 100644 --- a/pkg/scheme/scheme.go +++ b/pkg/scheme/scheme.go @@ -1,6 +1,7 @@ package scheme import ( + "github.com/go-playground/validator/v10" "github.com/gofrs/uuid" "reflect" "slices" @@ -14,9 +15,10 @@ import ( // Scheme manages type information and decodes spec implementations into node objects within a workflow environment. type Scheme struct { - types map[string]reflect.Type - codecs map[string]Codec - mu sync.RWMutex + types map[string]reflect.Type + codecs map[string]Codec + validate *validator.Validate + mu sync.RWMutex } var _ Codec = (*Scheme)(nil) @@ -24,8 +26,9 @@ var _ Codec = (*Scheme)(nil) // New creates a new Scheme instance with initialized type and codec maps. func New() *Scheme { return &Scheme{ - types: make(map[string]reflect.Type), - codecs: make(map[string]Codec), + types: make(map[string]reflect.Type), + codecs: make(map[string]Codec), + validate: validator.New(validator.WithRequiredStructEnabled()), } } @@ -132,7 +135,6 @@ func (s *Scheme) Decode(sp spec.Spec) (spec.Spec, error) { if !ok { return sp, nil } - if err := spec.Convert(sp, structured); err != nil { return nil, err } @@ -140,6 +142,11 @@ func (s *Scheme) Decode(sp spec.Spec) (spec.Spec, error) { if structured.GetID() == uuid.Nil { structured.SetID(uuid.Must(uuid.NewV7())) } + + if err := s.validate.Struct(structured); err != nil { + return nil, errors.WithMessage(encoding.ErrUnsupportedValue, err.Error()) + } + return structured, nil } diff --git a/pkg/scheme/scheme_test.go b/pkg/scheme/scheme_test.go index 4236cc48..6346ba8e 100644 --- a/pkg/scheme/scheme_test.go +++ b/pkg/scheme/scheme_test.go @@ -75,8 +75,9 @@ func TestScheme_Decode(t *testing.T) { meta := &spec.Unstructured{ Meta: spec.Meta{ - ID: uuid.Must(uuid.NewV7()), - Kind: kind, + ID: uuid.Must(uuid.NewV7()), + Kind: kind, + Namespace: faker.UUIDHyphenated(), }, } diff --git a/pkg/secret/secret.go b/pkg/secret/secret.go index db4eb3dc..47eed5c4 100644 --- a/pkg/secret/secret.go +++ b/pkg/secret/secret.go @@ -8,15 +8,15 @@ import ( // Secret defines the interface for a secret with various attributes. type Secret struct { // ID is the unique identifier of the secret. - ID uuid.UUID `json:"id,omitempty" bson:"_id,omitempty" yaml:"id,omitempty" map:"id,omitempty"` + ID uuid.UUID `json:"id" bson:"_id" yaml:"id" map:"id" validate:"required"` // Namespace groups secrets logically. - Namespace string `json:"namespace,omitempty" bson:"namespace,omitempty" yaml:"namespace,omitempty" map:"namespace,omitempty"` + Namespace string `json:"namespace" bson:"namespace" yaml:"namespace" map:"namespace" validate:"required"` // Name is the human-readable name of the secret. Name string `json:"name,omitempty" bson:"name,omitempty" yaml:"name,omitempty" map:"name,omitempty"` // Annotations hold additional metadata. Annotations map[string]string `json:"annotations,omitempty" bson:"annotations,omitempty" yaml:"annotations,omitempty" map:"annotations,omitempty"` // Data holds the secret's actual data. - Data any `json:"data,omitempty" bson:"data,omitempty" yaml:"data,omitempty" map:"data,omitempty"` + Data any `json:"data" bson:"data" yaml:"data" map:"data" validate:"required"` } // Key constants for commonly used fields. diff --git a/pkg/secret/secret_test.go b/pkg/secret/secret_test.go index 960e2938..757cca58 100644 --- a/pkg/secret/secret_test.go +++ b/pkg/secret/secret_test.go @@ -17,14 +17,14 @@ func TestSecret_SetID(t *testing.T) { func TestSecret_SetNamespace(t *testing.T) { scrt := New() - namespace := faker.Word() + namespace := faker.UUIDHyphenated() scrt.SetNamespace(namespace) assert.Equal(t, namespace, scrt.GetNamespace()) } func TestSecret_SetName(t *testing.T) { scrt := New() - name := faker.Word() + name := faker.UUIDHyphenated() scrt.SetName(name) assert.Equal(t, name, scrt.GetName()) } @@ -38,7 +38,7 @@ func TestSecret_SetAnnotations(t *testing.T) { func TestSecret_SetData_Nil(t *testing.T) { scrt := New() - data := faker.Word() + data := faker.UUIDHyphenated() scrt.SetData(data) assert.Equal(t, data, scrt.GetData()) } @@ -53,7 +53,7 @@ func TestSecret_IsIdentified(t *testing.T) { t.Run("Name", func(t *testing.T) { scrt := &Secret{ - Name: faker.Word(), + Name: faker.UUIDHyphenated(), } assert.True(t, scrt.IsIdentified()) }) diff --git a/pkg/spec/encoding_test.go b/pkg/spec/encoding_test.go index 318eda25..2b4998a3 100644 --- a/pkg/spec/encoding_test.go +++ b/pkg/spec/encoding_test.go @@ -19,7 +19,7 @@ func TestSpecDecoder_Decode(t *testing.T) { Meta: Meta{ ID: uuid.Must(uuid.NewV7()), Namespace: resource.DefaultNamespace, - Name: faker.Word(), + Name: faker.UUIDHyphenated(), }, Fields: map[string]any{}, } diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go index a0a745e2..924ecef0 100644 --- a/pkg/spec/spec.go +++ b/pkg/spec/spec.go @@ -45,11 +45,11 @@ type Spec interface { // Meta contains metadata for node specifications. type Meta struct { // ID is the unique identifier of the node. - ID uuid.UUID `json:"id,omitempty" bson:"_id,omitempty" yaml:"id,omitempty" map:"id,omitempty"` + ID uuid.UUID `json:"id" bson:"_id" yaml:"id" map:"id" validate:"required"` // Kind specifies the node's type. - Kind string `json:"kind,omitempty" bson:"kind,omitempty" yaml:"kind,omitempty" map:"kind,omitempty"` + Kind string `json:"kind" bson:"kind" yaml:"kind" map:"kind" validate:"required"` // Namespace groups nodes logically. - Namespace string `json:"namespace,omitempty" bson:"namespace,omitempty" yaml:"namespace,omitempty" map:"namespace,omitempty"` + Namespace string `json:"namespace" bson:"namespace" yaml:"namespace" map:"namespace" validate:"required"` // Name is the human-readable name of the node. Name string `json:"name,omitempty" bson:"name,omitempty" yaml:"name,omitempty" map:"name,omitempty"` // Annotations hold additional metadata. @@ -67,7 +67,7 @@ type Port struct { // Name is the human-readable name of the port. Name string `json:"name,omitempty" bson:"name,omitempty" yaml:"name,omitempty" map:"name,omitempty"` // Port is the port number or identifier within the namespace. - Port string `json:"port" bson:"port" yaml:"port" map:"port"` + Port string `json:"port" bson:"port" yaml:"port" map:"port" validate:"required"` } // Value represents a sensitive piece of data associated with a node. @@ -77,7 +77,7 @@ type Value struct { // Name is the human-readable name of the secret. Name string `json:"name,omitempty" bson:"name,omitempty" yaml:"name,omitempty" map:"name,omitempty"` // Data is the sensitive value of the secret. - Data any `json:"data" bson:"data" yaml:"data" map:"data"` + Data any `json:"data" bson:"data" yaml:"data" map:"data" validate:"required"` } var _ resource.Resource = (Spec)(nil) diff --git a/pkg/spec/spec_test.go b/pkg/spec/spec_test.go index 548286aa..84873de9 100644 --- a/pkg/spec/spec_test.go +++ b/pkg/spec/spec_test.go @@ -12,11 +12,11 @@ import ( func TestConvert(t *testing.T) { meta := &Meta{ ID: uuid.Must(uuid.NewV7()), - Kind: faker.Word(), + Kind: faker.UUIDHyphenated(), Namespace: "default", - Name: faker.Word(), + Name: faker.UUIDHyphenated(), Annotations: map[string]string{"key": "value"}, - Ports: map[string][]Port{"out": {{Name: faker.Word(), Port: "in"}}}, + Ports: map[string][]Port{"out": {{Name: faker.UUIDHyphenated(), Port: "in"}}}, Env: map[string][]Value{"env1": {{Name: "secret1", Data: "value1"}}}, } @@ -34,21 +34,21 @@ func TestMeta_SetID(t *testing.T) { func TestMeta_SetKind(t *testing.T) { meta := &Meta{} - kind := faker.Word() + kind := faker.UUIDHyphenated() meta.SetKind(kind) assert.Equal(t, kind, meta.GetKind()) } func TestMeta_SetNamespace(t *testing.T) { meta := &Meta{} - namespace := faker.Word() + namespace := faker.UUIDHyphenated() meta.SetNamespace(namespace) assert.Equal(t, namespace, meta.GetNamespace()) } func TestMeta_SetName(t *testing.T) { meta := &Meta{} - name := faker.Word() + name := faker.UUIDHyphenated() meta.SetName(name) assert.Equal(t, name, meta.GetName()) } diff --git a/pkg/spec/unstructured_test.go b/pkg/spec/unstructured_test.go index cb7a7b3f..c395af52 100644 --- a/pkg/spec/unstructured_test.go +++ b/pkg/spec/unstructured_test.go @@ -17,7 +17,7 @@ func TestUnstructured_GetSet(t *testing.T) { assert.True(t, ok) assert.Equal(t, id, val) - kind := faker.Word() + kind := faker.UUIDHyphenated() unstructured.Set(KeyKind, kind) val, ok = unstructured.Get(KeyKind) assert.True(t, ok) @@ -28,7 +28,7 @@ func TestUnstructured_GetSet(t *testing.T) { assert.True(t, ok) assert.Equal(t, "default", val) - name := faker.Word() + name := faker.UUIDHyphenated() unstructured.Set(KeyName, name) val, ok = unstructured.Get(KeyName) assert.True(t, ok) @@ -40,7 +40,7 @@ func TestUnstructured_GetSet(t *testing.T) { assert.True(t, ok) assert.Equal(t, annotations, val) - ports := map[string][]Port{"port1": {{Name: faker.Word(), Port: "8080"}}} + ports := map[string][]Port{"port1": {{Name: faker.UUIDHyphenated(), Port: "8080"}}} unstructured.Set(KeyPorts, ports) val, ok = unstructured.Get(KeyPorts) assert.True(t, ok) diff --git a/pkg/symbol/cluster_test.go b/pkg/symbol/cluster_test.go index 750ba9b1..7400c0f7 100644 --- a/pkg/symbol/cluster_test.go +++ b/pkg/symbol/cluster_test.go @@ -25,7 +25,7 @@ func TestCluster_Inbound(t *testing.T) { sb := &Symbol{ Spec: &spec.Meta{ ID: uuid.Must(uuid.NewV7()), - Kind: faker.Word(), + Kind: faker.UUIDHyphenated(), }, Node: node.NewOneToOneNode(nil), } @@ -44,7 +44,7 @@ func TestCluster_Outbound(t *testing.T) { sb := &Symbol{ Spec: &spec.Meta{ ID: uuid.Must(uuid.NewV7()), - Kind: faker.Word(), + Kind: faker.UUIDHyphenated(), }, Node: node.NewOneToOneNode(nil), } @@ -63,14 +63,14 @@ func TestCluster_Load(t *testing.T) { sb1 := &Symbol{ Spec: &spec.Meta{ ID: uuid.Must(uuid.NewV7()), - Kind: faker.Word(), + Kind: faker.UUIDHyphenated(), }, Node: node.NewOneToOneNode(nil), } sb2 := &Symbol{ Spec: &spec.Meta{ ID: uuid.Must(uuid.NewV7()), - Kind: faker.Word(), + Kind: faker.UUIDHyphenated(), Ports: map[string][]spec.Port{ node.PortOut: { { @@ -96,14 +96,14 @@ func TestCluster_Unload(t *testing.T) { sb1 := &Symbol{ Spec: &spec.Meta{ ID: uuid.Must(uuid.NewV7()), - Kind: faker.Word(), + Kind: faker.UUIDHyphenated(), }, Node: node.NewOneToOneNode(nil), } sb2 := &Symbol{ Spec: &spec.Meta{ ID: uuid.Must(uuid.NewV7()), - Kind: faker.Word(), + Kind: faker.UUIDHyphenated(), Ports: map[string][]spec.Port{ node.PortOut: { { @@ -134,7 +134,7 @@ func TestCluster_SendAndReceive(t *testing.T) { sb := &Symbol{ Spec: &spec.Meta{ ID: uuid.Must(uuid.NewV7()), - Kind: faker.Word(), + Kind: faker.UUIDHyphenated(), }, Node: node.NewOneToOneNode(func(_ *process.Process, inPck *packet.Packet) (*packet.Packet, *packet.Packet) { return inPck, nil diff --git a/pkg/symbol/loader_test.go b/pkg/symbol/loader_test.go index 34ba120f..64cc50ae 100644 --- a/pkg/symbol/loader_test.go +++ b/pkg/symbol/loader_test.go @@ -40,7 +40,11 @@ func TestLoader_Load(t *testing.T) { SecretStore: secretStore, }) - scrt := &secret.Secret{ID: uuid.Must(uuid.NewV7())} + scrt := &secret.Secret{ + ID: uuid.Must(uuid.NewV7()), + Data: faker.UUIDHyphenated(), + } + meta1 := &spec.Meta{ ID: uuid.Must(uuid.NewV7()), Kind: kind, @@ -50,7 +54,7 @@ func TestLoader_Load(t *testing.T) { "key": { { ID: scrt.GetID(), - Data: faker.Word(), + Data: faker.UUIDHyphenated(), }, }, }, @@ -96,7 +100,11 @@ func TestLoader_Load(t *testing.T) { SecretStore: secretStore, }) - scrt := &secret.Secret{ID: uuid.Must(uuid.NewV7())} + scrt := &secret.Secret{ + ID: uuid.Must(uuid.NewV7()), + Data: faker.UUIDHyphenated(), + } + meta := &spec.Meta{ ID: uuid.Must(uuid.NewV7()), Kind: kind, @@ -105,7 +113,7 @@ func TestLoader_Load(t *testing.T) { "key": { { ID: scrt.GetID(), - Data: faker.Word(), + Data: faker.UUIDHyphenated(), }, }, }, @@ -135,7 +143,11 @@ func TestLoader_Load(t *testing.T) { SecretStore: secretStore, }) - scrt := &secret.Secret{ID: uuid.Must(uuid.NewV7())} + scrt := &secret.Secret{ + ID: uuid.Must(uuid.NewV7()), + Data: faker.UUIDHyphenated(), + } + meta := &spec.Meta{ ID: uuid.Must(uuid.NewV7()), Kind: kind, @@ -144,7 +156,7 @@ func TestLoader_Load(t *testing.T) { "key": { { ID: scrt.GetID(), - Data: faker.Word(), + Data: faker.UUIDHyphenated(), }, }, }, @@ -177,8 +189,15 @@ func TestLoader_Load(t *testing.T) { SecretStore: secretStore, }) - sec1 := &secret.Secret{ID: uuid.Must(uuid.NewV7())} - sec2 := &secret.Secret{ID: uuid.Must(uuid.NewV7())} + sec1 := &secret.Secret{ + ID: uuid.Must(uuid.NewV7()), + Data: faker.UUIDHyphenated(), + } + sec2 := &secret.Secret{ + ID: uuid.Must(uuid.NewV7()), + Data: faker.UUIDHyphenated(), + } + meta := &spec.Meta{ ID: uuid.Must(uuid.NewV7()), Kind: kind, @@ -188,13 +207,13 @@ func TestLoader_Load(t *testing.T) { "sec1": { { ID: sec1.GetID(), - Data: faker.Word(), + Data: faker.UUIDHyphenated(), }, }, "sec2": { { ID: sec2.GetID(), - Data: faker.Word(), + Data: faker.UUIDHyphenated(), }, }, }, @@ -232,7 +251,7 @@ func TestLoader_Load(t *testing.T) { "nonexist": { { ID: uuid.Must(uuid.NewV7()), - Data: faker.Word(), + Data: faker.UUIDHyphenated(), }, }, }, diff --git a/pkg/symbol/symbol_test.go b/pkg/symbol/symbol_test.go index a3e4cc43..1078e6f7 100644 --- a/pkg/symbol/symbol_test.go +++ b/pkg/symbol/symbol_test.go @@ -82,7 +82,7 @@ func TestSymbol_Setter(t *testing.T) { sb.SetID(id) assert.Equal(t, id, sb.ID()) - namespace := faker.Word() + namespace := faker.UUIDHyphenated() sb.SetNamespace(namespace) assert.Equal(t, namespace, sb.Namespace()) diff --git a/pkg/types/map.go b/pkg/types/map.go index 0627e262..43aced11 100644 --- a/pkg/types/map.go +++ b/pkg/types/map.go @@ -2,7 +2,6 @@ package types import ( "encoding/binary" - "fmt" "hash/fnv" "reflect" "strings" @@ -433,9 +432,6 @@ func newMapDecoder(decoder *encoding.DecodeAssembler[Value, any]) encoding.Decod dec = encoding.DecodeFunc(func(source *mapProxy, target unsafe.Pointer) error { value, ok := source.Get(alias) if !ok { - if !tag.omitempty { - return errors.WithMessage(encoding.ErrUnsupportedValue, fmt.Sprintf("%v is zero value", field.Name)) - } return nil } source.Delete(alias) diff --git a/pkg/types/string_test.go b/pkg/types/string_test.go index e4daf8a0..70ea52d4 100644 --- a/pkg/types/string_test.go +++ b/pkg/types/string_test.go @@ -86,7 +86,7 @@ func TestString_Encode(t *testing.T) { }) t.Run("string", func(t *testing.T) { - source := faker.Word() + source := faker.UUIDHyphenated() v := NewString(source) decoded, err := enc.Encode(source)